diff options
203 files changed, 5229 insertions, 1527 deletions
diff --git a/.ci/scripts/format/script.sh b/.ci/scripts/format/script.sh index 25b0718f0..f9c63dbfa 100755 --- a/.ci/scripts/format/script.sh +++ b/.ci/scripts/format/script.sh | |||
| @@ -3,38 +3,35 @@ | |||
| 3 | # SPDX-FileCopyrightText: 2019 yuzu Emulator Project | 3 | # SPDX-FileCopyrightText: 2019 yuzu Emulator Project |
| 4 | # SPDX-License-Identifier: GPL-2.0-or-later | 4 | # SPDX-License-Identifier: GPL-2.0-or-later |
| 5 | 5 | ||
| 6 | if grep -nrI '\s$' src *.yml *.txt *.md Doxyfile .gitignore .gitmodules .ci* dist/*.desktop \ | 6 | shopt -s nullglob globstar |
| 7 | dist/*.svg dist/*.xml; then | 7 | |
| 8 | if git grep -nrI '\s$' src **/*.yml **/*.txt **/*.md Doxyfile .gitignore .gitmodules .ci* dist/*.desktop dist/*.svg dist/*.xml; then | ||
| 8 | echo Trailing whitespace found, aborting | 9 | echo Trailing whitespace found, aborting |
| 9 | exit 1 | 10 | exit 1 |
| 10 | fi | 11 | fi |
| 11 | 12 | ||
| 12 | # Default clang-format points to default 3.5 version one | 13 | # Default clang-format points to default 3.5 version one |
| 13 | CLANG_FORMAT=${CLANG_FORMAT:-clang-format-15} | 14 | CLANG_FORMAT="${CLANG_FORMAT:-clang-format-15}" |
| 14 | $CLANG_FORMAT --version | 15 | "$CLANG_FORMAT" --version |
| 15 | |||
| 16 | if [ "$TRAVIS_EVENT_TYPE" = "pull_request" ]; then | ||
| 17 | # Get list of every file modified in this pull request | ||
| 18 | files_to_lint="$(git diff --name-only --diff-filter=ACMRTUXB $TRAVIS_COMMIT_RANGE | grep '^src/[^.]*[.]\(cpp\|h\)$' || true)" | ||
| 19 | else | ||
| 20 | # Check everything for branch pushes | ||
| 21 | files_to_lint="$(find src/ -name '*.cpp' -or -name '*.h')" | ||
| 22 | fi | ||
| 23 | 16 | ||
| 24 | # Turn off tracing for this because it's too verbose | 17 | # Turn off tracing for this because it's too verbose |
| 25 | set +x | 18 | set +x |
| 26 | 19 | ||
| 27 | for f in $files_to_lint; do | 20 | # Check everything for branch pushes |
| 28 | d=$(diff -u "$f" <($CLANG_FORMAT "$f") || true) | 21 | FILES_TO_LINT="$(find src/ -name '*.cpp' -or -name '*.h')" |
| 29 | if ! [ -z "$d" ]; then | 22 | |
| 30 | echo "!!! $f not compliant to coding style, here is the fix:" | 23 | for f in $FILES_TO_LINT; do |
| 31 | echo "$d" | 24 | echo "$f" |
| 32 | fail=1 | 25 | "$CLANG_FORMAT" -i "$f" |
| 33 | fi | ||
| 34 | done | 26 | done |
| 35 | 27 | ||
| 36 | set -x | 28 | DIFF=$(git -c core.fileMode=false diff) |
| 37 | 29 | ||
| 38 | if [ "$fail" = 1 ]; then | 30 | if [ ! -z "$DIFF" ]; then |
| 31 | echo "!!! Not compliant to coding style, here is the fix:" | ||
| 32 | echo "$DIFF" | ||
| 39 | exit 1 | 33 | exit 1 |
| 40 | fi | 34 | fi |
| 35 | |||
| 36 | cd src/android | ||
| 37 | ./gradlew ktlintCheck | ||
diff --git a/.ci/scripts/linux/exec.sh b/.ci/scripts/linux/exec.sh index fa3d78cc2..04e2486a1 100644 --- a/.ci/scripts/linux/exec.sh +++ b/.ci/scripts/linux/exec.sh | |||
| @@ -9,7 +9,7 @@ chmod a+x ./.ci/scripts/linux/docker.sh | |||
| 9 | sudo chown -R 1027 ./ | 9 | sudo chown -R 1027 ./ |
| 10 | 10 | ||
| 11 | # The environment variables listed below: | 11 | # The environment variables listed below: |
| 12 | # AZURECIREPO TITLEBARFORMATIDLE TITLEBARFORMATRUNNING DISPLAYVERSION | 12 | # AZURECIREPO TITLEBARFORMATIDLE TITLEBARFORMATRUNNING DISPLAYVERSION |
| 13 | # are requested in src/common/CMakeLists.txt and appear to be provided somewhere in Azure DevOps | 13 | # are requested in src/common/CMakeLists.txt and appear to be provided somewhere in Azure DevOps |
| 14 | 14 | ||
| 15 | docker run -e AZURECIREPO -e TITLEBARFORMATIDLE -e TITLEBARFORMATRUNNING -e DISPLAYVERSION -e ENABLE_COMPATIBILITY_REPORTING -e CCACHE_DIR=/yuzu/ccache -v "$(pwd):/yuzu" -w /yuzu yuzuemu/build-environments:linux-fresh /bin/bash /yuzu/.ci/scripts/linux/docker.sh "$1" | 15 | docker run -e AZURECIREPO -e TITLEBARFORMATIDLE -e TITLEBARFORMATRUNNING -e DISPLAYVERSION -e ENABLE_COMPATIBILITY_REPORTING -e CCACHE_DIR=/yuzu/ccache -v "$(pwd):/yuzu" -w /yuzu yuzuemu/build-environments:linux-fresh /bin/bash /yuzu/.ci/scripts/linux/docker.sh "$1" |
diff --git a/.ci/yuzu-mainline-step2.yml b/.ci/yuzu-mainline-step2.yml index b294827f4..8bb0572f5 100644 --- a/.ci/yuzu-mainline-step2.yml +++ b/.ci/yuzu-mainline-step2.yml | |||
| @@ -8,17 +8,7 @@ variables: | |||
| 8 | DisplayVersion: $[counter(variables['DisplayPrefix'], 1)] | 8 | DisplayVersion: $[counter(variables['DisplayPrefix'], 1)] |
| 9 | 9 | ||
| 10 | stages: | 10 | stages: |
| 11 | - stage: format | ||
| 12 | displayName: 'format' | ||
| 13 | jobs: | ||
| 14 | - job: format | ||
| 15 | displayName: 'clang' | ||
| 16 | pool: | ||
| 17 | vmImage: ubuntu-latest | ||
| 18 | steps: | ||
| 19 | - template: ./templates/format-check.yml | ||
| 20 | - stage: build | 11 | - stage: build |
| 21 | dependsOn: format | ||
| 22 | displayName: 'build' | 12 | displayName: 'build' |
| 23 | jobs: | 13 | jobs: |
| 24 | - job: build | 14 | - job: build |
diff --git a/.github/workflows/verify.yml b/.github/workflows/verify.yml index c073f3f3f..62eb69aeb 100644 --- a/.github/workflows/verify.yml +++ b/.github/workflows/verify.yml | |||
| @@ -13,13 +13,15 @@ jobs: | |||
| 13 | format: | 13 | format: |
| 14 | name: 'verify format' | 14 | name: 'verify format' |
| 15 | runs-on: ubuntu-latest | 15 | runs-on: ubuntu-latest |
| 16 | container: | ||
| 17 | image: yuzuemu/build-environments:linux-clang-format | ||
| 18 | options: -u 1001 | ||
| 19 | steps: | 16 | steps: |
| 20 | - uses: actions/checkout@v3 | 17 | - uses: actions/checkout@v3 |
| 21 | with: | 18 | with: |
| 22 | submodules: false | 19 | submodules: false |
| 20 | - name: set up JDK 17 | ||
| 21 | uses: actions/setup-java@v3 | ||
| 22 | with: | ||
| 23 | java-version: '17' | ||
| 24 | distribution: 'temurin' | ||
| 23 | - name: 'Verify Formatting' | 25 | - name: 'Verify Formatting' |
| 24 | run: bash -ex ./.ci/scripts/format/script.sh | 26 | run: bash -ex ./.ci/scripts/format/script.sh |
| 25 | build: | 27 | build: |
diff --git a/LICENSES/BSD-2-Clause.txt b/LICENSES/BSD-2-Clause.txt index 5f662b354..eb3c575b8 100644 --- a/LICENSES/BSD-2-Clause.txt +++ b/LICENSES/BSD-2-Clause.txt | |||
| @@ -1,4 +1,4 @@ | |||
| 1 | Copyright (c) <year> <owner> | 1 | Copyright (c) <year> <owner> |
| 2 | 2 | ||
| 3 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: | 3 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: |
| 4 | 4 | ||
diff --git a/LICENSES/BSD-3-Clause.txt b/LICENSES/BSD-3-Clause.txt index ea890afbc..086d3992c 100644 --- a/LICENSES/BSD-3-Clause.txt +++ b/LICENSES/BSD-3-Clause.txt | |||
| @@ -1,4 +1,4 @@ | |||
| 1 | Copyright (c) <year> <owner>. | 1 | Copyright (c) <year> <owner>. |
| 2 | 2 | ||
| 3 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: | 3 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: |
| 4 | 4 | ||
diff --git a/LICENSES/MPL-2.0.txt b/LICENSES/MPL-2.0.txt index 14e2f777f..a612ad981 100644 --- a/LICENSES/MPL-2.0.txt +++ b/LICENSES/MPL-2.0.txt | |||
| @@ -35,7 +35,7 @@ Mozilla Public License Version 2.0 | |||
| 35 | means any form of the work other than Source Code Form. | 35 | means any form of the work other than Source Code Form. |
| 36 | 36 | ||
| 37 | 1.7. "Larger Work" | 37 | 1.7. "Larger Work" |
| 38 | means a work that combines Covered Software with other material, in | 38 | means a work that combines Covered Software with other material, in |
| 39 | a separate file or files, that is not Covered Software. | 39 | a separate file or files, that is not Covered Software. |
| 40 | 40 | ||
| 41 | 1.8. "License" | 41 | 1.8. "License" |
diff --git a/externals/ffmpeg/CMakeLists.txt b/externals/ffmpeg/CMakeLists.txt index f2886eb6c..543585d4f 100644 --- a/externals/ffmpeg/CMakeLists.txt +++ b/externals/ffmpeg/CMakeLists.txt | |||
| @@ -138,7 +138,7 @@ if (NOT WIN32 AND NOT ANDROID) | |||
| 138 | --cross-prefix=${TOOLCHAIN}/bin/aarch64-linux-android- | 138 | --cross-prefix=${TOOLCHAIN}/bin/aarch64-linux-android- |
| 139 | --sysroot=${SYSROOT} | 139 | --sysroot=${SYSROOT} |
| 140 | --target-os=android | 140 | --target-os=android |
| 141 | --extra-ldflags="--ld-path=${TOOLCHAIN}/bin/ld.lld" | 141 | --extra-ldflags="--ld-path=${TOOLCHAIN}/bin/ld.lld" |
| 142 | --extra-ldflags="-nostdlib" | 142 | --extra-ldflags="-nostdlib" |
| 143 | ) | 143 | ) |
| 144 | endif() | 144 | endif() |
diff --git a/externals/nx_tzdb/tzdb_to_nx b/externals/nx_tzdb/tzdb_to_nx | |||
| Subproject f6680093bca30265c161581fd813d4ddd33f1e3 | Subproject 404d39004570a26c734a9d1fa29ab4d63089c59 | ||
diff --git a/src/android/app/build.gradle.kts b/src/android/app/build.gradle.kts index 53aafa08c..06e59d1ac 100644 --- a/src/android/app/build.gradle.kts +++ b/src/android/app/build.gradle.kts | |||
| @@ -188,8 +188,15 @@ tasks.create<Delete>("ktlintReset") { | |||
| 188 | delete(File(buildDir.path + File.separator + "intermediates/ktLint")) | 188 | delete(File(buildDir.path + File.separator + "intermediates/ktLint")) |
| 189 | } | 189 | } |
| 190 | 190 | ||
| 191 | val showFormatHelp = { | ||
| 192 | logger.lifecycle( | ||
| 193 | "If this check fails, please try running \"gradlew ktlintFormat\" for automatic " + | ||
| 194 | "codestyle fixes" | ||
| 195 | ) | ||
| 196 | } | ||
| 197 | tasks.getByPath("ktlintKotlinScriptCheck").doFirst { showFormatHelp.invoke() } | ||
| 198 | tasks.getByPath("ktlintMainSourceSetCheck").doFirst { showFormatHelp.invoke() } | ||
| 191 | tasks.getByPath("loadKtlintReporters").dependsOn("ktlintReset") | 199 | tasks.getByPath("loadKtlintReporters").dependsOn("ktlintReset") |
| 192 | tasks.getByPath("preBuild").dependsOn("ktlintCheck") | ||
| 193 | 200 | ||
| 194 | ktlint { | 201 | ktlint { |
| 195 | version.set("0.47.1") | 202 | version.set("0.47.1") |
| @@ -228,71 +235,33 @@ dependencies { | |||
| 228 | implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.5.0") | 235 | implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.5.0") |
| 229 | } | 236 | } |
| 230 | 237 | ||
| 231 | fun getGitVersion(): String { | 238 | fun runGitCommand(command: List<String>): String { |
| 232 | var versionName = "0.0" | 239 | return try { |
| 233 | 240 | ProcessBuilder(command) | |
| 234 | try { | ||
| 235 | versionName = ProcessBuilder("git", "describe", "--always", "--long") | ||
| 236 | .directory(project.rootDir) | 241 | .directory(project.rootDir) |
| 237 | .redirectOutput(ProcessBuilder.Redirect.PIPE) | 242 | .redirectOutput(ProcessBuilder.Redirect.PIPE) |
| 238 | .redirectError(ProcessBuilder.Redirect.PIPE) | 243 | .redirectError(ProcessBuilder.Redirect.PIPE) |
| 239 | .start().inputStream.bufferedReader().use { it.readText() } | 244 | .start().inputStream.bufferedReader().use { it.readText() } |
| 240 | .trim() | 245 | .trim() |
| 241 | .replace(Regex("(-0)?-[^-]+$"), "") | ||
| 242 | } catch (e: Exception) { | 246 | } catch (e: Exception) { |
| 243 | logger.error("Cannot find git, defaulting to dummy version number") | 247 | logger.error("Cannot find git") |
| 248 | "" | ||
| 244 | } | 249 | } |
| 245 | |||
| 246 | if (System.getenv("GITHUB_ACTIONS") != null) { | ||
| 247 | val gitTag = System.getenv("GIT_TAG_NAME") | ||
| 248 | versionName = gitTag ?: versionName | ||
| 249 | } | ||
| 250 | |||
| 251 | return versionName | ||
| 252 | } | 250 | } |
| 253 | 251 | ||
| 254 | fun getGitHash(): String { | 252 | fun getGitVersion(): String { |
| 255 | try { | 253 | val versionName = if (System.getenv("GITHUB_ACTIONS") != null) { |
| 256 | val processBuilder = ProcessBuilder("git", "rev-parse", "--short", "HEAD") | 254 | val gitTag = System.getenv("GIT_TAG_NAME") ?: "" |
| 257 | processBuilder.directory(project.rootDir) | 255 | gitTag |
| 258 | val process = processBuilder.start() | 256 | } else { |
| 259 | val inputStream = process.inputStream | 257 | runGitCommand(listOf("git", "describe", "--always", "--long")) |
| 260 | val errorStream = process.errorStream | 258 | .replace(Regex("(-0)?-[^-]+$"), "") |
| 261 | process.waitFor() | ||
| 262 | |||
| 263 | return if (process.exitValue() == 0) { | ||
| 264 | inputStream.bufferedReader() | ||
| 265 | .use { it.readText().trim() } // return the value of gitHash | ||
| 266 | } else { | ||
| 267 | val errorMessage = errorStream.bufferedReader().use { it.readText().trim() } | ||
| 268 | logger.error("Error running git command: $errorMessage") | ||
| 269 | "dummy-hash" // return a dummy hash value in case of an error | ||
| 270 | } | ||
| 271 | } catch (e: Exception) { | ||
| 272 | logger.error("$e: Cannot find git, defaulting to dummy build hash") | ||
| 273 | return "dummy-hash" // return a dummy hash value in case of an error | ||
| 274 | } | 259 | } |
| 260 | return versionName.ifEmpty { "0.0" } | ||
| 275 | } | 261 | } |
| 276 | 262 | ||
| 277 | fun getBranch(): String { | 263 | fun getGitHash(): String = |
| 278 | try { | 264 | runGitCommand(listOf("git", "rev-parse", "--short", "HEAD")).ifEmpty { "dummy-hash" } |
| 279 | val processBuilder = ProcessBuilder("git", "rev-parse", "--abbrev-ref", "HEAD") | 265 | |
| 280 | processBuilder.directory(project.rootDir) | 266 | fun getBranch(): String = |
| 281 | val process = processBuilder.start() | 267 | runGitCommand(listOf("git", "rev-parse", "--abbrev-ref", "HEAD")).ifEmpty { "dummy-hash" } |
| 282 | val inputStream = process.inputStream | ||
| 283 | val errorStream = process.errorStream | ||
| 284 | process.waitFor() | ||
| 285 | |||
| 286 | return if (process.exitValue() == 0) { | ||
| 287 | inputStream.bufferedReader() | ||
| 288 | .use { it.readText().trim() } // return the value of gitHash | ||
| 289 | } else { | ||
| 290 | val errorMessage = errorStream.bufferedReader().use { it.readText().trim() } | ||
| 291 | logger.error("Error running git command: $errorMessage") | ||
| 292 | "dummy-hash" // return a dummy hash value in case of an error | ||
| 293 | } | ||
| 294 | } catch (e: Exception) { | ||
| 295 | logger.error("$e: Cannot find git, defaulting to dummy build hash") | ||
| 296 | return "dummy-hash" // return a dummy hash value in case of an error | ||
| 297 | } | ||
| 298 | } | ||
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/AbstractDiffAdapter.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/AbstractDiffAdapter.kt new file mode 100644 index 000000000..f006f9e3d --- /dev/null +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/AbstractDiffAdapter.kt | |||
| @@ -0,0 +1,33 @@ | |||
| 1 | // SPDX-FileCopyrightText: 2024 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | package org.yuzu.yuzu_emu.adapters | ||
| 5 | |||
| 6 | import android.annotation.SuppressLint | ||
| 7 | import androidx.recyclerview.widget.AsyncDifferConfig | ||
| 8 | import androidx.recyclerview.widget.DiffUtil | ||
| 9 | import androidx.recyclerview.widget.ListAdapter | ||
| 10 | import org.yuzu.yuzu_emu.viewholder.AbstractViewHolder | ||
| 11 | import androidx.recyclerview.widget.RecyclerView | ||
| 12 | |||
| 13 | /** | ||
| 14 | * Generic adapter that implements an [AsyncDifferConfig] and covers some of the basic boilerplate | ||
| 15 | * code used in every [RecyclerView]. | ||
| 16 | * Type assigned to [Model] must inherit from [Object] in order to be compared properly. | ||
| 17 | */ | ||
| 18 | abstract class AbstractDiffAdapter<Model : Any, Holder : AbstractViewHolder<Model>> : | ||
| 19 | ListAdapter<Model, Holder>(AsyncDifferConfig.Builder(DiffCallback<Model>()).build()) { | ||
| 20 | override fun onBindViewHolder(holder: Holder, position: Int) = | ||
| 21 | holder.bind(currentList[position]) | ||
| 22 | |||
| 23 | private class DiffCallback<Model> : DiffUtil.ItemCallback<Model>() { | ||
| 24 | override fun areItemsTheSame(oldItem: Model & Any, newItem: Model & Any): Boolean { | ||
| 25 | return oldItem === newItem | ||
| 26 | } | ||
| 27 | |||
| 28 | @SuppressLint("DiffUtilEquals") | ||
| 29 | override fun areContentsTheSame(oldItem: Model & Any, newItem: Model & Any): Boolean { | ||
| 30 | return oldItem == newItem | ||
| 31 | } | ||
| 32 | } | ||
| 33 | } | ||
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/AbstractListAdapter.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/AbstractListAdapter.kt new file mode 100644 index 000000000..3dfee3d0c --- /dev/null +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/AbstractListAdapter.kt | |||
| @@ -0,0 +1,98 @@ | |||
| 1 | // SPDX-FileCopyrightText: 2024 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | package org.yuzu.yuzu_emu.adapters | ||
| 5 | |||
| 6 | import android.annotation.SuppressLint | ||
| 7 | import androidx.recyclerview.widget.RecyclerView | ||
| 8 | import org.yuzu.yuzu_emu.viewholder.AbstractViewHolder | ||
| 9 | |||
| 10 | /** | ||
| 11 | * Generic list class meant to take care of basic lists | ||
| 12 | * @param currentList The list to show initially | ||
| 13 | */ | ||
| 14 | abstract class AbstractListAdapter<Model : Any, Holder : AbstractViewHolder<Model>>( | ||
| 15 | open var currentList: List<Model> | ||
| 16 | ) : RecyclerView.Adapter<Holder>() { | ||
| 17 | override fun onBindViewHolder(holder: Holder, position: Int) = | ||
| 18 | holder.bind(currentList[position]) | ||
| 19 | |||
| 20 | override fun getItemCount(): Int = currentList.size | ||
| 21 | |||
| 22 | /** | ||
| 23 | * Adds an item to [currentList] and notifies the underlying adapter of the change. If no parameter | ||
| 24 | * is passed in for position, [item] is added to the end of the list. Invokes [callback] last. | ||
| 25 | * @param item The item to add to the list | ||
| 26 | * @param position Index where [item] will be added | ||
| 27 | * @param callback Lambda that's called at the end of the list changes and has the added list | ||
| 28 | * position passed in as a parameter | ||
| 29 | */ | ||
| 30 | open fun addItem(item: Model, position: Int = -1, callback: ((position: Int) -> Unit)? = null) { | ||
| 31 | val newList = currentList.toMutableList() | ||
| 32 | val positionToUpdate: Int | ||
| 33 | if (position == -1) { | ||
| 34 | newList.add(item) | ||
| 35 | currentList = newList | ||
| 36 | positionToUpdate = currentList.size - 1 | ||
| 37 | } else { | ||
| 38 | newList.add(position, item) | ||
| 39 | currentList = newList | ||
| 40 | positionToUpdate = position | ||
| 41 | } | ||
| 42 | onItemAdded(positionToUpdate, callback) | ||
| 43 | } | ||
| 44 | |||
| 45 | protected fun onItemAdded(position: Int, callback: ((Int) -> Unit)? = null) { | ||
| 46 | notifyItemInserted(position) | ||
| 47 | callback?.invoke(position) | ||
| 48 | } | ||
| 49 | |||
| 50 | /** | ||
| 51 | * Replaces the [item] at [position] in the [currentList] and notifies the underlying adapter | ||
| 52 | * of the change. Invokes [callback] last. | ||
| 53 | * @param item New list item | ||
| 54 | * @param position Index where [item] will replace the existing list item | ||
| 55 | * @param callback Lambda that's called at the end of the list changes and has the changed list | ||
| 56 | * position passed in as a parameter | ||
| 57 | */ | ||
| 58 | fun changeItem(item: Model, position: Int, callback: ((position: Int) -> Unit)? = null) { | ||
| 59 | val newList = currentList.toMutableList() | ||
| 60 | newList[position] = item | ||
| 61 | currentList = newList | ||
| 62 | onItemChanged(position, callback) | ||
| 63 | } | ||
| 64 | |||
| 65 | protected fun onItemChanged(position: Int, callback: ((Int) -> Unit)? = null) { | ||
| 66 | notifyItemChanged(position) | ||
| 67 | callback?.invoke(position) | ||
| 68 | } | ||
| 69 | |||
| 70 | /** | ||
| 71 | * Removes the list item at [position] in [currentList] and notifies the underlying adapter | ||
| 72 | * of the change. Invokes [callback] last. | ||
| 73 | * @param position Index where the list item will be removed | ||
| 74 | * @param callback Lambda that's called at the end of the list changes and has the removed list | ||
| 75 | * position passed in as a parameter | ||
| 76 | */ | ||
| 77 | fun removeItem(position: Int, callback: ((position: Int) -> Unit)? = null) { | ||
| 78 | val newList = currentList.toMutableList() | ||
| 79 | newList.removeAt(position) | ||
| 80 | currentList = newList | ||
| 81 | onItemRemoved(position, callback) | ||
| 82 | } | ||
| 83 | |||
| 84 | protected fun onItemRemoved(position: Int, callback: ((Int) -> Unit)? = null) { | ||
| 85 | notifyItemRemoved(position) | ||
| 86 | callback?.invoke(position) | ||
| 87 | } | ||
| 88 | |||
| 89 | /** | ||
| 90 | * Replaces [currentList] with [newList] and notifies the underlying adapter of the change. | ||
| 91 | * @param newList The new list to replace [currentList] | ||
| 92 | */ | ||
| 93 | @SuppressLint("NotifyDataSetChanged") | ||
| 94 | open fun replaceList(newList: List<Model>) { | ||
| 95 | currentList = newList | ||
| 96 | notifyDataSetChanged() | ||
| 97 | } | ||
| 98 | } | ||
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/AbstractSingleSelectionList.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/AbstractSingleSelectionList.kt new file mode 100644 index 000000000..52163f9d7 --- /dev/null +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/AbstractSingleSelectionList.kt | |||
| @@ -0,0 +1,105 @@ | |||
| 1 | // SPDX-FileCopyrightText: 2024 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | package org.yuzu.yuzu_emu.adapters | ||
| 5 | |||
| 6 | import org.yuzu.yuzu_emu.model.SelectableItem | ||
| 7 | import org.yuzu.yuzu_emu.viewholder.AbstractViewHolder | ||
| 8 | |||
| 9 | /** | ||
| 10 | * Generic list class meant to take care of single selection UI updates | ||
| 11 | * @param currentList The list to show initially | ||
| 12 | * @param defaultSelection The default selection to use if no list items are selected by | ||
| 13 | * [SelectableItem.selected] or if the currently selected item is removed from the list | ||
| 14 | */ | ||
| 15 | abstract class AbstractSingleSelectionList< | ||
| 16 | Model : SelectableItem, | ||
| 17 | Holder : AbstractViewHolder<Model> | ||
| 18 | >( | ||
| 19 | final override var currentList: List<Model>, | ||
| 20 | private val defaultSelection: DefaultSelection = DefaultSelection.Start | ||
| 21 | ) : AbstractListAdapter<Model, Holder>(currentList) { | ||
| 22 | var selectedItem = getDefaultSelection() | ||
| 23 | |||
| 24 | init { | ||
| 25 | findSelectedItem() | ||
| 26 | } | ||
| 27 | |||
| 28 | /** | ||
| 29 | * Changes the selection state of the [SelectableItem] that was selected and the previously selected | ||
| 30 | * item and notifies the underlying adapter of the change for those items. Invokes [callback] last. | ||
| 31 | * Does nothing if [position] is the same as the currently selected item. | ||
| 32 | * @param position Index of the item that was selected | ||
| 33 | * @param callback Lambda that's called at the end of the list changes and has the selected list | ||
| 34 | * position passed in as a parameter | ||
| 35 | */ | ||
| 36 | fun selectItem(position: Int, callback: ((position: Int) -> Unit)? = null) { | ||
| 37 | if (position == selectedItem) { | ||
| 38 | return | ||
| 39 | } | ||
| 40 | |||
| 41 | val previouslySelectedItem = selectedItem | ||
| 42 | selectedItem = position | ||
| 43 | if (currentList.indices.contains(selectedItem)) { | ||
| 44 | currentList[selectedItem].onSelectionStateChanged(true) | ||
| 45 | } | ||
| 46 | if (currentList.indices.contains(previouslySelectedItem)) { | ||
| 47 | currentList[previouslySelectedItem].onSelectionStateChanged(false) | ||
| 48 | } | ||
| 49 | onItemChanged(previouslySelectedItem) | ||
| 50 | onItemChanged(selectedItem) | ||
| 51 | callback?.invoke(position) | ||
| 52 | } | ||
| 53 | |||
| 54 | /** | ||
| 55 | * Removes a given item from the list and notifies the underlying adapter of the change. If the | ||
| 56 | * currently selected item was the item that was removed, the item at the position provided | ||
| 57 | * by [defaultSelection] will be made the new selection. Invokes [callback] last. | ||
| 58 | * @param position Index of the item that was removed | ||
| 59 | * @param callback Lambda that's called at the end of the list changes and has the removed and | ||
| 60 | * selected list positions passed in as parameters | ||
| 61 | */ | ||
| 62 | fun removeSelectableItem( | ||
| 63 | position: Int, | ||
| 64 | callback: ((removedPosition: Int, selectedPosition: Int) -> Unit)? | ||
| 65 | ) { | ||
| 66 | removeItem(position) | ||
| 67 | if (position == selectedItem) { | ||
| 68 | selectedItem = getDefaultSelection() | ||
| 69 | currentList[selectedItem].onSelectionStateChanged(true) | ||
| 70 | onItemChanged(selectedItem) | ||
| 71 | } else if (position < selectedItem) { | ||
| 72 | selectedItem-- | ||
| 73 | } | ||
| 74 | callback?.invoke(position, selectedItem) | ||
| 75 | } | ||
| 76 | |||
| 77 | override fun addItem(item: Model, position: Int, callback: ((Int) -> Unit)?) { | ||
| 78 | super.addItem(item, position, callback) | ||
| 79 | if (position <= selectedItem && position != -1) { | ||
| 80 | selectedItem++ | ||
| 81 | } | ||
| 82 | } | ||
| 83 | |||
| 84 | override fun replaceList(newList: List<Model>) { | ||
| 85 | super.replaceList(newList) | ||
| 86 | findSelectedItem() | ||
| 87 | } | ||
| 88 | |||
| 89 | private fun findSelectedItem() { | ||
| 90 | for (i in currentList.indices) { | ||
| 91 | if (currentList[i].selected) { | ||
| 92 | selectedItem = i | ||
| 93 | break | ||
| 94 | } | ||
| 95 | } | ||
| 96 | } | ||
| 97 | |||
| 98 | private fun getDefaultSelection(): Int = | ||
| 99 | when (defaultSelection) { | ||
| 100 | DefaultSelection.Start -> currentList.indices.first | ||
| 101 | DefaultSelection.End -> currentList.indices.last | ||
| 102 | } | ||
| 103 | |||
| 104 | enum class DefaultSelection { Start, End } | ||
| 105 | } | ||
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/AddonAdapter.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/AddonAdapter.kt index 15c7ca3c9..94c151325 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/AddonAdapter.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/AddonAdapter.kt | |||
| @@ -5,48 +5,28 @@ package org.yuzu.yuzu_emu.adapters | |||
| 5 | 5 | ||
| 6 | import android.view.LayoutInflater | 6 | import android.view.LayoutInflater |
| 7 | import android.view.ViewGroup | 7 | import android.view.ViewGroup |
| 8 | import androidx.recyclerview.widget.AsyncDifferConfig | ||
| 9 | import androidx.recyclerview.widget.DiffUtil | ||
| 10 | import androidx.recyclerview.widget.ListAdapter | ||
| 11 | import androidx.recyclerview.widget.RecyclerView | ||
| 12 | import org.yuzu.yuzu_emu.databinding.ListItemAddonBinding | 8 | import org.yuzu.yuzu_emu.databinding.ListItemAddonBinding |
| 13 | import org.yuzu.yuzu_emu.model.Addon | 9 | import org.yuzu.yuzu_emu.model.Addon |
| 10 | import org.yuzu.yuzu_emu.viewholder.AbstractViewHolder | ||
| 14 | 11 | ||
| 15 | class AddonAdapter : ListAdapter<Addon, AddonAdapter.AddonViewHolder>( | 12 | class AddonAdapter : AbstractDiffAdapter<Addon, AddonAdapter.AddonViewHolder>() { |
| 16 | AsyncDifferConfig.Builder(DiffCallback()).build() | ||
| 17 | ) { | ||
| 18 | override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): AddonViewHolder { | 13 | override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): AddonViewHolder { |
| 19 | ListItemAddonBinding.inflate(LayoutInflater.from(parent.context), parent, false) | 14 | ListItemAddonBinding.inflate(LayoutInflater.from(parent.context), parent, false) |
| 20 | .also { return AddonViewHolder(it) } | 15 | .also { return AddonViewHolder(it) } |
| 21 | } | 16 | } |
| 22 | 17 | ||
| 23 | override fun getItemCount(): Int = currentList.size | ||
| 24 | |||
| 25 | override fun onBindViewHolder(holder: AddonViewHolder, position: Int) = | ||
| 26 | holder.bind(currentList[position]) | ||
| 27 | |||
| 28 | inner class AddonViewHolder(val binding: ListItemAddonBinding) : | 18 | inner class AddonViewHolder(val binding: ListItemAddonBinding) : |
| 29 | RecyclerView.ViewHolder(binding.root) { | 19 | AbstractViewHolder<Addon>(binding) { |
| 30 | fun bind(addon: Addon) { | 20 | override fun bind(model: Addon) { |
| 31 | binding.root.setOnClickListener { | 21 | binding.root.setOnClickListener { |
| 32 | binding.addonSwitch.isChecked = !binding.addonSwitch.isChecked | 22 | binding.addonSwitch.isChecked = !binding.addonSwitch.isChecked |
| 33 | } | 23 | } |
| 34 | binding.title.text = addon.title | 24 | binding.title.text = model.title |
| 35 | binding.version.text = addon.version | 25 | binding.version.text = model.version |
| 36 | binding.addonSwitch.setOnCheckedChangeListener { _, checked -> | 26 | binding.addonSwitch.setOnCheckedChangeListener { _, checked -> |
| 37 | addon.enabled = checked | 27 | model.enabled = checked |
| 38 | } | 28 | } |
| 39 | binding.addonSwitch.isChecked = addon.enabled | 29 | binding.addonSwitch.isChecked = model.enabled |
| 40 | } | ||
| 41 | } | ||
| 42 | |||
| 43 | private class DiffCallback : DiffUtil.ItemCallback<Addon>() { | ||
| 44 | override fun areItemsTheSame(oldItem: Addon, newItem: Addon): Boolean { | ||
| 45 | return oldItem == newItem | ||
| 46 | } | ||
| 47 | |||
| 48 | override fun areContentsTheSame(oldItem: Addon, newItem: Addon): Boolean { | ||
| 49 | return oldItem == newItem | ||
| 50 | } | 30 | } |
| 51 | } | 31 | } |
| 52 | } | 32 | } |
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/AppletAdapter.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/AppletAdapter.kt index 4a05c5be9..41d7f72b8 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/AppletAdapter.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/AppletAdapter.kt | |||
| @@ -4,13 +4,11 @@ | |||
| 4 | package org.yuzu.yuzu_emu.adapters | 4 | package org.yuzu.yuzu_emu.adapters |
| 5 | 5 | ||
| 6 | import android.view.LayoutInflater | 6 | import android.view.LayoutInflater |
| 7 | import android.view.View | ||
| 8 | import android.view.ViewGroup | 7 | import android.view.ViewGroup |
| 9 | import android.widget.Toast | 8 | import android.widget.Toast |
| 10 | import androidx.core.content.res.ResourcesCompat | 9 | import androidx.core.content.res.ResourcesCompat |
| 11 | import androidx.fragment.app.FragmentActivity | 10 | import androidx.fragment.app.FragmentActivity |
| 12 | import androidx.navigation.findNavController | 11 | import androidx.navigation.findNavController |
| 13 | import androidx.recyclerview.widget.RecyclerView | ||
| 14 | import org.yuzu.yuzu_emu.HomeNavigationDirections | 12 | import org.yuzu.yuzu_emu.HomeNavigationDirections |
| 15 | import org.yuzu.yuzu_emu.NativeLibrary | 13 | import org.yuzu.yuzu_emu.NativeLibrary |
| 16 | import org.yuzu.yuzu_emu.R | 14 | import org.yuzu.yuzu_emu.R |
| @@ -19,72 +17,58 @@ import org.yuzu.yuzu_emu.databinding.CardSimpleOutlinedBinding | |||
| 19 | import org.yuzu.yuzu_emu.model.Applet | 17 | import org.yuzu.yuzu_emu.model.Applet |
| 20 | import org.yuzu.yuzu_emu.model.AppletInfo | 18 | import org.yuzu.yuzu_emu.model.AppletInfo |
| 21 | import org.yuzu.yuzu_emu.model.Game | 19 | import org.yuzu.yuzu_emu.model.Game |
| 20 | import org.yuzu.yuzu_emu.viewholder.AbstractViewHolder | ||
| 22 | 21 | ||
| 23 | class AppletAdapter(val activity: FragmentActivity, var applets: List<Applet>) : | 22 | class AppletAdapter(val activity: FragmentActivity, applets: List<Applet>) : |
| 24 | RecyclerView.Adapter<AppletAdapter.AppletViewHolder>(), | 23 | AbstractListAdapter<Applet, AppletAdapter.AppletViewHolder>(applets) { |
| 25 | View.OnClickListener { | ||
| 26 | |||
| 27 | override fun onCreateViewHolder( | 24 | override fun onCreateViewHolder( |
| 28 | parent: ViewGroup, | 25 | parent: ViewGroup, |
| 29 | viewType: Int | 26 | viewType: Int |
| 30 | ): AppletAdapter.AppletViewHolder { | 27 | ): AppletAdapter.AppletViewHolder { |
| 31 | CardSimpleOutlinedBinding.inflate(LayoutInflater.from(parent.context), parent, false) | 28 | CardSimpleOutlinedBinding.inflate(LayoutInflater.from(parent.context), parent, false) |
| 32 | .apply { root.setOnClickListener(this@AppletAdapter) } | ||
| 33 | .also { return AppletViewHolder(it) } | 29 | .also { return AppletViewHolder(it) } |
| 34 | } | 30 | } |
| 35 | 31 | ||
| 36 | override fun onBindViewHolder(holder: AppletViewHolder, position: Int) = | ||
| 37 | holder.bind(applets[position]) | ||
| 38 | |||
| 39 | override fun getItemCount(): Int = applets.size | ||
| 40 | |||
| 41 | override fun onClick(view: View) { | ||
| 42 | val applet = (view.tag as AppletViewHolder).applet | ||
| 43 | val appletPath = NativeLibrary.getAppletLaunchPath(applet.appletInfo.entryId) | ||
| 44 | if (appletPath.isEmpty()) { | ||
| 45 | Toast.makeText( | ||
| 46 | YuzuApplication.appContext, | ||
| 47 | R.string.applets_error_applet, | ||
| 48 | Toast.LENGTH_SHORT | ||
| 49 | ).show() | ||
| 50 | return | ||
| 51 | } | ||
| 52 | |||
| 53 | if (applet.appletInfo == AppletInfo.Cabinet) { | ||
| 54 | view.findNavController() | ||
| 55 | .navigate(R.id.action_appletLauncherFragment_to_cabinetLauncherDialogFragment) | ||
| 56 | return | ||
| 57 | } | ||
| 58 | |||
| 59 | NativeLibrary.setCurrentAppletId(applet.appletInfo.appletId) | ||
| 60 | val appletGame = Game( | ||
| 61 | title = YuzuApplication.appContext.getString(applet.titleId), | ||
| 62 | path = appletPath | ||
| 63 | ) | ||
| 64 | val action = HomeNavigationDirections.actionGlobalEmulationActivity(appletGame) | ||
| 65 | view.findNavController().navigate(action) | ||
| 66 | } | ||
| 67 | |||
| 68 | inner class AppletViewHolder(val binding: CardSimpleOutlinedBinding) : | 32 | inner class AppletViewHolder(val binding: CardSimpleOutlinedBinding) : |
| 69 | RecyclerView.ViewHolder(binding.root) { | 33 | AbstractViewHolder<Applet>(binding) { |
| 70 | lateinit var applet: Applet | 34 | override fun bind(model: Applet) { |
| 71 | 35 | binding.title.setText(model.titleId) | |
| 72 | init { | 36 | binding.description.setText(model.descriptionId) |
| 73 | itemView.tag = this | ||
| 74 | } | ||
| 75 | |||
| 76 | fun bind(applet: Applet) { | ||
| 77 | this.applet = applet | ||
| 78 | |||
| 79 | binding.title.setText(applet.titleId) | ||
| 80 | binding.description.setText(applet.descriptionId) | ||
| 81 | binding.icon.setImageDrawable( | 37 | binding.icon.setImageDrawable( |
| 82 | ResourcesCompat.getDrawable( | 38 | ResourcesCompat.getDrawable( |
| 83 | binding.icon.context.resources, | 39 | binding.icon.context.resources, |
| 84 | applet.iconId, | 40 | model.iconId, |
| 85 | binding.icon.context.theme | 41 | binding.icon.context.theme |
| 86 | ) | 42 | ) |
| 87 | ) | 43 | ) |
| 44 | |||
| 45 | binding.root.setOnClickListener { onClick(model) } | ||
| 46 | } | ||
| 47 | |||
| 48 | fun onClick(applet: Applet) { | ||
| 49 | val appletPath = NativeLibrary.getAppletLaunchPath(applet.appletInfo.entryId) | ||
| 50 | if (appletPath.isEmpty()) { | ||
| 51 | Toast.makeText( | ||
| 52 | binding.root.context, | ||
| 53 | R.string.applets_error_applet, | ||
| 54 | Toast.LENGTH_SHORT | ||
| 55 | ).show() | ||
| 56 | return | ||
| 57 | } | ||
| 58 | |||
| 59 | if (applet.appletInfo == AppletInfo.Cabinet) { | ||
| 60 | binding.root.findNavController() | ||
| 61 | .navigate(R.id.action_appletLauncherFragment_to_cabinetLauncherDialogFragment) | ||
| 62 | return | ||
| 63 | } | ||
| 64 | |||
| 65 | NativeLibrary.setCurrentAppletId(applet.appletInfo.appletId) | ||
| 66 | val appletGame = Game( | ||
| 67 | title = YuzuApplication.appContext.getString(applet.titleId), | ||
| 68 | path = appletPath | ||
| 69 | ) | ||
| 70 | val action = HomeNavigationDirections.actionGlobalEmulationActivity(appletGame) | ||
| 71 | binding.root.findNavController().navigate(action) | ||
| 88 | } | 72 | } |
| 89 | } | 73 | } |
| 90 | } | 74 | } |
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/CabinetLauncherDialogAdapter.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/CabinetLauncherDialogAdapter.kt index e7b7c0f2f..a56137148 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/CabinetLauncherDialogAdapter.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/CabinetLauncherDialogAdapter.kt | |||
| @@ -4,12 +4,10 @@ | |||
| 4 | package org.yuzu.yuzu_emu.adapters | 4 | package org.yuzu.yuzu_emu.adapters |
| 5 | 5 | ||
| 6 | import android.view.LayoutInflater | 6 | import android.view.LayoutInflater |
| 7 | import android.view.View | ||
| 8 | import android.view.ViewGroup | 7 | import android.view.ViewGroup |
| 9 | import androidx.core.content.res.ResourcesCompat | 8 | import androidx.core.content.res.ResourcesCompat |
| 10 | import androidx.fragment.app.Fragment | 9 | import androidx.fragment.app.Fragment |
| 11 | import androidx.navigation.fragment.findNavController | 10 | import androidx.navigation.fragment.findNavController |
| 12 | import androidx.recyclerview.widget.RecyclerView | ||
| 13 | import org.yuzu.yuzu_emu.HomeNavigationDirections | 11 | import org.yuzu.yuzu_emu.HomeNavigationDirections |
| 14 | import org.yuzu.yuzu_emu.NativeLibrary | 12 | import org.yuzu.yuzu_emu.NativeLibrary |
| 15 | import org.yuzu.yuzu_emu.R | 13 | import org.yuzu.yuzu_emu.R |
| @@ -19,54 +17,43 @@ import org.yuzu.yuzu_emu.model.CabinetMode | |||
| 19 | import org.yuzu.yuzu_emu.adapters.CabinetLauncherDialogAdapter.CabinetModeViewHolder | 17 | import org.yuzu.yuzu_emu.adapters.CabinetLauncherDialogAdapter.CabinetModeViewHolder |
| 20 | import org.yuzu.yuzu_emu.model.AppletInfo | 18 | import org.yuzu.yuzu_emu.model.AppletInfo |
| 21 | import org.yuzu.yuzu_emu.model.Game | 19 | import org.yuzu.yuzu_emu.model.Game |
| 20 | import org.yuzu.yuzu_emu.viewholder.AbstractViewHolder | ||
| 22 | 21 | ||
| 23 | class CabinetLauncherDialogAdapter(val fragment: Fragment) : | 22 | class CabinetLauncherDialogAdapter(val fragment: Fragment) : |
| 24 | RecyclerView.Adapter<CabinetModeViewHolder>(), | 23 | AbstractListAdapter<CabinetMode, CabinetModeViewHolder>( |
| 25 | View.OnClickListener { | 24 | CabinetMode.values().copyOfRange(1, CabinetMode.entries.size).toList() |
| 26 | private val cabinetModes = CabinetMode.values().copyOfRange(1, CabinetMode.values().size) | 25 | ) { |
| 27 | 26 | ||
| 28 | override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): CabinetModeViewHolder { | 27 | override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): CabinetModeViewHolder { |
| 29 | DialogListItemBinding.inflate(LayoutInflater.from(parent.context), parent, false) | 28 | DialogListItemBinding.inflate(LayoutInflater.from(parent.context), parent, false) |
| 30 | .apply { root.setOnClickListener(this@CabinetLauncherDialogAdapter) } | ||
| 31 | .also { return CabinetModeViewHolder(it) } | 29 | .also { return CabinetModeViewHolder(it) } |
| 32 | } | 30 | } |
| 33 | 31 | ||
| 34 | override fun getItemCount(): Int = cabinetModes.size | ||
| 35 | |||
| 36 | override fun onBindViewHolder(holder: CabinetModeViewHolder, position: Int) = | ||
| 37 | holder.bind(cabinetModes[position]) | ||
| 38 | |||
| 39 | override fun onClick(view: View) { | ||
| 40 | val mode = (view.tag as CabinetModeViewHolder).cabinetMode | ||
| 41 | val appletPath = NativeLibrary.getAppletLaunchPath(AppletInfo.Cabinet.entryId) | ||
| 42 | NativeLibrary.setCurrentAppletId(AppletInfo.Cabinet.appletId) | ||
| 43 | NativeLibrary.setCabinetMode(mode.id) | ||
| 44 | val appletGame = Game( | ||
| 45 | title = YuzuApplication.appContext.getString(R.string.cabinet_applet), | ||
| 46 | path = appletPath | ||
| 47 | ) | ||
| 48 | val action = HomeNavigationDirections.actionGlobalEmulationActivity(appletGame) | ||
| 49 | fragment.findNavController().navigate(action) | ||
| 50 | } | ||
| 51 | |||
| 52 | inner class CabinetModeViewHolder(val binding: DialogListItemBinding) : | 32 | inner class CabinetModeViewHolder(val binding: DialogListItemBinding) : |
| 53 | RecyclerView.ViewHolder(binding.root) { | 33 | AbstractViewHolder<CabinetMode>(binding) { |
| 54 | lateinit var cabinetMode: CabinetMode | 34 | override fun bind(model: CabinetMode) { |
| 55 | |||
| 56 | init { | ||
| 57 | itemView.tag = this | ||
| 58 | } | ||
| 59 | |||
| 60 | fun bind(cabinetMode: CabinetMode) { | ||
| 61 | this.cabinetMode = cabinetMode | ||
| 62 | binding.icon.setImageDrawable( | 35 | binding.icon.setImageDrawable( |
| 63 | ResourcesCompat.getDrawable( | 36 | ResourcesCompat.getDrawable( |
| 64 | binding.icon.context.resources, | 37 | binding.icon.context.resources, |
| 65 | cabinetMode.iconId, | 38 | model.iconId, |
| 66 | binding.icon.context.theme | 39 | binding.icon.context.theme |
| 67 | ) | 40 | ) |
| 68 | ) | 41 | ) |
| 69 | binding.title.setText(cabinetMode.titleId) | 42 | binding.title.setText(model.titleId) |
| 43 | |||
| 44 | binding.root.setOnClickListener { onClick(model) } | ||
| 45 | } | ||
| 46 | |||
| 47 | private fun onClick(mode: CabinetMode) { | ||
| 48 | val appletPath = NativeLibrary.getAppletLaunchPath(AppletInfo.Cabinet.entryId) | ||
| 49 | NativeLibrary.setCurrentAppletId(AppletInfo.Cabinet.appletId) | ||
| 50 | NativeLibrary.setCabinetMode(mode.id) | ||
| 51 | val appletGame = Game( | ||
| 52 | title = YuzuApplication.appContext.getString(R.string.cabinet_applet), | ||
| 53 | path = appletPath | ||
| 54 | ) | ||
| 55 | val action = HomeNavigationDirections.actionGlobalEmulationActivity(appletGame) | ||
| 56 | fragment.findNavController().navigate(action) | ||
| 70 | } | 57 | } |
| 71 | } | 58 | } |
| 72 | } | 59 | } |
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/DriverAdapter.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/DriverAdapter.kt index d290a656c..d6f17cf29 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/DriverAdapter.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/DriverAdapter.kt | |||
| @@ -7,65 +7,39 @@ import android.text.TextUtils | |||
| 7 | import android.view.LayoutInflater | 7 | import android.view.LayoutInflater |
| 8 | import android.view.View | 8 | import android.view.View |
| 9 | import android.view.ViewGroup | 9 | import android.view.ViewGroup |
| 10 | import androidx.recyclerview.widget.AsyncDifferConfig | ||
| 11 | import androidx.recyclerview.widget.DiffUtil | ||
| 12 | import androidx.recyclerview.widget.ListAdapter | ||
| 13 | import androidx.recyclerview.widget.RecyclerView | ||
| 14 | import org.yuzu.yuzu_emu.R | ||
| 15 | import org.yuzu.yuzu_emu.databinding.CardDriverOptionBinding | 10 | import org.yuzu.yuzu_emu.databinding.CardDriverOptionBinding |
| 11 | import org.yuzu.yuzu_emu.features.settings.model.StringSetting | ||
| 12 | import org.yuzu.yuzu_emu.model.Driver | ||
| 16 | import org.yuzu.yuzu_emu.model.DriverViewModel | 13 | import org.yuzu.yuzu_emu.model.DriverViewModel |
| 17 | import org.yuzu.yuzu_emu.utils.GpuDriverHelper | 14 | import org.yuzu.yuzu_emu.viewholder.AbstractViewHolder |
| 18 | import org.yuzu.yuzu_emu.utils.GpuDriverMetadata | ||
| 19 | 15 | ||
| 20 | class DriverAdapter(private val driverViewModel: DriverViewModel) : | 16 | class DriverAdapter(private val driverViewModel: DriverViewModel) : |
| 21 | ListAdapter<Pair<String, GpuDriverMetadata>, DriverAdapter.DriverViewHolder>( | 17 | AbstractSingleSelectionList<Driver, DriverAdapter.DriverViewHolder>( |
| 22 | AsyncDifferConfig.Builder(DiffCallback()).build() | 18 | driverViewModel.driverList.value |
| 23 | ) { | 19 | ) { |
| 24 | override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): DriverViewHolder { | 20 | override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): DriverViewHolder { |
| 25 | val binding = | 21 | CardDriverOptionBinding.inflate(LayoutInflater.from(parent.context), parent, false) |
| 26 | CardDriverOptionBinding.inflate(LayoutInflater.from(parent.context), parent, false) | 22 | .also { return DriverViewHolder(it) } |
| 27 | return DriverViewHolder(binding) | ||
| 28 | } | ||
| 29 | |||
| 30 | override fun getItemCount(): Int = currentList.size | ||
| 31 | |||
| 32 | override fun onBindViewHolder(holder: DriverViewHolder, position: Int) = | ||
| 33 | holder.bind(currentList[position]) | ||
| 34 | |||
| 35 | private fun onSelectDriver(position: Int) { | ||
| 36 | driverViewModel.setSelectedDriverIndex(position) | ||
| 37 | notifyItemChanged(driverViewModel.previouslySelectedDriver) | ||
| 38 | notifyItemChanged(driverViewModel.selectedDriver) | ||
| 39 | } | ||
| 40 | |||
| 41 | private fun onDeleteDriver(driverData: Pair<String, GpuDriverMetadata>, position: Int) { | ||
| 42 | if (driverViewModel.selectedDriver > position) { | ||
| 43 | driverViewModel.setSelectedDriverIndex(driverViewModel.selectedDriver - 1) | ||
| 44 | } | ||
| 45 | if (GpuDriverHelper.customDriverSettingData == driverData.second) { | ||
| 46 | driverViewModel.setSelectedDriverIndex(0) | ||
| 47 | } | ||
| 48 | driverViewModel.driversToDelete.add(driverData.first) | ||
| 49 | driverViewModel.removeDriver(driverData) | ||
| 50 | notifyItemRemoved(position) | ||
| 51 | notifyItemChanged(driverViewModel.selectedDriver) | ||
| 52 | } | 23 | } |
| 53 | 24 | ||
| 54 | inner class DriverViewHolder(val binding: CardDriverOptionBinding) : | 25 | inner class DriverViewHolder(val binding: CardDriverOptionBinding) : |
| 55 | RecyclerView.ViewHolder(binding.root) { | 26 | AbstractViewHolder<Driver>(binding) { |
| 56 | private lateinit var driverData: Pair<String, GpuDriverMetadata> | 27 | override fun bind(model: Driver) { |
| 57 | |||
| 58 | fun bind(driverData: Pair<String, GpuDriverMetadata>) { | ||
| 59 | this.driverData = driverData | ||
| 60 | val driver = driverData.second | ||
| 61 | |||
| 62 | binding.apply { | 28 | binding.apply { |
| 63 | radioButton.isChecked = driverViewModel.selectedDriver == bindingAdapterPosition | 29 | radioButton.isChecked = model.selected |
| 64 | root.setOnClickListener { | 30 | root.setOnClickListener { |
| 65 | onSelectDriver(bindingAdapterPosition) | 31 | selectItem(bindingAdapterPosition) { |
| 32 | driverViewModel.onDriverSelected(it) | ||
| 33 | driverViewModel.showClearButton(!StringSetting.DRIVER_PATH.global) | ||
| 34 | } | ||
| 66 | } | 35 | } |
| 67 | buttonDelete.setOnClickListener { | 36 | buttonDelete.setOnClickListener { |
| 68 | onDeleteDriver(driverData, bindingAdapterPosition) | 37 | removeSelectableItem( |
| 38 | bindingAdapterPosition | ||
| 39 | ) { removedPosition: Int, selectedPosition: Int -> | ||
| 40 | driverViewModel.onDriverRemoved(removedPosition, selectedPosition) | ||
| 41 | driverViewModel.showClearButton(!StringSetting.DRIVER_PATH.global) | ||
| 42 | } | ||
| 69 | } | 43 | } |
| 70 | 44 | ||
| 71 | // Delay marquee by 3s | 45 | // Delay marquee by 3s |
| @@ -80,38 +54,19 @@ class DriverAdapter(private val driverViewModel: DriverViewModel) : | |||
| 80 | }, | 54 | }, |
| 81 | 3000 | 55 | 3000 |
| 82 | ) | 56 | ) |
| 83 | if (driver.name == null) { | 57 | title.text = model.title |
| 84 | title.setText(R.string.system_gpu_driver) | 58 | version.text = model.version |
| 85 | description.text = "" | 59 | description.text = model.description |
| 86 | version.text = "" | 60 | if (model.description.isNotEmpty()) { |
| 87 | version.visibility = View.GONE | ||
| 88 | description.visibility = View.GONE | ||
| 89 | buttonDelete.visibility = View.GONE | ||
| 90 | } else { | ||
| 91 | title.text = driver.name | ||
| 92 | version.text = driver.version | ||
| 93 | description.text = driver.description | ||
| 94 | version.visibility = View.VISIBLE | 61 | version.visibility = View.VISIBLE |
| 95 | description.visibility = View.VISIBLE | 62 | description.visibility = View.VISIBLE |
| 96 | buttonDelete.visibility = View.VISIBLE | 63 | buttonDelete.visibility = View.VISIBLE |
| 64 | } else { | ||
| 65 | version.visibility = View.GONE | ||
| 66 | description.visibility = View.GONE | ||
| 67 | buttonDelete.visibility = View.GONE | ||
| 97 | } | 68 | } |
| 98 | } | 69 | } |
| 99 | } | 70 | } |
| 100 | } | 71 | } |
| 101 | |||
| 102 | private class DiffCallback : DiffUtil.ItemCallback<Pair<String, GpuDriverMetadata>>() { | ||
| 103 | override fun areItemsTheSame( | ||
| 104 | oldItem: Pair<String, GpuDriverMetadata>, | ||
| 105 | newItem: Pair<String, GpuDriverMetadata> | ||
| 106 | ): Boolean { | ||
| 107 | return oldItem.first == newItem.first | ||
| 108 | } | ||
| 109 | |||
| 110 | override fun areContentsTheSame( | ||
| 111 | oldItem: Pair<String, GpuDriverMetadata>, | ||
| 112 | newItem: Pair<String, GpuDriverMetadata> | ||
| 113 | ): Boolean { | ||
| 114 | return oldItem.second == newItem.second | ||
| 115 | } | ||
| 116 | } | ||
| 117 | } | 72 | } |
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/FolderAdapter.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/FolderAdapter.kt index ab657a7b9..3d8f0bda8 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/FolderAdapter.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/FolderAdapter.kt | |||
| @@ -8,19 +8,14 @@ import android.text.TextUtils | |||
| 8 | import android.view.LayoutInflater | 8 | import android.view.LayoutInflater |
| 9 | import android.view.ViewGroup | 9 | import android.view.ViewGroup |
| 10 | import androidx.fragment.app.FragmentActivity | 10 | import androidx.fragment.app.FragmentActivity |
| 11 | import androidx.recyclerview.widget.AsyncDifferConfig | ||
| 12 | import androidx.recyclerview.widget.DiffUtil | ||
| 13 | import androidx.recyclerview.widget.ListAdapter | ||
| 14 | import androidx.recyclerview.widget.RecyclerView | ||
| 15 | import org.yuzu.yuzu_emu.databinding.CardFolderBinding | 11 | import org.yuzu.yuzu_emu.databinding.CardFolderBinding |
| 16 | import org.yuzu.yuzu_emu.fragments.GameFolderPropertiesDialogFragment | 12 | import org.yuzu.yuzu_emu.fragments.GameFolderPropertiesDialogFragment |
| 17 | import org.yuzu.yuzu_emu.model.GameDir | 13 | import org.yuzu.yuzu_emu.model.GameDir |
| 18 | import org.yuzu.yuzu_emu.model.GamesViewModel | 14 | import org.yuzu.yuzu_emu.model.GamesViewModel |
| 15 | import org.yuzu.yuzu_emu.viewholder.AbstractViewHolder | ||
| 19 | 16 | ||
| 20 | class FolderAdapter(val activity: FragmentActivity, val gamesViewModel: GamesViewModel) : | 17 | class FolderAdapter(val activity: FragmentActivity, val gamesViewModel: GamesViewModel) : |
| 21 | ListAdapter<GameDir, FolderAdapter.FolderViewHolder>( | 18 | AbstractDiffAdapter<GameDir, FolderAdapter.FolderViewHolder>() { |
| 22 | AsyncDifferConfig.Builder(DiffCallback()).build() | ||
| 23 | ) { | ||
| 24 | override fun onCreateViewHolder( | 19 | override fun onCreateViewHolder( |
| 25 | parent: ViewGroup, | 20 | parent: ViewGroup, |
| 26 | viewType: Int | 21 | viewType: Int |
| @@ -29,18 +24,11 @@ class FolderAdapter(val activity: FragmentActivity, val gamesViewModel: GamesVie | |||
| 29 | .also { return FolderViewHolder(it) } | 24 | .also { return FolderViewHolder(it) } |
| 30 | } | 25 | } |
| 31 | 26 | ||
| 32 | override fun onBindViewHolder(holder: FolderAdapter.FolderViewHolder, position: Int) = | ||
| 33 | holder.bind(currentList[position]) | ||
| 34 | |||
| 35 | inner class FolderViewHolder(val binding: CardFolderBinding) : | 27 | inner class FolderViewHolder(val binding: CardFolderBinding) : |
| 36 | RecyclerView.ViewHolder(binding.root) { | 28 | AbstractViewHolder<GameDir>(binding) { |
| 37 | private lateinit var gameDir: GameDir | 29 | override fun bind(model: GameDir) { |
| 38 | |||
| 39 | fun bind(gameDir: GameDir) { | ||
| 40 | this.gameDir = gameDir | ||
| 41 | |||
| 42 | binding.apply { | 30 | binding.apply { |
| 43 | path.text = Uri.parse(gameDir.uriString).path | 31 | path.text = Uri.parse(model.uriString).path |
| 44 | path.postDelayed( | 32 | path.postDelayed( |
| 45 | { | 33 | { |
| 46 | path.isSelected = true | 34 | path.isSelected = true |
| @@ -50,7 +38,7 @@ class FolderAdapter(val activity: FragmentActivity, val gamesViewModel: GamesVie | |||
| 50 | ) | 38 | ) |
| 51 | 39 | ||
| 52 | buttonEdit.setOnClickListener { | 40 | buttonEdit.setOnClickListener { |
| 53 | GameFolderPropertiesDialogFragment.newInstance(this@FolderViewHolder.gameDir) | 41 | GameFolderPropertiesDialogFragment.newInstance(model) |
| 54 | .show( | 42 | .show( |
| 55 | activity.supportFragmentManager, | 43 | activity.supportFragmentManager, |
| 56 | GameFolderPropertiesDialogFragment.TAG | 44 | GameFolderPropertiesDialogFragment.TAG |
| @@ -58,19 +46,9 @@ class FolderAdapter(val activity: FragmentActivity, val gamesViewModel: GamesVie | |||
| 58 | } | 46 | } |
| 59 | 47 | ||
| 60 | buttonDelete.setOnClickListener { | 48 | buttonDelete.setOnClickListener { |
| 61 | gamesViewModel.removeFolder(this@FolderViewHolder.gameDir) | 49 | gamesViewModel.removeFolder(model) |
| 62 | } | 50 | } |
| 63 | } | 51 | } |
| 64 | } | 52 | } |
| 65 | } | 53 | } |
| 66 | |||
| 67 | private class DiffCallback : DiffUtil.ItemCallback<GameDir>() { | ||
| 68 | override fun areItemsTheSame(oldItem: GameDir, newItem: GameDir): Boolean { | ||
| 69 | return oldItem == newItem | ||
| 70 | } | ||
| 71 | |||
| 72 | override fun areContentsTheSame(oldItem: GameDir, newItem: GameDir): Boolean { | ||
| 73 | return oldItem == newItem | ||
| 74 | } | ||
| 75 | } | ||
| 76 | } | 54 | } |
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/GameAdapter.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/GameAdapter.kt index a578f0de8..e26c2e0ab 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/GameAdapter.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/GameAdapter.kt | |||
| @@ -9,7 +9,6 @@ import android.graphics.drawable.LayerDrawable | |||
| 9 | import android.net.Uri | 9 | import android.net.Uri |
| 10 | import android.text.TextUtils | 10 | import android.text.TextUtils |
| 11 | import android.view.LayoutInflater | 11 | import android.view.LayoutInflater |
| 12 | import android.view.View | ||
| 13 | import android.view.ViewGroup | 12 | import android.view.ViewGroup |
| 14 | import android.widget.ImageView | 13 | import android.widget.ImageView |
| 15 | import android.widget.Toast | 14 | import android.widget.Toast |
| @@ -25,10 +24,6 @@ import androidx.lifecycle.ViewModelProvider | |||
| 25 | import androidx.lifecycle.lifecycleScope | 24 | import androidx.lifecycle.lifecycleScope |
| 26 | import androidx.navigation.findNavController | 25 | import androidx.navigation.findNavController |
| 27 | import androidx.preference.PreferenceManager | 26 | import androidx.preference.PreferenceManager |
| 28 | import androidx.recyclerview.widget.AsyncDifferConfig | ||
| 29 | import androidx.recyclerview.widget.DiffUtil | ||
| 30 | import androidx.recyclerview.widget.ListAdapter | ||
| 31 | import androidx.recyclerview.widget.RecyclerView | ||
| 32 | import kotlinx.coroutines.Dispatchers | 27 | import kotlinx.coroutines.Dispatchers |
| 33 | import kotlinx.coroutines.launch | 28 | import kotlinx.coroutines.launch |
| 34 | import kotlinx.coroutines.withContext | 29 | import kotlinx.coroutines.withContext |
| @@ -36,122 +31,26 @@ import org.yuzu.yuzu_emu.HomeNavigationDirections | |||
| 36 | import org.yuzu.yuzu_emu.R | 31 | import org.yuzu.yuzu_emu.R |
| 37 | import org.yuzu.yuzu_emu.YuzuApplication | 32 | import org.yuzu.yuzu_emu.YuzuApplication |
| 38 | import org.yuzu.yuzu_emu.activities.EmulationActivity | 33 | import org.yuzu.yuzu_emu.activities.EmulationActivity |
| 39 | import org.yuzu.yuzu_emu.adapters.GameAdapter.GameViewHolder | ||
| 40 | import org.yuzu.yuzu_emu.databinding.CardGameBinding | 34 | import org.yuzu.yuzu_emu.databinding.CardGameBinding |
| 41 | import org.yuzu.yuzu_emu.model.Game | 35 | import org.yuzu.yuzu_emu.model.Game |
| 42 | import org.yuzu.yuzu_emu.model.GamesViewModel | 36 | import org.yuzu.yuzu_emu.model.GamesViewModel |
| 43 | import org.yuzu.yuzu_emu.utils.GameIconUtils | 37 | import org.yuzu.yuzu_emu.utils.GameIconUtils |
| 38 | import org.yuzu.yuzu_emu.viewholder.AbstractViewHolder | ||
| 44 | 39 | ||
| 45 | class GameAdapter(private val activity: AppCompatActivity) : | 40 | class GameAdapter(private val activity: AppCompatActivity) : |
| 46 | ListAdapter<Game, GameViewHolder>(AsyncDifferConfig.Builder(DiffCallback()).build()), | 41 | AbstractDiffAdapter<Game, GameAdapter.GameViewHolder>() { |
| 47 | View.OnClickListener, | ||
| 48 | View.OnLongClickListener { | ||
| 49 | override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): GameViewHolder { | 42 | override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): GameViewHolder { |
| 50 | // Create a new view. | 43 | CardGameBinding.inflate(LayoutInflater.from(parent.context), parent, false) |
| 51 | val binding = CardGameBinding.inflate(LayoutInflater.from(parent.context), parent, false) | 44 | .also { return GameViewHolder(it) } |
| 52 | binding.cardGame.setOnClickListener(this) | ||
| 53 | binding.cardGame.setOnLongClickListener(this) | ||
| 54 | |||
| 55 | // Use that view to create a ViewHolder. | ||
| 56 | return GameViewHolder(binding) | ||
| 57 | } | ||
| 58 | |||
| 59 | override fun onBindViewHolder(holder: GameViewHolder, position: Int) = | ||
| 60 | holder.bind(currentList[position]) | ||
| 61 | |||
| 62 | override fun getItemCount(): Int = currentList.size | ||
| 63 | |||
| 64 | /** | ||
| 65 | * Launches the game that was clicked on. | ||
| 66 | * | ||
| 67 | * @param view The card representing the game the user wants to play. | ||
| 68 | */ | ||
| 69 | override fun onClick(view: View) { | ||
| 70 | val holder = view.tag as GameViewHolder | ||
| 71 | |||
| 72 | val gameExists = DocumentFile.fromSingleUri( | ||
| 73 | YuzuApplication.appContext, | ||
| 74 | Uri.parse(holder.game.path) | ||
| 75 | )?.exists() == true | ||
| 76 | if (!gameExists) { | ||
| 77 | Toast.makeText( | ||
| 78 | YuzuApplication.appContext, | ||
| 79 | R.string.loader_error_file_not_found, | ||
| 80 | Toast.LENGTH_LONG | ||
| 81 | ).show() | ||
| 82 | |||
| 83 | ViewModelProvider(activity)[GamesViewModel::class.java].reloadGames(true) | ||
| 84 | return | ||
| 85 | } | ||
| 86 | |||
| 87 | val preferences = PreferenceManager.getDefaultSharedPreferences(YuzuApplication.appContext) | ||
| 88 | preferences.edit() | ||
| 89 | .putLong( | ||
| 90 | holder.game.keyLastPlayedTime, | ||
| 91 | System.currentTimeMillis() | ||
| 92 | ) | ||
| 93 | .apply() | ||
| 94 | |||
| 95 | val openIntent = Intent(YuzuApplication.appContext, EmulationActivity::class.java).apply { | ||
| 96 | action = Intent.ACTION_VIEW | ||
| 97 | data = Uri.parse(holder.game.path) | ||
| 98 | } | ||
| 99 | |||
| 100 | activity.lifecycleScope.launch { | ||
| 101 | withContext(Dispatchers.IO) { | ||
| 102 | val layerDrawable = ResourcesCompat.getDrawable( | ||
| 103 | YuzuApplication.appContext.resources, | ||
| 104 | R.drawable.shortcut, | ||
| 105 | null | ||
| 106 | ) as LayerDrawable | ||
| 107 | layerDrawable.setDrawableByLayerId( | ||
| 108 | R.id.shortcut_foreground, | ||
| 109 | GameIconUtils.getGameIcon(activity, holder.game) | ||
| 110 | .toDrawable(YuzuApplication.appContext.resources) | ||
| 111 | ) | ||
| 112 | val inset = YuzuApplication.appContext.resources | ||
| 113 | .getDimensionPixelSize(R.dimen.icon_inset) | ||
| 114 | layerDrawable.setLayerInset(1, inset, inset, inset, inset) | ||
| 115 | val shortcut = | ||
| 116 | ShortcutInfoCompat.Builder(YuzuApplication.appContext, holder.game.path) | ||
| 117 | .setShortLabel(holder.game.title) | ||
| 118 | .setIcon( | ||
| 119 | IconCompat.createWithAdaptiveBitmap( | ||
| 120 | layerDrawable.toBitmap(config = Bitmap.Config.ARGB_8888) | ||
| 121 | ) | ||
| 122 | ) | ||
| 123 | .setIntent(openIntent) | ||
| 124 | .build() | ||
| 125 | ShortcutManagerCompat.pushDynamicShortcut(YuzuApplication.appContext, shortcut) | ||
| 126 | } | ||
| 127 | } | ||
| 128 | |||
| 129 | val action = HomeNavigationDirections.actionGlobalEmulationActivity(holder.game, true) | ||
| 130 | view.findNavController().navigate(action) | ||
| 131 | } | ||
| 132 | |||
| 133 | override fun onLongClick(view: View): Boolean { | ||
| 134 | val holder = view.tag as GameViewHolder | ||
| 135 | val action = HomeNavigationDirections.actionGlobalPerGamePropertiesFragment(holder.game) | ||
| 136 | view.findNavController().navigate(action) | ||
| 137 | return true | ||
| 138 | } | 45 | } |
| 139 | 46 | ||
| 140 | inner class GameViewHolder(val binding: CardGameBinding) : | 47 | inner class GameViewHolder(val binding: CardGameBinding) : |
| 141 | RecyclerView.ViewHolder(binding.root) { | 48 | AbstractViewHolder<Game>(binding) { |
| 142 | lateinit var game: Game | 49 | override fun bind(model: Game) { |
| 143 | |||
| 144 | init { | ||
| 145 | binding.cardGame.tag = this | ||
| 146 | } | ||
| 147 | |||
| 148 | fun bind(game: Game) { | ||
| 149 | this.game = game | ||
| 150 | |||
| 151 | binding.imageGameScreen.scaleType = ImageView.ScaleType.CENTER_CROP | 50 | binding.imageGameScreen.scaleType = ImageView.ScaleType.CENTER_CROP |
| 152 | GameIconUtils.loadGameIcon(game, binding.imageGameScreen) | 51 | GameIconUtils.loadGameIcon(model, binding.imageGameScreen) |
| 153 | 52 | ||
| 154 | binding.textGameTitle.text = game.title.replace("[\\t\\n\\r]+".toRegex(), " ") | 53 | binding.textGameTitle.text = model.title.replace("[\\t\\n\\r]+".toRegex(), " ") |
| 155 | 54 | ||
| 156 | binding.textGameTitle.postDelayed( | 55 | binding.textGameTitle.postDelayed( |
| 157 | { | 56 | { |
| @@ -160,16 +59,79 @@ class GameAdapter(private val activity: AppCompatActivity) : | |||
| 160 | }, | 59 | }, |
| 161 | 3000 | 60 | 3000 |
| 162 | ) | 61 | ) |
| 62 | |||
| 63 | binding.cardGame.setOnClickListener { onClick(model) } | ||
| 64 | binding.cardGame.setOnLongClickListener { onLongClick(model) } | ||
| 163 | } | 65 | } |
| 164 | } | ||
| 165 | 66 | ||
| 166 | private class DiffCallback : DiffUtil.ItemCallback<Game>() { | 67 | fun onClick(game: Game) { |
| 167 | override fun areItemsTheSame(oldItem: Game, newItem: Game): Boolean { | 68 | val gameExists = DocumentFile.fromSingleUri( |
| 168 | return oldItem == newItem | 69 | YuzuApplication.appContext, |
| 70 | Uri.parse(game.path) | ||
| 71 | )?.exists() == true | ||
| 72 | if (!gameExists) { | ||
| 73 | Toast.makeText( | ||
| 74 | YuzuApplication.appContext, | ||
| 75 | R.string.loader_error_file_not_found, | ||
| 76 | Toast.LENGTH_LONG | ||
| 77 | ).show() | ||
| 78 | |||
| 79 | ViewModelProvider(activity)[GamesViewModel::class.java].reloadGames(true) | ||
| 80 | return | ||
| 81 | } | ||
| 82 | |||
| 83 | val preferences = | ||
| 84 | PreferenceManager.getDefaultSharedPreferences(YuzuApplication.appContext) | ||
| 85 | preferences.edit() | ||
| 86 | .putLong( | ||
| 87 | game.keyLastPlayedTime, | ||
| 88 | System.currentTimeMillis() | ||
| 89 | ) | ||
| 90 | .apply() | ||
| 91 | |||
| 92 | val openIntent = | ||
| 93 | Intent(YuzuApplication.appContext, EmulationActivity::class.java).apply { | ||
| 94 | action = Intent.ACTION_VIEW | ||
| 95 | data = Uri.parse(game.path) | ||
| 96 | } | ||
| 97 | |||
| 98 | activity.lifecycleScope.launch { | ||
| 99 | withContext(Dispatchers.IO) { | ||
| 100 | val layerDrawable = ResourcesCompat.getDrawable( | ||
| 101 | YuzuApplication.appContext.resources, | ||
| 102 | R.drawable.shortcut, | ||
| 103 | null | ||
| 104 | ) as LayerDrawable | ||
| 105 | layerDrawable.setDrawableByLayerId( | ||
| 106 | R.id.shortcut_foreground, | ||
| 107 | GameIconUtils.getGameIcon(activity, game) | ||
| 108 | .toDrawable(YuzuApplication.appContext.resources) | ||
| 109 | ) | ||
| 110 | val inset = YuzuApplication.appContext.resources | ||
| 111 | .getDimensionPixelSize(R.dimen.icon_inset) | ||
| 112 | layerDrawable.setLayerInset(1, inset, inset, inset, inset) | ||
| 113 | val shortcut = | ||
| 114 | ShortcutInfoCompat.Builder(YuzuApplication.appContext, game.path) | ||
| 115 | .setShortLabel(game.title) | ||
| 116 | .setIcon( | ||
| 117 | IconCompat.createWithAdaptiveBitmap( | ||
| 118 | layerDrawable.toBitmap(config = Bitmap.Config.ARGB_8888) | ||
| 119 | ) | ||
| 120 | ) | ||
| 121 | .setIntent(openIntent) | ||
| 122 | .build() | ||
| 123 | ShortcutManagerCompat.pushDynamicShortcut(YuzuApplication.appContext, shortcut) | ||
| 124 | } | ||
| 125 | } | ||
| 126 | |||
| 127 | val action = HomeNavigationDirections.actionGlobalEmulationActivity(game, true) | ||
| 128 | binding.root.findNavController().navigate(action) | ||
| 169 | } | 129 | } |
| 170 | 130 | ||
| 171 | override fun areContentsTheSame(oldItem: Game, newItem: Game): Boolean { | 131 | fun onLongClick(game: Game): Boolean { |
| 172 | return oldItem == newItem | 132 | val action = HomeNavigationDirections.actionGlobalPerGamePropertiesFragment(game) |
| 133 | binding.root.findNavController().navigate(action) | ||
| 134 | return true | ||
| 173 | } | 135 | } |
| 174 | } | 136 | } |
| 175 | } | 137 | } |
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/GamePropertiesAdapter.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/GamePropertiesAdapter.kt index 95841d786..0046d5314 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/GamePropertiesAdapter.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/GamePropertiesAdapter.kt | |||
| @@ -12,23 +12,22 @@ import androidx.lifecycle.Lifecycle | |||
| 12 | import androidx.lifecycle.LifecycleOwner | 12 | import androidx.lifecycle.LifecycleOwner |
| 13 | import androidx.lifecycle.lifecycleScope | 13 | import androidx.lifecycle.lifecycleScope |
| 14 | import androidx.lifecycle.repeatOnLifecycle | 14 | import androidx.lifecycle.repeatOnLifecycle |
| 15 | import androidx.recyclerview.widget.RecyclerView | ||
| 16 | import kotlinx.coroutines.launch | 15 | import kotlinx.coroutines.launch |
| 17 | import org.yuzu.yuzu_emu.databinding.CardInstallableIconBinding | 16 | import org.yuzu.yuzu_emu.databinding.CardInstallableIconBinding |
| 18 | import org.yuzu.yuzu_emu.databinding.CardSimpleOutlinedBinding | 17 | import org.yuzu.yuzu_emu.databinding.CardSimpleOutlinedBinding |
| 19 | import org.yuzu.yuzu_emu.model.GameProperty | 18 | import org.yuzu.yuzu_emu.model.GameProperty |
| 20 | import org.yuzu.yuzu_emu.model.InstallableProperty | 19 | import org.yuzu.yuzu_emu.model.InstallableProperty |
| 21 | import org.yuzu.yuzu_emu.model.SubmenuProperty | 20 | import org.yuzu.yuzu_emu.model.SubmenuProperty |
| 21 | import org.yuzu.yuzu_emu.viewholder.AbstractViewHolder | ||
| 22 | 22 | ||
| 23 | class GamePropertiesAdapter( | 23 | class GamePropertiesAdapter( |
| 24 | private val viewLifecycle: LifecycleOwner, | 24 | private val viewLifecycle: LifecycleOwner, |
| 25 | private var properties: List<GameProperty> | 25 | private var properties: List<GameProperty> |
| 26 | ) : | 26 | ) : AbstractListAdapter<GameProperty, AbstractViewHolder<GameProperty>>(properties) { |
| 27 | RecyclerView.Adapter<GamePropertiesAdapter.GamePropertyViewHolder>() { | ||
| 28 | override fun onCreateViewHolder( | 27 | override fun onCreateViewHolder( |
| 29 | parent: ViewGroup, | 28 | parent: ViewGroup, |
| 30 | viewType: Int | 29 | viewType: Int |
| 31 | ): GamePropertyViewHolder { | 30 | ): AbstractViewHolder<GameProperty> { |
| 32 | val inflater = LayoutInflater.from(parent.context) | 31 | val inflater = LayoutInflater.from(parent.context) |
| 33 | return when (viewType) { | 32 | return when (viewType) { |
| 34 | PropertyType.Submenu.ordinal -> { | 33 | PropertyType.Submenu.ordinal -> { |
| @@ -51,11 +50,6 @@ class GamePropertiesAdapter( | |||
| 51 | } | 50 | } |
| 52 | } | 51 | } |
| 53 | 52 | ||
| 54 | override fun getItemCount(): Int = properties.size | ||
| 55 | |||
| 56 | override fun onBindViewHolder(holder: GamePropertyViewHolder, position: Int) = | ||
| 57 | holder.bind(properties[position]) | ||
| 58 | |||
| 59 | override fun getItemViewType(position: Int): Int { | 53 | override fun getItemViewType(position: Int): Int { |
| 60 | return when (properties[position]) { | 54 | return when (properties[position]) { |
| 61 | is SubmenuProperty -> PropertyType.Submenu.ordinal | 55 | is SubmenuProperty -> PropertyType.Submenu.ordinal |
| @@ -63,14 +57,10 @@ class GamePropertiesAdapter( | |||
| 63 | } | 57 | } |
| 64 | } | 58 | } |
| 65 | 59 | ||
| 66 | sealed class GamePropertyViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { | ||
| 67 | abstract fun bind(property: GameProperty) | ||
| 68 | } | ||
| 69 | |||
| 70 | inner class SubmenuPropertyViewHolder(val binding: CardSimpleOutlinedBinding) : | 60 | inner class SubmenuPropertyViewHolder(val binding: CardSimpleOutlinedBinding) : |
| 71 | GamePropertyViewHolder(binding.root) { | 61 | AbstractViewHolder<GameProperty>(binding) { |
| 72 | override fun bind(property: GameProperty) { | 62 | override fun bind(model: GameProperty) { |
| 73 | val submenuProperty = property as SubmenuProperty | 63 | val submenuProperty = model as SubmenuProperty |
| 74 | 64 | ||
| 75 | binding.root.setOnClickListener { | 65 | binding.root.setOnClickListener { |
| 76 | submenuProperty.action.invoke() | 66 | submenuProperty.action.invoke() |
| @@ -108,9 +98,9 @@ class GamePropertiesAdapter( | |||
| 108 | } | 98 | } |
| 109 | 99 | ||
| 110 | inner class InstallablePropertyViewHolder(val binding: CardInstallableIconBinding) : | 100 | inner class InstallablePropertyViewHolder(val binding: CardInstallableIconBinding) : |
| 111 | GamePropertyViewHolder(binding.root) { | 101 | AbstractViewHolder<GameProperty>(binding) { |
| 112 | override fun bind(property: GameProperty) { | 102 | override fun bind(model: GameProperty) { |
| 113 | val installableProperty = property as InstallableProperty | 103 | val installableProperty = model as InstallableProperty |
| 114 | 104 | ||
| 115 | binding.title.setText(installableProperty.titleId) | 105 | binding.title.setText(installableProperty.titleId) |
| 116 | binding.description.setText(installableProperty.descriptionId) | 106 | binding.description.setText(installableProperty.descriptionId) |
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/HomeSettingAdapter.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/HomeSettingAdapter.kt index 58ce343f4..b512845d5 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/HomeSettingAdapter.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/HomeSettingAdapter.kt | |||
| @@ -14,69 +14,37 @@ import androidx.lifecycle.Lifecycle | |||
| 14 | import androidx.lifecycle.LifecycleOwner | 14 | import androidx.lifecycle.LifecycleOwner |
| 15 | import androidx.lifecycle.lifecycleScope | 15 | import androidx.lifecycle.lifecycleScope |
| 16 | import androidx.lifecycle.repeatOnLifecycle | 16 | import androidx.lifecycle.repeatOnLifecycle |
| 17 | import androidx.recyclerview.widget.RecyclerView | ||
| 18 | import kotlinx.coroutines.launch | 17 | import kotlinx.coroutines.launch |
| 19 | import org.yuzu.yuzu_emu.R | 18 | import org.yuzu.yuzu_emu.R |
| 20 | import org.yuzu.yuzu_emu.databinding.CardHomeOptionBinding | 19 | import org.yuzu.yuzu_emu.databinding.CardHomeOptionBinding |
| 21 | import org.yuzu.yuzu_emu.fragments.MessageDialogFragment | 20 | import org.yuzu.yuzu_emu.fragments.MessageDialogFragment |
| 22 | import org.yuzu.yuzu_emu.model.HomeSetting | 21 | import org.yuzu.yuzu_emu.model.HomeSetting |
| 22 | import org.yuzu.yuzu_emu.viewholder.AbstractViewHolder | ||
| 23 | 23 | ||
| 24 | class HomeSettingAdapter( | 24 | class HomeSettingAdapter( |
| 25 | private val activity: AppCompatActivity, | 25 | private val activity: AppCompatActivity, |
| 26 | private val viewLifecycle: LifecycleOwner, | 26 | private val viewLifecycle: LifecycleOwner, |
| 27 | var options: List<HomeSetting> | 27 | options: List<HomeSetting> |
| 28 | ) : | 28 | ) : AbstractListAdapter<HomeSetting, HomeSettingAdapter.HomeOptionViewHolder>(options) { |
| 29 | RecyclerView.Adapter<HomeSettingAdapter.HomeOptionViewHolder>(), | ||
| 30 | View.OnClickListener { | ||
| 31 | override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): HomeOptionViewHolder { | 29 | override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): HomeOptionViewHolder { |
| 32 | val binding = | 30 | CardHomeOptionBinding.inflate(LayoutInflater.from(parent.context), parent, false) |
| 33 | CardHomeOptionBinding.inflate(LayoutInflater.from(parent.context), parent, false) | 31 | .also { return HomeOptionViewHolder(it) } |
| 34 | binding.root.setOnClickListener(this) | ||
| 35 | return HomeOptionViewHolder(binding) | ||
| 36 | } | ||
| 37 | |||
| 38 | override fun getItemCount(): Int { | ||
| 39 | return options.size | ||
| 40 | } | ||
| 41 | |||
| 42 | override fun onBindViewHolder(holder: HomeOptionViewHolder, position: Int) { | ||
| 43 | holder.bind(options[position]) | ||
| 44 | } | ||
| 45 | |||
| 46 | override fun onClick(view: View) { | ||
| 47 | val holder = view.tag as HomeOptionViewHolder | ||
| 48 | if (holder.option.isEnabled.invoke()) { | ||
| 49 | holder.option.onClick.invoke() | ||
| 50 | } else { | ||
| 51 | MessageDialogFragment.newInstance( | ||
| 52 | activity, | ||
| 53 | titleId = holder.option.disabledTitleId, | ||
| 54 | descriptionId = holder.option.disabledMessageId | ||
| 55 | ).show(activity.supportFragmentManager, MessageDialogFragment.TAG) | ||
| 56 | } | ||
| 57 | } | 32 | } |
| 58 | 33 | ||
| 59 | inner class HomeOptionViewHolder(val binding: CardHomeOptionBinding) : | 34 | inner class HomeOptionViewHolder(val binding: CardHomeOptionBinding) : |
| 60 | RecyclerView.ViewHolder(binding.root) { | 35 | AbstractViewHolder<HomeSetting>(binding) { |
| 61 | lateinit var option: HomeSetting | 36 | override fun bind(model: HomeSetting) { |
| 62 | 37 | binding.optionTitle.text = activity.resources.getString(model.titleId) | |
| 63 | init { | 38 | binding.optionDescription.text = activity.resources.getString(model.descriptionId) |
| 64 | itemView.tag = this | ||
| 65 | } | ||
| 66 | |||
| 67 | fun bind(option: HomeSetting) { | ||
| 68 | this.option = option | ||
| 69 | binding.optionTitle.text = activity.resources.getString(option.titleId) | ||
| 70 | binding.optionDescription.text = activity.resources.getString(option.descriptionId) | ||
| 71 | binding.optionIcon.setImageDrawable( | 39 | binding.optionIcon.setImageDrawable( |
| 72 | ResourcesCompat.getDrawable( | 40 | ResourcesCompat.getDrawable( |
| 73 | activity.resources, | 41 | activity.resources, |
| 74 | option.iconId, | 42 | model.iconId, |
| 75 | activity.theme | 43 | activity.theme |
| 76 | ) | 44 | ) |
| 77 | ) | 45 | ) |
| 78 | 46 | ||
| 79 | when (option.titleId) { | 47 | when (model.titleId) { |
| 80 | R.string.get_early_access -> | 48 | R.string.get_early_access -> |
| 81 | binding.optionLayout.background = | 49 | binding.optionLayout.background = |
| 82 | ContextCompat.getDrawable( | 50 | ContextCompat.getDrawable( |
| @@ -85,7 +53,7 @@ class HomeSettingAdapter( | |||
| 85 | ) | 53 | ) |
| 86 | } | 54 | } |
| 87 | 55 | ||
| 88 | if (!option.isEnabled.invoke()) { | 56 | if (!model.isEnabled.invoke()) { |
| 89 | binding.optionTitle.alpha = 0.5f | 57 | binding.optionTitle.alpha = 0.5f |
| 90 | binding.optionDescription.alpha = 0.5f | 58 | binding.optionDescription.alpha = 0.5f |
| 91 | binding.optionIcon.alpha = 0.5f | 59 | binding.optionIcon.alpha = 0.5f |
| @@ -93,7 +61,7 @@ class HomeSettingAdapter( | |||
| 93 | 61 | ||
| 94 | viewLifecycle.lifecycleScope.launch { | 62 | viewLifecycle.lifecycleScope.launch { |
| 95 | viewLifecycle.repeatOnLifecycle(Lifecycle.State.CREATED) { | 63 | viewLifecycle.repeatOnLifecycle(Lifecycle.State.CREATED) { |
| 96 | option.details.collect { updateOptionDetails(it) } | 64 | model.details.collect { updateOptionDetails(it) } |
| 97 | } | 65 | } |
| 98 | } | 66 | } |
| 99 | binding.optionDetail.postDelayed( | 67 | binding.optionDetail.postDelayed( |
| @@ -103,6 +71,20 @@ class HomeSettingAdapter( | |||
| 103 | }, | 71 | }, |
| 104 | 3000 | 72 | 3000 |
| 105 | ) | 73 | ) |
| 74 | |||
| 75 | binding.root.setOnClickListener { onClick(model) } | ||
| 76 | } | ||
| 77 | |||
| 78 | private fun onClick(model: HomeSetting) { | ||
| 79 | if (model.isEnabled.invoke()) { | ||
| 80 | model.onClick.invoke() | ||
| 81 | } else { | ||
| 82 | MessageDialogFragment.newInstance( | ||
| 83 | activity, | ||
| 84 | titleId = model.disabledTitleId, | ||
| 85 | descriptionId = model.disabledMessageId | ||
| 86 | ).show(activity.supportFragmentManager, MessageDialogFragment.TAG) | ||
| 87 | } | ||
| 106 | } | 88 | } |
| 107 | 89 | ||
| 108 | private fun updateOptionDetails(detailString: String) { | 90 | private fun updateOptionDetails(detailString: String) { |
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/InstallableAdapter.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/InstallableAdapter.kt index e960fbaab..4218c4e52 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/InstallableAdapter.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/InstallableAdapter.kt | |||
| @@ -6,43 +6,33 @@ package org.yuzu.yuzu_emu.adapters | |||
| 6 | import android.view.LayoutInflater | 6 | import android.view.LayoutInflater |
| 7 | import android.view.View | 7 | import android.view.View |
| 8 | import android.view.ViewGroup | 8 | import android.view.ViewGroup |
| 9 | import androidx.recyclerview.widget.RecyclerView | ||
| 10 | import org.yuzu.yuzu_emu.databinding.CardInstallableBinding | 9 | import org.yuzu.yuzu_emu.databinding.CardInstallableBinding |
| 11 | import org.yuzu.yuzu_emu.model.Installable | 10 | import org.yuzu.yuzu_emu.model.Installable |
| 11 | import org.yuzu.yuzu_emu.viewholder.AbstractViewHolder | ||
| 12 | 12 | ||
| 13 | class InstallableAdapter(private val installables: List<Installable>) : | 13 | class InstallableAdapter(installables: List<Installable>) : |
| 14 | RecyclerView.Adapter<InstallableAdapter.InstallableViewHolder>() { | 14 | AbstractListAdapter<Installable, InstallableAdapter.InstallableViewHolder>(installables) { |
| 15 | override fun onCreateViewHolder( | 15 | override fun onCreateViewHolder( |
| 16 | parent: ViewGroup, | 16 | parent: ViewGroup, |
| 17 | viewType: Int | 17 | viewType: Int |
| 18 | ): InstallableAdapter.InstallableViewHolder { | 18 | ): InstallableAdapter.InstallableViewHolder { |
| 19 | val binding = | 19 | CardInstallableBinding.inflate(LayoutInflater.from(parent.context), parent, false) |
| 20 | CardInstallableBinding.inflate(LayoutInflater.from(parent.context), parent, false) | 20 | .also { return InstallableViewHolder(it) } |
| 21 | return InstallableViewHolder(binding) | ||
| 22 | } | 21 | } |
| 23 | 22 | ||
| 24 | override fun getItemCount(): Int = installables.size | ||
| 25 | |||
| 26 | override fun onBindViewHolder(holder: InstallableAdapter.InstallableViewHolder, position: Int) = | ||
| 27 | holder.bind(installables[position]) | ||
| 28 | |||
| 29 | inner class InstallableViewHolder(val binding: CardInstallableBinding) : | 23 | inner class InstallableViewHolder(val binding: CardInstallableBinding) : |
| 30 | RecyclerView.ViewHolder(binding.root) { | 24 | AbstractViewHolder<Installable>(binding) { |
| 31 | lateinit var installable: Installable | 25 | override fun bind(model: Installable) { |
| 32 | 26 | binding.title.setText(model.titleId) | |
| 33 | fun bind(installable: Installable) { | 27 | binding.description.setText(model.descriptionId) |
| 34 | this.installable = installable | ||
| 35 | |||
| 36 | binding.title.setText(installable.titleId) | ||
| 37 | binding.description.setText(installable.descriptionId) | ||
| 38 | 28 | ||
| 39 | if (installable.install != null) { | 29 | if (model.install != null) { |
| 40 | binding.buttonInstall.visibility = View.VISIBLE | 30 | binding.buttonInstall.visibility = View.VISIBLE |
| 41 | binding.buttonInstall.setOnClickListener { installable.install.invoke() } | 31 | binding.buttonInstall.setOnClickListener { model.install.invoke() } |
| 42 | } | 32 | } |
| 43 | if (installable.export != null) { | 33 | if (model.export != null) { |
| 44 | binding.buttonExport.visibility = View.VISIBLE | 34 | binding.buttonExport.visibility = View.VISIBLE |
| 45 | binding.buttonExport.setOnClickListener { installable.export.invoke() } | 35 | binding.buttonExport.setOnClickListener { model.export.invoke() } |
| 46 | } | 36 | } |
| 47 | } | 37 | } |
| 48 | } | 38 | } |
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/LicenseAdapter.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/LicenseAdapter.kt index bc6ff1364..38bb1f96f 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/LicenseAdapter.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/LicenseAdapter.kt | |||
| @@ -7,49 +7,33 @@ import android.view.LayoutInflater | |||
| 7 | import android.view.View | 7 | import android.view.View |
| 8 | import android.view.ViewGroup | 8 | import android.view.ViewGroup |
| 9 | import androidx.appcompat.app.AppCompatActivity | 9 | import androidx.appcompat.app.AppCompatActivity |
| 10 | import androidx.recyclerview.widget.RecyclerView | ||
| 11 | import androidx.recyclerview.widget.RecyclerView.ViewHolder | ||
| 12 | import org.yuzu.yuzu_emu.YuzuApplication | ||
| 13 | import org.yuzu.yuzu_emu.databinding.ListItemSettingBinding | 10 | import org.yuzu.yuzu_emu.databinding.ListItemSettingBinding |
| 14 | import org.yuzu.yuzu_emu.fragments.LicenseBottomSheetDialogFragment | 11 | import org.yuzu.yuzu_emu.fragments.LicenseBottomSheetDialogFragment |
| 15 | import org.yuzu.yuzu_emu.model.License | 12 | import org.yuzu.yuzu_emu.model.License |
| 13 | import org.yuzu.yuzu_emu.viewholder.AbstractViewHolder | ||
| 16 | 14 | ||
| 17 | class LicenseAdapter(private val activity: AppCompatActivity, var licenses: List<License>) : | 15 | class LicenseAdapter(private val activity: AppCompatActivity, licenses: List<License>) : |
| 18 | RecyclerView.Adapter<LicenseAdapter.LicenseViewHolder>(), | 16 | AbstractListAdapter<License, LicenseAdapter.LicenseViewHolder>(licenses) { |
| 19 | View.OnClickListener { | ||
| 20 | override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): LicenseViewHolder { | 17 | override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): LicenseViewHolder { |
| 21 | val binding = | 18 | ListItemSettingBinding.inflate(LayoutInflater.from(parent.context), parent, false) |
| 22 | ListItemSettingBinding.inflate(LayoutInflater.from(parent.context), parent, false) | 19 | .also { return LicenseViewHolder(it) } |
| 23 | binding.root.setOnClickListener(this) | ||
| 24 | return LicenseViewHolder(binding) | ||
| 25 | } | 20 | } |
| 26 | 21 | ||
| 27 | override fun getItemCount(): Int = licenses.size | 22 | inner class LicenseViewHolder(val binding: ListItemSettingBinding) : |
| 23 | AbstractViewHolder<License>(binding) { | ||
| 24 | override fun bind(model: License) { | ||
| 25 | binding.apply { | ||
| 26 | textSettingName.text = root.context.getString(model.titleId) | ||
| 27 | textSettingDescription.text = root.context.getString(model.descriptionId) | ||
| 28 | textSettingValue.visibility = View.GONE | ||
| 28 | 29 | ||
| 29 | override fun onBindViewHolder(holder: LicenseViewHolder, position: Int) { | 30 | root.setOnClickListener { onClick(model) } |
| 30 | holder.bind(licenses[position]) | 31 | } |
| 31 | } | ||
| 32 | |||
| 33 | override fun onClick(view: View) { | ||
| 34 | val license = (view.tag as LicenseViewHolder).license | ||
| 35 | LicenseBottomSheetDialogFragment.newInstance(license) | ||
| 36 | .show(activity.supportFragmentManager, LicenseBottomSheetDialogFragment.TAG) | ||
| 37 | } | ||
| 38 | |||
| 39 | inner class LicenseViewHolder(val binding: ListItemSettingBinding) : ViewHolder(binding.root) { | ||
| 40 | lateinit var license: License | ||
| 41 | |||
| 42 | init { | ||
| 43 | itemView.tag = this | ||
| 44 | } | 32 | } |
| 45 | 33 | ||
| 46 | fun bind(license: License) { | 34 | private fun onClick(license: License) { |
| 47 | this.license = license | 35 | LicenseBottomSheetDialogFragment.newInstance(license) |
| 48 | 36 | .show(activity.supportFragmentManager, LicenseBottomSheetDialogFragment.TAG) | |
| 49 | val context = YuzuApplication.appContext | ||
| 50 | binding.textSettingName.text = context.getString(license.titleId) | ||
| 51 | binding.textSettingDescription.text = context.getString(license.descriptionId) | ||
| 52 | binding.textSettingValue.visibility = View.GONE | ||
| 53 | } | 37 | } |
| 54 | } | 38 | } |
| 55 | } | 39 | } |
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/SetupAdapter.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/SetupAdapter.kt index 6b46d359e..02118e1a8 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/SetupAdapter.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/SetupAdapter.kt | |||
| @@ -10,7 +10,6 @@ import android.view.ViewGroup | |||
| 10 | import androidx.appcompat.app.AppCompatActivity | 10 | import androidx.appcompat.app.AppCompatActivity |
| 11 | import androidx.core.content.res.ResourcesCompat | 11 | import androidx.core.content.res.ResourcesCompat |
| 12 | import androidx.lifecycle.ViewModelProvider | 12 | import androidx.lifecycle.ViewModelProvider |
| 13 | import androidx.recyclerview.widget.RecyclerView | ||
| 14 | import com.google.android.material.button.MaterialButton | 13 | import com.google.android.material.button.MaterialButton |
| 15 | import org.yuzu.yuzu_emu.databinding.PageSetupBinding | 14 | import org.yuzu.yuzu_emu.databinding.PageSetupBinding |
| 16 | import org.yuzu.yuzu_emu.model.HomeViewModel | 15 | import org.yuzu.yuzu_emu.model.HomeViewModel |
| @@ -18,31 +17,19 @@ import org.yuzu.yuzu_emu.model.SetupCallback | |||
| 18 | import org.yuzu.yuzu_emu.model.SetupPage | 17 | import org.yuzu.yuzu_emu.model.SetupPage |
| 19 | import org.yuzu.yuzu_emu.model.StepState | 18 | import org.yuzu.yuzu_emu.model.StepState |
| 20 | import org.yuzu.yuzu_emu.utils.ViewUtils | 19 | import org.yuzu.yuzu_emu.utils.ViewUtils |
| 20 | import org.yuzu.yuzu_emu.viewholder.AbstractViewHolder | ||
| 21 | 21 | ||
| 22 | class SetupAdapter(val activity: AppCompatActivity, val pages: List<SetupPage>) : | 22 | class SetupAdapter(val activity: AppCompatActivity, pages: List<SetupPage>) : |
| 23 | RecyclerView.Adapter<SetupAdapter.SetupPageViewHolder>() { | 23 | AbstractListAdapter<SetupPage, SetupAdapter.SetupPageViewHolder>(pages) { |
| 24 | override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): SetupPageViewHolder { | 24 | override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): SetupPageViewHolder { |
| 25 | val binding = PageSetupBinding.inflate(LayoutInflater.from(parent.context), parent, false) | 25 | PageSetupBinding.inflate(LayoutInflater.from(parent.context), parent, false) |
| 26 | return SetupPageViewHolder(binding) | 26 | .also { return SetupPageViewHolder(it) } |
| 27 | } | 27 | } |
| 28 | 28 | ||
| 29 | override fun getItemCount(): Int = pages.size | ||
| 30 | |||
| 31 | override fun onBindViewHolder(holder: SetupPageViewHolder, position: Int) = | ||
| 32 | holder.bind(pages[position]) | ||
| 33 | |||
| 34 | inner class SetupPageViewHolder(val binding: PageSetupBinding) : | 29 | inner class SetupPageViewHolder(val binding: PageSetupBinding) : |
| 35 | RecyclerView.ViewHolder(binding.root), SetupCallback { | 30 | AbstractViewHolder<SetupPage>(binding), SetupCallback { |
| 36 | lateinit var page: SetupPage | 31 | override fun bind(model: SetupPage) { |
| 37 | 32 | if (model.stepCompleted.invoke() == StepState.COMPLETE) { | |
| 38 | init { | ||
| 39 | itemView.tag = this | ||
| 40 | } | ||
| 41 | |||
| 42 | fun bind(page: SetupPage) { | ||
| 43 | this.page = page | ||
| 44 | |||
| 45 | if (page.stepCompleted.invoke() == StepState.COMPLETE) { | ||
| 46 | binding.buttonAction.visibility = View.INVISIBLE | 33 | binding.buttonAction.visibility = View.INVISIBLE |
| 47 | binding.textConfirmation.visibility = View.VISIBLE | 34 | binding.textConfirmation.visibility = View.VISIBLE |
| 48 | } | 35 | } |
| @@ -50,31 +37,31 @@ class SetupAdapter(val activity: AppCompatActivity, val pages: List<SetupPage>) | |||
| 50 | binding.icon.setImageDrawable( | 37 | binding.icon.setImageDrawable( |
| 51 | ResourcesCompat.getDrawable( | 38 | ResourcesCompat.getDrawable( |
| 52 | activity.resources, | 39 | activity.resources, |
| 53 | page.iconId, | 40 | model.iconId, |
| 54 | activity.theme | 41 | activity.theme |
| 55 | ) | 42 | ) |
| 56 | ) | 43 | ) |
| 57 | binding.textTitle.text = activity.resources.getString(page.titleId) | 44 | binding.textTitle.text = activity.resources.getString(model.titleId) |
| 58 | binding.textDescription.text = | 45 | binding.textDescription.text = |
| 59 | Html.fromHtml(activity.resources.getString(page.descriptionId), 0) | 46 | Html.fromHtml(activity.resources.getString(model.descriptionId), 0) |
| 60 | 47 | ||
| 61 | binding.buttonAction.apply { | 48 | binding.buttonAction.apply { |
| 62 | text = activity.resources.getString(page.buttonTextId) | 49 | text = activity.resources.getString(model.buttonTextId) |
| 63 | if (page.buttonIconId != 0) { | 50 | if (model.buttonIconId != 0) { |
| 64 | icon = ResourcesCompat.getDrawable( | 51 | icon = ResourcesCompat.getDrawable( |
| 65 | activity.resources, | 52 | activity.resources, |
| 66 | page.buttonIconId, | 53 | model.buttonIconId, |
| 67 | activity.theme | 54 | activity.theme |
| 68 | ) | 55 | ) |
| 69 | } | 56 | } |
| 70 | iconGravity = | 57 | iconGravity = |
| 71 | if (page.leftAlignedIcon) { | 58 | if (model.leftAlignedIcon) { |
| 72 | MaterialButton.ICON_GRAVITY_START | 59 | MaterialButton.ICON_GRAVITY_START |
| 73 | } else { | 60 | } else { |
| 74 | MaterialButton.ICON_GRAVITY_END | 61 | MaterialButton.ICON_GRAVITY_END |
| 75 | } | 62 | } |
| 76 | setOnClickListener { | 63 | setOnClickListener { |
| 77 | page.buttonAction.invoke(this@SetupPageViewHolder) | 64 | model.buttonAction.invoke(this@SetupPageViewHolder) |
| 78 | } | 65 | } |
| 79 | } | 66 | } |
| 80 | } | 67 | } |
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/AboutFragment.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/AboutFragment.kt index a1620fbb7..5b5f800c1 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/AboutFragment.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/AboutFragment.kt | |||
| @@ -76,8 +76,8 @@ class AboutFragment : Fragment() { | |||
| 76 | binding.root.findNavController().navigate(R.id.action_aboutFragment_to_licensesFragment) | 76 | binding.root.findNavController().navigate(R.id.action_aboutFragment_to_licensesFragment) |
| 77 | } | 77 | } |
| 78 | 78 | ||
| 79 | binding.textBuildHash.text = BuildConfig.GIT_HASH | 79 | binding.textVersionName.text = BuildConfig.VERSION_NAME |
| 80 | binding.buttonBuildHash.setOnClickListener { | 80 | binding.textVersionName.setOnClickListener { |
| 81 | val clipBoard = | 81 | val clipBoard = |
| 82 | requireContext().getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager | 82 | requireContext().getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager |
| 83 | val clip = ClipData.newPlainText(getString(R.string.build), BuildConfig.GIT_HASH) | 83 | val clip = ClipData.newPlainText(getString(R.string.build), BuildConfig.GIT_HASH) |
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/DriverManagerFragment.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/DriverManagerFragment.kt index cc71254dc..9dabb9c41 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/DriverManagerFragment.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/DriverManagerFragment.kt | |||
| @@ -3,6 +3,7 @@ | |||
| 3 | 3 | ||
| 4 | package org.yuzu.yuzu_emu.fragments | 4 | package org.yuzu.yuzu_emu.fragments |
| 5 | 5 | ||
| 6 | import android.annotation.SuppressLint | ||
| 6 | import android.os.Bundle | 7 | import android.os.Bundle |
| 7 | import android.view.LayoutInflater | 8 | import android.view.LayoutInflater |
| 8 | import android.view.View | 9 | import android.view.View |
| @@ -13,20 +14,26 @@ import androidx.core.view.WindowInsetsCompat | |||
| 13 | import androidx.core.view.updatePadding | 14 | import androidx.core.view.updatePadding |
| 14 | import androidx.fragment.app.Fragment | 15 | import androidx.fragment.app.Fragment |
| 15 | import androidx.fragment.app.activityViewModels | 16 | import androidx.fragment.app.activityViewModels |
| 17 | import androidx.lifecycle.Lifecycle | ||
| 16 | import androidx.lifecycle.lifecycleScope | 18 | import androidx.lifecycle.lifecycleScope |
| 19 | import androidx.lifecycle.repeatOnLifecycle | ||
| 17 | import androidx.navigation.findNavController | 20 | import androidx.navigation.findNavController |
| 18 | import androidx.navigation.fragment.navArgs | 21 | import androidx.navigation.fragment.navArgs |
| 19 | import androidx.recyclerview.widget.GridLayoutManager | 22 | import androidx.recyclerview.widget.GridLayoutManager |
| 20 | import com.google.android.material.transition.MaterialSharedAxis | 23 | import com.google.android.material.transition.MaterialSharedAxis |
| 21 | import kotlinx.coroutines.flow.collectLatest | 24 | import kotlinx.coroutines.Dispatchers |
| 22 | import kotlinx.coroutines.launch | 25 | import kotlinx.coroutines.launch |
| 26 | import kotlinx.coroutines.withContext | ||
| 23 | import org.yuzu.yuzu_emu.R | 27 | import org.yuzu.yuzu_emu.R |
| 24 | import org.yuzu.yuzu_emu.adapters.DriverAdapter | 28 | import org.yuzu.yuzu_emu.adapters.DriverAdapter |
| 25 | import org.yuzu.yuzu_emu.databinding.FragmentDriverManagerBinding | 29 | import org.yuzu.yuzu_emu.databinding.FragmentDriverManagerBinding |
| 30 | import org.yuzu.yuzu_emu.features.settings.model.StringSetting | ||
| 31 | import org.yuzu.yuzu_emu.model.Driver.Companion.toDriver | ||
| 26 | import org.yuzu.yuzu_emu.model.DriverViewModel | 32 | import org.yuzu.yuzu_emu.model.DriverViewModel |
| 27 | import org.yuzu.yuzu_emu.model.HomeViewModel | 33 | import org.yuzu.yuzu_emu.model.HomeViewModel |
| 28 | import org.yuzu.yuzu_emu.utils.FileUtil | 34 | import org.yuzu.yuzu_emu.utils.FileUtil |
| 29 | import org.yuzu.yuzu_emu.utils.GpuDriverHelper | 35 | import org.yuzu.yuzu_emu.utils.GpuDriverHelper |
| 36 | import org.yuzu.yuzu_emu.utils.NativeConfig | ||
| 30 | import java.io.File | 37 | import java.io.File |
| 31 | import java.io.IOException | 38 | import java.io.IOException |
| 32 | 39 | ||
| @@ -55,12 +62,43 @@ class DriverManagerFragment : Fragment() { | |||
| 55 | return binding.root | 62 | return binding.root |
| 56 | } | 63 | } |
| 57 | 64 | ||
| 65 | // This is using the correct scope, lint is just acting up | ||
| 66 | @SuppressLint("UnsafeRepeatOnLifecycleDetector") | ||
| 58 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) { | 67 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) { |
| 59 | super.onViewCreated(view, savedInstanceState) | 68 | super.onViewCreated(view, savedInstanceState) |
| 60 | homeViewModel.setNavigationVisibility(visible = false, animated = true) | 69 | homeViewModel.setNavigationVisibility(visible = false, animated = true) |
| 61 | homeViewModel.setStatusBarShadeVisibility(visible = false) | 70 | homeViewModel.setStatusBarShadeVisibility(visible = false) |
| 62 | 71 | ||
| 63 | driverViewModel.onOpenDriverManager(args.game) | 72 | driverViewModel.onOpenDriverManager(args.game) |
| 73 | if (NativeConfig.isPerGameConfigLoaded()) { | ||
| 74 | binding.toolbarDrivers.inflateMenu(R.menu.menu_driver_manager) | ||
| 75 | driverViewModel.showClearButton(!StringSetting.DRIVER_PATH.global) | ||
| 76 | binding.toolbarDrivers.setOnMenuItemClickListener { | ||
| 77 | when (it.itemId) { | ||
| 78 | R.id.menu_driver_clear -> { | ||
| 79 | StringSetting.DRIVER_PATH.global = true | ||
| 80 | driverViewModel.updateDriverList() | ||
| 81 | (binding.listDrivers.adapter as DriverAdapter) | ||
| 82 | .replaceList(driverViewModel.driverList.value) | ||
| 83 | driverViewModel.showClearButton(false) | ||
| 84 | true | ||
| 85 | } | ||
| 86 | |||
| 87 | else -> false | ||
| 88 | } | ||
| 89 | } | ||
| 90 | |||
| 91 | viewLifecycleOwner.lifecycleScope.apply { | ||
| 92 | launch { | ||
| 93 | repeatOnLifecycle(Lifecycle.State.STARTED) { | ||
| 94 | driverViewModel.showClearButton.collect { | ||
| 95 | binding.toolbarDrivers.menu | ||
| 96 | .findItem(R.id.menu_driver_clear).isVisible = it | ||
| 97 | } | ||
| 98 | } | ||
| 99 | } | ||
| 100 | } | ||
| 101 | } | ||
| 64 | 102 | ||
| 65 | if (!driverViewModel.isInteractionAllowed.value) { | 103 | if (!driverViewModel.isInteractionAllowed.value) { |
| 66 | DriversLoadingDialogFragment().show( | 104 | DriversLoadingDialogFragment().show( |
| @@ -85,25 +123,6 @@ class DriverManagerFragment : Fragment() { | |||
| 85 | adapter = DriverAdapter(driverViewModel) | 123 | adapter = DriverAdapter(driverViewModel) |
| 86 | } | 124 | } |
| 87 | 125 | ||
| 88 | viewLifecycleOwner.lifecycleScope.apply { | ||
| 89 | launch { | ||
| 90 | driverViewModel.driverList.collectLatest { | ||
| 91 | (binding.listDrivers.adapter as DriverAdapter).submitList(it) | ||
| 92 | } | ||
| 93 | } | ||
| 94 | launch { | ||
| 95 | driverViewModel.newDriverInstalled.collect { | ||
| 96 | if (_binding != null && it) { | ||
| 97 | (binding.listDrivers.adapter as DriverAdapter).apply { | ||
| 98 | notifyItemChanged(driverViewModel.previouslySelectedDriver) | ||
| 99 | notifyItemChanged(driverViewModel.selectedDriver) | ||
| 100 | driverViewModel.setNewDriverInstalled(false) | ||
| 101 | } | ||
| 102 | } | ||
| 103 | } | ||
| 104 | } | ||
| 105 | } | ||
| 106 | |||
| 107 | setInsets() | 126 | setInsets() |
| 108 | } | 127 | } |
| 109 | 128 | ||
| @@ -160,7 +179,7 @@ class DriverManagerFragment : Fragment() { | |||
| 160 | false | 179 | false |
| 161 | ) { | 180 | ) { |
| 162 | val driverPath = | 181 | val driverPath = |
| 163 | "${GpuDriverHelper.driverStoragePath}/${FileUtil.getFilename(result)}" | 182 | "${GpuDriverHelper.driverStoragePath}${FileUtil.getFilename(result)}" |
| 164 | val driverFile = File(driverPath) | 183 | val driverFile = File(driverPath) |
| 165 | 184 | ||
| 166 | // Ignore file exceptions when a user selects an invalid zip | 185 | // Ignore file exceptions when a user selects an invalid zip |
| @@ -177,12 +196,21 @@ class DriverManagerFragment : Fragment() { | |||
| 177 | 196 | ||
| 178 | val driverData = GpuDriverHelper.getMetadataFromZip(driverFile) | 197 | val driverData = GpuDriverHelper.getMetadataFromZip(driverFile) |
| 179 | val driverInList = | 198 | val driverInList = |
| 180 | driverViewModel.driverList.value.firstOrNull { it.second == driverData } | 199 | driverViewModel.driverData.firstOrNull { it.second == driverData } |
| 181 | if (driverInList != null) { | 200 | if (driverInList != null) { |
| 182 | return@newInstance getString(R.string.driver_already_installed) | 201 | return@newInstance getString(R.string.driver_already_installed) |
| 183 | } else { | 202 | } else { |
| 184 | driverViewModel.addDriver(Pair(driverPath, driverData)) | 203 | driverViewModel.onDriverAdded(Pair(driverPath, driverData)) |
| 185 | driverViewModel.setNewDriverInstalled(true) | 204 | withContext(Dispatchers.Main) { |
| 205 | if (_binding != null) { | ||
| 206 | val adapter = binding.listDrivers.adapter as DriverAdapter | ||
| 207 | adapter.addItem(driverData.toDriver()) | ||
| 208 | adapter.selectItem(adapter.currentList.indices.last) | ||
| 209 | driverViewModel.showClearButton(!StringSetting.DRIVER_PATH.global) | ||
| 210 | binding.listDrivers | ||
| 211 | .smoothScrollToPosition(adapter.currentList.indices.last) | ||
| 212 | } | ||
| 213 | } | ||
| 186 | } | 214 | } |
| 187 | return@newInstance Any() | 215 | return@newInstance Any() |
| 188 | }.show(childFragmentManager, IndeterminateProgressDialogFragment.TAG) | 216 | }.show(childFragmentManager, IndeterminateProgressDialogFragment.TAG) |
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/Driver.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/Driver.kt new file mode 100644 index 000000000..de342212a --- /dev/null +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/Driver.kt | |||
| @@ -0,0 +1,27 @@ | |||
| 1 | // SPDX-FileCopyrightText: 2024 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | package org.yuzu.yuzu_emu.model | ||
| 5 | |||
| 6 | import org.yuzu.yuzu_emu.utils.GpuDriverMetadata | ||
| 7 | |||
| 8 | data class Driver( | ||
| 9 | override var selected: Boolean, | ||
| 10 | val title: String, | ||
| 11 | val version: String = "", | ||
| 12 | val description: String = "" | ||
| 13 | ) : SelectableItem { | ||
| 14 | override fun onSelectionStateChanged(selected: Boolean) { | ||
| 15 | this.selected = selected | ||
| 16 | } | ||
| 17 | |||
| 18 | companion object { | ||
| 19 | fun GpuDriverMetadata.toDriver(selected: Boolean = false): Driver = | ||
| 20 | Driver( | ||
| 21 | selected, | ||
| 22 | this.name ?: "", | ||
| 23 | this.version ?: "", | ||
| 24 | this.description ?: "" | ||
| 25 | ) | ||
| 26 | } | ||
| 27 | } | ||
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/DriverViewModel.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/DriverViewModel.kt index 76accf8f3..15ae3a42b 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/DriverViewModel.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/DriverViewModel.kt | |||
| @@ -9,6 +9,7 @@ import kotlinx.coroutines.Dispatchers | |||
| 9 | import kotlinx.coroutines.flow.MutableStateFlow | 9 | import kotlinx.coroutines.flow.MutableStateFlow |
| 10 | import kotlinx.coroutines.flow.SharingStarted | 10 | import kotlinx.coroutines.flow.SharingStarted |
| 11 | import kotlinx.coroutines.flow.StateFlow | 11 | import kotlinx.coroutines.flow.StateFlow |
| 12 | import kotlinx.coroutines.flow.asStateFlow | ||
| 12 | import kotlinx.coroutines.flow.combine | 13 | import kotlinx.coroutines.flow.combine |
| 13 | import kotlinx.coroutines.flow.stateIn | 14 | import kotlinx.coroutines.flow.stateIn |
| 14 | import kotlinx.coroutines.launch | 15 | import kotlinx.coroutines.launch |
| @@ -17,11 +18,10 @@ import org.yuzu.yuzu_emu.R | |||
| 17 | import org.yuzu.yuzu_emu.YuzuApplication | 18 | import org.yuzu.yuzu_emu.YuzuApplication |
| 18 | import org.yuzu.yuzu_emu.features.settings.model.StringSetting | 19 | import org.yuzu.yuzu_emu.features.settings.model.StringSetting |
| 19 | import org.yuzu.yuzu_emu.features.settings.utils.SettingsFile | 20 | import org.yuzu.yuzu_emu.features.settings.utils.SettingsFile |
| 20 | import org.yuzu.yuzu_emu.utils.FileUtil | 21 | import org.yuzu.yuzu_emu.model.Driver.Companion.toDriver |
| 21 | import org.yuzu.yuzu_emu.utils.GpuDriverHelper | 22 | import org.yuzu.yuzu_emu.utils.GpuDriverHelper |
| 22 | import org.yuzu.yuzu_emu.utils.GpuDriverMetadata | 23 | import org.yuzu.yuzu_emu.utils.GpuDriverMetadata |
| 23 | import org.yuzu.yuzu_emu.utils.NativeConfig | 24 | import org.yuzu.yuzu_emu.utils.NativeConfig |
| 24 | import java.io.BufferedOutputStream | ||
| 25 | import java.io.File | 25 | import java.io.File |
| 26 | 26 | ||
| 27 | class DriverViewModel : ViewModel() { | 27 | class DriverViewModel : ViewModel() { |
| @@ -38,97 +38,81 @@ class DriverViewModel : ViewModel() { | |||
| 38 | !loading && ready && !deleting | 38 | !loading && ready && !deleting |
| 39 | }.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), initialValue = false) | 39 | }.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), initialValue = false) |
| 40 | 40 | ||
| 41 | private val _driverList = MutableStateFlow(GpuDriverHelper.getDrivers()) | 41 | var driverData = GpuDriverHelper.getDrivers() |
| 42 | val driverList: StateFlow<MutableList<Pair<String, GpuDriverMetadata>>> get() = _driverList | ||
| 43 | 42 | ||
| 44 | var previouslySelectedDriver = 0 | 43 | private val _driverList = MutableStateFlow(emptyList<Driver>()) |
| 45 | var selectedDriver = -1 | 44 | val driverList: StateFlow<List<Driver>> get() = _driverList |
| 46 | 45 | ||
| 47 | // Used for showing which driver is currently installed within the driver manager card | 46 | // Used for showing which driver is currently installed within the driver manager card |
| 48 | private val _selectedDriverTitle = MutableStateFlow("") | 47 | private val _selectedDriverTitle = MutableStateFlow("") |
| 49 | val selectedDriverTitle: StateFlow<String> get() = _selectedDriverTitle | 48 | val selectedDriverTitle: StateFlow<String> get() = _selectedDriverTitle |
| 50 | 49 | ||
| 51 | private val _newDriverInstalled = MutableStateFlow(false) | 50 | private val _showClearButton = MutableStateFlow(false) |
| 52 | val newDriverInstalled: StateFlow<Boolean> get() = _newDriverInstalled | 51 | val showClearButton = _showClearButton.asStateFlow() |
| 53 | 52 | ||
| 54 | val driversToDelete = mutableListOf<String>() | 53 | private val driversToDelete = mutableListOf<String>() |
| 55 | 54 | ||
| 56 | init { | 55 | init { |
| 57 | val currentDriverMetadata = GpuDriverHelper.installedCustomDriverData | 56 | updateDriverList() |
| 58 | findSelectedDriver(currentDriverMetadata) | 57 | updateDriverNameForGame(null) |
| 59 | 58 | } | |
| 60 | // If a user had installed a driver before the manager was implemented, this zips | ||
| 61 | // the installed driver to UserData/gpu_drivers/CustomDriver.zip so that it can | ||
| 62 | // be indexed and exported as expected. | ||
| 63 | if (selectedDriver == -1) { | ||
| 64 | val driverToSave = | ||
| 65 | File(GpuDriverHelper.driverStoragePath, "CustomDriver.zip") | ||
| 66 | driverToSave.createNewFile() | ||
| 67 | FileUtil.zipFromInternalStorage( | ||
| 68 | File(GpuDriverHelper.driverInstallationPath!!), | ||
| 69 | GpuDriverHelper.driverInstallationPath!!, | ||
| 70 | BufferedOutputStream(driverToSave.outputStream()) | ||
| 71 | ) | ||
| 72 | _driverList.value.add(Pair(driverToSave.path, currentDriverMetadata)) | ||
| 73 | setSelectedDriverIndex(_driverList.value.size - 1) | ||
| 74 | } | ||
| 75 | 59 | ||
| 76 | // If a user had installed a driver before the config was reworked to be multiplatform, | 60 | fun reloadDriverData() { |
| 77 | // we have save the path of the previously selected driver to the new setting. | 61 | _areDriversLoading.value = true |
| 78 | if (StringSetting.DRIVER_PATH.getString(true).isEmpty() && selectedDriver > 0 && | 62 | driverData = GpuDriverHelper.getDrivers() |
| 79 | StringSetting.DRIVER_PATH.global | 63 | updateDriverList() |
| 80 | ) { | 64 | _areDriversLoading.value = false |
| 81 | StringSetting.DRIVER_PATH.setString(_driverList.value[selectedDriver].first) | 65 | } |
| 82 | NativeConfig.saveGlobalConfig() | 66 | |
| 83 | } else { | 67 | fun updateDriverList() { |
| 84 | findSelectedDriver(GpuDriverHelper.customDriverSettingData) | 68 | val selectedDriver = GpuDriverHelper.customDriverSettingData |
| 69 | val newDriverList = mutableListOf( | ||
| 70 | Driver( | ||
| 71 | selectedDriver == GpuDriverMetadata(), | ||
| 72 | YuzuApplication.appContext.getString(R.string.system_gpu_driver) | ||
| 73 | ) | ||
| 74 | ) | ||
| 75 | driverData.forEach { | ||
| 76 | newDriverList.add(it.second.toDriver(it.second == selectedDriver)) | ||
| 85 | } | 77 | } |
| 86 | updateDriverNameForGame(null) | 78 | _driverList.value = newDriverList |
| 87 | } | 79 | } |
| 88 | 80 | ||
| 89 | fun setSelectedDriverIndex(value: Int) { | 81 | fun onOpenDriverManager(game: Game?) { |
| 90 | if (selectedDriver != -1) { | 82 | if (game != null) { |
| 91 | previouslySelectedDriver = selectedDriver | 83 | SettingsFile.loadCustomConfig(game) |
| 92 | } | 84 | } |
| 93 | selectedDriver = value | 85 | updateDriverList() |
| 94 | } | 86 | } |
| 95 | 87 | ||
| 96 | fun setNewDriverInstalled(value: Boolean) { | 88 | fun showClearButton(value: Boolean) { |
| 97 | _newDriverInstalled.value = value | 89 | _showClearButton.value = value |
| 98 | } | 90 | } |
| 99 | 91 | ||
| 100 | fun addDriver(driverData: Pair<String, GpuDriverMetadata>) { | 92 | fun onDriverSelected(position: Int) { |
| 101 | val driverIndex = _driverList.value.indexOfFirst { it == driverData } | 93 | if (position == 0) { |
| 102 | if (driverIndex == -1) { | 94 | StringSetting.DRIVER_PATH.setString("") |
| 103 | _driverList.value.add(driverData) | ||
| 104 | setSelectedDriverIndex(_driverList.value.size - 1) | ||
| 105 | _selectedDriverTitle.value = driverData.second.name | ||
| 106 | ?: YuzuApplication.appContext.getString(R.string.system_gpu_driver) | ||
| 107 | } else { | 95 | } else { |
| 108 | setSelectedDriverIndex(driverIndex) | 96 | StringSetting.DRIVER_PATH.setString(driverData[position - 1].first) |
| 109 | } | 97 | } |
| 110 | } | 98 | } |
| 111 | 99 | ||
| 112 | fun removeDriver(driverData: Pair<String, GpuDriverMetadata>) { | 100 | fun onDriverRemoved(removedPosition: Int, selectedPosition: Int) { |
| 113 | _driverList.value.remove(driverData) | 101 | driversToDelete.add(driverData[removedPosition - 1].first) |
| 102 | driverData.removeAt(removedPosition - 1) | ||
| 103 | onDriverSelected(selectedPosition) | ||
| 114 | } | 104 | } |
| 115 | 105 | ||
| 116 | fun onOpenDriverManager(game: Game?) { | 106 | fun onDriverAdded(driver: Pair<String, GpuDriverMetadata>) { |
| 117 | if (game != null) { | 107 | if (driversToDelete.contains(driver.first)) { |
| 118 | SettingsFile.loadCustomConfig(game) | 108 | driversToDelete.remove(driver.first) |
| 119 | } | ||
| 120 | |||
| 121 | val driverPath = StringSetting.DRIVER_PATH.getString() | ||
| 122 | if (driverPath.isEmpty()) { | ||
| 123 | setSelectedDriverIndex(0) | ||
| 124 | } else { | ||
| 125 | findSelectedDriver(GpuDriverHelper.getMetadataFromZip(File(driverPath))) | ||
| 126 | } | 109 | } |
| 110 | driverData.add(driver) | ||
| 111 | onDriverSelected(driverData.size) | ||
| 127 | } | 112 | } |
| 128 | 113 | ||
| 129 | fun onCloseDriverManager(game: Game?) { | 114 | fun onCloseDriverManager(game: Game?) { |
| 130 | _isDeletingDrivers.value = true | 115 | _isDeletingDrivers.value = true |
| 131 | StringSetting.DRIVER_PATH.setString(driverList.value[selectedDriver].first) | ||
| 132 | updateDriverNameForGame(game) | 116 | updateDriverNameForGame(game) |
| 133 | if (game == null) { | 117 | if (game == null) { |
| 134 | NativeConfig.saveGlobalConfig() | 118 | NativeConfig.saveGlobalConfig() |
| @@ -181,20 +165,6 @@ class DriverViewModel : ViewModel() { | |||
| 181 | } | 165 | } |
| 182 | } | 166 | } |
| 183 | 167 | ||
| 184 | private fun findSelectedDriver(currentDriverMetadata: GpuDriverMetadata) { | ||
| 185 | if (driverList.value.size == 1) { | ||
| 186 | setSelectedDriverIndex(0) | ||
| 187 | return | ||
| 188 | } | ||
| 189 | |||
| 190 | driverList.value.forEachIndexed { i: Int, driver: Pair<String, GpuDriverMetadata> -> | ||
| 191 | if (driver.second == currentDriverMetadata) { | ||
| 192 | setSelectedDriverIndex(i) | ||
| 193 | return | ||
| 194 | } | ||
| 195 | } | ||
| 196 | } | ||
| 197 | |||
| 198 | fun updateDriverNameForGame(game: Game?) { | 168 | fun updateDriverNameForGame(game: Game?) { |
| 199 | if (!GpuDriverHelper.supportsCustomDriverLoading()) { | 169 | if (!GpuDriverHelper.supportsCustomDriverLoading()) { |
| 200 | return | 170 | return |
| @@ -217,7 +187,6 @@ class DriverViewModel : ViewModel() { | |||
| 217 | 187 | ||
| 218 | private fun setDriverReady() { | 188 | private fun setDriverReady() { |
| 219 | _isDriverReady.value = true | 189 | _isDriverReady.value = true |
| 220 | _selectedDriverTitle.value = GpuDriverHelper.customDriverSettingData.name | 190 | updateName() |
| 221 | ?: YuzuApplication.appContext.getString(R.string.system_gpu_driver) | ||
| 222 | } | 191 | } |
| 223 | } | 192 | } |
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/SelectableItem.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/SelectableItem.kt new file mode 100644 index 000000000..11c22d323 --- /dev/null +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/SelectableItem.kt | |||
| @@ -0,0 +1,9 @@ | |||
| 1 | // SPDX-FileCopyrightText: 2024 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | package org.yuzu.yuzu_emu.model | ||
| 5 | |||
| 6 | interface SelectableItem { | ||
| 7 | var selected: Boolean | ||
| 8 | fun onSelectionStateChanged(selected: Boolean) | ||
| 9 | } | ||
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/main/MainActivity.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/main/MainActivity.kt index 622ae996e..644289e25 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/main/MainActivity.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/main/MainActivity.kt | |||
| @@ -41,6 +41,7 @@ import org.yuzu.yuzu_emu.fragments.AddGameFolderDialogFragment | |||
| 41 | import org.yuzu.yuzu_emu.fragments.IndeterminateProgressDialogFragment | 41 | import org.yuzu.yuzu_emu.fragments.IndeterminateProgressDialogFragment |
| 42 | import org.yuzu.yuzu_emu.fragments.MessageDialogFragment | 42 | import org.yuzu.yuzu_emu.fragments.MessageDialogFragment |
| 43 | import org.yuzu.yuzu_emu.model.AddonViewModel | 43 | import org.yuzu.yuzu_emu.model.AddonViewModel |
| 44 | import org.yuzu.yuzu_emu.model.DriverViewModel | ||
| 44 | import org.yuzu.yuzu_emu.model.GamesViewModel | 45 | import org.yuzu.yuzu_emu.model.GamesViewModel |
| 45 | import org.yuzu.yuzu_emu.model.HomeViewModel | 46 | import org.yuzu.yuzu_emu.model.HomeViewModel |
| 46 | import org.yuzu.yuzu_emu.model.TaskState | 47 | import org.yuzu.yuzu_emu.model.TaskState |
| @@ -58,6 +59,7 @@ class MainActivity : AppCompatActivity(), ThemeProvider { | |||
| 58 | private val gamesViewModel: GamesViewModel by viewModels() | 59 | private val gamesViewModel: GamesViewModel by viewModels() |
| 59 | private val taskViewModel: TaskViewModel by viewModels() | 60 | private val taskViewModel: TaskViewModel by viewModels() |
| 60 | private val addonViewModel: AddonViewModel by viewModels() | 61 | private val addonViewModel: AddonViewModel by viewModels() |
| 62 | private val driverViewModel: DriverViewModel by viewModels() | ||
| 61 | 63 | ||
| 62 | override var themeId: Int = 0 | 64 | override var themeId: Int = 0 |
| 63 | 65 | ||
| @@ -689,6 +691,7 @@ class MainActivity : AppCompatActivity(), ThemeProvider { | |||
| 689 | NativeLibrary.initializeSystem(true) | 691 | NativeLibrary.initializeSystem(true) |
| 690 | NativeConfig.initializeGlobalConfig() | 692 | NativeConfig.initializeGlobalConfig() |
| 691 | gamesViewModel.reloadGames(false) | 693 | gamesViewModel.reloadGames(false) |
| 694 | driverViewModel.reloadDriverData() | ||
| 692 | 695 | ||
| 693 | return@newInstance getString(R.string.user_data_import_success) | 696 | return@newInstance getString(R.string.user_data_import_success) |
| 694 | }.show(supportFragmentManager, IndeterminateProgressDialogFragment.TAG) | 697 | }.show(supportFragmentManager, IndeterminateProgressDialogFragment.TAG) |
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/FileUtil.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/FileUtil.kt index 132f002fb..b54a19c65 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/FileUtil.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/FileUtil.kt | |||
| @@ -104,7 +104,7 @@ object FileUtil { | |||
| 104 | 104 | ||
| 105 | /** | 105 | /** |
| 106 | * Reference: https://stackoverflow.com/questions/42186820/documentfile-is-very-slow | 106 | * Reference: https://stackoverflow.com/questions/42186820/documentfile-is-very-slow |
| 107 | * This function will be faster than DoucmentFile.listFiles | 107 | * This function will be faster than DocumentFile.listFiles |
| 108 | * @param uri Directory uri. | 108 | * @param uri Directory uri. |
| 109 | * @return CheapDocument lists. | 109 | * @return CheapDocument lists. |
| 110 | */ | 110 | */ |
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/GpuDriverHelper.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/GpuDriverHelper.kt index 685272288..a8f9dcc34 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/GpuDriverHelper.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/GpuDriverHelper.kt | |||
| @@ -62,9 +62,6 @@ object GpuDriverHelper { | |||
| 62 | ?.sortedByDescending { it: Pair<String, GpuDriverMetadata> -> it.second.name } | 62 | ?.sortedByDescending { it: Pair<String, GpuDriverMetadata> -> it.second.name } |
| 63 | ?.distinct() | 63 | ?.distinct() |
| 64 | ?.toMutableList() ?: mutableListOf() | 64 | ?.toMutableList() ?: mutableListOf() |
| 65 | |||
| 66 | // TODO: Get system driver information | ||
| 67 | drivers.add(0, Pair("", GpuDriverMetadata())) | ||
| 68 | return drivers | 65 | return drivers |
| 69 | } | 66 | } |
| 70 | 67 | ||
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/viewholder/AbstractViewHolder.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/viewholder/AbstractViewHolder.kt new file mode 100644 index 000000000..7101ad434 --- /dev/null +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/viewholder/AbstractViewHolder.kt | |||
| @@ -0,0 +1,18 @@ | |||
| 1 | // SPDX-FileCopyrightText: 2024 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | package org.yuzu.yuzu_emu.viewholder | ||
| 5 | |||
| 6 | import androidx.recyclerview.widget.RecyclerView | ||
| 7 | import androidx.viewbinding.ViewBinding | ||
| 8 | import org.yuzu.yuzu_emu.adapters.AbstractDiffAdapter | ||
| 9 | import org.yuzu.yuzu_emu.adapters.AbstractListAdapter | ||
| 10 | |||
| 11 | /** | ||
| 12 | * [RecyclerView.ViewHolder] meant to work together with a [AbstractDiffAdapter] or a | ||
| 13 | * [AbstractListAdapter] so we can run [bind] on each list item without needing a manual hookup. | ||
| 14 | */ | ||
| 15 | abstract class AbstractViewHolder<Model>(binding: ViewBinding) : | ||
| 16 | RecyclerView.ViewHolder(binding.root) { | ||
| 17 | abstract fun bind(model: Model) | ||
| 18 | } | ||
diff --git a/src/android/app/src/main/jni/native.cpp b/src/android/app/src/main/jni/native.cpp index 136c8dee6..ed3b1353a 100644 --- a/src/android/app/src/main/jni/native.cpp +++ b/src/android/app/src/main/jni/native.cpp | |||
| @@ -410,8 +410,8 @@ void EmulationSession::OnGamepadConnectEvent([[maybe_unused]] int index) { | |||
| 410 | jauto handheld = m_system.HIDCore().GetEmulatedController(Core::HID::NpadIdType::Handheld); | 410 | jauto handheld = m_system.HIDCore().GetEmulatedController(Core::HID::NpadIdType::Handheld); |
| 411 | 411 | ||
| 412 | if (controller->GetNpadStyleIndex() == Core::HID::NpadStyleIndex::Handheld) { | 412 | if (controller->GetNpadStyleIndex() == Core::HID::NpadStyleIndex::Handheld) { |
| 413 | handheld->SetNpadStyleIndex(Core::HID::NpadStyleIndex::ProController); | 413 | handheld->SetNpadStyleIndex(Core::HID::NpadStyleIndex::Fullkey); |
| 414 | controller->SetNpadStyleIndex(Core::HID::NpadStyleIndex::ProController); | 414 | controller->SetNpadStyleIndex(Core::HID::NpadStyleIndex::Fullkey); |
| 415 | handheld->Disconnect(); | 415 | handheld->Disconnect(); |
| 416 | } | 416 | } |
| 417 | } | 417 | } |
| @@ -770,8 +770,8 @@ void Java_org_yuzu_yuzu_1emu_NativeLibrary_initializeEmptyUserDirectory(JNIEnv* | |||
| 770 | ASSERT(user_id); | 770 | ASSERT(user_id); |
| 771 | 771 | ||
| 772 | const auto user_save_data_path = FileSys::SaveDataFactory::GetFullPath( | 772 | const auto user_save_data_path = FileSys::SaveDataFactory::GetFullPath( |
| 773 | EmulationSession::GetInstance().System(), vfs_nand_dir, FileSys::SaveDataSpaceId::NandUser, | 773 | {}, vfs_nand_dir, FileSys::SaveDataSpaceId::NandUser, FileSys::SaveDataType::SaveData, 1, |
| 774 | FileSys::SaveDataType::SaveData, 1, user_id->AsU128(), 0); | 774 | user_id->AsU128(), 0); |
| 775 | 775 | ||
| 776 | const auto full_path = Common::FS::ConcatPathSafe(nand_dir, user_save_data_path); | 776 | const auto full_path = Common::FS::ConcatPathSafe(nand_dir, user_save_data_path); |
| 777 | if (!Common::FS::CreateParentDirs(full_path)) { | 777 | if (!Common::FS::CreateParentDirs(full_path)) { |
| @@ -878,7 +878,7 @@ jstring Java_org_yuzu_yuzu_1emu_NativeLibrary_getSavePath(JNIEnv* env, jobject j | |||
| 878 | FileSys::Mode::Read); | 878 | FileSys::Mode::Read); |
| 879 | 879 | ||
| 880 | const auto user_save_data_path = FileSys::SaveDataFactory::GetFullPath( | 880 | const auto user_save_data_path = FileSys::SaveDataFactory::GetFullPath( |
| 881 | system, vfsNandDir, FileSys::SaveDataSpaceId::NandUser, FileSys::SaveDataType::SaveData, | 881 | {}, vfsNandDir, FileSys::SaveDataSpaceId::NandUser, FileSys::SaveDataType::SaveData, |
| 882 | program_id, user_id->AsU128(), 0); | 882 | program_id, user_id->AsU128(), 0); |
| 883 | return ToJString(env, user_save_data_path); | 883 | return ToJString(env, user_save_data_path); |
| 884 | } | 884 | } |
diff --git a/src/android/app/src/main/jni/native_config.cpp b/src/android/app/src/main/jni/native_config.cpp index 535902483..c6c3343dc 100644 --- a/src/android/app/src/main/jni/native_config.cpp +++ b/src/android/app/src/main/jni/native_config.cpp | |||
| @@ -205,7 +205,7 @@ jboolean Java_org_yuzu_yuzu_1emu_utils_NativeConfig_getIsRuntimeModifiable(JNIEn | |||
| 205 | jstring jkey) { | 205 | jstring jkey) { |
| 206 | auto setting = getSetting<std::string>(env, jkey); | 206 | auto setting = getSetting<std::string>(env, jkey); |
| 207 | if (setting != nullptr) { | 207 | if (setting != nullptr) { |
| 208 | return setting->RuntimeModfiable(); | 208 | return setting->RuntimeModifiable(); |
| 209 | } | 209 | } |
| 210 | return true; | 210 | return true; |
| 211 | } | 211 | } |
diff --git a/src/android/app/src/main/res/layout-w600dp/fragment_about.xml b/src/android/app/src/main/res/layout-w600dp/fragment_about.xml index a26ffbc73..655e49219 100644 --- a/src/android/app/src/main/res/layout-w600dp/fragment_about.xml +++ b/src/android/app/src/main/res/layout-w600dp/fragment_about.xml | |||
| @@ -147,7 +147,7 @@ | |||
| 147 | android:layout_marginHorizontal="20dp" /> | 147 | android:layout_marginHorizontal="20dp" /> |
| 148 | 148 | ||
| 149 | <LinearLayout | 149 | <LinearLayout |
| 150 | android:id="@+id/button_build_hash" | 150 | android:id="@+id/button_version_name" |
| 151 | android:layout_width="match_parent" | 151 | android:layout_width="match_parent" |
| 152 | android:layout_height="wrap_content" | 152 | android:layout_height="wrap_content" |
| 153 | android:background="?attr/selectableItemBackground" | 153 | android:background="?attr/selectableItemBackground" |
| @@ -164,7 +164,7 @@ | |||
| 164 | android:textAlignment="viewStart" /> | 164 | android:textAlignment="viewStart" /> |
| 165 | 165 | ||
| 166 | <com.google.android.material.textview.MaterialTextView | 166 | <com.google.android.material.textview.MaterialTextView |
| 167 | android:id="@+id/text_build_hash" | 167 | android:id="@+id/text_version_name" |
| 168 | style="@style/TextAppearance.Material3.BodyMedium" | 168 | style="@style/TextAppearance.Material3.BodyMedium" |
| 169 | android:layout_width="match_parent" | 169 | android:layout_width="match_parent" |
| 170 | android:layout_height="wrap_content" | 170 | android:layout_height="wrap_content" |
diff --git a/src/android/app/src/main/res/layout/fragment_about.xml b/src/android/app/src/main/res/layout/fragment_about.xml index a24f5230e..38090fa50 100644 --- a/src/android/app/src/main/res/layout/fragment_about.xml +++ b/src/android/app/src/main/res/layout/fragment_about.xml | |||
| @@ -148,7 +148,7 @@ | |||
| 148 | android:layout_marginHorizontal="20dp" /> | 148 | android:layout_marginHorizontal="20dp" /> |
| 149 | 149 | ||
| 150 | <LinearLayout | 150 | <LinearLayout |
| 151 | android:id="@+id/button_build_hash" | 151 | android:id="@+id/button_version_name" |
| 152 | android:layout_width="match_parent" | 152 | android:layout_width="match_parent" |
| 153 | android:layout_height="wrap_content" | 153 | android:layout_height="wrap_content" |
| 154 | android:paddingVertical="16dp" | 154 | android:paddingVertical="16dp" |
| @@ -165,7 +165,7 @@ | |||
| 165 | android:text="@string/build" /> | 165 | android:text="@string/build" /> |
| 166 | 166 | ||
| 167 | <com.google.android.material.textview.MaterialTextView | 167 | <com.google.android.material.textview.MaterialTextView |
| 168 | android:id="@+id/text_build_hash" | 168 | android:id="@+id/text_version_name" |
| 169 | style="@style/TextAppearance.Material3.BodyMedium" | 169 | style="@style/TextAppearance.Material3.BodyMedium" |
| 170 | android:layout_width="match_parent" | 170 | android:layout_width="match_parent" |
| 171 | android:layout_height="wrap_content" | 171 | android:layout_height="wrap_content" |
diff --git a/src/android/app/src/main/res/menu/menu_driver_manager.xml b/src/android/app/src/main/res/menu/menu_driver_manager.xml new file mode 100644 index 000000000..dee5d57b6 --- /dev/null +++ b/src/android/app/src/main/res/menu/menu_driver_manager.xml | |||
| @@ -0,0 +1,11 @@ | |||
| 1 | <?xml version="1.0" encoding="utf-8"?> | ||
| 2 | <menu xmlns:android="http://schemas.android.com/apk/res/android" | ||
| 3 | xmlns:app="http://schemas.android.com/apk/res-auto"> | ||
| 4 | |||
| 5 | <item | ||
| 6 | android:id="@+id/menu_driver_clear" | ||
| 7 | android:icon="@drawable/ic_clear" | ||
| 8 | android:title="@string/clear" | ||
| 9 | app:showAsAction="always" /> | ||
| 10 | |||
| 11 | </menu> | ||
diff --git a/src/android/app/src/main/res/values/arrays.xml b/src/android/app/src/main/res/values/arrays.xml index 0363ff3b6..4701913eb 100644 --- a/src/android/app/src/main/res/values/arrays.xml +++ b/src/android/app/src/main/res/values/arrays.xml | |||
| @@ -29,7 +29,7 @@ | |||
| 29 | <item>@string/language_dutch</item> | 29 | <item>@string/language_dutch</item> |
| 30 | <item>@string/language_english</item> | 30 | <item>@string/language_english</item> |
| 31 | <item>@string/language_french</item> | 31 | <item>@string/language_french</item> |
| 32 | <item>@string/langauge_german</item> | 32 | <item>@string/language_german</item> |
| 33 | <item>@string/language_italian</item> | 33 | <item>@string/language_italian</item> |
| 34 | <item>@string/language_japanese</item> | 34 | <item>@string/language_japanese</item> |
| 35 | <item>@string/language_korean</item> | 35 | <item>@string/language_korean</item> |
| @@ -228,10 +228,10 @@ | |||
| 228 | <item>R</item> | 228 | <item>R</item> |
| 229 | <item>ZL</item> | 229 | <item>ZL</item> |
| 230 | <item>ZR</item> | 230 | <item>ZR</item> |
| 231 | <item>@string/gamepad_left_stick</item> | ||
| 232 | <item>@string/gamepad_right_stick</item> | ||
| 233 | <item>L3</item> | 231 | <item>L3</item> |
| 234 | <item>R3</item> | 232 | <item>R3</item> |
| 233 | <item>@string/gamepad_left_stick</item> | ||
| 234 | <item>@string/gamepad_right_stick</item> | ||
| 235 | <item>@string/gamepad_d_pad</item> | 235 | <item>@string/gamepad_d_pad</item> |
| 236 | </string-array> | 236 | </string-array> |
| 237 | 237 | ||
diff --git a/src/android/app/src/main/res/values/strings.xml b/src/android/app/src/main/res/values/strings.xml index 3bb92ad67..547752bda 100644 --- a/src/android/app/src/main/res/values/strings.xml +++ b/src/android/app/src/main/res/values/strings.xml | |||
| @@ -410,7 +410,7 @@ | |||
| 410 | <string name="language_japanese" translatable="false">日本語</string> | 410 | <string name="language_japanese" translatable="false">日本語</string> |
| 411 | <string name="language_english" translatable="false">English</string> | 411 | <string name="language_english" translatable="false">English</string> |
| 412 | <string name="language_french" translatable="false">Français</string> | 412 | <string name="language_french" translatable="false">Français</string> |
| 413 | <string name="langauge_german" translatable="false">Deutsch</string> | 413 | <string name="language_german" translatable="false">Deutsch</string> |
| 414 | <string name="language_italian" translatable="false">Italiano</string> | 414 | <string name="language_italian" translatable="false">Italiano</string> |
| 415 | <string name="language_spanish" translatable="false">Español</string> | 415 | <string name="language_spanish" translatable="false">Español</string> |
| 416 | <string name="language_chinese" translatable="false">ç®€ä½“ä¸æ–‡</string> | 416 | <string name="language_chinese" translatable="false">ç®€ä½“ä¸æ–‡</string> |
diff --git a/src/audio_core/adsp/adsp.cpp b/src/audio_core/adsp/adsp.cpp index 6c53c98fd..48f0a63d4 100644 --- a/src/audio_core/adsp/adsp.cpp +++ b/src/audio_core/adsp/adsp.cpp | |||
| @@ -11,7 +11,7 @@ ADSP::ADSP(Core::System& system, Sink::Sink& sink) { | |||
| 11 | opus_decoder = std::make_unique<OpusDecoder::OpusDecoder>(system); | 11 | opus_decoder = std::make_unique<OpusDecoder::OpusDecoder>(system); |
| 12 | opus_decoder->Send(Direction::DSP, OpusDecoder::Message::Start); | 12 | opus_decoder->Send(Direction::DSP, OpusDecoder::Message::Start); |
| 13 | if (opus_decoder->Receive(Direction::Host) != OpusDecoder::Message::StartOK) { | 13 | if (opus_decoder->Receive(Direction::Host) != OpusDecoder::Message::StartOK) { |
| 14 | LOG_ERROR(Service_Audio, "OpusDeocder failed to initialize."); | 14 | LOG_ERROR(Service_Audio, "OpusDecoder failed to initialize."); |
| 15 | return; | 15 | return; |
| 16 | } | 16 | } |
| 17 | } | 17 | } |
diff --git a/src/audio_core/device/device_session.cpp b/src/audio_core/device/device_session.cpp index ee42ae529..3c214ec00 100644 --- a/src/audio_core/device/device_session.cpp +++ b/src/audio_core/device/device_session.cpp | |||
| @@ -10,6 +10,8 @@ | |||
| 10 | #include "core/core_timing.h" | 10 | #include "core/core_timing.h" |
| 11 | #include "core/memory.h" | 11 | #include "core/memory.h" |
| 12 | 12 | ||
| 13 | #include "core/hle/kernel/k_process.h" | ||
| 14 | |||
| 13 | namespace AudioCore { | 15 | namespace AudioCore { |
| 14 | 16 | ||
| 15 | using namespace std::literals; | 17 | using namespace std::literals; |
| @@ -25,7 +27,7 @@ DeviceSession::~DeviceSession() { | |||
| 25 | } | 27 | } |
| 26 | 28 | ||
| 27 | Result DeviceSession::Initialize(std::string_view name_, SampleFormat sample_format_, | 29 | Result DeviceSession::Initialize(std::string_view name_, SampleFormat sample_format_, |
| 28 | u16 channel_count_, size_t session_id_, u32 handle_, | 30 | u16 channel_count_, size_t session_id_, Kernel::KProcess* handle_, |
| 29 | u64 applet_resource_user_id_, Sink::StreamType type_) { | 31 | u64 applet_resource_user_id_, Sink::StreamType type_) { |
| 30 | if (stream) { | 32 | if (stream) { |
| 31 | Finalize(); | 33 | Finalize(); |
| @@ -36,6 +38,7 @@ Result DeviceSession::Initialize(std::string_view name_, SampleFormat sample_for | |||
| 36 | channel_count = channel_count_; | 38 | channel_count = channel_count_; |
| 37 | session_id = session_id_; | 39 | session_id = session_id_; |
| 38 | handle = handle_; | 40 | handle = handle_; |
| 41 | handle->Open(); | ||
| 39 | applet_resource_user_id = applet_resource_user_id_; | 42 | applet_resource_user_id = applet_resource_user_id_; |
| 40 | 43 | ||
| 41 | if (type == Sink::StreamType::In) { | 44 | if (type == Sink::StreamType::In) { |
| @@ -54,6 +57,11 @@ void DeviceSession::Finalize() { | |||
| 54 | sink->CloseStream(stream); | 57 | sink->CloseStream(stream); |
| 55 | stream = nullptr; | 58 | stream = nullptr; |
| 56 | } | 59 | } |
| 60 | |||
| 61 | if (handle) { | ||
| 62 | handle->Close(); | ||
| 63 | handle = nullptr; | ||
| 64 | } | ||
| 57 | } | 65 | } |
| 58 | 66 | ||
| 59 | void DeviceSession::Start() { | 67 | void DeviceSession::Start() { |
| @@ -91,7 +99,7 @@ void DeviceSession::AppendBuffers(std::span<const AudioBuffer> buffers) { | |||
| 91 | stream->AppendBuffer(new_buffer, tmp_samples); | 99 | stream->AppendBuffer(new_buffer, tmp_samples); |
| 92 | } else { | 100 | } else { |
| 93 | Core::Memory::CpuGuestMemory<s16, Core::Memory::GuestMemoryFlags::UnsafeRead> samples( | 101 | Core::Memory::CpuGuestMemory<s16, Core::Memory::GuestMemoryFlags::UnsafeRead> samples( |
| 94 | system.ApplicationMemory(), buffer.samples, buffer.size / sizeof(s16)); | 102 | handle->GetMemory(), buffer.samples, buffer.size / sizeof(s16)); |
| 95 | stream->AppendBuffer(new_buffer, samples); | 103 | stream->AppendBuffer(new_buffer, samples); |
| 96 | } | 104 | } |
| 97 | } | 105 | } |
| @@ -100,7 +108,7 @@ void DeviceSession::AppendBuffers(std::span<const AudioBuffer> buffers) { | |||
| 100 | void DeviceSession::ReleaseBuffer(const AudioBuffer& buffer) const { | 108 | void DeviceSession::ReleaseBuffer(const AudioBuffer& buffer) const { |
| 101 | if (type == Sink::StreamType::In) { | 109 | if (type == Sink::StreamType::In) { |
| 102 | auto samples{stream->ReleaseBuffer(buffer.size / sizeof(s16))}; | 110 | auto samples{stream->ReleaseBuffer(buffer.size / sizeof(s16))}; |
| 103 | system.ApplicationMemory().WriteBlockUnsafe(buffer.samples, samples.data(), buffer.size); | 111 | handle->GetMemory().WriteBlockUnsafe(buffer.samples, samples.data(), buffer.size); |
| 104 | } | 112 | } |
| 105 | } | 113 | } |
| 106 | 114 | ||
diff --git a/src/audio_core/device/device_session.h b/src/audio_core/device/device_session.h index 7d52f362d..f3fae2617 100644 --- a/src/audio_core/device/device_session.h +++ b/src/audio_core/device/device_session.h | |||
| @@ -20,6 +20,10 @@ struct EventType; | |||
| 20 | } // namespace Timing | 20 | } // namespace Timing |
| 21 | } // namespace Core | 21 | } // namespace Core |
| 22 | 22 | ||
| 23 | namespace Kernel { | ||
| 24 | class KProcess; | ||
| 25 | } // namespace Kernel | ||
| 26 | |||
| 23 | namespace AudioCore { | 27 | namespace AudioCore { |
| 24 | 28 | ||
| 25 | namespace Sink { | 29 | namespace Sink { |
| @@ -44,13 +48,13 @@ public: | |||
| 44 | * @param sample_format - Sample format for this device's output. | 48 | * @param sample_format - Sample format for this device's output. |
| 45 | * @param channel_count - Number of channels for this device (2 or 6). | 49 | * @param channel_count - Number of channels for this device (2 or 6). |
| 46 | * @param session_id - This session's id. | 50 | * @param session_id - This session's id. |
| 47 | * @param handle - Handle for this device session (unused). | 51 | * @param handle - Process handle for this device session. |
| 48 | * @param applet_resource_user_id - Applet resource user id for this device session (unused). | 52 | * @param applet_resource_user_id - Applet resource user id for this device session (unused). |
| 49 | * @param type - Type of this stream (Render, In, Out). | 53 | * @param type - Type of this stream (Render, In, Out). |
| 50 | * @return Result code for this call. | 54 | * @return Result code for this call. |
| 51 | */ | 55 | */ |
| 52 | Result Initialize(std::string_view name, SampleFormat sample_format, u16 channel_count, | 56 | Result Initialize(std::string_view name, SampleFormat sample_format, u16 channel_count, |
| 53 | size_t session_id, u32 handle, u64 applet_resource_user_id, | 57 | size_t session_id, Kernel::KProcess* handle, u64 applet_resource_user_id, |
| 54 | Sink::StreamType type); | 58 | Sink::StreamType type); |
| 55 | 59 | ||
| 56 | /** | 60 | /** |
| @@ -137,8 +141,8 @@ private: | |||
| 137 | u16 channel_count{}; | 141 | u16 channel_count{}; |
| 138 | /// Session id of this device session | 142 | /// Session id of this device session |
| 139 | size_t session_id{}; | 143 | size_t session_id{}; |
| 140 | /// Handle of this device session | 144 | /// Process handle of device memory owner |
| 141 | u32 handle{}; | 145 | Kernel::KProcess* handle{}; |
| 142 | /// Applet resource user id of this device session | 146 | /// Applet resource user id of this device session |
| 143 | u64 applet_resource_user_id{}; | 147 | u64 applet_resource_user_id{}; |
| 144 | /// Total number of samples played by this device session | 148 | /// Total number of samples played by this device session |
diff --git a/src/audio_core/in/audio_in_system.cpp b/src/audio_core/in/audio_in_system.cpp index 579129121..b2dd3ef9f 100644 --- a/src/audio_core/in/audio_in_system.cpp +++ b/src/audio_core/in/audio_in_system.cpp | |||
| @@ -57,7 +57,7 @@ Result System::IsConfigValid(const std::string_view device_name, | |||
| 57 | } | 57 | } |
| 58 | 58 | ||
| 59 | Result System::Initialize(std::string device_name, const AudioInParameter& in_params, | 59 | Result System::Initialize(std::string device_name, const AudioInParameter& in_params, |
| 60 | const u32 handle_, const u64 applet_resource_user_id_) { | 60 | Kernel::KProcess* handle_, const u64 applet_resource_user_id_) { |
| 61 | auto result{IsConfigValid(device_name, in_params)}; | 61 | auto result{IsConfigValid(device_name, in_params)}; |
| 62 | if (result.IsError()) { | 62 | if (result.IsError()) { |
| 63 | return result; | 63 | return result; |
diff --git a/src/audio_core/in/audio_in_system.h b/src/audio_core/in/audio_in_system.h index 1c5154638..ee048190c 100644 --- a/src/audio_core/in/audio_in_system.h +++ b/src/audio_core/in/audio_in_system.h | |||
| @@ -19,7 +19,8 @@ class System; | |||
| 19 | 19 | ||
| 20 | namespace Kernel { | 20 | namespace Kernel { |
| 21 | class KEvent; | 21 | class KEvent; |
| 22 | } | 22 | class KProcess; |
| 23 | } // namespace Kernel | ||
| 23 | 24 | ||
| 24 | namespace AudioCore::AudioIn { | 25 | namespace AudioCore::AudioIn { |
| 25 | 26 | ||
| @@ -93,12 +94,12 @@ public: | |||
| 93 | * | 94 | * |
| 94 | * @param device_name - The name of the requested input device. | 95 | * @param device_name - The name of the requested input device. |
| 95 | * @param in_params - Input parameters, see AudioInParameter. | 96 | * @param in_params - Input parameters, see AudioInParameter. |
| 96 | * @param handle - Unused. | 97 | * @param handle - Process handle. |
| 97 | * @param applet_resource_user_id - Unused. | 98 | * @param applet_resource_user_id - Unused. |
| 98 | * @return Result code. | 99 | * @return Result code. |
| 99 | */ | 100 | */ |
| 100 | Result Initialize(std::string device_name, const AudioInParameter& in_params, u32 handle, | 101 | Result Initialize(std::string device_name, const AudioInParameter& in_params, |
| 101 | u64 applet_resource_user_id); | 102 | Kernel::KProcess* handle, u64 applet_resource_user_id); |
| 102 | 103 | ||
| 103 | /** | 104 | /** |
| 104 | * Start this system. | 105 | * Start this system. |
| @@ -244,8 +245,8 @@ public: | |||
| 244 | private: | 245 | private: |
| 245 | /// Core system | 246 | /// Core system |
| 246 | Core::System& system; | 247 | Core::System& system; |
| 247 | /// (Unused) | 248 | /// Process handle |
| 248 | u32 handle{}; | 249 | Kernel::KProcess* handle{}; |
| 249 | /// (Unused) | 250 | /// (Unused) |
| 250 | u64 applet_resource_user_id{}; | 251 | u64 applet_resource_user_id{}; |
| 251 | /// Buffer event, signalled when a buffer is ready | 252 | /// Buffer event, signalled when a buffer is ready |
diff --git a/src/audio_core/out/audio_out_system.cpp b/src/audio_core/out/audio_out_system.cpp index 0adf64bd3..7b3ff4e88 100644 --- a/src/audio_core/out/audio_out_system.cpp +++ b/src/audio_core/out/audio_out_system.cpp | |||
| @@ -48,8 +48,8 @@ Result System::IsConfigValid(std::string_view device_name, | |||
| 48 | return Service::Audio::ResultInvalidChannelCount; | 48 | return Service::Audio::ResultInvalidChannelCount; |
| 49 | } | 49 | } |
| 50 | 50 | ||
| 51 | Result System::Initialize(std::string device_name, const AudioOutParameter& in_params, u32 handle_, | 51 | Result System::Initialize(std::string device_name, const AudioOutParameter& in_params, |
| 52 | u64 applet_resource_user_id_) { | 52 | Kernel::KProcess* handle_, u64 applet_resource_user_id_) { |
| 53 | auto result = IsConfigValid(device_name, in_params); | 53 | auto result = IsConfigValid(device_name, in_params); |
| 54 | if (result.IsError()) { | 54 | if (result.IsError()) { |
| 55 | return result; | 55 | return result; |
diff --git a/src/audio_core/out/audio_out_system.h b/src/audio_core/out/audio_out_system.h index b95cb91be..82aada185 100644 --- a/src/audio_core/out/audio_out_system.h +++ b/src/audio_core/out/audio_out_system.h | |||
| @@ -19,7 +19,8 @@ class System; | |||
| 19 | 19 | ||
| 20 | namespace Kernel { | 20 | namespace Kernel { |
| 21 | class KEvent; | 21 | class KEvent; |
| 22 | } | 22 | class KProcess; |
| 23 | } // namespace Kernel | ||
| 23 | 24 | ||
| 24 | namespace AudioCore::AudioOut { | 25 | namespace AudioCore::AudioOut { |
| 25 | 26 | ||
| @@ -84,12 +85,12 @@ public: | |||
| 84 | * | 85 | * |
| 85 | * @param device_name - The name of the requested output device. | 86 | * @param device_name - The name of the requested output device. |
| 86 | * @param in_params - Input parameters, see AudioOutParameter. | 87 | * @param in_params - Input parameters, see AudioOutParameter. |
| 87 | * @param handle - Unused. | 88 | * @param handle - Process handle. |
| 88 | * @param applet_resource_user_id - Unused. | 89 | * @param applet_resource_user_id - Unused. |
| 89 | * @return Result code. | 90 | * @return Result code. |
| 90 | */ | 91 | */ |
| 91 | Result Initialize(std::string device_name, const AudioOutParameter& in_params, u32 handle, | 92 | Result Initialize(std::string device_name, const AudioOutParameter& in_params, |
| 92 | u64 applet_resource_user_id); | 93 | Kernel::KProcess* handle, u64 applet_resource_user_id); |
| 93 | 94 | ||
| 94 | /** | 95 | /** |
| 95 | * Start this system. | 96 | * Start this system. |
| @@ -228,8 +229,8 @@ public: | |||
| 228 | private: | 229 | private: |
| 229 | /// Core system | 230 | /// Core system |
| 230 | Core::System& system; | 231 | Core::System& system; |
| 231 | /// (Unused) | 232 | /// Process handle |
| 232 | u32 handle{}; | 233 | Kernel::KProcess* handle{}; |
| 233 | /// (Unused) | 234 | /// (Unused) |
| 234 | u64 applet_resource_user_id{}; | 235 | u64 applet_resource_user_id{}; |
| 235 | /// Buffer event, signalled when a buffer is ready | 236 | /// Buffer event, signalled when a buffer is ready |
diff --git a/src/audio_core/renderer/command/command_generator.cpp b/src/audio_core/renderer/command/command_generator.cpp index ccb186209..f97db5899 100644 --- a/src/audio_core/renderer/command/command_generator.cpp +++ b/src/audio_core/renderer/command/command_generator.cpp | |||
| @@ -41,7 +41,7 @@ void CommandGenerator::GenerateDataSourceCommand(VoiceInfo& voice_info, | |||
| 41 | const VoiceState& voice_state, const s8 channel) { | 41 | const VoiceState& voice_state, const s8 channel) { |
| 42 | if (voice_info.mix_id == UnusedMixId) { | 42 | if (voice_info.mix_id == UnusedMixId) { |
| 43 | if (voice_info.splitter_id != UnusedSplitterId) { | 43 | if (voice_info.splitter_id != UnusedSplitterId) { |
| 44 | auto destination{splitter_context.GetDesintationData(voice_info.splitter_id, 0)}; | 44 | auto destination{splitter_context.GetDestinationData(voice_info.splitter_id, 0)}; |
| 45 | u32 dest_id{0}; | 45 | u32 dest_id{0}; |
| 46 | while (destination != nullptr) { | 46 | while (destination != nullptr) { |
| 47 | if (destination->IsConfigured()) { | 47 | if (destination->IsConfigured()) { |
| @@ -55,7 +55,7 @@ void CommandGenerator::GenerateDataSourceCommand(VoiceInfo& voice_info, | |||
| 55 | } | 55 | } |
| 56 | } | 56 | } |
| 57 | dest_id++; | 57 | dest_id++; |
| 58 | destination = splitter_context.GetDesintationData(voice_info.splitter_id, dest_id); | 58 | destination = splitter_context.GetDestinationData(voice_info.splitter_id, dest_id); |
| 59 | } | 59 | } |
| 60 | } | 60 | } |
| 61 | } else { | 61 | } else { |
| @@ -234,7 +234,7 @@ void CommandGenerator::GenerateVoiceCommand(VoiceInfo& voice_info) { | |||
| 234 | if (voice_info.mix_id == UnusedMixId) { | 234 | if (voice_info.mix_id == UnusedMixId) { |
| 235 | if (voice_info.splitter_id != UnusedSplitterId) { | 235 | if (voice_info.splitter_id != UnusedSplitterId) { |
| 236 | auto i{channel}; | 236 | auto i{channel}; |
| 237 | auto destination{splitter_context.GetDesintationData(voice_info.splitter_id, i)}; | 237 | auto destination{splitter_context.GetDestinationData(voice_info.splitter_id, i)}; |
| 238 | while (destination != nullptr) { | 238 | while (destination != nullptr) { |
| 239 | if (destination->IsConfigured()) { | 239 | if (destination->IsConfigured()) { |
| 240 | const auto mix_id{destination->GetMixId()}; | 240 | const auto mix_id{destination->GetMixId()}; |
| @@ -249,7 +249,7 @@ void CommandGenerator::GenerateVoiceCommand(VoiceInfo& voice_info) { | |||
| 249 | } | 249 | } |
| 250 | } | 250 | } |
| 251 | i += voice_info.channel_count; | 251 | i += voice_info.channel_count; |
| 252 | destination = splitter_context.GetDesintationData(voice_info.splitter_id, i); | 252 | destination = splitter_context.GetDestinationData(voice_info.splitter_id, i); |
| 253 | } | 253 | } |
| 254 | } | 254 | } |
| 255 | } else { | 255 | } else { |
| @@ -591,7 +591,7 @@ void CommandGenerator::GenerateMixCommands(MixInfo& mix_info) { | |||
| 591 | if (mix_info.dst_splitter_id != UnusedSplitterId) { | 591 | if (mix_info.dst_splitter_id != UnusedSplitterId) { |
| 592 | s16 dest_id{0}; | 592 | s16 dest_id{0}; |
| 593 | auto destination{ | 593 | auto destination{ |
| 594 | splitter_context.GetDesintationData(mix_info.dst_splitter_id, dest_id)}; | 594 | splitter_context.GetDestinationData(mix_info.dst_splitter_id, dest_id)}; |
| 595 | while (destination != nullptr) { | 595 | while (destination != nullptr) { |
| 596 | if (destination->IsConfigured()) { | 596 | if (destination->IsConfigured()) { |
| 597 | auto splitter_mix_id{destination->GetMixId()}; | 597 | auto splitter_mix_id{destination->GetMixId()}; |
| @@ -612,7 +612,7 @@ void CommandGenerator::GenerateMixCommands(MixInfo& mix_info) { | |||
| 612 | } | 612 | } |
| 613 | dest_id++; | 613 | dest_id++; |
| 614 | destination = | 614 | destination = |
| 615 | splitter_context.GetDesintationData(mix_info.dst_splitter_id, dest_id); | 615 | splitter_context.GetDestinationData(mix_info.dst_splitter_id, dest_id); |
| 616 | } | 616 | } |
| 617 | } | 617 | } |
| 618 | } else { | 618 | } else { |
diff --git a/src/audio_core/renderer/mix/mix_info.cpp b/src/audio_core/renderer/mix/mix_info.cpp index 5e44bde18..68bbe0aed 100644 --- a/src/audio_core/renderer/mix/mix_info.cpp +++ b/src/audio_core/renderer/mix/mix_info.cpp | |||
| @@ -93,7 +93,7 @@ bool MixInfo::UpdateConnection(EdgeMatrix& edge_matrix, const InParameter& in_pa | |||
| 93 | 93 | ||
| 94 | for (u32 i = 0; i < destination_count; i++) { | 94 | for (u32 i = 0; i < destination_count; i++) { |
| 95 | auto destination{ | 95 | auto destination{ |
| 96 | splitter_context.GetDesintationData(in_params.dest_splitter_id, i)}; | 96 | splitter_context.GetDestinationData(in_params.dest_splitter_id, i)}; |
| 97 | 97 | ||
| 98 | if (destination) { | 98 | if (destination) { |
| 99 | const auto destination_id{destination->GetMixId()}; | 99 | const auto destination_id{destination->GetMixId()}; |
diff --git a/src/audio_core/renderer/splitter/splitter_context.cpp b/src/audio_core/renderer/splitter/splitter_context.cpp index 686150ea6..d0f3b60c2 100644 --- a/src/audio_core/renderer/splitter/splitter_context.cpp +++ b/src/audio_core/renderer/splitter/splitter_context.cpp | |||
| @@ -9,7 +9,7 @@ | |||
| 9 | 9 | ||
| 10 | namespace AudioCore::Renderer { | 10 | namespace AudioCore::Renderer { |
| 11 | 11 | ||
| 12 | SplitterDestinationData* SplitterContext::GetDesintationData(const s32 splitter_id, | 12 | SplitterDestinationData* SplitterContext::GetDestinationData(const s32 splitter_id, |
| 13 | const s32 destination_id) { | 13 | const s32 destination_id) { |
| 14 | return splitter_infos[splitter_id].GetData(destination_id); | 14 | return splitter_infos[splitter_id].GetData(destination_id); |
| 15 | } | 15 | } |
diff --git a/src/audio_core/renderer/splitter/splitter_context.h b/src/audio_core/renderer/splitter/splitter_context.h index 556e6dcc3..1c0b84671 100644 --- a/src/audio_core/renderer/splitter/splitter_context.h +++ b/src/audio_core/renderer/splitter/splitter_context.h | |||
| @@ -42,7 +42,7 @@ public: | |||
| 42 | * @param destination_id - Destination index within the splitter. | 42 | * @param destination_id - Destination index within the splitter. |
| 43 | * @return Pointer to the found destination. May be nullptr. | 43 | * @return Pointer to the found destination. May be nullptr. |
| 44 | */ | 44 | */ |
| 45 | SplitterDestinationData* GetDesintationData(s32 splitter_id, s32 destination_id); | 45 | SplitterDestinationData* GetDestinationData(s32 splitter_id, s32 destination_id); |
| 46 | 46 | ||
| 47 | /** | 47 | /** |
| 48 | * Get a splitter from the given index. | 48 | * Get a splitter from the given index. |
diff --git a/src/common/page_table.cpp b/src/common/page_table.cpp index 166dc3dce..85dc18c11 100644 --- a/src/common/page_table.cpp +++ b/src/common/page_table.cpp | |||
| @@ -2,6 +2,7 @@ | |||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | 2 | // SPDX-License-Identifier: GPL-2.0-or-later |
| 3 | 3 | ||
| 4 | #include "common/page_table.h" | 4 | #include "common/page_table.h" |
| 5 | #include "common/scope_exit.h" | ||
| 5 | 6 | ||
| 6 | namespace Common { | 7 | namespace Common { |
| 7 | 8 | ||
| @@ -11,29 +12,10 @@ PageTable::~PageTable() noexcept = default; | |||
| 11 | 12 | ||
| 12 | bool PageTable::BeginTraversal(TraversalEntry* out_entry, TraversalContext* out_context, | 13 | bool PageTable::BeginTraversal(TraversalEntry* out_entry, TraversalContext* out_context, |
| 13 | Common::ProcessAddress address) const { | 14 | Common::ProcessAddress address) const { |
| 14 | // Setup invalid defaults. | 15 | out_context->next_offset = GetInteger(address); |
| 15 | out_entry->phys_addr = 0; | 16 | out_context->next_page = address / page_size; |
| 16 | out_entry->block_size = page_size; | ||
| 17 | out_context->next_page = 0; | ||
| 18 | |||
| 19 | // Validate that we can read the actual entry. | ||
| 20 | const auto page = address / page_size; | ||
| 21 | if (page >= backing_addr.size()) { | ||
| 22 | return false; | ||
| 23 | } | ||
| 24 | |||
| 25 | // Validate that the entry is mapped. | ||
| 26 | const auto phys_addr = backing_addr[page]; | ||
| 27 | if (phys_addr == 0) { | ||
| 28 | return false; | ||
| 29 | } | ||
| 30 | 17 | ||
| 31 | // Populate the results. | 18 | return this->ContinueTraversal(out_entry, out_context); |
| 32 | out_entry->phys_addr = phys_addr + GetInteger(address); | ||
| 33 | out_context->next_page = page + 1; | ||
| 34 | out_context->next_offset = GetInteger(address) + page_size; | ||
| 35 | |||
| 36 | return true; | ||
| 37 | } | 19 | } |
| 38 | 20 | ||
| 39 | bool PageTable::ContinueTraversal(TraversalEntry* out_entry, TraversalContext* context) const { | 21 | bool PageTable::ContinueTraversal(TraversalEntry* out_entry, TraversalContext* context) const { |
| @@ -41,6 +23,12 @@ bool PageTable::ContinueTraversal(TraversalEntry* out_entry, TraversalContext* c | |||
| 41 | out_entry->phys_addr = 0; | 23 | out_entry->phys_addr = 0; |
| 42 | out_entry->block_size = page_size; | 24 | out_entry->block_size = page_size; |
| 43 | 25 | ||
| 26 | // Regardless of whether the page was mapped, advance on exit. | ||
| 27 | SCOPE_EXIT({ | ||
| 28 | context->next_page += 1; | ||
| 29 | context->next_offset += page_size; | ||
| 30 | }); | ||
| 31 | |||
| 44 | // Validate that we can read the actual entry. | 32 | // Validate that we can read the actual entry. |
| 45 | const auto page = context->next_page; | 33 | const auto page = context->next_page; |
| 46 | if (page >= backing_addr.size()) { | 34 | if (page >= backing_addr.size()) { |
| @@ -55,8 +43,6 @@ bool PageTable::ContinueTraversal(TraversalEntry* out_entry, TraversalContext* c | |||
| 55 | 43 | ||
| 56 | // Populate the results. | 44 | // Populate the results. |
| 57 | out_entry->phys_addr = phys_addr + context->next_offset; | 45 | out_entry->phys_addr = phys_addr + context->next_offset; |
| 58 | context->next_page = page + 1; | ||
| 59 | context->next_offset += page_size; | ||
| 60 | 46 | ||
| 61 | return true; | 47 | return true; |
| 62 | } | 48 | } |
diff --git a/src/common/settings_common.cpp b/src/common/settings_common.cpp index 5960b78aa..b90e3509c 100644 --- a/src/common/settings_common.cpp +++ b/src/common/settings_common.cpp | |||
| @@ -35,7 +35,7 @@ bool BasicSetting::Save() const { | |||
| 35 | return save; | 35 | return save; |
| 36 | } | 36 | } |
| 37 | 37 | ||
| 38 | bool BasicSetting::RuntimeModfiable() const { | 38 | bool BasicSetting::RuntimeModifiable() const { |
| 39 | return runtime_modifiable; | 39 | return runtime_modifiable; |
| 40 | } | 40 | } |
| 41 | 41 | ||
diff --git a/src/common/settings_common.h b/src/common/settings_common.h index 1a290ad77..987489e8a 100644 --- a/src/common/settings_common.h +++ b/src/common/settings_common.h | |||
| @@ -186,7 +186,7 @@ public: | |||
| 186 | /** | 186 | /** |
| 187 | * @returns true if the current setting can be changed while the guest is running. | 187 | * @returns true if the current setting can be changed while the guest is running. |
| 188 | */ | 188 | */ |
| 189 | [[nodiscard]] bool RuntimeModfiable() const; | 189 | [[nodiscard]] bool RuntimeModifiable() const; |
| 190 | 190 | ||
| 191 | /** | 191 | /** |
| 192 | * @returns A unique number corresponding to the setting. | 192 | * @returns A unique number corresponding to the setting. |
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 753f55ebe..293d9647b 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt | |||
| @@ -490,6 +490,10 @@ add_library(core STATIC | |||
| 490 | hle/service/filesystem/fsp_pr.h | 490 | hle/service/filesystem/fsp_pr.h |
| 491 | hle/service/filesystem/fsp_srv.cpp | 491 | hle/service/filesystem/fsp_srv.cpp |
| 492 | hle/service/filesystem/fsp_srv.h | 492 | hle/service/filesystem/fsp_srv.h |
| 493 | hle/service/filesystem/romfs_controller.cpp | ||
| 494 | hle/service/filesystem/romfs_controller.h | ||
| 495 | hle/service/filesystem/save_data_controller.cpp | ||
| 496 | hle/service/filesystem/save_data_controller.h | ||
| 493 | hle/service/fgm/fgm.cpp | 497 | hle/service/fgm/fgm.cpp |
| 494 | hle/service/fgm/fgm.h | 498 | hle/service/fgm/fgm.h |
| 495 | hle/service/friend/friend.cpp | 499 | hle/service/friend/friend.cpp |
diff --git a/src/core/arm/nce/patcher.cpp b/src/core/arm/nce/patcher.cpp index 47a7a8880..c7285e3a0 100644 --- a/src/core/arm/nce/patcher.cpp +++ b/src/core/arm/nce/patcher.cpp | |||
| @@ -22,14 +22,10 @@ using NativeExecutionParameters = Kernel::KThread::NativeExecutionParameters; | |||
| 22 | constexpr size_t MaxRelativeBranch = 128_MiB; | 22 | constexpr size_t MaxRelativeBranch = 128_MiB; |
| 23 | constexpr u32 ModuleCodeIndex = 0x24 / sizeof(u32); | 23 | constexpr u32 ModuleCodeIndex = 0x24 / sizeof(u32); |
| 24 | 24 | ||
| 25 | Patcher::Patcher() : c(m_patch_instructions) {} | 25 | Patcher::Patcher() : c(m_patch_instructions) { |
| 26 | 26 | // The first word of the patch section is always a branch to the first instruction of the | |
| 27 | Patcher::~Patcher() = default; | 27 | // module. |
| 28 | 28 | c.dw(0); | |
| 29 | void Patcher::PatchText(const Kernel::PhysicalMemory& program_image, | ||
| 30 | const Kernel::CodeSet::Segment& code) { | ||
| 31 | // Branch to the first instruction of the module. | ||
| 32 | this->BranchToModule(0); | ||
| 33 | 29 | ||
| 34 | // Write save context helper function. | 30 | // Write save context helper function. |
| 35 | c.l(m_save_context); | 31 | c.l(m_save_context); |
| @@ -38,6 +34,25 @@ void Patcher::PatchText(const Kernel::PhysicalMemory& program_image, | |||
| 38 | // Write load context helper function. | 34 | // Write load context helper function. |
| 39 | c.l(m_load_context); | 35 | c.l(m_load_context); |
| 40 | WriteLoadContext(); | 36 | WriteLoadContext(); |
| 37 | } | ||
| 38 | |||
| 39 | Patcher::~Patcher() = default; | ||
| 40 | |||
| 41 | bool Patcher::PatchText(const Kernel::PhysicalMemory& program_image, | ||
| 42 | const Kernel::CodeSet::Segment& code) { | ||
| 43 | // If we have patched modules but cannot reach the new module, then it needs its own patcher. | ||
| 44 | const size_t image_size = program_image.size(); | ||
| 45 | if (total_program_size + image_size > MaxRelativeBranch && total_program_size > 0) { | ||
| 46 | return false; | ||
| 47 | } | ||
| 48 | |||
| 49 | // Add a new module patch to our list | ||
| 50 | modules.emplace_back(); | ||
| 51 | curr_patch = &modules.back(); | ||
| 52 | |||
| 53 | // The first word of the patch section is always a branch to the first instruction of the | ||
| 54 | // module. | ||
| 55 | curr_patch->m_branch_to_module_relocations.push_back({0, 0}); | ||
| 41 | 56 | ||
| 42 | // Retrieve text segment data. | 57 | // Retrieve text segment data. |
| 43 | const auto text = std::span{program_image}.subspan(code.offset, code.size); | 58 | const auto text = std::span{program_image}.subspan(code.offset, code.size); |
| @@ -94,16 +109,17 @@ void Patcher::PatchText(const Kernel::PhysicalMemory& program_image, | |||
| 94 | } | 109 | } |
| 95 | 110 | ||
| 96 | if (auto exclusive = Exclusive{inst}; exclusive.Verify()) { | 111 | if (auto exclusive = Exclusive{inst}; exclusive.Verify()) { |
| 97 | m_exclusives.push_back(i); | 112 | curr_patch->m_exclusives.push_back(i); |
| 98 | } | 113 | } |
| 99 | } | 114 | } |
| 100 | 115 | ||
| 101 | // Determine patching mode for the final relocation step | 116 | // Determine patching mode for the final relocation step |
| 102 | const size_t image_size = program_image.size(); | 117 | total_program_size += image_size; |
| 103 | this->mode = image_size > MaxRelativeBranch ? PatchMode::PreText : PatchMode::PostData; | 118 | this->mode = image_size > MaxRelativeBranch ? PatchMode::PreText : PatchMode::PostData; |
| 119 | return true; | ||
| 104 | } | 120 | } |
| 105 | 121 | ||
| 106 | void Patcher::RelocateAndCopy(Common::ProcessAddress load_base, | 122 | bool Patcher::RelocateAndCopy(Common::ProcessAddress load_base, |
| 107 | const Kernel::CodeSet::Segment& code, | 123 | const Kernel::CodeSet::Segment& code, |
| 108 | Kernel::PhysicalMemory& program_image, | 124 | Kernel::PhysicalMemory& program_image, |
| 109 | EntryTrampolines* out_trampolines) { | 125 | EntryTrampolines* out_trampolines) { |
| @@ -120,7 +136,7 @@ void Patcher::RelocateAndCopy(Common::ProcessAddress load_base, | |||
| 120 | if (mode == PatchMode::PreText) { | 136 | if (mode == PatchMode::PreText) { |
| 121 | rc.B(rel.patch_offset - patch_size - rel.module_offset); | 137 | rc.B(rel.patch_offset - patch_size - rel.module_offset); |
| 122 | } else { | 138 | } else { |
| 123 | rc.B(image_size - rel.module_offset + rel.patch_offset); | 139 | rc.B(total_program_size - rel.module_offset + rel.patch_offset); |
| 124 | } | 140 | } |
| 125 | }; | 141 | }; |
| 126 | 142 | ||
| @@ -129,7 +145,7 @@ void Patcher::RelocateAndCopy(Common::ProcessAddress load_base, | |||
| 129 | if (mode == PatchMode::PreText) { | 145 | if (mode == PatchMode::PreText) { |
| 130 | rc.B(patch_size - rel.patch_offset + rel.module_offset); | 146 | rc.B(patch_size - rel.patch_offset + rel.module_offset); |
| 131 | } else { | 147 | } else { |
| 132 | rc.B(rel.module_offset - image_size - rel.patch_offset); | 148 | rc.B(rel.module_offset - total_program_size - rel.patch_offset); |
| 133 | } | 149 | } |
| 134 | }; | 150 | }; |
| 135 | 151 | ||
| @@ -137,7 +153,7 @@ void Patcher::RelocateAndCopy(Common::ProcessAddress load_base, | |||
| 137 | if (mode == PatchMode::PreText) { | 153 | if (mode == PatchMode::PreText) { |
| 138 | return GetInteger(load_base) + patch_offset; | 154 | return GetInteger(load_base) + patch_offset; |
| 139 | } else { | 155 | } else { |
| 140 | return GetInteger(load_base) + image_size + patch_offset; | 156 | return GetInteger(load_base) + total_program_size + patch_offset; |
| 141 | } | 157 | } |
| 142 | }; | 158 | }; |
| 143 | 159 | ||
| @@ -150,39 +166,50 @@ void Patcher::RelocateAndCopy(Common::ProcessAddress load_base, | |||
| 150 | }; | 166 | }; |
| 151 | 167 | ||
| 152 | // We are now ready to relocate! | 168 | // We are now ready to relocate! |
| 153 | for (const Relocation& rel : m_branch_to_patch_relocations) { | 169 | auto& patch = modules[m_relocate_module_index++]; |
| 170 | for (const Relocation& rel : patch.m_branch_to_patch_relocations) { | ||
| 154 | ApplyBranchToPatchRelocation(text_words.data() + rel.module_offset / sizeof(u32), rel); | 171 | ApplyBranchToPatchRelocation(text_words.data() + rel.module_offset / sizeof(u32), rel); |
| 155 | } | 172 | } |
| 156 | for (const Relocation& rel : m_branch_to_module_relocations) { | 173 | for (const Relocation& rel : patch.m_branch_to_module_relocations) { |
| 157 | ApplyBranchToModuleRelocation(m_patch_instructions.data() + rel.patch_offset / sizeof(u32), | 174 | ApplyBranchToModuleRelocation(m_patch_instructions.data() + rel.patch_offset / sizeof(u32), |
| 158 | rel); | 175 | rel); |
| 159 | } | 176 | } |
| 160 | 177 | ||
| 161 | // Rewrite PC constants and record post trampolines | 178 | // Rewrite PC constants and record post trampolines |
| 162 | for (const Relocation& rel : m_write_module_pc_relocations) { | 179 | for (const Relocation& rel : patch.m_write_module_pc_relocations) { |
| 163 | oaknut::CodeGenerator rc{m_patch_instructions.data() + rel.patch_offset / sizeof(u32)}; | 180 | oaknut::CodeGenerator rc{m_patch_instructions.data() + rel.patch_offset / sizeof(u32)}; |
| 164 | rc.dx(RebasePc(rel.module_offset)); | 181 | rc.dx(RebasePc(rel.module_offset)); |
| 165 | } | 182 | } |
| 166 | for (const Trampoline& rel : m_trampolines) { | 183 | for (const Trampoline& rel : patch.m_trampolines) { |
| 167 | out_trampolines->insert({RebasePc(rel.module_offset), RebasePatch(rel.patch_offset)}); | 184 | out_trampolines->insert({RebasePc(rel.module_offset), RebasePatch(rel.patch_offset)}); |
| 168 | } | 185 | } |
| 169 | 186 | ||
| 170 | // Cortex-A57 seems to treat all exclusives as ordered, but newer processors do not. | 187 | // Cortex-A57 seems to treat all exclusives as ordered, but newer processors do not. |
| 171 | // Convert to ordered to preserve this assumption. | 188 | // Convert to ordered to preserve this assumption. |
| 172 | for (const ModuleTextAddress i : m_exclusives) { | 189 | for (const ModuleTextAddress i : patch.m_exclusives) { |
| 173 | auto exclusive = Exclusive{text_words[i]}; | 190 | auto exclusive = Exclusive{text_words[i]}; |
| 174 | text_words[i] = exclusive.AsOrdered(); | 191 | text_words[i] = exclusive.AsOrdered(); |
| 175 | } | 192 | } |
| 176 | 193 | ||
| 177 | // Copy to program image | 194 | // Remove the patched module size from the total. This is done so total_program_size |
| 178 | if (this->mode == PatchMode::PreText) { | 195 | // always represents the distance from the currently patched module to the patch section. |
| 179 | std::memcpy(program_image.data(), m_patch_instructions.data(), | 196 | total_program_size -= image_size; |
| 180 | m_patch_instructions.size() * sizeof(u32)); | 197 | |
| 181 | } else { | 198 | // Only copy to the program image of the last module |
| 182 | program_image.resize(image_size + patch_size); | 199 | if (m_relocate_module_index == modules.size()) { |
| 183 | std::memcpy(program_image.data() + image_size, m_patch_instructions.data(), | 200 | if (this->mode == PatchMode::PreText) { |
| 184 | m_patch_instructions.size() * sizeof(u32)); | 201 | ASSERT(image_size == total_program_size); |
| 202 | std::memcpy(program_image.data(), m_patch_instructions.data(), | ||
| 203 | m_patch_instructions.size() * sizeof(u32)); | ||
| 204 | } else { | ||
| 205 | program_image.resize(image_size + patch_size); | ||
| 206 | std::memcpy(program_image.data() + image_size, m_patch_instructions.data(), | ||
| 207 | m_patch_instructions.size() * sizeof(u32)); | ||
| 208 | } | ||
| 209 | return true; | ||
| 185 | } | 210 | } |
| 211 | |||
| 212 | return false; | ||
| 186 | } | 213 | } |
| 187 | 214 | ||
| 188 | size_t Patcher::GetSectionSize() const noexcept { | 215 | size_t Patcher::GetSectionSize() const noexcept { |
| @@ -322,7 +349,7 @@ void Patcher::WriteSvcTrampoline(ModuleDestLabel module_dest, u32 svc_id) { | |||
| 322 | 349 | ||
| 323 | // Write the post-SVC trampoline address, which will jump back to the guest after restoring its | 350 | // Write the post-SVC trampoline address, which will jump back to the guest after restoring its |
| 324 | // state. | 351 | // state. |
| 325 | m_trampolines.push_back({c.offset(), module_dest}); | 352 | curr_patch->m_trampolines.push_back({c.offset(), module_dest}); |
| 326 | 353 | ||
| 327 | // Host called this location. Save the return address so we can | 354 | // Host called this location. Save the return address so we can |
| 328 | // unwind the stack properly when jumping back. | 355 | // unwind the stack properly when jumping back. |
diff --git a/src/core/arm/nce/patcher.h b/src/core/arm/nce/patcher.h index c6d1608c1..a44f385e2 100644 --- a/src/core/arm/nce/patcher.h +++ b/src/core/arm/nce/patcher.h | |||
| @@ -31,9 +31,9 @@ public: | |||
| 31 | explicit Patcher(); | 31 | explicit Patcher(); |
| 32 | ~Patcher(); | 32 | ~Patcher(); |
| 33 | 33 | ||
| 34 | void PatchText(const Kernel::PhysicalMemory& program_image, | 34 | bool PatchText(const Kernel::PhysicalMemory& program_image, |
| 35 | const Kernel::CodeSet::Segment& code); | 35 | const Kernel::CodeSet::Segment& code); |
| 36 | void RelocateAndCopy(Common::ProcessAddress load_base, const Kernel::CodeSet::Segment& code, | 36 | bool RelocateAndCopy(Common::ProcessAddress load_base, const Kernel::CodeSet::Segment& code, |
| 37 | Kernel::PhysicalMemory& program_image, EntryTrampolines* out_trampolines); | 37 | Kernel::PhysicalMemory& program_image, EntryTrampolines* out_trampolines); |
| 38 | size_t GetSectionSize() const noexcept; | 38 | size_t GetSectionSize() const noexcept; |
| 39 | 39 | ||
| @@ -61,16 +61,16 @@ private: | |||
| 61 | 61 | ||
| 62 | private: | 62 | private: |
| 63 | void BranchToPatch(uintptr_t module_dest) { | 63 | void BranchToPatch(uintptr_t module_dest) { |
| 64 | m_branch_to_patch_relocations.push_back({c.offset(), module_dest}); | 64 | curr_patch->m_branch_to_patch_relocations.push_back({c.offset(), module_dest}); |
| 65 | } | 65 | } |
| 66 | 66 | ||
| 67 | void BranchToModule(uintptr_t module_dest) { | 67 | void BranchToModule(uintptr_t module_dest) { |
| 68 | m_branch_to_module_relocations.push_back({c.offset(), module_dest}); | 68 | curr_patch->m_branch_to_module_relocations.push_back({c.offset(), module_dest}); |
| 69 | c.dw(0); | 69 | c.dw(0); |
| 70 | } | 70 | } |
| 71 | 71 | ||
| 72 | void WriteModulePc(uintptr_t module_dest) { | 72 | void WriteModulePc(uintptr_t module_dest) { |
| 73 | m_write_module_pc_relocations.push_back({c.offset(), module_dest}); | 73 | curr_patch->m_write_module_pc_relocations.push_back({c.offset(), module_dest}); |
| 74 | c.dx(0); | 74 | c.dx(0); |
| 75 | } | 75 | } |
| 76 | 76 | ||
| @@ -84,15 +84,22 @@ private: | |||
| 84 | uintptr_t module_offset; ///< Offset in bytes from the start of the text section. | 84 | uintptr_t module_offset; ///< Offset in bytes from the start of the text section. |
| 85 | }; | 85 | }; |
| 86 | 86 | ||
| 87 | struct ModulePatch { | ||
| 88 | std::vector<Trampoline> m_trampolines; | ||
| 89 | std::vector<Relocation> m_branch_to_patch_relocations{}; | ||
| 90 | std::vector<Relocation> m_branch_to_module_relocations{}; | ||
| 91 | std::vector<Relocation> m_write_module_pc_relocations{}; | ||
| 92 | std::vector<ModuleTextAddress> m_exclusives{}; | ||
| 93 | }; | ||
| 94 | |||
| 87 | oaknut::VectorCodeGenerator c; | 95 | oaknut::VectorCodeGenerator c; |
| 88 | std::vector<Trampoline> m_trampolines; | ||
| 89 | std::vector<Relocation> m_branch_to_patch_relocations{}; | ||
| 90 | std::vector<Relocation> m_branch_to_module_relocations{}; | ||
| 91 | std::vector<Relocation> m_write_module_pc_relocations{}; | ||
| 92 | std::vector<ModuleTextAddress> m_exclusives{}; | ||
| 93 | oaknut::Label m_save_context{}; | 96 | oaknut::Label m_save_context{}; |
| 94 | oaknut::Label m_load_context{}; | 97 | oaknut::Label m_load_context{}; |
| 95 | PatchMode mode{PatchMode::None}; | 98 | PatchMode mode{PatchMode::None}; |
| 99 | size_t total_program_size{}; | ||
| 100 | size_t m_relocate_module_index{}; | ||
| 101 | std::vector<ModulePatch> modules; | ||
| 102 | ModulePatch* curr_patch; | ||
| 96 | }; | 103 | }; |
| 97 | 104 | ||
| 98 | } // namespace Core::NCE | 105 | } // namespace Core::NCE |
diff --git a/src/core/core.cpp b/src/core/core.cpp index c063f7719..461eea9c8 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp | |||
| @@ -413,6 +413,7 @@ struct System::Impl { | |||
| 413 | kernel.ShutdownCores(); | 413 | kernel.ShutdownCores(); |
| 414 | services.reset(); | 414 | services.reset(); |
| 415 | service_manager.reset(); | 415 | service_manager.reset(); |
| 416 | fs_controller.Reset(); | ||
| 416 | cheat_engine.reset(); | 417 | cheat_engine.reset(); |
| 417 | telemetry_session.reset(); | 418 | telemetry_session.reset(); |
| 418 | time_manager.Shutdown(); | 419 | time_manager.Shutdown(); |
diff --git a/src/core/cpu_manager.h b/src/core/cpu_manager.h index 0deea9c58..a249dc5f7 100644 --- a/src/core/cpu_manager.h +++ b/src/core/cpu_manager.h | |||
| @@ -64,7 +64,7 @@ public: | |||
| 64 | return [this] { ShutdownThreadFunction(); }; | 64 | return [this] { ShutdownThreadFunction(); }; |
| 65 | } | 65 | } |
| 66 | 66 | ||
| 67 | void PreemptSingleCore(bool from_running_enviroment = true); | 67 | void PreemptSingleCore(bool from_running_environment = true); |
| 68 | 68 | ||
| 69 | std::size_t CurrentCore() const { | 69 | std::size_t CurrentCore() const { |
| 70 | return current_core.load(); | 70 | return current_core.load(); |
diff --git a/src/core/debugger/debugger.cpp b/src/core/debugger/debugger.cpp index 0e270eb50..e86aae846 100644 --- a/src/core/debugger/debugger.cpp +++ b/src/core/debugger/debugger.cpp | |||
| @@ -114,7 +114,7 @@ public: | |||
| 114 | } | 114 | } |
| 115 | 115 | ||
| 116 | Kernel::KThread* GetActiveThread() override { | 116 | Kernel::KThread* GetActiveThread() override { |
| 117 | return state->active_thread; | 117 | return state->active_thread.GetPointerUnsafe(); |
| 118 | } | 118 | } |
| 119 | 119 | ||
| 120 | private: | 120 | private: |
| @@ -147,11 +147,14 @@ private: | |||
| 147 | 147 | ||
| 148 | std::scoped_lock lk{connection_lock}; | 148 | std::scoped_lock lk{connection_lock}; |
| 149 | 149 | ||
| 150 | // Find the process we are going to debug. | ||
| 151 | SetDebugProcess(); | ||
| 152 | |||
| 150 | // Ensure everything is stopped. | 153 | // Ensure everything is stopped. |
| 151 | PauseEmulation(); | 154 | PauseEmulation(); |
| 152 | 155 | ||
| 153 | // Set up the new frontend. | 156 | // Set up the new frontend. |
| 154 | frontend = std::make_unique<GDBStub>(*this, system); | 157 | frontend = std::make_unique<GDBStub>(*this, system, debug_process.GetPointerUnsafe()); |
| 155 | 158 | ||
| 156 | // Set the new state. This will tear down any existing state. | 159 | // Set the new state. This will tear down any existing state. |
| 157 | state = ConnectionState{ | 160 | state = ConnectionState{ |
| @@ -194,15 +197,20 @@ private: | |||
| 194 | UpdateActiveThread(); | 197 | UpdateActiveThread(); |
| 195 | 198 | ||
| 196 | if (state->info.type == SignalType::Watchpoint) { | 199 | if (state->info.type == SignalType::Watchpoint) { |
| 197 | frontend->Watchpoint(state->active_thread, *state->info.watchpoint); | 200 | frontend->Watchpoint(std::addressof(*state->active_thread), |
| 201 | *state->info.watchpoint); | ||
| 198 | } else { | 202 | } else { |
| 199 | frontend->Stopped(state->active_thread); | 203 | frontend->Stopped(std::addressof(*state->active_thread)); |
| 200 | } | 204 | } |
| 201 | 205 | ||
| 202 | break; | 206 | break; |
| 203 | case SignalType::ShuttingDown: | 207 | case SignalType::ShuttingDown: |
| 204 | frontend->ShuttingDown(); | 208 | frontend->ShuttingDown(); |
| 205 | 209 | ||
| 210 | // Release members. | ||
| 211 | state->active_thread.Reset(nullptr); | ||
| 212 | debug_process.Reset(nullptr); | ||
| 213 | |||
| 206 | // Wait for emulation to shut down gracefully now. | 214 | // Wait for emulation to shut down gracefully now. |
| 207 | state->signal_pipe.close(); | 215 | state->signal_pipe.close(); |
| 208 | state->client_socket.shutdown(boost::asio::socket_base::shutdown_both); | 216 | state->client_socket.shutdown(boost::asio::socket_base::shutdown_both); |
| @@ -222,7 +230,7 @@ private: | |||
| 222 | stopped = true; | 230 | stopped = true; |
| 223 | PauseEmulation(); | 231 | PauseEmulation(); |
| 224 | UpdateActiveThread(); | 232 | UpdateActiveThread(); |
| 225 | frontend->Stopped(state->active_thread); | 233 | frontend->Stopped(state->active_thread.GetPointerUnsafe()); |
| 226 | break; | 234 | break; |
| 227 | } | 235 | } |
| 228 | case DebuggerAction::Continue: | 236 | case DebuggerAction::Continue: |
| @@ -232,7 +240,7 @@ private: | |||
| 232 | MarkResumed([&] { | 240 | MarkResumed([&] { |
| 233 | state->active_thread->SetStepState(Kernel::StepState::StepPending); | 241 | state->active_thread->SetStepState(Kernel::StepState::StepPending); |
| 234 | state->active_thread->Resume(Kernel::SuspendType::Debug); | 242 | state->active_thread->Resume(Kernel::SuspendType::Debug); |
| 235 | ResumeEmulation(state->active_thread); | 243 | ResumeEmulation(state->active_thread.GetPointerUnsafe()); |
| 236 | }); | 244 | }); |
| 237 | break; | 245 | break; |
| 238 | case DebuggerAction::StepThreadLocked: { | 246 | case DebuggerAction::StepThreadLocked: { |
| @@ -255,6 +263,7 @@ private: | |||
| 255 | } | 263 | } |
| 256 | 264 | ||
| 257 | void PauseEmulation() { | 265 | void PauseEmulation() { |
| 266 | Kernel::KScopedLightLock ll{debug_process->GetListLock()}; | ||
| 258 | Kernel::KScopedSchedulerLock sl{system.Kernel()}; | 267 | Kernel::KScopedSchedulerLock sl{system.Kernel()}; |
| 259 | 268 | ||
| 260 | // Put all threads to sleep on next scheduler round. | 269 | // Put all threads to sleep on next scheduler round. |
| @@ -264,6 +273,9 @@ private: | |||
| 264 | } | 273 | } |
| 265 | 274 | ||
| 266 | void ResumeEmulation(Kernel::KThread* except = nullptr) { | 275 | void ResumeEmulation(Kernel::KThread* except = nullptr) { |
| 276 | Kernel::KScopedLightLock ll{debug_process->GetListLock()}; | ||
| 277 | Kernel::KScopedSchedulerLock sl{system.Kernel()}; | ||
| 278 | |||
| 267 | // Wake up all threads. | 279 | // Wake up all threads. |
| 268 | for (auto& thread : ThreadList()) { | 280 | for (auto& thread : ThreadList()) { |
| 269 | if (std::addressof(thread) == except) { | 281 | if (std::addressof(thread) == except) { |
| @@ -277,15 +289,16 @@ private: | |||
| 277 | 289 | ||
| 278 | template <typename Callback> | 290 | template <typename Callback> |
| 279 | void MarkResumed(Callback&& cb) { | 291 | void MarkResumed(Callback&& cb) { |
| 280 | Kernel::KScopedSchedulerLock sl{system.Kernel()}; | ||
| 281 | stopped = false; | 292 | stopped = false; |
| 282 | cb(); | 293 | cb(); |
| 283 | } | 294 | } |
| 284 | 295 | ||
| 285 | void UpdateActiveThread() { | 296 | void UpdateActiveThread() { |
| 297 | Kernel::KScopedLightLock ll{debug_process->GetListLock()}; | ||
| 298 | |||
| 286 | auto& threads{ThreadList()}; | 299 | auto& threads{ThreadList()}; |
| 287 | for (auto& thread : threads) { | 300 | for (auto& thread : threads) { |
| 288 | if (std::addressof(thread) == state->active_thread) { | 301 | if (std::addressof(thread) == state->active_thread.GetPointerUnsafe()) { |
| 289 | // Thread is still alive, no need to update. | 302 | // Thread is still alive, no need to update. |
| 290 | return; | 303 | return; |
| 291 | } | 304 | } |
| @@ -293,12 +306,18 @@ private: | |||
| 293 | state->active_thread = std::addressof(threads.front()); | 306 | state->active_thread = std::addressof(threads.front()); |
| 294 | } | 307 | } |
| 295 | 308 | ||
| 309 | private: | ||
| 310 | void SetDebugProcess() { | ||
| 311 | debug_process = std::move(system.Kernel().GetProcessList().back()); | ||
| 312 | } | ||
| 313 | |||
| 296 | Kernel::KProcess::ThreadList& ThreadList() { | 314 | Kernel::KProcess::ThreadList& ThreadList() { |
| 297 | return system.ApplicationProcess()->GetThreadList(); | 315 | return debug_process->GetThreadList(); |
| 298 | } | 316 | } |
| 299 | 317 | ||
| 300 | private: | 318 | private: |
| 301 | System& system; | 319 | System& system; |
| 320 | Kernel::KScopedAutoObject<Kernel::KProcess> debug_process; | ||
| 302 | std::unique_ptr<DebuggerFrontend> frontend; | 321 | std::unique_ptr<DebuggerFrontend> frontend; |
| 303 | 322 | ||
| 304 | boost::asio::io_context io_context; | 323 | boost::asio::io_context io_context; |
| @@ -310,7 +329,7 @@ private: | |||
| 310 | boost::process::async_pipe signal_pipe; | 329 | boost::process::async_pipe signal_pipe; |
| 311 | 330 | ||
| 312 | SignalInfo info; | 331 | SignalInfo info; |
| 313 | Kernel::KThread* active_thread; | 332 | Kernel::KScopedAutoObject<Kernel::KThread> active_thread; |
| 314 | std::array<u8, 4096> client_data; | 333 | std::array<u8, 4096> client_data; |
| 315 | bool pipe_data; | 334 | bool pipe_data; |
| 316 | }; | 335 | }; |
diff --git a/src/core/debugger/gdbstub.cpp b/src/core/debugger/gdbstub.cpp index 66e46c4ba..80091cc7e 100644 --- a/src/core/debugger/gdbstub.cpp +++ b/src/core/debugger/gdbstub.cpp | |||
| @@ -108,9 +108,9 @@ static std::string EscapeXML(std::string_view data) { | |||
| 108 | return escaped; | 108 | return escaped; |
| 109 | } | 109 | } |
| 110 | 110 | ||
| 111 | GDBStub::GDBStub(DebuggerBackend& backend_, Core::System& system_) | 111 | GDBStub::GDBStub(DebuggerBackend& backend_, Core::System& system_, Kernel::KProcess* debug_process_) |
| 112 | : DebuggerFrontend(backend_), system{system_} { | 112 | : DebuggerFrontend(backend_), system{system_}, debug_process{debug_process_} { |
| 113 | if (system.ApplicationProcess()->Is64Bit()) { | 113 | if (GetProcess()->Is64Bit()) { |
| 114 | arch = std::make_unique<GDBStubA64>(); | 114 | arch = std::make_unique<GDBStubA64>(); |
| 115 | } else { | 115 | } else { |
| 116 | arch = std::make_unique<GDBStubA32>(); | 116 | arch = std::make_unique<GDBStubA32>(); |
| @@ -276,7 +276,7 @@ void GDBStub::ExecuteCommand(std::string_view packet, std::vector<DebuggerAction | |||
| 276 | const size_t size{static_cast<size_t>(strtoll(command.data() + sep, nullptr, 16))}; | 276 | const size_t size{static_cast<size_t>(strtoll(command.data() + sep, nullptr, 16))}; |
| 277 | 277 | ||
| 278 | std::vector<u8> mem(size); | 278 | std::vector<u8> mem(size); |
| 279 | if (system.ApplicationMemory().ReadBlock(addr, mem.data(), size)) { | 279 | if (GetMemory().ReadBlock(addr, mem.data(), size)) { |
| 280 | // Restore any bytes belonging to replaced instructions. | 280 | // Restore any bytes belonging to replaced instructions. |
| 281 | auto it = replaced_instructions.lower_bound(addr); | 281 | auto it = replaced_instructions.lower_bound(addr); |
| 282 | for (; it != replaced_instructions.end() && it->first < addr + size; it++) { | 282 | for (; it != replaced_instructions.end() && it->first < addr + size; it++) { |
| @@ -310,8 +310,8 @@ void GDBStub::ExecuteCommand(std::string_view packet, std::vector<DebuggerAction | |||
| 310 | const auto mem_substr{std::string_view(command).substr(mem_sep)}; | 310 | const auto mem_substr{std::string_view(command).substr(mem_sep)}; |
| 311 | const auto mem{Common::HexStringToVector(mem_substr, false)}; | 311 | const auto mem{Common::HexStringToVector(mem_substr, false)}; |
| 312 | 312 | ||
| 313 | if (system.ApplicationMemory().WriteBlock(addr, mem.data(), size)) { | 313 | if (GetMemory().WriteBlock(addr, mem.data(), size)) { |
| 314 | Core::InvalidateInstructionCacheRange(system.ApplicationProcess(), addr, size); | 314 | Core::InvalidateInstructionCacheRange(GetProcess(), addr, size); |
| 315 | SendReply(GDB_STUB_REPLY_OK); | 315 | SendReply(GDB_STUB_REPLY_OK); |
| 316 | } else { | 316 | } else { |
| 317 | SendReply(GDB_STUB_REPLY_ERR); | 317 | SendReply(GDB_STUB_REPLY_ERR); |
| @@ -353,7 +353,7 @@ void GDBStub::HandleBreakpointInsert(std::string_view command) { | |||
| 353 | const size_t addr{static_cast<size_t>(strtoll(command.data() + addr_sep, nullptr, 16))}; | 353 | const size_t addr{static_cast<size_t>(strtoll(command.data() + addr_sep, nullptr, 16))}; |
| 354 | const size_t size{static_cast<size_t>(strtoll(command.data() + size_sep, nullptr, 16))}; | 354 | const size_t size{static_cast<size_t>(strtoll(command.data() + size_sep, nullptr, 16))}; |
| 355 | 355 | ||
| 356 | if (!system.ApplicationMemory().IsValidVirtualAddressRange(addr, size)) { | 356 | if (!GetMemory().IsValidVirtualAddressRange(addr, size)) { |
| 357 | SendReply(GDB_STUB_REPLY_ERR); | 357 | SendReply(GDB_STUB_REPLY_ERR); |
| 358 | return; | 358 | return; |
| 359 | } | 359 | } |
| @@ -362,22 +362,20 @@ void GDBStub::HandleBreakpointInsert(std::string_view command) { | |||
| 362 | 362 | ||
| 363 | switch (type) { | 363 | switch (type) { |
| 364 | case BreakpointType::Software: | 364 | case BreakpointType::Software: |
| 365 | replaced_instructions[addr] = system.ApplicationMemory().Read32(addr); | 365 | replaced_instructions[addr] = GetMemory().Read32(addr); |
| 366 | system.ApplicationMemory().Write32(addr, arch->BreakpointInstruction()); | 366 | GetMemory().Write32(addr, arch->BreakpointInstruction()); |
| 367 | Core::InvalidateInstructionCacheRange(system.ApplicationProcess(), addr, sizeof(u32)); | 367 | Core::InvalidateInstructionCacheRange(GetProcess(), addr, sizeof(u32)); |
| 368 | success = true; | 368 | success = true; |
| 369 | break; | 369 | break; |
| 370 | case BreakpointType::WriteWatch: | 370 | case BreakpointType::WriteWatch: |
| 371 | success = system.ApplicationProcess()->InsertWatchpoint(addr, size, | 371 | success = GetProcess()->InsertWatchpoint(addr, size, Kernel::DebugWatchpointType::Write); |
| 372 | Kernel::DebugWatchpointType::Write); | ||
| 373 | break; | 372 | break; |
| 374 | case BreakpointType::ReadWatch: | 373 | case BreakpointType::ReadWatch: |
| 375 | success = system.ApplicationProcess()->InsertWatchpoint(addr, size, | 374 | success = GetProcess()->InsertWatchpoint(addr, size, Kernel::DebugWatchpointType::Read); |
| 376 | Kernel::DebugWatchpointType::Read); | ||
| 377 | break; | 375 | break; |
| 378 | case BreakpointType::AccessWatch: | 376 | case BreakpointType::AccessWatch: |
| 379 | success = system.ApplicationProcess()->InsertWatchpoint( | 377 | success = |
| 380 | addr, size, Kernel::DebugWatchpointType::ReadOrWrite); | 378 | GetProcess()->InsertWatchpoint(addr, size, Kernel::DebugWatchpointType::ReadOrWrite); |
| 381 | break; | 379 | break; |
| 382 | case BreakpointType::Hardware: | 380 | case BreakpointType::Hardware: |
| 383 | default: | 381 | default: |
| @@ -400,7 +398,7 @@ void GDBStub::HandleBreakpointRemove(std::string_view command) { | |||
| 400 | const size_t addr{static_cast<size_t>(strtoll(command.data() + addr_sep, nullptr, 16))}; | 398 | const size_t addr{static_cast<size_t>(strtoll(command.data() + addr_sep, nullptr, 16))}; |
| 401 | const size_t size{static_cast<size_t>(strtoll(command.data() + size_sep, nullptr, 16))}; | 399 | const size_t size{static_cast<size_t>(strtoll(command.data() + size_sep, nullptr, 16))}; |
| 402 | 400 | ||
| 403 | if (!system.ApplicationMemory().IsValidVirtualAddressRange(addr, size)) { | 401 | if (!GetMemory().IsValidVirtualAddressRange(addr, size)) { |
| 404 | SendReply(GDB_STUB_REPLY_ERR); | 402 | SendReply(GDB_STUB_REPLY_ERR); |
| 405 | return; | 403 | return; |
| 406 | } | 404 | } |
| @@ -411,24 +409,22 @@ void GDBStub::HandleBreakpointRemove(std::string_view command) { | |||
| 411 | case BreakpointType::Software: { | 409 | case BreakpointType::Software: { |
| 412 | const auto orig_insn{replaced_instructions.find(addr)}; | 410 | const auto orig_insn{replaced_instructions.find(addr)}; |
| 413 | if (orig_insn != replaced_instructions.end()) { | 411 | if (orig_insn != replaced_instructions.end()) { |
| 414 | system.ApplicationMemory().Write32(addr, orig_insn->second); | 412 | GetMemory().Write32(addr, orig_insn->second); |
| 415 | Core::InvalidateInstructionCacheRange(system.ApplicationProcess(), addr, sizeof(u32)); | 413 | Core::InvalidateInstructionCacheRange(GetProcess(), addr, sizeof(u32)); |
| 416 | replaced_instructions.erase(addr); | 414 | replaced_instructions.erase(addr); |
| 417 | success = true; | 415 | success = true; |
| 418 | } | 416 | } |
| 419 | break; | 417 | break; |
| 420 | } | 418 | } |
| 421 | case BreakpointType::WriteWatch: | 419 | case BreakpointType::WriteWatch: |
| 422 | success = system.ApplicationProcess()->RemoveWatchpoint(addr, size, | 420 | success = GetProcess()->RemoveWatchpoint(addr, size, Kernel::DebugWatchpointType::Write); |
| 423 | Kernel::DebugWatchpointType::Write); | ||
| 424 | break; | 421 | break; |
| 425 | case BreakpointType::ReadWatch: | 422 | case BreakpointType::ReadWatch: |
| 426 | success = system.ApplicationProcess()->RemoveWatchpoint(addr, size, | 423 | success = GetProcess()->RemoveWatchpoint(addr, size, Kernel::DebugWatchpointType::Read); |
| 427 | Kernel::DebugWatchpointType::Read); | ||
| 428 | break; | 424 | break; |
| 429 | case BreakpointType::AccessWatch: | 425 | case BreakpointType::AccessWatch: |
| 430 | success = system.ApplicationProcess()->RemoveWatchpoint( | 426 | success = |
| 431 | addr, size, Kernel::DebugWatchpointType::ReadOrWrite); | 427 | GetProcess()->RemoveWatchpoint(addr, size, Kernel::DebugWatchpointType::ReadOrWrite); |
| 432 | break; | 428 | break; |
| 433 | case BreakpointType::Hardware: | 429 | case BreakpointType::Hardware: |
| 434 | default: | 430 | default: |
| @@ -466,10 +462,10 @@ void GDBStub::HandleQuery(std::string_view command) { | |||
| 466 | const auto target_xml{arch->GetTargetXML()}; | 462 | const auto target_xml{arch->GetTargetXML()}; |
| 467 | SendReply(PaginateBuffer(target_xml, command.substr(30))); | 463 | SendReply(PaginateBuffer(target_xml, command.substr(30))); |
| 468 | } else if (command.starts_with("Offsets")) { | 464 | } else if (command.starts_with("Offsets")) { |
| 469 | const auto main_offset = Core::FindMainModuleEntrypoint(system.ApplicationProcess()); | 465 | const auto main_offset = Core::FindMainModuleEntrypoint(GetProcess()); |
| 470 | SendReply(fmt::format("TextSeg={:x}", GetInteger(main_offset))); | 466 | SendReply(fmt::format("TextSeg={:x}", GetInteger(main_offset))); |
| 471 | } else if (command.starts_with("Xfer:libraries:read::")) { | 467 | } else if (command.starts_with("Xfer:libraries:read::")) { |
| 472 | auto modules = Core::FindModules(system.ApplicationProcess()); | 468 | auto modules = Core::FindModules(GetProcess()); |
| 473 | 469 | ||
| 474 | std::string buffer; | 470 | std::string buffer; |
| 475 | buffer += R"(<?xml version="1.0"?>)"; | 471 | buffer += R"(<?xml version="1.0"?>)"; |
| @@ -483,7 +479,7 @@ void GDBStub::HandleQuery(std::string_view command) { | |||
| 483 | SendReply(PaginateBuffer(buffer, command.substr(21))); | 479 | SendReply(PaginateBuffer(buffer, command.substr(21))); |
| 484 | } else if (command.starts_with("fThreadInfo")) { | 480 | } else if (command.starts_with("fThreadInfo")) { |
| 485 | // beginning of list | 481 | // beginning of list |
| 486 | const auto& threads = system.ApplicationProcess()->GetThreadList(); | 482 | const auto& threads = GetProcess()->GetThreadList(); |
| 487 | std::vector<std::string> thread_ids; | 483 | std::vector<std::string> thread_ids; |
| 488 | for (const auto& thread : threads) { | 484 | for (const auto& thread : threads) { |
| 489 | thread_ids.push_back(fmt::format("{:x}", thread.GetThreadId())); | 485 | thread_ids.push_back(fmt::format("{:x}", thread.GetThreadId())); |
| @@ -497,7 +493,7 @@ void GDBStub::HandleQuery(std::string_view command) { | |||
| 497 | buffer += R"(<?xml version="1.0"?>)"; | 493 | buffer += R"(<?xml version="1.0"?>)"; |
| 498 | buffer += "<threads>"; | 494 | buffer += "<threads>"; |
| 499 | 495 | ||
| 500 | const auto& threads = system.ApplicationProcess()->GetThreadList(); | 496 | const auto& threads = GetProcess()->GetThreadList(); |
| 501 | for (const auto& thread : threads) { | 497 | for (const auto& thread : threads) { |
| 502 | auto thread_name{Core::GetThreadName(&thread)}; | 498 | auto thread_name{Core::GetThreadName(&thread)}; |
| 503 | if (!thread_name) { | 499 | if (!thread_name) { |
| @@ -559,28 +555,28 @@ void GDBStub::HandleVCont(std::string_view command, std::vector<DebuggerAction>& | |||
| 559 | } | 555 | } |
| 560 | 556 | ||
| 561 | constexpr std::array<std::pair<const char*, Kernel::Svc::MemoryState>, 22> MemoryStateNames{{ | 557 | constexpr std::array<std::pair<const char*, Kernel::Svc::MemoryState>, 22> MemoryStateNames{{ |
| 562 | {"----- Free -----", Kernel::Svc::MemoryState::Free}, | 558 | {"----- Free ------", Kernel::Svc::MemoryState::Free}, |
| 563 | {"Io ", Kernel::Svc::MemoryState::Io}, | 559 | {"Io ", Kernel::Svc::MemoryState::Io}, |
| 564 | {"Static ", Kernel::Svc::MemoryState::Static}, | 560 | {"Static ", Kernel::Svc::MemoryState::Static}, |
| 565 | {"Code ", Kernel::Svc::MemoryState::Code}, | 561 | {"Code ", Kernel::Svc::MemoryState::Code}, |
| 566 | {"CodeData ", Kernel::Svc::MemoryState::CodeData}, | 562 | {"CodeData ", Kernel::Svc::MemoryState::CodeData}, |
| 567 | {"Normal ", Kernel::Svc::MemoryState::Normal}, | 563 | {"Normal ", Kernel::Svc::MemoryState::Normal}, |
| 568 | {"Shared ", Kernel::Svc::MemoryState::Shared}, | 564 | {"Shared ", Kernel::Svc::MemoryState::Shared}, |
| 569 | {"AliasCode ", Kernel::Svc::MemoryState::AliasCode}, | 565 | {"AliasCode ", Kernel::Svc::MemoryState::AliasCode}, |
| 570 | {"AliasCodeData ", Kernel::Svc::MemoryState::AliasCodeData}, | 566 | {"AliasCodeData ", Kernel::Svc::MemoryState::AliasCodeData}, |
| 571 | {"Ipc ", Kernel::Svc::MemoryState::Ipc}, | 567 | {"Ipc ", Kernel::Svc::MemoryState::Ipc}, |
| 572 | {"Stack ", Kernel::Svc::MemoryState::Stack}, | 568 | {"Stack ", Kernel::Svc::MemoryState::Stack}, |
| 573 | {"ThreadLocal ", Kernel::Svc::MemoryState::ThreadLocal}, | 569 | {"ThreadLocal ", Kernel::Svc::MemoryState::ThreadLocal}, |
| 574 | {"Transfered ", Kernel::Svc::MemoryState::Transfered}, | 570 | {"Transferred ", Kernel::Svc::MemoryState::Transferred}, |
| 575 | {"SharedTransfered", Kernel::Svc::MemoryState::SharedTransfered}, | 571 | {"SharedTransferred", Kernel::Svc::MemoryState::SharedTransferred}, |
| 576 | {"SharedCode ", Kernel::Svc::MemoryState::SharedCode}, | 572 | {"SharedCode ", Kernel::Svc::MemoryState::SharedCode}, |
| 577 | {"Inaccessible ", Kernel::Svc::MemoryState::Inaccessible}, | 573 | {"Inaccessible ", Kernel::Svc::MemoryState::Inaccessible}, |
| 578 | {"NonSecureIpc ", Kernel::Svc::MemoryState::NonSecureIpc}, | 574 | {"NonSecureIpc ", Kernel::Svc::MemoryState::NonSecureIpc}, |
| 579 | {"NonDeviceIpc ", Kernel::Svc::MemoryState::NonDeviceIpc}, | 575 | {"NonDeviceIpc ", Kernel::Svc::MemoryState::NonDeviceIpc}, |
| 580 | {"Kernel ", Kernel::Svc::MemoryState::Kernel}, | 576 | {"Kernel ", Kernel::Svc::MemoryState::Kernel}, |
| 581 | {"GeneratedCode ", Kernel::Svc::MemoryState::GeneratedCode}, | 577 | {"GeneratedCode ", Kernel::Svc::MemoryState::GeneratedCode}, |
| 582 | {"CodeOut ", Kernel::Svc::MemoryState::CodeOut}, | 578 | {"CodeOut ", Kernel::Svc::MemoryState::CodeOut}, |
| 583 | {"Coverage ", Kernel::Svc::MemoryState::Coverage}, | 579 | {"Coverage ", Kernel::Svc::MemoryState::Coverage}, |
| 584 | }}; | 580 | }}; |
| 585 | 581 | ||
| 586 | static constexpr const char* GetMemoryStateName(Kernel::Svc::MemoryState state) { | 582 | static constexpr const char* GetMemoryStateName(Kernel::Svc::MemoryState state) { |
| @@ -613,7 +609,7 @@ void GDBStub::HandleRcmd(const std::vector<u8>& command) { | |||
| 613 | std::string_view command_str{reinterpret_cast<const char*>(&command[0]), command.size()}; | 609 | std::string_view command_str{reinterpret_cast<const char*>(&command[0]), command.size()}; |
| 614 | std::string reply; | 610 | std::string reply; |
| 615 | 611 | ||
| 616 | auto* process = system.ApplicationProcess(); | 612 | auto* process = GetProcess(); |
| 617 | auto& page_table = process->GetPageTable(); | 613 | auto& page_table = process->GetPageTable(); |
| 618 | 614 | ||
| 619 | const char* commands = "Commands:\n" | 615 | const char* commands = "Commands:\n" |
| @@ -714,7 +710,7 @@ void GDBStub::HandleRcmd(const std::vector<u8>& command) { | |||
| 714 | } | 710 | } |
| 715 | 711 | ||
| 716 | Kernel::KThread* GDBStub::GetThreadByID(u64 thread_id) { | 712 | Kernel::KThread* GDBStub::GetThreadByID(u64 thread_id) { |
| 717 | auto& threads{system.ApplicationProcess()->GetThreadList()}; | 713 | auto& threads{GetProcess()->GetThreadList()}; |
| 718 | for (auto& thread : threads) { | 714 | for (auto& thread : threads) { |
| 719 | if (thread.GetThreadId() == thread_id) { | 715 | if (thread.GetThreadId() == thread_id) { |
| 720 | return std::addressof(thread); | 716 | return std::addressof(thread); |
| @@ -783,4 +779,12 @@ void GDBStub::SendStatus(char status) { | |||
| 783 | backend.WriteToClient(buf); | 779 | backend.WriteToClient(buf); |
| 784 | } | 780 | } |
| 785 | 781 | ||
| 782 | Kernel::KProcess* GDBStub::GetProcess() { | ||
| 783 | return debug_process; | ||
| 784 | } | ||
| 785 | |||
| 786 | Core::Memory::Memory& GDBStub::GetMemory() { | ||
| 787 | return GetProcess()->GetMemory(); | ||
| 788 | } | ||
| 789 | |||
| 786 | } // namespace Core | 790 | } // namespace Core |
diff --git a/src/core/debugger/gdbstub.h b/src/core/debugger/gdbstub.h index 368197920..232dcf49f 100644 --- a/src/core/debugger/gdbstub.h +++ b/src/core/debugger/gdbstub.h | |||
| @@ -12,13 +12,22 @@ | |||
| 12 | #include "core/debugger/debugger_interface.h" | 12 | #include "core/debugger/debugger_interface.h" |
| 13 | #include "core/debugger/gdbstub_arch.h" | 13 | #include "core/debugger/gdbstub_arch.h" |
| 14 | 14 | ||
| 15 | namespace Kernel { | ||
| 16 | class KProcess; | ||
| 17 | } | ||
| 18 | |||
| 19 | namespace Core::Memory { | ||
| 20 | class Memory; | ||
| 21 | } | ||
| 22 | |||
| 15 | namespace Core { | 23 | namespace Core { |
| 16 | 24 | ||
| 17 | class System; | 25 | class System; |
| 18 | 26 | ||
| 19 | class GDBStub : public DebuggerFrontend { | 27 | class GDBStub : public DebuggerFrontend { |
| 20 | public: | 28 | public: |
| 21 | explicit GDBStub(DebuggerBackend& backend, Core::System& system); | 29 | explicit GDBStub(DebuggerBackend& backend, Core::System& system, |
| 30 | Kernel::KProcess* debug_process); | ||
| 22 | ~GDBStub() override; | 31 | ~GDBStub() override; |
| 23 | 32 | ||
| 24 | void Connected() override; | 33 | void Connected() override; |
| @@ -42,8 +51,12 @@ private: | |||
| 42 | void SendReply(std::string_view data); | 51 | void SendReply(std::string_view data); |
| 43 | void SendStatus(char status); | 52 | void SendStatus(char status); |
| 44 | 53 | ||
| 54 | Kernel::KProcess* GetProcess(); | ||
| 55 | Core::Memory::Memory& GetMemory(); | ||
| 56 | |||
| 45 | private: | 57 | private: |
| 46 | Core::System& system; | 58 | Core::System& system; |
| 59 | Kernel::KProcess* debug_process; | ||
| 47 | std::unique_ptr<GDBStubArch> arch; | 60 | std::unique_ptr<GDBStubArch> arch; |
| 48 | std::vector<char> current_command; | 61 | std::vector<char> current_command; |
| 49 | std::map<VAddr, u32> replaced_instructions; | 62 | std::map<VAddr, u32> replaced_instructions; |
diff --git a/src/core/file_sys/savedata_factory.cpp b/src/core/file_sys/savedata_factory.cpp index 12b3bd797..23196cd5f 100644 --- a/src/core/file_sys/savedata_factory.cpp +++ b/src/core/file_sys/savedata_factory.cpp | |||
| @@ -97,8 +97,9 @@ std::string SaveDataAttribute::DebugInfo() const { | |||
| 97 | static_cast<u8>(rank), index); | 97 | static_cast<u8>(rank), index); |
| 98 | } | 98 | } |
| 99 | 99 | ||
| 100 | SaveDataFactory::SaveDataFactory(Core::System& system_, VirtualDir save_directory_) | 100 | SaveDataFactory::SaveDataFactory(Core::System& system_, ProgramId program_id_, |
| 101 | : dir{std::move(save_directory_)}, system{system_} { | 101 | VirtualDir save_directory_) |
| 102 | : system{system_}, program_id{program_id_}, dir{std::move(save_directory_)} { | ||
| 102 | // Delete all temporary storages | 103 | // Delete all temporary storages |
| 103 | // On hardware, it is expected that temporary storage be empty at first use. | 104 | // On hardware, it is expected that temporary storage be empty at first use. |
| 104 | dir->DeleteSubdirectoryRecursive("temp"); | 105 | dir->DeleteSubdirectoryRecursive("temp"); |
| @@ -110,7 +111,7 @@ VirtualDir SaveDataFactory::Create(SaveDataSpaceId space, const SaveDataAttribut | |||
| 110 | PrintSaveDataAttributeWarnings(meta); | 111 | PrintSaveDataAttributeWarnings(meta); |
| 111 | 112 | ||
| 112 | const auto save_directory = | 113 | const auto save_directory = |
| 113 | GetFullPath(system, dir, space, meta.type, meta.title_id, meta.user_id, meta.save_id); | 114 | GetFullPath(program_id, dir, space, meta.type, meta.title_id, meta.user_id, meta.save_id); |
| 114 | 115 | ||
| 115 | return dir->CreateDirectoryRelative(save_directory); | 116 | return dir->CreateDirectoryRelative(save_directory); |
| 116 | } | 117 | } |
| @@ -118,7 +119,7 @@ VirtualDir SaveDataFactory::Create(SaveDataSpaceId space, const SaveDataAttribut | |||
| 118 | VirtualDir SaveDataFactory::Open(SaveDataSpaceId space, const SaveDataAttribute& meta) const { | 119 | VirtualDir SaveDataFactory::Open(SaveDataSpaceId space, const SaveDataAttribute& meta) const { |
| 119 | 120 | ||
| 120 | const auto save_directory = | 121 | const auto save_directory = |
| 121 | GetFullPath(system, dir, space, meta.type, meta.title_id, meta.user_id, meta.save_id); | 122 | GetFullPath(program_id, dir, space, meta.type, meta.title_id, meta.user_id, meta.save_id); |
| 122 | 123 | ||
| 123 | auto out = dir->GetDirectoryRelative(save_directory); | 124 | auto out = dir->GetDirectoryRelative(save_directory); |
| 124 | 125 | ||
| @@ -147,14 +148,14 @@ std::string SaveDataFactory::GetSaveDataSpaceIdPath(SaveDataSpaceId space) { | |||
| 147 | } | 148 | } |
| 148 | } | 149 | } |
| 149 | 150 | ||
| 150 | std::string SaveDataFactory::GetFullPath(Core::System& system, VirtualDir dir, | 151 | std::string SaveDataFactory::GetFullPath(ProgramId program_id, VirtualDir dir, |
| 151 | SaveDataSpaceId space, SaveDataType type, u64 title_id, | 152 | SaveDataSpaceId space, SaveDataType type, u64 title_id, |
| 152 | u128 user_id, u64 save_id) { | 153 | u128 user_id, u64 save_id) { |
| 153 | // According to switchbrew, if a save is of type SaveData and the title id field is 0, it should | 154 | // According to switchbrew, if a save is of type SaveData and the title id field is 0, it should |
| 154 | // be interpreted as the title id of the current process. | 155 | // be interpreted as the title id of the current process. |
| 155 | if (type == SaveDataType::SaveData || type == SaveDataType::DeviceSaveData) { | 156 | if (type == SaveDataType::SaveData || type == SaveDataType::DeviceSaveData) { |
| 156 | if (title_id == 0) { | 157 | if (title_id == 0) { |
| 157 | title_id = system.GetApplicationProcessProgramID(); | 158 | title_id = program_id; |
| 158 | } | 159 | } |
| 159 | } | 160 | } |
| 160 | 161 | ||
| @@ -201,7 +202,7 @@ std::string SaveDataFactory::GetUserGameSaveDataRoot(u128 user_id, bool future) | |||
| 201 | SaveDataSize SaveDataFactory::ReadSaveDataSize(SaveDataType type, u64 title_id, | 202 | SaveDataSize SaveDataFactory::ReadSaveDataSize(SaveDataType type, u64 title_id, |
| 202 | u128 user_id) const { | 203 | u128 user_id) const { |
| 203 | const auto path = | 204 | const auto path = |
| 204 | GetFullPath(system, dir, SaveDataSpaceId::NandUser, type, title_id, user_id, 0); | 205 | GetFullPath(program_id, dir, SaveDataSpaceId::NandUser, type, title_id, user_id, 0); |
| 205 | const auto relative_dir = GetOrCreateDirectoryRelative(dir, path); | 206 | const auto relative_dir = GetOrCreateDirectoryRelative(dir, path); |
| 206 | 207 | ||
| 207 | const auto size_file = relative_dir->GetFile(GetSaveDataSizeFileName()); | 208 | const auto size_file = relative_dir->GetFile(GetSaveDataSizeFileName()); |
| @@ -220,7 +221,7 @@ SaveDataSize SaveDataFactory::ReadSaveDataSize(SaveDataType type, u64 title_id, | |||
| 220 | void SaveDataFactory::WriteSaveDataSize(SaveDataType type, u64 title_id, u128 user_id, | 221 | void SaveDataFactory::WriteSaveDataSize(SaveDataType type, u64 title_id, u128 user_id, |
| 221 | SaveDataSize new_value) const { | 222 | SaveDataSize new_value) const { |
| 222 | const auto path = | 223 | const auto path = |
| 223 | GetFullPath(system, dir, SaveDataSpaceId::NandUser, type, title_id, user_id, 0); | 224 | GetFullPath(program_id, dir, SaveDataSpaceId::NandUser, type, title_id, user_id, 0); |
| 224 | const auto relative_dir = GetOrCreateDirectoryRelative(dir, path); | 225 | const auto relative_dir = GetOrCreateDirectoryRelative(dir, path); |
| 225 | 226 | ||
| 226 | const auto size_file = relative_dir->CreateFile(GetSaveDataSizeFileName()); | 227 | const auto size_file = relative_dir->CreateFile(GetSaveDataSizeFileName()); |
diff --git a/src/core/file_sys/savedata_factory.h b/src/core/file_sys/savedata_factory.h index fd4887e99..30d96928e 100644 --- a/src/core/file_sys/savedata_factory.h +++ b/src/core/file_sys/savedata_factory.h | |||
| @@ -87,10 +87,13 @@ constexpr const char* GetSaveDataSizeFileName() { | |||
| 87 | return ".yuzu_save_size"; | 87 | return ".yuzu_save_size"; |
| 88 | } | 88 | } |
| 89 | 89 | ||
| 90 | using ProgramId = u64; | ||
| 91 | |||
| 90 | /// File system interface to the SaveData archive | 92 | /// File system interface to the SaveData archive |
| 91 | class SaveDataFactory { | 93 | class SaveDataFactory { |
| 92 | public: | 94 | public: |
| 93 | explicit SaveDataFactory(Core::System& system_, VirtualDir save_directory_); | 95 | explicit SaveDataFactory(Core::System& system_, ProgramId program_id_, |
| 96 | VirtualDir save_directory_); | ||
| 94 | ~SaveDataFactory(); | 97 | ~SaveDataFactory(); |
| 95 | 98 | ||
| 96 | VirtualDir Create(SaveDataSpaceId space, const SaveDataAttribute& meta) const; | 99 | VirtualDir Create(SaveDataSpaceId space, const SaveDataAttribute& meta) const; |
| @@ -99,7 +102,7 @@ public: | |||
| 99 | VirtualDir GetSaveDataSpaceDirectory(SaveDataSpaceId space) const; | 102 | VirtualDir GetSaveDataSpaceDirectory(SaveDataSpaceId space) const; |
| 100 | 103 | ||
| 101 | static std::string GetSaveDataSpaceIdPath(SaveDataSpaceId space); | 104 | static std::string GetSaveDataSpaceIdPath(SaveDataSpaceId space); |
| 102 | static std::string GetFullPath(Core::System& system, VirtualDir dir, SaveDataSpaceId space, | 105 | static std::string GetFullPath(ProgramId program_id, VirtualDir dir, SaveDataSpaceId space, |
| 103 | SaveDataType type, u64 title_id, u128 user_id, u64 save_id); | 106 | SaveDataType type, u64 title_id, u128 user_id, u64 save_id); |
| 104 | static std::string GetUserGameSaveDataRoot(u128 user_id, bool future); | 107 | static std::string GetUserGameSaveDataRoot(u128 user_id, bool future); |
| 105 | 108 | ||
| @@ -110,8 +113,9 @@ public: | |||
| 110 | void SetAutoCreate(bool state); | 113 | void SetAutoCreate(bool state); |
| 111 | 114 | ||
| 112 | private: | 115 | private: |
| 113 | VirtualDir dir; | ||
| 114 | Core::System& system; | 116 | Core::System& system; |
| 117 | ProgramId program_id; | ||
| 118 | VirtualDir dir; | ||
| 115 | bool auto_create{true}; | 119 | bool auto_create{true}; |
| 116 | }; | 120 | }; |
| 117 | 121 | ||
diff --git a/src/core/frontend/applets/controller.cpp b/src/core/frontend/applets/controller.cpp index 34fe23b6a..e04d884ba 100644 --- a/src/core/frontend/applets/controller.cpp +++ b/src/core/frontend/applets/controller.cpp | |||
| @@ -47,7 +47,7 @@ void DefaultControllerApplet::ReconfigureControllers(ReconfigureCallback callbac | |||
| 47 | // Connect controllers based on the following priority list from highest to lowest priority: | 47 | // Connect controllers based on the following priority list from highest to lowest priority: |
| 48 | // Pro Controller -> Dual Joycons -> Left Joycon/Right Joycon -> Handheld | 48 | // Pro Controller -> Dual Joycons -> Left Joycon/Right Joycon -> Handheld |
| 49 | if (parameters.allow_pro_controller) { | 49 | if (parameters.allow_pro_controller) { |
| 50 | controller->SetNpadStyleIndex(Core::HID::NpadStyleIndex::ProController); | 50 | controller->SetNpadStyleIndex(Core::HID::NpadStyleIndex::Fullkey); |
| 51 | controller->Connect(true); | 51 | controller->Connect(true); |
| 52 | } else if (parameters.allow_dual_joycons) { | 52 | } else if (parameters.allow_dual_joycons) { |
| 53 | controller->SetNpadStyleIndex(Core::HID::NpadStyleIndex::JoyconDual); | 53 | controller->SetNpadStyleIndex(Core::HID::NpadStyleIndex::JoyconDual); |
diff --git a/src/core/hle/kernel/k_memory_block.h b/src/core/hle/kernel/k_memory_block.h index ef3f61321..d2b7e9a66 100644 --- a/src/core/hle/kernel/k_memory_block.h +++ b/src/core/hle/kernel/k_memory_block.h | |||
| @@ -81,12 +81,12 @@ enum class KMemoryState : u32 { | |||
| 81 | 81 | ||
| 82 | ThreadLocal = static_cast<u32>(Svc::MemoryState::ThreadLocal) | FlagLinearMapped, | 82 | ThreadLocal = static_cast<u32>(Svc::MemoryState::ThreadLocal) | FlagLinearMapped, |
| 83 | 83 | ||
| 84 | Transfered = static_cast<u32>(Svc::MemoryState::Transfered) | FlagsMisc | | 84 | Transferred = static_cast<u32>(Svc::MemoryState::Transferred) | FlagsMisc | |
| 85 | FlagCanAlignedDeviceMap | FlagCanChangeAttribute | FlagCanUseIpc | | 85 | FlagCanAlignedDeviceMap | FlagCanChangeAttribute | FlagCanUseIpc | |
| 86 | FlagCanUseNonSecureIpc | FlagCanUseNonDeviceIpc, | 86 | FlagCanUseNonSecureIpc | FlagCanUseNonDeviceIpc, |
| 87 | 87 | ||
| 88 | SharedTransfered = static_cast<u32>(Svc::MemoryState::SharedTransfered) | FlagsMisc | | 88 | SharedTransferred = static_cast<u32>(Svc::MemoryState::SharedTransferred) | FlagsMisc | |
| 89 | FlagCanAlignedDeviceMap | FlagCanUseNonSecureIpc | FlagCanUseNonDeviceIpc, | 89 | FlagCanAlignedDeviceMap | FlagCanUseNonSecureIpc | FlagCanUseNonDeviceIpc, |
| 90 | 90 | ||
| 91 | SharedCode = static_cast<u32>(Svc::MemoryState::SharedCode) | FlagMapped | | 91 | SharedCode = static_cast<u32>(Svc::MemoryState::SharedCode) | FlagMapped | |
| 92 | FlagReferenceCounted | FlagLinearMapped | FlagCanUseNonSecureIpc | | 92 | FlagReferenceCounted | FlagLinearMapped | FlagCanUseNonSecureIpc | |
| @@ -130,8 +130,8 @@ static_assert(static_cast<u32>(KMemoryState::AliasCodeData) == 0x0FFFBD09); | |||
| 130 | static_assert(static_cast<u32>(KMemoryState::Ipc) == 0x045C3C0A); | 130 | static_assert(static_cast<u32>(KMemoryState::Ipc) == 0x045C3C0A); |
| 131 | static_assert(static_cast<u32>(KMemoryState::Stack) == 0x045C3C0B); | 131 | static_assert(static_cast<u32>(KMemoryState::Stack) == 0x045C3C0B); |
| 132 | static_assert(static_cast<u32>(KMemoryState::ThreadLocal) == 0x0400000C); | 132 | static_assert(static_cast<u32>(KMemoryState::ThreadLocal) == 0x0400000C); |
| 133 | static_assert(static_cast<u32>(KMemoryState::Transfered) == 0x055C3C0D); | 133 | static_assert(static_cast<u32>(KMemoryState::Transferred) == 0x055C3C0D); |
| 134 | static_assert(static_cast<u32>(KMemoryState::SharedTransfered) == 0x045C380E); | 134 | static_assert(static_cast<u32>(KMemoryState::SharedTransferred) == 0x045C380E); |
| 135 | static_assert(static_cast<u32>(KMemoryState::SharedCode) == 0x0440380F); | 135 | static_assert(static_cast<u32>(KMemoryState::SharedCode) == 0x0440380F); |
| 136 | static_assert(static_cast<u32>(KMemoryState::Inaccessible) == 0x00000010); | 136 | static_assert(static_cast<u32>(KMemoryState::Inaccessible) == 0x00000010); |
| 137 | static_assert(static_cast<u32>(KMemoryState::NonSecureIpc) == 0x045C3811); | 137 | static_assert(static_cast<u32>(KMemoryState::NonSecureIpc) == 0x045C3811); |
diff --git a/src/core/hle/kernel/k_memory_block_manager.cpp b/src/core/hle/kernel/k_memory_block_manager.cpp index 58a1e7216..f08a6e448 100644 --- a/src/core/hle/kernel/k_memory_block_manager.cpp +++ b/src/core/hle/kernel/k_memory_block_manager.cpp | |||
| @@ -28,14 +28,14 @@ Result KMemoryBlockManager::Initialize(KProcessAddress st, KProcessAddress nd, | |||
| 28 | } | 28 | } |
| 29 | 29 | ||
| 30 | void KMemoryBlockManager::Finalize(KMemoryBlockSlabManager* slab_manager, | 30 | void KMemoryBlockManager::Finalize(KMemoryBlockSlabManager* slab_manager, |
| 31 | HostUnmapCallback&& host_unmap_callback) { | 31 | BlockCallback&& block_callback) { |
| 32 | // Erase every block until we have none left. | 32 | // Erase every block until we have none left. |
| 33 | auto it = m_memory_block_tree.begin(); | 33 | auto it = m_memory_block_tree.begin(); |
| 34 | while (it != m_memory_block_tree.end()) { | 34 | while (it != m_memory_block_tree.end()) { |
| 35 | KMemoryBlock* block = std::addressof(*it); | 35 | KMemoryBlock* block = std::addressof(*it); |
| 36 | it = m_memory_block_tree.erase(it); | 36 | it = m_memory_block_tree.erase(it); |
| 37 | block_callback(block->GetAddress(), block->GetSize()); | ||
| 37 | slab_manager->Free(block); | 38 | slab_manager->Free(block); |
| 38 | host_unmap_callback(block->GetAddress(), block->GetSize()); | ||
| 39 | } | 39 | } |
| 40 | 40 | ||
| 41 | ASSERT(m_memory_block_tree.empty()); | 41 | ASSERT(m_memory_block_tree.empty()); |
diff --git a/src/core/hle/kernel/k_memory_block_manager.h b/src/core/hle/kernel/k_memory_block_manager.h index cb7b6f430..377628504 100644 --- a/src/core/hle/kernel/k_memory_block_manager.h +++ b/src/core/hle/kernel/k_memory_block_manager.h | |||
| @@ -85,11 +85,11 @@ public: | |||
| 85 | public: | 85 | public: |
| 86 | KMemoryBlockManager(); | 86 | KMemoryBlockManager(); |
| 87 | 87 | ||
| 88 | using HostUnmapCallback = std::function<void(Common::ProcessAddress, u64)>; | 88 | using BlockCallback = std::function<void(Common::ProcessAddress, u64)>; |
| 89 | 89 | ||
| 90 | Result Initialize(KProcessAddress st, KProcessAddress nd, | 90 | Result Initialize(KProcessAddress st, KProcessAddress nd, |
| 91 | KMemoryBlockSlabManager* slab_manager); | 91 | KMemoryBlockSlabManager* slab_manager); |
| 92 | void Finalize(KMemoryBlockSlabManager* slab_manager, HostUnmapCallback&& host_unmap_callback); | 92 | void Finalize(KMemoryBlockSlabManager* slab_manager, BlockCallback&& block_callback); |
| 93 | 93 | ||
| 94 | iterator end() { | 94 | iterator end() { |
| 95 | return m_memory_block_tree.end(); | 95 | return m_memory_block_tree.end(); |
diff --git a/src/core/hle/kernel/k_page_table_base.cpp b/src/core/hle/kernel/k_page_table_base.cpp index 8c1549559..3f0a39d33 100644 --- a/src/core/hle/kernel/k_page_table_base.cpp +++ b/src/core/hle/kernel/k_page_table_base.cpp | |||
| @@ -431,15 +431,43 @@ Result KPageTableBase::InitializeForProcess(Svc::CreateProcessFlag as_type, bool | |||
| 431 | m_memory_block_slab_manager)); | 431 | m_memory_block_slab_manager)); |
| 432 | } | 432 | } |
| 433 | 433 | ||
| 434 | Result KPageTableBase::FinalizeProcess() { | ||
| 435 | // Only process tables should be finalized. | ||
| 436 | ASSERT(!this->IsKernel()); | ||
| 437 | |||
| 438 | // NOTE: Here Nintendo calls an unknown OnFinalize function. | ||
| 439 | // this->OnFinalize(); | ||
| 440 | |||
| 441 | // NOTE: Here Nintendo calls a second unknown OnFinalize function. | ||
| 442 | // this->OnFinalize2(); | ||
| 443 | |||
| 444 | // NOTE: Here Nintendo does a page table walk to discover heap pages to free. | ||
| 445 | // We will use the block manager finalization below to free them. | ||
| 446 | |||
| 447 | R_SUCCEED(); | ||
| 448 | } | ||
| 449 | |||
| 434 | void KPageTableBase::Finalize() { | 450 | void KPageTableBase::Finalize() { |
| 435 | auto HostUnmapCallback = [&](KProcessAddress addr, u64 size) { | 451 | this->FinalizeProcess(); |
| 436 | if (Settings::IsFastmemEnabled()) { | 452 | |
| 453 | auto BlockCallback = [&](KProcessAddress addr, u64 size) { | ||
| 454 | if (m_impl->fastmem_arena) { | ||
| 437 | m_system.DeviceMemory().buffer.Unmap(GetInteger(addr), size, false); | 455 | m_system.DeviceMemory().buffer.Unmap(GetInteger(addr), size, false); |
| 438 | } | 456 | } |
| 457 | |||
| 458 | // Get physical pages. | ||
| 459 | KPageGroup pg(m_kernel, m_block_info_manager); | ||
| 460 | this->MakePageGroup(pg, addr, size / PageSize); | ||
| 461 | |||
| 462 | // Free the pages. | ||
| 463 | pg.CloseAndReset(); | ||
| 439 | }; | 464 | }; |
| 440 | 465 | ||
| 441 | // Finalize memory blocks. | 466 | // Finalize memory blocks. |
| 442 | m_memory_block_manager.Finalize(m_memory_block_slab_manager, std::move(HostUnmapCallback)); | 467 | { |
| 468 | KScopedLightLock lk(m_general_lock); | ||
| 469 | m_memory_block_manager.Finalize(m_memory_block_slab_manager, std::move(BlockCallback)); | ||
| 470 | } | ||
| 443 | 471 | ||
| 444 | // Free any unsafe mapped memory. | 472 | // Free any unsafe mapped memory. |
| 445 | if (m_mapped_unsafe_physical_memory) { | 473 | if (m_mapped_unsafe_physical_memory) { |
| @@ -486,8 +514,8 @@ KProcessAddress KPageTableBase::GetRegionAddress(Svc::MemoryState state) const { | |||
| 486 | case Svc::MemoryState::Shared: | 514 | case Svc::MemoryState::Shared: |
| 487 | case Svc::MemoryState::AliasCode: | 515 | case Svc::MemoryState::AliasCode: |
| 488 | case Svc::MemoryState::AliasCodeData: | 516 | case Svc::MemoryState::AliasCodeData: |
| 489 | case Svc::MemoryState::Transfered: | 517 | case Svc::MemoryState::Transferred: |
| 490 | case Svc::MemoryState::SharedTransfered: | 518 | case Svc::MemoryState::SharedTransferred: |
| 491 | case Svc::MemoryState::SharedCode: | 519 | case Svc::MemoryState::SharedCode: |
| 492 | case Svc::MemoryState::GeneratedCode: | 520 | case Svc::MemoryState::GeneratedCode: |
| 493 | case Svc::MemoryState::CodeOut: | 521 | case Svc::MemoryState::CodeOut: |
| @@ -522,8 +550,8 @@ size_t KPageTableBase::GetRegionSize(Svc::MemoryState state) const { | |||
| 522 | case Svc::MemoryState::Shared: | 550 | case Svc::MemoryState::Shared: |
| 523 | case Svc::MemoryState::AliasCode: | 551 | case Svc::MemoryState::AliasCode: |
| 524 | case Svc::MemoryState::AliasCodeData: | 552 | case Svc::MemoryState::AliasCodeData: |
| 525 | case Svc::MemoryState::Transfered: | 553 | case Svc::MemoryState::Transferred: |
| 526 | case Svc::MemoryState::SharedTransfered: | 554 | case Svc::MemoryState::SharedTransferred: |
| 527 | case Svc::MemoryState::SharedCode: | 555 | case Svc::MemoryState::SharedCode: |
| 528 | case Svc::MemoryState::GeneratedCode: | 556 | case Svc::MemoryState::GeneratedCode: |
| 529 | case Svc::MemoryState::CodeOut: | 557 | case Svc::MemoryState::CodeOut: |
| @@ -564,8 +592,8 @@ bool KPageTableBase::CanContain(KProcessAddress addr, size_t size, Svc::MemorySt | |||
| 564 | case Svc::MemoryState::AliasCodeData: | 592 | case Svc::MemoryState::AliasCodeData: |
| 565 | case Svc::MemoryState::Stack: | 593 | case Svc::MemoryState::Stack: |
| 566 | case Svc::MemoryState::ThreadLocal: | 594 | case Svc::MemoryState::ThreadLocal: |
| 567 | case Svc::MemoryState::Transfered: | 595 | case Svc::MemoryState::Transferred: |
| 568 | case Svc::MemoryState::SharedTransfered: | 596 | case Svc::MemoryState::SharedTransferred: |
| 569 | case Svc::MemoryState::SharedCode: | 597 | case Svc::MemoryState::SharedCode: |
| 570 | case Svc::MemoryState::GeneratedCode: | 598 | case Svc::MemoryState::GeneratedCode: |
| 571 | case Svc::MemoryState::CodeOut: | 599 | case Svc::MemoryState::CodeOut: |
diff --git a/src/core/hle/kernel/k_page_table_base.h b/src/core/hle/kernel/k_page_table_base.h index 077cafc96..748419f86 100644 --- a/src/core/hle/kernel/k_page_table_base.h +++ b/src/core/hle/kernel/k_page_table_base.h | |||
| @@ -241,6 +241,7 @@ public: | |||
| 241 | KResourceLimit* resource_limit, Core::Memory::Memory& memory, | 241 | KResourceLimit* resource_limit, Core::Memory::Memory& memory, |
| 242 | KProcessAddress aslr_space_start); | 242 | KProcessAddress aslr_space_start); |
| 243 | 243 | ||
| 244 | Result FinalizeProcess(); | ||
| 244 | void Finalize(); | 245 | void Finalize(); |
| 245 | 246 | ||
| 246 | bool IsKernel() const { | 247 | bool IsKernel() const { |
diff --git a/src/core/hle/kernel/k_process.cpp b/src/core/hle/kernel/k_process.cpp index 068e71dff..53735a225 100644 --- a/src/core/hle/kernel/k_process.cpp +++ b/src/core/hle/kernel/k_process.cpp | |||
| @@ -171,6 +171,12 @@ void KProcess::Finalize() { | |||
| 171 | m_resource_limit->Close(); | 171 | m_resource_limit->Close(); |
| 172 | } | 172 | } |
| 173 | 173 | ||
| 174 | // Clear expensive resources, as the destructor is not called for guest objects. | ||
| 175 | for (auto& interface : m_arm_interfaces) { | ||
| 176 | interface.reset(); | ||
| 177 | } | ||
| 178 | m_exclusive_monitor.reset(); | ||
| 179 | |||
| 174 | // Perform inherited finalization. | 180 | // Perform inherited finalization. |
| 175 | KSynchronizationObject::Finalize(); | 181 | KSynchronizationObject::Finalize(); |
| 176 | } | 182 | } |
| @@ -1233,10 +1239,10 @@ void KProcess::LoadModule(CodeSet code_set, KProcessAddress base_addr) { | |||
| 1233 | ReprotectSegment(code_set.DataSegment(), Svc::MemoryPermission::ReadWrite); | 1239 | ReprotectSegment(code_set.DataSegment(), Svc::MemoryPermission::ReadWrite); |
| 1234 | 1240 | ||
| 1235 | #ifdef HAS_NCE | 1241 | #ifdef HAS_NCE |
| 1236 | if (this->IsApplication() && Settings::IsNceEnabled()) { | 1242 | const auto& patch = code_set.PatchSegment(); |
| 1243 | if (this->IsApplication() && Settings::IsNceEnabled() && patch.size != 0) { | ||
| 1237 | auto& buffer = m_kernel.System().DeviceMemory().buffer; | 1244 | auto& buffer = m_kernel.System().DeviceMemory().buffer; |
| 1238 | const auto& code = code_set.CodeSegment(); | 1245 | const auto& code = code_set.CodeSegment(); |
| 1239 | const auto& patch = code_set.PatchSegment(); | ||
| 1240 | buffer.Protect(GetInteger(base_addr + code.addr), code.size, | 1246 | buffer.Protect(GetInteger(base_addr + code.addr), code.size, |
| 1241 | Common::MemoryPermission::Read | Common::MemoryPermission::Execute); | 1247 | Common::MemoryPermission::Read | Common::MemoryPermission::Execute); |
| 1242 | buffer.Protect(GetInteger(base_addr + patch.addr), patch.size, | 1248 | buffer.Protect(GetInteger(base_addr + patch.addr), patch.size, |
diff --git a/src/core/hle/kernel/k_transfer_memory.cpp b/src/core/hle/kernel/k_transfer_memory.cpp index 0e2e11743..cbb1b02bb 100644 --- a/src/core/hle/kernel/k_transfer_memory.cpp +++ b/src/core/hle/kernel/k_transfer_memory.cpp | |||
| @@ -76,8 +76,8 @@ Result KTransferMemory::Map(KProcessAddress address, size_t size, Svc::MemoryPer | |||
| 76 | 76 | ||
| 77 | // Map the memory. | 77 | // Map the memory. |
| 78 | const KMemoryState state = (m_owner_perm == Svc::MemoryPermission::None) | 78 | const KMemoryState state = (m_owner_perm == Svc::MemoryPermission::None) |
| 79 | ? KMemoryState::Transfered | 79 | ? KMemoryState::Transferred |
| 80 | : KMemoryState::SharedTransfered; | 80 | : KMemoryState::SharedTransferred; |
| 81 | R_TRY(GetCurrentProcess(m_kernel).GetPageTable().MapPageGroup( | 81 | R_TRY(GetCurrentProcess(m_kernel).GetPageTable().MapPageGroup( |
| 82 | address, *m_page_group, state, KMemoryPermission::UserReadWrite)); | 82 | address, *m_page_group, state, KMemoryPermission::UserReadWrite)); |
| 83 | 83 | ||
| @@ -96,8 +96,8 @@ Result KTransferMemory::Unmap(KProcessAddress address, size_t size) { | |||
| 96 | 96 | ||
| 97 | // Unmap the memory. | 97 | // Unmap the memory. |
| 98 | const KMemoryState state = (m_owner_perm == Svc::MemoryPermission::None) | 98 | const KMemoryState state = (m_owner_perm == Svc::MemoryPermission::None) |
| 99 | ? KMemoryState::Transfered | 99 | ? KMemoryState::Transferred |
| 100 | : KMemoryState::SharedTransfered; | 100 | : KMemoryState::SharedTransferred; |
| 101 | R_TRY(GetCurrentProcess(m_kernel).GetPageTable().UnmapPageGroup(address, *m_page_group, state)); | 101 | R_TRY(GetCurrentProcess(m_kernel).GetPageTable().UnmapPageGroup(address, *m_page_group, state)); |
| 102 | 102 | ||
| 103 | // Mark ourselves as unmapped. | 103 | // Mark ourselves as unmapped. |
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index 1030f0c12..f3683cdcc 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp | |||
| @@ -112,7 +112,14 @@ struct KernelCore::Impl { | |||
| 112 | old_process->Close(); | 112 | old_process->Close(); |
| 113 | } | 113 | } |
| 114 | 114 | ||
| 115 | process_list.clear(); | 115 | { |
| 116 | std::scoped_lock lk{process_list_lock}; | ||
| 117 | for (auto* const process : process_list) { | ||
| 118 | process->Terminate(); | ||
| 119 | process->Close(); | ||
| 120 | } | ||
| 121 | process_list.clear(); | ||
| 122 | } | ||
| 116 | 123 | ||
| 117 | next_object_id = 0; | 124 | next_object_id = 0; |
| 118 | next_kernel_process_id = KProcess::InitialProcessIdMin; | 125 | next_kernel_process_id = KProcess::InitialProcessIdMin; |
| @@ -770,6 +777,7 @@ struct KernelCore::Impl { | |||
| 770 | std::atomic<u64> next_thread_id{1}; | 777 | std::atomic<u64> next_thread_id{1}; |
| 771 | 778 | ||
| 772 | // Lists all processes that exist in the current session. | 779 | // Lists all processes that exist in the current session. |
| 780 | std::mutex process_list_lock; | ||
| 773 | std::vector<KProcess*> process_list; | 781 | std::vector<KProcess*> process_list; |
| 774 | std::atomic<KProcess*> application_process{}; | 782 | std::atomic<KProcess*> application_process{}; |
| 775 | std::unique_ptr<Kernel::GlobalSchedulerContext> global_scheduler_context; | 783 | std::unique_ptr<Kernel::GlobalSchedulerContext> global_scheduler_context; |
| @@ -869,9 +877,19 @@ KResourceLimit* KernelCore::GetSystemResourceLimit() { | |||
| 869 | } | 877 | } |
| 870 | 878 | ||
| 871 | void KernelCore::AppendNewProcess(KProcess* process) { | 879 | void KernelCore::AppendNewProcess(KProcess* process) { |
| 880 | process->Open(); | ||
| 881 | |||
| 882 | std::scoped_lock lk{impl->process_list_lock}; | ||
| 872 | impl->process_list.push_back(process); | 883 | impl->process_list.push_back(process); |
| 873 | } | 884 | } |
| 874 | 885 | ||
| 886 | void KernelCore::RemoveProcess(KProcess* process) { | ||
| 887 | std::scoped_lock lk{impl->process_list_lock}; | ||
| 888 | if (std::erase(impl->process_list, process)) { | ||
| 889 | process->Close(); | ||
| 890 | } | ||
| 891 | } | ||
| 892 | |||
| 875 | void KernelCore::MakeApplicationProcess(KProcess* process) { | 893 | void KernelCore::MakeApplicationProcess(KProcess* process) { |
| 876 | impl->MakeApplicationProcess(process); | 894 | impl->MakeApplicationProcess(process); |
| 877 | } | 895 | } |
| @@ -884,8 +902,15 @@ const KProcess* KernelCore::ApplicationProcess() const { | |||
| 884 | return impl->application_process; | 902 | return impl->application_process; |
| 885 | } | 903 | } |
| 886 | 904 | ||
| 887 | const std::vector<KProcess*>& KernelCore::GetProcessList() const { | 905 | std::list<KScopedAutoObject<KProcess>> KernelCore::GetProcessList() { |
| 888 | return impl->process_list; | 906 | std::list<KScopedAutoObject<KProcess>> processes; |
| 907 | std::scoped_lock lk{impl->process_list_lock}; | ||
| 908 | |||
| 909 | for (auto* const process : impl->process_list) { | ||
| 910 | processes.emplace_back(process); | ||
| 911 | } | ||
| 912 | |||
| 913 | return processes; | ||
| 889 | } | 914 | } |
| 890 | 915 | ||
| 891 | Kernel::GlobalSchedulerContext& KernelCore::GlobalSchedulerContext() { | 916 | Kernel::GlobalSchedulerContext& KernelCore::GlobalSchedulerContext() { |
diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index 5d4102145..8ea5bed1c 100644 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h | |||
| @@ -5,6 +5,7 @@ | |||
| 5 | 5 | ||
| 6 | #include <array> | 6 | #include <array> |
| 7 | #include <functional> | 7 | #include <functional> |
| 8 | #include <list> | ||
| 8 | #include <memory> | 9 | #include <memory> |
| 9 | #include <string> | 10 | #include <string> |
| 10 | #include <unordered_map> | 11 | #include <unordered_map> |
| @@ -116,8 +117,9 @@ public: | |||
| 116 | /// Retrieves a shared pointer to the system resource limit instance. | 117 | /// Retrieves a shared pointer to the system resource limit instance. |
| 117 | KResourceLimit* GetSystemResourceLimit(); | 118 | KResourceLimit* GetSystemResourceLimit(); |
| 118 | 119 | ||
| 119 | /// Adds the given shared pointer to an internal list of active processes. | 120 | /// Adds/removes the given pointer to an internal list of active processes. |
| 120 | void AppendNewProcess(KProcess* process); | 121 | void AppendNewProcess(KProcess* process); |
| 122 | void RemoveProcess(KProcess* process); | ||
| 121 | 123 | ||
| 122 | /// Makes the given process the new application process. | 124 | /// Makes the given process the new application process. |
| 123 | void MakeApplicationProcess(KProcess* process); | 125 | void MakeApplicationProcess(KProcess* process); |
| @@ -129,7 +131,7 @@ public: | |||
| 129 | const KProcess* ApplicationProcess() const; | 131 | const KProcess* ApplicationProcess() const; |
| 130 | 132 | ||
| 131 | /// Retrieves the list of processes. | 133 | /// Retrieves the list of processes. |
| 132 | const std::vector<KProcess*>& GetProcessList() const; | 134 | std::list<KScopedAutoObject<KProcess>> GetProcessList(); |
| 133 | 135 | ||
| 134 | /// Gets the sole instance of the global scheduler | 136 | /// Gets the sole instance of the global scheduler |
| 135 | Kernel::GlobalSchedulerContext& GlobalSchedulerContext(); | 137 | Kernel::GlobalSchedulerContext& GlobalSchedulerContext(); |
diff --git a/src/core/hle/kernel/svc/svc_process.cpp b/src/core/hle/kernel/svc/svc_process.cpp index caa8bee9a..5c3e8829f 100644 --- a/src/core/hle/kernel/svc/svc_process.cpp +++ b/src/core/hle/kernel/svc/svc_process.cpp | |||
| @@ -74,13 +74,15 @@ Result GetProcessList(Core::System& system, s32* out_num_processes, u64 out_proc | |||
| 74 | } | 74 | } |
| 75 | 75 | ||
| 76 | auto& memory = GetCurrentMemory(kernel); | 76 | auto& memory = GetCurrentMemory(kernel); |
| 77 | const auto& process_list = kernel.GetProcessList(); | 77 | auto process_list = kernel.GetProcessList(); |
| 78 | auto it = process_list.begin(); | ||
| 79 | |||
| 78 | const auto num_processes = process_list.size(); | 80 | const auto num_processes = process_list.size(); |
| 79 | const auto copy_amount = | 81 | const auto copy_amount = |
| 80 | std::min(static_cast<std::size_t>(out_process_ids_size), num_processes); | 82 | std::min(static_cast<std::size_t>(out_process_ids_size), num_processes); |
| 81 | 83 | ||
| 82 | for (std::size_t i = 0; i < copy_amount; ++i) { | 84 | for (std::size_t i = 0; i < copy_amount && it != process_list.end(); ++i, ++it) { |
| 83 | memory.Write64(out_process_ids, process_list[i]->GetProcessId()); | 85 | memory.Write64(out_process_ids, (*it)->GetProcessId()); |
| 84 | out_process_ids += sizeof(u64); | 86 | out_process_ids += sizeof(u64); |
| 85 | } | 87 | } |
| 86 | 88 | ||
diff --git a/src/core/hle/kernel/svc/svc_transfer_memory.cpp b/src/core/hle/kernel/svc/svc_transfer_memory.cpp index 1f97121b3..671bca23f 100644 --- a/src/core/hle/kernel/svc/svc_transfer_memory.cpp +++ b/src/core/hle/kernel/svc/svc_transfer_memory.cpp | |||
| @@ -90,7 +90,7 @@ Result MapTransferMemory(Core::System& system, Handle trmem_handle, uint64_t add | |||
| 90 | // Verify that the mapping is in range. | 90 | // Verify that the mapping is in range. |
| 91 | R_UNLESS(GetCurrentProcess(system.Kernel()) | 91 | R_UNLESS(GetCurrentProcess(system.Kernel()) |
| 92 | .GetPageTable() | 92 | .GetPageTable() |
| 93 | .CanContain(address, size, KMemoryState::Transfered), | 93 | .CanContain(address, size, KMemoryState::Transferred), |
| 94 | ResultInvalidMemoryRegion); | 94 | ResultInvalidMemoryRegion); |
| 95 | 95 | ||
| 96 | // Map the transfer memory. | 96 | // Map the transfer memory. |
| @@ -117,7 +117,7 @@ Result UnmapTransferMemory(Core::System& system, Handle trmem_handle, uint64_t a | |||
| 117 | // Verify that the mapping is in range. | 117 | // Verify that the mapping is in range. |
| 118 | R_UNLESS(GetCurrentProcess(system.Kernel()) | 118 | R_UNLESS(GetCurrentProcess(system.Kernel()) |
| 119 | .GetPageTable() | 119 | .GetPageTable() |
| 120 | .CanContain(address, size, KMemoryState::Transfered), | 120 | .CanContain(address, size, KMemoryState::Transferred), |
| 121 | ResultInvalidMemoryRegion); | 121 | ResultInvalidMemoryRegion); |
| 122 | 122 | ||
| 123 | // Unmap the transfer memory. | 123 | // Unmap the transfer memory. |
diff --git a/src/core/hle/kernel/svc_types.h b/src/core/hle/kernel/svc_types.h index 50de02e36..ab432ea78 100644 --- a/src/core/hle/kernel/svc_types.h +++ b/src/core/hle/kernel/svc_types.h | |||
| @@ -27,8 +27,8 @@ enum class MemoryState : u32 { | |||
| 27 | Ipc = 0x0A, | 27 | Ipc = 0x0A, |
| 28 | Stack = 0x0B, | 28 | Stack = 0x0B, |
| 29 | ThreadLocal = 0x0C, | 29 | ThreadLocal = 0x0C, |
| 30 | Transfered = 0x0D, | 30 | Transferred = 0x0D, |
| 31 | SharedTransfered = 0x0E, | 31 | SharedTransferred = 0x0E, |
| 32 | SharedCode = 0x0F, | 32 | SharedCode = 0x0F, |
| 33 | Inaccessible = 0x10, | 33 | Inaccessible = 0x10, |
| 34 | NonSecureIpc = 0x11, | 34 | NonSecureIpc = 0x11, |
diff --git a/src/core/hle/service/acc/profile_manager.cpp b/src/core/hle/service/acc/profile_manager.cpp index 5542d6cbc..683f44e27 100644 --- a/src/core/hle/service/acc/profile_manager.cpp +++ b/src/core/hle/service/acc/profile_manager.cpp | |||
| @@ -61,9 +61,7 @@ ProfileManager::ProfileManager() { | |||
| 61 | OpenUser(*GetUser(current)); | 61 | OpenUser(*GetUser(current)); |
| 62 | } | 62 | } |
| 63 | 63 | ||
| 64 | ProfileManager::~ProfileManager() { | 64 | ProfileManager::~ProfileManager() = default; |
| 65 | WriteUserSaveFile(); | ||
| 66 | } | ||
| 67 | 65 | ||
| 68 | /// After a users creation it needs to be "registered" to the system. AddToProfiles handles the | 66 | /// After a users creation it needs to be "registered" to the system. AddToProfiles handles the |
| 69 | /// internal management of the users profiles | 67 | /// internal management of the users profiles |
| @@ -113,6 +111,8 @@ Result ProfileManager::CreateNewUser(UUID uuid, const ProfileUsername& username) | |||
| 113 | return ERROR_USER_ALREADY_EXISTS; | 111 | return ERROR_USER_ALREADY_EXISTS; |
| 114 | } | 112 | } |
| 115 | 113 | ||
| 114 | is_save_needed = true; | ||
| 115 | |||
| 116 | return AddUser({ | 116 | return AddUser({ |
| 117 | .user_uuid = uuid, | 117 | .user_uuid = uuid, |
| 118 | .username = username, | 118 | .username = username, |
| @@ -326,6 +326,9 @@ bool ProfileManager::RemoveUser(UUID uuid) { | |||
| 326 | profiles[*index] = ProfileInfo{}; | 326 | profiles[*index] = ProfileInfo{}; |
| 327 | std::stable_partition(profiles.begin(), profiles.end(), | 327 | std::stable_partition(profiles.begin(), profiles.end(), |
| 328 | [](const ProfileInfo& profile) { return profile.user_uuid.IsValid(); }); | 328 | [](const ProfileInfo& profile) { return profile.user_uuid.IsValid(); }); |
| 329 | |||
| 330 | is_save_needed = true; | ||
| 331 | |||
| 329 | return true; | 332 | return true; |
| 330 | } | 333 | } |
| 331 | 334 | ||
| @@ -340,6 +343,8 @@ bool ProfileManager::SetProfileBase(UUID uuid, const ProfileBase& profile_new) { | |||
| 340 | profile.username = profile_new.username; | 343 | profile.username = profile_new.username; |
| 341 | profile.creation_time = profile_new.timestamp; | 344 | profile.creation_time = profile_new.timestamp; |
| 342 | 345 | ||
| 346 | is_save_needed = true; | ||
| 347 | |||
| 343 | return true; | 348 | return true; |
| 344 | } | 349 | } |
| 345 | 350 | ||
| @@ -348,6 +353,7 @@ bool ProfileManager::SetProfileBaseAndData(Common::UUID uuid, const ProfileBase& | |||
| 348 | const auto index = GetUserIndex(uuid); | 353 | const auto index = GetUserIndex(uuid); |
| 349 | if (index.has_value() && SetProfileBase(uuid, profile_new)) { | 354 | if (index.has_value() && SetProfileBase(uuid, profile_new)) { |
| 350 | profiles[*index].data = data_new; | 355 | profiles[*index].data = data_new; |
| 356 | is_save_needed = true; | ||
| 351 | return true; | 357 | return true; |
| 352 | } | 358 | } |
| 353 | 359 | ||
| @@ -391,6 +397,10 @@ void ProfileManager::ParseUserSaveFile() { | |||
| 391 | } | 397 | } |
| 392 | 398 | ||
| 393 | void ProfileManager::WriteUserSaveFile() { | 399 | void ProfileManager::WriteUserSaveFile() { |
| 400 | if (!is_save_needed) { | ||
| 401 | return; | ||
| 402 | } | ||
| 403 | |||
| 394 | ProfileDataRaw raw{}; | 404 | ProfileDataRaw raw{}; |
| 395 | 405 | ||
| 396 | for (std::size_t i = 0; i < MAX_USERS; ++i) { | 406 | for (std::size_t i = 0; i < MAX_USERS; ++i) { |
| @@ -423,7 +433,10 @@ void ProfileManager::WriteUserSaveFile() { | |||
| 423 | if (!save.IsOpen() || !save.SetSize(sizeof(ProfileDataRaw)) || !save.WriteObject(raw)) { | 433 | if (!save.IsOpen() || !save.SetSize(sizeof(ProfileDataRaw)) || !save.WriteObject(raw)) { |
| 424 | LOG_WARNING(Service_ACC, "Failed to write save data to file... No changes to user data " | 434 | LOG_WARNING(Service_ACC, "Failed to write save data to file... No changes to user data " |
| 425 | "made in current session will be saved."); | 435 | "made in current session will be saved."); |
| 436 | return; | ||
| 426 | } | 437 | } |
| 438 | |||
| 439 | is_save_needed = false; | ||
| 427 | } | 440 | } |
| 428 | 441 | ||
| 429 | }; // namespace Service::Account | 442 | }; // namespace Service::Account |
diff --git a/src/core/hle/service/acc/profile_manager.h b/src/core/hle/service/acc/profile_manager.h index 900e32200..e21863e64 100644 --- a/src/core/hle/service/acc/profile_manager.h +++ b/src/core/hle/service/acc/profile_manager.h | |||
| @@ -103,6 +103,7 @@ private: | |||
| 103 | std::optional<std::size_t> AddToProfiles(const ProfileInfo& profile); | 103 | std::optional<std::size_t> AddToProfiles(const ProfileInfo& profile); |
| 104 | bool RemoveProfileAtIndex(std::size_t index); | 104 | bool RemoveProfileAtIndex(std::size_t index); |
| 105 | 105 | ||
| 106 | bool is_save_needed{}; | ||
| 106 | std::array<ProfileInfo, MAX_USERS> profiles{}; | 107 | std::array<ProfileInfo, MAX_USERS> profiles{}; |
| 107 | std::array<ProfileInfo, MAX_USERS> stored_opened_profiles{}; | 108 | std::array<ProfileInfo, MAX_USERS> stored_opened_profiles{}; |
| 108 | std::size_t user_count{}; | 109 | std::size_t user_count{}; |
diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp index 9e05bdafa..a768bdc54 100644 --- a/src/core/hle/service/am/am.cpp +++ b/src/core/hle/service/am/am.cpp | |||
| @@ -36,6 +36,7 @@ | |||
| 36 | #include "core/hle/service/caps/caps_su.h" | 36 | #include "core/hle/service/caps/caps_su.h" |
| 37 | #include "core/hle/service/caps/caps_types.h" | 37 | #include "core/hle/service/caps/caps_types.h" |
| 38 | #include "core/hle/service/filesystem/filesystem.h" | 38 | #include "core/hle/service/filesystem/filesystem.h" |
| 39 | #include "core/hle/service/filesystem/save_data_controller.h" | ||
| 39 | #include "core/hle/service/ipc_helpers.h" | 40 | #include "core/hle/service/ipc_helpers.h" |
| 40 | #include "core/hle/service/ns/ns.h" | 41 | #include "core/hle/service/ns/ns.h" |
| 41 | #include "core/hle/service/nvnflinger/fb_share_buffer_manager.h" | 42 | #include "core/hle/service/nvnflinger/fb_share_buffer_manager.h" |
| @@ -2178,7 +2179,7 @@ void IApplicationFunctions::EnsureSaveData(HLERequestContext& ctx) { | |||
| 2178 | attribute.type = FileSys::SaveDataType::SaveData; | 2179 | attribute.type = FileSys::SaveDataType::SaveData; |
| 2179 | 2180 | ||
| 2180 | FileSys::VirtualDir save_data{}; | 2181 | FileSys::VirtualDir save_data{}; |
| 2181 | const auto res = system.GetFileSystemController().CreateSaveData( | 2182 | const auto res = system.GetFileSystemController().OpenSaveDataController()->CreateSaveData( |
| 2182 | &save_data, FileSys::SaveDataSpaceId::NandUser, attribute); | 2183 | &save_data, FileSys::SaveDataSpaceId::NandUser, attribute); |
| 2183 | 2184 | ||
| 2184 | IPC::ResponseBuilder rb{ctx, 4}; | 2185 | IPC::ResponseBuilder rb{ctx, 4}; |
| @@ -2353,7 +2354,7 @@ void IApplicationFunctions::ExtendSaveData(HLERequestContext& ctx) { | |||
| 2353 | "new_journal={:016X}", | 2354 | "new_journal={:016X}", |
| 2354 | static_cast<u8>(type), user_id[1], user_id[0], new_normal_size, new_journal_size); | 2355 | static_cast<u8>(type), user_id[1], user_id[0], new_normal_size, new_journal_size); |
| 2355 | 2356 | ||
| 2356 | system.GetFileSystemController().WriteSaveDataSize( | 2357 | system.GetFileSystemController().OpenSaveDataController()->WriteSaveDataSize( |
| 2357 | type, system.GetApplicationProcessProgramID(), user_id, | 2358 | type, system.GetApplicationProcessProgramID(), user_id, |
| 2358 | {new_normal_size, new_journal_size}); | 2359 | {new_normal_size, new_journal_size}); |
| 2359 | 2360 | ||
| @@ -2378,7 +2379,7 @@ void IApplicationFunctions::GetSaveDataSize(HLERequestContext& ctx) { | |||
| 2378 | LOG_DEBUG(Service_AM, "called with type={:02X}, user_id={:016X}{:016X}", type, user_id[1], | 2379 | LOG_DEBUG(Service_AM, "called with type={:02X}, user_id={:016X}{:016X}", type, user_id[1], |
| 2379 | user_id[0]); | 2380 | user_id[0]); |
| 2380 | 2381 | ||
| 2381 | const auto size = system.GetFileSystemController().ReadSaveDataSize( | 2382 | const auto size = system.GetFileSystemController().OpenSaveDataController()->ReadSaveDataSize( |
| 2382 | type, system.GetApplicationProcessProgramID(), user_id); | 2383 | type, system.GetApplicationProcessProgramID(), user_id); |
| 2383 | 2384 | ||
| 2384 | IPC::ResponseBuilder rb{ctx, 6}; | 2385 | IPC::ResponseBuilder rb{ctx, 6}; |
diff --git a/src/core/hle/service/am/applets/applet_profile_select.h b/src/core/hle/service/am/applets/applet_profile_select.h index 369f9250f..673eed516 100644 --- a/src/core/hle/service/am/applets/applet_profile_select.h +++ b/src/core/hle/service/am/applets/applet_profile_select.h | |||
| @@ -76,7 +76,7 @@ struct UiSettingsDisplayOptions { | |||
| 76 | bool is_system_or_launcher; | 76 | bool is_system_or_launcher; |
| 77 | bool is_registration_permitted; | 77 | bool is_registration_permitted; |
| 78 | bool show_skip_button; | 78 | bool show_skip_button; |
| 79 | bool aditional_select; | 79 | bool additional_select; |
| 80 | bool show_user_selector; | 80 | bool show_user_selector; |
| 81 | bool is_unqualified_user_selectable; | 81 | bool is_unqualified_user_selectable; |
| 82 | }; | 82 | }; |
diff --git a/src/core/hle/service/audio/audin_u.cpp b/src/core/hle/service/audio/audin_u.cpp index 56fee4591..de2aa6906 100644 --- a/src/core/hle/service/audio/audin_u.cpp +++ b/src/core/hle/service/audio/audin_u.cpp | |||
| @@ -18,11 +18,11 @@ using namespace AudioCore::AudioIn; | |||
| 18 | class IAudioIn final : public ServiceFramework<IAudioIn> { | 18 | class IAudioIn final : public ServiceFramework<IAudioIn> { |
| 19 | public: | 19 | public: |
| 20 | explicit IAudioIn(Core::System& system_, Manager& manager, size_t session_id, | 20 | explicit IAudioIn(Core::System& system_, Manager& manager, size_t session_id, |
| 21 | const std::string& device_name, const AudioInParameter& in_params, u32 handle, | 21 | const std::string& device_name, const AudioInParameter& in_params, |
| 22 | u64 applet_resource_user_id) | 22 | Kernel::KProcess* handle, u64 applet_resource_user_id) |
| 23 | : ServiceFramework{system_, "IAudioIn"}, | 23 | : ServiceFramework{system_, "IAudioIn"}, |
| 24 | service_context{system_, "IAudioIn"}, event{service_context.CreateEvent("AudioInEvent")}, | 24 | service_context{system_, "IAudioIn"}, event{service_context.CreateEvent("AudioInEvent")}, |
| 25 | impl{std::make_shared<In>(system_, manager, event, session_id)} { | 25 | process{handle}, impl{std::make_shared<In>(system_, manager, event, session_id)} { |
| 26 | // clang-format off | 26 | // clang-format off |
| 27 | static const FunctionInfo functions[] = { | 27 | static const FunctionInfo functions[] = { |
| 28 | {0, &IAudioIn::GetAudioInState, "GetAudioInState"}, | 28 | {0, &IAudioIn::GetAudioInState, "GetAudioInState"}, |
| @@ -45,6 +45,8 @@ public: | |||
| 45 | 45 | ||
| 46 | RegisterHandlers(functions); | 46 | RegisterHandlers(functions); |
| 47 | 47 | ||
| 48 | process->Open(); | ||
| 49 | |||
| 48 | if (impl->GetSystem() | 50 | if (impl->GetSystem() |
| 49 | .Initialize(device_name, in_params, handle, applet_resource_user_id) | 51 | .Initialize(device_name, in_params, handle, applet_resource_user_id) |
| 50 | .IsError()) { | 52 | .IsError()) { |
| @@ -55,6 +57,7 @@ public: | |||
| 55 | ~IAudioIn() override { | 57 | ~IAudioIn() override { |
| 56 | impl->Free(); | 58 | impl->Free(); |
| 57 | service_context.CloseEvent(event); | 59 | service_context.CloseEvent(event); |
| 60 | process->Close(); | ||
| 58 | } | 61 | } |
| 59 | 62 | ||
| 60 | [[nodiscard]] std::shared_ptr<In> GetImpl() { | 63 | [[nodiscard]] std::shared_ptr<In> GetImpl() { |
| @@ -196,6 +199,7 @@ private: | |||
| 196 | 199 | ||
| 197 | KernelHelpers::ServiceContext service_context; | 200 | KernelHelpers::ServiceContext service_context; |
| 198 | Kernel::KEvent* event; | 201 | Kernel::KEvent* event; |
| 202 | Kernel::KProcess* process; | ||
| 199 | std::shared_ptr<AudioCore::AudioIn::In> impl; | 203 | std::shared_ptr<AudioCore::AudioIn::In> impl; |
| 200 | Common::ScratchBuffer<u64> released_buffer; | 204 | Common::ScratchBuffer<u64> released_buffer; |
| 201 | }; | 205 | }; |
| @@ -267,6 +271,14 @@ void AudInU::OpenAudioIn(HLERequestContext& ctx) { | |||
| 267 | auto device_name = Common::StringFromBuffer(device_name_data); | 271 | auto device_name = Common::StringFromBuffer(device_name_data); |
| 268 | auto handle{ctx.GetCopyHandle(0)}; | 272 | auto handle{ctx.GetCopyHandle(0)}; |
| 269 | 273 | ||
| 274 | auto process{ctx.GetObjectFromHandle<Kernel::KProcess>(handle)}; | ||
| 275 | if (process.IsNull()) { | ||
| 276 | LOG_ERROR(Service_Audio, "Failed to get process handle"); | ||
| 277 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 278 | rb.Push(ResultUnknown); | ||
| 279 | return; | ||
| 280 | } | ||
| 281 | |||
| 270 | std::scoped_lock l{impl->mutex}; | 282 | std::scoped_lock l{impl->mutex}; |
| 271 | auto link{impl->LinkToManager()}; | 283 | auto link{impl->LinkToManager()}; |
| 272 | if (link.IsError()) { | 284 | if (link.IsError()) { |
| @@ -287,8 +299,9 @@ void AudInU::OpenAudioIn(HLERequestContext& ctx) { | |||
| 287 | LOG_DEBUG(Service_Audio, "Opening new AudioIn, sessionid={}, free sessions={}", new_session_id, | 299 | LOG_DEBUG(Service_Audio, "Opening new AudioIn, sessionid={}, free sessions={}", new_session_id, |
| 288 | impl->num_free_sessions); | 300 | impl->num_free_sessions); |
| 289 | 301 | ||
| 290 | auto audio_in = std::make_shared<IAudioIn>(system, *impl, new_session_id, device_name, | 302 | auto audio_in = |
| 291 | in_params, handle, applet_resource_user_id); | 303 | std::make_shared<IAudioIn>(system, *impl, new_session_id, device_name, in_params, |
| 304 | process.GetPointerUnsafe(), applet_resource_user_id); | ||
| 292 | impl->sessions[new_session_id] = audio_in->GetImpl(); | 305 | impl->sessions[new_session_id] = audio_in->GetImpl(); |
| 293 | impl->applet_resource_user_ids[new_session_id] = applet_resource_user_id; | 306 | impl->applet_resource_user_ids[new_session_id] = applet_resource_user_id; |
| 294 | 307 | ||
| @@ -318,6 +331,14 @@ void AudInU::OpenAudioInProtocolSpecified(HLERequestContext& ctx) { | |||
| 318 | auto device_name = Common::StringFromBuffer(device_name_data); | 331 | auto device_name = Common::StringFromBuffer(device_name_data); |
| 319 | auto handle{ctx.GetCopyHandle(0)}; | 332 | auto handle{ctx.GetCopyHandle(0)}; |
| 320 | 333 | ||
| 334 | auto process{ctx.GetObjectFromHandle<Kernel::KProcess>(handle)}; | ||
| 335 | if (process.IsNull()) { | ||
| 336 | LOG_ERROR(Service_Audio, "Failed to get process handle"); | ||
| 337 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 338 | rb.Push(ResultUnknown); | ||
| 339 | return; | ||
| 340 | } | ||
| 341 | |||
| 321 | std::scoped_lock l{impl->mutex}; | 342 | std::scoped_lock l{impl->mutex}; |
| 322 | auto link{impl->LinkToManager()}; | 343 | auto link{impl->LinkToManager()}; |
| 323 | if (link.IsError()) { | 344 | if (link.IsError()) { |
| @@ -338,8 +359,9 @@ void AudInU::OpenAudioInProtocolSpecified(HLERequestContext& ctx) { | |||
| 338 | LOG_DEBUG(Service_Audio, "Opening new AudioIn, sessionid={}, free sessions={}", new_session_id, | 359 | LOG_DEBUG(Service_Audio, "Opening new AudioIn, sessionid={}, free sessions={}", new_session_id, |
| 339 | impl->num_free_sessions); | 360 | impl->num_free_sessions); |
| 340 | 361 | ||
| 341 | auto audio_in = std::make_shared<IAudioIn>(system, *impl, new_session_id, device_name, | 362 | auto audio_in = |
| 342 | in_params, handle, applet_resource_user_id); | 363 | std::make_shared<IAudioIn>(system, *impl, new_session_id, device_name, in_params, |
| 364 | process.GetPointerUnsafe(), applet_resource_user_id); | ||
| 343 | impl->sessions[new_session_id] = audio_in->GetImpl(); | 365 | impl->sessions[new_session_id] = audio_in->GetImpl(); |
| 344 | impl->applet_resource_user_ids[new_session_id] = applet_resource_user_id; | 366 | impl->applet_resource_user_ids[new_session_id] = applet_resource_user_id; |
| 345 | 367 | ||
diff --git a/src/core/hle/service/audio/audout_u.cpp b/src/core/hle/service/audio/audout_u.cpp index ca683d72c..8cc7b69f4 100644 --- a/src/core/hle/service/audio/audout_u.cpp +++ b/src/core/hle/service/audio/audout_u.cpp | |||
| @@ -26,9 +26,10 @@ class IAudioOut final : public ServiceFramework<IAudioOut> { | |||
| 26 | public: | 26 | public: |
| 27 | explicit IAudioOut(Core::System& system_, AudioCore::AudioOut::Manager& manager, | 27 | explicit IAudioOut(Core::System& system_, AudioCore::AudioOut::Manager& manager, |
| 28 | size_t session_id, const std::string& device_name, | 28 | size_t session_id, const std::string& device_name, |
| 29 | const AudioOutParameter& in_params, u32 handle, u64 applet_resource_user_id) | 29 | const AudioOutParameter& in_params, Kernel::KProcess* handle, |
| 30 | u64 applet_resource_user_id) | ||
| 30 | : ServiceFramework{system_, "IAudioOut"}, service_context{system_, "IAudioOut"}, | 31 | : ServiceFramework{system_, "IAudioOut"}, service_context{system_, "IAudioOut"}, |
| 31 | event{service_context.CreateEvent("AudioOutEvent")}, | 32 | event{service_context.CreateEvent("AudioOutEvent")}, process{handle}, |
| 32 | impl{std::make_shared<AudioCore::AudioOut::Out>(system_, manager, event, session_id)} { | 33 | impl{std::make_shared<AudioCore::AudioOut::Out>(system_, manager, event, session_id)} { |
| 33 | 34 | ||
| 34 | // clang-format off | 35 | // clang-format off |
| @@ -50,11 +51,14 @@ public: | |||
| 50 | }; | 51 | }; |
| 51 | // clang-format on | 52 | // clang-format on |
| 52 | RegisterHandlers(functions); | 53 | RegisterHandlers(functions); |
| 54 | |||
| 55 | process->Open(); | ||
| 53 | } | 56 | } |
| 54 | 57 | ||
| 55 | ~IAudioOut() override { | 58 | ~IAudioOut() override { |
| 56 | impl->Free(); | 59 | impl->Free(); |
| 57 | service_context.CloseEvent(event); | 60 | service_context.CloseEvent(event); |
| 61 | process->Close(); | ||
| 58 | } | 62 | } |
| 59 | 63 | ||
| 60 | [[nodiscard]] std::shared_ptr<AudioCore::AudioOut::Out> GetImpl() { | 64 | [[nodiscard]] std::shared_ptr<AudioCore::AudioOut::Out> GetImpl() { |
| @@ -206,6 +210,7 @@ private: | |||
| 206 | 210 | ||
| 207 | KernelHelpers::ServiceContext service_context; | 211 | KernelHelpers::ServiceContext service_context; |
| 208 | Kernel::KEvent* event; | 212 | Kernel::KEvent* event; |
| 213 | Kernel::KProcess* process; | ||
| 209 | std::shared_ptr<AudioCore::AudioOut::Out> impl; | 214 | std::shared_ptr<AudioCore::AudioOut::Out> impl; |
| 210 | Common::ScratchBuffer<u64> released_buffer; | 215 | Common::ScratchBuffer<u64> released_buffer; |
| 211 | }; | 216 | }; |
| @@ -257,6 +262,14 @@ void AudOutU::OpenAudioOut(HLERequestContext& ctx) { | |||
| 257 | auto device_name = Common::StringFromBuffer(device_name_data); | 262 | auto device_name = Common::StringFromBuffer(device_name_data); |
| 258 | auto handle{ctx.GetCopyHandle(0)}; | 263 | auto handle{ctx.GetCopyHandle(0)}; |
| 259 | 264 | ||
| 265 | auto process{ctx.GetObjectFromHandle<Kernel::KProcess>(handle)}; | ||
| 266 | if (process.IsNull()) { | ||
| 267 | LOG_ERROR(Service_Audio, "Failed to get process handle"); | ||
| 268 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 269 | rb.Push(ResultUnknown); | ||
| 270 | return; | ||
| 271 | } | ||
| 272 | |||
| 260 | auto link{impl->LinkToManager()}; | 273 | auto link{impl->LinkToManager()}; |
| 261 | if (link.IsError()) { | 274 | if (link.IsError()) { |
| 262 | LOG_ERROR(Service_Audio, "Failed to link Audio Out to Audio Manager"); | 275 | LOG_ERROR(Service_Audio, "Failed to link Audio Out to Audio Manager"); |
| @@ -276,10 +289,11 @@ void AudOutU::OpenAudioOut(HLERequestContext& ctx) { | |||
| 276 | LOG_DEBUG(Service_Audio, "Opening new AudioOut, sessionid={}, free sessions={}", new_session_id, | 289 | LOG_DEBUG(Service_Audio, "Opening new AudioOut, sessionid={}, free sessions={}", new_session_id, |
| 277 | impl->num_free_sessions); | 290 | impl->num_free_sessions); |
| 278 | 291 | ||
| 279 | auto audio_out = std::make_shared<IAudioOut>(system, *impl, new_session_id, device_name, | 292 | auto audio_out = |
| 280 | in_params, handle, applet_resource_user_id); | 293 | std::make_shared<IAudioOut>(system, *impl, new_session_id, device_name, in_params, |
| 281 | result = audio_out->GetImpl()->GetSystem().Initialize(device_name, in_params, handle, | 294 | process.GetPointerUnsafe(), applet_resource_user_id); |
| 282 | applet_resource_user_id); | 295 | result = audio_out->GetImpl()->GetSystem().Initialize( |
| 296 | device_name, in_params, process.GetPointerUnsafe(), applet_resource_user_id); | ||
| 283 | if (result.IsError()) { | 297 | if (result.IsError()) { |
| 284 | LOG_ERROR(Service_Audio, "Failed to initialize the AudioOut System!"); | 298 | LOG_ERROR(Service_Audio, "Failed to initialize the AudioOut System!"); |
| 285 | IPC::ResponseBuilder rb{ctx, 2}; | 299 | IPC::ResponseBuilder rb{ctx, 2}; |
diff --git a/src/core/hle/service/caps/caps_manager.cpp b/src/core/hle/service/caps/caps_manager.cpp index 96b225d5f..261fc204c 100644 --- a/src/core/hle/service/caps/caps_manager.cpp +++ b/src/core/hle/service/caps/caps_manager.cpp | |||
| @@ -85,7 +85,7 @@ Result AlbumManager::GetAlbumFileList(std::vector<AlbumEntry>& out_entries, Albu | |||
| 85 | } | 85 | } |
| 86 | 86 | ||
| 87 | Result AlbumManager::GetAlbumFileList(std::vector<ApplicationAlbumFileEntry>& out_entries, | 87 | Result AlbumManager::GetAlbumFileList(std::vector<ApplicationAlbumFileEntry>& out_entries, |
| 88 | ContentType contex_type, s64 start_posix_time, | 88 | ContentType content_type, s64 start_posix_time, |
| 89 | s64 end_posix_time, u64 aruid) const { | 89 | s64 end_posix_time, u64 aruid) const { |
| 90 | if (!is_mounted) { | 90 | if (!is_mounted) { |
| 91 | return ResultIsNotMounted; | 91 | return ResultIsNotMounted; |
| @@ -94,7 +94,7 @@ Result AlbumManager::GetAlbumFileList(std::vector<ApplicationAlbumFileEntry>& ou | |||
| 94 | std::vector<ApplicationAlbumEntry> album_entries; | 94 | std::vector<ApplicationAlbumEntry> album_entries; |
| 95 | const auto start_date = ConvertToAlbumDateTime(start_posix_time); | 95 | const auto start_date = ConvertToAlbumDateTime(start_posix_time); |
| 96 | const auto end_date = ConvertToAlbumDateTime(end_posix_time); | 96 | const auto end_date = ConvertToAlbumDateTime(end_posix_time); |
| 97 | const auto result = GetAlbumFileList(album_entries, contex_type, start_date, end_date, aruid); | 97 | const auto result = GetAlbumFileList(album_entries, content_type, start_date, end_date, aruid); |
| 98 | 98 | ||
| 99 | if (result.IsError()) { | 99 | if (result.IsError()) { |
| 100 | return result; | 100 | return result; |
| @@ -113,14 +113,14 @@ Result AlbumManager::GetAlbumFileList(std::vector<ApplicationAlbumFileEntry>& ou | |||
| 113 | } | 113 | } |
| 114 | 114 | ||
| 115 | Result AlbumManager::GetAlbumFileList(std::vector<ApplicationAlbumEntry>& out_entries, | 115 | Result AlbumManager::GetAlbumFileList(std::vector<ApplicationAlbumEntry>& out_entries, |
| 116 | ContentType contex_type, AlbumFileDateTime start_date, | 116 | ContentType content_type, AlbumFileDateTime start_date, |
| 117 | AlbumFileDateTime end_date, u64 aruid) const { | 117 | AlbumFileDateTime end_date, u64 aruid) const { |
| 118 | if (!is_mounted) { | 118 | if (!is_mounted) { |
| 119 | return ResultIsNotMounted; | 119 | return ResultIsNotMounted; |
| 120 | } | 120 | } |
| 121 | 121 | ||
| 122 | for (auto& [file_id, path] : album_files) { | 122 | for (auto& [file_id, path] : album_files) { |
| 123 | if (file_id.type != contex_type) { | 123 | if (file_id.type != content_type) { |
| 124 | continue; | 124 | continue; |
| 125 | } | 125 | } |
| 126 | if (file_id.date > start_date) { | 126 | if (file_id.date > start_date) { |
| @@ -139,7 +139,7 @@ Result AlbumManager::GetAlbumFileList(std::vector<ApplicationAlbumEntry>& out_en | |||
| 139 | .hash{}, | 139 | .hash{}, |
| 140 | .datetime = file_id.date, | 140 | .datetime = file_id.date, |
| 141 | .storage = file_id.storage, | 141 | .storage = file_id.storage, |
| 142 | .content = contex_type, | 142 | .content = content_type, |
| 143 | .unknown = 1, | 143 | .unknown = 1, |
| 144 | }; | 144 | }; |
| 145 | out_entries.push_back(entry); | 145 | out_entries.push_back(entry); |
diff --git a/src/core/hle/service/caps/caps_manager.h b/src/core/hle/service/caps/caps_manager.h index e20c70c7b..6fd34f589 100644 --- a/src/core/hle/service/caps/caps_manager.h +++ b/src/core/hle/service/caps/caps_manager.h | |||
| @@ -45,10 +45,10 @@ public: | |||
| 45 | Result GetAlbumFileList(std::vector<AlbumEntry>& out_entries, AlbumStorage storage, | 45 | Result GetAlbumFileList(std::vector<AlbumEntry>& out_entries, AlbumStorage storage, |
| 46 | u8 flags) const; | 46 | u8 flags) const; |
| 47 | Result GetAlbumFileList(std::vector<ApplicationAlbumFileEntry>& out_entries, | 47 | Result GetAlbumFileList(std::vector<ApplicationAlbumFileEntry>& out_entries, |
| 48 | ContentType contex_type, s64 start_posix_time, s64 end_posix_time, | 48 | ContentType content_type, s64 start_posix_time, s64 end_posix_time, |
| 49 | u64 aruid) const; | 49 | u64 aruid) const; |
| 50 | Result GetAlbumFileList(std::vector<ApplicationAlbumEntry>& out_entries, | 50 | Result GetAlbumFileList(std::vector<ApplicationAlbumEntry>& out_entries, |
| 51 | ContentType contex_type, AlbumFileDateTime start_date, | 51 | ContentType content_type, AlbumFileDateTime start_date, |
| 52 | AlbumFileDateTime end_date, u64 aruid) const; | 52 | AlbumFileDateTime end_date, u64 aruid) const; |
| 53 | Result GetAutoSavingStorage(bool& out_is_autosaving) const; | 53 | Result GetAutoSavingStorage(bool& out_is_autosaving) const; |
| 54 | Result LoadAlbumScreenShotImage(LoadAlbumScreenShotImageOutput& out_image_output, | 54 | Result LoadAlbumScreenShotImage(LoadAlbumScreenShotImageOutput& out_image_output, |
diff --git a/src/core/hle/service/caps/caps_result.h b/src/core/hle/service/caps/caps_result.h index c65e5fb9a..179ae4840 100644 --- a/src/core/hle/service/caps/caps_result.h +++ b/src/core/hle/service/caps/caps_result.h | |||
| @@ -12,7 +12,7 @@ constexpr Result ResultUnknown5(ErrorModule::Capture, 5); | |||
| 12 | constexpr Result ResultUnknown6(ErrorModule::Capture, 6); | 12 | constexpr Result ResultUnknown6(ErrorModule::Capture, 6); |
| 13 | constexpr Result ResultUnknown7(ErrorModule::Capture, 7); | 13 | constexpr Result ResultUnknown7(ErrorModule::Capture, 7); |
| 14 | constexpr Result ResultOutOfRange(ErrorModule::Capture, 8); | 14 | constexpr Result ResultOutOfRange(ErrorModule::Capture, 8); |
| 15 | constexpr Result ResulInvalidTimestamp(ErrorModule::Capture, 12); | 15 | constexpr Result ResultInvalidTimestamp(ErrorModule::Capture, 12); |
| 16 | constexpr Result ResultInvalidStorage(ErrorModule::Capture, 13); | 16 | constexpr Result ResultInvalidStorage(ErrorModule::Capture, 13); |
| 17 | constexpr Result ResultInvalidFileContents(ErrorModule::Capture, 14); | 17 | constexpr Result ResultInvalidFileContents(ErrorModule::Capture, 14); |
| 18 | constexpr Result ResultIsNotMounted(ErrorModule::Capture, 21); | 18 | constexpr Result ResultIsNotMounted(ErrorModule::Capture, 21); |
diff --git a/src/core/hle/service/filesystem/filesystem.cpp b/src/core/hle/service/filesystem/filesystem.cpp index 780f8c74d..ca6d8d607 100644 --- a/src/core/hle/service/filesystem/filesystem.cpp +++ b/src/core/hle/service/filesystem/filesystem.cpp | |||
| @@ -24,15 +24,13 @@ | |||
| 24 | #include "core/hle/service/filesystem/fsp_ldr.h" | 24 | #include "core/hle/service/filesystem/fsp_ldr.h" |
| 25 | #include "core/hle/service/filesystem/fsp_pr.h" | 25 | #include "core/hle/service/filesystem/fsp_pr.h" |
| 26 | #include "core/hle/service/filesystem/fsp_srv.h" | 26 | #include "core/hle/service/filesystem/fsp_srv.h" |
| 27 | #include "core/hle/service/filesystem/romfs_controller.h" | ||
| 28 | #include "core/hle/service/filesystem/save_data_controller.h" | ||
| 27 | #include "core/hle/service/server_manager.h" | 29 | #include "core/hle/service/server_manager.h" |
| 28 | #include "core/loader/loader.h" | 30 | #include "core/loader/loader.h" |
| 29 | 31 | ||
| 30 | namespace Service::FileSystem { | 32 | namespace Service::FileSystem { |
| 31 | 33 | ||
| 32 | // A default size for normal/journal save data size if application control metadata cannot be found. | ||
| 33 | // This should be large enough to satisfy even the most extreme requirements (~4.2GB) | ||
| 34 | constexpr u64 SUFFICIENT_SAVE_DATA_SIZE = 0xF0000000; | ||
| 35 | |||
| 36 | static FileSys::VirtualDir GetDirectoryRelativeWrapped(FileSys::VirtualDir base, | 34 | static FileSys::VirtualDir GetDirectoryRelativeWrapped(FileSys::VirtualDir base, |
| 37 | std::string_view dir_name_) { | 35 | std::string_view dir_name_) { |
| 38 | std::string dir_name(Common::FS::SanitizePath(dir_name_)); | 36 | std::string dir_name(Common::FS::SanitizePath(dir_name_)); |
| @@ -297,145 +295,65 @@ FileSystemController::FileSystemController(Core::System& system_) : system{syste | |||
| 297 | 295 | ||
| 298 | FileSystemController::~FileSystemController() = default; | 296 | FileSystemController::~FileSystemController() = default; |
| 299 | 297 | ||
| 300 | Result FileSystemController::RegisterRomFS(std::unique_ptr<FileSys::RomFSFactory>&& factory) { | 298 | Result FileSystemController::RegisterProcess( |
| 301 | romfs_factory = std::move(factory); | 299 | ProcessId process_id, ProgramId program_id, |
| 302 | LOG_DEBUG(Service_FS, "Registered RomFS"); | 300 | std::shared_ptr<FileSys::RomFSFactory>&& romfs_factory) { |
| 303 | return ResultSuccess; | 301 | std::scoped_lock lk{registration_lock}; |
| 304 | } | ||
| 305 | |||
| 306 | Result FileSystemController::RegisterSaveData(std::unique_ptr<FileSys::SaveDataFactory>&& factory) { | ||
| 307 | ASSERT_MSG(save_data_factory == nullptr, "Tried to register a second save data"); | ||
| 308 | save_data_factory = std::move(factory); | ||
| 309 | LOG_DEBUG(Service_FS, "Registered save data"); | ||
| 310 | return ResultSuccess; | ||
| 311 | } | ||
| 312 | 302 | ||
| 313 | Result FileSystemController::RegisterSDMC(std::unique_ptr<FileSys::SDMCFactory>&& factory) { | 303 | registrations.emplace(process_id, Registration{ |
| 314 | ASSERT_MSG(sdmc_factory == nullptr, "Tried to register a second SDMC"); | 304 | .program_id = program_id, |
| 315 | sdmc_factory = std::move(factory); | 305 | .romfs_factory = std::move(romfs_factory), |
| 316 | LOG_DEBUG(Service_FS, "Registered SDMC"); | 306 | .save_data_factory = CreateSaveDataFactory(program_id), |
| 317 | return ResultSuccess; | 307 | }); |
| 318 | } | ||
| 319 | 308 | ||
| 320 | Result FileSystemController::RegisterBIS(std::unique_ptr<FileSys::BISFactory>&& factory) { | 309 | LOG_DEBUG(Service_FS, "Registered for process {}", process_id); |
| 321 | ASSERT_MSG(bis_factory == nullptr, "Tried to register a second BIS"); | ||
| 322 | bis_factory = std::move(factory); | ||
| 323 | LOG_DEBUG(Service_FS, "Registered BIS"); | ||
| 324 | return ResultSuccess; | 310 | return ResultSuccess; |
| 325 | } | 311 | } |
| 326 | 312 | ||
| 327 | void FileSystemController::SetPackedUpdate(FileSys::VirtualFile update_raw) { | 313 | Result FileSystemController::OpenProcess( |
| 328 | LOG_TRACE(Service_FS, "Setting packed update for romfs"); | 314 | ProgramId* out_program_id, std::shared_ptr<SaveDataController>* out_save_data_controller, |
| 329 | 315 | std::shared_ptr<RomFsController>* out_romfs_controller, ProcessId process_id) { | |
| 330 | if (romfs_factory == nullptr) | 316 | std::scoped_lock lk{registration_lock}; |
| 331 | return; | ||
| 332 | |||
| 333 | romfs_factory->SetPackedUpdate(std::move(update_raw)); | ||
| 334 | } | ||
| 335 | |||
| 336 | FileSys::VirtualFile FileSystemController::OpenRomFSCurrentProcess() const { | ||
| 337 | LOG_TRACE(Service_FS, "Opening RomFS for current process"); | ||
| 338 | |||
| 339 | if (romfs_factory == nullptr) { | ||
| 340 | return nullptr; | ||
| 341 | } | ||
| 342 | |||
| 343 | return romfs_factory->OpenCurrentProcess(system.GetApplicationProcessProgramID()); | ||
| 344 | } | ||
| 345 | |||
| 346 | FileSys::VirtualFile FileSystemController::OpenPatchedRomFS(u64 title_id, | ||
| 347 | FileSys::ContentRecordType type) const { | ||
| 348 | LOG_TRACE(Service_FS, "Opening patched RomFS for title_id={:016X}", title_id); | ||
| 349 | |||
| 350 | if (romfs_factory == nullptr) { | ||
| 351 | return nullptr; | ||
| 352 | } | ||
| 353 | |||
| 354 | return romfs_factory->OpenPatchedRomFS(title_id, type); | ||
| 355 | } | ||
| 356 | |||
| 357 | FileSys::VirtualFile FileSystemController::OpenPatchedRomFSWithProgramIndex( | ||
| 358 | u64 title_id, u8 program_index, FileSys::ContentRecordType type) const { | ||
| 359 | LOG_TRACE(Service_FS, "Opening patched RomFS for title_id={:016X}, program_index={}", title_id, | ||
| 360 | program_index); | ||
| 361 | |||
| 362 | if (romfs_factory == nullptr) { | ||
| 363 | return nullptr; | ||
| 364 | } | ||
| 365 | |||
| 366 | return romfs_factory->OpenPatchedRomFSWithProgramIndex(title_id, program_index, type); | ||
| 367 | } | ||
| 368 | |||
| 369 | FileSys::VirtualFile FileSystemController::OpenRomFS(u64 title_id, FileSys::StorageId storage_id, | ||
| 370 | FileSys::ContentRecordType type) const { | ||
| 371 | LOG_TRACE(Service_FS, "Opening RomFS for title_id={:016X}, storage_id={:02X}, type={:02X}", | ||
| 372 | title_id, storage_id, type); | ||
| 373 | |||
| 374 | if (romfs_factory == nullptr) { | ||
| 375 | return nullptr; | ||
| 376 | } | ||
| 377 | |||
| 378 | return romfs_factory->Open(title_id, storage_id, type); | ||
| 379 | } | ||
| 380 | |||
| 381 | std::shared_ptr<FileSys::NCA> FileSystemController::OpenBaseNca( | ||
| 382 | u64 title_id, FileSys::StorageId storage_id, FileSys::ContentRecordType type) const { | ||
| 383 | return romfs_factory->GetEntry(title_id, storage_id, type); | ||
| 384 | } | ||
| 385 | |||
| 386 | Result FileSystemController::CreateSaveData(FileSys::VirtualDir* out_save_data, | ||
| 387 | FileSys::SaveDataSpaceId space, | ||
| 388 | const FileSys::SaveDataAttribute& save_struct) const { | ||
| 389 | LOG_TRACE(Service_FS, "Creating Save Data for space_id={:01X}, save_struct={}", space, | ||
| 390 | save_struct.DebugInfo()); | ||
| 391 | 317 | ||
| 392 | if (save_data_factory == nullptr) { | 318 | const auto it = registrations.find(process_id); |
| 319 | if (it == registrations.end()) { | ||
| 393 | return FileSys::ERROR_ENTITY_NOT_FOUND; | 320 | return FileSys::ERROR_ENTITY_NOT_FOUND; |
| 394 | } | 321 | } |
| 395 | 322 | ||
| 396 | auto save_data = save_data_factory->Create(space, save_struct); | 323 | *out_program_id = it->second.program_id; |
| 397 | if (save_data == nullptr) { | 324 | *out_save_data_controller = |
| 398 | return FileSys::ERROR_ENTITY_NOT_FOUND; | 325 | std::make_shared<SaveDataController>(system, it->second.save_data_factory); |
| 399 | } | 326 | *out_romfs_controller = |
| 400 | 327 | std::make_shared<RomFsController>(it->second.romfs_factory, it->second.program_id); | |
| 401 | *out_save_data = save_data; | ||
| 402 | return ResultSuccess; | 328 | return ResultSuccess; |
| 403 | } | 329 | } |
| 404 | 330 | ||
| 405 | Result FileSystemController::OpenSaveData(FileSys::VirtualDir* out_save_data, | 331 | void FileSystemController::SetPackedUpdate(ProcessId process_id, FileSys::VirtualFile update_raw) { |
| 406 | FileSys::SaveDataSpaceId space, | 332 | LOG_TRACE(Service_FS, "Setting packed update for romfs"); |
| 407 | const FileSys::SaveDataAttribute& attribute) const { | ||
| 408 | LOG_TRACE(Service_FS, "Opening Save Data for space_id={:01X}, save_struct={}", space, | ||
| 409 | attribute.DebugInfo()); | ||
| 410 | |||
| 411 | if (save_data_factory == nullptr) { | ||
| 412 | return FileSys::ERROR_ENTITY_NOT_FOUND; | ||
| 413 | } | ||
| 414 | 333 | ||
| 415 | auto save_data = save_data_factory->Open(space, attribute); | 334 | std::scoped_lock lk{registration_lock}; |
| 416 | if (save_data == nullptr) { | 335 | const auto it = registrations.find(process_id); |
| 417 | return FileSys::ERROR_ENTITY_NOT_FOUND; | 336 | if (it == registrations.end()) { |
| 337 | return; | ||
| 418 | } | 338 | } |
| 419 | 339 | ||
| 420 | *out_save_data = save_data; | 340 | it->second.romfs_factory->SetPackedUpdate(std::move(update_raw)); |
| 421 | return ResultSuccess; | ||
| 422 | } | 341 | } |
| 423 | 342 | ||
| 424 | Result FileSystemController::OpenSaveDataSpace(FileSys::VirtualDir* out_save_data_space, | 343 | std::shared_ptr<SaveDataController> FileSystemController::OpenSaveDataController() { |
| 425 | FileSys::SaveDataSpaceId space) const { | 344 | return std::make_shared<SaveDataController>(system, CreateSaveDataFactory(ProgramId{})); |
| 426 | LOG_TRACE(Service_FS, "Opening Save Data Space for space_id={:01X}", space); | 345 | } |
| 427 | |||
| 428 | if (save_data_factory == nullptr) { | ||
| 429 | return FileSys::ERROR_ENTITY_NOT_FOUND; | ||
| 430 | } | ||
| 431 | 346 | ||
| 432 | auto save_data_space = save_data_factory->GetSaveDataSpaceDirectory(space); | 347 | std::shared_ptr<FileSys::SaveDataFactory> FileSystemController::CreateSaveDataFactory( |
| 433 | if (save_data_space == nullptr) { | 348 | ProgramId program_id) { |
| 434 | return FileSys::ERROR_ENTITY_NOT_FOUND; | 349 | using YuzuPath = Common::FS::YuzuPath; |
| 435 | } | 350 | const auto rw_mode = FileSys::Mode::ReadWrite; |
| 436 | 351 | ||
| 437 | *out_save_data_space = save_data_space; | 352 | auto vfs = system.GetFilesystem(); |
| 438 | return ResultSuccess; | 353 | const auto nand_directory = |
| 354 | vfs->OpenDirectory(Common::FS::GetYuzuPathString(YuzuPath::NANDDir), rw_mode); | ||
| 355 | return std::make_shared<FileSys::SaveDataFactory>(system, program_id, | ||
| 356 | std::move(nand_directory)); | ||
| 439 | } | 357 | } |
| 440 | 358 | ||
| 441 | Result FileSystemController::OpenSDMC(FileSys::VirtualDir* out_sdmc) const { | 359 | Result FileSystemController::OpenSDMC(FileSys::VirtualDir* out_sdmc) const { |
| @@ -540,48 +458,6 @@ u64 FileSystemController::GetTotalSpaceSize(FileSys::StorageId id) const { | |||
| 540 | return 0; | 458 | return 0; |
| 541 | } | 459 | } |
| 542 | 460 | ||
| 543 | FileSys::SaveDataSize FileSystemController::ReadSaveDataSize(FileSys::SaveDataType type, | ||
| 544 | u64 title_id, u128 user_id) const { | ||
| 545 | if (save_data_factory == nullptr) { | ||
| 546 | return {0, 0}; | ||
| 547 | } | ||
| 548 | |||
| 549 | const auto value = save_data_factory->ReadSaveDataSize(type, title_id, user_id); | ||
| 550 | |||
| 551 | if (value.normal == 0 && value.journal == 0) { | ||
| 552 | FileSys::SaveDataSize new_size{SUFFICIENT_SAVE_DATA_SIZE, SUFFICIENT_SAVE_DATA_SIZE}; | ||
| 553 | |||
| 554 | FileSys::NACP nacp; | ||
| 555 | const auto res = system.GetAppLoader().ReadControlData(nacp); | ||
| 556 | |||
| 557 | if (res != Loader::ResultStatus::Success) { | ||
| 558 | const FileSys::PatchManager pm{system.GetApplicationProcessProgramID(), | ||
| 559 | system.GetFileSystemController(), | ||
| 560 | system.GetContentProvider()}; | ||
| 561 | const auto metadata = pm.GetControlMetadata(); | ||
| 562 | const auto& nacp_unique = metadata.first; | ||
| 563 | |||
| 564 | if (nacp_unique != nullptr) { | ||
| 565 | new_size = {nacp_unique->GetDefaultNormalSaveSize(), | ||
| 566 | nacp_unique->GetDefaultJournalSaveSize()}; | ||
| 567 | } | ||
| 568 | } else { | ||
| 569 | new_size = {nacp.GetDefaultNormalSaveSize(), nacp.GetDefaultJournalSaveSize()}; | ||
| 570 | } | ||
| 571 | |||
| 572 | WriteSaveDataSize(type, title_id, user_id, new_size); | ||
| 573 | return new_size; | ||
| 574 | } | ||
| 575 | |||
| 576 | return value; | ||
| 577 | } | ||
| 578 | |||
| 579 | void FileSystemController::WriteSaveDataSize(FileSys::SaveDataType type, u64 title_id, u128 user_id, | ||
| 580 | FileSys::SaveDataSize new_value) const { | ||
| 581 | if (save_data_factory != nullptr) | ||
| 582 | save_data_factory->WriteSaveDataSize(type, title_id, user_id, new_value); | ||
| 583 | } | ||
| 584 | |||
| 585 | void FileSystemController::SetGameCard(FileSys::VirtualFile file) { | 461 | void FileSystemController::SetGameCard(FileSys::VirtualFile file) { |
| 586 | gamecard = std::make_unique<FileSys::XCI>(file); | 462 | gamecard = std::make_unique<FileSys::XCI>(file); |
| 587 | const auto dir = gamecard->ConcatenatedPseudoDirectory(); | 463 | const auto dir = gamecard->ConcatenatedPseudoDirectory(); |
| @@ -801,14 +677,9 @@ FileSys::VirtualDir FileSystemController::GetBCATDirectory(u64 title_id) const { | |||
| 801 | return bis_factory->GetBCATDirectory(title_id); | 677 | return bis_factory->GetBCATDirectory(title_id); |
| 802 | } | 678 | } |
| 803 | 679 | ||
| 804 | void FileSystemController::SetAutoSaveDataCreation(bool enable) { | ||
| 805 | save_data_factory->SetAutoCreate(enable); | ||
| 806 | } | ||
| 807 | |||
| 808 | void FileSystemController::CreateFactories(FileSys::VfsFilesystem& vfs, bool overwrite) { | 680 | void FileSystemController::CreateFactories(FileSys::VfsFilesystem& vfs, bool overwrite) { |
| 809 | if (overwrite) { | 681 | if (overwrite) { |
| 810 | bis_factory = nullptr; | 682 | bis_factory = nullptr; |
| 811 | save_data_factory = nullptr; | ||
| 812 | sdmc_factory = nullptr; | 683 | sdmc_factory = nullptr; |
| 813 | } | 684 | } |
| 814 | 685 | ||
| @@ -836,11 +707,6 @@ void FileSystemController::CreateFactories(FileSys::VfsFilesystem& vfs, bool ove | |||
| 836 | bis_factory->GetUserNANDContents()); | 707 | bis_factory->GetUserNANDContents()); |
| 837 | } | 708 | } |
| 838 | 709 | ||
| 839 | if (save_data_factory == nullptr) { | ||
| 840 | save_data_factory = | ||
| 841 | std::make_unique<FileSys::SaveDataFactory>(system, std::move(nand_directory)); | ||
| 842 | } | ||
| 843 | |||
| 844 | if (sdmc_factory == nullptr) { | 710 | if (sdmc_factory == nullptr) { |
| 845 | sdmc_factory = std::make_unique<FileSys::SDMCFactory>(std::move(sd_directory), | 711 | sdmc_factory = std::make_unique<FileSys::SDMCFactory>(std::move(sd_directory), |
| 846 | std::move(sd_load_directory)); | 712 | std::move(sd_load_directory)); |
| @@ -849,12 +715,19 @@ void FileSystemController::CreateFactories(FileSys::VfsFilesystem& vfs, bool ove | |||
| 849 | } | 715 | } |
| 850 | } | 716 | } |
| 851 | 717 | ||
| 718 | void FileSystemController::Reset() { | ||
| 719 | std::scoped_lock lk{registration_lock}; | ||
| 720 | registrations.clear(); | ||
| 721 | } | ||
| 722 | |||
| 852 | void LoopProcess(Core::System& system) { | 723 | void LoopProcess(Core::System& system) { |
| 853 | auto server_manager = std::make_unique<ServerManager>(system); | 724 | auto server_manager = std::make_unique<ServerManager>(system); |
| 854 | 725 | ||
| 726 | const auto FileSystemProxyFactory = [&] { return std::make_shared<FSP_SRV>(system); }; | ||
| 727 | |||
| 855 | server_manager->RegisterNamedService("fsp-ldr", std::make_shared<FSP_LDR>(system)); | 728 | server_manager->RegisterNamedService("fsp-ldr", std::make_shared<FSP_LDR>(system)); |
| 856 | server_manager->RegisterNamedService("fsp:pr", std::make_shared<FSP_PR>(system)); | 729 | server_manager->RegisterNamedService("fsp:pr", std::make_shared<FSP_PR>(system)); |
| 857 | server_manager->RegisterNamedService("fsp-srv", std::make_shared<FSP_SRV>(system)); | 730 | server_manager->RegisterNamedService("fsp-srv", std::move(FileSystemProxyFactory)); |
| 858 | ServerManager::RunServer(std::move(server_manager)); | 731 | ServerManager::RunServer(std::move(server_manager)); |
| 859 | } | 732 | } |
| 860 | 733 | ||
diff --git a/src/core/hle/service/filesystem/filesystem.h b/src/core/hle/service/filesystem/filesystem.h index 276d264e1..48f37d289 100644 --- a/src/core/hle/service/filesystem/filesystem.h +++ b/src/core/hle/service/filesystem/filesystem.h | |||
| @@ -43,6 +43,9 @@ class ServiceManager; | |||
| 43 | 43 | ||
| 44 | namespace FileSystem { | 44 | namespace FileSystem { |
| 45 | 45 | ||
| 46 | class RomFsController; | ||
| 47 | class SaveDataController; | ||
| 48 | |||
| 46 | enum class ContentStorageId : u32 { | 49 | enum class ContentStorageId : u32 { |
| 47 | System, | 50 | System, |
| 48 | User, | 51 | User, |
| @@ -61,32 +64,24 @@ enum class OpenDirectoryMode : u64 { | |||
| 61 | }; | 64 | }; |
| 62 | DECLARE_ENUM_FLAG_OPERATORS(OpenDirectoryMode); | 65 | DECLARE_ENUM_FLAG_OPERATORS(OpenDirectoryMode); |
| 63 | 66 | ||
| 67 | using ProcessId = u64; | ||
| 68 | using ProgramId = u64; | ||
| 69 | |||
| 64 | class FileSystemController { | 70 | class FileSystemController { |
| 65 | public: | 71 | public: |
| 66 | explicit FileSystemController(Core::System& system_); | 72 | explicit FileSystemController(Core::System& system_); |
| 67 | ~FileSystemController(); | 73 | ~FileSystemController(); |
| 68 | 74 | ||
| 69 | Result RegisterRomFS(std::unique_ptr<FileSys::RomFSFactory>&& factory); | 75 | Result RegisterProcess(ProcessId process_id, ProgramId program_id, |
| 70 | Result RegisterSaveData(std::unique_ptr<FileSys::SaveDataFactory>&& factory); | 76 | std::shared_ptr<FileSys::RomFSFactory>&& factory); |
| 71 | Result RegisterSDMC(std::unique_ptr<FileSys::SDMCFactory>&& factory); | 77 | Result OpenProcess(ProgramId* out_program_id, |
| 72 | Result RegisterBIS(std::unique_ptr<FileSys::BISFactory>&& factory); | 78 | std::shared_ptr<SaveDataController>* out_save_data_controller, |
| 73 | 79 | std::shared_ptr<RomFsController>* out_romfs_controller, | |
| 74 | void SetPackedUpdate(FileSys::VirtualFile update_raw); | 80 | ProcessId process_id); |
| 75 | FileSys::VirtualFile OpenRomFSCurrentProcess() const; | 81 | void SetPackedUpdate(ProcessId process_id, FileSys::VirtualFile update_raw); |
| 76 | FileSys::VirtualFile OpenPatchedRomFS(u64 title_id, FileSys::ContentRecordType type) const; | 82 | |
| 77 | FileSys::VirtualFile OpenPatchedRomFSWithProgramIndex(u64 title_id, u8 program_index, | 83 | std::shared_ptr<SaveDataController> OpenSaveDataController(); |
| 78 | FileSys::ContentRecordType type) const; | 84 | |
| 79 | FileSys::VirtualFile OpenRomFS(u64 title_id, FileSys::StorageId storage_id, | ||
| 80 | FileSys::ContentRecordType type) const; | ||
| 81 | std::shared_ptr<FileSys::NCA> OpenBaseNca(u64 title_id, FileSys::StorageId storage_id, | ||
| 82 | FileSys::ContentRecordType type) const; | ||
| 83 | |||
| 84 | Result CreateSaveData(FileSys::VirtualDir* out_save_data, FileSys::SaveDataSpaceId space, | ||
| 85 | const FileSys::SaveDataAttribute& save_struct) const; | ||
| 86 | Result OpenSaveData(FileSys::VirtualDir* out_save_data, FileSys::SaveDataSpaceId space, | ||
| 87 | const FileSys::SaveDataAttribute& save_struct) const; | ||
| 88 | Result OpenSaveDataSpace(FileSys::VirtualDir* out_save_data_space, | ||
| 89 | FileSys::SaveDataSpaceId space) const; | ||
| 90 | Result OpenSDMC(FileSys::VirtualDir* out_sdmc) const; | 85 | Result OpenSDMC(FileSys::VirtualDir* out_sdmc) const; |
| 91 | Result OpenBISPartition(FileSys::VirtualDir* out_bis_partition, | 86 | Result OpenBISPartition(FileSys::VirtualDir* out_bis_partition, |
| 92 | FileSys::BisPartitionId id) const; | 87 | FileSys::BisPartitionId id) const; |
| @@ -96,11 +91,6 @@ public: | |||
| 96 | u64 GetFreeSpaceSize(FileSys::StorageId id) const; | 91 | u64 GetFreeSpaceSize(FileSys::StorageId id) const; |
| 97 | u64 GetTotalSpaceSize(FileSys::StorageId id) const; | 92 | u64 GetTotalSpaceSize(FileSys::StorageId id) const; |
| 98 | 93 | ||
| 99 | FileSys::SaveDataSize ReadSaveDataSize(FileSys::SaveDataType type, u64 title_id, | ||
| 100 | u128 user_id) const; | ||
| 101 | void WriteSaveDataSize(FileSys::SaveDataType type, u64 title_id, u128 user_id, | ||
| 102 | FileSys::SaveDataSize new_value) const; | ||
| 103 | |||
| 104 | void SetGameCard(FileSys::VirtualFile file); | 94 | void SetGameCard(FileSys::VirtualFile file); |
| 105 | FileSys::XCI* GetGameCard() const; | 95 | FileSys::XCI* GetGameCard() const; |
| 106 | 96 | ||
| @@ -133,15 +123,24 @@ public: | |||
| 133 | 123 | ||
| 134 | FileSys::VirtualDir GetBCATDirectory(u64 title_id) const; | 124 | FileSys::VirtualDir GetBCATDirectory(u64 title_id) const; |
| 135 | 125 | ||
| 136 | void SetAutoSaveDataCreation(bool enable); | ||
| 137 | |||
| 138 | // Creates the SaveData, SDMC, and BIS Factories. Should be called once and before any function | 126 | // Creates the SaveData, SDMC, and BIS Factories. Should be called once and before any function |
| 139 | // above is called. | 127 | // above is called. |
| 140 | void CreateFactories(FileSys::VfsFilesystem& vfs, bool overwrite = true); | 128 | void CreateFactories(FileSys::VfsFilesystem& vfs, bool overwrite = true); |
| 141 | 129 | ||
| 130 | void Reset(); | ||
| 131 | |||
| 142 | private: | 132 | private: |
| 143 | std::unique_ptr<FileSys::RomFSFactory> romfs_factory; | 133 | std::shared_ptr<FileSys::SaveDataFactory> CreateSaveDataFactory(ProgramId program_id); |
| 144 | std::unique_ptr<FileSys::SaveDataFactory> save_data_factory; | 134 | |
| 135 | struct Registration { | ||
| 136 | ProgramId program_id; | ||
| 137 | std::shared_ptr<FileSys::RomFSFactory> romfs_factory; | ||
| 138 | std::shared_ptr<FileSys::SaveDataFactory> save_data_factory; | ||
| 139 | }; | ||
| 140 | |||
| 141 | std::mutex registration_lock; | ||
| 142 | std::map<ProcessId, Registration> registrations; | ||
| 143 | |||
| 145 | std::unique_ptr<FileSys::SDMCFactory> sdmc_factory; | 144 | std::unique_ptr<FileSys::SDMCFactory> sdmc_factory; |
| 146 | std::unique_ptr<FileSys::BISFactory> bis_factory; | 145 | std::unique_ptr<FileSys::BISFactory> bis_factory; |
| 147 | 146 | ||
diff --git a/src/core/hle/service/filesystem/fsp_srv.cpp b/src/core/hle/service/filesystem/fsp_srv.cpp index 82ecc1b90..a2397bec4 100644 --- a/src/core/hle/service/filesystem/fsp_srv.cpp +++ b/src/core/hle/service/filesystem/fsp_srv.cpp | |||
| @@ -27,6 +27,8 @@ | |||
| 27 | #include "core/hle/result.h" | 27 | #include "core/hle/result.h" |
| 28 | #include "core/hle/service/filesystem/filesystem.h" | 28 | #include "core/hle/service/filesystem/filesystem.h" |
| 29 | #include "core/hle/service/filesystem/fsp_srv.h" | 29 | #include "core/hle/service/filesystem/fsp_srv.h" |
| 30 | #include "core/hle/service/filesystem/romfs_controller.h" | ||
| 31 | #include "core/hle/service/filesystem/save_data_controller.h" | ||
| 30 | #include "core/hle/service/hle_ipc.h" | 32 | #include "core/hle/service/hle_ipc.h" |
| 31 | #include "core/hle/service/ipc_helpers.h" | 33 | #include "core/hle/service/ipc_helpers.h" |
| 32 | #include "core/reporter.h" | 34 | #include "core/reporter.h" |
| @@ -577,9 +579,11 @@ private: | |||
| 577 | 579 | ||
| 578 | class ISaveDataInfoReader final : public ServiceFramework<ISaveDataInfoReader> { | 580 | class ISaveDataInfoReader final : public ServiceFramework<ISaveDataInfoReader> { |
| 579 | public: | 581 | public: |
| 580 | explicit ISaveDataInfoReader(Core::System& system_, FileSys::SaveDataSpaceId space, | 582 | explicit ISaveDataInfoReader(Core::System& system_, |
| 581 | FileSystemController& fsc_) | 583 | std::shared_ptr<SaveDataController> save_data_controller_, |
| 582 | : ServiceFramework{system_, "ISaveDataInfoReader"}, fsc{fsc_} { | 584 | FileSys::SaveDataSpaceId space) |
| 585 | : ServiceFramework{system_, "ISaveDataInfoReader"}, save_data_controller{ | ||
| 586 | save_data_controller_} { | ||
| 583 | static const FunctionInfo functions[] = { | 587 | static const FunctionInfo functions[] = { |
| 584 | {0, &ISaveDataInfoReader::ReadSaveDataInfo, "ReadSaveDataInfo"}, | 588 | {0, &ISaveDataInfoReader::ReadSaveDataInfo, "ReadSaveDataInfo"}, |
| 585 | }; | 589 | }; |
| @@ -626,7 +630,7 @@ private: | |||
| 626 | 630 | ||
| 627 | void FindAllSaves(FileSys::SaveDataSpaceId space) { | 631 | void FindAllSaves(FileSys::SaveDataSpaceId space) { |
| 628 | FileSys::VirtualDir save_root{}; | 632 | FileSys::VirtualDir save_root{}; |
| 629 | const auto result = fsc.OpenSaveDataSpace(&save_root, space); | 633 | const auto result = save_data_controller->OpenSaveDataSpace(&save_root, space); |
| 630 | 634 | ||
| 631 | if (result != ResultSuccess || save_root == nullptr) { | 635 | if (result != ResultSuccess || save_root == nullptr) { |
| 632 | LOG_ERROR(Service_FS, "The save root for the space_id={:02X} was invalid!", space); | 636 | LOG_ERROR(Service_FS, "The save root for the space_id={:02X} was invalid!", space); |
| @@ -723,7 +727,8 @@ private: | |||
| 723 | }; | 727 | }; |
| 724 | static_assert(sizeof(SaveDataInfo) == 0x60, "SaveDataInfo has incorrect size."); | 728 | static_assert(sizeof(SaveDataInfo) == 0x60, "SaveDataInfo has incorrect size."); |
| 725 | 729 | ||
| 726 | FileSystemController& fsc; | 730 | ProcessId process_id = 0; |
| 731 | std::shared_ptr<SaveDataController> save_data_controller; | ||
| 727 | std::vector<SaveDataInfo> info; | 732 | std::vector<SaveDataInfo> info; |
| 728 | u64 next_entry_index = 0; | 733 | u64 next_entry_index = 0; |
| 729 | }; | 734 | }; |
| @@ -863,21 +868,20 @@ FSP_SRV::FSP_SRV(Core::System& system_) | |||
| 863 | if (Settings::values.enable_fs_access_log) { | 868 | if (Settings::values.enable_fs_access_log) { |
| 864 | access_log_mode = AccessLogMode::SdCard; | 869 | access_log_mode = AccessLogMode::SdCard; |
| 865 | } | 870 | } |
| 866 | |||
| 867 | // This should be true on creation | ||
| 868 | fsc.SetAutoSaveDataCreation(true); | ||
| 869 | } | 871 | } |
| 870 | 872 | ||
| 871 | FSP_SRV::~FSP_SRV() = default; | 873 | FSP_SRV::~FSP_SRV() = default; |
| 872 | 874 | ||
| 873 | void FSP_SRV::SetCurrentProcess(HLERequestContext& ctx) { | 875 | void FSP_SRV::SetCurrentProcess(HLERequestContext& ctx) { |
| 874 | IPC::RequestParser rp{ctx}; | 876 | current_process_id = ctx.GetPID(); |
| 875 | current_process_id = rp.Pop<u64>(); | ||
| 876 | 877 | ||
| 877 | LOG_DEBUG(Service_FS, "called. current_process_id=0x{:016X}", current_process_id); | 878 | LOG_DEBUG(Service_FS, "called. current_process_id=0x{:016X}", current_process_id); |
| 878 | 879 | ||
| 880 | const auto res = | ||
| 881 | fsc.OpenProcess(&program_id, &save_data_controller, &romfs_controller, current_process_id); | ||
| 882 | |||
| 879 | IPC::ResponseBuilder rb{ctx, 2}; | 883 | IPC::ResponseBuilder rb{ctx, 2}; |
| 880 | rb.Push(ResultSuccess); | 884 | rb.Push(res); |
| 881 | } | 885 | } |
| 882 | 886 | ||
| 883 | void FSP_SRV::OpenFileSystemWithPatch(HLERequestContext& ctx) { | 887 | void FSP_SRV::OpenFileSystemWithPatch(HLERequestContext& ctx) { |
| @@ -916,7 +920,8 @@ void FSP_SRV::CreateSaveDataFileSystem(HLERequestContext& ctx) { | |||
| 916 | uid[1], uid[0]); | 920 | uid[1], uid[0]); |
| 917 | 921 | ||
| 918 | FileSys::VirtualDir save_data_dir{}; | 922 | FileSys::VirtualDir save_data_dir{}; |
| 919 | fsc.CreateSaveData(&save_data_dir, FileSys::SaveDataSpaceId::NandUser, save_struct); | 923 | save_data_controller->CreateSaveData(&save_data_dir, FileSys::SaveDataSpaceId::NandUser, |
| 924 | save_struct); | ||
| 920 | 925 | ||
| 921 | IPC::ResponseBuilder rb{ctx, 2}; | 926 | IPC::ResponseBuilder rb{ctx, 2}; |
| 922 | rb.Push(ResultSuccess); | 927 | rb.Push(ResultSuccess); |
| @@ -931,7 +936,8 @@ void FSP_SRV::CreateSaveDataFileSystemBySystemSaveDataId(HLERequestContext& ctx) | |||
| 931 | LOG_DEBUG(Service_FS, "called save_struct = {}", save_struct.DebugInfo()); | 936 | LOG_DEBUG(Service_FS, "called save_struct = {}", save_struct.DebugInfo()); |
| 932 | 937 | ||
| 933 | FileSys::VirtualDir save_data_dir{}; | 938 | FileSys::VirtualDir save_data_dir{}; |
| 934 | fsc.CreateSaveData(&save_data_dir, FileSys::SaveDataSpaceId::NandSystem, save_struct); | 939 | save_data_controller->CreateSaveData(&save_data_dir, FileSys::SaveDataSpaceId::NandSystem, |
| 940 | save_struct); | ||
| 935 | 941 | ||
| 936 | IPC::ResponseBuilder rb{ctx, 2}; | 942 | IPC::ResponseBuilder rb{ctx, 2}; |
| 937 | rb.Push(ResultSuccess); | 943 | rb.Push(ResultSuccess); |
| @@ -950,7 +956,8 @@ void FSP_SRV::OpenSaveDataFileSystem(HLERequestContext& ctx) { | |||
| 950 | LOG_INFO(Service_FS, "called."); | 956 | LOG_INFO(Service_FS, "called."); |
| 951 | 957 | ||
| 952 | FileSys::VirtualDir dir{}; | 958 | FileSys::VirtualDir dir{}; |
| 953 | auto result = fsc.OpenSaveData(&dir, parameters.space_id, parameters.attribute); | 959 | auto result = |
| 960 | save_data_controller->OpenSaveData(&dir, parameters.space_id, parameters.attribute); | ||
| 954 | if (result != ResultSuccess) { | 961 | if (result != ResultSuccess) { |
| 955 | IPC::ResponseBuilder rb{ctx, 2, 0, 0}; | 962 | IPC::ResponseBuilder rb{ctx, 2, 0, 0}; |
| 956 | rb.Push(FileSys::ERROR_ENTITY_NOT_FOUND); | 963 | rb.Push(FileSys::ERROR_ENTITY_NOT_FOUND); |
| @@ -1001,7 +1008,7 @@ void FSP_SRV::OpenSaveDataInfoReaderBySaveDataSpaceId(HLERequestContext& ctx) { | |||
| 1001 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 1008 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 1002 | rb.Push(ResultSuccess); | 1009 | rb.Push(ResultSuccess); |
| 1003 | rb.PushIpcInterface<ISaveDataInfoReader>( | 1010 | rb.PushIpcInterface<ISaveDataInfoReader>( |
| 1004 | std::make_shared<ISaveDataInfoReader>(system, space, fsc)); | 1011 | std::make_shared<ISaveDataInfoReader>(system, save_data_controller, space)); |
| 1005 | } | 1012 | } |
| 1006 | 1013 | ||
| 1007 | void FSP_SRV::OpenSaveDataInfoReaderOnlyCacheStorage(HLERequestContext& ctx) { | 1014 | void FSP_SRV::OpenSaveDataInfoReaderOnlyCacheStorage(HLERequestContext& ctx) { |
| @@ -1009,8 +1016,8 @@ void FSP_SRV::OpenSaveDataInfoReaderOnlyCacheStorage(HLERequestContext& ctx) { | |||
| 1009 | 1016 | ||
| 1010 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 1017 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 1011 | rb.Push(ResultSuccess); | 1018 | rb.Push(ResultSuccess); |
| 1012 | rb.PushIpcInterface<ISaveDataInfoReader>(system, FileSys::SaveDataSpaceId::TemporaryStorage, | 1019 | rb.PushIpcInterface<ISaveDataInfoReader>(system, save_data_controller, |
| 1013 | fsc); | 1020 | FileSys::SaveDataSpaceId::TemporaryStorage); |
| 1014 | } | 1021 | } |
| 1015 | 1022 | ||
| 1016 | void FSP_SRV::WriteSaveDataFileSystemExtraDataBySaveDataAttribute(HLERequestContext& ctx) { | 1023 | void FSP_SRV::WriteSaveDataFileSystemExtraDataBySaveDataAttribute(HLERequestContext& ctx) { |
| @@ -1050,7 +1057,7 @@ void FSP_SRV::OpenDataStorageByCurrentProcess(HLERequestContext& ctx) { | |||
| 1050 | LOG_DEBUG(Service_FS, "called"); | 1057 | LOG_DEBUG(Service_FS, "called"); |
| 1051 | 1058 | ||
| 1052 | if (!romfs) { | 1059 | if (!romfs) { |
| 1053 | auto current_romfs = fsc.OpenRomFSCurrentProcess(); | 1060 | auto current_romfs = romfs_controller->OpenRomFSCurrentProcess(); |
| 1054 | if (!current_romfs) { | 1061 | if (!current_romfs) { |
| 1055 | // TODO (bunnei): Find the right error code to use here | 1062 | // TODO (bunnei): Find the right error code to use here |
| 1056 | LOG_CRITICAL(Service_FS, "no file system interface available!"); | 1063 | LOG_CRITICAL(Service_FS, "no file system interface available!"); |
| @@ -1078,7 +1085,7 @@ void FSP_SRV::OpenDataStorageByDataId(HLERequestContext& ctx) { | |||
| 1078 | LOG_DEBUG(Service_FS, "called with storage_id={:02X}, unknown={:08X}, title_id={:016X}", | 1085 | LOG_DEBUG(Service_FS, "called with storage_id={:02X}, unknown={:08X}, title_id={:016X}", |
| 1079 | storage_id, unknown, title_id); | 1086 | storage_id, unknown, title_id); |
| 1080 | 1087 | ||
| 1081 | auto data = fsc.OpenRomFS(title_id, storage_id, FileSys::ContentRecordType::Data); | 1088 | auto data = romfs_controller->OpenRomFS(title_id, storage_id, FileSys::ContentRecordType::Data); |
| 1082 | 1089 | ||
| 1083 | if (!data) { | 1090 | if (!data) { |
| 1084 | const auto archive = FileSys::SystemArchive::SynthesizeSystemArchive(title_id); | 1091 | const auto archive = FileSys::SystemArchive::SynthesizeSystemArchive(title_id); |
| @@ -1101,7 +1108,8 @@ void FSP_SRV::OpenDataStorageByDataId(HLERequestContext& ctx) { | |||
| 1101 | 1108 | ||
| 1102 | const FileSys::PatchManager pm{title_id, fsc, content_provider}; | 1109 | const FileSys::PatchManager pm{title_id, fsc, content_provider}; |
| 1103 | 1110 | ||
| 1104 | auto base = fsc.OpenBaseNca(title_id, storage_id, FileSys::ContentRecordType::Data); | 1111 | auto base = |
| 1112 | romfs_controller->OpenBaseNca(title_id, storage_id, FileSys::ContentRecordType::Data); | ||
| 1105 | auto storage = std::make_shared<IStorage>( | 1113 | auto storage = std::make_shared<IStorage>( |
| 1106 | system, pm.PatchRomFS(base.get(), std::move(data), FileSys::ContentRecordType::Data)); | 1114 | system, pm.PatchRomFS(base.get(), std::move(data), FileSys::ContentRecordType::Data)); |
| 1107 | 1115 | ||
| @@ -1129,9 +1137,8 @@ void FSP_SRV::OpenDataStorageWithProgramIndex(HLERequestContext& ctx) { | |||
| 1129 | 1137 | ||
| 1130 | LOG_DEBUG(Service_FS, "called, program_index={}", program_index); | 1138 | LOG_DEBUG(Service_FS, "called, program_index={}", program_index); |
| 1131 | 1139 | ||
| 1132 | auto patched_romfs = | 1140 | auto patched_romfs = romfs_controller->OpenPatchedRomFSWithProgramIndex( |
| 1133 | fsc.OpenPatchedRomFSWithProgramIndex(system.GetApplicationProcessProgramID(), program_index, | 1141 | program_id, program_index, FileSys::ContentRecordType::Program); |
| 1134 | FileSys::ContentRecordType::Program); | ||
| 1135 | 1142 | ||
| 1136 | if (!patched_romfs) { | 1143 | if (!patched_romfs) { |
| 1137 | // TODO: Find the right error code to use here | 1144 | // TODO: Find the right error code to use here |
| @@ -1152,7 +1159,7 @@ void FSP_SRV::OpenDataStorageWithProgramIndex(HLERequestContext& ctx) { | |||
| 1152 | void FSP_SRV::DisableAutoSaveDataCreation(HLERequestContext& ctx) { | 1159 | void FSP_SRV::DisableAutoSaveDataCreation(HLERequestContext& ctx) { |
| 1153 | LOG_DEBUG(Service_FS, "called"); | 1160 | LOG_DEBUG(Service_FS, "called"); |
| 1154 | 1161 | ||
| 1155 | fsc.SetAutoSaveDataCreation(false); | 1162 | save_data_controller->SetAutoCreate(false); |
| 1156 | 1163 | ||
| 1157 | IPC::ResponseBuilder rb{ctx, 2}; | 1164 | IPC::ResponseBuilder rb{ctx, 2}; |
| 1158 | rb.Push(ResultSuccess); | 1165 | rb.Push(ResultSuccess); |
diff --git a/src/core/hle/service/filesystem/fsp_srv.h b/src/core/hle/service/filesystem/fsp_srv.h index 280bc9867..26980af99 100644 --- a/src/core/hle/service/filesystem/fsp_srv.h +++ b/src/core/hle/service/filesystem/fsp_srv.h | |||
| @@ -17,6 +17,9 @@ class FileSystemBackend; | |||
| 17 | 17 | ||
| 18 | namespace Service::FileSystem { | 18 | namespace Service::FileSystem { |
| 19 | 19 | ||
| 20 | class RomFsController; | ||
| 21 | class SaveDataController; | ||
| 22 | |||
| 20 | enum class AccessLogVersion : u32 { | 23 | enum class AccessLogVersion : u32 { |
| 21 | V7_0_0 = 2, | 24 | V7_0_0 = 2, |
| 22 | 25 | ||
| @@ -67,6 +70,9 @@ private: | |||
| 67 | u64 current_process_id = 0; | 70 | u64 current_process_id = 0; |
| 68 | u32 access_log_program_index = 0; | 71 | u32 access_log_program_index = 0; |
| 69 | AccessLogMode access_log_mode = AccessLogMode::None; | 72 | AccessLogMode access_log_mode = AccessLogMode::None; |
| 73 | u64 program_id = 0; | ||
| 74 | std::shared_ptr<SaveDataController> save_data_controller; | ||
| 75 | std::shared_ptr<RomFsController> romfs_controller; | ||
| 70 | }; | 76 | }; |
| 71 | 77 | ||
| 72 | } // namespace Service::FileSystem | 78 | } // namespace Service::FileSystem |
diff --git a/src/core/hle/service/filesystem/romfs_controller.cpp b/src/core/hle/service/filesystem/romfs_controller.cpp new file mode 100644 index 000000000..19c9cec72 --- /dev/null +++ b/src/core/hle/service/filesystem/romfs_controller.cpp | |||
| @@ -0,0 +1,37 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #include "core/hle/service/filesystem/romfs_controller.h" | ||
| 5 | |||
| 6 | namespace Service::FileSystem { | ||
| 7 | |||
| 8 | RomFsController::RomFsController(std::shared_ptr<FileSys::RomFSFactory> factory_, u64 program_id_) | ||
| 9 | : factory{std::move(factory_)}, program_id{program_id_} {} | ||
| 10 | RomFsController::~RomFsController() = default; | ||
| 11 | |||
| 12 | FileSys::VirtualFile RomFsController::OpenRomFSCurrentProcess() { | ||
| 13 | return factory->OpenCurrentProcess(program_id); | ||
| 14 | } | ||
| 15 | |||
| 16 | FileSys::VirtualFile RomFsController::OpenPatchedRomFS(u64 title_id, | ||
| 17 | FileSys::ContentRecordType type) { | ||
| 18 | return factory->OpenPatchedRomFS(title_id, type); | ||
| 19 | } | ||
| 20 | |||
| 21 | FileSys::VirtualFile RomFsController::OpenPatchedRomFSWithProgramIndex( | ||
| 22 | u64 title_id, u8 program_index, FileSys::ContentRecordType type) { | ||
| 23 | return factory->OpenPatchedRomFSWithProgramIndex(title_id, program_index, type); | ||
| 24 | } | ||
| 25 | |||
| 26 | FileSys::VirtualFile RomFsController::OpenRomFS(u64 title_id, FileSys::StorageId storage_id, | ||
| 27 | FileSys::ContentRecordType type) { | ||
| 28 | return factory->Open(title_id, storage_id, type); | ||
| 29 | } | ||
| 30 | |||
| 31 | std::shared_ptr<FileSys::NCA> RomFsController::OpenBaseNca(u64 title_id, | ||
| 32 | FileSys::StorageId storage_id, | ||
| 33 | FileSys::ContentRecordType type) { | ||
| 34 | return factory->GetEntry(title_id, storage_id, type); | ||
| 35 | } | ||
| 36 | |||
| 37 | } // namespace Service::FileSystem | ||
diff --git a/src/core/hle/service/filesystem/romfs_controller.h b/src/core/hle/service/filesystem/romfs_controller.h new file mode 100644 index 000000000..9a478f71d --- /dev/null +++ b/src/core/hle/service/filesystem/romfs_controller.h | |||
| @@ -0,0 +1,31 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include "core/file_sys/nca_metadata.h" | ||
| 7 | #include "core/file_sys/romfs_factory.h" | ||
| 8 | #include "core/file_sys/vfs_types.h" | ||
| 9 | |||
| 10 | namespace Service::FileSystem { | ||
| 11 | |||
| 12 | class RomFsController { | ||
| 13 | public: | ||
| 14 | explicit RomFsController(std::shared_ptr<FileSys::RomFSFactory> factory_, u64 program_id_); | ||
| 15 | ~RomFsController(); | ||
| 16 | |||
| 17 | FileSys::VirtualFile OpenRomFSCurrentProcess(); | ||
| 18 | FileSys::VirtualFile OpenPatchedRomFS(u64 title_id, FileSys::ContentRecordType type); | ||
| 19 | FileSys::VirtualFile OpenPatchedRomFSWithProgramIndex(u64 title_id, u8 program_index, | ||
| 20 | FileSys::ContentRecordType type); | ||
| 21 | FileSys::VirtualFile OpenRomFS(u64 title_id, FileSys::StorageId storage_id, | ||
| 22 | FileSys::ContentRecordType type); | ||
| 23 | std::shared_ptr<FileSys::NCA> OpenBaseNca(u64 title_id, FileSys::StorageId storage_id, | ||
| 24 | FileSys::ContentRecordType type); | ||
| 25 | |||
| 26 | private: | ||
| 27 | const std::shared_ptr<FileSys::RomFSFactory> factory; | ||
| 28 | const u64 program_id; | ||
| 29 | }; | ||
| 30 | |||
| 31 | } // namespace Service::FileSystem | ||
diff --git a/src/core/hle/service/filesystem/save_data_controller.cpp b/src/core/hle/service/filesystem/save_data_controller.cpp new file mode 100644 index 000000000..d19b3ea1e --- /dev/null +++ b/src/core/hle/service/filesystem/save_data_controller.cpp | |||
| @@ -0,0 +1,99 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #include "core/core.h" | ||
| 5 | #include "core/file_sys/control_metadata.h" | ||
| 6 | #include "core/file_sys/errors.h" | ||
| 7 | #include "core/file_sys/patch_manager.h" | ||
| 8 | #include "core/hle/service/filesystem/save_data_controller.h" | ||
| 9 | #include "core/loader/loader.h" | ||
| 10 | |||
| 11 | namespace Service::FileSystem { | ||
| 12 | |||
| 13 | namespace { | ||
| 14 | |||
| 15 | // A default size for normal/journal save data size if application control metadata cannot be found. | ||
| 16 | // This should be large enough to satisfy even the most extreme requirements (~4.2GB) | ||
| 17 | constexpr u64 SufficientSaveDataSize = 0xF0000000; | ||
| 18 | |||
| 19 | FileSys::SaveDataSize GetDefaultSaveDataSize(Core::System& system, u64 program_id) { | ||
| 20 | const FileSys::PatchManager pm{program_id, system.GetFileSystemController(), | ||
| 21 | system.GetContentProvider()}; | ||
| 22 | const auto metadata = pm.GetControlMetadata(); | ||
| 23 | const auto& nacp = metadata.first; | ||
| 24 | |||
| 25 | if (nacp != nullptr) { | ||
| 26 | return {nacp->GetDefaultNormalSaveSize(), nacp->GetDefaultJournalSaveSize()}; | ||
| 27 | } | ||
| 28 | |||
| 29 | return {SufficientSaveDataSize, SufficientSaveDataSize}; | ||
| 30 | } | ||
| 31 | |||
| 32 | } // namespace | ||
| 33 | |||
| 34 | SaveDataController::SaveDataController(Core::System& system_, | ||
| 35 | std::shared_ptr<FileSys::SaveDataFactory> factory_) | ||
| 36 | : system{system_}, factory{std::move(factory_)} {} | ||
| 37 | SaveDataController::~SaveDataController() = default; | ||
| 38 | |||
| 39 | Result SaveDataController::CreateSaveData(FileSys::VirtualDir* out_save_data, | ||
| 40 | FileSys::SaveDataSpaceId space, | ||
| 41 | const FileSys::SaveDataAttribute& attribute) { | ||
| 42 | LOG_TRACE(Service_FS, "Creating Save Data for space_id={:01X}, save_struct={}", space, | ||
| 43 | attribute.DebugInfo()); | ||
| 44 | |||
| 45 | auto save_data = factory->Create(space, attribute); | ||
| 46 | if (save_data == nullptr) { | ||
| 47 | return FileSys::ERROR_ENTITY_NOT_FOUND; | ||
| 48 | } | ||
| 49 | |||
| 50 | *out_save_data = save_data; | ||
| 51 | return ResultSuccess; | ||
| 52 | } | ||
| 53 | |||
| 54 | Result SaveDataController::OpenSaveData(FileSys::VirtualDir* out_save_data, | ||
| 55 | FileSys::SaveDataSpaceId space, | ||
| 56 | const FileSys::SaveDataAttribute& attribute) { | ||
| 57 | auto save_data = factory->Open(space, attribute); | ||
| 58 | if (save_data == nullptr) { | ||
| 59 | return FileSys::ERROR_ENTITY_NOT_FOUND; | ||
| 60 | } | ||
| 61 | |||
| 62 | *out_save_data = save_data; | ||
| 63 | return ResultSuccess; | ||
| 64 | } | ||
| 65 | |||
| 66 | Result SaveDataController::OpenSaveDataSpace(FileSys::VirtualDir* out_save_data_space, | ||
| 67 | FileSys::SaveDataSpaceId space) { | ||
| 68 | auto save_data_space = factory->GetSaveDataSpaceDirectory(space); | ||
| 69 | if (save_data_space == nullptr) { | ||
| 70 | return FileSys::ERROR_ENTITY_NOT_FOUND; | ||
| 71 | } | ||
| 72 | |||
| 73 | *out_save_data_space = save_data_space; | ||
| 74 | return ResultSuccess; | ||
| 75 | } | ||
| 76 | |||
| 77 | FileSys::SaveDataSize SaveDataController::ReadSaveDataSize(FileSys::SaveDataType type, u64 title_id, | ||
| 78 | u128 user_id) { | ||
| 79 | const auto value = factory->ReadSaveDataSize(type, title_id, user_id); | ||
| 80 | |||
| 81 | if (value.normal == 0 && value.journal == 0) { | ||
| 82 | const auto size = GetDefaultSaveDataSize(system, title_id); | ||
| 83 | factory->WriteSaveDataSize(type, title_id, user_id, size); | ||
| 84 | return size; | ||
| 85 | } | ||
| 86 | |||
| 87 | return value; | ||
| 88 | } | ||
| 89 | |||
| 90 | void SaveDataController::WriteSaveDataSize(FileSys::SaveDataType type, u64 title_id, u128 user_id, | ||
| 91 | FileSys::SaveDataSize new_value) { | ||
| 92 | factory->WriteSaveDataSize(type, title_id, user_id, new_value); | ||
| 93 | } | ||
| 94 | |||
| 95 | void SaveDataController::SetAutoCreate(bool state) { | ||
| 96 | factory->SetAutoCreate(state); | ||
| 97 | } | ||
| 98 | |||
| 99 | } // namespace Service::FileSystem | ||
diff --git a/src/core/hle/service/filesystem/save_data_controller.h b/src/core/hle/service/filesystem/save_data_controller.h new file mode 100644 index 000000000..863188e4c --- /dev/null +++ b/src/core/hle/service/filesystem/save_data_controller.h | |||
| @@ -0,0 +1,35 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include "core/file_sys/nca_metadata.h" | ||
| 7 | #include "core/file_sys/savedata_factory.h" | ||
| 8 | #include "core/file_sys/vfs_types.h" | ||
| 9 | |||
| 10 | namespace Service::FileSystem { | ||
| 11 | |||
| 12 | class SaveDataController { | ||
| 13 | public: | ||
| 14 | explicit SaveDataController(Core::System& system, | ||
| 15 | std::shared_ptr<FileSys::SaveDataFactory> factory_); | ||
| 16 | ~SaveDataController(); | ||
| 17 | |||
| 18 | Result CreateSaveData(FileSys::VirtualDir* out_save_data, FileSys::SaveDataSpaceId space, | ||
| 19 | const FileSys::SaveDataAttribute& attribute); | ||
| 20 | Result OpenSaveData(FileSys::VirtualDir* out_save_data, FileSys::SaveDataSpaceId space, | ||
| 21 | const FileSys::SaveDataAttribute& attribute); | ||
| 22 | Result OpenSaveDataSpace(FileSys::VirtualDir* out_save_data_space, | ||
| 23 | FileSys::SaveDataSpaceId space); | ||
| 24 | |||
| 25 | FileSys::SaveDataSize ReadSaveDataSize(FileSys::SaveDataType type, u64 title_id, u128 user_id); | ||
| 26 | void WriteSaveDataSize(FileSys::SaveDataType type, u64 title_id, u128 user_id, | ||
| 27 | FileSys::SaveDataSize new_value); | ||
| 28 | void SetAutoCreate(bool state); | ||
| 29 | |||
| 30 | private: | ||
| 31 | Core::System& system; | ||
| 32 | const std::shared_ptr<FileSys::SaveDataFactory> factory; | ||
| 33 | }; | ||
| 34 | |||
| 35 | } // namespace Service::FileSystem | ||
diff --git a/src/core/hle/service/friend/friend.cpp b/src/core/hle/service/friend/friend.cpp index 0507b14e7..aeb849efa 100644 --- a/src/core/hle/service/friend/friend.cpp +++ b/src/core/hle/service/friend/friend.cpp | |||
| @@ -131,7 +131,7 @@ private: | |||
| 131 | u8 is_favorite; | 131 | u8 is_favorite; |
| 132 | u8 same_app; | 132 | u8 same_app; |
| 133 | u8 same_app_played; | 133 | u8 same_app_played; |
| 134 | u8 arbitary_app_played; | 134 | u8 arbitrary_app_played; |
| 135 | u64 group_id; | 135 | u64 group_id; |
| 136 | }; | 136 | }; |
| 137 | static_assert(sizeof(SizedFriendFilter) == 0x10, "SizedFriendFilter is an invalid size"); | 137 | static_assert(sizeof(SizedFriendFilter) == 0x10, "SizedFriendFilter is an invalid size"); |
diff --git a/src/core/hle/service/glue/arp.cpp b/src/core/hle/service/glue/arp.cpp index 6f1151b03..1254b6d49 100644 --- a/src/core/hle/service/glue/arp.cpp +++ b/src/core/hle/service/glue/arp.cpp | |||
| @@ -15,9 +15,10 @@ | |||
| 15 | namespace Service::Glue { | 15 | namespace Service::Glue { |
| 16 | 16 | ||
| 17 | namespace { | 17 | namespace { |
| 18 | std::optional<u64> GetTitleIDForProcessID(const Core::System& system, u64 process_id) { | 18 | std::optional<u64> GetTitleIDForProcessID(Core::System& system, u64 process_id) { |
| 19 | const auto& list = system.Kernel().GetProcessList(); | 19 | auto list = system.Kernel().GetProcessList(); |
| 20 | const auto iter = std::find_if(list.begin(), list.end(), [&process_id](const auto& process) { | 20 | |
| 21 | const auto iter = std::find_if(list.begin(), list.end(), [&process_id](auto& process) { | ||
| 21 | return process->GetProcessId() == process_id; | 22 | return process->GetProcessId() == process_id; |
| 22 | }); | 23 | }); |
| 23 | 24 | ||
diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp index fc8a3ab66..4ce0a9834 100644 --- a/src/core/hle/service/hid/hid.cpp +++ b/src/core/hle/service/hid/hid.cpp | |||
| @@ -18,23 +18,21 @@ namespace Service::HID { | |||
| 18 | 18 | ||
| 19 | void LoopProcess(Core::System& system) { | 19 | void LoopProcess(Core::System& system) { |
| 20 | auto server_manager = std::make_unique<ServerManager>(system); | 20 | auto server_manager = std::make_unique<ServerManager>(system); |
| 21 | std::shared_ptr<ResourceManager> resouce_manager = std::make_shared<ResourceManager>(system); | 21 | std::shared_ptr<ResourceManager> resource_manager = std::make_shared<ResourceManager>(system); |
| 22 | std::shared_ptr<HidFirmwareSettings> firmware_settings = | 22 | std::shared_ptr<HidFirmwareSettings> firmware_settings = |
| 23 | std::make_shared<HidFirmwareSettings>(); | 23 | std::make_shared<HidFirmwareSettings>(); |
| 24 | 24 | ||
| 25 | // TODO: Remove this hack until this service is emulated properly. | 25 | // TODO: Remove this hack when am is emulated properly. |
| 26 | const auto process_list = system.Kernel().GetProcessList(); | 26 | resource_manager->Initialize(); |
| 27 | if (!process_list.empty()) { | 27 | resource_manager->RegisterAppletResourceUserId(system.ApplicationProcess()->GetProcessId(), |
| 28 | resouce_manager->Initialize(); | 28 | true); |
| 29 | resouce_manager->RegisterAppletResourceUserId(process_list[0]->GetId(), true); | ||
| 30 | } | ||
| 31 | 29 | ||
| 32 | server_manager->RegisterNamedService( | 30 | server_manager->RegisterNamedService( |
| 33 | "hid", std::make_shared<IHidServer>(system, resouce_manager, firmware_settings)); | 31 | "hid", std::make_shared<IHidServer>(system, resource_manager, firmware_settings)); |
| 34 | server_manager->RegisterNamedService( | 32 | server_manager->RegisterNamedService( |
| 35 | "hid:dbg", std::make_shared<IHidDebugServer>(system, resouce_manager)); | 33 | "hid:dbg", std::make_shared<IHidDebugServer>(system, resource_manager)); |
| 36 | server_manager->RegisterNamedService( | 34 | server_manager->RegisterNamedService( |
| 37 | "hid:sys", std::make_shared<IHidSystemServer>(system, resouce_manager)); | 35 | "hid:sys", std::make_shared<IHidSystemServer>(system, resource_manager)); |
| 38 | 36 | ||
| 39 | server_manager->RegisterNamedService("hidbus", std::make_shared<HidBus>(system)); | 37 | server_manager->RegisterNamedService("hidbus", std::make_shared<HidBus>(system)); |
| 40 | 38 | ||
diff --git a/src/core/hle/service/hid/hid_server.cpp b/src/core/hle/service/hid/hid_server.cpp index 74898888a..1951da33b 100644 --- a/src/core/hle/service/hid/hid_server.cpp +++ b/src/core/hle/service/hid/hid_server.cpp | |||
| @@ -1498,7 +1498,7 @@ void IHidServer::GetVibrationDeviceInfo(HLERequestContext& ctx) { | |||
| 1498 | bool check_device_index = false; | 1498 | bool check_device_index = false; |
| 1499 | 1499 | ||
| 1500 | switch (vibration_device_handle.npad_type) { | 1500 | switch (vibration_device_handle.npad_type) { |
| 1501 | case Core::HID::NpadStyleIndex::ProController: | 1501 | case Core::HID::NpadStyleIndex::Fullkey: |
| 1502 | case Core::HID::NpadStyleIndex::Handheld: | 1502 | case Core::HID::NpadStyleIndex::Handheld: |
| 1503 | case Core::HID::NpadStyleIndex::JoyconDual: | 1503 | case Core::HID::NpadStyleIndex::JoyconDual: |
| 1504 | case Core::HID::NpadStyleIndex::JoyconLeft: | 1504 | case Core::HID::NpadStyleIndex::JoyconLeft: |
diff --git a/src/core/hle/service/hid/hidbus.cpp b/src/core/hle/service/hid/hidbus.cpp index 46f503d38..c903ee8b8 100644 --- a/src/core/hle/service/hid/hidbus.cpp +++ b/src/core/hle/service/hid/hidbus.cpp | |||
| @@ -67,7 +67,7 @@ HidBus::~HidBus() { | |||
| 67 | void HidBus::UpdateHidbus(std::chrono::nanoseconds ns_late) { | 67 | void HidBus::UpdateHidbus(std::chrono::nanoseconds ns_late) { |
| 68 | if (is_hidbus_enabled) { | 68 | if (is_hidbus_enabled) { |
| 69 | for (std::size_t i = 0; i < devices.size(); ++i) { | 69 | for (std::size_t i = 0; i < devices.size(); ++i) { |
| 70 | if (!devices[i].is_device_initializated) { | 70 | if (!devices[i].is_device_initialized) { |
| 71 | continue; | 71 | continue; |
| 72 | } | 72 | } |
| 73 | auto& device = devices[i].device; | 73 | auto& device = devices[i].device; |
| @@ -213,7 +213,7 @@ void HidBus::Initialize(HLERequestContext& ctx) { | |||
| 213 | 213 | ||
| 214 | if (bus_handle_.internal_index == 0 && Settings::values.enable_ring_controller) { | 214 | if (bus_handle_.internal_index == 0 && Settings::values.enable_ring_controller) { |
| 215 | MakeDevice<RingController>(bus_handle_); | 215 | MakeDevice<RingController>(bus_handle_); |
| 216 | devices[device_index.value()].is_device_initializated = true; | 216 | devices[device_index.value()].is_device_initialized = true; |
| 217 | devices[device_index.value()].device->ActivateDevice(); | 217 | devices[device_index.value()].device->ActivateDevice(); |
| 218 | cur_entry.is_in_focus = true; | 218 | cur_entry.is_in_focus = true; |
| 219 | cur_entry.is_connected = true; | 219 | cur_entry.is_connected = true; |
| @@ -222,7 +222,7 @@ void HidBus::Initialize(HLERequestContext& ctx) { | |||
| 222 | cur_entry.is_polling_mode = false; | 222 | cur_entry.is_polling_mode = false; |
| 223 | } else { | 223 | } else { |
| 224 | MakeDevice<HidbusStubbed>(bus_handle_); | 224 | MakeDevice<HidbusStubbed>(bus_handle_); |
| 225 | devices[device_index.value()].is_device_initializated = true; | 225 | devices[device_index.value()].is_device_initialized = true; |
| 226 | cur_entry.is_in_focus = true; | 226 | cur_entry.is_in_focus = true; |
| 227 | cur_entry.is_connected = false; | 227 | cur_entry.is_connected = false; |
| 228 | cur_entry.is_connected_result = ResultSuccess; | 228 | cur_entry.is_connected_result = ResultSuccess; |
| @@ -261,7 +261,7 @@ void HidBus::Finalize(HLERequestContext& ctx) { | |||
| 261 | const auto entry_index = devices[device_index.value()].handle.internal_index; | 261 | const auto entry_index = devices[device_index.value()].handle.internal_index; |
| 262 | auto& cur_entry = hidbus_status.entries[entry_index]; | 262 | auto& cur_entry = hidbus_status.entries[entry_index]; |
| 263 | auto& device = devices[device_index.value()].device; | 263 | auto& device = devices[device_index.value()].device; |
| 264 | devices[device_index.value()].is_device_initializated = false; | 264 | devices[device_index.value()].is_device_initialized = false; |
| 265 | device->DeactivateDevice(); | 265 | device->DeactivateDevice(); |
| 266 | 266 | ||
| 267 | cur_entry.is_in_focus = true; | 267 | cur_entry.is_in_focus = true; |
diff --git a/src/core/hle/service/hid/hidbus.h b/src/core/hle/service/hid/hidbus.h index 05f62f634..03d9f6863 100644 --- a/src/core/hle/service/hid/hidbus.h +++ b/src/core/hle/service/hid/hidbus.h | |||
| @@ -89,7 +89,7 @@ private: | |||
| 89 | static_assert(sizeof(HidbusStatusManager) <= 0x1000, "HidbusStatusManager is an invalid size"); | 89 | static_assert(sizeof(HidbusStatusManager) <= 0x1000, "HidbusStatusManager is an invalid size"); |
| 90 | 90 | ||
| 91 | struct HidbusDevice { | 91 | struct HidbusDevice { |
| 92 | bool is_device_initializated{}; | 92 | bool is_device_initialized{}; |
| 93 | BusHandle handle{}; | 93 | BusHandle handle{}; |
| 94 | std::unique_ptr<HidbusBase> device{nullptr}; | 94 | std::unique_ptr<HidbusBase> device{nullptr}; |
| 95 | }; | 95 | }; |
diff --git a/src/core/hle/service/hle_ipc.cpp b/src/core/hle/service/hle_ipc.cpp index 39df77e43..3f38ceb03 100644 --- a/src/core/hle/service/hle_ipc.cpp +++ b/src/core/hle/service/hle_ipc.cpp | |||
| @@ -181,22 +181,22 @@ void HLERequestContext::ParseCommandBuffer(u32_le* src_cmdbuf, bool incoming) { | |||
| 181 | } | 181 | } |
| 182 | } | 182 | } |
| 183 | 183 | ||
| 184 | buffer_x_desciptors.reserve(command_header->num_buf_x_descriptors); | 184 | buffer_x_descriptors.reserve(command_header->num_buf_x_descriptors); |
| 185 | buffer_a_desciptors.reserve(command_header->num_buf_a_descriptors); | 185 | buffer_a_descriptors.reserve(command_header->num_buf_a_descriptors); |
| 186 | buffer_b_desciptors.reserve(command_header->num_buf_b_descriptors); | 186 | buffer_b_descriptors.reserve(command_header->num_buf_b_descriptors); |
| 187 | buffer_w_desciptors.reserve(command_header->num_buf_w_descriptors); | 187 | buffer_w_descriptors.reserve(command_header->num_buf_w_descriptors); |
| 188 | 188 | ||
| 189 | for (u32 i = 0; i < command_header->num_buf_x_descriptors; ++i) { | 189 | for (u32 i = 0; i < command_header->num_buf_x_descriptors; ++i) { |
| 190 | buffer_x_desciptors.push_back(rp.PopRaw<IPC::BufferDescriptorX>()); | 190 | buffer_x_descriptors.push_back(rp.PopRaw<IPC::BufferDescriptorX>()); |
| 191 | } | 191 | } |
| 192 | for (u32 i = 0; i < command_header->num_buf_a_descriptors; ++i) { | 192 | for (u32 i = 0; i < command_header->num_buf_a_descriptors; ++i) { |
| 193 | buffer_a_desciptors.push_back(rp.PopRaw<IPC::BufferDescriptorABW>()); | 193 | buffer_a_descriptors.push_back(rp.PopRaw<IPC::BufferDescriptorABW>()); |
| 194 | } | 194 | } |
| 195 | for (u32 i = 0; i < command_header->num_buf_b_descriptors; ++i) { | 195 | for (u32 i = 0; i < command_header->num_buf_b_descriptors; ++i) { |
| 196 | buffer_b_desciptors.push_back(rp.PopRaw<IPC::BufferDescriptorABW>()); | 196 | buffer_b_descriptors.push_back(rp.PopRaw<IPC::BufferDescriptorABW>()); |
| 197 | } | 197 | } |
| 198 | for (u32 i = 0; i < command_header->num_buf_w_descriptors; ++i) { | 198 | for (u32 i = 0; i < command_header->num_buf_w_descriptors; ++i) { |
| 199 | buffer_w_desciptors.push_back(rp.PopRaw<IPC::BufferDescriptorABW>()); | 199 | buffer_w_descriptors.push_back(rp.PopRaw<IPC::BufferDescriptorABW>()); |
| 200 | } | 200 | } |
| 201 | 201 | ||
| 202 | const auto buffer_c_offset = rp.GetCurrentOffset() + command_header->data_size; | 202 | const auto buffer_c_offset = rp.GetCurrentOffset() + command_header->data_size; |
| @@ -246,7 +246,7 @@ void HLERequestContext::ParseCommandBuffer(u32_le* src_cmdbuf, bool incoming) { | |||
| 246 | IPC::CommandHeader::BufferDescriptorCFlag::InlineDescriptor) { | 246 | IPC::CommandHeader::BufferDescriptorCFlag::InlineDescriptor) { |
| 247 | if (command_header->buf_c_descriptor_flags == | 247 | if (command_header->buf_c_descriptor_flags == |
| 248 | IPC::CommandHeader::BufferDescriptorCFlag::OneDescriptor) { | 248 | IPC::CommandHeader::BufferDescriptorCFlag::OneDescriptor) { |
| 249 | buffer_c_desciptors.push_back(rp.PopRaw<IPC::BufferDescriptorC>()); | 249 | buffer_c_descriptors.push_back(rp.PopRaw<IPC::BufferDescriptorC>()); |
| 250 | } else { | 250 | } else { |
| 251 | u32 num_buf_c_descriptors = | 251 | u32 num_buf_c_descriptors = |
| 252 | static_cast<u32>(command_header->buf_c_descriptor_flags.Value()) - 2; | 252 | static_cast<u32>(command_header->buf_c_descriptor_flags.Value()) - 2; |
| @@ -256,7 +256,7 @@ void HLERequestContext::ParseCommandBuffer(u32_le* src_cmdbuf, bool incoming) { | |||
| 256 | ASSERT(num_buf_c_descriptors < 14); | 256 | ASSERT(num_buf_c_descriptors < 14); |
| 257 | 257 | ||
| 258 | for (u32 i = 0; i < num_buf_c_descriptors; ++i) { | 258 | for (u32 i = 0; i < num_buf_c_descriptors; ++i) { |
| 259 | buffer_c_desciptors.push_back(rp.PopRaw<IPC::BufferDescriptorC>()); | 259 | buffer_c_descriptors.push_back(rp.PopRaw<IPC::BufferDescriptorC>()); |
| 260 | } | 260 | } |
| 261 | } | 261 | } |
| 262 | } | 262 | } |
diff --git a/src/core/hle/service/hle_ipc.h b/src/core/hle/service/hle_ipc.h index 40d86943e..440737db5 100644 --- a/src/core/hle/service/hle_ipc.h +++ b/src/core/hle/service/hle_ipc.h | |||
| @@ -232,19 +232,19 @@ public: | |||
| 232 | } | 232 | } |
| 233 | 233 | ||
| 234 | [[nodiscard]] const std::vector<IPC::BufferDescriptorX>& BufferDescriptorX() const { | 234 | [[nodiscard]] const std::vector<IPC::BufferDescriptorX>& BufferDescriptorX() const { |
| 235 | return buffer_x_desciptors; | 235 | return buffer_x_descriptors; |
| 236 | } | 236 | } |
| 237 | 237 | ||
| 238 | [[nodiscard]] const std::vector<IPC::BufferDescriptorABW>& BufferDescriptorA() const { | 238 | [[nodiscard]] const std::vector<IPC::BufferDescriptorABW>& BufferDescriptorA() const { |
| 239 | return buffer_a_desciptors; | 239 | return buffer_a_descriptors; |
| 240 | } | 240 | } |
| 241 | 241 | ||
| 242 | [[nodiscard]] const std::vector<IPC::BufferDescriptorABW>& BufferDescriptorB() const { | 242 | [[nodiscard]] const std::vector<IPC::BufferDescriptorABW>& BufferDescriptorB() const { |
| 243 | return buffer_b_desciptors; | 243 | return buffer_b_descriptors; |
| 244 | } | 244 | } |
| 245 | 245 | ||
| 246 | [[nodiscard]] const std::vector<IPC::BufferDescriptorC>& BufferDescriptorC() const { | 246 | [[nodiscard]] const std::vector<IPC::BufferDescriptorC>& BufferDescriptorC() const { |
| 247 | return buffer_c_desciptors; | 247 | return buffer_c_descriptors; |
| 248 | } | 248 | } |
| 249 | 249 | ||
| 250 | [[nodiscard]] const IPC::DomainMessageHeader& GetDomainMessageHeader() const { | 250 | [[nodiscard]] const IPC::DomainMessageHeader& GetDomainMessageHeader() const { |
| @@ -406,11 +406,11 @@ private: | |||
| 406 | std::optional<IPC::HandleDescriptorHeader> handle_descriptor_header; | 406 | std::optional<IPC::HandleDescriptorHeader> handle_descriptor_header; |
| 407 | std::optional<IPC::DataPayloadHeader> data_payload_header; | 407 | std::optional<IPC::DataPayloadHeader> data_payload_header; |
| 408 | std::optional<IPC::DomainMessageHeader> domain_message_header; | 408 | std::optional<IPC::DomainMessageHeader> domain_message_header; |
| 409 | std::vector<IPC::BufferDescriptorX> buffer_x_desciptors; | 409 | std::vector<IPC::BufferDescriptorX> buffer_x_descriptors; |
| 410 | std::vector<IPC::BufferDescriptorABW> buffer_a_desciptors; | 410 | std::vector<IPC::BufferDescriptorABW> buffer_a_descriptors; |
| 411 | std::vector<IPC::BufferDescriptorABW> buffer_b_desciptors; | 411 | std::vector<IPC::BufferDescriptorABW> buffer_b_descriptors; |
| 412 | std::vector<IPC::BufferDescriptorABW> buffer_w_desciptors; | 412 | std::vector<IPC::BufferDescriptorABW> buffer_w_descriptors; |
| 413 | std::vector<IPC::BufferDescriptorC> buffer_c_desciptors; | 413 | std::vector<IPC::BufferDescriptorC> buffer_c_descriptors; |
| 414 | 414 | ||
| 415 | u32_le command{}; | 415 | u32_le command{}; |
| 416 | u64 pid{}; | 416 | u64 pid{}; |
diff --git a/src/core/hle/service/nfc/common/amiibo_crypto.cpp b/src/core/hle/service/nfc/common/amiibo_crypto.cpp index 9556e9193..4274a92c9 100644 --- a/src/core/hle/service/nfc/common/amiibo_crypto.cpp +++ b/src/core/hle/service/nfc/common/amiibo_crypto.cpp | |||
| @@ -19,7 +19,7 @@ namespace Service::NFP::AmiiboCrypto { | |||
| 19 | bool IsAmiiboValid(const EncryptedNTAG215File& ntag_file) { | 19 | bool IsAmiiboValid(const EncryptedNTAG215File& ntag_file) { |
| 20 | const auto& amiibo_data = ntag_file.user_memory; | 20 | const auto& amiibo_data = ntag_file.user_memory; |
| 21 | LOG_DEBUG(Service_NFP, "uuid_lock=0x{0:x}", ntag_file.static_lock); | 21 | LOG_DEBUG(Service_NFP, "uuid_lock=0x{0:x}", ntag_file.static_lock); |
| 22 | LOG_DEBUG(Service_NFP, "compability_container=0x{0:x}", ntag_file.compability_container); | 22 | LOG_DEBUG(Service_NFP, "compatibility_container=0x{0:x}", ntag_file.compatibility_container); |
| 23 | LOG_DEBUG(Service_NFP, "write_count={}", static_cast<u16>(amiibo_data.write_counter)); | 23 | LOG_DEBUG(Service_NFP, "write_count={}", static_cast<u16>(amiibo_data.write_counter)); |
| 24 | 24 | ||
| 25 | LOG_DEBUG(Service_NFP, "character_id=0x{0:x}", amiibo_data.model_info.character_id); | 25 | LOG_DEBUG(Service_NFP, "character_id=0x{0:x}", amiibo_data.model_info.character_id); |
| @@ -49,7 +49,7 @@ bool IsAmiiboValid(const EncryptedNTAG215File& ntag_file) { | |||
| 49 | if (ntag_file.static_lock != 0xE00F) { | 49 | if (ntag_file.static_lock != 0xE00F) { |
| 50 | return false; | 50 | return false; |
| 51 | } | 51 | } |
| 52 | if (ntag_file.compability_container != 0xEEFF10F1U) { | 52 | if (ntag_file.compatibility_container != 0xEEFF10F1U) { |
| 53 | return false; | 53 | return false; |
| 54 | } | 54 | } |
| 55 | if (amiibo_data.model_info.tag_type != NFC::PackedTagType::Type2) { | 55 | if (amiibo_data.model_info.tag_type != NFC::PackedTagType::Type2) { |
| @@ -78,7 +78,7 @@ NTAG215File NfcDataToEncodedData(const EncryptedNTAG215File& nfc_data) { | |||
| 78 | encoded_data.uid_crc_check2 = nfc_data.uuid_crc_check2; | 78 | encoded_data.uid_crc_check2 = nfc_data.uuid_crc_check2; |
| 79 | encoded_data.internal_number = nfc_data.internal_number; | 79 | encoded_data.internal_number = nfc_data.internal_number; |
| 80 | encoded_data.static_lock = nfc_data.static_lock; | 80 | encoded_data.static_lock = nfc_data.static_lock; |
| 81 | encoded_data.compability_container = nfc_data.compability_container; | 81 | encoded_data.compatibility_container = nfc_data.compatibility_container; |
| 82 | encoded_data.hmac_data = nfc_data.user_memory.hmac_data; | 82 | encoded_data.hmac_data = nfc_data.user_memory.hmac_data; |
| 83 | encoded_data.constant_value = nfc_data.user_memory.constant_value; | 83 | encoded_data.constant_value = nfc_data.user_memory.constant_value; |
| 84 | encoded_data.write_counter = nfc_data.user_memory.write_counter; | 84 | encoded_data.write_counter = nfc_data.user_memory.write_counter; |
| @@ -112,7 +112,7 @@ EncryptedNTAG215File EncodedDataToNfcData(const NTAG215File& encoded_data) { | |||
| 112 | nfc_data.uuid_crc_check2 = encoded_data.uid_crc_check2; | 112 | nfc_data.uuid_crc_check2 = encoded_data.uid_crc_check2; |
| 113 | nfc_data.internal_number = encoded_data.internal_number; | 113 | nfc_data.internal_number = encoded_data.internal_number; |
| 114 | nfc_data.static_lock = encoded_data.static_lock; | 114 | nfc_data.static_lock = encoded_data.static_lock; |
| 115 | nfc_data.compability_container = encoded_data.compability_container; | 115 | nfc_data.compatibility_container = encoded_data.compatibility_container; |
| 116 | nfc_data.user_memory.hmac_data = encoded_data.hmac_data; | 116 | nfc_data.user_memory.hmac_data = encoded_data.hmac_data; |
| 117 | nfc_data.user_memory.constant_value = encoded_data.constant_value; | 117 | nfc_data.user_memory.constant_value = encoded_data.constant_value; |
| 118 | nfc_data.user_memory.write_counter = encoded_data.write_counter; | 118 | nfc_data.user_memory.write_counter = encoded_data.write_counter; |
| @@ -257,7 +257,7 @@ void Cipher(const DerivedKeys& keys, const NTAG215File& in_data, NTAG215File& ou | |||
| 257 | out_data.uid_crc_check2 = in_data.uid_crc_check2; | 257 | out_data.uid_crc_check2 = in_data.uid_crc_check2; |
| 258 | out_data.internal_number = in_data.internal_number; | 258 | out_data.internal_number = in_data.internal_number; |
| 259 | out_data.static_lock = in_data.static_lock; | 259 | out_data.static_lock = in_data.static_lock; |
| 260 | out_data.compability_container = in_data.compability_container; | 260 | out_data.compatibility_container = in_data.compatibility_container; |
| 261 | 261 | ||
| 262 | out_data.constant_value = in_data.constant_value; | 262 | out_data.constant_value = in_data.constant_value; |
| 263 | out_data.write_counter = in_data.write_counter; | 263 | out_data.write_counter = in_data.write_counter; |
diff --git a/src/core/hle/service/nfc/common/device.cpp b/src/core/hle/service/nfc/common/device.cpp index b37fb6da3..31cc87acc 100644 --- a/src/core/hle/service/nfc/common/device.cpp +++ b/src/core/hle/service/nfc/common/device.cpp | |||
| @@ -75,7 +75,7 @@ void NfcDevice::NpadUpdate(Core::HID::ControllerTriggerType type) { | |||
| 75 | return; | 75 | return; |
| 76 | } | 76 | } |
| 77 | 77 | ||
| 78 | if (!is_initalized) { | 78 | if (!is_initialized) { |
| 79 | return; | 79 | return; |
| 80 | } | 80 | } |
| 81 | 81 | ||
| @@ -207,7 +207,7 @@ void NfcDevice::Initialize() { | |||
| 207 | return; | 207 | return; |
| 208 | } | 208 | } |
| 209 | 209 | ||
| 210 | is_initalized = npad_device->AddNfcHandle(); | 210 | is_initialized = npad_device->AddNfcHandle(); |
| 211 | } | 211 | } |
| 212 | 212 | ||
| 213 | void NfcDevice::Finalize() { | 213 | void NfcDevice::Finalize() { |
| @@ -226,7 +226,7 @@ void NfcDevice::Finalize() { | |||
| 226 | } | 226 | } |
| 227 | 227 | ||
| 228 | device_state = DeviceState::Unavailable; | 228 | device_state = DeviceState::Unavailable; |
| 229 | is_initalized = false; | 229 | is_initialized = false; |
| 230 | } | 230 | } |
| 231 | 231 | ||
| 232 | Result NfcDevice::StartDetection(NfcProtocol allowed_protocol) { | 232 | Result NfcDevice::StartDetection(NfcProtocol allowed_protocol) { |
diff --git a/src/core/hle/service/nfc/common/device.h b/src/core/hle/service/nfc/common/device.h index d8efe25ec..15f9b25da 100644 --- a/src/core/hle/service/nfc/common/device.h +++ b/src/core/hle/service/nfc/common/device.h | |||
| @@ -126,7 +126,7 @@ private: | |||
| 126 | Kernel::KEvent* deactivate_event = nullptr; | 126 | Kernel::KEvent* deactivate_event = nullptr; |
| 127 | Kernel::KEvent* availability_change_event = nullptr; | 127 | Kernel::KEvent* availability_change_event = nullptr; |
| 128 | 128 | ||
| 129 | bool is_initalized{}; | 129 | bool is_initialized{}; |
| 130 | NfcProtocol allowed_protocols{}; | 130 | NfcProtocol allowed_protocols{}; |
| 131 | DeviceState device_state{DeviceState::Unavailable}; | 131 | DeviceState device_state{DeviceState::Unavailable}; |
| 132 | 132 | ||
diff --git a/src/core/hle/service/nfp/nfp_types.h b/src/core/hle/service/nfp/nfp_types.h index f96d21220..2505eb551 100644 --- a/src/core/hle/service/nfp/nfp_types.h +++ b/src/core/hle/service/nfp/nfp_types.h | |||
| @@ -243,12 +243,12 @@ static_assert(sizeof(EncryptedAmiiboFile) == 0x1F8, "AmiiboFile is an invalid si | |||
| 243 | struct NTAG215File { | 243 | struct NTAG215File { |
| 244 | u8 uid_crc_check2; | 244 | u8 uid_crc_check2; |
| 245 | u8 internal_number; | 245 | u8 internal_number; |
| 246 | u16 static_lock; // Set defined pages as read only | 246 | u16 static_lock; // Set defined pages as read only |
| 247 | u32 compability_container; // Defines available memory | 247 | u32 compatibility_container; // Defines available memory |
| 248 | HashData hmac_data; // Hash | 248 | HashData hmac_data; // Hash |
| 249 | u8 constant_value; // Must be A5 | 249 | u8 constant_value; // Must be A5 |
| 250 | u16_be write_counter; // Number of times the amiibo has been written? | 250 | u16_be write_counter; // Number of times the amiibo has been written? |
| 251 | u8 amiibo_version; // Amiibo file version | 251 | u8 amiibo_version; // Amiibo file version |
| 252 | AmiiboSettings settings; | 252 | AmiiboSettings settings; |
| 253 | Service::Mii::Ver3StoreData owner_mii; // Mii data | 253 | Service::Mii::Ver3StoreData owner_mii; // Mii data |
| 254 | u64_be application_id; // Game id | 254 | u64_be application_id; // Game id |
| @@ -278,7 +278,7 @@ struct EncryptedNTAG215File { | |||
| 278 | u8 uuid_crc_check2; | 278 | u8 uuid_crc_check2; |
| 279 | u8 internal_number; | 279 | u8 internal_number; |
| 280 | u16 static_lock; // Set defined pages as read only | 280 | u16 static_lock; // Set defined pages as read only |
| 281 | u32 compability_container; // Defines available memory | 281 | u32 compatibility_container; // Defines available memory |
| 282 | EncryptedAmiiboFile user_memory; // Writable data | 282 | EncryptedAmiiboFile user_memory; // Writable data |
| 283 | u32 dynamic_lock; // Dynamic lock | 283 | u32 dynamic_lock; // Dynamic lock |
| 284 | u32 CFG0; // Defines memory protected by password | 284 | u32 CFG0; // Defines memory protected by password |
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h index 932997e75..79a21683d 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h | |||
| @@ -90,7 +90,7 @@ private: | |||
| 90 | u64_le align; | 90 | u64_le align; |
| 91 | }; | 91 | }; |
| 92 | }; | 92 | }; |
| 93 | static_assert(sizeof(IoctlAllocSpace) == 24, "IoctlInitalizeEx is incorrect size"); | 93 | static_assert(sizeof(IoctlAllocSpace) == 24, "IoctlInitializeEx is incorrect size"); |
| 94 | 94 | ||
| 95 | struct IoctlFreeSpace { | 95 | struct IoctlFreeSpace { |
| 96 | u64_le offset{}; | 96 | u64_le offset{}; |
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp index 61a2df121..3e0c96456 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp | |||
| @@ -15,7 +15,7 @@ namespace Service::Nvidia::Devices { | |||
| 15 | nvhost_ctrl_gpu::nvhost_ctrl_gpu(Core::System& system_, EventInterface& events_interface_) | 15 | nvhost_ctrl_gpu::nvhost_ctrl_gpu(Core::System& system_, EventInterface& events_interface_) |
| 16 | : nvdevice{system_}, events_interface{events_interface_} { | 16 | : nvdevice{system_}, events_interface{events_interface_} { |
| 17 | error_notifier_event = events_interface.CreateEvent("CtrlGpuErrorNotifier"); | 17 | error_notifier_event = events_interface.CreateEvent("CtrlGpuErrorNotifier"); |
| 18 | unknown_event = events_interface.CreateEvent("CtrlGpuUknownEvent"); | 18 | unknown_event = events_interface.CreateEvent("CtrlGpuUnknownEvent"); |
| 19 | } | 19 | } |
| 20 | nvhost_ctrl_gpu::~nvhost_ctrl_gpu() { | 20 | nvhost_ctrl_gpu::~nvhost_ctrl_gpu() { |
| 21 | events_interface.FreeEvent(error_notifier_event); | 21 | events_interface.FreeEvent(error_notifier_event); |
diff --git a/src/core/hle/service/nvdrv/nvdata.h b/src/core/hle/service/nvdrv/nvdata.h index 0e2f47075..38f35e79f 100644 --- a/src/core/hle/service/nvdrv/nvdata.h +++ b/src/core/hle/service/nvdrv/nvdata.h | |||
| @@ -51,7 +51,7 @@ enum class NvResult : u32 { | |||
| 51 | DispNoDisplaysAttached = 0x20003, | 51 | DispNoDisplaysAttached = 0x20003, |
| 52 | DispModeNotSupported = 0x20004, | 52 | DispModeNotSupported = 0x20004, |
| 53 | DispNotFound = 0x20005, | 53 | DispNotFound = 0x20005, |
| 54 | DispAttachDissallowed = 0x20006, | 54 | DispAttachDisallowed = 0x20006, |
| 55 | DispTypeNotSupported = 0x20007, | 55 | DispTypeNotSupported = 0x20007, |
| 56 | DispAuthenticationFailed = 0x20008, | 56 | DispAuthenticationFailed = 0x20008, |
| 57 | DispNotAttached = 0x20009, | 57 | DispNotAttached = 0x20009, |
diff --git a/src/core/hle/service/nvnflinger/nvnflinger.cpp b/src/core/hle/service/nvnflinger/nvnflinger.cpp index aa8aaa2d9..0469110e8 100644 --- a/src/core/hle/service/nvnflinger/nvnflinger.cpp +++ b/src/core/hle/service/nvnflinger/nvnflinger.cpp | |||
| @@ -223,7 +223,8 @@ Result Nvnflinger::FindVsyncEvent(Kernel::KReadableEvent** out_vsync_event, u64 | |||
| 223 | return VI::ResultNotFound; | 223 | return VI::ResultNotFound; |
| 224 | } | 224 | } |
| 225 | 225 | ||
| 226 | return display->GetVSyncEvent(out_vsync_event); | 226 | *out_vsync_event = display->GetVSyncEvent(); |
| 227 | return ResultSuccess; | ||
| 227 | } | 228 | } |
| 228 | 229 | ||
| 229 | VI::Display* Nvnflinger::FindDisplay(u64 display_id) { | 230 | VI::Display* Nvnflinger::FindDisplay(u64 display_id) { |
diff --git a/src/core/hle/service/pcv/pcv.cpp b/src/core/hle/service/pcv/pcv.cpp index c13ffa6f6..3d0f2aeb7 100644 --- a/src/core/hle/service/pcv/pcv.cpp +++ b/src/core/hle/service/pcv/pcv.cpp | |||
| @@ -54,8 +54,8 @@ public: | |||
| 54 | 54 | ||
| 55 | class IClkrstSession final : public ServiceFramework<IClkrstSession> { | 55 | class IClkrstSession final : public ServiceFramework<IClkrstSession> { |
| 56 | public: | 56 | public: |
| 57 | explicit IClkrstSession(Core::System& system_, DeviceCode deivce_code_) | 57 | explicit IClkrstSession(Core::System& system_, DeviceCode device_code_) |
| 58 | : ServiceFramework{system_, "IClkrstSession"}, deivce_code(deivce_code_) { | 58 | : ServiceFramework{system_, "IClkrstSession"}, device_code(device_code_) { |
| 59 | // clang-format off | 59 | // clang-format off |
| 60 | static const FunctionInfo functions[] = { | 60 | static const FunctionInfo functions[] = { |
| 61 | {0, nullptr, "SetClockEnabled"}, | 61 | {0, nullptr, "SetClockEnabled"}, |
| @@ -93,7 +93,7 @@ private: | |||
| 93 | rb.Push<u32>(clock_rate); | 93 | rb.Push<u32>(clock_rate); |
| 94 | } | 94 | } |
| 95 | 95 | ||
| 96 | DeviceCode deivce_code; | 96 | DeviceCode device_code; |
| 97 | u32 clock_rate{}; | 97 | u32 clock_rate{}; |
| 98 | }; | 98 | }; |
| 99 | 99 | ||
| @@ -118,9 +118,9 @@ private: | |||
| 118 | void OpenSession(HLERequestContext& ctx) { | 118 | void OpenSession(HLERequestContext& ctx) { |
| 119 | IPC::RequestParser rp{ctx}; | 119 | IPC::RequestParser rp{ctx}; |
| 120 | const auto device_code = static_cast<DeviceCode>(rp.Pop<u32>()); | 120 | const auto device_code = static_cast<DeviceCode>(rp.Pop<u32>()); |
| 121 | const auto unkonwn_input = rp.Pop<u32>(); | 121 | const auto unknown_input = rp.Pop<u32>(); |
| 122 | 122 | ||
| 123 | LOG_DEBUG(Service_PCV, "called, device_code={}, input={}", device_code, unkonwn_input); | 123 | LOG_DEBUG(Service_PCV, "called, device_code={}, input={}", device_code, unknown_input); |
| 124 | 124 | ||
| 125 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 125 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 126 | rb.Push(ResultSuccess); | 126 | rb.Push(ResultSuccess); |
diff --git a/src/core/hle/service/pm/pm.cpp b/src/core/hle/service/pm/pm.cpp index d92499f05..b52468e41 100644 --- a/src/core/hle/service/pm/pm.cpp +++ b/src/core/hle/service/pm/pm.cpp | |||
| @@ -22,27 +22,26 @@ constexpr Result ResultProcessNotFound{ErrorModule::PM, 1}; | |||
| 22 | 22 | ||
| 23 | constexpr u64 NO_PROCESS_FOUND_PID{0}; | 23 | constexpr u64 NO_PROCESS_FOUND_PID{0}; |
| 24 | 24 | ||
| 25 | std::optional<Kernel::KProcess*> SearchProcessList( | 25 | using ProcessList = std::list<Kernel::KScopedAutoObject<Kernel::KProcess>>; |
| 26 | const std::vector<Kernel::KProcess*>& process_list, | 26 | |
| 27 | std::function<bool(Kernel::KProcess*)> predicate) { | 27 | template <typename F> |
| 28 | Kernel::KScopedAutoObject<Kernel::KProcess> SearchProcessList(ProcessList& process_list, | ||
| 29 | F&& predicate) { | ||
| 28 | const auto iter = std::find_if(process_list.begin(), process_list.end(), predicate); | 30 | const auto iter = std::find_if(process_list.begin(), process_list.end(), predicate); |
| 29 | 31 | ||
| 30 | if (iter == process_list.end()) { | 32 | if (iter == process_list.end()) { |
| 31 | return std::nullopt; | 33 | return nullptr; |
| 32 | } | 34 | } |
| 33 | 35 | ||
| 34 | return *iter; | 36 | return iter->GetPointerUnsafe(); |
| 35 | } | 37 | } |
| 36 | 38 | ||
| 37 | void GetApplicationPidGeneric(HLERequestContext& ctx, | 39 | void GetApplicationPidGeneric(HLERequestContext& ctx, ProcessList& process_list) { |
| 38 | const std::vector<Kernel::KProcess*>& process_list) { | 40 | auto process = SearchProcessList(process_list, [](auto& p) { return p->IsApplication(); }); |
| 39 | const auto process = SearchProcessList(process_list, [](const auto& proc) { | ||
| 40 | return proc->GetProcessId() == Kernel::KProcess::ProcessIdMin; | ||
| 41 | }); | ||
| 42 | 41 | ||
| 43 | IPC::ResponseBuilder rb{ctx, 4}; | 42 | IPC::ResponseBuilder rb{ctx, 4}; |
| 44 | rb.Push(ResultSuccess); | 43 | rb.Push(ResultSuccess); |
| 45 | rb.Push(process.has_value() ? (*process)->GetProcessId() : NO_PROCESS_FOUND_PID); | 44 | rb.Push(process.IsNull() ? NO_PROCESS_FOUND_PID : process->GetProcessId()); |
| 46 | } | 45 | } |
| 47 | 46 | ||
| 48 | } // Anonymous namespace | 47 | } // Anonymous namespace |
| @@ -80,8 +79,7 @@ private: | |||
| 80 | 79 | ||
| 81 | class DebugMonitor final : public ServiceFramework<DebugMonitor> { | 80 | class DebugMonitor final : public ServiceFramework<DebugMonitor> { |
| 82 | public: | 81 | public: |
| 83 | explicit DebugMonitor(Core::System& system_) | 82 | explicit DebugMonitor(Core::System& system_) : ServiceFramework{system_, "pm:dmnt"} { |
| 84 | : ServiceFramework{system_, "pm:dmnt"}, kernel{system_.Kernel()} { | ||
| 85 | // clang-format off | 83 | // clang-format off |
| 86 | static const FunctionInfo functions[] = { | 84 | static const FunctionInfo functions[] = { |
| 87 | {0, nullptr, "GetJitDebugProcessIdList"}, | 85 | {0, nullptr, "GetJitDebugProcessIdList"}, |
| @@ -106,12 +104,11 @@ private: | |||
| 106 | 104 | ||
| 107 | LOG_DEBUG(Service_PM, "called, program_id={:016X}", program_id); | 105 | LOG_DEBUG(Service_PM, "called, program_id={:016X}", program_id); |
| 108 | 106 | ||
| 109 | const auto process = | 107 | auto list = kernel.GetProcessList(); |
| 110 | SearchProcessList(kernel.GetProcessList(), [program_id](const auto& proc) { | 108 | auto process = SearchProcessList( |
| 111 | return proc->GetProgramId() == program_id; | 109 | list, [program_id](auto& p) { return p->GetProgramId() == program_id; }); |
| 112 | }); | ||
| 113 | 110 | ||
| 114 | if (!process.has_value()) { | 111 | if (process.IsNull()) { |
| 115 | IPC::ResponseBuilder rb{ctx, 2}; | 112 | IPC::ResponseBuilder rb{ctx, 2}; |
| 116 | rb.Push(ResultProcessNotFound); | 113 | rb.Push(ResultProcessNotFound); |
| 117 | return; | 114 | return; |
| @@ -119,12 +116,13 @@ private: | |||
| 119 | 116 | ||
| 120 | IPC::ResponseBuilder rb{ctx, 4}; | 117 | IPC::ResponseBuilder rb{ctx, 4}; |
| 121 | rb.Push(ResultSuccess); | 118 | rb.Push(ResultSuccess); |
| 122 | rb.Push((*process)->GetProcessId()); | 119 | rb.Push(process->GetProcessId()); |
| 123 | } | 120 | } |
| 124 | 121 | ||
| 125 | void GetApplicationProcessId(HLERequestContext& ctx) { | 122 | void GetApplicationProcessId(HLERequestContext& ctx) { |
| 126 | LOG_DEBUG(Service_PM, "called"); | 123 | LOG_DEBUG(Service_PM, "called"); |
| 127 | GetApplicationPidGeneric(ctx, kernel.GetProcessList()); | 124 | auto list = kernel.GetProcessList(); |
| 125 | GetApplicationPidGeneric(ctx, list); | ||
| 128 | } | 126 | } |
| 129 | 127 | ||
| 130 | void AtmosphereGetProcessInfo(HLERequestContext& ctx) { | 128 | void AtmosphereGetProcessInfo(HLERequestContext& ctx) { |
| @@ -135,11 +133,10 @@ private: | |||
| 135 | 133 | ||
| 136 | LOG_WARNING(Service_PM, "(Partial Implementation) called, pid={:016X}", pid); | 134 | LOG_WARNING(Service_PM, "(Partial Implementation) called, pid={:016X}", pid); |
| 137 | 135 | ||
| 138 | const auto process = SearchProcessList(kernel.GetProcessList(), [pid](const auto& proc) { | 136 | auto list = kernel.GetProcessList(); |
| 139 | return proc->GetProcessId() == pid; | 137 | auto process = SearchProcessList(list, [pid](auto& p) { return p->GetProcessId() == pid; }); |
| 140 | }); | ||
| 141 | 138 | ||
| 142 | if (!process.has_value()) { | 139 | if (process.IsNull()) { |
| 143 | IPC::ResponseBuilder rb{ctx, 2}; | 140 | IPC::ResponseBuilder rb{ctx, 2}; |
| 144 | rb.Push(ResultProcessNotFound); | 141 | rb.Push(ResultProcessNotFound); |
| 145 | return; | 142 | return; |
| @@ -159,7 +156,7 @@ private: | |||
| 159 | 156 | ||
| 160 | OverrideStatus override_status{}; | 157 | OverrideStatus override_status{}; |
| 161 | ProgramLocation program_location{ | 158 | ProgramLocation program_location{ |
| 162 | .program_id = (*process)->GetProgramId(), | 159 | .program_id = process->GetProgramId(), |
| 163 | .storage_id = 0, | 160 | .storage_id = 0, |
| 164 | }; | 161 | }; |
| 165 | 162 | ||
| @@ -169,14 +166,11 @@ private: | |||
| 169 | rb.PushRaw(program_location); | 166 | rb.PushRaw(program_location); |
| 170 | rb.PushRaw(override_status); | 167 | rb.PushRaw(override_status); |
| 171 | } | 168 | } |
| 172 | |||
| 173 | const Kernel::KernelCore& kernel; | ||
| 174 | }; | 169 | }; |
| 175 | 170 | ||
| 176 | class Info final : public ServiceFramework<Info> { | 171 | class Info final : public ServiceFramework<Info> { |
| 177 | public: | 172 | public: |
| 178 | explicit Info(Core::System& system_, const std::vector<Kernel::KProcess*>& process_list_) | 173 | explicit Info(Core::System& system_) : ServiceFramework{system_, "pm:info"} { |
| 179 | : ServiceFramework{system_, "pm:info"}, process_list{process_list_} { | ||
| 180 | static const FunctionInfo functions[] = { | 174 | static const FunctionInfo functions[] = { |
| 181 | {0, &Info::GetProgramId, "GetProgramId"}, | 175 | {0, &Info::GetProgramId, "GetProgramId"}, |
| 182 | {65000, &Info::AtmosphereGetProcessId, "AtmosphereGetProcessId"}, | 176 | {65000, &Info::AtmosphereGetProcessId, "AtmosphereGetProcessId"}, |
| @@ -193,11 +187,11 @@ private: | |||
| 193 | 187 | ||
| 194 | LOG_DEBUG(Service_PM, "called, process_id={:016X}", process_id); | 188 | LOG_DEBUG(Service_PM, "called, process_id={:016X}", process_id); |
| 195 | 189 | ||
| 196 | const auto process = SearchProcessList(process_list, [process_id](const auto& proc) { | 190 | auto list = kernel.GetProcessList(); |
| 197 | return proc->GetProcessId() == process_id; | 191 | auto process = SearchProcessList( |
| 198 | }); | 192 | list, [process_id](auto& p) { return p->GetProcessId() == process_id; }); |
| 199 | 193 | ||
| 200 | if (!process.has_value()) { | 194 | if (process.IsNull()) { |
| 201 | IPC::ResponseBuilder rb{ctx, 2}; | 195 | IPC::ResponseBuilder rb{ctx, 2}; |
| 202 | rb.Push(ResultProcessNotFound); | 196 | rb.Push(ResultProcessNotFound); |
| 203 | return; | 197 | return; |
| @@ -205,7 +199,7 @@ private: | |||
| 205 | 199 | ||
| 206 | IPC::ResponseBuilder rb{ctx, 4}; | 200 | IPC::ResponseBuilder rb{ctx, 4}; |
| 207 | rb.Push(ResultSuccess); | 201 | rb.Push(ResultSuccess); |
| 208 | rb.Push((*process)->GetProgramId()); | 202 | rb.Push(process->GetProgramId()); |
| 209 | } | 203 | } |
| 210 | 204 | ||
| 211 | void AtmosphereGetProcessId(HLERequestContext& ctx) { | 205 | void AtmosphereGetProcessId(HLERequestContext& ctx) { |
| @@ -214,11 +208,11 @@ private: | |||
| 214 | 208 | ||
| 215 | LOG_DEBUG(Service_PM, "called, program_id={:016X}", program_id); | 209 | LOG_DEBUG(Service_PM, "called, program_id={:016X}", program_id); |
| 216 | 210 | ||
| 217 | const auto process = SearchProcessList(process_list, [program_id](const auto& proc) { | 211 | auto list = system.Kernel().GetProcessList(); |
| 218 | return proc->GetProgramId() == program_id; | 212 | auto process = SearchProcessList( |
| 219 | }); | 213 | list, [program_id](auto& p) { return p->GetProgramId() == program_id; }); |
| 220 | 214 | ||
| 221 | if (!process.has_value()) { | 215 | if (process.IsNull()) { |
| 222 | IPC::ResponseBuilder rb{ctx, 2}; | 216 | IPC::ResponseBuilder rb{ctx, 2}; |
| 223 | rb.Push(ResultProcessNotFound); | 217 | rb.Push(ResultProcessNotFound); |
| 224 | return; | 218 | return; |
| @@ -226,16 +220,13 @@ private: | |||
| 226 | 220 | ||
| 227 | IPC::ResponseBuilder rb{ctx, 4}; | 221 | IPC::ResponseBuilder rb{ctx, 4}; |
| 228 | rb.Push(ResultSuccess); | 222 | rb.Push(ResultSuccess); |
| 229 | rb.Push((*process)->GetProcessId()); | 223 | rb.Push(process->GetProcessId()); |
| 230 | } | 224 | } |
| 231 | |||
| 232 | const std::vector<Kernel::KProcess*>& process_list; | ||
| 233 | }; | 225 | }; |
| 234 | 226 | ||
| 235 | class Shell final : public ServiceFramework<Shell> { | 227 | class Shell final : public ServiceFramework<Shell> { |
| 236 | public: | 228 | public: |
| 237 | explicit Shell(Core::System& system_) | 229 | explicit Shell(Core::System& system_) : ServiceFramework{system_, "pm:shell"} { |
| 238 | : ServiceFramework{system_, "pm:shell"}, kernel{system_.Kernel()} { | ||
| 239 | // clang-format off | 230 | // clang-format off |
| 240 | static const FunctionInfo functions[] = { | 231 | static const FunctionInfo functions[] = { |
| 241 | {0, nullptr, "LaunchProgram"}, | 232 | {0, nullptr, "LaunchProgram"}, |
| @@ -257,10 +248,9 @@ public: | |||
| 257 | private: | 248 | private: |
| 258 | void GetApplicationProcessIdForShell(HLERequestContext& ctx) { | 249 | void GetApplicationProcessIdForShell(HLERequestContext& ctx) { |
| 259 | LOG_DEBUG(Service_PM, "called"); | 250 | LOG_DEBUG(Service_PM, "called"); |
| 260 | GetApplicationPidGeneric(ctx, kernel.GetProcessList()); | 251 | auto list = kernel.GetProcessList(); |
| 252 | GetApplicationPidGeneric(ctx, list); | ||
| 261 | } | 253 | } |
| 262 | |||
| 263 | const Kernel::KernelCore& kernel; | ||
| 264 | }; | 254 | }; |
| 265 | 255 | ||
| 266 | void LoopProcess(Core::System& system) { | 256 | void LoopProcess(Core::System& system) { |
| @@ -268,8 +258,7 @@ void LoopProcess(Core::System& system) { | |||
| 268 | 258 | ||
| 269 | server_manager->RegisterNamedService("pm:bm", std::make_shared<BootMode>(system)); | 259 | server_manager->RegisterNamedService("pm:bm", std::make_shared<BootMode>(system)); |
| 270 | server_manager->RegisterNamedService("pm:dmnt", std::make_shared<DebugMonitor>(system)); | 260 | server_manager->RegisterNamedService("pm:dmnt", std::make_shared<DebugMonitor>(system)); |
| 271 | server_manager->RegisterNamedService( | 261 | server_manager->RegisterNamedService("pm:info", std::make_shared<Info>(system)); |
| 272 | "pm:info", std::make_shared<Info>(system, system.Kernel().GetProcessList())); | ||
| 273 | server_manager->RegisterNamedService("pm:shell", std::make_shared<Shell>(system)); | 262 | server_manager->RegisterNamedService("pm:shell", std::make_shared<Shell>(system)); |
| 274 | ServerManager::RunServer(std::move(server_manager)); | 263 | ServerManager::RunServer(std::move(server_manager)); |
| 275 | } | 264 | } |
diff --git a/src/core/hle/service/server_manager.cpp b/src/core/hle/service/server_manager.cpp index 15edb23e0..8ef49387d 100644 --- a/src/core/hle/service/server_manager.cpp +++ b/src/core/hle/service/server_manager.cpp | |||
| @@ -256,8 +256,13 @@ Result ServerManager::WaitAndProcessImpl() { | |||
| 256 | 256 | ||
| 257 | // Wait for a signal. | 257 | // Wait for a signal. |
| 258 | s32 out_index{-1}; | 258 | s32 out_index{-1}; |
| 259 | R_TRY(Kernel::KSynchronizationObject::Wait(m_system.Kernel(), &out_index, wait_objs.data(), | 259 | R_TRY_CATCH(Kernel::KSynchronizationObject::Wait(m_system.Kernel(), &out_index, |
| 260 | num_objs, -1)); | 260 | wait_objs.data(), num_objs, -1)) { |
| 261 | R_CATCH(Kernel::ResultSessionClosed) { | ||
| 262 | // On session closed, index is updated and we don't want to return an error. | ||
| 263 | } | ||
| 264 | } | ||
| 265 | R_END_TRY_CATCH; | ||
| 261 | ASSERT(out_index >= 0 && out_index < num_objs); | 266 | ASSERT(out_index >= 0 && out_index < num_objs); |
| 262 | 267 | ||
| 263 | // Set the output index. | 268 | // Set the output index. |
diff --git a/src/core/hle/service/set/system_settings.cpp b/src/core/hle/service/set/system_settings.cpp index 2723417ad..5977429b2 100644 --- a/src/core/hle/service/set/system_settings.cpp +++ b/src/core/hle/service/set/system_settings.cpp | |||
| @@ -28,7 +28,7 @@ SystemSettings DefaultSystemSettings() { | |||
| 28 | .cmu_mode = CmuMode::None, | 28 | .cmu_mode = CmuMode::None, |
| 29 | .tv_underscan = {}, | 29 | .tv_underscan = {}, |
| 30 | .tv_gama = 1.0f, | 30 | .tv_gama = 1.0f, |
| 31 | .constrast_ratio = 0.5f, | 31 | .contrast_ratio = 0.5f, |
| 32 | }; | 32 | }; |
| 33 | 33 | ||
| 34 | settings.initial_launch_settings_packed = { | 34 | settings.initial_launch_settings_packed = { |
diff --git a/src/core/hle/service/set/system_settings.h b/src/core/hle/service/set/system_settings.h index ded2906ad..6ec9e71e7 100644 --- a/src/core/hle/service/set/system_settings.h +++ b/src/core/hle/service/set/system_settings.h | |||
| @@ -208,7 +208,7 @@ struct TvSettings { | |||
| 208 | CmuMode cmu_mode; | 208 | CmuMode cmu_mode; |
| 209 | u32 tv_underscan; | 209 | u32 tv_underscan; |
| 210 | f32 tv_gama; | 210 | f32 tv_gama; |
| 211 | f32 constrast_ratio; | 211 | f32 contrast_ratio; |
| 212 | }; | 212 | }; |
| 213 | static_assert(sizeof(TvSettings) == 0x20, "TvSettings is an invalid size"); | 213 | static_assert(sizeof(TvSettings) == 0x20, "TvSettings is an invalid size"); |
| 214 | 214 | ||
| @@ -341,7 +341,7 @@ struct SystemSettings { | |||
| 341 | std::array<u8, 0x3C> reserved_09934; | 341 | std::array<u8, 0x3C> reserved_09934; |
| 342 | 342 | ||
| 343 | // nn::settings::system::ErrorReportSharePermission | 343 | // nn::settings::system::ErrorReportSharePermission |
| 344 | ErrorReportSharePermission error_report_share_permssion; | 344 | ErrorReportSharePermission error_report_share_permission; |
| 345 | 345 | ||
| 346 | std::array<u8, 0x3C> reserved_09974; | 346 | std::array<u8, 0x3C> reserved_09974; |
| 347 | 347 | ||
diff --git a/src/core/hle/service/set/system_settings_server.cpp b/src/core/hle/service/set/system_settings_server.cpp index f7ad6193e..af9348522 100644 --- a/src/core/hle/service/set/system_settings_server.cpp +++ b/src/core/hle/service/set/system_settings_server.cpp | |||
| @@ -721,10 +721,10 @@ void ISystemSettingsServer::SetTvSettings(HLERequestContext& ctx) { | |||
| 721 | SetSaveNeeded(); | 721 | SetSaveNeeded(); |
| 722 | 722 | ||
| 723 | LOG_INFO(Service_SET, | 723 | LOG_INFO(Service_SET, |
| 724 | "called, flags={}, cmu_mode={}, constrast_ratio={}, hdmi_content_type={}, " | 724 | "called, flags={}, cmu_mode={}, contrast_ratio={}, hdmi_content_type={}, " |
| 725 | "rgb_range={}, tv_gama={}, tv_resolution={}, tv_underscan={}", | 725 | "rgb_range={}, tv_gama={}, tv_resolution={}, tv_underscan={}", |
| 726 | m_system_settings.tv_settings.flags.raw, m_system_settings.tv_settings.cmu_mode, | 726 | m_system_settings.tv_settings.flags.raw, m_system_settings.tv_settings.cmu_mode, |
| 727 | m_system_settings.tv_settings.constrast_ratio, | 727 | m_system_settings.tv_settings.contrast_ratio, |
| 728 | m_system_settings.tv_settings.hdmi_content_type, | 728 | m_system_settings.tv_settings.hdmi_content_type, |
| 729 | m_system_settings.tv_settings.rgb_range, m_system_settings.tv_settings.tv_gama, | 729 | m_system_settings.tv_settings.rgb_range, m_system_settings.tv_settings.tv_gama, |
| 730 | m_system_settings.tv_settings.tv_resolution, | 730 | m_system_settings.tv_settings.tv_resolution, |
| @@ -870,10 +870,10 @@ void ISystemSettingsServer::GetInitialLaunchSettings(HLERequestContext& ctx) { | |||
| 870 | 870 | ||
| 871 | void ISystemSettingsServer::SetInitialLaunchSettings(HLERequestContext& ctx) { | 871 | void ISystemSettingsServer::SetInitialLaunchSettings(HLERequestContext& ctx) { |
| 872 | IPC::RequestParser rp{ctx}; | 872 | IPC::RequestParser rp{ctx}; |
| 873 | auto inital_launch_settings = rp.PopRaw<InitialLaunchSettings>(); | 873 | auto initial_launch_settings = rp.PopRaw<InitialLaunchSettings>(); |
| 874 | 874 | ||
| 875 | m_system_settings.initial_launch_settings_packed.flags = inital_launch_settings.flags; | 875 | m_system_settings.initial_launch_settings_packed.flags = initial_launch_settings.flags; |
| 876 | m_system_settings.initial_launch_settings_packed.timestamp = inital_launch_settings.timestamp; | 876 | m_system_settings.initial_launch_settings_packed.timestamp = initial_launch_settings.timestamp; |
| 877 | SetSaveNeeded(); | 877 | SetSaveNeeded(); |
| 878 | 878 | ||
| 879 | LOG_INFO(Service_SET, "called, flags={}, timestamp={}", | 879 | LOG_INFO(Service_SET, "called, flags={}, timestamp={}", |
diff --git a/src/core/hle/service/vi/display/vi_display.cpp b/src/core/hle/service/vi/display/vi_display.cpp index 71ce9be50..e2d9cd98a 100644 --- a/src/core/hle/service/vi/display/vi_display.cpp +++ b/src/core/hle/service/vi/display/vi_display.cpp | |||
| @@ -71,18 +71,7 @@ size_t Display::GetNumLayers() const { | |||
| 71 | return std::ranges::count_if(layers, [](auto& l) { return l->IsOpen(); }); | 71 | return std::ranges::count_if(layers, [](auto& l) { return l->IsOpen(); }); |
| 72 | } | 72 | } |
| 73 | 73 | ||
| 74 | Result Display::GetVSyncEvent(Kernel::KReadableEvent** out_vsync_event) { | 74 | Kernel::KReadableEvent* Display::GetVSyncEvent() { |
| 75 | if (got_vsync_event) { | ||
| 76 | return ResultPermissionDenied; | ||
| 77 | } | ||
| 78 | |||
| 79 | got_vsync_event = true; | ||
| 80 | |||
| 81 | *out_vsync_event = GetVSyncEventUnchecked(); | ||
| 82 | return ResultSuccess; | ||
| 83 | } | ||
| 84 | |||
| 85 | Kernel::KReadableEvent* Display::GetVSyncEventUnchecked() { | ||
| 86 | return &vsync_event->GetReadableEvent(); | 75 | return &vsync_event->GetReadableEvent(); |
| 87 | } | 76 | } |
| 88 | 77 | ||
diff --git a/src/core/hle/service/vi/display/vi_display.h b/src/core/hle/service/vi/display/vi_display.h index 1d9360b96..7e68ee79b 100644 --- a/src/core/hle/service/vi/display/vi_display.h +++ b/src/core/hle/service/vi/display/vi_display.h | |||
| @@ -74,16 +74,8 @@ public: | |||
| 74 | 74 | ||
| 75 | std::size_t GetNumLayers() const; | 75 | std::size_t GetNumLayers() const; |
| 76 | 76 | ||
| 77 | /** | ||
| 78 | * Gets the internal vsync event. | ||
| 79 | * | ||
| 80 | * @returns The internal Vsync event if it has not yet been retrieved, | ||
| 81 | * VI::ResultPermissionDenied otherwise. | ||
| 82 | */ | ||
| 83 | [[nodiscard]] Result GetVSyncEvent(Kernel::KReadableEvent** out_vsync_event); | ||
| 84 | |||
| 85 | /// Gets the internal vsync event. | 77 | /// Gets the internal vsync event. |
| 86 | Kernel::KReadableEvent* GetVSyncEventUnchecked(); | 78 | Kernel::KReadableEvent* GetVSyncEvent(); |
| 87 | 79 | ||
| 88 | /// Signals the internal vsync event. | 80 | /// Signals the internal vsync event. |
| 89 | void SignalVSyncEvent(); | 81 | void SignalVSyncEvent(); |
| @@ -104,7 +96,6 @@ public: | |||
| 104 | /// Resets the display for a new connection. | 96 | /// Resets the display for a new connection. |
| 105 | void Reset() { | 97 | void Reset() { |
| 106 | layers.clear(); | 98 | layers.clear(); |
| 107 | got_vsync_event = false; | ||
| 108 | } | 99 | } |
| 109 | 100 | ||
| 110 | /// Attempts to find a layer with the given ID. | 101 | /// Attempts to find a layer with the given ID. |
| @@ -133,7 +124,6 @@ private: | |||
| 133 | 124 | ||
| 134 | std::vector<std::unique_ptr<Layer>> layers; | 125 | std::vector<std::unique_ptr<Layer>> layers; |
| 135 | Kernel::KEvent* vsync_event{}; | 126 | Kernel::KEvent* vsync_event{}; |
| 136 | bool got_vsync_event{false}; | ||
| 137 | }; | 127 | }; |
| 138 | 128 | ||
| 139 | } // namespace Service::VI | 129 | } // namespace Service::VI |
diff --git a/src/core/hle/service/vi/vi.cpp b/src/core/hle/service/vi/vi.cpp index 9ab8788e3..39d5be90d 100644 --- a/src/core/hle/service/vi/vi.cpp +++ b/src/core/hle/service/vi/vi.cpp | |||
| @@ -343,8 +343,8 @@ private: | |||
| 343 | 343 | ||
| 344 | class IManagerDisplayService final : public ServiceFramework<IManagerDisplayService> { | 344 | class IManagerDisplayService final : public ServiceFramework<IManagerDisplayService> { |
| 345 | public: | 345 | public: |
| 346 | explicit IManagerDisplayService(Core::System& system_, Nvnflinger::Nvnflinger& nv_flinger_) | 346 | explicit IManagerDisplayService(Core::System& system_, Nvnflinger::Nvnflinger& nvnflinger_) |
| 347 | : ServiceFramework{system_, "IManagerDisplayService"}, nv_flinger{nv_flinger_} { | 347 | : ServiceFramework{system_, "IManagerDisplayService"}, nvnflinger{nvnflinger_} { |
| 348 | // clang-format off | 348 | // clang-format off |
| 349 | static const FunctionInfo functions[] = { | 349 | static const FunctionInfo functions[] = { |
| 350 | {200, nullptr, "AllocateProcessHeapBlock"}, | 350 | {200, nullptr, "AllocateProcessHeapBlock"}, |
| @@ -440,7 +440,7 @@ private: | |||
| 440 | IPC::RequestParser rp{ctx}; | 440 | IPC::RequestParser rp{ctx}; |
| 441 | const u64 display = rp.Pop<u64>(); | 441 | const u64 display = rp.Pop<u64>(); |
| 442 | 442 | ||
| 443 | const Result rc = nv_flinger.CloseDisplay(display) ? ResultSuccess : ResultUnknown; | 443 | const Result rc = nvnflinger.CloseDisplay(display) ? ResultSuccess : ResultUnknown; |
| 444 | 444 | ||
| 445 | IPC::ResponseBuilder rb{ctx, 2}; | 445 | IPC::ResponseBuilder rb{ctx, 2}; |
| 446 | rb.Push(rc); | 446 | rb.Push(rc); |
| @@ -457,7 +457,7 @@ private: | |||
| 457 | "(STUBBED) called. unknown=0x{:08X}, display=0x{:016X}, aruid=0x{:016X}", | 457 | "(STUBBED) called. unknown=0x{:08X}, display=0x{:016X}, aruid=0x{:016X}", |
| 458 | unknown, display, aruid); | 458 | unknown, display, aruid); |
| 459 | 459 | ||
| 460 | const auto layer_id = nv_flinger.CreateLayer(display); | 460 | const auto layer_id = nvnflinger.CreateLayer(display); |
| 461 | if (!layer_id) { | 461 | if (!layer_id) { |
| 462 | LOG_ERROR(Service_VI, "Layer not found! display=0x{:016X}", display); | 462 | LOG_ERROR(Service_VI, "Layer not found! display=0x{:016X}", display); |
| 463 | IPC::ResponseBuilder rb{ctx, 2}; | 463 | IPC::ResponseBuilder rb{ctx, 2}; |
| @@ -494,14 +494,14 @@ private: | |||
| 494 | rb.Push(ResultSuccess); | 494 | rb.Push(ResultSuccess); |
| 495 | } | 495 | } |
| 496 | 496 | ||
| 497 | Nvnflinger::Nvnflinger& nv_flinger; | 497 | Nvnflinger::Nvnflinger& nvnflinger; |
| 498 | }; | 498 | }; |
| 499 | 499 | ||
| 500 | class IApplicationDisplayService final : public ServiceFramework<IApplicationDisplayService> { | 500 | class IApplicationDisplayService final : public ServiceFramework<IApplicationDisplayService> { |
| 501 | public: | 501 | public: |
| 502 | IApplicationDisplayService(Core::System& system_, Nvnflinger::Nvnflinger& nv_flinger_, | 502 | IApplicationDisplayService(Core::System& system_, Nvnflinger::Nvnflinger& nvnflinger_, |
| 503 | Nvnflinger::HosBinderDriverServer& hos_binder_driver_server_) | 503 | Nvnflinger::HosBinderDriverServer& hos_binder_driver_server_) |
| 504 | : ServiceFramework{system_, "IApplicationDisplayService"}, nv_flinger{nv_flinger_}, | 504 | : ServiceFramework{system_, "IApplicationDisplayService"}, nvnflinger{nvnflinger_}, |
| 505 | hos_binder_driver_server{hos_binder_driver_server_} { | 505 | hos_binder_driver_server{hos_binder_driver_server_} { |
| 506 | 506 | ||
| 507 | static const FunctionInfo functions[] = { | 507 | static const FunctionInfo functions[] = { |
| @@ -564,7 +564,7 @@ private: | |||
| 564 | 564 | ||
| 565 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 565 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 566 | rb.Push(ResultSuccess); | 566 | rb.Push(ResultSuccess); |
| 567 | rb.PushIpcInterface<ISystemDisplayService>(system, nv_flinger); | 567 | rb.PushIpcInterface<ISystemDisplayService>(system, nvnflinger); |
| 568 | } | 568 | } |
| 569 | 569 | ||
| 570 | void GetManagerDisplayService(HLERequestContext& ctx) { | 570 | void GetManagerDisplayService(HLERequestContext& ctx) { |
| @@ -572,7 +572,7 @@ private: | |||
| 572 | 572 | ||
| 573 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 573 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 574 | rb.Push(ResultSuccess); | 574 | rb.Push(ResultSuccess); |
| 575 | rb.PushIpcInterface<IManagerDisplayService>(system, nv_flinger); | 575 | rb.PushIpcInterface<IManagerDisplayService>(system, nvnflinger); |
| 576 | } | 576 | } |
| 577 | 577 | ||
| 578 | void GetIndirectDisplayTransactionService(HLERequestContext& ctx) { | 578 | void GetIndirectDisplayTransactionService(HLERequestContext& ctx) { |
| @@ -607,7 +607,7 @@ private: | |||
| 607 | 607 | ||
| 608 | ASSERT_MSG(name == "Default", "Non-default displays aren't supported yet"); | 608 | ASSERT_MSG(name == "Default", "Non-default displays aren't supported yet"); |
| 609 | 609 | ||
| 610 | const auto display_id = nv_flinger.OpenDisplay(name); | 610 | const auto display_id = nvnflinger.OpenDisplay(name); |
| 611 | if (!display_id) { | 611 | if (!display_id) { |
| 612 | LOG_ERROR(Service_VI, "Display not found! display_name={}", name); | 612 | LOG_ERROR(Service_VI, "Display not found! display_name={}", name); |
| 613 | IPC::ResponseBuilder rb{ctx, 2}; | 613 | IPC::ResponseBuilder rb{ctx, 2}; |
| @@ -624,7 +624,7 @@ private: | |||
| 624 | IPC::RequestParser rp{ctx}; | 624 | IPC::RequestParser rp{ctx}; |
| 625 | const u64 display_id = rp.Pop<u64>(); | 625 | const u64 display_id = rp.Pop<u64>(); |
| 626 | 626 | ||
| 627 | const Result rc = nv_flinger.CloseDisplay(display_id) ? ResultSuccess : ResultUnknown; | 627 | const Result rc = nvnflinger.CloseDisplay(display_id) ? ResultSuccess : ResultUnknown; |
| 628 | 628 | ||
| 629 | IPC::ResponseBuilder rb{ctx, 2}; | 629 | IPC::ResponseBuilder rb{ctx, 2}; |
| 630 | rb.Push(rc); | 630 | rb.Push(rc); |
| @@ -703,7 +703,7 @@ private: | |||
| 703 | 703 | ||
| 704 | LOG_DEBUG(Service_VI, "called. layer_id=0x{:016X}, aruid=0x{:016X}", layer_id, aruid); | 704 | LOG_DEBUG(Service_VI, "called. layer_id=0x{:016X}, aruid=0x{:016X}", layer_id, aruid); |
| 705 | 705 | ||
| 706 | const auto display_id = nv_flinger.OpenDisplay(display_name); | 706 | const auto display_id = nvnflinger.OpenDisplay(display_name); |
| 707 | if (!display_id) { | 707 | if (!display_id) { |
| 708 | LOG_ERROR(Service_VI, "Layer not found! layer_id={}", layer_id); | 708 | LOG_ERROR(Service_VI, "Layer not found! layer_id={}", layer_id); |
| 709 | IPC::ResponseBuilder rb{ctx, 2}; | 709 | IPC::ResponseBuilder rb{ctx, 2}; |
| @@ -711,7 +711,7 @@ private: | |||
| 711 | return; | 711 | return; |
| 712 | } | 712 | } |
| 713 | 713 | ||
| 714 | const auto buffer_queue_id = nv_flinger.FindBufferQueueId(*display_id, layer_id); | 714 | const auto buffer_queue_id = nvnflinger.FindBufferQueueId(*display_id, layer_id); |
| 715 | if (!buffer_queue_id) { | 715 | if (!buffer_queue_id) { |
| 716 | LOG_ERROR(Service_VI, "Buffer queue id not found! display_id={}", *display_id); | 716 | LOG_ERROR(Service_VI, "Buffer queue id not found! display_id={}", *display_id); |
| 717 | IPC::ResponseBuilder rb{ctx, 2}; | 717 | IPC::ResponseBuilder rb{ctx, 2}; |
| @@ -719,7 +719,7 @@ private: | |||
| 719 | return; | 719 | return; |
| 720 | } | 720 | } |
| 721 | 721 | ||
| 722 | nv_flinger.OpenLayer(layer_id); | 722 | nvnflinger.OpenLayer(layer_id); |
| 723 | 723 | ||
| 724 | android::OutputParcel parcel; | 724 | android::OutputParcel parcel; |
| 725 | parcel.WriteInterface(NativeWindow{*buffer_queue_id}); | 725 | parcel.WriteInterface(NativeWindow{*buffer_queue_id}); |
| @@ -737,7 +737,7 @@ private: | |||
| 737 | 737 | ||
| 738 | LOG_DEBUG(Service_VI, "called. layer_id=0x{:016X}", layer_id); | 738 | LOG_DEBUG(Service_VI, "called. layer_id=0x{:016X}", layer_id); |
| 739 | 739 | ||
| 740 | nv_flinger.CloseLayer(layer_id); | 740 | nvnflinger.CloseLayer(layer_id); |
| 741 | 741 | ||
| 742 | IPC::ResponseBuilder rb{ctx, 2}; | 742 | IPC::ResponseBuilder rb{ctx, 2}; |
| 743 | rb.Push(ResultSuccess); | 743 | rb.Push(ResultSuccess); |
| @@ -753,7 +753,7 @@ private: | |||
| 753 | 753 | ||
| 754 | // TODO(Subv): What's the difference between a Stray and a Managed layer? | 754 | // TODO(Subv): What's the difference between a Stray and a Managed layer? |
| 755 | 755 | ||
| 756 | const auto layer_id = nv_flinger.CreateLayer(display_id); | 756 | const auto layer_id = nvnflinger.CreateLayer(display_id); |
| 757 | if (!layer_id) { | 757 | if (!layer_id) { |
| 758 | LOG_ERROR(Service_VI, "Layer not found! display_id={}", display_id); | 758 | LOG_ERROR(Service_VI, "Layer not found! display_id={}", display_id); |
| 759 | IPC::ResponseBuilder rb{ctx, 2}; | 759 | IPC::ResponseBuilder rb{ctx, 2}; |
| @@ -761,7 +761,7 @@ private: | |||
| 761 | return; | 761 | return; |
| 762 | } | 762 | } |
| 763 | 763 | ||
| 764 | const auto buffer_queue_id = nv_flinger.FindBufferQueueId(display_id, *layer_id); | 764 | const auto buffer_queue_id = nvnflinger.FindBufferQueueId(display_id, *layer_id); |
| 765 | if (!buffer_queue_id) { | 765 | if (!buffer_queue_id) { |
| 766 | LOG_ERROR(Service_VI, "Buffer queue id not found! display_id={}", display_id); | 766 | LOG_ERROR(Service_VI, "Buffer queue id not found! display_id={}", display_id); |
| 767 | IPC::ResponseBuilder rb{ctx, 2}; | 767 | IPC::ResponseBuilder rb{ctx, 2}; |
| @@ -785,7 +785,7 @@ private: | |||
| 785 | const u64 layer_id = rp.Pop<u64>(); | 785 | const u64 layer_id = rp.Pop<u64>(); |
| 786 | 786 | ||
| 787 | LOG_WARNING(Service_VI, "(STUBBED) called. layer_id=0x{:016X}", layer_id); | 787 | LOG_WARNING(Service_VI, "(STUBBED) called. layer_id=0x{:016X}", layer_id); |
| 788 | nv_flinger.DestroyLayer(layer_id); | 788 | nvnflinger.DestroyLayer(layer_id); |
| 789 | 789 | ||
| 790 | IPC::ResponseBuilder rb{ctx, 2}; | 790 | IPC::ResponseBuilder rb{ctx, 2}; |
| 791 | rb.Push(ResultSuccess); | 791 | rb.Push(ResultSuccess); |
| @@ -798,7 +798,7 @@ private: | |||
| 798 | LOG_DEBUG(Service_VI, "called. display_id={}", display_id); | 798 | LOG_DEBUG(Service_VI, "called. display_id={}", display_id); |
| 799 | 799 | ||
| 800 | Kernel::KReadableEvent* vsync_event{}; | 800 | Kernel::KReadableEvent* vsync_event{}; |
| 801 | const auto result = nv_flinger.FindVsyncEvent(&vsync_event, display_id); | 801 | const auto result = nvnflinger.FindVsyncEvent(&vsync_event, display_id); |
| 802 | if (result != ResultSuccess) { | 802 | if (result != ResultSuccess) { |
| 803 | if (result == ResultNotFound) { | 803 | if (result == ResultNotFound) { |
| 804 | LOG_ERROR(Service_VI, "Vsync event was not found for display_id={}", display_id); | 804 | LOG_ERROR(Service_VI, "Vsync event was not found for display_id={}", display_id); |
| @@ -808,6 +808,12 @@ private: | |||
| 808 | rb.Push(result); | 808 | rb.Push(result); |
| 809 | return; | 809 | return; |
| 810 | } | 810 | } |
| 811 | if (vsync_event_fetched) { | ||
| 812 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 813 | rb.Push(VI::ResultPermissionDenied); | ||
| 814 | return; | ||
| 815 | } | ||
| 816 | vsync_event_fetched = true; | ||
| 811 | 817 | ||
| 812 | IPC::ResponseBuilder rb{ctx, 2, 1}; | 818 | IPC::ResponseBuilder rb{ctx, 2, 1}; |
| 813 | rb.Push(ResultSuccess); | 819 | rb.Push(ResultSuccess); |
| @@ -899,8 +905,9 @@ private: | |||
| 899 | } | 905 | } |
| 900 | } | 906 | } |
| 901 | 907 | ||
| 902 | Nvnflinger::Nvnflinger& nv_flinger; | 908 | Nvnflinger::Nvnflinger& nvnflinger; |
| 903 | Nvnflinger::HosBinderDriverServer& hos_binder_driver_server; | 909 | Nvnflinger::HosBinderDriverServer& hos_binder_driver_server; |
| 910 | bool vsync_event_fetched{false}; | ||
| 904 | }; | 911 | }; |
| 905 | 912 | ||
| 906 | static bool IsValidServiceAccess(Permission permission, Policy policy) { | 913 | static bool IsValidServiceAccess(Permission permission, Policy policy) { |
| @@ -916,7 +923,7 @@ static bool IsValidServiceAccess(Permission permission, Policy policy) { | |||
| 916 | } | 923 | } |
| 917 | 924 | ||
| 918 | void detail::GetDisplayServiceImpl(HLERequestContext& ctx, Core::System& system, | 925 | void detail::GetDisplayServiceImpl(HLERequestContext& ctx, Core::System& system, |
| 919 | Nvnflinger::Nvnflinger& nv_flinger, | 926 | Nvnflinger::Nvnflinger& nvnflinger, |
| 920 | Nvnflinger::HosBinderDriverServer& hos_binder_driver_server, | 927 | Nvnflinger::HosBinderDriverServer& hos_binder_driver_server, |
| 921 | Permission permission) { | 928 | Permission permission) { |
| 922 | IPC::RequestParser rp{ctx}; | 929 | IPC::RequestParser rp{ctx}; |
| @@ -931,19 +938,19 @@ void detail::GetDisplayServiceImpl(HLERequestContext& ctx, Core::System& system, | |||
| 931 | 938 | ||
| 932 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 939 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 933 | rb.Push(ResultSuccess); | 940 | rb.Push(ResultSuccess); |
| 934 | rb.PushIpcInterface<IApplicationDisplayService>(system, nv_flinger, hos_binder_driver_server); | 941 | rb.PushIpcInterface<IApplicationDisplayService>(system, nvnflinger, hos_binder_driver_server); |
| 935 | } | 942 | } |
| 936 | 943 | ||
| 937 | void LoopProcess(Core::System& system, Nvnflinger::Nvnflinger& nv_flinger, | 944 | void LoopProcess(Core::System& system, Nvnflinger::Nvnflinger& nvnflinger, |
| 938 | Nvnflinger::HosBinderDriverServer& hos_binder_driver_server) { | 945 | Nvnflinger::HosBinderDriverServer& hos_binder_driver_server) { |
| 939 | auto server_manager = std::make_unique<ServerManager>(system); | 946 | auto server_manager = std::make_unique<ServerManager>(system); |
| 940 | 947 | ||
| 941 | server_manager->RegisterNamedService( | 948 | server_manager->RegisterNamedService( |
| 942 | "vi:m", std::make_shared<VI_M>(system, nv_flinger, hos_binder_driver_server)); | 949 | "vi:m", std::make_shared<VI_M>(system, nvnflinger, hos_binder_driver_server)); |
| 943 | server_manager->RegisterNamedService( | 950 | server_manager->RegisterNamedService( |
| 944 | "vi:s", std::make_shared<VI_S>(system, nv_flinger, hos_binder_driver_server)); | 951 | "vi:s", std::make_shared<VI_S>(system, nvnflinger, hos_binder_driver_server)); |
| 945 | server_manager->RegisterNamedService( | 952 | server_manager->RegisterNamedService( |
| 946 | "vi:u", std::make_shared<VI_U>(system, nv_flinger, hos_binder_driver_server)); | 953 | "vi:u", std::make_shared<VI_U>(system, nvnflinger, hos_binder_driver_server)); |
| 947 | ServerManager::RunServer(std::move(server_manager)); | 954 | ServerManager::RunServer(std::move(server_manager)); |
| 948 | } | 955 | } |
| 949 | 956 | ||
diff --git a/src/core/hle/service/vi/vi.h b/src/core/hle/service/vi/vi.h index a35b62f97..ee4bcbcfa 100644 --- a/src/core/hle/service/vi/vi.h +++ b/src/core/hle/service/vi/vi.h | |||
| @@ -48,7 +48,7 @@ void GetDisplayServiceImpl(HLERequestContext& ctx, Core::System& system, | |||
| 48 | Permission permission); | 48 | Permission permission); |
| 49 | } // namespace detail | 49 | } // namespace detail |
| 50 | 50 | ||
| 51 | void LoopProcess(Core::System& system, Nvnflinger::Nvnflinger& nv_flinger, | 51 | void LoopProcess(Core::System& system, Nvnflinger::Nvnflinger& nvnflinger, |
| 52 | Nvnflinger::HosBinderDriverServer& hos_binder_driver_server); | 52 | Nvnflinger::HosBinderDriverServer& hos_binder_driver_server); |
| 53 | 53 | ||
| 54 | } // namespace Service::VI | 54 | } // namespace Service::VI |
diff --git a/src/core/loader/deconstructed_rom_directory.cpp b/src/core/loader/deconstructed_rom_directory.cpp index c9f8707b7..9b75c660c 100644 --- a/src/core/loader/deconstructed_rom_directory.cpp +++ b/src/core/loader/deconstructed_rom_directory.cpp | |||
| @@ -19,8 +19,54 @@ | |||
| 19 | #include "core/arm/nce/patcher.h" | 19 | #include "core/arm/nce/patcher.h" |
| 20 | #endif | 20 | #endif |
| 21 | 21 | ||
| 22 | #ifndef HAS_NCE | ||
| 23 | namespace Core::NCE { | ||
| 24 | class Patcher {}; | ||
| 25 | } // namespace Core::NCE | ||
| 26 | #endif | ||
| 27 | |||
| 22 | namespace Loader { | 28 | namespace Loader { |
| 23 | 29 | ||
| 30 | struct PatchCollection { | ||
| 31 | explicit PatchCollection(bool is_application_) : is_application{is_application_} { | ||
| 32 | module_patcher_indices.fill(-1); | ||
| 33 | patchers.emplace_back(); | ||
| 34 | } | ||
| 35 | |||
| 36 | std::vector<Core::NCE::Patcher>* GetPatchers() { | ||
| 37 | if (is_application && Settings::IsNceEnabled()) { | ||
| 38 | return &patchers; | ||
| 39 | } | ||
| 40 | return nullptr; | ||
| 41 | } | ||
| 42 | |||
| 43 | size_t GetTotalPatchSize() const { | ||
| 44 | size_t total_size{}; | ||
| 45 | #ifdef HAS_NCE | ||
| 46 | for (auto& patcher : patchers) { | ||
| 47 | total_size += patcher.GetSectionSize(); | ||
| 48 | } | ||
| 49 | #endif | ||
| 50 | return total_size; | ||
| 51 | } | ||
| 52 | |||
| 53 | void SaveIndex(size_t module) { | ||
| 54 | module_patcher_indices[module] = static_cast<s32>(patchers.size() - 1); | ||
| 55 | } | ||
| 56 | |||
| 57 | s32 GetIndex(size_t module) const { | ||
| 58 | return module_patcher_indices[module]; | ||
| 59 | } | ||
| 60 | |||
| 61 | s32 GetLastIndex() const { | ||
| 62 | return static_cast<s32>(patchers.size()) - 1; | ||
| 63 | } | ||
| 64 | |||
| 65 | bool is_application; | ||
| 66 | std::vector<Core::NCE::Patcher> patchers; | ||
| 67 | std::array<s32, 13> module_patcher_indices{}; | ||
| 68 | }; | ||
| 69 | |||
| 24 | AppLoader_DeconstructedRomDirectory::AppLoader_DeconstructedRomDirectory(FileSys::VirtualFile file_, | 70 | AppLoader_DeconstructedRomDirectory::AppLoader_DeconstructedRomDirectory(FileSys::VirtualFile file_, |
| 25 | bool override_update_) | 71 | bool override_update_) |
| 26 | : AppLoader(std::move(file_)), override_update(override_update_), is_hbl(false) { | 72 | : AppLoader(std::move(file_)), override_update(override_update_), is_hbl(false) { |
| @@ -142,18 +188,7 @@ AppLoader_DeconstructedRomDirectory::LoadResult AppLoader_DeconstructedRomDirect | |||
| 142 | std::size_t code_size{}; | 188 | std::size_t code_size{}; |
| 143 | 189 | ||
| 144 | // Define an nce patch context for each potential module. | 190 | // Define an nce patch context for each potential module. |
| 145 | #ifdef HAS_NCE | 191 | PatchCollection patch_ctx{is_application}; |
| 146 | std::array<Core::NCE::Patcher, 13> module_patchers; | ||
| 147 | #endif | ||
| 148 | |||
| 149 | const auto GetPatcher = [&](size_t i) -> Core::NCE::Patcher* { | ||
| 150 | #ifdef HAS_NCE | ||
| 151 | if (is_application && Settings::IsNceEnabled()) { | ||
| 152 | return &module_patchers[i]; | ||
| 153 | } | ||
| 154 | #endif | ||
| 155 | return nullptr; | ||
| 156 | }; | ||
| 157 | 192 | ||
| 158 | // Use the NSO module loader to figure out the code layout | 193 | // Use the NSO module loader to figure out the code layout |
| 159 | for (size_t i = 0; i < static_modules.size(); i++) { | 194 | for (size_t i = 0; i < static_modules.size(); i++) { |
| @@ -164,13 +199,14 @@ AppLoader_DeconstructedRomDirectory::LoadResult AppLoader_DeconstructedRomDirect | |||
| 164 | } | 199 | } |
| 165 | 200 | ||
| 166 | const bool should_pass_arguments = std::strcmp(module, "rtld") == 0; | 201 | const bool should_pass_arguments = std::strcmp(module, "rtld") == 0; |
| 167 | const auto tentative_next_load_addr = | 202 | const auto tentative_next_load_addr = AppLoader_NSO::LoadModule( |
| 168 | AppLoader_NSO::LoadModule(process, system, *module_file, code_size, | 203 | process, system, *module_file, code_size, should_pass_arguments, false, {}, |
| 169 | should_pass_arguments, false, {}, GetPatcher(i)); | 204 | patch_ctx.GetPatchers(), patch_ctx.GetLastIndex()); |
| 170 | if (!tentative_next_load_addr) { | 205 | if (!tentative_next_load_addr) { |
| 171 | return {ResultStatus::ErrorLoadingNSO, {}}; | 206 | return {ResultStatus::ErrorLoadingNSO, {}}; |
| 172 | } | 207 | } |
| 173 | 208 | ||
| 209 | patch_ctx.SaveIndex(i); | ||
| 174 | code_size = *tentative_next_load_addr; | 210 | code_size = *tentative_next_load_addr; |
| 175 | } | 211 | } |
| 176 | 212 | ||
| @@ -184,6 +220,9 @@ AppLoader_DeconstructedRomDirectory::LoadResult AppLoader_DeconstructedRomDirect | |||
| 184 | return 0; | 220 | return 0; |
| 185 | }(); | 221 | }(); |
| 186 | 222 | ||
| 223 | // Add patch size to the total module size | ||
| 224 | code_size += patch_ctx.GetTotalPatchSize(); | ||
| 225 | |||
| 187 | // Setup the process code layout | 226 | // Setup the process code layout |
| 188 | if (process.LoadFromMetadata(metadata, code_size, fastmem_base, is_hbl).IsError()) { | 227 | if (process.LoadFromMetadata(metadata, code_size, fastmem_base, is_hbl).IsError()) { |
| 189 | return {ResultStatus::ErrorUnableToParseKernelMetadata, {}}; | 228 | return {ResultStatus::ErrorUnableToParseKernelMetadata, {}}; |
| @@ -204,9 +243,9 @@ AppLoader_DeconstructedRomDirectory::LoadResult AppLoader_DeconstructedRomDirect | |||
| 204 | 243 | ||
| 205 | const VAddr load_addr{next_load_addr}; | 244 | const VAddr load_addr{next_load_addr}; |
| 206 | const bool should_pass_arguments = std::strcmp(module, "rtld") == 0; | 245 | const bool should_pass_arguments = std::strcmp(module, "rtld") == 0; |
| 207 | const auto tentative_next_load_addr = | 246 | const auto tentative_next_load_addr = AppLoader_NSO::LoadModule( |
| 208 | AppLoader_NSO::LoadModule(process, system, *module_file, load_addr, | 247 | process, system, *module_file, load_addr, should_pass_arguments, true, pm, |
| 209 | should_pass_arguments, true, pm, GetPatcher(i)); | 248 | patch_ctx.GetPatchers(), patch_ctx.GetIndex(i)); |
| 210 | if (!tentative_next_load_addr) { | 249 | if (!tentative_next_load_addr) { |
| 211 | return {ResultStatus::ErrorLoadingNSO, {}}; | 250 | return {ResultStatus::ErrorLoadingNSO, {}}; |
| 212 | } | 251 | } |
| @@ -216,20 +255,6 @@ AppLoader_DeconstructedRomDirectory::LoadResult AppLoader_DeconstructedRomDirect | |||
| 216 | LOG_DEBUG(Loader, "loaded module {} @ {:#X}", module, load_addr); | 255 | LOG_DEBUG(Loader, "loaded module {} @ {:#X}", module, load_addr); |
| 217 | } | 256 | } |
| 218 | 257 | ||
| 219 | // Find the RomFS by searching for a ".romfs" file in this directory | ||
| 220 | const auto& files = dir->GetFiles(); | ||
| 221 | const auto romfs_iter = | ||
| 222 | std::find_if(files.begin(), files.end(), [](const FileSys::VirtualFile& f) { | ||
| 223 | return f->GetName().find(".romfs") != std::string::npos; | ||
| 224 | }); | ||
| 225 | |||
| 226 | // Register the RomFS if a ".romfs" file was found | ||
| 227 | if (romfs_iter != files.end() && *romfs_iter != nullptr) { | ||
| 228 | romfs = *romfs_iter; | ||
| 229 | system.GetFileSystemController().RegisterRomFS(std::make_unique<FileSys::RomFSFactory>( | ||
| 230 | *this, system.GetContentProvider(), system.GetFileSystemController())); | ||
| 231 | } | ||
| 232 | |||
| 233 | is_loaded = true; | 258 | is_loaded = true; |
| 234 | return {ResultStatus::Success, | 259 | return {ResultStatus::Success, |
| 235 | LoadParameters{metadata.GetMainThreadPriority(), metadata.GetMainThreadStackSize()}}; | 260 | LoadParameters{metadata.GetMainThreadPriority(), metadata.GetMainThreadStackSize()}}; |
diff --git a/src/core/loader/nca.cpp b/src/core/loader/nca.cpp index 814407535..2a32b1276 100644 --- a/src/core/loader/nca.cpp +++ b/src/core/loader/nca.cpp | |||
| @@ -74,8 +74,10 @@ AppLoader_NCA::LoadResult AppLoader_NCA::Load(Kernel::KProcess& process, Core::S | |||
| 74 | return load_result; | 74 | return load_result; |
| 75 | } | 75 | } |
| 76 | 76 | ||
| 77 | system.GetFileSystemController().RegisterRomFS(std::make_unique<FileSys::RomFSFactory>( | 77 | system.GetFileSystemController().RegisterProcess( |
| 78 | *this, system.GetContentProvider(), system.GetFileSystemController())); | 78 | process.GetProcessId(), nca->GetTitleId(), |
| 79 | std::make_shared<FileSys::RomFSFactory>(*this, system.GetContentProvider(), | ||
| 80 | system.GetFileSystemController())); | ||
| 79 | 81 | ||
| 80 | is_loaded = true; | 82 | is_loaded = true; |
| 81 | return load_result; | 83 | return load_result; |
diff --git a/src/core/loader/nro.cpp b/src/core/loader/nro.cpp index e74697cda..f8225d697 100644 --- a/src/core/loader/nro.cpp +++ b/src/core/loader/nro.cpp | |||
| @@ -275,10 +275,12 @@ AppLoader_NRO::LoadResult AppLoader_NRO::Load(Kernel::KProcess& process, Core::S | |||
| 275 | return {ResultStatus::ErrorLoadingNRO, {}}; | 275 | return {ResultStatus::ErrorLoadingNRO, {}}; |
| 276 | } | 276 | } |
| 277 | 277 | ||
| 278 | if (romfs != nullptr) { | 278 | u64 program_id{}; |
| 279 | system.GetFileSystemController().RegisterRomFS(std::make_unique<FileSys::RomFSFactory>( | 279 | ReadProgramId(program_id); |
| 280 | *this, system.GetContentProvider(), system.GetFileSystemController())); | 280 | system.GetFileSystemController().RegisterProcess( |
| 281 | } | 281 | process.GetProcessId(), program_id, |
| 282 | std::make_unique<FileSys::RomFSFactory>(*this, system.GetContentProvider(), | ||
| 283 | system.GetFileSystemController())); | ||
| 282 | 284 | ||
| 283 | is_loaded = true; | 285 | is_loaded = true; |
| 284 | return {ResultStatus::Success, LoadParameters{Kernel::KThread::DefaultThreadPriority, | 286 | return {ResultStatus::Success, LoadParameters{Kernel::KThread::DefaultThreadPriority, |
diff --git a/src/core/loader/nso.cpp b/src/core/loader/nso.cpp index b053a0d14..583b7e927 100644 --- a/src/core/loader/nso.cpp +++ b/src/core/loader/nso.cpp | |||
| @@ -77,7 +77,8 @@ std::optional<VAddr> AppLoader_NSO::LoadModule(Kernel::KProcess& process, Core:: | |||
| 77 | const FileSys::VfsFile& nso_file, VAddr load_base, | 77 | const FileSys::VfsFile& nso_file, VAddr load_base, |
| 78 | bool should_pass_arguments, bool load_into_process, | 78 | bool should_pass_arguments, bool load_into_process, |
| 79 | std::optional<FileSys::PatchManager> pm, | 79 | std::optional<FileSys::PatchManager> pm, |
| 80 | Core::NCE::Patcher* patch) { | 80 | std::vector<Core::NCE::Patcher>* patches, |
| 81 | s32 patch_index) { | ||
| 81 | if (nso_file.GetSize() < sizeof(NSOHeader)) { | 82 | if (nso_file.GetSize() < sizeof(NSOHeader)) { |
| 82 | return std::nullopt; | 83 | return std::nullopt; |
| 83 | } | 84 | } |
| @@ -94,8 +95,11 @@ std::optional<VAddr> AppLoader_NSO::LoadModule(Kernel::KProcess& process, Core:: | |||
| 94 | // Allocate some space at the beginning if we are patching in PreText mode. | 95 | // Allocate some space at the beginning if we are patching in PreText mode. |
| 95 | const size_t module_start = [&]() -> size_t { | 96 | const size_t module_start = [&]() -> size_t { |
| 96 | #ifdef HAS_NCE | 97 | #ifdef HAS_NCE |
| 97 | if (patch && patch->GetPatchMode() == Core::NCE::PatchMode::PreText) { | 98 | if (patches && load_into_process) { |
| 98 | return patch->GetSectionSize(); | 99 | auto* patch = &patches->operator[](patch_index); |
| 100 | if (patch->GetPatchMode() == Core::NCE::PatchMode::PreText) { | ||
| 101 | return patch->GetSectionSize(); | ||
| 102 | } | ||
| 99 | } | 103 | } |
| 100 | #endif | 104 | #endif |
| 101 | return 0; | 105 | return 0; |
| @@ -160,27 +164,24 @@ std::optional<VAddr> AppLoader_NSO::LoadModule(Kernel::KProcess& process, Core:: | |||
| 160 | #ifdef HAS_NCE | 164 | #ifdef HAS_NCE |
| 161 | // If we are computing the process code layout and using nce backend, patch. | 165 | // If we are computing the process code layout and using nce backend, patch. |
| 162 | const auto& code = codeset.CodeSegment(); | 166 | const auto& code = codeset.CodeSegment(); |
| 163 | if (patch && patch->GetPatchMode() == Core::NCE::PatchMode::None) { | 167 | auto* patch = patches ? &patches->operator[](patch_index) : nullptr; |
| 168 | if (patch && !load_into_process) { | ||
| 164 | // Patch SVCs and MRS calls in the guest code | 169 | // Patch SVCs and MRS calls in the guest code |
| 165 | patch->PatchText(program_image, code); | 170 | while (!patch->PatchText(program_image, code)) { |
| 166 | 171 | patch = &patches->emplace_back(); | |
| 167 | // Add patch section size to the module size. | 172 | } |
| 168 | image_size += static_cast<u32>(patch->GetSectionSize()); | ||
| 169 | } else if (patch) { | 173 | } else if (patch) { |
| 170 | // Relocate code patch and copy to the program_image. | 174 | // Relocate code patch and copy to the program_image. |
| 171 | patch->RelocateAndCopy(load_base, code, program_image, &process.GetPostHandlers()); | 175 | if (patch->RelocateAndCopy(load_base, code, program_image, &process.GetPostHandlers())) { |
| 172 | 176 | // Update patch section. | |
| 173 | // Update patch section. | 177 | auto& patch_segment = codeset.PatchSegment(); |
| 174 | auto& patch_segment = codeset.PatchSegment(); | 178 | patch_segment.addr = |
| 175 | patch_segment.addr = | 179 | patch->GetPatchMode() == Core::NCE::PatchMode::PreText ? 0 : image_size; |
| 176 | patch->GetPatchMode() == Core::NCE::PatchMode::PreText ? 0 : image_size; | 180 | patch_segment.size = static_cast<u32>(patch->GetSectionSize()); |
| 177 | patch_segment.size = static_cast<u32>(patch->GetSectionSize()); | ||
| 178 | |||
| 179 | // Add patch section size to the module size. In PreText mode image_size | ||
| 180 | // already contains the patch segment as part of module_start. | ||
| 181 | if (patch->GetPatchMode() == Core::NCE::PatchMode::PostData) { | ||
| 182 | image_size += patch_segment.size; | ||
| 183 | } | 181 | } |
| 182 | |||
| 183 | // Refresh image_size to take account the patch section if it was added by RelocateAndCopy | ||
| 184 | image_size = static_cast<u32>(program_image.size()); | ||
| 184 | } | 185 | } |
| 185 | #endif | 186 | #endif |
| 186 | 187 | ||
diff --git a/src/core/loader/nso.h b/src/core/loader/nso.h index 29b86ed4c..6356697e3 100644 --- a/src/core/loader/nso.h +++ b/src/core/loader/nso.h | |||
| @@ -93,7 +93,8 @@ public: | |||
| 93 | const FileSys::VfsFile& nso_file, VAddr load_base, | 93 | const FileSys::VfsFile& nso_file, VAddr load_base, |
| 94 | bool should_pass_arguments, bool load_into_process, | 94 | bool should_pass_arguments, bool load_into_process, |
| 95 | std::optional<FileSys::PatchManager> pm = {}, | 95 | std::optional<FileSys::PatchManager> pm = {}, |
| 96 | Core::NCE::Patcher* patch = nullptr); | 96 | std::vector<Core::NCE::Patcher>* patches = nullptr, |
| 97 | s32 patch_index = -1); | ||
| 97 | 98 | ||
| 98 | LoadResult Load(Kernel::KProcess& process, Core::System& system) override; | 99 | LoadResult Load(Kernel::KProcess& process, Core::System& system) override; |
| 99 | 100 | ||
diff --git a/src/core/loader/nsp.cpp b/src/core/loader/nsp.cpp index f4ab75b77..28116ff3a 100644 --- a/src/core/loader/nsp.cpp +++ b/src/core/loader/nsp.cpp | |||
| @@ -111,7 +111,8 @@ AppLoader_NSP::LoadResult AppLoader_NSP::Load(Kernel::KProcess& process, Core::S | |||
| 111 | 111 | ||
| 112 | FileSys::VirtualFile update_raw; | 112 | FileSys::VirtualFile update_raw; |
| 113 | if (ReadUpdateRaw(update_raw) == ResultStatus::Success && update_raw != nullptr) { | 113 | if (ReadUpdateRaw(update_raw) == ResultStatus::Success && update_raw != nullptr) { |
| 114 | system.GetFileSystemController().SetPackedUpdate(std::move(update_raw)); | 114 | system.GetFileSystemController().SetPackedUpdate(process.GetProcessId(), |
| 115 | std::move(update_raw)); | ||
| 115 | } | 116 | } |
| 116 | 117 | ||
| 117 | is_loaded = true; | 118 | is_loaded = true; |
diff --git a/src/core/loader/xci.cpp b/src/core/loader/xci.cpp index 12d72c380..e9abb199a 100644 --- a/src/core/loader/xci.cpp +++ b/src/core/loader/xci.cpp | |||
| @@ -78,7 +78,8 @@ AppLoader_XCI::LoadResult AppLoader_XCI::Load(Kernel::KProcess& process, Core::S | |||
| 78 | 78 | ||
| 79 | FileSys::VirtualFile update_raw; | 79 | FileSys::VirtualFile update_raw; |
| 80 | if (ReadUpdateRaw(update_raw) == ResultStatus::Success && update_raw != nullptr) { | 80 | if (ReadUpdateRaw(update_raw) == ResultStatus::Success && update_raw != nullptr) { |
| 81 | system.GetFileSystemController().SetPackedUpdate(std::move(update_raw)); | 81 | system.GetFileSystemController().SetPackedUpdate(process.GetProcessId(), |
| 82 | std::move(update_raw)); | ||
| 82 | } | 83 | } |
| 83 | 84 | ||
| 84 | is_loaded = true; | 85 | is_loaded = true; |
diff --git a/src/hid_core/CMakeLists.txt b/src/hid_core/CMakeLists.txt index cce4e6857..aa85502b5 100644 --- a/src/hid_core/CMakeLists.txt +++ b/src/hid_core/CMakeLists.txt | |||
| @@ -36,6 +36,30 @@ add_library(hid_core STATIC | |||
| 36 | irsensor/processor_base.h | 36 | irsensor/processor_base.h |
| 37 | irsensor/tera_plugin_processor.cpp | 37 | irsensor/tera_plugin_processor.cpp |
| 38 | irsensor/tera_plugin_processor.h | 38 | irsensor/tera_plugin_processor.h |
| 39 | resources/abstracted_pad/abstract_battery_handler.cpp | ||
| 40 | resources/abstracted_pad/abstract_battery_handler.h | ||
| 41 | resources/abstracted_pad/abstract_button_handler.cpp | ||
| 42 | resources/abstracted_pad/abstract_button_handler.h | ||
| 43 | resources/abstracted_pad/abstract_ir_sensor_handler.cpp | ||
| 44 | resources/abstracted_pad/abstract_ir_sensor_handler.h | ||
| 45 | resources/abstracted_pad/abstract_led_handler.cpp | ||
| 46 | resources/abstracted_pad/abstract_led_handler.h | ||
| 47 | resources/abstracted_pad/abstract_mcu_handler.cpp | ||
| 48 | resources/abstracted_pad/abstract_mcu_handler.h | ||
| 49 | resources/abstracted_pad/abstract_nfc_handler.cpp | ||
| 50 | resources/abstracted_pad/abstract_nfc_handler.h | ||
| 51 | resources/abstracted_pad/abstract_pad.cpp | ||
| 52 | resources/abstracted_pad/abstract_pad.h | ||
| 53 | resources/abstracted_pad/abstract_pad_holder.cpp | ||
| 54 | resources/abstracted_pad/abstract_pad_holder.h | ||
| 55 | resources/abstracted_pad/abstract_palma_handler.cpp | ||
| 56 | resources/abstracted_pad/abstract_palma_handler.h | ||
| 57 | resources/abstracted_pad/abstract_properties_handler.cpp | ||
| 58 | resources/abstracted_pad/abstract_properties_handler.h | ||
| 59 | resources/abstracted_pad/abstract_sixaxis_handler.cpp | ||
| 60 | resources/abstracted_pad/abstract_sixaxis_handler.h | ||
| 61 | resources/abstracted_pad/abstract_vibration_handler.cpp | ||
| 62 | resources/abstracted_pad/abstract_vibration_handler.h | ||
| 39 | resources/debug_pad/debug_pad.cpp | 63 | resources/debug_pad/debug_pad.cpp |
| 40 | resources/debug_pad/debug_pad.h | 64 | resources/debug_pad/debug_pad.h |
| 41 | resources/debug_pad/debug_pad_types.h | 65 | resources/debug_pad/debug_pad_types.h |
| @@ -56,6 +80,8 @@ add_library(hid_core STATIC | |||
| 56 | resources/npad/npad_resource.cpp | 80 | resources/npad/npad_resource.cpp |
| 57 | resources/npad/npad_resource.h | 81 | resources/npad/npad_resource.h |
| 58 | resources/npad/npad_types.h | 82 | resources/npad/npad_types.h |
| 83 | resources/npad/npad_vibration.cpp | ||
| 84 | resources/npad/npad_vibration.h | ||
| 59 | resources/palma/palma.cpp | 85 | resources/palma/palma.cpp |
| 60 | resources/palma/palma.h | 86 | resources/palma/palma.h |
| 61 | resources/six_axis/console_six_axis.cpp | 87 | resources/six_axis/console_six_axis.cpp |
| @@ -78,6 +104,14 @@ add_library(hid_core STATIC | |||
| 78 | resources/touch_screen/touch_types.h | 104 | resources/touch_screen/touch_types.h |
| 79 | resources/unique_pad/unique_pad.cpp | 105 | resources/unique_pad/unique_pad.cpp |
| 80 | resources/unique_pad/unique_pad.h | 106 | resources/unique_pad/unique_pad.h |
| 107 | resources/vibration/gc_vibration_device.h | ||
| 108 | resources/vibration/gc_vibration_device.cpp | ||
| 109 | resources/vibration/n64_vibration_device.h | ||
| 110 | resources/vibration/n64_vibration_device.cpp | ||
| 111 | resources/vibration/vibration_base.h | ||
| 112 | resources/vibration/vibration_base.cpp | ||
| 113 | resources/vibration/vibration_device.h | ||
| 114 | resources/vibration/vibration_device.cpp | ||
| 81 | resources/applet_resource.cpp | 115 | resources/applet_resource.cpp |
| 82 | resources/applet_resource.h | 116 | resources/applet_resource.h |
| 83 | resources/controller_base.cpp | 117 | resources/controller_base.cpp |
diff --git a/src/hid_core/frontend/emulated_controller.cpp b/src/hid_core/frontend/emulated_controller.cpp index 3d2d1e9f9..2ab93402d 100644 --- a/src/hid_core/frontend/emulated_controller.cpp +++ b/src/hid_core/frontend/emulated_controller.cpp | |||
| @@ -27,7 +27,7 @@ EmulatedController::~EmulatedController() = default; | |||
| 27 | NpadStyleIndex EmulatedController::MapSettingsTypeToNPad(Settings::ControllerType type) { | 27 | NpadStyleIndex EmulatedController::MapSettingsTypeToNPad(Settings::ControllerType type) { |
| 28 | switch (type) { | 28 | switch (type) { |
| 29 | case Settings::ControllerType::ProController: | 29 | case Settings::ControllerType::ProController: |
| 30 | return NpadStyleIndex::ProController; | 30 | return NpadStyleIndex::Fullkey; |
| 31 | case Settings::ControllerType::DualJoyconDetached: | 31 | case Settings::ControllerType::DualJoyconDetached: |
| 32 | return NpadStyleIndex::JoyconDual; | 32 | return NpadStyleIndex::JoyconDual; |
| 33 | case Settings::ControllerType::LeftJoycon: | 33 | case Settings::ControllerType::LeftJoycon: |
| @@ -49,13 +49,13 @@ NpadStyleIndex EmulatedController::MapSettingsTypeToNPad(Settings::ControllerTyp | |||
| 49 | case Settings::ControllerType::SegaGenesis: | 49 | case Settings::ControllerType::SegaGenesis: |
| 50 | return NpadStyleIndex::SegaGenesis; | 50 | return NpadStyleIndex::SegaGenesis; |
| 51 | default: | 51 | default: |
| 52 | return NpadStyleIndex::ProController; | 52 | return NpadStyleIndex::Fullkey; |
| 53 | } | 53 | } |
| 54 | } | 54 | } |
| 55 | 55 | ||
| 56 | Settings::ControllerType EmulatedController::MapNPadToSettingsType(NpadStyleIndex type) { | 56 | Settings::ControllerType EmulatedController::MapNPadToSettingsType(NpadStyleIndex type) { |
| 57 | switch (type) { | 57 | switch (type) { |
| 58 | case NpadStyleIndex::ProController: | 58 | case NpadStyleIndex::Fullkey: |
| 59 | return Settings::ControllerType::ProController; | 59 | return Settings::ControllerType::ProController; |
| 60 | case NpadStyleIndex::JoyconDual: | 60 | case NpadStyleIndex::JoyconDual: |
| 61 | return Settings::ControllerType::DualJoyconDetached; | 61 | return Settings::ControllerType::DualJoyconDetached; |
| @@ -106,7 +106,7 @@ void EmulatedController::ReloadFromSettings() { | |||
| 106 | SetNpadStyleIndex(MapSettingsTypeToNPad(player.controller_type)); | 106 | SetNpadStyleIndex(MapSettingsTypeToNPad(player.controller_type)); |
| 107 | original_npad_type = npad_type; | 107 | original_npad_type = npad_type; |
| 108 | } else { | 108 | } else { |
| 109 | SetNpadStyleIndex(NpadStyleIndex::ProController); | 109 | SetNpadStyleIndex(NpadStyleIndex::Fullkey); |
| 110 | original_npad_type = npad_type; | 110 | original_npad_type = npad_type; |
| 111 | } | 111 | } |
| 112 | 112 | ||
| @@ -509,11 +509,11 @@ void EmulatedController::ReloadInput() { | |||
| 509 | }); | 509 | }); |
| 510 | } | 510 | } |
| 511 | turbo_button_state = 0; | 511 | turbo_button_state = 0; |
| 512 | is_initalized = true; | 512 | is_initialized = true; |
| 513 | } | 513 | } |
| 514 | 514 | ||
| 515 | void EmulatedController::UnloadInput() { | 515 | void EmulatedController::UnloadInput() { |
| 516 | is_initalized = false; | 516 | is_initialized = false; |
| 517 | for (auto& button : button_devices) { | 517 | for (auto& button : button_devices) { |
| 518 | button.reset(); | 518 | button.reset(); |
| 519 | } | 519 | } |
| @@ -1073,7 +1073,7 @@ void EmulatedController::SetColors(const Common::Input::CallbackStatus& callback | |||
| 1073 | .body = GetNpadColor(controller.color_values[index].body), | 1073 | .body = GetNpadColor(controller.color_values[index].body), |
| 1074 | .button = GetNpadColor(controller.color_values[index].buttons), | 1074 | .button = GetNpadColor(controller.color_values[index].buttons), |
| 1075 | }; | 1075 | }; |
| 1076 | if (npad_type == NpadStyleIndex::ProController) { | 1076 | if (npad_type == NpadStyleIndex::Fullkey) { |
| 1077 | controller.colors_state.left = { | 1077 | controller.colors_state.left = { |
| 1078 | .body = GetNpadColor(controller.color_values[index].left_grip), | 1078 | .body = GetNpadColor(controller.color_values[index].left_grip), |
| 1079 | .button = GetNpadColor(controller.color_values[index].buttons), | 1079 | .button = GetNpadColor(controller.color_values[index].buttons), |
| @@ -1209,7 +1209,7 @@ void EmulatedController::SetNfc(const Common::Input::CallbackStatus& callback) { | |||
| 1209 | } | 1209 | } |
| 1210 | 1210 | ||
| 1211 | bool EmulatedController::SetVibration(std::size_t device_index, VibrationValue vibration) { | 1211 | bool EmulatedController::SetVibration(std::size_t device_index, VibrationValue vibration) { |
| 1212 | if (!is_initalized) { | 1212 | if (!is_initialized) { |
| 1213 | return false; | 1213 | return false; |
| 1214 | } | 1214 | } |
| 1215 | if (device_index >= output_devices.size()) { | 1215 | if (device_index >= output_devices.size()) { |
| @@ -1247,7 +1247,7 @@ bool EmulatedController::IsVibrationEnabled(std::size_t device_index) { | |||
| 1247 | const auto player_index = Service::HID::NpadIdTypeToIndex(npad_id_type); | 1247 | const auto player_index = Service::HID::NpadIdTypeToIndex(npad_id_type); |
| 1248 | const auto& player = Settings::values.players.GetValue()[player_index]; | 1248 | const auto& player = Settings::values.players.GetValue()[player_index]; |
| 1249 | 1249 | ||
| 1250 | if (!is_initalized) { | 1250 | if (!is_initialized) { |
| 1251 | return false; | 1251 | return false; |
| 1252 | } | 1252 | } |
| 1253 | 1253 | ||
| @@ -1270,7 +1270,7 @@ Common::Input::DriverResult EmulatedController::SetPollingMode( | |||
| 1270 | EmulatedDeviceIndex device_index, Common::Input::PollingMode polling_mode) { | 1270 | EmulatedDeviceIndex device_index, Common::Input::PollingMode polling_mode) { |
| 1271 | LOG_INFO(Service_HID, "Set polling mode {}, device_index={}", polling_mode, device_index); | 1271 | LOG_INFO(Service_HID, "Set polling mode {}, device_index={}", polling_mode, device_index); |
| 1272 | 1272 | ||
| 1273 | if (!is_initalized) { | 1273 | if (!is_initialized) { |
| 1274 | return Common::Input::DriverResult::InvalidHandle; | 1274 | return Common::Input::DriverResult::InvalidHandle; |
| 1275 | } | 1275 | } |
| 1276 | 1276 | ||
| @@ -1319,7 +1319,7 @@ bool EmulatedController::SetCameraFormat( | |||
| 1319 | Core::IrSensor::ImageTransferProcessorFormat camera_format) { | 1319 | Core::IrSensor::ImageTransferProcessorFormat camera_format) { |
| 1320 | LOG_INFO(Service_HID, "Set camera format {}", camera_format); | 1320 | LOG_INFO(Service_HID, "Set camera format {}", camera_format); |
| 1321 | 1321 | ||
| 1322 | if (!is_initalized) { | 1322 | if (!is_initialized) { |
| 1323 | return false; | 1323 | return false; |
| 1324 | } | 1324 | } |
| 1325 | 1325 | ||
| @@ -1347,7 +1347,7 @@ void EmulatedController::SetRingParam(Common::ParamPackage param) { | |||
| 1347 | 1347 | ||
| 1348 | bool EmulatedController::HasNfc() const { | 1348 | bool EmulatedController::HasNfc() const { |
| 1349 | 1349 | ||
| 1350 | if (!is_initalized) { | 1350 | if (!is_initialized) { |
| 1351 | return false; | 1351 | return false; |
| 1352 | } | 1352 | } |
| 1353 | 1353 | ||
| @@ -1356,7 +1356,7 @@ bool EmulatedController::HasNfc() const { | |||
| 1356 | switch (npad_type) { | 1356 | switch (npad_type) { |
| 1357 | case NpadStyleIndex::JoyconRight: | 1357 | case NpadStyleIndex::JoyconRight: |
| 1358 | case NpadStyleIndex::JoyconDual: | 1358 | case NpadStyleIndex::JoyconDual: |
| 1359 | case NpadStyleIndex::ProController: | 1359 | case NpadStyleIndex::Fullkey: |
| 1360 | case NpadStyleIndex::Handheld: | 1360 | case NpadStyleIndex::Handheld: |
| 1361 | break; | 1361 | break; |
| 1362 | default: | 1362 | default: |
| @@ -1388,7 +1388,7 @@ bool EmulatedController::RemoveNfcHandle() { | |||
| 1388 | } | 1388 | } |
| 1389 | 1389 | ||
| 1390 | bool EmulatedController::StartNfcPolling() { | 1390 | bool EmulatedController::StartNfcPolling() { |
| 1391 | if (!is_initalized) { | 1391 | if (!is_initialized) { |
| 1392 | return false; | 1392 | return false; |
| 1393 | } | 1393 | } |
| 1394 | 1394 | ||
| @@ -1403,7 +1403,7 @@ bool EmulatedController::StartNfcPolling() { | |||
| 1403 | } | 1403 | } |
| 1404 | 1404 | ||
| 1405 | bool EmulatedController::StopNfcPolling() { | 1405 | bool EmulatedController::StopNfcPolling() { |
| 1406 | if (!is_initalized) { | 1406 | if (!is_initialized) { |
| 1407 | return false; | 1407 | return false; |
| 1408 | } | 1408 | } |
| 1409 | 1409 | ||
| @@ -1418,7 +1418,7 @@ bool EmulatedController::StopNfcPolling() { | |||
| 1418 | } | 1418 | } |
| 1419 | 1419 | ||
| 1420 | bool EmulatedController::ReadAmiiboData(std::vector<u8>& data) { | 1420 | bool EmulatedController::ReadAmiiboData(std::vector<u8>& data) { |
| 1421 | if (!is_initalized) { | 1421 | if (!is_initialized) { |
| 1422 | return false; | 1422 | return false; |
| 1423 | } | 1423 | } |
| 1424 | 1424 | ||
| @@ -1434,7 +1434,7 @@ bool EmulatedController::ReadAmiiboData(std::vector<u8>& data) { | |||
| 1434 | 1434 | ||
| 1435 | bool EmulatedController::ReadMifareData(const Common::Input::MifareRequest& request, | 1435 | bool EmulatedController::ReadMifareData(const Common::Input::MifareRequest& request, |
| 1436 | Common::Input::MifareRequest& out_data) { | 1436 | Common::Input::MifareRequest& out_data) { |
| 1437 | if (!is_initalized) { | 1437 | if (!is_initialized) { |
| 1438 | return false; | 1438 | return false; |
| 1439 | } | 1439 | } |
| 1440 | 1440 | ||
| @@ -1450,7 +1450,7 @@ bool EmulatedController::ReadMifareData(const Common::Input::MifareRequest& requ | |||
| 1450 | } | 1450 | } |
| 1451 | 1451 | ||
| 1452 | bool EmulatedController::WriteMifareData(const Common::Input::MifareRequest& request) { | 1452 | bool EmulatedController::WriteMifareData(const Common::Input::MifareRequest& request) { |
| 1453 | if (!is_initalized) { | 1453 | if (!is_initialized) { |
| 1454 | return false; | 1454 | return false; |
| 1455 | } | 1455 | } |
| 1456 | 1456 | ||
| @@ -1465,7 +1465,7 @@ bool EmulatedController::WriteMifareData(const Common::Input::MifareRequest& req | |||
| 1465 | } | 1465 | } |
| 1466 | 1466 | ||
| 1467 | bool EmulatedController::WriteNfc(const std::vector<u8>& data) { | 1467 | bool EmulatedController::WriteNfc(const std::vector<u8>& data) { |
| 1468 | if (!is_initalized) { | 1468 | if (!is_initialized) { |
| 1469 | return false; | 1469 | return false; |
| 1470 | } | 1470 | } |
| 1471 | 1471 | ||
| @@ -1480,7 +1480,7 @@ bool EmulatedController::WriteNfc(const std::vector<u8>& data) { | |||
| 1480 | } | 1480 | } |
| 1481 | 1481 | ||
| 1482 | void EmulatedController::SetLedPattern() { | 1482 | void EmulatedController::SetLedPattern() { |
| 1483 | if (!is_initalized) { | 1483 | if (!is_initialized) { |
| 1484 | return; | 1484 | return; |
| 1485 | } | 1485 | } |
| 1486 | 1486 | ||
| @@ -1508,8 +1508,8 @@ void EmulatedController::SetGyroscopeZeroDriftMode(GyroscopeZeroDriftMode mode) | |||
| 1508 | motion.emulated.SetGyroThreshold(motion.emulated.ThresholdLoose); | 1508 | motion.emulated.SetGyroThreshold(motion.emulated.ThresholdLoose); |
| 1509 | break; | 1509 | break; |
| 1510 | case GyroscopeZeroDriftMode::Tight: | 1510 | case GyroscopeZeroDriftMode::Tight: |
| 1511 | motion_sensitivity = motion.emulated.IsAtRestThight; | 1511 | motion_sensitivity = motion.emulated.IsAtRestTight; |
| 1512 | motion.emulated.SetGyroThreshold(motion.emulated.ThresholdThight); | 1512 | motion.emulated.SetGyroThreshold(motion.emulated.ThresholdTight); |
| 1513 | break; | 1513 | break; |
| 1514 | case GyroscopeZeroDriftMode::Standard: | 1514 | case GyroscopeZeroDriftMode::Standard: |
| 1515 | default: | 1515 | default: |
| @@ -1548,7 +1548,7 @@ void EmulatedController::SetSupportedNpadStyleTag(NpadStyleTag supported_styles) | |||
| 1548 | // Fallback Fullkey controllers to Pro controllers | 1548 | // Fallback Fullkey controllers to Pro controllers |
| 1549 | if (IsControllerFullkey() && supported_style_tag.fullkey) { | 1549 | if (IsControllerFullkey() && supported_style_tag.fullkey) { |
| 1550 | LOG_WARNING(Service_HID, "Reconnecting controller type {} as Pro controller", npad_type); | 1550 | LOG_WARNING(Service_HID, "Reconnecting controller type {} as Pro controller", npad_type); |
| 1551 | SetNpadStyleIndex(NpadStyleIndex::ProController); | 1551 | SetNpadStyleIndex(NpadStyleIndex::Fullkey); |
| 1552 | Connect(); | 1552 | Connect(); |
| 1553 | return; | 1553 | return; |
| 1554 | } | 1554 | } |
| @@ -1556,13 +1556,13 @@ void EmulatedController::SetSupportedNpadStyleTag(NpadStyleTag supported_styles) | |||
| 1556 | // Fallback Dual joycon controllers to Pro controllers | 1556 | // Fallback Dual joycon controllers to Pro controllers |
| 1557 | if (npad_type == NpadStyleIndex::JoyconDual && supported_style_tag.fullkey) { | 1557 | if (npad_type == NpadStyleIndex::JoyconDual && supported_style_tag.fullkey) { |
| 1558 | LOG_WARNING(Service_HID, "Reconnecting controller type {} as Pro controller", npad_type); | 1558 | LOG_WARNING(Service_HID, "Reconnecting controller type {} as Pro controller", npad_type); |
| 1559 | SetNpadStyleIndex(NpadStyleIndex::ProController); | 1559 | SetNpadStyleIndex(NpadStyleIndex::Fullkey); |
| 1560 | Connect(); | 1560 | Connect(); |
| 1561 | return; | 1561 | return; |
| 1562 | } | 1562 | } |
| 1563 | 1563 | ||
| 1564 | // Fallback Pro controllers to Dual joycon | 1564 | // Fallback Pro controllers to Dual joycon |
| 1565 | if (npad_type == NpadStyleIndex::ProController && supported_style_tag.joycon_dual) { | 1565 | if (npad_type == NpadStyleIndex::Fullkey && supported_style_tag.joycon_dual) { |
| 1566 | LOG_WARNING(Service_HID, "Reconnecting controller type {} as Dual Joycons", npad_type); | 1566 | LOG_WARNING(Service_HID, "Reconnecting controller type {} as Dual Joycons", npad_type); |
| 1567 | SetNpadStyleIndex(NpadStyleIndex::JoyconDual); | 1567 | SetNpadStyleIndex(NpadStyleIndex::JoyconDual); |
| 1568 | Connect(); | 1568 | Connect(); |
| @@ -1577,7 +1577,7 @@ bool EmulatedController::IsControllerFullkey(bool use_temporary_value) const { | |||
| 1577 | std::scoped_lock lock{mutex}; | 1577 | std::scoped_lock lock{mutex}; |
| 1578 | const auto type = is_configuring && use_temporary_value ? tmp_npad_type : npad_type; | 1578 | const auto type = is_configuring && use_temporary_value ? tmp_npad_type : npad_type; |
| 1579 | switch (type) { | 1579 | switch (type) { |
| 1580 | case NpadStyleIndex::ProController: | 1580 | case NpadStyleIndex::Fullkey: |
| 1581 | case NpadStyleIndex::GameCube: | 1581 | case NpadStyleIndex::GameCube: |
| 1582 | case NpadStyleIndex::NES: | 1582 | case NpadStyleIndex::NES: |
| 1583 | case NpadStyleIndex::SNES: | 1583 | case NpadStyleIndex::SNES: |
| @@ -1593,7 +1593,7 @@ bool EmulatedController::IsControllerSupported(bool use_temporary_value) const { | |||
| 1593 | std::scoped_lock lock{mutex}; | 1593 | std::scoped_lock lock{mutex}; |
| 1594 | const auto type = is_configuring && use_temporary_value ? tmp_npad_type : npad_type; | 1594 | const auto type = is_configuring && use_temporary_value ? tmp_npad_type : npad_type; |
| 1595 | switch (type) { | 1595 | switch (type) { |
| 1596 | case NpadStyleIndex::ProController: | 1596 | case NpadStyleIndex::Fullkey: |
| 1597 | return supported_style_tag.fullkey.As<bool>(); | 1597 | return supported_style_tag.fullkey.As<bool>(); |
| 1598 | case NpadStyleIndex::Handheld: | 1598 | case NpadStyleIndex::Handheld: |
| 1599 | return supported_style_tag.handheld.As<bool>(); | 1599 | return supported_style_tag.handheld.As<bool>(); |
diff --git a/src/hid_core/frontend/emulated_controller.h b/src/hid_core/frontend/emulated_controller.h index 94798164d..90e536e07 100644 --- a/src/hid_core/frontend/emulated_controller.h +++ b/src/hid_core/frontend/emulated_controller.h | |||
| @@ -559,7 +559,7 @@ private: | |||
| 559 | NpadStyleTag supported_style_tag{NpadStyleSet::All}; | 559 | NpadStyleTag supported_style_tag{NpadStyleSet::All}; |
| 560 | bool is_connected{false}; | 560 | bool is_connected{false}; |
| 561 | bool is_configuring{false}; | 561 | bool is_configuring{false}; |
| 562 | bool is_initalized{false}; | 562 | bool is_initialized{false}; |
| 563 | bool system_buttons_enabled{true}; | 563 | bool system_buttons_enabled{true}; |
| 564 | f32 motion_sensitivity{Core::HID::MotionInput::IsAtRestStandard}; | 564 | f32 motion_sensitivity{Core::HID::MotionInput::IsAtRestStandard}; |
| 565 | u32 turbo_button_state{0}; | 565 | u32 turbo_button_state{0}; |
diff --git a/src/hid_core/frontend/motion_input.h b/src/hid_core/frontend/motion_input.h index 11678983d..c902a3a6e 100644 --- a/src/hid_core/frontend/motion_input.h +++ b/src/hid_core/frontend/motion_input.h | |||
| @@ -13,12 +13,12 @@ class MotionInput { | |||
| 13 | public: | 13 | public: |
| 14 | static constexpr float ThresholdLoose = 0.01f; | 14 | static constexpr float ThresholdLoose = 0.01f; |
| 15 | static constexpr float ThresholdStandard = 0.007f; | 15 | static constexpr float ThresholdStandard = 0.007f; |
| 16 | static constexpr float ThresholdThight = 0.002f; | 16 | static constexpr float ThresholdTight = 0.002f; |
| 17 | 17 | ||
| 18 | static constexpr float IsAtRestRelaxed = 0.05f; | 18 | static constexpr float IsAtRestRelaxed = 0.05f; |
| 19 | static constexpr float IsAtRestLoose = 0.02f; | 19 | static constexpr float IsAtRestLoose = 0.02f; |
| 20 | static constexpr float IsAtRestStandard = 0.01f; | 20 | static constexpr float IsAtRestStandard = 0.01f; |
| 21 | static constexpr float IsAtRestThight = 0.005f; | 21 | static constexpr float IsAtRestTight = 0.005f; |
| 22 | 22 | ||
| 23 | static constexpr float GyroMaxValue = 5.0f; | 23 | static constexpr float GyroMaxValue = 5.0f; |
| 24 | static constexpr float AccelMaxValue = 7.0f; | 24 | static constexpr float AccelMaxValue = 7.0f; |
diff --git a/src/hid_core/hid_result.h b/src/hid_core/hid_result.h index bb14aa61e..df9b28c9a 100644 --- a/src/hid_core/hid_result.h +++ b/src/hid_core/hid_result.h | |||
| @@ -15,7 +15,7 @@ constexpr Result ResultVibrationNotInitialized{ErrorModule::HID, 121}; | |||
| 15 | constexpr Result ResultVibrationInvalidStyleIndex{ErrorModule::HID, 122}; | 15 | constexpr Result ResultVibrationInvalidStyleIndex{ErrorModule::HID, 122}; |
| 16 | constexpr Result ResultVibrationInvalidNpadId{ErrorModule::HID, 123}; | 16 | constexpr Result ResultVibrationInvalidNpadId{ErrorModule::HID, 123}; |
| 17 | constexpr Result ResultVibrationDeviceIndexOutOfRange{ErrorModule::HID, 124}; | 17 | constexpr Result ResultVibrationDeviceIndexOutOfRange{ErrorModule::HID, 124}; |
| 18 | constexpr Result ResultVibrationStrenghtOutOfRange{ErrorModule::HID, 126}; | 18 | constexpr Result ResultVibrationStrengthOutOfRange{ErrorModule::HID, 126}; |
| 19 | constexpr Result ResultVibrationArraySizeMismatch{ErrorModule::HID, 131}; | 19 | constexpr Result ResultVibrationArraySizeMismatch{ErrorModule::HID, 131}; |
| 20 | 20 | ||
| 21 | constexpr Result InvalidSixAxisFusionRange{ErrorModule::HID, 423}; | 21 | constexpr Result InvalidSixAxisFusionRange{ErrorModule::HID, 423}; |
diff --git a/src/hid_core/hid_types.h b/src/hid_core/hid_types.h index a81ed6af0..2c3f02f34 100644 --- a/src/hid_core/hid_types.h +++ b/src/hid_core/hid_types.h | |||
| @@ -220,6 +220,7 @@ enum class NpadIdType : u32 { | |||
| 220 | }; | 220 | }; |
| 221 | 221 | ||
| 222 | enum class NpadInterfaceType : u8 { | 222 | enum class NpadInterfaceType : u8 { |
| 223 | None = 0, | ||
| 223 | Bluetooth = 1, | 224 | Bluetooth = 1, |
| 224 | Rail = 2, | 225 | Rail = 2, |
| 225 | Usb = 3, | 226 | Usb = 3, |
| @@ -229,7 +230,7 @@ enum class NpadInterfaceType : u8 { | |||
| 229 | // This is nn::hid::NpadStyleIndex | 230 | // This is nn::hid::NpadStyleIndex |
| 230 | enum class NpadStyleIndex : u8 { | 231 | enum class NpadStyleIndex : u8 { |
| 231 | None = 0, | 232 | None = 0, |
| 232 | ProController = 3, | 233 | Fullkey = 3, |
| 233 | Handheld = 4, | 234 | Handheld = 4, |
| 234 | HandheldNES = 4, | 235 | HandheldNES = 4, |
| 235 | JoyconDual = 5, | 236 | JoyconDual = 5, |
diff --git a/src/hid_core/hid_util.h b/src/hid_core/hid_util.h index 94ff2d23a..397a87472 100644 --- a/src/hid_core/hid_util.h +++ b/src/hid_core/hid_util.h | |||
| @@ -42,7 +42,7 @@ constexpr Result IsSixaxisHandleValid(const Core::HID::SixAxisSensorHandle& hand | |||
| 42 | 42 | ||
| 43 | constexpr Result IsVibrationHandleValid(const Core::HID::VibrationDeviceHandle& handle) { | 43 | constexpr Result IsVibrationHandleValid(const Core::HID::VibrationDeviceHandle& handle) { |
| 44 | switch (handle.npad_type) { | 44 | switch (handle.npad_type) { |
| 45 | case Core::HID::NpadStyleIndex::ProController: | 45 | case Core::HID::NpadStyleIndex::Fullkey: |
| 46 | case Core::HID::NpadStyleIndex::Handheld: | 46 | case Core::HID::NpadStyleIndex::Handheld: |
| 47 | case Core::HID::NpadStyleIndex::JoyconDual: | 47 | case Core::HID::NpadStyleIndex::JoyconDual: |
| 48 | case Core::HID::NpadStyleIndex::JoyconLeft: | 48 | case Core::HID::NpadStyleIndex::JoyconLeft: |
diff --git a/src/hid_core/irsensor/irs_types.h b/src/hid_core/irsensor/irs_types.h index 017f38e6c..d7354de21 100644 --- a/src/hid_core/irsensor/irs_types.h +++ b/src/hid_core/irsensor/irs_types.h | |||
| @@ -106,8 +106,8 @@ enum class HandAnalysisMode : u32 { | |||
| 106 | None, | 106 | None, |
| 107 | Silhouette, | 107 | Silhouette, |
| 108 | Image, | 108 | Image, |
| 109 | SilhoueteAndImage, | 109 | SilhouetteAndImage, |
| 110 | SilhuetteOnly, | 110 | SilhouetteOnly, |
| 111 | }; | 111 | }; |
| 112 | 112 | ||
| 113 | // This is nn::irsensor::IrSensorFunctionLevel | 113 | // This is nn::irsensor::IrSensorFunctionLevel |
diff --git a/src/hid_core/resources/abstracted_pad/abstract_battery_handler.cpp b/src/hid_core/resources/abstracted_pad/abstract_battery_handler.cpp new file mode 100644 index 000000000..62fbbb0a7 --- /dev/null +++ b/src/hid_core/resources/abstracted_pad/abstract_battery_handler.cpp | |||
| @@ -0,0 +1,197 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-3.0-or-later | ||
| 3 | |||
| 4 | #include "core/core_timing.h" | ||
| 5 | #include "hid_core/hid_result.h" | ||
| 6 | #include "hid_core/hid_util.h" | ||
| 7 | #include "hid_core/resources/abstracted_pad/abstract_battery_handler.h" | ||
| 8 | #include "hid_core/resources/abstracted_pad/abstract_pad_holder.h" | ||
| 9 | #include "hid_core/resources/abstracted_pad/abstract_properties_handler.h" | ||
| 10 | #include "hid_core/resources/applet_resource.h" | ||
| 11 | #include "hid_core/resources/npad/npad_types.h" | ||
| 12 | #include "hid_core/resources/shared_memory_format.h" | ||
| 13 | |||
| 14 | namespace Service::HID { | ||
| 15 | |||
| 16 | NpadAbstractBatteryHandler::NpadAbstractBatteryHandler() {} | ||
| 17 | |||
| 18 | NpadAbstractBatteryHandler::~NpadAbstractBatteryHandler() = default; | ||
| 19 | |||
| 20 | void NpadAbstractBatteryHandler::SetAbstractPadHolder(NpadAbstractedPadHolder* holder) { | ||
| 21 | abstract_pad_holder = holder; | ||
| 22 | } | ||
| 23 | |||
| 24 | void NpadAbstractBatteryHandler::SetAppletResource(AppletResourceHolder* applet_resource) { | ||
| 25 | applet_resource_holder = applet_resource; | ||
| 26 | } | ||
| 27 | |||
| 28 | void NpadAbstractBatteryHandler::SetPropertiesHandler(NpadAbstractPropertiesHandler* handler) { | ||
| 29 | properties_handler = handler; | ||
| 30 | } | ||
| 31 | |||
| 32 | Result NpadAbstractBatteryHandler::IncrementRefCounter() { | ||
| 33 | if (ref_counter == std::numeric_limits<s32>::max() - 1) { | ||
| 34 | return ResultNpadHandlerOverflow; | ||
| 35 | } | ||
| 36 | ref_counter++; | ||
| 37 | return ResultSuccess; | ||
| 38 | } | ||
| 39 | |||
| 40 | Result NpadAbstractBatteryHandler::DecrementRefCounter() { | ||
| 41 | if (ref_counter == 0) { | ||
| 42 | return ResultNpadHandlerNotInitialized; | ||
| 43 | } | ||
| 44 | ref_counter--; | ||
| 45 | return ResultSuccess; | ||
| 46 | } | ||
| 47 | |||
| 48 | Result NpadAbstractBatteryHandler::UpdateBatteryState(u64 aruid) { | ||
| 49 | const auto npad_index = NpadIdTypeToIndex(properties_handler->GetNpadId()); | ||
| 50 | AruidData* aruid_data = applet_resource_holder->applet_resource->GetAruidData(aruid); | ||
| 51 | if (aruid_data == nullptr) { | ||
| 52 | return ResultSuccess; | ||
| 53 | } | ||
| 54 | |||
| 55 | auto& npad_internal_state = | ||
| 56 | aruid_data->shared_memory_format->npad.npad_entry[npad_index].internal_state; | ||
| 57 | auto& system_properties = npad_internal_state.system_properties; | ||
| 58 | |||
| 59 | system_properties.is_charging_joy_dual.Assign(dual_battery.is_charging); | ||
| 60 | system_properties.is_powered_joy_dual.Assign(dual_battery.is_powered); | ||
| 61 | system_properties.is_charging_joy_left.Assign(left_battery.is_charging); | ||
| 62 | system_properties.is_powered_joy_left.Assign(left_battery.is_powered); | ||
| 63 | system_properties.is_charging_joy_right.Assign(right_battery.is_charging); | ||
| 64 | system_properties.is_powered_joy_right.Assign(right_battery.is_powered); | ||
| 65 | |||
| 66 | npad_internal_state.battery_level_dual = dual_battery.battery_level; | ||
| 67 | npad_internal_state.battery_level_left = left_battery.battery_level; | ||
| 68 | npad_internal_state.battery_level_right = right_battery.battery_level; | ||
| 69 | |||
| 70 | return ResultSuccess; | ||
| 71 | } | ||
| 72 | |||
| 73 | void NpadAbstractBatteryHandler::UpdateBatteryState() { | ||
| 74 | if (ref_counter == 0) { | ||
| 75 | return; | ||
| 76 | } | ||
| 77 | has_new_battery_data = GetNewBatteryState(); | ||
| 78 | } | ||
| 79 | |||
| 80 | bool NpadAbstractBatteryHandler::GetNewBatteryState() { | ||
| 81 | bool has_changed = false; | ||
| 82 | Core::HID::NpadPowerInfo new_dual_battery_state{}; | ||
| 83 | Core::HID::NpadPowerInfo new_left_battery_state{}; | ||
| 84 | Core::HID::NpadPowerInfo new_right_battery_state{}; | ||
| 85 | std::array<IAbstractedPad*, 5> abstract_pads{}; | ||
| 86 | const std::size_t count = abstract_pad_holder->GetAbstractedPads(abstract_pads); | ||
| 87 | |||
| 88 | for (std::size_t i = 0; i < count; i++) { | ||
| 89 | auto* abstract_pad = abstract_pads[i]; | ||
| 90 | if (!abstract_pad->internal_flags.is_connected) { | ||
| 91 | continue; | ||
| 92 | } | ||
| 93 | const auto power_info = abstract_pad->power_info; | ||
| 94 | if (power_info.battery_level > Core::HID::NpadBatteryLevel::Full) { | ||
| 95 | // Abort | ||
| 96 | continue; | ||
| 97 | } | ||
| 98 | |||
| 99 | const auto style = abstract_pad->assignment_style; | ||
| 100 | |||
| 101 | if (style.is_external_assigned || style.is_handheld_assigned) { | ||
| 102 | new_dual_battery_state = power_info; | ||
| 103 | } | ||
| 104 | if (style.is_external_left_assigned || style.is_handheld_left_assigned) { | ||
| 105 | new_left_battery_state = power_info; | ||
| 106 | } | ||
| 107 | if (style.is_external_right_assigned || style.is_handheld_right_assigned) { | ||
| 108 | new_right_battery_state = power_info; | ||
| 109 | } | ||
| 110 | |||
| 111 | if (abstract_pad->internal_flags.is_battery_low_ovln_required) { | ||
| 112 | if (abstract_pad->interface_type == Core::HID::NpadInterfaceType::Rail) { | ||
| 113 | // TODO | ||
| 114 | } | ||
| 115 | abstract_pad->internal_flags.is_battery_low_ovln_required.Assign(false); | ||
| 116 | } | ||
| 117 | } | ||
| 118 | |||
| 119 | if (dual_battery.battery_level != new_dual_battery_state.battery_level || | ||
| 120 | dual_battery.is_charging != new_dual_battery_state.is_charging || | ||
| 121 | dual_battery.is_powered != new_dual_battery_state.is_powered) { | ||
| 122 | has_changed = true; | ||
| 123 | dual_battery = new_dual_battery_state; | ||
| 124 | } | ||
| 125 | |||
| 126 | if (left_battery.battery_level != new_left_battery_state.battery_level || | ||
| 127 | left_battery.is_charging != new_left_battery_state.is_charging || | ||
| 128 | left_battery.is_powered != new_left_battery_state.is_powered) { | ||
| 129 | has_changed = true; | ||
| 130 | left_battery = new_left_battery_state; | ||
| 131 | } | ||
| 132 | |||
| 133 | if (right_battery.battery_level != new_right_battery_state.battery_level || | ||
| 134 | right_battery.is_charging != new_right_battery_state.is_charging || | ||
| 135 | right_battery.is_powered != new_right_battery_state.is_powered) { | ||
| 136 | has_changed = true; | ||
| 137 | right_battery = new_right_battery_state; | ||
| 138 | } | ||
| 139 | |||
| 140 | return has_changed; | ||
| 141 | } | ||
| 142 | |||
| 143 | void NpadAbstractBatteryHandler::UpdateCoreBatteryState() { | ||
| 144 | if (ref_counter == 0) { | ||
| 145 | return; | ||
| 146 | } | ||
| 147 | if (!has_new_battery_data) { | ||
| 148 | return; | ||
| 149 | } | ||
| 150 | |||
| 151 | UpdateBatteryState(0); | ||
| 152 | } | ||
| 153 | |||
| 154 | void NpadAbstractBatteryHandler::InitializeBatteryState(u64 aruid) { | ||
| 155 | UpdateBatteryState(aruid); | ||
| 156 | } | ||
| 157 | |||
| 158 | bool NpadAbstractBatteryHandler::HasBattery() const { | ||
| 159 | std::array<IAbstractedPad*, 5> abstract_pads{}; | ||
| 160 | const std::size_t count = abstract_pad_holder->GetAbstractedPads(abstract_pads); | ||
| 161 | |||
| 162 | for (std::size_t i = 0; i < count; i++) { | ||
| 163 | const auto* abstract_pad = abstract_pads[i]; | ||
| 164 | if (!abstract_pad->internal_flags.is_connected) { | ||
| 165 | continue; | ||
| 166 | } | ||
| 167 | return abstract_pad->disabled_feature_set.has_fullkey_battery || | ||
| 168 | abstract_pad->disabled_feature_set.has_left_right_joy_battery; | ||
| 169 | } | ||
| 170 | |||
| 171 | return false; | ||
| 172 | } | ||
| 173 | |||
| 174 | void NpadAbstractBatteryHandler::HasLeftRightBattery(bool& has_left, bool& has_right) const { | ||
| 175 | std::array<IAbstractedPad*, 5> abstract_pads{}; | ||
| 176 | const std::size_t count = abstract_pad_holder->GetAbstractedPads(abstract_pads); | ||
| 177 | |||
| 178 | has_left = false; | ||
| 179 | has_right = false; | ||
| 180 | |||
| 181 | for (std::size_t i = 0; i < count; i++) { | ||
| 182 | const auto* abstract_pad = abstract_pads[i]; | ||
| 183 | if (!abstract_pad->internal_flags.is_connected) { | ||
| 184 | continue; | ||
| 185 | } | ||
| 186 | if (!abstract_pad->disabled_feature_set.has_fullkey_battery && | ||
| 187 | !abstract_pad->disabled_feature_set.has_left_right_joy_battery) { | ||
| 188 | continue; | ||
| 189 | } | ||
| 190 | has_left = abstract_pad->assignment_style.is_external_left_assigned || | ||
| 191 | abstract_pad->assignment_style.is_handheld_left_assigned; | ||
| 192 | has_right = abstract_pad->assignment_style.is_external_right_assigned || | ||
| 193 | abstract_pad->assignment_style.is_handheld_right_assigned; | ||
| 194 | } | ||
| 195 | } | ||
| 196 | |||
| 197 | } // namespace Service::HID | ||
diff --git a/src/hid_core/resources/abstracted_pad/abstract_battery_handler.h b/src/hid_core/resources/abstracted_pad/abstract_battery_handler.h new file mode 100644 index 000000000..85ac5eb72 --- /dev/null +++ b/src/hid_core/resources/abstracted_pad/abstract_battery_handler.h | |||
| @@ -0,0 +1,49 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-3.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include "common/common_types.h" | ||
| 7 | #include "core/hle/result.h" | ||
| 8 | #include "hid_core/hid_types.h" | ||
| 9 | |||
| 10 | namespace Service::HID { | ||
| 11 | struct AppletResourceHolder; | ||
| 12 | class NpadAbstractedPadHolder; | ||
| 13 | class NpadAbstractPropertiesHandler; | ||
| 14 | |||
| 15 | /// Handles Npad request from HID interfaces | ||
| 16 | class NpadAbstractBatteryHandler final { | ||
| 17 | public: | ||
| 18 | explicit NpadAbstractBatteryHandler(); | ||
| 19 | ~NpadAbstractBatteryHandler(); | ||
| 20 | |||
| 21 | void SetAbstractPadHolder(NpadAbstractedPadHolder* holder); | ||
| 22 | void SetAppletResource(AppletResourceHolder* applet_resource); | ||
| 23 | void SetPropertiesHandler(NpadAbstractPropertiesHandler* handler); | ||
| 24 | |||
| 25 | Result IncrementRefCounter(); | ||
| 26 | Result DecrementRefCounter(); | ||
| 27 | |||
| 28 | Result UpdateBatteryState(u64 aruid); | ||
| 29 | void UpdateBatteryState(); | ||
| 30 | bool GetNewBatteryState(); | ||
| 31 | void UpdateCoreBatteryState(); | ||
| 32 | void InitializeBatteryState(u64 aruid); | ||
| 33 | |||
| 34 | bool HasBattery() const; | ||
| 35 | void HasLeftRightBattery(bool& has_left, bool& has_right) const; | ||
| 36 | |||
| 37 | private: | ||
| 38 | AppletResourceHolder* applet_resource_holder{nullptr}; | ||
| 39 | NpadAbstractedPadHolder* abstract_pad_holder{nullptr}; | ||
| 40 | NpadAbstractPropertiesHandler* properties_handler{nullptr}; | ||
| 41 | |||
| 42 | s32 ref_counter{}; | ||
| 43 | Core::HID::NpadPowerInfo dual_battery{}; | ||
| 44 | Core::HID::NpadPowerInfo left_battery{}; | ||
| 45 | Core::HID::NpadPowerInfo right_battery{}; | ||
| 46 | bool has_new_battery_data{}; | ||
| 47 | }; | ||
| 48 | |||
| 49 | } // namespace Service::HID | ||
diff --git a/src/hid_core/resources/abstracted_pad/abstract_button_handler.cpp b/src/hid_core/resources/abstracted_pad/abstract_button_handler.cpp new file mode 100644 index 000000000..587169433 --- /dev/null +++ b/src/hid_core/resources/abstracted_pad/abstract_button_handler.cpp | |||
| @@ -0,0 +1,199 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-3.0-or-later | ||
| 3 | |||
| 4 | #include "hid_core/hid_result.h" | ||
| 5 | #include "hid_core/hid_util.h" | ||
| 6 | #include "hid_core/resources/abstracted_pad/abstract_button_handler.h" | ||
| 7 | #include "hid_core/resources/abstracted_pad/abstract_pad_holder.h" | ||
| 8 | #include "hid_core/resources/abstracted_pad/abstract_properties_handler.h" | ||
| 9 | #include "hid_core/resources/applet_resource.h" | ||
| 10 | #include "hid_core/resources/npad/npad_resource.h" | ||
| 11 | #include "hid_core/resources/npad/npad_types.h" | ||
| 12 | #include "hid_core/resources/shared_memory_format.h" | ||
| 13 | |||
| 14 | namespace Service::HID { | ||
| 15 | |||
| 16 | NpadAbstractButtonHandler::NpadAbstractButtonHandler() {} | ||
| 17 | |||
| 18 | NpadAbstractButtonHandler::~NpadAbstractButtonHandler() = default; | ||
| 19 | |||
| 20 | void NpadAbstractButtonHandler::SetAbstractPadHolder(NpadAbstractedPadHolder* holder) { | ||
| 21 | abstract_pad_holder = holder; | ||
| 22 | } | ||
| 23 | |||
| 24 | void NpadAbstractButtonHandler::SetAppletResource(AppletResourceHolder* applet_resource) { | ||
| 25 | applet_resource_holder = applet_resource; | ||
| 26 | } | ||
| 27 | |||
| 28 | void NpadAbstractButtonHandler::SetPropertiesHandler(NpadAbstractPropertiesHandler* handler) { | ||
| 29 | properties_handler = handler; | ||
| 30 | } | ||
| 31 | |||
| 32 | Result NpadAbstractButtonHandler::IncrementRefCounter() { | ||
| 33 | if (ref_counter == std::numeric_limits<s32>::max() - 1) { | ||
| 34 | return ResultNpadHandlerOverflow; | ||
| 35 | } | ||
| 36 | ref_counter++; | ||
| 37 | return ResultSuccess; | ||
| 38 | } | ||
| 39 | |||
| 40 | Result NpadAbstractButtonHandler::DecrementRefCounter() { | ||
| 41 | if (ref_counter == 0) { | ||
| 42 | return ResultNpadHandlerNotInitialized; | ||
| 43 | } | ||
| 44 | ref_counter--; | ||
| 45 | return ResultSuccess; | ||
| 46 | } | ||
| 47 | |||
| 48 | Result NpadAbstractButtonHandler::UpdateAllButtonWithHomeProtection(u64 aruid) { | ||
| 49 | const Core::HID::NpadIdType npad_id = properties_handler->GetNpadId(); | ||
| 50 | auto* data = applet_resource_holder->applet_resource->GetAruidData(aruid); | ||
| 51 | |||
| 52 | if (data == nullptr) { | ||
| 53 | return ResultSuccess; | ||
| 54 | } | ||
| 55 | |||
| 56 | auto& npad_entry = data->shared_memory_format->npad.npad_entry[NpadIdTypeToIndex(npad_id)]; | ||
| 57 | UpdateButtonLifo(npad_entry, aruid); | ||
| 58 | |||
| 59 | bool is_home_button_protection_enabled{}; | ||
| 60 | const auto result = applet_resource_holder->shared_npad_resource->GetHomeProtectionEnabled( | ||
| 61 | is_home_button_protection_enabled, aruid, npad_id); | ||
| 62 | |||
| 63 | if (result.IsError()) { | ||
| 64 | return ResultSuccess; | ||
| 65 | } | ||
| 66 | |||
| 67 | npad_entry.internal_state.button_properties.is_home_button_protection_enabled.Assign( | ||
| 68 | is_home_button_protection_enabled); | ||
| 69 | |||
| 70 | return ResultSuccess; | ||
| 71 | } | ||
| 72 | |||
| 73 | void NpadAbstractButtonHandler::UpdateAllButtonLifo() { | ||
| 74 | Core::HID::NpadIdType npad_id = properties_handler->GetNpadId(); | ||
| 75 | for (std::size_t i = 0; i < AruidIndexMax; i++) { | ||
| 76 | auto* data = applet_resource_holder->applet_resource->GetAruidDataByIndex(i); | ||
| 77 | auto& npad_entry = data->shared_memory_format->npad.npad_entry[NpadIdTypeToIndex(npad_id)]; | ||
| 78 | UpdateButtonLifo(npad_entry, data->aruid); | ||
| 79 | } | ||
| 80 | } | ||
| 81 | |||
| 82 | void NpadAbstractButtonHandler::UpdateCoreBatteryState() { | ||
| 83 | Core::HID::NpadIdType npad_id = properties_handler->GetNpadId(); | ||
| 84 | for (std::size_t i = 0; i < AruidIndexMax; i++) { | ||
| 85 | auto* data = applet_resource_holder->applet_resource->GetAruidDataByIndex(i); | ||
| 86 | auto& npad_entry = data->shared_memory_format->npad.npad_entry[NpadIdTypeToIndex(npad_id)]; | ||
| 87 | UpdateButtonLifo(npad_entry, data->aruid); | ||
| 88 | } | ||
| 89 | } | ||
| 90 | |||
| 91 | void NpadAbstractButtonHandler::UpdateButtonState(u64 aruid) { | ||
| 92 | Core::HID::NpadIdType npad_id = properties_handler->GetNpadId(); | ||
| 93 | auto* data = applet_resource_holder->applet_resource->GetAruidData(aruid); | ||
| 94 | if (data == nullptr) { | ||
| 95 | return; | ||
| 96 | } | ||
| 97 | auto& npad_entry = data->shared_memory_format->npad.npad_entry[NpadIdTypeToIndex(npad_id)]; | ||
| 98 | UpdateButtonLifo(npad_entry, aruid); | ||
| 99 | } | ||
| 100 | |||
| 101 | Result NpadAbstractButtonHandler::SetHomeProtection(bool is_enabled, u64 aruid) { | ||
| 102 | const Core::HID::NpadIdType npad_id = properties_handler->GetNpadId(); | ||
| 103 | auto result = applet_resource_holder->shared_npad_resource->SetHomeProtectionEnabled( | ||
| 104 | aruid, npad_id, is_enabled); | ||
| 105 | if (result.IsError()) { | ||
| 106 | return result; | ||
| 107 | } | ||
| 108 | |||
| 109 | auto* data = applet_resource_holder->applet_resource->GetAruidData(aruid); | ||
| 110 | if (data == nullptr) { | ||
| 111 | return ResultSuccess; | ||
| 112 | } | ||
| 113 | |||
| 114 | bool is_home_protection_enabled{}; | ||
| 115 | result = applet_resource_holder->shared_npad_resource->GetHomeProtectionEnabled( | ||
| 116 | is_home_protection_enabled, aruid, npad_id); | ||
| 117 | if (result.IsError()) { | ||
| 118 | return ResultSuccess; | ||
| 119 | } | ||
| 120 | |||
| 121 | auto& npad_entry = data->shared_memory_format->npad.npad_entry[NpadIdTypeToIndex(npad_id)]; | ||
| 122 | npad_entry.internal_state.button_properties.is_home_button_protection_enabled.Assign( | ||
| 123 | is_home_protection_enabled); | ||
| 124 | return ResultSuccess; | ||
| 125 | } | ||
| 126 | |||
| 127 | bool NpadAbstractButtonHandler::IsButtonPressedOnConsoleMode() { | ||
| 128 | return is_button_pressed_on_console_mode; | ||
| 129 | } | ||
| 130 | |||
| 131 | void NpadAbstractButtonHandler::EnableCenterClamp() { | ||
| 132 | std::array<IAbstractedPad*, 5> abstract_pads{}; | ||
| 133 | const std::size_t count = abstract_pad_holder->GetAbstractedPads(abstract_pads); | ||
| 134 | |||
| 135 | for (std::size_t i = 0; i < count; i++) { | ||
| 136 | auto* abstract_pad = abstract_pads[i]; | ||
| 137 | if (!abstract_pad->internal_flags.is_connected) { | ||
| 138 | continue; | ||
| 139 | } | ||
| 140 | abstract_pad->internal_flags.use_center_clamp.Assign(true); | ||
| 141 | } | ||
| 142 | } | ||
| 143 | |||
| 144 | void NpadAbstractButtonHandler::UpdateButtonLifo(NpadSharedMemoryEntry& shared_memory, u64 aruid) { | ||
| 145 | auto* npad_resource = applet_resource_holder->shared_npad_resource; | ||
| 146 | Core::HID::NpadStyleTag style_tag = {properties_handler->GetStyleSet(aruid)}; | ||
| 147 | style_tag.system_ext.Assign(npad_resource->GetActiveData()->GetNpadSystemExtState()); | ||
| 148 | |||
| 149 | UpdateNpadFullkeyLifo(style_tag, 0, aruid, shared_memory); | ||
| 150 | UpdateHandheldLifo(style_tag, 1, aruid, shared_memory); | ||
| 151 | UpdateJoyconDualLifo(style_tag, 2, aruid, shared_memory); | ||
| 152 | UpdateJoyconLeftLifo(style_tag, 3, aruid, shared_memory); | ||
| 153 | UpdateJoyconRightLifo(style_tag, 4, aruid, shared_memory); | ||
| 154 | UpdatePalmaLifo(style_tag, 5, aruid, shared_memory); | ||
| 155 | UpdateSystemExtLifo(style_tag, 6, aruid, shared_memory); | ||
| 156 | } | ||
| 157 | |||
| 158 | void NpadAbstractButtonHandler::UpdateNpadFullkeyLifo(Core::HID::NpadStyleTag style_tag, | ||
| 159 | int style_index, u64 aruid, | ||
| 160 | NpadSharedMemoryEntry& shared_memory) { | ||
| 161 | // TODO | ||
| 162 | } | ||
| 163 | |||
| 164 | void NpadAbstractButtonHandler::UpdateHandheldLifo(Core::HID::NpadStyleTag style_tag, | ||
| 165 | int style_index, u64 aruid, | ||
| 166 | NpadSharedMemoryEntry& shared_memory) { | ||
| 167 | // TODO | ||
| 168 | } | ||
| 169 | |||
| 170 | void NpadAbstractButtonHandler::UpdateJoyconDualLifo(Core::HID::NpadStyleTag style_tag, | ||
| 171 | int style_index, u64 aruid, | ||
| 172 | NpadSharedMemoryEntry& shared_memory) { | ||
| 173 | // TODO | ||
| 174 | } | ||
| 175 | |||
| 176 | void NpadAbstractButtonHandler::UpdateJoyconLeftLifo(Core::HID::NpadStyleTag style_tag, | ||
| 177 | int style_index, u64 aruid, | ||
| 178 | NpadSharedMemoryEntry& shared_memory) { | ||
| 179 | // TODO | ||
| 180 | } | ||
| 181 | |||
| 182 | void NpadAbstractButtonHandler::UpdateJoyconRightLifo(Core::HID::NpadStyleTag style_tag, | ||
| 183 | int style_index, u64 aruid, | ||
| 184 | NpadSharedMemoryEntry& shared_memory) { | ||
| 185 | // TODO | ||
| 186 | } | ||
| 187 | |||
| 188 | void NpadAbstractButtonHandler::UpdateSystemExtLifo(Core::HID::NpadStyleTag style_tag, | ||
| 189 | int style_index, u64 aruid, | ||
| 190 | NpadSharedMemoryEntry& shared_memory) { | ||
| 191 | // TODO | ||
| 192 | } | ||
| 193 | |||
| 194 | void NpadAbstractButtonHandler::UpdatePalmaLifo(Core::HID::NpadStyleTag style_tag, int style_index, | ||
| 195 | u64 aruid, NpadSharedMemoryEntry& shared_memory) { | ||
| 196 | // TODO | ||
| 197 | } | ||
| 198 | |||
| 199 | } // namespace Service::HID | ||
diff --git a/src/hid_core/resources/abstracted_pad/abstract_button_handler.h b/src/hid_core/resources/abstracted_pad/abstract_button_handler.h new file mode 100644 index 000000000..01eafe96d --- /dev/null +++ b/src/hid_core/resources/abstracted_pad/abstract_button_handler.h | |||
| @@ -0,0 +1,75 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-3.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include "common/common_types.h" | ||
| 7 | #include "core/hle/result.h" | ||
| 8 | #include "hid_core/hid_types.h" | ||
| 9 | |||
| 10 | namespace Service::HID { | ||
| 11 | struct NpadSharedMemoryEntry; | ||
| 12 | |||
| 13 | struct AppletResourceHolder; | ||
| 14 | class NpadAbstractedPadHolder; | ||
| 15 | class NpadAbstractPropertiesHandler; | ||
| 16 | |||
| 17 | /// Handles Npad request from HID interfaces | ||
| 18 | class NpadAbstractButtonHandler final { | ||
| 19 | public: | ||
| 20 | explicit NpadAbstractButtonHandler(); | ||
| 21 | ~NpadAbstractButtonHandler(); | ||
| 22 | |||
| 23 | void SetAbstractPadHolder(NpadAbstractedPadHolder* holder); | ||
| 24 | void SetAppletResource(AppletResourceHolder* applet_resource); | ||
| 25 | void SetPropertiesHandler(NpadAbstractPropertiesHandler* handler); | ||
| 26 | |||
| 27 | Result IncrementRefCounter(); | ||
| 28 | Result DecrementRefCounter(); | ||
| 29 | |||
| 30 | Result UpdateAllButtonWithHomeProtection(u64 aruid); | ||
| 31 | |||
| 32 | void UpdateAllButtonLifo(); | ||
| 33 | void UpdateCoreBatteryState(); | ||
| 34 | void UpdateButtonState(u64 aruid); | ||
| 35 | |||
| 36 | Result SetHomeProtection(bool is_enabled, u64 aruid); | ||
| 37 | bool IsButtonPressedOnConsoleMode(); | ||
| 38 | void EnableCenterClamp(); | ||
| 39 | |||
| 40 | void UpdateButtonLifo(NpadSharedMemoryEntry& shared_memory, u64 aruid); | ||
| 41 | |||
| 42 | void UpdateNpadFullkeyLifo(Core::HID::NpadStyleTag style_tag, int index, u64 aruid, | ||
| 43 | NpadSharedMemoryEntry& shared_memory); | ||
| 44 | void UpdateHandheldLifo(Core::HID::NpadStyleTag style_tag, int index, u64 aruid, | ||
| 45 | NpadSharedMemoryEntry& shared_memory); | ||
| 46 | void UpdateJoyconDualLifo(Core::HID::NpadStyleTag style_tag, int index, u64 aruid, | ||
| 47 | NpadSharedMemoryEntry& shared_memory); | ||
| 48 | void UpdateJoyconLeftLifo(Core::HID::NpadStyleTag style_tag, int index, u64 aruid, | ||
| 49 | NpadSharedMemoryEntry& shared_memory); | ||
| 50 | void UpdateJoyconRightLifo(Core::HID::NpadStyleTag style_tag, int index, u64 aruid, | ||
| 51 | NpadSharedMemoryEntry& shared_memory); | ||
| 52 | void UpdateSystemExtLifo(Core::HID::NpadStyleTag style_tag, int index, u64 aruid, | ||
| 53 | NpadSharedMemoryEntry& shared_memory); | ||
| 54 | void UpdatePalmaLifo(Core::HID::NpadStyleTag style_tag, int index, u64 aruid, | ||
| 55 | NpadSharedMemoryEntry& shared_memory); | ||
| 56 | |||
| 57 | private: | ||
| 58 | struct GcTrigger { | ||
| 59 | float left; | ||
| 60 | float right; | ||
| 61 | }; | ||
| 62 | |||
| 63 | AppletResourceHolder* applet_resource_holder{nullptr}; | ||
| 64 | NpadAbstractedPadHolder* abstract_pad_holder{nullptr}; | ||
| 65 | NpadAbstractPropertiesHandler* properties_handler{nullptr}; | ||
| 66 | |||
| 67 | s32 ref_counter{}; | ||
| 68 | |||
| 69 | bool is_button_pressed_on_console_mode{}; | ||
| 70 | |||
| 71 | u64 gc_sampling_number{}; | ||
| 72 | GcTrigger gc_trigger_state{}; | ||
| 73 | }; | ||
| 74 | |||
| 75 | } // namespace Service::HID | ||
diff --git a/src/hid_core/resources/abstracted_pad/abstract_ir_sensor_handler.cpp b/src/hid_core/resources/abstracted_pad/abstract_ir_sensor_handler.cpp new file mode 100644 index 000000000..d4e4181bf --- /dev/null +++ b/src/hid_core/resources/abstracted_pad/abstract_ir_sensor_handler.cpp | |||
| @@ -0,0 +1,126 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-3.0-or-later | ||
| 3 | |||
| 4 | #include "core/hle/kernel/k_event.h" | ||
| 5 | #include "core/hle/kernel/k_readable_event.h" | ||
| 6 | #include "hid_core/hid_result.h" | ||
| 7 | #include "hid_core/resources/abstracted_pad/abstract_ir_sensor_handler.h" | ||
| 8 | #include "hid_core/resources/abstracted_pad/abstract_pad_holder.h" | ||
| 9 | #include "hid_core/resources/abstracted_pad/abstract_properties_handler.h" | ||
| 10 | #include "hid_core/resources/npad/npad_types.h" | ||
| 11 | |||
| 12 | namespace Service::HID { | ||
| 13 | |||
| 14 | NpadAbstractIrSensorHandler::NpadAbstractIrSensorHandler() {} | ||
| 15 | |||
| 16 | NpadAbstractIrSensorHandler::~NpadAbstractIrSensorHandler() = default; | ||
| 17 | |||
| 18 | void NpadAbstractIrSensorHandler::SetAbstractPadHolder(NpadAbstractedPadHolder* holder) { | ||
| 19 | abstract_pad_holder = holder; | ||
| 20 | } | ||
| 21 | |||
| 22 | void NpadAbstractIrSensorHandler::SetPropertiesHandler(NpadAbstractPropertiesHandler* handler) { | ||
| 23 | properties_handler = handler; | ||
| 24 | } | ||
| 25 | |||
| 26 | Result NpadAbstractIrSensorHandler::IncrementRefCounter() { | ||
| 27 | if (ref_counter == std::numeric_limits<s32>::max() - 1) { | ||
| 28 | return ResultNpadHandlerOverflow; | ||
| 29 | } | ||
| 30 | ref_counter++; | ||
| 31 | return ResultSuccess; | ||
| 32 | } | ||
| 33 | |||
| 34 | Result NpadAbstractIrSensorHandler::DecrementRefCounter() { | ||
| 35 | if (ref_counter == 0) { | ||
| 36 | return ResultNpadHandlerNotInitialized; | ||
| 37 | } | ||
| 38 | ref_counter--; | ||
| 39 | return ResultSuccess; | ||
| 40 | } | ||
| 41 | |||
| 42 | void NpadAbstractIrSensorHandler::UpdateIrSensorState() { | ||
| 43 | const auto previous_state = sensor_state; | ||
| 44 | std::array<IAbstractedPad*, 5> abstract_pads{}; | ||
| 45 | const std::size_t count = abstract_pad_holder->GetAbstractedPads(abstract_pads); | ||
| 46 | |||
| 47 | if (count == 0) { | ||
| 48 | sensor_state = NpadIrSensorState::Disabled; | ||
| 49 | if (sensor_state == previous_state) { | ||
| 50 | return; | ||
| 51 | } | ||
| 52 | ir_sensor_event->Signal(); | ||
| 53 | return; | ||
| 54 | } | ||
| 55 | |||
| 56 | bool is_found{}; | ||
| 57 | for (std::size_t i = 0; i < count; i++) { | ||
| 58 | auto* abstract_pad = abstract_pads[i]; | ||
| 59 | if (!abstract_pad->internal_flags.is_connected) { | ||
| 60 | continue; | ||
| 61 | } | ||
| 62 | if (!abstract_pad->disabled_feature_set.has_bluetooth_address) { | ||
| 63 | continue; | ||
| 64 | } | ||
| 65 | is_found = true; | ||
| 66 | xcd_handle = abstract_pad->xcd_handle; | ||
| 67 | } | ||
| 68 | |||
| 69 | if (is_found) { | ||
| 70 | if (sensor_state == NpadIrSensorState::Active) { | ||
| 71 | return; | ||
| 72 | } | ||
| 73 | sensor_state = NpadIrSensorState::Available; | ||
| 74 | if (sensor_state == previous_state) { | ||
| 75 | return; | ||
| 76 | } | ||
| 77 | ir_sensor_event->Signal(); | ||
| 78 | return; | ||
| 79 | } | ||
| 80 | |||
| 81 | sensor_state = NpadIrSensorState::Unavailable; | ||
| 82 | if (sensor_state == previous_state) { | ||
| 83 | return; | ||
| 84 | } | ||
| 85 | |||
| 86 | ir_sensor_event->Signal(); | ||
| 87 | return; | ||
| 88 | } | ||
| 89 | |||
| 90 | Result NpadAbstractIrSensorHandler::ActivateIrSensor(bool is_enabled) { | ||
| 91 | if (sensor_state == NpadIrSensorState::Unavailable) { | ||
| 92 | return ResultIrSensorIsNotReady; | ||
| 93 | } | ||
| 94 | if (is_enabled && sensor_state == NpadIrSensorState::Available) { | ||
| 95 | sensor_state = NpadIrSensorState::Active; | ||
| 96 | } else { | ||
| 97 | if (is_enabled) { | ||
| 98 | return ResultSuccess; | ||
| 99 | } | ||
| 100 | if (sensor_state != NpadIrSensorState::Active) { | ||
| 101 | return ResultSuccess; | ||
| 102 | } | ||
| 103 | sensor_state = NpadIrSensorState::Available; | ||
| 104 | } | ||
| 105 | ir_sensor_event->Signal(); | ||
| 106 | return ResultSuccess; | ||
| 107 | } | ||
| 108 | |||
| 109 | Result NpadAbstractIrSensorHandler::GetIrSensorEventHandle(Kernel::KReadableEvent** out_event) { | ||
| 110 | *out_event = &ir_sensor_event->GetReadableEvent(); | ||
| 111 | return ResultSuccess; | ||
| 112 | } | ||
| 113 | |||
| 114 | Result NpadAbstractIrSensorHandler::GetXcdHandleForNpadWithIrSensor(u64& handle) const { | ||
| 115 | if (sensor_state < NpadIrSensorState::Available) { | ||
| 116 | return ResultIrSensorIsNotReady; | ||
| 117 | } | ||
| 118 | handle = xcd_handle; | ||
| 119 | return ResultSuccess; | ||
| 120 | } | ||
| 121 | |||
| 122 | NpadIrSensorState NpadAbstractIrSensorHandler::GetSensorState() const { | ||
| 123 | return sensor_state; | ||
| 124 | } | ||
| 125 | |||
| 126 | } // namespace Service::HID | ||
diff --git a/src/hid_core/resources/abstracted_pad/abstract_ir_sensor_handler.h b/src/hid_core/resources/abstracted_pad/abstract_ir_sensor_handler.h new file mode 100644 index 000000000..fe8e005af --- /dev/null +++ b/src/hid_core/resources/abstracted_pad/abstract_ir_sensor_handler.h | |||
| @@ -0,0 +1,56 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-3.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include "common/common_types.h" | ||
| 7 | #include "core/hle/result.h" | ||
| 8 | #include "hid_core/hid_types.h" | ||
| 9 | |||
| 10 | namespace Kernel { | ||
| 11 | class KEvent; | ||
| 12 | class KReadableEvent; | ||
| 13 | } // namespace Kernel | ||
| 14 | |||
| 15 | enum class NpadIrSensorState : u32 { | ||
| 16 | Disabled, | ||
| 17 | Unavailable, | ||
| 18 | Available, | ||
| 19 | Active, | ||
| 20 | }; | ||
| 21 | |||
| 22 | namespace Service::HID { | ||
| 23 | class NpadAbstractedPadHolder; | ||
| 24 | class NpadAbstractPropertiesHandler; | ||
| 25 | |||
| 26 | /// Handles Npad request from HID interfaces | ||
| 27 | class NpadAbstractIrSensorHandler final { | ||
| 28 | public: | ||
| 29 | explicit NpadAbstractIrSensorHandler(); | ||
| 30 | ~NpadAbstractIrSensorHandler(); | ||
| 31 | |||
| 32 | void SetAbstractPadHolder(NpadAbstractedPadHolder* holder); | ||
| 33 | void SetPropertiesHandler(NpadAbstractPropertiesHandler* handler); | ||
| 34 | |||
| 35 | Result IncrementRefCounter(); | ||
| 36 | Result DecrementRefCounter(); | ||
| 37 | |||
| 38 | void UpdateIrSensorState(); | ||
| 39 | Result ActivateIrSensor(bool param_2); | ||
| 40 | |||
| 41 | Result GetIrSensorEventHandle(Kernel::KReadableEvent** out_event); | ||
| 42 | |||
| 43 | Result GetXcdHandleForNpadWithIrSensor(u64& handle) const; | ||
| 44 | |||
| 45 | NpadIrSensorState GetSensorState() const; | ||
| 46 | |||
| 47 | private: | ||
| 48 | NpadAbstractedPadHolder* abstract_pad_holder{nullptr}; | ||
| 49 | NpadAbstractPropertiesHandler* properties_handler{nullptr}; | ||
| 50 | |||
| 51 | s32 ref_counter{}; | ||
| 52 | Kernel::KEvent* ir_sensor_event{nullptr}; | ||
| 53 | u64 xcd_handle{}; | ||
| 54 | NpadIrSensorState sensor_state{}; | ||
| 55 | }; | ||
| 56 | } // namespace Service::HID | ||
diff --git a/src/hid_core/resources/abstracted_pad/abstract_led_handler.cpp b/src/hid_core/resources/abstracted_pad/abstract_led_handler.cpp new file mode 100644 index 000000000..0b2bfe88d --- /dev/null +++ b/src/hid_core/resources/abstracted_pad/abstract_led_handler.cpp | |||
| @@ -0,0 +1,123 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-3.0-or-later | ||
| 3 | |||
| 4 | #include "core/core_timing.h" | ||
| 5 | #include "hid_core/hid_result.h" | ||
| 6 | #include "hid_core/hid_util.h" | ||
| 7 | #include "hid_core/resources/abstracted_pad/abstract_led_handler.h" | ||
| 8 | #include "hid_core/resources/abstracted_pad/abstract_pad_holder.h" | ||
| 9 | #include "hid_core/resources/abstracted_pad/abstract_properties_handler.h" | ||
| 10 | #include "hid_core/resources/applet_resource.h" | ||
| 11 | #include "hid_core/resources/npad/npad_types.h" | ||
| 12 | |||
| 13 | namespace Service::HID { | ||
| 14 | |||
| 15 | NpadAbstractLedHandler::NpadAbstractLedHandler() {} | ||
| 16 | |||
| 17 | NpadAbstractLedHandler::~NpadAbstractLedHandler() = default; | ||
| 18 | |||
| 19 | void NpadAbstractLedHandler::SetAbstractPadHolder(NpadAbstractedPadHolder* holder) { | ||
| 20 | abstract_pad_holder = holder; | ||
| 21 | } | ||
| 22 | |||
| 23 | void NpadAbstractLedHandler::SetAppletResource(AppletResourceHolder* applet_resource) { | ||
| 24 | applet_resource_holder = applet_resource; | ||
| 25 | } | ||
| 26 | |||
| 27 | void NpadAbstractLedHandler::SetPropertiesHandler(NpadAbstractPropertiesHandler* handler) { | ||
| 28 | properties_handler = handler; | ||
| 29 | } | ||
| 30 | |||
| 31 | Result NpadAbstractLedHandler::IncrementRefCounter() { | ||
| 32 | if (ref_counter == std::numeric_limits<s32>::max() - 1) { | ||
| 33 | return ResultNpadHandlerOverflow; | ||
| 34 | } | ||
| 35 | ref_counter++; | ||
| 36 | return ResultSuccess; | ||
| 37 | } | ||
| 38 | |||
| 39 | Result NpadAbstractLedHandler::DecrementRefCounter() { | ||
| 40 | if (ref_counter == 0) { | ||
| 41 | return ResultNpadHandlerNotInitialized; | ||
| 42 | } | ||
| 43 | ref_counter--; | ||
| 44 | return ResultSuccess; | ||
| 45 | } | ||
| 46 | |||
| 47 | void NpadAbstractLedHandler::SetNpadLedHandlerLedPattern() { | ||
| 48 | const auto npad_id = properties_handler->GetNpadId(); | ||
| 49 | |||
| 50 | switch (npad_id) { | ||
| 51 | case Core::HID::NpadIdType::Player1: | ||
| 52 | left_pattern = Core::HID::LedPattern{1, 0, 0, 0}; | ||
| 53 | break; | ||
| 54 | case Core::HID::NpadIdType::Player2: | ||
| 55 | left_pattern = Core::HID::LedPattern{1, 1, 0, 0}; | ||
| 56 | break; | ||
| 57 | case Core::HID::NpadIdType::Player3: | ||
| 58 | left_pattern = Core::HID::LedPattern{1, 1, 1, 0}; | ||
| 59 | break; | ||
| 60 | case Core::HID::NpadIdType::Player4: | ||
| 61 | left_pattern = Core::HID::LedPattern{1, 1, 1, 1}; | ||
| 62 | break; | ||
| 63 | case Core::HID::NpadIdType::Player5: | ||
| 64 | left_pattern = Core::HID::LedPattern{1, 0, 0, 1}; | ||
| 65 | break; | ||
| 66 | case Core::HID::NpadIdType::Player6: | ||
| 67 | left_pattern = Core::HID::LedPattern{1, 0, 1, 0}; | ||
| 68 | break; | ||
| 69 | case Core::HID::NpadIdType::Player7: | ||
| 70 | left_pattern = Core::HID::LedPattern{1, 0, 1, 1}; | ||
| 71 | break; | ||
| 72 | case Core::HID::NpadIdType::Player8: | ||
| 73 | left_pattern = Core::HID::LedPattern{0, 1, 1, 0}; | ||
| 74 | break; | ||
| 75 | case Core::HID::NpadIdType::Other: | ||
| 76 | case Core::HID::NpadIdType::Handheld: | ||
| 77 | left_pattern = Core::HID::LedPattern{0, 0, 0, 0}; | ||
| 78 | break; | ||
| 79 | default: | ||
| 80 | ASSERT_MSG(false, "Invalid npad id type"); | ||
| 81 | break; | ||
| 82 | } | ||
| 83 | |||
| 84 | switch (npad_id) { | ||
| 85 | case Core::HID::NpadIdType::Player1: | ||
| 86 | right_pattern = Core::HID::LedPattern{0, 0, 0, 1}; | ||
| 87 | break; | ||
| 88 | case Core::HID::NpadIdType::Player2: | ||
| 89 | right_pattern = Core::HID::LedPattern{0, 1, 1, 1}; | ||
| 90 | break; | ||
| 91 | case Core::HID::NpadIdType::Player3: | ||
| 92 | right_pattern = Core::HID::LedPattern{0, 1, 1, 1}; | ||
| 93 | break; | ||
| 94 | case Core::HID::NpadIdType::Player4: | ||
| 95 | right_pattern = Core::HID::LedPattern{1, 1, 1, 1}; | ||
| 96 | break; | ||
| 97 | case Core::HID::NpadIdType::Player5: | ||
| 98 | right_pattern = Core::HID::LedPattern{1, 0, 0, 1}; | ||
| 99 | break; | ||
| 100 | case Core::HID::NpadIdType::Player6: | ||
| 101 | right_pattern = Core::HID::LedPattern{0, 1, 0, 1}; | ||
| 102 | break; | ||
| 103 | case Core::HID::NpadIdType::Player7: | ||
| 104 | right_pattern = Core::HID::LedPattern{1, 1, 0, 1}; | ||
| 105 | break; | ||
| 106 | case Core::HID::NpadIdType::Player8: | ||
| 107 | right_pattern = Core::HID::LedPattern{0, 1, 1, 0}; | ||
| 108 | break; | ||
| 109 | case Core::HID::NpadIdType::Other: | ||
| 110 | case Core::HID::NpadIdType::Handheld: | ||
| 111 | right_pattern = Core::HID::LedPattern{0, 0, 0, 0}; | ||
| 112 | break; | ||
| 113 | default: | ||
| 114 | ASSERT_MSG(false, "Invalid npad id type"); | ||
| 115 | break; | ||
| 116 | } | ||
| 117 | } | ||
| 118 | |||
| 119 | void NpadAbstractLedHandler::SetLedBlinkingDevice(Core::HID::LedPattern pattern) { | ||
| 120 | led_blinking = pattern; | ||
| 121 | } | ||
| 122 | |||
| 123 | } // namespace Service::HID | ||
diff --git a/src/hid_core/resources/abstracted_pad/abstract_led_handler.h b/src/hid_core/resources/abstracted_pad/abstract_led_handler.h new file mode 100644 index 000000000..09528129b --- /dev/null +++ b/src/hid_core/resources/abstracted_pad/abstract_led_handler.h | |||
| @@ -0,0 +1,43 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-3.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include "common/common_types.h" | ||
| 7 | #include "core/hle/result.h" | ||
| 8 | #include "hid_core/hid_types.h" | ||
| 9 | |||
| 10 | namespace Service::HID { | ||
| 11 | struct AppletResourceHolder; | ||
| 12 | class NpadAbstractedPadHolder; | ||
| 13 | class NpadAbstractPropertiesHandler; | ||
| 14 | |||
| 15 | /// Handles Npad request from HID interfaces | ||
| 16 | class NpadAbstractLedHandler final { | ||
| 17 | public: | ||
| 18 | explicit NpadAbstractLedHandler(); | ||
| 19 | ~NpadAbstractLedHandler(); | ||
| 20 | |||
| 21 | void SetAbstractPadHolder(NpadAbstractedPadHolder* holder); | ||
| 22 | void SetAppletResource(AppletResourceHolder* applet_resource); | ||
| 23 | void SetPropertiesHandler(NpadAbstractPropertiesHandler* handler); | ||
| 24 | |||
| 25 | Result IncrementRefCounter(); | ||
| 26 | Result DecrementRefCounter(); | ||
| 27 | |||
| 28 | void SetNpadLedHandlerLedPattern(); | ||
| 29 | |||
| 30 | void SetLedBlinkingDevice(Core::HID::LedPattern pattern); | ||
| 31 | |||
| 32 | private: | ||
| 33 | AppletResourceHolder* applet_resource_holder{nullptr}; | ||
| 34 | NpadAbstractedPadHolder* abstract_pad_holder{nullptr}; | ||
| 35 | NpadAbstractPropertiesHandler* properties_handler{nullptr}; | ||
| 36 | |||
| 37 | s32 ref_counter{}; | ||
| 38 | Core::HID::LedPattern led_blinking{0, 0, 0, 0}; | ||
| 39 | Core::HID::LedPattern left_pattern{0, 0, 0, 0}; | ||
| 40 | Core::HID::LedPattern right_pattern{0, 0, 0, 0}; | ||
| 41 | u64 led_interval{}; | ||
| 42 | }; | ||
| 43 | } // namespace Service::HID | ||
diff --git a/src/hid_core/resources/abstracted_pad/abstract_mcu_handler.cpp b/src/hid_core/resources/abstracted_pad/abstract_mcu_handler.cpp new file mode 100644 index 000000000..6f35bd95c --- /dev/null +++ b/src/hid_core/resources/abstracted_pad/abstract_mcu_handler.cpp | |||
| @@ -0,0 +1,108 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-3.0-or-later | ||
| 3 | |||
| 4 | #include "hid_core/hid_result.h" | ||
| 5 | #include "hid_core/resources/abstracted_pad/abstract_mcu_handler.h" | ||
| 6 | #include "hid_core/resources/abstracted_pad/abstract_pad_holder.h" | ||
| 7 | #include "hid_core/resources/abstracted_pad/abstract_properties_handler.h" | ||
| 8 | #include "hid_core/resources/npad/npad_types.h" | ||
| 9 | |||
| 10 | namespace Service::HID { | ||
| 11 | |||
| 12 | NpadAbstractMcuHandler::NpadAbstractMcuHandler() {} | ||
| 13 | |||
| 14 | NpadAbstractMcuHandler::~NpadAbstractMcuHandler() = default; | ||
| 15 | |||
| 16 | void NpadAbstractMcuHandler::SetAbstractPadHolder(NpadAbstractedPadHolder* holder) { | ||
| 17 | abstract_pad_holder = holder; | ||
| 18 | } | ||
| 19 | |||
| 20 | void NpadAbstractMcuHandler::SetPropertiesHandler(NpadAbstractPropertiesHandler* handler) { | ||
| 21 | properties_handler = handler; | ||
| 22 | } | ||
| 23 | |||
| 24 | Result NpadAbstractMcuHandler::IncrementRefCounter() { | ||
| 25 | if (ref_counter == std::numeric_limits<s32>::max() - 1) { | ||
| 26 | return ResultNpadHandlerOverflow; | ||
| 27 | } | ||
| 28 | ref_counter++; | ||
| 29 | return ResultSuccess; | ||
| 30 | } | ||
| 31 | |||
| 32 | Result NpadAbstractMcuHandler::DecrementRefCounter() { | ||
| 33 | if (ref_counter == 0) { | ||
| 34 | return ResultNpadHandlerNotInitialized; | ||
| 35 | } | ||
| 36 | ref_counter--; | ||
| 37 | return ResultSuccess; | ||
| 38 | } | ||
| 39 | |||
| 40 | void NpadAbstractMcuHandler::UpdateMcuState() { | ||
| 41 | std::array<IAbstractedPad*, 5> abstract_pads{}; | ||
| 42 | const std::size_t count = properties_handler->GetAbstractedPads(abstract_pads); | ||
| 43 | |||
| 44 | if (count == 0) { | ||
| 45 | mcu_holder = {}; | ||
| 46 | return; | ||
| 47 | } | ||
| 48 | |||
| 49 | for (std::size_t i = 0; i < count; i++) { | ||
| 50 | auto* abstract_pad = abstract_pads[i]; | ||
| 51 | if (!abstract_pad->internal_flags.is_connected) { | ||
| 52 | continue; | ||
| 53 | } | ||
| 54 | if (!abstract_pad->disabled_feature_set.has_left_joy_rail_bus) { | ||
| 55 | if (!abstract_pad->disabled_feature_set.has_left_joy_six_axis_sensor && | ||
| 56 | !abstract_pad->disabled_feature_set.has_right_joy_six_axis_sensor) { | ||
| 57 | continue; | ||
| 58 | } | ||
| 59 | if (mcu_holder[1].state != NpadMcuState::Active) { | ||
| 60 | mcu_holder[1].state = NpadMcuState::Available; | ||
| 61 | } | ||
| 62 | mcu_holder[1].abstracted_pad = abstract_pad; | ||
| 63 | continue; | ||
| 64 | } | ||
| 65 | if (mcu_holder[0].state != NpadMcuState::Active) { | ||
| 66 | mcu_holder[0].state = NpadMcuState::Available; | ||
| 67 | } | ||
| 68 | mcu_holder[0].abstracted_pad = abstract_pad; | ||
| 69 | } | ||
| 70 | } | ||
| 71 | |||
| 72 | Result NpadAbstractMcuHandler::GetAbstractedPad(IAbstractedPad** data, u32 mcu_index) { | ||
| 73 | if (mcu_holder[mcu_index].state == NpadMcuState::None || | ||
| 74 | mcu_holder[mcu_index].abstracted_pad == nullptr) { | ||
| 75 | return ResultMcuIsNotReady; | ||
| 76 | } | ||
| 77 | *data = mcu_holder[mcu_index].abstracted_pad; | ||
| 78 | return ResultSuccess; | ||
| 79 | } | ||
| 80 | |||
| 81 | NpadMcuState NpadAbstractMcuHandler::GetMcuState(u32 mcu_index) { | ||
| 82 | return mcu_holder[mcu_index].state; | ||
| 83 | } | ||
| 84 | |||
| 85 | Result NpadAbstractMcuHandler::SetMcuState(bool is_enabled, u32 mcu_index) { | ||
| 86 | NpadMcuState& state = mcu_holder[mcu_index].state; | ||
| 87 | |||
| 88 | if (state == NpadMcuState::None) { | ||
| 89 | return ResultMcuIsNotReady; | ||
| 90 | } | ||
| 91 | |||
| 92 | if ((is_enabled) && (state == NpadMcuState::Available)) { | ||
| 93 | state = NpadMcuState::Active; | ||
| 94 | return ResultSuccess; | ||
| 95 | } | ||
| 96 | |||
| 97 | if (is_enabled) { | ||
| 98 | return ResultSuccess; | ||
| 99 | } | ||
| 100 | if (state != NpadMcuState::Active) { | ||
| 101 | return ResultSuccess; | ||
| 102 | } | ||
| 103 | |||
| 104 | state = NpadMcuState::Available; | ||
| 105 | return ResultSuccess; | ||
| 106 | } | ||
| 107 | |||
| 108 | } // namespace Service::HID | ||
diff --git a/src/hid_core/resources/abstracted_pad/abstract_mcu_handler.h b/src/hid_core/resources/abstracted_pad/abstract_mcu_handler.h new file mode 100644 index 000000000..9902dd03a --- /dev/null +++ b/src/hid_core/resources/abstracted_pad/abstract_mcu_handler.h | |||
| @@ -0,0 +1,52 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-3.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include "common/common_types.h" | ||
| 7 | #include "core/hle/result.h" | ||
| 8 | #include "hid_core/hid_types.h" | ||
| 9 | |||
| 10 | namespace Service::HID { | ||
| 11 | struct IAbstractedPad; | ||
| 12 | class NpadAbstractedPadHolder; | ||
| 13 | class NpadAbstractPropertiesHandler; | ||
| 14 | |||
| 15 | enum class NpadMcuState : u32 { | ||
| 16 | None, | ||
| 17 | Available, | ||
| 18 | Active, | ||
| 19 | }; | ||
| 20 | |||
| 21 | struct NpadMcuHolder { | ||
| 22 | NpadMcuState state; | ||
| 23 | INSERT_PADDING_BYTES(0x4); | ||
| 24 | IAbstractedPad* abstracted_pad; | ||
| 25 | }; | ||
| 26 | static_assert(sizeof(NpadMcuHolder) == 0x10, "NpadMcuHolder is an invalid size"); | ||
| 27 | |||
| 28 | /// Handles Npad request from HID interfaces | ||
| 29 | class NpadAbstractMcuHandler final { | ||
| 30 | public: | ||
| 31 | explicit NpadAbstractMcuHandler(); | ||
| 32 | ~NpadAbstractMcuHandler(); | ||
| 33 | |||
| 34 | void SetAbstractPadHolder(NpadAbstractedPadHolder* holder); | ||
| 35 | void SetPropertiesHandler(NpadAbstractPropertiesHandler* handler); | ||
| 36 | |||
| 37 | Result IncrementRefCounter(); | ||
| 38 | Result DecrementRefCounter(); | ||
| 39 | |||
| 40 | void UpdateMcuState(); | ||
| 41 | Result GetAbstractedPad(IAbstractedPad** data, u32 mcu_index); | ||
| 42 | NpadMcuState GetMcuState(u32 mcu_index); | ||
| 43 | Result SetMcuState(bool is_enabled, u32 mcu_index); | ||
| 44 | |||
| 45 | private: | ||
| 46 | NpadAbstractedPadHolder* abstract_pad_holder{nullptr}; | ||
| 47 | NpadAbstractPropertiesHandler* properties_handler{nullptr}; | ||
| 48 | |||
| 49 | s32 ref_counter{}; | ||
| 50 | std::array<NpadMcuHolder, 2> mcu_holder{}; | ||
| 51 | }; | ||
| 52 | } // namespace Service::HID | ||
diff --git a/src/hid_core/resources/abstracted_pad/abstract_nfc_handler.cpp b/src/hid_core/resources/abstracted_pad/abstract_nfc_handler.cpp new file mode 100644 index 000000000..bd9b79333 --- /dev/null +++ b/src/hid_core/resources/abstracted_pad/abstract_nfc_handler.cpp | |||
| @@ -0,0 +1,140 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-3.0-or-later | ||
| 3 | |||
| 4 | #include "core/hle/kernel/k_event.h" | ||
| 5 | #include "core/hle/kernel/k_readable_event.h" | ||
| 6 | #include "hid_core/hid_result.h" | ||
| 7 | #include "hid_core/resources/abstracted_pad/abstract_nfc_handler.h" | ||
| 8 | #include "hid_core/resources/abstracted_pad/abstract_pad_holder.h" | ||
| 9 | #include "hid_core/resources/abstracted_pad/abstract_properties_handler.h" | ||
| 10 | #include "hid_core/resources/npad/npad_types.h" | ||
| 11 | |||
| 12 | namespace Service::HID { | ||
| 13 | |||
| 14 | NpadAbstractNfcHandler::NpadAbstractNfcHandler() {} | ||
| 15 | |||
| 16 | NpadAbstractNfcHandler::~NpadAbstractNfcHandler() = default; | ||
| 17 | |||
| 18 | void NpadAbstractNfcHandler::SetAbstractPadHolder(NpadAbstractedPadHolder* holder) { | ||
| 19 | abstract_pad_holder = holder; | ||
| 20 | } | ||
| 21 | |||
| 22 | void NpadAbstractNfcHandler::SetPropertiesHandler(NpadAbstractPropertiesHandler* handler) { | ||
| 23 | properties_handler = handler; | ||
| 24 | } | ||
| 25 | |||
| 26 | Result NpadAbstractNfcHandler::IncrementRefCounter() { | ||
| 27 | if (ref_counter == std::numeric_limits<s32>::max() - 1) { | ||
| 28 | return ResultNpadHandlerOverflow; | ||
| 29 | } | ||
| 30 | ref_counter++; | ||
| 31 | return ResultSuccess; | ||
| 32 | } | ||
| 33 | |||
| 34 | Result NpadAbstractNfcHandler::DecrementRefCounter() { | ||
| 35 | if (ref_counter == 0) { | ||
| 36 | return ResultNpadHandlerNotInitialized; | ||
| 37 | } | ||
| 38 | ref_counter--; | ||
| 39 | return ResultSuccess; | ||
| 40 | } | ||
| 41 | |||
| 42 | void NpadAbstractNfcHandler::UpdateNfcState() { | ||
| 43 | std::array<IAbstractedPad*, 5> abstract_pads{}; | ||
| 44 | const std::size_t count = properties_handler->GetAbstractedPads(abstract_pads); | ||
| 45 | |||
| 46 | if (count == 0) { | ||
| 47 | if (sensor_state == NpadNfcState::Active) { | ||
| 48 | nfc_activate_event->Signal(); | ||
| 49 | } | ||
| 50 | if (sensor_state == NpadNfcState::Unavailable) { | ||
| 51 | return; | ||
| 52 | } | ||
| 53 | sensor_state = NpadNfcState::Unavailable; | ||
| 54 | input_event->Signal(); | ||
| 55 | return; | ||
| 56 | } | ||
| 57 | |||
| 58 | bool is_found{}; | ||
| 59 | for (std::size_t i = 0; i < count; i++) { | ||
| 60 | auto* abstract_pad = abstract_pads[i]; | ||
| 61 | if (!abstract_pad->internal_flags.is_connected) { | ||
| 62 | continue; | ||
| 63 | } | ||
| 64 | if (!abstract_pad->disabled_feature_set.has_nfc) { | ||
| 65 | continue; | ||
| 66 | } | ||
| 67 | is_found = true; | ||
| 68 | xcd_handle = 0; | ||
| 69 | } | ||
| 70 | |||
| 71 | if (is_found) { | ||
| 72 | if (sensor_state == NpadNfcState::Active) { | ||
| 73 | return; | ||
| 74 | } | ||
| 75 | if (sensor_state == NpadNfcState::Available) { | ||
| 76 | return; | ||
| 77 | } | ||
| 78 | sensor_state = NpadNfcState::Available; | ||
| 79 | input_event->Signal(); | ||
| 80 | return; | ||
| 81 | } | ||
| 82 | |||
| 83 | if (sensor_state == NpadNfcState::Active) { | ||
| 84 | nfc_activate_event->Signal(); | ||
| 85 | } | ||
| 86 | if (sensor_state == NpadNfcState::Unavailable) { | ||
| 87 | return; | ||
| 88 | } | ||
| 89 | sensor_state = NpadNfcState::Unavailable; | ||
| 90 | input_event->Signal(); | ||
| 91 | return; | ||
| 92 | } | ||
| 93 | |||
| 94 | bool NpadAbstractNfcHandler::HasNfcSensor() { | ||
| 95 | return sensor_state != NpadNfcState::Unavailable; | ||
| 96 | } | ||
| 97 | |||
| 98 | bool NpadAbstractNfcHandler::IsNfcActivated() { | ||
| 99 | return sensor_state == NpadNfcState::Active; | ||
| 100 | } | ||
| 101 | |||
| 102 | Result NpadAbstractNfcHandler::GetAcquireNfcActivateEventHandle( | ||
| 103 | Kernel::KReadableEvent** out_event) { | ||
| 104 | *out_event = &nfc_activate_event->GetReadableEvent(); | ||
| 105 | return ResultSuccess; | ||
| 106 | } | ||
| 107 | |||
| 108 | void NpadAbstractNfcHandler::SetInputEvent(Kernel::KEvent* event) { | ||
| 109 | input_event = event; | ||
| 110 | } | ||
| 111 | |||
| 112 | Result NpadAbstractNfcHandler::ActivateNfc(bool is_enabled) { | ||
| 113 | if (sensor_state == NpadNfcState::Active) { | ||
| 114 | return ResultNfcIsNotReady; | ||
| 115 | } | ||
| 116 | |||
| 117 | NpadNfcState new_state = NpadNfcState::Available; | ||
| 118 | if (is_enabled) { | ||
| 119 | new_state = NpadNfcState::Active; | ||
| 120 | } | ||
| 121 | if (sensor_state != new_state) { | ||
| 122 | sensor_state = new_state; | ||
| 123 | nfc_activate_event->Signal(); | ||
| 124 | } | ||
| 125 | return ResultSuccess; | ||
| 126 | } | ||
| 127 | |||
| 128 | Result NpadAbstractNfcHandler::GetXcdHandleWithNfc(u64& out_xcd_handle) const { | ||
| 129 | if (sensor_state == NpadNfcState::Unavailable) { | ||
| 130 | return ResultNfcIsNotReady; | ||
| 131 | } | ||
| 132 | if (xcd_handle == 0) { | ||
| 133 | return ResultNfcXcdHandleIsNotInitialized; | ||
| 134 | } | ||
| 135 | |||
| 136 | out_xcd_handle = xcd_handle; | ||
| 137 | return ResultSuccess; | ||
| 138 | } | ||
| 139 | |||
| 140 | } // namespace Service::HID | ||
diff --git a/src/hid_core/resources/abstracted_pad/abstract_nfc_handler.h b/src/hid_core/resources/abstracted_pad/abstract_nfc_handler.h new file mode 100644 index 000000000..0702722a6 --- /dev/null +++ b/src/hid_core/resources/abstracted_pad/abstract_nfc_handler.h | |||
| @@ -0,0 +1,57 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-3.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include "common/common_types.h" | ||
| 7 | #include "core/hle/result.h" | ||
| 8 | #include "hid_core/hid_types.h" | ||
| 9 | |||
| 10 | namespace Kernel { | ||
| 11 | class KReadableEvent; | ||
| 12 | } | ||
| 13 | |||
| 14 | enum class NpadNfcState : u32 { | ||
| 15 | Unavailable, | ||
| 16 | Available, | ||
| 17 | Active, | ||
| 18 | }; | ||
| 19 | |||
| 20 | namespace Service::HID { | ||
| 21 | class NpadAbstractedPadHolder; | ||
| 22 | class NpadAbstractPropertiesHandler; | ||
| 23 | |||
| 24 | /// Handles Npad request from HID interfaces | ||
| 25 | class NpadAbstractNfcHandler final { | ||
| 26 | public: | ||
| 27 | explicit NpadAbstractNfcHandler(); | ||
| 28 | ~NpadAbstractNfcHandler(); | ||
| 29 | |||
| 30 | void SetAbstractPadHolder(NpadAbstractedPadHolder* holder); | ||
| 31 | void SetPropertiesHandler(NpadAbstractPropertiesHandler* handler); | ||
| 32 | |||
| 33 | Result IncrementRefCounter(); | ||
| 34 | Result DecrementRefCounter(); | ||
| 35 | |||
| 36 | void UpdateNfcState(); | ||
| 37 | bool HasNfcSensor(); | ||
| 38 | bool IsNfcActivated(); | ||
| 39 | |||
| 40 | Result GetAcquireNfcActivateEventHandle(Kernel::KReadableEvent** out_event); | ||
| 41 | void SetInputEvent(Kernel::KEvent* event); | ||
| 42 | |||
| 43 | Result ActivateNfc(bool is_enabled); | ||
| 44 | |||
| 45 | Result GetXcdHandleWithNfc(u64& out_xcd_handle) const; | ||
| 46 | |||
| 47 | private: | ||
| 48 | NpadAbstractedPadHolder* abstract_pad_holder{nullptr}; | ||
| 49 | NpadAbstractPropertiesHandler* properties_handler{nullptr}; | ||
| 50 | |||
| 51 | s32 ref_counter{}; | ||
| 52 | Kernel::KEvent* nfc_activate_event{nullptr}; | ||
| 53 | Kernel::KEvent* input_event{nullptr}; | ||
| 54 | u64 xcd_handle{}; | ||
| 55 | NpadNfcState sensor_state{NpadNfcState::Unavailable}; | ||
| 56 | }; | ||
| 57 | } // namespace Service::HID | ||
diff --git a/src/hid_core/resources/abstracted_pad/abstract_pad.cpp b/src/hid_core/resources/abstracted_pad/abstract_pad.cpp new file mode 100644 index 000000000..2c7691d7c --- /dev/null +++ b/src/hid_core/resources/abstracted_pad/abstract_pad.cpp | |||
| @@ -0,0 +1,294 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-3.0-or-later | ||
| 3 | |||
| 4 | #include "hid_core/hid_result.h" | ||
| 5 | #include "hid_core/resources/abstracted_pad/abstract_pad.h" | ||
| 6 | #include "hid_core/resources/applet_resource.h" | ||
| 7 | #include "hid_core/resources/npad/npad_types.h" | ||
| 8 | |||
| 9 | namespace Service::HID { | ||
| 10 | |||
| 11 | AbstractPad::AbstractPad() {} | ||
| 12 | |||
| 13 | AbstractPad::~AbstractPad() = default; | ||
| 14 | |||
| 15 | void AbstractPad::SetExternals(AppletResourceHolder* applet_resource, | ||
| 16 | CaptureButtonResource* capture_button_resource, | ||
| 17 | HomeButtonResource* home_button_resource, | ||
| 18 | SixAxisResource* sixaxis_resource, PalmaResource* palma_resource, | ||
| 19 | VibrationHandler* vibration) { | ||
| 20 | applet_resource_holder = applet_resource; | ||
| 21 | |||
| 22 | properties_handler.SetAppletResource(applet_resource_holder); | ||
| 23 | properties_handler.SetAbstractPadHolder(&abstract_pad_holder); | ||
| 24 | |||
| 25 | led_handler.SetAppletResource(applet_resource_holder); | ||
| 26 | led_handler.SetAbstractPadHolder(&abstract_pad_holder); | ||
| 27 | led_handler.SetPropertiesHandler(&properties_handler); | ||
| 28 | |||
| 29 | ir_sensor_handler.SetAbstractPadHolder(&abstract_pad_holder); | ||
| 30 | ir_sensor_handler.SetPropertiesHandler(&properties_handler); | ||
| 31 | |||
| 32 | nfc_handler.SetAbstractPadHolder(&abstract_pad_holder); | ||
| 33 | nfc_handler.SetPropertiesHandler(&properties_handler); | ||
| 34 | |||
| 35 | mcu_handler.SetAbstractPadHolder(&abstract_pad_holder); | ||
| 36 | mcu_handler.SetPropertiesHandler(&properties_handler); | ||
| 37 | |||
| 38 | std::array<NpadVibrationDevice*, 2> vibration_devices{&vibration_left, &vibration_right}; | ||
| 39 | vibration_handler.SetAppletResource(applet_resource_holder); | ||
| 40 | vibration_handler.SetAbstractPadHolder(&abstract_pad_holder); | ||
| 41 | vibration_handler.SetPropertiesHandler(&properties_handler); | ||
| 42 | vibration_handler.SetN64Vibration(&vibration_n64); | ||
| 43 | vibration_handler.SetVibration(vibration_devices); | ||
| 44 | vibration_handler.SetGcVibration(&vibration_gc); | ||
| 45 | |||
| 46 | sixaxis_handler.SetAppletResource(applet_resource_holder); | ||
| 47 | sixaxis_handler.SetAbstractPadHolder(&abstract_pad_holder); | ||
| 48 | sixaxis_handler.SetPropertiesHandler(&properties_handler); | ||
| 49 | sixaxis_handler.SetSixaxisResource(sixaxis_resource); | ||
| 50 | |||
| 51 | button_handler.SetAppletResource(applet_resource_holder); | ||
| 52 | button_handler.SetAbstractPadHolder(&abstract_pad_holder); | ||
| 53 | button_handler.SetPropertiesHandler(&properties_handler); | ||
| 54 | |||
| 55 | battery_handler.SetAppletResource(applet_resource_holder); | ||
| 56 | battery_handler.SetAbstractPadHolder(&abstract_pad_holder); | ||
| 57 | battery_handler.SetPropertiesHandler(&properties_handler); | ||
| 58 | |||
| 59 | palma_handler.SetAbstractPadHolder(&abstract_pad_holder); | ||
| 60 | palma_handler.SetPropertiesHandler(&properties_handler); | ||
| 61 | palma_handler.SetPalmaResource(palma_resource); | ||
| 62 | } | ||
| 63 | |||
| 64 | void AbstractPad::SetNpadId(Core::HID::NpadIdType npad_id) { | ||
| 65 | properties_handler.SetNpadId(npad_id); | ||
| 66 | } | ||
| 67 | |||
| 68 | Result AbstractPad::Activate() { | ||
| 69 | if (ref_counter == std::numeric_limits<s32>::max() - 1) { | ||
| 70 | return ResultNpadHandlerOverflow; | ||
| 71 | } | ||
| 72 | |||
| 73 | if (ref_counter != 0) { | ||
| 74 | ref_counter++; | ||
| 75 | return ResultSuccess; | ||
| 76 | } | ||
| 77 | |||
| 78 | std::size_t stage = 0; | ||
| 79 | Result result = ResultSuccess; | ||
| 80 | |||
| 81 | if (result.IsSuccess()) { | ||
| 82 | stage++; | ||
| 83 | result = properties_handler.IncrementRefCounter(); | ||
| 84 | } | ||
| 85 | if (result.IsSuccess()) { | ||
| 86 | stage++; | ||
| 87 | result = led_handler.IncrementRefCounter(); | ||
| 88 | } | ||
| 89 | if (result.IsSuccess()) { | ||
| 90 | stage++; | ||
| 91 | result = ir_sensor_handler.IncrementRefCounter(); | ||
| 92 | } | ||
| 93 | if (result.IsSuccess()) { | ||
| 94 | stage++; | ||
| 95 | result = mcu_handler.IncrementRefCounter(); | ||
| 96 | } | ||
| 97 | if (result.IsSuccess()) { | ||
| 98 | stage++; | ||
| 99 | result = nfc_handler.IncrementRefCounter(); | ||
| 100 | } | ||
| 101 | if (result.IsSuccess()) { | ||
| 102 | stage++; | ||
| 103 | result = vibration_handler.IncrementRefCounter(); | ||
| 104 | } | ||
| 105 | if (result.IsSuccess()) { | ||
| 106 | stage++; | ||
| 107 | result = sixaxis_handler.IncrementRefCounter(); | ||
| 108 | } | ||
| 109 | if (result.IsSuccess()) { | ||
| 110 | stage++; | ||
| 111 | result = button_handler.IncrementRefCounter(); | ||
| 112 | } | ||
| 113 | if (result.IsSuccess()) { | ||
| 114 | stage++; | ||
| 115 | result = battery_handler.IncrementRefCounter(); | ||
| 116 | } | ||
| 117 | if (result.IsSuccess()) { | ||
| 118 | stage++; | ||
| 119 | result = palma_handler.IncrementRefCounter(); | ||
| 120 | } | ||
| 121 | |||
| 122 | if (result.IsSuccess()) { | ||
| 123 | ref_counter++; | ||
| 124 | return result; | ||
| 125 | } | ||
| 126 | |||
| 127 | if (stage > 9) { | ||
| 128 | battery_handler.DecrementRefCounter(); | ||
| 129 | } | ||
| 130 | if (stage > 8) { | ||
| 131 | button_handler.DecrementRefCounter(); | ||
| 132 | } | ||
| 133 | if (stage > 7) { | ||
| 134 | sixaxis_handler.DecrementRefCounter(); | ||
| 135 | } | ||
| 136 | if (stage > 6) { | ||
| 137 | vibration_handler.DecrementRefCounter(); | ||
| 138 | } | ||
| 139 | if (stage > 5) { | ||
| 140 | nfc_handler.DecrementRefCounter(); | ||
| 141 | } | ||
| 142 | if (stage > 4) { | ||
| 143 | mcu_handler.DecrementRefCounter(); | ||
| 144 | } | ||
| 145 | if (stage > 3) { | ||
| 146 | ir_sensor_handler.DecrementRefCounter(); | ||
| 147 | } | ||
| 148 | if (stage > 2) { | ||
| 149 | led_handler.DecrementRefCounter(); | ||
| 150 | } | ||
| 151 | if (stage > 1) { | ||
| 152 | properties_handler.DecrementRefCounter(); | ||
| 153 | } | ||
| 154 | return result; | ||
| 155 | } | ||
| 156 | |||
| 157 | Result AbstractPad::Deactivate() { | ||
| 158 | if (ref_counter == 0) { | ||
| 159 | return ResultNpadResourceNotInitialized; | ||
| 160 | } | ||
| 161 | |||
| 162 | ref_counter--; | ||
| 163 | battery_handler.DecrementRefCounter(); | ||
| 164 | button_handler.DecrementRefCounter(); | ||
| 165 | sixaxis_handler.DecrementRefCounter(); | ||
| 166 | vibration_handler.DecrementRefCounter(); | ||
| 167 | nfc_handler.DecrementRefCounter(); | ||
| 168 | ir_sensor_handler.DecrementRefCounter(); | ||
| 169 | mcu_handler.DecrementRefCounter(); | ||
| 170 | led_handler.DecrementRefCounter(); | ||
| 171 | properties_handler.DecrementRefCounter(); | ||
| 172 | palma_handler.DecrementRefCounter(); | ||
| 173 | |||
| 174 | return ResultSuccess; | ||
| 175 | } | ||
| 176 | |||
| 177 | Result AbstractPad::ActivateNpad(u64 aruid) { | ||
| 178 | Result result = ResultSuccess; | ||
| 179 | if (result.IsSuccess()) { | ||
| 180 | result = properties_handler.ActivateNpadUnknown0x88(aruid); | ||
| 181 | } | ||
| 182 | if (result.IsSuccess()) { | ||
| 183 | result = sixaxis_handler.UpdateSixAxisState2(aruid); | ||
| 184 | } | ||
| 185 | if (result.IsSuccess()) { | ||
| 186 | result = battery_handler.UpdateBatteryState(aruid); | ||
| 187 | } | ||
| 188 | return result; | ||
| 189 | } | ||
| 190 | |||
| 191 | NpadAbstractedPadHolder* AbstractPad::GetAbstractedPadHolder() { | ||
| 192 | return &abstract_pad_holder; | ||
| 193 | } | ||
| 194 | |||
| 195 | NpadAbstractPropertiesHandler* AbstractPad::GetAbstractPropertiesHandler() { | ||
| 196 | return &properties_handler; | ||
| 197 | } | ||
| 198 | |||
| 199 | NpadAbstractLedHandler* AbstractPad::GetAbstractLedHandler() { | ||
| 200 | return &led_handler; | ||
| 201 | } | ||
| 202 | |||
| 203 | NpadAbstractIrSensorHandler* AbstractPad::GetAbstractIrSensorHandler() { | ||
| 204 | return &ir_sensor_handler; | ||
| 205 | } | ||
| 206 | |||
| 207 | NpadAbstractMcuHandler* AbstractPad::GetAbstractMcuHandler() { | ||
| 208 | return &mcu_handler; | ||
| 209 | } | ||
| 210 | |||
| 211 | NpadAbstractNfcHandler* AbstractPad::GetAbstractNfcHandler() { | ||
| 212 | return &nfc_handler; | ||
| 213 | } | ||
| 214 | |||
| 215 | NpadAbstractVibrationHandler* AbstractPad::GetAbstractVibrationHandler() { | ||
| 216 | return &vibration_handler; | ||
| 217 | } | ||
| 218 | |||
| 219 | NpadAbstractSixAxisHandler* AbstractPad::GetAbstractSixAxisHandler() { | ||
| 220 | return &sixaxis_handler; | ||
| 221 | } | ||
| 222 | |||
| 223 | NpadAbstractButtonHandler* AbstractPad::GetAbstractButtonHandler() { | ||
| 224 | return &button_handler; | ||
| 225 | } | ||
| 226 | |||
| 227 | NpadAbstractBatteryHandler* AbstractPad::GetAbstractBatteryHandler() { | ||
| 228 | return &battery_handler; | ||
| 229 | } | ||
| 230 | |||
| 231 | NpadN64VibrationDevice* AbstractPad::GetN64VibrationDevice() { | ||
| 232 | return &vibration_n64; | ||
| 233 | } | ||
| 234 | |||
| 235 | NpadVibrationDevice* AbstractPad::GetVibrationDevice(Core::HID::DeviceIndex device_index) { | ||
| 236 | if (device_index == Core::HID::DeviceIndex::Right) { | ||
| 237 | return &vibration_right; | ||
| 238 | } | ||
| 239 | return &vibration_left; | ||
| 240 | } | ||
| 241 | |||
| 242 | void AbstractPad::GetLeftRightVibrationDevice(std::vector<NpadVibrationDevice*> list) { | ||
| 243 | list.emplace_back(&vibration_left); | ||
| 244 | list.emplace_back(&vibration_right); | ||
| 245 | } | ||
| 246 | |||
| 247 | NpadGcVibrationDevice* AbstractPad::GetGCVibrationDevice() { | ||
| 248 | return &vibration_gc; | ||
| 249 | } | ||
| 250 | |||
| 251 | Core::HID::NpadIdType AbstractPad::GetLastActiveNpad() { | ||
| 252 | return properties_handler.GetNpadId(); | ||
| 253 | } | ||
| 254 | |||
| 255 | void AbstractPad::UpdateInterfaceType() { | ||
| 256 | if (interface_type != properties_handler.GetInterfaceType()) { | ||
| 257 | Update(); | ||
| 258 | } | ||
| 259 | battery_handler.UpdateBatteryState(); | ||
| 260 | } | ||
| 261 | |||
| 262 | void AbstractPad::Update() { | ||
| 263 | properties_handler.UpdateDeviceType(); | ||
| 264 | led_handler.SetNpadLedHandlerLedPattern(); | ||
| 265 | vibration_handler.UpdateVibrationState(); | ||
| 266 | sixaxis_handler.UpdateSixAxisState(); | ||
| 267 | nfc_handler.UpdateNfcState(); | ||
| 268 | ir_sensor_handler.UpdateIrSensorState(); | ||
| 269 | mcu_handler.UpdateMcuState(); | ||
| 270 | palma_handler.UpdatePalmaState(); | ||
| 271 | battery_handler.UpdateBatteryState(); | ||
| 272 | button_handler.EnableCenterClamp(); | ||
| 273 | |||
| 274 | interface_type = properties_handler.GetInterfaceType(); | ||
| 275 | |||
| 276 | std::scoped_lock lock{*applet_resource_holder->shared_mutex}; | ||
| 277 | properties_handler.UpdateAllDeviceProperties(); | ||
| 278 | battery_handler.UpdateCoreBatteryState(); | ||
| 279 | button_handler.UpdateCoreBatteryState(); | ||
| 280 | } | ||
| 281 | |||
| 282 | void AbstractPad::UpdatePadState() { | ||
| 283 | button_handler.UpdateAllButtonLifo(); | ||
| 284 | sixaxis_handler.UpdateSixAxisState(); | ||
| 285 | battery_handler.UpdateCoreBatteryState(); | ||
| 286 | } | ||
| 287 | |||
| 288 | void AbstractPad::EnableAppletToGetInput(u64 aruid) { | ||
| 289 | button_handler.UpdateButtonState(aruid); | ||
| 290 | sixaxis_handler.UpdateSixAxisState(aruid); | ||
| 291 | battery_handler.UpdateBatteryState(aruid); | ||
| 292 | } | ||
| 293 | |||
| 294 | } // namespace Service::HID | ||
diff --git a/src/hid_core/resources/abstracted_pad/abstract_pad.h b/src/hid_core/resources/abstracted_pad/abstract_pad.h new file mode 100644 index 000000000..cbdf84af7 --- /dev/null +++ b/src/hid_core/resources/abstracted_pad/abstract_pad.h | |||
| @@ -0,0 +1,123 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-3.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include <array> | ||
| 7 | #include <mutex> | ||
| 8 | |||
| 9 | #include "common/common_types.h" | ||
| 10 | #include "core/hle/result.h" | ||
| 11 | #include "hid_core/hid_types.h" | ||
| 12 | #include "hid_core/resources/applet_resource.h" | ||
| 13 | #include "hid_core/resources/npad/npad_types.h" | ||
| 14 | |||
| 15 | #include "hid_core/resources/abstracted_pad/abstract_battery_handler.h" | ||
| 16 | #include "hid_core/resources/abstracted_pad/abstract_button_handler.h" | ||
| 17 | #include "hid_core/resources/abstracted_pad/abstract_ir_sensor_handler.h" | ||
| 18 | #include "hid_core/resources/abstracted_pad/abstract_led_handler.h" | ||
| 19 | #include "hid_core/resources/abstracted_pad/abstract_mcu_handler.h" | ||
| 20 | #include "hid_core/resources/abstracted_pad/abstract_nfc_handler.h" | ||
| 21 | #include "hid_core/resources/abstracted_pad/abstract_pad_holder.h" | ||
| 22 | #include "hid_core/resources/abstracted_pad/abstract_palma_handler.h" | ||
| 23 | #include "hid_core/resources/abstracted_pad/abstract_properties_handler.h" | ||
| 24 | #include "hid_core/resources/abstracted_pad/abstract_sixaxis_handler.h" | ||
| 25 | #include "hid_core/resources/abstracted_pad/abstract_vibration_handler.h" | ||
| 26 | #include "hid_core/resources/vibration/gc_vibration_device.h" | ||
| 27 | #include "hid_core/resources/vibration/n64_vibration_device.h" | ||
| 28 | #include "hid_core/resources/vibration/vibration_device.h" | ||
| 29 | |||
| 30 | namespace Service::HID { | ||
| 31 | class AppletResource; | ||
| 32 | class SixAxisResource; | ||
| 33 | class PalmaResource; | ||
| 34 | class NPadResource; | ||
| 35 | class AbstractPad; | ||
| 36 | class NpadLastActiveHandler; | ||
| 37 | class NpadIrNfcHandler; | ||
| 38 | class UniquePads; | ||
| 39 | class NpadPalmaHandler; | ||
| 40 | class FirmwareResource; | ||
| 41 | class NpadVibration; | ||
| 42 | class NpadHighestBattery; | ||
| 43 | class NpadGcVibration; | ||
| 44 | |||
| 45 | class CaptureButtonResource; | ||
| 46 | class HomeButtonResource; | ||
| 47 | class VibrationHandler; | ||
| 48 | |||
| 49 | struct HandheldConfig; | ||
| 50 | |||
| 51 | /// Handles Npad request from HID interfaces | ||
| 52 | class AbstractPad final { | ||
| 53 | public: | ||
| 54 | explicit AbstractPad(); | ||
| 55 | ~AbstractPad(); | ||
| 56 | |||
| 57 | void SetExternals(AppletResourceHolder* applet_resource, | ||
| 58 | CaptureButtonResource* capture_button_resource, | ||
| 59 | HomeButtonResource* home_button_resource, SixAxisResource* sixaxis_resource, | ||
| 60 | PalmaResource* palma_resource, VibrationHandler* vibration); | ||
| 61 | void SetNpadId(Core::HID::NpadIdType npad_id); | ||
| 62 | |||
| 63 | Result Activate(); | ||
| 64 | Result Deactivate(); | ||
| 65 | |||
| 66 | Result ActivateNpad(u64 aruid); | ||
| 67 | |||
| 68 | NpadAbstractedPadHolder* GetAbstractedPadHolder(); | ||
| 69 | NpadAbstractPropertiesHandler* GetAbstractPropertiesHandler(); | ||
| 70 | NpadAbstractLedHandler* GetAbstractLedHandler(); | ||
| 71 | NpadAbstractIrSensorHandler* GetAbstractIrSensorHandler(); | ||
| 72 | NpadAbstractMcuHandler* GetAbstractMcuHandler(); | ||
| 73 | NpadAbstractNfcHandler* GetAbstractNfcHandler(); | ||
| 74 | NpadAbstractVibrationHandler* GetAbstractVibrationHandler(); | ||
| 75 | NpadAbstractSixAxisHandler* GetAbstractSixAxisHandler(); | ||
| 76 | NpadAbstractButtonHandler* GetAbstractButtonHandler(); | ||
| 77 | NpadAbstractBatteryHandler* GetAbstractBatteryHandler(); | ||
| 78 | |||
| 79 | NpadN64VibrationDevice* GetN64VibrationDevice(); | ||
| 80 | NpadVibrationDevice* GetVibrationDevice(Core::HID::DeviceIndex device_index); | ||
| 81 | void GetLeftRightVibrationDevice(std::vector<NpadVibrationDevice*> list); | ||
| 82 | NpadGcVibrationDevice* GetGCVibrationDevice(); | ||
| 83 | |||
| 84 | Core::HID::NpadIdType GetLastActiveNpad(); | ||
| 85 | void UpdateInterfaceType(); | ||
| 86 | void Update(); | ||
| 87 | |||
| 88 | void UpdatePadState(); | ||
| 89 | void EnableAppletToGetInput(u64 aruid); | ||
| 90 | |||
| 91 | private: | ||
| 92 | AppletResourceHolder* applet_resource_holder{nullptr}; | ||
| 93 | NpadAbstractedPadHolder abstract_pad_holder{}; | ||
| 94 | NpadAbstractPropertiesHandler properties_handler{}; | ||
| 95 | NpadAbstractLedHandler led_handler{}; | ||
| 96 | NpadAbstractIrSensorHandler ir_sensor_handler{}; | ||
| 97 | NpadAbstractNfcHandler nfc_handler{}; | ||
| 98 | NpadAbstractMcuHandler mcu_handler{}; | ||
| 99 | NpadAbstractVibrationHandler vibration_handler{}; | ||
| 100 | NpadAbstractSixAxisHandler sixaxis_handler{}; | ||
| 101 | NpadAbstractButtonHandler button_handler{}; | ||
| 102 | NpadAbstractBatteryHandler battery_handler{}; | ||
| 103 | NpadAbstractPalmaHandler palma_handler{}; | ||
| 104 | |||
| 105 | NpadN64VibrationDevice vibration_n64{}; | ||
| 106 | NpadVibrationDevice vibration_left{}; | ||
| 107 | NpadVibrationDevice vibration_right{}; | ||
| 108 | NpadGcVibrationDevice vibration_gc{}; | ||
| 109 | |||
| 110 | // SixAxisConfigHolder fullkey_config; | ||
| 111 | // SixAxisConfigHolder handheld_config; | ||
| 112 | // SixAxisConfigHolder dual_left_config; | ||
| 113 | // SixAxisConfigHolder dual_right_config; | ||
| 114 | // SixAxisConfigHolder left_config; | ||
| 115 | // SixAxisConfigHolder right_config; | ||
| 116 | |||
| 117 | s32 ref_counter{}; | ||
| 118 | Core::HID::NpadInterfaceType interface_type{Core::HID::NpadInterfaceType::None}; | ||
| 119 | }; | ||
| 120 | |||
| 121 | using FullAbstractPad = std::array<AbstractPad, MaxSupportedNpadIdTypes>; | ||
| 122 | |||
| 123 | } // namespace Service::HID | ||
diff --git a/src/hid_core/resources/abstracted_pad/abstract_pad_holder.cpp b/src/hid_core/resources/abstracted_pad/abstract_pad_holder.cpp new file mode 100644 index 000000000..8334dc34f --- /dev/null +++ b/src/hid_core/resources/abstracted_pad/abstract_pad_holder.cpp | |||
| @@ -0,0 +1,99 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-3.0-or-later | ||
| 3 | |||
| 4 | #include "hid_core/hid_result.h" | ||
| 5 | #include "hid_core/resources/abstracted_pad/abstract_pad_holder.h" | ||
| 6 | #include "hid_core/resources/npad/npad_types.h" | ||
| 7 | |||
| 8 | namespace Service::HID { | ||
| 9 | |||
| 10 | Result NpadAbstractedPadHolder::RegisterAbstractPad(IAbstractedPad* abstracted_pad) { | ||
| 11 | if (list_size >= assignment_list.size()) { | ||
| 12 | return ResultNpadIsNotProController; | ||
| 13 | } | ||
| 14 | |||
| 15 | for (std::size_t i = 0; i < list_size; i++) { | ||
| 16 | if (assignment_list[i].device_type == abstracted_pad->device_type) { | ||
| 17 | return ResultNpadIsNotProController; | ||
| 18 | } | ||
| 19 | } | ||
| 20 | |||
| 21 | assignment_list[list_size] = { | ||
| 22 | .abstracted_pad = abstracted_pad, | ||
| 23 | .device_type = abstracted_pad->device_type, | ||
| 24 | .interface_type = abstracted_pad->interface_type, | ||
| 25 | .controller_id = abstracted_pad->controller_id, | ||
| 26 | }; | ||
| 27 | |||
| 28 | list_size++; | ||
| 29 | return ResultSuccess; | ||
| 30 | } | ||
| 31 | |||
| 32 | void NpadAbstractedPadHolder::RemoveAbstractPadByControllerId(u64 controller_id) { | ||
| 33 | if (list_size == 0) { | ||
| 34 | return; | ||
| 35 | } | ||
| 36 | if (controller_id == 0) { | ||
| 37 | return; | ||
| 38 | } | ||
| 39 | for (std::size_t i = 0; i < list_size; i++) { | ||
| 40 | if (assignment_list[i].controller_id != controller_id) { | ||
| 41 | continue; | ||
| 42 | } | ||
| 43 | for (std::size_t e = i + 1; e < list_size; e++) { | ||
| 44 | assignment_list[e - 1] = assignment_list[e]; | ||
| 45 | } | ||
| 46 | list_size--; | ||
| 47 | return; | ||
| 48 | } | ||
| 49 | } | ||
| 50 | |||
| 51 | void NpadAbstractedPadHolder::DetachAbstractedPad() { | ||
| 52 | while (list_size > 0) { | ||
| 53 | for (std::size_t i = 1; i < list_size; i++) { | ||
| 54 | assignment_list[i - 1] = assignment_list[i]; | ||
| 55 | } | ||
| 56 | list_size--; | ||
| 57 | } | ||
| 58 | } | ||
| 59 | |||
| 60 | u64 NpadAbstractedPadHolder::RemoveAbstractPadByAssignmentStyle( | ||
| 61 | Service::HID::AssignmentStyle assignment_style) { | ||
| 62 | for (std::size_t i = 0; i < list_size; i++) { | ||
| 63 | if ((assignment_style.raw & assignment_list[i].abstracted_pad->assignment_style.raw) == 0) { | ||
| 64 | continue; | ||
| 65 | } | ||
| 66 | for (std::size_t e = i + 1; e < list_size; e++) { | ||
| 67 | assignment_list[e - 1] = assignment_list[e]; | ||
| 68 | } | ||
| 69 | list_size--; | ||
| 70 | return list_size; | ||
| 71 | } | ||
| 72 | return list_size; | ||
| 73 | } | ||
| 74 | |||
| 75 | u32 NpadAbstractedPadHolder::GetAbstractedPads(std::span<IAbstractedPad*> list) const { | ||
| 76 | u32 num_elements = std::min(static_cast<u32>(list.size()), list_size); | ||
| 77 | for (std::size_t i = 0; i < num_elements; i++) { | ||
| 78 | list[i] = assignment_list[i].abstracted_pad; | ||
| 79 | } | ||
| 80 | return num_elements; | ||
| 81 | } | ||
| 82 | |||
| 83 | void NpadAbstractedPadHolder::SetAssignmentMode(const NpadJoyAssignmentMode& mode) { | ||
| 84 | assignment_mode = mode; | ||
| 85 | } | ||
| 86 | |||
| 87 | NpadJoyAssignmentMode NpadAbstractedPadHolder::GetAssignmentMode() const { | ||
| 88 | return assignment_mode; | ||
| 89 | } | ||
| 90 | |||
| 91 | std::size_t NpadAbstractedPadHolder::GetStyleIndexList( | ||
| 92 | std::span<Core::HID::NpadStyleIndex> list) const { | ||
| 93 | for (std::size_t i = 0; i < list_size; i++) { | ||
| 94 | list[i] = assignment_list[i].device_type; | ||
| 95 | } | ||
| 96 | return list_size; | ||
| 97 | } | ||
| 98 | |||
| 99 | } // namespace Service::HID | ||
diff --git a/src/hid_core/resources/abstracted_pad/abstract_pad_holder.h b/src/hid_core/resources/abstracted_pad/abstract_pad_holder.h new file mode 100644 index 000000000..fb7f472e8 --- /dev/null +++ b/src/hid_core/resources/abstracted_pad/abstract_pad_holder.h | |||
| @@ -0,0 +1,47 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-3.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include <array> | ||
| 7 | #include <mutex> | ||
| 8 | #include <span> | ||
| 9 | |||
| 10 | #include "common/common_types.h" | ||
| 11 | #include "core/hle/result.h" | ||
| 12 | #include "hid_core/hid_types.h" | ||
| 13 | #include "hid_core/resources/npad/npad_types.h" | ||
| 14 | |||
| 15 | namespace Service::HID { | ||
| 16 | struct IAbstractedPad; | ||
| 17 | |||
| 18 | struct AbstractAssignmentHolder { | ||
| 19 | IAbstractedPad* abstracted_pad; | ||
| 20 | Core::HID::NpadStyleIndex device_type; | ||
| 21 | Core::HID::NpadInterfaceType interface_type; | ||
| 22 | INSERT_PADDING_BYTES(0x6); | ||
| 23 | u64 controller_id; | ||
| 24 | }; | ||
| 25 | static_assert(sizeof(AbstractAssignmentHolder) == 0x18, | ||
| 26 | "AbstractAssignmentHolder is an invalid size"); | ||
| 27 | |||
| 28 | /// This is nn::hid::server::NpadAbstractedPadHolder | ||
| 29 | class NpadAbstractedPadHolder final { | ||
| 30 | public: | ||
| 31 | Result RegisterAbstractPad(IAbstractedPad* abstracted_pad); | ||
| 32 | void RemoveAbstractPadByControllerId(u64 controller_id); | ||
| 33 | void DetachAbstractedPad(); | ||
| 34 | u64 RemoveAbstractPadByAssignmentStyle(Service::HID::AssignmentStyle assignment_style); | ||
| 35 | u32 GetAbstractedPads(std::span<IAbstractedPad*> list) const; | ||
| 36 | |||
| 37 | void SetAssignmentMode(const NpadJoyAssignmentMode& mode); | ||
| 38 | NpadJoyAssignmentMode GetAssignmentMode() const; | ||
| 39 | |||
| 40 | std::size_t GetStyleIndexList(std::span<Core::HID::NpadStyleIndex> list) const; | ||
| 41 | |||
| 42 | private: | ||
| 43 | std::array<AbstractAssignmentHolder, 5> assignment_list{}; | ||
| 44 | u32 list_size{}; | ||
| 45 | NpadJoyAssignmentMode assignment_mode{NpadJoyAssignmentMode::Dual}; | ||
| 46 | }; | ||
| 47 | } // namespace Service::HID | ||
diff --git a/src/hid_core/resources/abstracted_pad/abstract_palma_handler.cpp b/src/hid_core/resources/abstracted_pad/abstract_palma_handler.cpp new file mode 100644 index 000000000..04d276d61 --- /dev/null +++ b/src/hid_core/resources/abstracted_pad/abstract_palma_handler.cpp | |||
| @@ -0,0 +1,47 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-3.0-or-later | ||
| 3 | |||
| 4 | #include "hid_core/hid_result.h" | ||
| 5 | #include "hid_core/resources/abstracted_pad/abstract_palma_handler.h" | ||
| 6 | #include "hid_core/resources/abstracted_pad/abstract_properties_handler.h" | ||
| 7 | |||
| 8 | namespace Service::HID { | ||
| 9 | |||
| 10 | NpadAbstractPalmaHandler::NpadAbstractPalmaHandler() {} | ||
| 11 | |||
| 12 | NpadAbstractPalmaHandler::~NpadAbstractPalmaHandler() = default; | ||
| 13 | |||
| 14 | void NpadAbstractPalmaHandler::SetAbstractPadHolder(NpadAbstractedPadHolder* holder) { | ||
| 15 | abstract_pad_holder = holder; | ||
| 16 | } | ||
| 17 | |||
| 18 | void NpadAbstractPalmaHandler::SetPropertiesHandler(NpadAbstractPropertiesHandler* handler) { | ||
| 19 | properties_handler = handler; | ||
| 20 | return; | ||
| 21 | } | ||
| 22 | |||
| 23 | void NpadAbstractPalmaHandler::SetPalmaResource(PalmaResource* resource) { | ||
| 24 | palma_resource = resource; | ||
| 25 | } | ||
| 26 | |||
| 27 | Result NpadAbstractPalmaHandler::IncrementRefCounter() { | ||
| 28 | if (ref_counter == std::numeric_limits<s32>::max() - 1) { | ||
| 29 | return ResultNpadHandlerOverflow; | ||
| 30 | } | ||
| 31 | ref_counter++; | ||
| 32 | return ResultSuccess; | ||
| 33 | } | ||
| 34 | |||
| 35 | Result NpadAbstractPalmaHandler::DecrementRefCounter() { | ||
| 36 | if (ref_counter == 0) { | ||
| 37 | return ResultNpadHandlerNotInitialized; | ||
| 38 | } | ||
| 39 | ref_counter--; | ||
| 40 | return ResultSuccess; | ||
| 41 | } | ||
| 42 | |||
| 43 | void NpadAbstractPalmaHandler::UpdatePalmaState() { | ||
| 44 | // TODO | ||
| 45 | } | ||
| 46 | |||
| 47 | } // namespace Service::HID | ||
diff --git a/src/hid_core/resources/abstracted_pad/abstract_palma_handler.h b/src/hid_core/resources/abstracted_pad/abstract_palma_handler.h new file mode 100644 index 000000000..fbd2e67e5 --- /dev/null +++ b/src/hid_core/resources/abstracted_pad/abstract_palma_handler.h | |||
| @@ -0,0 +1,37 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-3.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include "common/common_types.h" | ||
| 7 | #include "core/hle/result.h" | ||
| 8 | #include "hid_core/hid_types.h" | ||
| 9 | |||
| 10 | namespace Service::HID { | ||
| 11 | class NpadAbstractedPadHolder; | ||
| 12 | class NpadAbstractPropertiesHandler; | ||
| 13 | class PalmaResource; | ||
| 14 | |||
| 15 | class NpadAbstractPalmaHandler final { | ||
| 16 | public: | ||
| 17 | explicit NpadAbstractPalmaHandler(); | ||
| 18 | ~NpadAbstractPalmaHandler(); | ||
| 19 | |||
| 20 | void SetAbstractPadHolder(NpadAbstractedPadHolder* holder); | ||
| 21 | void SetPropertiesHandler(NpadAbstractPropertiesHandler* handler); | ||
| 22 | void SetPalmaResource(PalmaResource* resource); | ||
| 23 | |||
| 24 | Result IncrementRefCounter(); | ||
| 25 | Result DecrementRefCounter(); | ||
| 26 | |||
| 27 | void UpdatePalmaState(); | ||
| 28 | |||
| 29 | private: | ||
| 30 | NpadAbstractedPadHolder* abstract_pad_holder{nullptr}; | ||
| 31 | NpadAbstractPropertiesHandler* properties_handler{nullptr}; | ||
| 32 | PalmaResource* palma_resource{nullptr}; | ||
| 33 | |||
| 34 | s32 ref_counter{}; | ||
| 35 | }; | ||
| 36 | |||
| 37 | } // namespace Service::HID | ||
diff --git a/src/hid_core/resources/abstracted_pad/abstract_properties_handler.cpp b/src/hid_core/resources/abstracted_pad/abstract_properties_handler.cpp new file mode 100644 index 000000000..4897a2784 --- /dev/null +++ b/src/hid_core/resources/abstracted_pad/abstract_properties_handler.cpp | |||
| @@ -0,0 +1,322 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-3.0-or-later | ||
| 3 | |||
| 4 | #include "hid_core/hid_util.h" | ||
| 5 | #include "hid_core/resources/abstracted_pad/abstract_pad_holder.h" | ||
| 6 | #include "hid_core/resources/abstracted_pad/abstract_properties_handler.h" | ||
| 7 | #include "hid_core/resources/applet_resource.h" | ||
| 8 | #include "hid_core/resources/npad/npad_resource.h" | ||
| 9 | #include "hid_core/resources/npad/npad_types.h" | ||
| 10 | #include "hid_core/resources/shared_memory_format.h" | ||
| 11 | |||
| 12 | namespace Service::HID { | ||
| 13 | |||
| 14 | NpadAbstractPropertiesHandler::NpadAbstractPropertiesHandler() {} | ||
| 15 | |||
| 16 | NpadAbstractPropertiesHandler::~NpadAbstractPropertiesHandler() = default; | ||
| 17 | |||
| 18 | void NpadAbstractPropertiesHandler::SetAbstractPadHolder(NpadAbstractedPadHolder* holder) { | ||
| 19 | abstract_pad_holder = holder; | ||
| 20 | return; | ||
| 21 | } | ||
| 22 | |||
| 23 | void NpadAbstractPropertiesHandler::SetAppletResource(AppletResourceHolder* applet_resource) { | ||
| 24 | applet_resource_holder = applet_resource; | ||
| 25 | return; | ||
| 26 | } | ||
| 27 | |||
| 28 | void NpadAbstractPropertiesHandler::SetNpadId(Core::HID::NpadIdType npad_id) { | ||
| 29 | if (!IsNpadIdValid(npad_id)) { | ||
| 30 | ASSERT_MSG(false, "Invalid npad id"); | ||
| 31 | } | ||
| 32 | |||
| 33 | npad_id_type = npad_id; | ||
| 34 | } | ||
| 35 | |||
| 36 | Core::HID::NpadIdType NpadAbstractPropertiesHandler::GetNpadId() const { | ||
| 37 | return npad_id_type; | ||
| 38 | } | ||
| 39 | |||
| 40 | Result NpadAbstractPropertiesHandler::IncrementRefCounter() { | ||
| 41 | if (ref_counter == std::numeric_limits<s32>::max() - 1) { | ||
| 42 | return ResultNpadHandlerOverflow; | ||
| 43 | } | ||
| 44 | |||
| 45 | if (ref_counter != 0) { | ||
| 46 | ref_counter++; | ||
| 47 | return ResultSuccess; | ||
| 48 | } | ||
| 49 | |||
| 50 | const auto npad_index = NpadIdTypeToIndex(npad_id_type); | ||
| 51 | for (std::size_t aruid_index = 0; aruid_index < AruidIndexMax; aruid_index++) { | ||
| 52 | auto* data = applet_resource_holder->applet_resource->GetAruidData(aruid_index); | ||
| 53 | auto& internal_state = | ||
| 54 | data->shared_memory_format->npad.npad_entry[npad_index].internal_state; | ||
| 55 | if (!data->flag.is_assigned) { | ||
| 56 | continue; | ||
| 57 | } | ||
| 58 | internal_state.fullkey_lifo.buffer_count = 0; | ||
| 59 | internal_state.handheld_lifo.buffer_count = 0; | ||
| 60 | internal_state.joy_dual_lifo.buffer_count = 0; | ||
| 61 | internal_state.joy_left_lifo.buffer_count = 0; | ||
| 62 | internal_state.joy_right_lifo.buffer_count = 0; | ||
| 63 | internal_state.palma_lifo.buffer_count = 0; | ||
| 64 | internal_state.system_ext_lifo.buffer_count = 0; | ||
| 65 | internal_state.gc_trigger_lifo.buffer_count = 0; | ||
| 66 | internal_state.sixaxis_fullkey_lifo.lifo.buffer_count = 0; | ||
| 67 | internal_state.sixaxis_handheld_lifo.lifo.buffer_count = 0; | ||
| 68 | internal_state.sixaxis_dual_left_lifo.lifo.buffer_count = 0; | ||
| 69 | internal_state.sixaxis_dual_right_lifo.lifo.buffer_count = 0; | ||
| 70 | internal_state.sixaxis_left_lifo.lifo.buffer_count = 0; | ||
| 71 | internal_state.sixaxis_right_lifo.lifo.buffer_count = 0; | ||
| 72 | |||
| 73 | internal_state.style_tag = {Core::HID::NpadStyleSet::None}; | ||
| 74 | internal_state.assignment_mode = NpadJoyAssignmentMode::Dual; | ||
| 75 | internal_state.joycon_color = {}; | ||
| 76 | internal_state.fullkey_color = {}; | ||
| 77 | |||
| 78 | internal_state.system_properties.raw = 0; | ||
| 79 | internal_state.button_properties.raw = 0; | ||
| 80 | internal_state.device_type.raw = 0; | ||
| 81 | |||
| 82 | internal_state.battery_level_dual = Core::HID::NpadBatteryLevel::Empty; | ||
| 83 | internal_state.battery_level_left = Core::HID::NpadBatteryLevel::Empty; | ||
| 84 | internal_state.battery_level_right = Core::HID::NpadBatteryLevel::Empty; | ||
| 85 | |||
| 86 | internal_state.applet_footer_type = AppletFooterUiType::None; | ||
| 87 | internal_state.applet_footer_attributes = {}; | ||
| 88 | internal_state.lark_type_l_and_main = {}; | ||
| 89 | internal_state.lark_type_r = {}; | ||
| 90 | |||
| 91 | internal_state.sixaxis_fullkey_properties.is_newly_assigned.Assign(true); | ||
| 92 | internal_state.sixaxis_handheld_properties.is_newly_assigned.Assign(true); | ||
| 93 | internal_state.sixaxis_dual_left_properties.is_newly_assigned.Assign(true); | ||
| 94 | internal_state.sixaxis_dual_right_properties.is_newly_assigned.Assign(true); | ||
| 95 | internal_state.sixaxis_left_properties.is_newly_assigned.Assign(true); | ||
| 96 | internal_state.sixaxis_right_properties.is_newly_assigned.Assign(true); | ||
| 97 | } | ||
| 98 | |||
| 99 | ref_counter++; | ||
| 100 | return ResultSuccess; | ||
| 101 | } | ||
| 102 | |||
| 103 | Result NpadAbstractPropertiesHandler::DecrementRefCounter() { | ||
| 104 | if (ref_counter == 0) { | ||
| 105 | return ResultNpadHandlerNotInitialized; | ||
| 106 | } | ||
| 107 | ref_counter--; | ||
| 108 | return ResultSuccess; | ||
| 109 | } | ||
| 110 | |||
| 111 | Result NpadAbstractPropertiesHandler::ActivateNpadUnknown0x88(u64 aruid) { | ||
| 112 | const auto npad_index = NpadIdTypeToIndex(npad_id_type); | ||
| 113 | for (std::size_t aruid_index = 0; aruid_index < AruidIndexMax; aruid_index++) { | ||
| 114 | auto* data = applet_resource_holder->applet_resource->GetAruidData(aruid_index); | ||
| 115 | if (!data->flag.is_assigned || data->aruid != aruid) { | ||
| 116 | continue; | ||
| 117 | } | ||
| 118 | UpdateDeviceProperties(aruid, data->shared_memory_format->npad.npad_entry[npad_index]); | ||
| 119 | return ResultSuccess; | ||
| 120 | } | ||
| 121 | return ResultSuccess; | ||
| 122 | } | ||
| 123 | |||
| 124 | void NpadAbstractPropertiesHandler::UpdateDeviceType() { | ||
| 125 | // TODO | ||
| 126 | } | ||
| 127 | |||
| 128 | void NpadAbstractPropertiesHandler::UpdateDeviceColor() { | ||
| 129 | // TODO | ||
| 130 | } | ||
| 131 | |||
| 132 | void NpadAbstractPropertiesHandler::UpdateFooterAttributes() { | ||
| 133 | // TODO | ||
| 134 | } | ||
| 135 | |||
| 136 | void NpadAbstractPropertiesHandler::UpdateAllDeviceProperties() { | ||
| 137 | const auto npad_index = NpadIdTypeToIndex(npad_id_type); | ||
| 138 | for (std::size_t aruid_index = 0; aruid_index < AruidIndexMax; aruid_index++) { | ||
| 139 | auto* data = applet_resource_holder->applet_resource->GetAruidData(aruid_index); | ||
| 140 | if (!data->flag.is_assigned) { | ||
| 141 | continue; | ||
| 142 | } | ||
| 143 | auto& npad_entry = data->shared_memory_format->npad.npad_entry[npad_index]; | ||
| 144 | UpdateDeviceProperties(data->aruid, npad_entry); | ||
| 145 | } | ||
| 146 | } | ||
| 147 | |||
| 148 | Core::HID::NpadInterfaceType NpadAbstractPropertiesHandler::GetFullkeyInterfaceType() { | ||
| 149 | std::array<IAbstractedPad*, 5> abstract_pads{}; | ||
| 150 | const std::size_t count = abstract_pad_holder->GetAbstractedPads(abstract_pads); | ||
| 151 | |||
| 152 | for (std::size_t i = 0; i < count; i++) { | ||
| 153 | auto* abstract_pad = abstract_pads[i]; | ||
| 154 | if (!abstract_pad->internal_flags.is_connected) { | ||
| 155 | continue; | ||
| 156 | } | ||
| 157 | if (abstract_pad->device_type != Core::HID::NpadStyleIndex::Fullkey) { | ||
| 158 | continue; | ||
| 159 | } | ||
| 160 | if (abstract_pad->interface_type >= Core::HID::NpadInterfaceType::Embedded) { | ||
| 161 | // Abort | ||
| 162 | continue; | ||
| 163 | } | ||
| 164 | return abstract_pad->interface_type; | ||
| 165 | } | ||
| 166 | |||
| 167 | return Core::HID::NpadInterfaceType::None; | ||
| 168 | } | ||
| 169 | |||
| 170 | Core::HID::NpadInterfaceType NpadAbstractPropertiesHandler::GetInterfaceType() { | ||
| 171 | std::array<IAbstractedPad*, 5> abstract_pads{}; | ||
| 172 | const std::size_t count = abstract_pad_holder->GetAbstractedPads(abstract_pads); | ||
| 173 | |||
| 174 | for (std::size_t i = 0; i < count; i++) { | ||
| 175 | auto* abstract_pad = abstract_pads[i]; | ||
| 176 | if (!abstract_pad->internal_flags.is_connected) { | ||
| 177 | continue; | ||
| 178 | } | ||
| 179 | if (!abstract_pad->disabled_feature_set.has_identification_code) { | ||
| 180 | continue; | ||
| 181 | } | ||
| 182 | if (abstract_pad->interface_type >= Core::HID::NpadInterfaceType::Embedded) { | ||
| 183 | // Abort | ||
| 184 | continue; | ||
| 185 | } | ||
| 186 | return abstract_pad->interface_type; | ||
| 187 | } | ||
| 188 | return Core::HID::NpadInterfaceType::None; | ||
| 189 | } | ||
| 190 | |||
| 191 | Core::HID::NpadStyleSet NpadAbstractPropertiesHandler::GetStyleSet(u64 aruid) { | ||
| 192 | // TODO | ||
| 193 | return Core::HID::NpadStyleSet::None; | ||
| 194 | } | ||
| 195 | |||
| 196 | std::size_t NpadAbstractPropertiesHandler::GetAbstractedPadsWithStyleTag( | ||
| 197 | std::span<IAbstractedPad*> list, Core::HID::NpadStyleTag style) { | ||
| 198 | std::array<IAbstractedPad*, 5> abstract_pads{}; | ||
| 199 | const std::size_t count = abstract_pad_holder->GetAbstractedPads(abstract_pads); | ||
| 200 | |||
| 201 | if (count == 0) { | ||
| 202 | return count; | ||
| 203 | } | ||
| 204 | |||
| 205 | bool is_supported_style_set{}; | ||
| 206 | const auto result = applet_resource_holder->shared_npad_resource->IsSupportedNpadStyleSet( | ||
| 207 | is_supported_style_set, applet_resource_holder->applet_resource->GetActiveAruid()); | ||
| 208 | |||
| 209 | if (!is_supported_style_set || result.IsError()) { | ||
| 210 | for (std::size_t i = 0; i < count; i++) { | ||
| 211 | // TODO | ||
| 212 | } | ||
| 213 | return count; | ||
| 214 | } | ||
| 215 | |||
| 216 | std::size_t filtered_count{}; | ||
| 217 | for (std::size_t i = 0; i < count; i++) { | ||
| 218 | auto* abstract_pad = abstract_pads[i]; | ||
| 219 | const bool is_enabled = true; | ||
| 220 | if (is_enabled) { | ||
| 221 | list[filtered_count] = abstract_pad; | ||
| 222 | filtered_count++; | ||
| 223 | } | ||
| 224 | } | ||
| 225 | |||
| 226 | return filtered_count; | ||
| 227 | } | ||
| 228 | |||
| 229 | std::size_t NpadAbstractPropertiesHandler::GetAbstractedPads(std::span<IAbstractedPad*> list) { | ||
| 230 | Core::HID::NpadStyleTag style{ | ||
| 231 | GetStyleSet(applet_resource_holder->applet_resource->GetActiveAruid())}; | ||
| 232 | return GetAbstractedPadsWithStyleTag(list, style); | ||
| 233 | } | ||
| 234 | |||
| 235 | AppletFooterUiType NpadAbstractPropertiesHandler::GetAppletFooterUiType() { | ||
| 236 | return applet_ui_type.footer; | ||
| 237 | } | ||
| 238 | |||
| 239 | AppletDetailedUiType NpadAbstractPropertiesHandler::GetAppletDetailedUiType() { | ||
| 240 | return applet_ui_type; | ||
| 241 | } | ||
| 242 | |||
| 243 | void NpadAbstractPropertiesHandler::UpdateDeviceProperties(u64 aruid, | ||
| 244 | NpadSharedMemoryEntry& internal_state) { | ||
| 245 | // TODO | ||
| 246 | } | ||
| 247 | |||
| 248 | Core::HID::NpadInterfaceType NpadAbstractPropertiesHandler::GetNpadInterfaceType() { | ||
| 249 | std::array<IAbstractedPad*, 5> abstract_pads{}; | ||
| 250 | const std::size_t count = abstract_pad_holder->GetAbstractedPads(abstract_pads); | ||
| 251 | |||
| 252 | for (std::size_t i = 0; i < count; i++) { | ||
| 253 | auto* abstract_pad = abstract_pads[i]; | ||
| 254 | if (!abstract_pad->internal_flags.is_connected) { | ||
| 255 | continue; | ||
| 256 | } | ||
| 257 | if (abstract_pad->interface_type >= Core::HID::NpadInterfaceType::Embedded) { | ||
| 258 | // Abort | ||
| 259 | continue; | ||
| 260 | } | ||
| 261 | return abstract_pad->interface_type; | ||
| 262 | } | ||
| 263 | |||
| 264 | return Core::HID::NpadInterfaceType::None; | ||
| 265 | } | ||
| 266 | |||
| 267 | Result NpadAbstractPropertiesHandler::GetNpadFullKeyGripColor( | ||
| 268 | Core::HID::NpadColor& main_color, Core::HID::NpadColor& sub_color) const { | ||
| 269 | std::array<IAbstractedPad*, 5> abstract_pads{}; | ||
| 270 | const std::size_t count = abstract_pad_holder->GetAbstractedPads(abstract_pads); | ||
| 271 | |||
| 272 | if (applet_ui_type.footer != AppletFooterUiType::SwitchProController) { | ||
| 273 | return ResultNpadIsNotProController; | ||
| 274 | } | ||
| 275 | |||
| 276 | for (std::size_t i = 0; i < count; i++) { | ||
| 277 | auto* abstract_pad = abstract_pads[i]; | ||
| 278 | if (!abstract_pad->internal_flags.is_connected) { | ||
| 279 | continue; | ||
| 280 | } | ||
| 281 | return ResultSuccess; | ||
| 282 | } | ||
| 283 | |||
| 284 | return ResultNpadIsNotProController; | ||
| 285 | } | ||
| 286 | |||
| 287 | void NpadAbstractPropertiesHandler::GetNpadLeftRightInterfaceType( | ||
| 288 | Core::HID::NpadInterfaceType& out_left_interface, | ||
| 289 | Core::HID::NpadInterfaceType& out_right_interface) const { | ||
| 290 | out_left_interface = Core::HID::NpadInterfaceType::None; | ||
| 291 | out_right_interface = Core::HID::NpadInterfaceType::None; | ||
| 292 | |||
| 293 | std::array<IAbstractedPad*, 5> abstract_pads{}; | ||
| 294 | const std::size_t count = abstract_pad_holder->GetAbstractedPads(abstract_pads); | ||
| 295 | |||
| 296 | for (std::size_t i = 0; i < count; i++) { | ||
| 297 | auto* abstract_pad = abstract_pads[i]; | ||
| 298 | if (!abstract_pad->internal_flags.is_connected) { | ||
| 299 | continue; | ||
| 300 | } | ||
| 301 | if (abstract_pad->assignment_style.is_external_left_assigned && | ||
| 302 | abstract_pad->assignment_style.is_handheld_left_assigned) { | ||
| 303 | if (abstract_pad->interface_type > Core::HID::NpadInterfaceType::Embedded) { | ||
| 304 | // Abort | ||
| 305 | continue; | ||
| 306 | } | ||
| 307 | out_left_interface = abstract_pad->interface_type; | ||
| 308 | continue; | ||
| 309 | } | ||
| 310 | if (abstract_pad->assignment_style.is_external_right_assigned && | ||
| 311 | abstract_pad->assignment_style.is_handheld_right_assigned) { | ||
| 312 | if (abstract_pad->interface_type > Core::HID::NpadInterfaceType::Embedded) { | ||
| 313 | // Abort | ||
| 314 | continue; | ||
| 315 | } | ||
| 316 | out_right_interface = abstract_pad->interface_type; | ||
| 317 | continue; | ||
| 318 | } | ||
| 319 | } | ||
| 320 | } | ||
| 321 | |||
| 322 | } // namespace Service::HID | ||
diff --git a/src/hid_core/resources/abstracted_pad/abstract_properties_handler.h b/src/hid_core/resources/abstracted_pad/abstract_properties_handler.h new file mode 100644 index 000000000..fa6827899 --- /dev/null +++ b/src/hid_core/resources/abstracted_pad/abstract_properties_handler.h | |||
| @@ -0,0 +1,86 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-3.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include <span> | ||
| 7 | |||
| 8 | #include "common/common_types.h" | ||
| 9 | #include "core/hle/result.h" | ||
| 10 | #include "hid_core/hid_types.h" | ||
| 11 | #include "hid_core/resources/npad/npad_types.h" | ||
| 12 | |||
| 13 | namespace Service::HID { | ||
| 14 | struct NpadSharedMemoryEntry; | ||
| 15 | |||
| 16 | struct AppletResourceHolder; | ||
| 17 | class NpadAbstractedPadHolder; | ||
| 18 | |||
| 19 | struct ColorProperties { | ||
| 20 | ColorAttribute attribute; | ||
| 21 | Core::HID::NpadControllerColor color; | ||
| 22 | INSERT_PADDING_BYTES(0x4); | ||
| 23 | }; | ||
| 24 | |||
| 25 | /// Handles Npad request from HID interfaces | ||
| 26 | class NpadAbstractPropertiesHandler final { | ||
| 27 | public: | ||
| 28 | explicit NpadAbstractPropertiesHandler(); | ||
| 29 | ~NpadAbstractPropertiesHandler(); | ||
| 30 | |||
| 31 | void SetAbstractPadHolder(NpadAbstractedPadHolder* holder); | ||
| 32 | void SetAppletResource(AppletResourceHolder* applet_resource); | ||
| 33 | void SetNpadId(Core::HID::NpadIdType npad_id); | ||
| 34 | |||
| 35 | Core::HID::NpadIdType GetNpadId() const; | ||
| 36 | |||
| 37 | Result IncrementRefCounter(); | ||
| 38 | Result DecrementRefCounter(); | ||
| 39 | |||
| 40 | Result ActivateNpadUnknown0x88(u64 aruid); | ||
| 41 | |||
| 42 | void UpdateDeviceType(); | ||
| 43 | void UpdateDeviceColor(); | ||
| 44 | void UpdateFooterAttributes(); | ||
| 45 | void UpdateAllDeviceProperties(); | ||
| 46 | |||
| 47 | Core::HID::NpadInterfaceType GetFullkeyInterfaceType(); | ||
| 48 | Core::HID::NpadInterfaceType GetInterfaceType(); | ||
| 49 | |||
| 50 | Core::HID::NpadStyleSet GetStyleSet(u64 aruid); | ||
| 51 | std::size_t GetAbstractedPadsWithStyleTag(std::span<IAbstractedPad*> list, | ||
| 52 | Core::HID::NpadStyleTag style); | ||
| 53 | std::size_t GetAbstractedPads(std::span<IAbstractedPad*> list); | ||
| 54 | |||
| 55 | AppletFooterUiType GetAppletFooterUiType(); | ||
| 56 | |||
| 57 | AppletDetailedUiType GetAppletDetailedUiType(); | ||
| 58 | |||
| 59 | void UpdateDeviceProperties(u64 aruid, NpadSharedMemoryEntry& internal_state); | ||
| 60 | |||
| 61 | Core::HID::NpadInterfaceType GetNpadInterfaceType(); | ||
| 62 | |||
| 63 | Result GetNpadFullKeyGripColor(Core::HID::NpadColor& main_color, | ||
| 64 | Core::HID::NpadColor& sub_color) const; | ||
| 65 | |||
| 66 | void GetNpadLeftRightInterfaceType(Core::HID::NpadInterfaceType& param_2, | ||
| 67 | Core::HID::NpadInterfaceType& param_3) const; | ||
| 68 | |||
| 69 | private: | ||
| 70 | AppletResourceHolder* applet_resource_holder{nullptr}; | ||
| 71 | NpadAbstractedPadHolder* abstract_pad_holder{nullptr}; | ||
| 72 | Core::HID::NpadIdType npad_id_type{Core::HID::NpadIdType::Invalid}; | ||
| 73 | s32 ref_counter{}; | ||
| 74 | Core::HID::DeviceIndex device_type{}; | ||
| 75 | AppletDetailedUiType applet_ui_type{}; | ||
| 76 | AppletFooterUiAttributes applet_ui_attributes{}; | ||
| 77 | bool is_vertical{}; | ||
| 78 | bool is_horizontal{}; | ||
| 79 | bool use_plus{}; | ||
| 80 | bool use_minus{}; | ||
| 81 | bool has_directional_buttons{}; | ||
| 82 | ColorProperties fullkey_color{}; | ||
| 83 | ColorProperties left_color{}; | ||
| 84 | ColorProperties right_color{}; | ||
| 85 | }; | ||
| 86 | } // namespace Service::HID | ||
diff --git a/src/hid_core/resources/abstracted_pad/abstract_sixaxis_handler.cpp b/src/hid_core/resources/abstracted_pad/abstract_sixaxis_handler.cpp new file mode 100644 index 000000000..6d759298e --- /dev/null +++ b/src/hid_core/resources/abstracted_pad/abstract_sixaxis_handler.cpp | |||
| @@ -0,0 +1,154 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-3.0-or-later | ||
| 3 | |||
| 4 | #include "hid_core/hid_result.h" | ||
| 5 | #include "hid_core/hid_util.h" | ||
| 6 | #include "hid_core/resources/abstracted_pad/abstract_pad_holder.h" | ||
| 7 | #include "hid_core/resources/abstracted_pad/abstract_properties_handler.h" | ||
| 8 | #include "hid_core/resources/abstracted_pad/abstract_sixaxis_handler.h" | ||
| 9 | #include "hid_core/resources/applet_resource.h" | ||
| 10 | #include "hid_core/resources/npad/npad_types.h" | ||
| 11 | #include "hid_core/resources/shared_memory_format.h" | ||
| 12 | |||
| 13 | namespace Service::HID { | ||
| 14 | |||
| 15 | NpadAbstractSixAxisHandler::NpadAbstractSixAxisHandler() {} | ||
| 16 | |||
| 17 | NpadAbstractSixAxisHandler::~NpadAbstractSixAxisHandler() = default; | ||
| 18 | |||
| 19 | void NpadAbstractSixAxisHandler::SetAbstractPadHolder(NpadAbstractedPadHolder* holder) { | ||
| 20 | abstract_pad_holder = holder; | ||
| 21 | } | ||
| 22 | |||
| 23 | void NpadAbstractSixAxisHandler::SetAppletResource(AppletResourceHolder* applet_resource) { | ||
| 24 | applet_resource_holder = applet_resource; | ||
| 25 | } | ||
| 26 | |||
| 27 | void NpadAbstractSixAxisHandler::SetPropertiesHandler(NpadAbstractPropertiesHandler* handler) { | ||
| 28 | properties_handler = handler; | ||
| 29 | } | ||
| 30 | |||
| 31 | void NpadAbstractSixAxisHandler::SetSixaxisResource(SixAxisResource* resource) { | ||
| 32 | six_axis_resource = resource; | ||
| 33 | } | ||
| 34 | |||
| 35 | Result NpadAbstractSixAxisHandler::IncrementRefCounter() { | ||
| 36 | if (ref_counter == std::numeric_limits<s32>::max() - 1) { | ||
| 37 | return ResultNpadHandlerOverflow; | ||
| 38 | } | ||
| 39 | ref_counter++; | ||
| 40 | return ResultSuccess; | ||
| 41 | } | ||
| 42 | |||
| 43 | Result NpadAbstractSixAxisHandler::DecrementRefCounter() { | ||
| 44 | if (ref_counter == 0) { | ||
| 45 | return ResultNpadHandlerNotInitialized; | ||
| 46 | } | ||
| 47 | ref_counter--; | ||
| 48 | return ResultSuccess; | ||
| 49 | } | ||
| 50 | |||
| 51 | u64 NpadAbstractSixAxisHandler::IsFirmwareUpdateAvailable() { | ||
| 52 | // TODO | ||
| 53 | return false; | ||
| 54 | } | ||
| 55 | |||
| 56 | Result NpadAbstractSixAxisHandler::UpdateSixAxisState() { | ||
| 57 | Core::HID::NpadIdType npad_id = properties_handler->GetNpadId(); | ||
| 58 | for (std::size_t i = 0; i < AruidIndexMax; i++) { | ||
| 59 | auto* data = applet_resource_holder->applet_resource->GetAruidDataByIndex(i); | ||
| 60 | if (data->flag.is_assigned) { | ||
| 61 | continue; | ||
| 62 | } | ||
| 63 | auto& npad_entry = data->shared_memory_format->npad.npad_entry[NpadIdTypeToIndex(npad_id)]; | ||
| 64 | UpdateSixaxisInternalState(npad_entry, data->aruid, | ||
| 65 | data->flag.enable_six_axis_sensor.As<bool>()); | ||
| 66 | } | ||
| 67 | return ResultSuccess; | ||
| 68 | } | ||
| 69 | |||
| 70 | Result NpadAbstractSixAxisHandler::UpdateSixAxisState(u64 aruid) { | ||
| 71 | Core::HID::NpadIdType npad_id = properties_handler->GetNpadId(); | ||
| 72 | auto* data = applet_resource_holder->applet_resource->GetAruidData(aruid); | ||
| 73 | if (data == nullptr) { | ||
| 74 | return ResultSuccess; | ||
| 75 | } | ||
| 76 | auto& npad_entry = data->shared_memory_format->npad.npad_entry[NpadIdTypeToIndex(npad_id)]; | ||
| 77 | UpdateSixaxisInternalState(npad_entry, data->aruid, | ||
| 78 | data->flag.enable_six_axis_sensor.As<bool>()); | ||
| 79 | return ResultSuccess; | ||
| 80 | } | ||
| 81 | |||
| 82 | Result NpadAbstractSixAxisHandler::UpdateSixAxisState2(u64 aruid) { | ||
| 83 | const auto npad_index = NpadIdTypeToIndex(properties_handler->GetNpadId()); | ||
| 84 | AruidData* aruid_data = applet_resource_holder->applet_resource->GetAruidData(aruid); | ||
| 85 | if (aruid_data == nullptr) { | ||
| 86 | return ResultSuccess; | ||
| 87 | } | ||
| 88 | auto& npad_internal_state = aruid_data->shared_memory_format->npad.npad_entry[npad_index]; | ||
| 89 | UpdateSixaxisInternalState(npad_internal_state, aruid, | ||
| 90 | aruid_data->flag.enable_six_axis_sensor.As<bool>()); | ||
| 91 | return ResultSuccess; | ||
| 92 | } | ||
| 93 | |||
| 94 | void NpadAbstractSixAxisHandler::UpdateSixaxisInternalState(NpadSharedMemoryEntry& npad_entry, | ||
| 95 | u64 aruid, bool is_sensor_enabled) { | ||
| 96 | const Core::HID::NpadStyleTag style_tag{properties_handler->GetStyleSet(aruid)}; | ||
| 97 | |||
| 98 | if (!style_tag.palma) { | ||
| 99 | UpdateSixaxisFullkeyLifo(style_tag, npad_entry.internal_state.sixaxis_fullkey_lifo, | ||
| 100 | is_sensor_enabled); | ||
| 101 | } else { | ||
| 102 | UpdateSixAxisPalmaLifo(style_tag, npad_entry.internal_state.sixaxis_fullkey_lifo, | ||
| 103 | is_sensor_enabled); | ||
| 104 | } | ||
| 105 | UpdateSixaxisHandheldLifo(style_tag, npad_entry.internal_state.sixaxis_handheld_lifo, | ||
| 106 | is_sensor_enabled); | ||
| 107 | UpdateSixaxisDualLifo(style_tag, npad_entry.internal_state.sixaxis_dual_left_lifo, | ||
| 108 | is_sensor_enabled); | ||
| 109 | UpdateSixaxisDualLifo(style_tag, npad_entry.internal_state.sixaxis_dual_right_lifo, | ||
| 110 | is_sensor_enabled); | ||
| 111 | UpdateSixaxisLeftLifo(style_tag, npad_entry.internal_state.sixaxis_left_lifo, | ||
| 112 | is_sensor_enabled); | ||
| 113 | UpdateSixaxisRightLifo(style_tag, npad_entry.internal_state.sixaxis_right_lifo, | ||
| 114 | is_sensor_enabled); | ||
| 115 | // TODO: Set sixaxis properties | ||
| 116 | } | ||
| 117 | |||
| 118 | void NpadAbstractSixAxisHandler::UpdateSixaxisFullkeyLifo(Core::HID::NpadStyleTag style_tag, | ||
| 119 | NpadSixAxisSensorLifo& sensor_lifo, | ||
| 120 | bool is_sensor_enabled) { | ||
| 121 | // TODO | ||
| 122 | } | ||
| 123 | |||
| 124 | void NpadAbstractSixAxisHandler::UpdateSixAxisPalmaLifo(Core::HID::NpadStyleTag style_tag, | ||
| 125 | NpadSixAxisSensorLifo& sensor_lifo, | ||
| 126 | bool is_sensor_enabled) { | ||
| 127 | // TODO | ||
| 128 | } | ||
| 129 | |||
| 130 | void NpadAbstractSixAxisHandler::UpdateSixaxisHandheldLifo(Core::HID::NpadStyleTag style_tag, | ||
| 131 | NpadSixAxisSensorLifo& sensor_lifo, | ||
| 132 | bool is_sensor_enabled) { | ||
| 133 | // TODO | ||
| 134 | } | ||
| 135 | |||
| 136 | void NpadAbstractSixAxisHandler::UpdateSixaxisDualLifo(Core::HID::NpadStyleTag style_tag, | ||
| 137 | NpadSixAxisSensorLifo& sensor_lifo, | ||
| 138 | bool is_sensor_enabled) { | ||
| 139 | // TODO | ||
| 140 | } | ||
| 141 | |||
| 142 | void NpadAbstractSixAxisHandler::UpdateSixaxisLeftLifo(Core::HID::NpadStyleTag style_tag, | ||
| 143 | NpadSixAxisSensorLifo& sensor_lifo, | ||
| 144 | bool is_sensor_enabled) { | ||
| 145 | // TODO | ||
| 146 | } | ||
| 147 | |||
| 148 | void NpadAbstractSixAxisHandler::UpdateSixaxisRightLifo(Core::HID::NpadStyleTag style_tag, | ||
| 149 | NpadSixAxisSensorLifo& sensor_lifo, | ||
| 150 | bool is_sensor_enabled) { | ||
| 151 | // TODO | ||
| 152 | } | ||
| 153 | |||
| 154 | } // namespace Service::HID | ||
diff --git a/src/hid_core/resources/abstracted_pad/abstract_sixaxis_handler.h b/src/hid_core/resources/abstracted_pad/abstract_sixaxis_handler.h new file mode 100644 index 000000000..9c20459e9 --- /dev/null +++ b/src/hid_core/resources/abstracted_pad/abstract_sixaxis_handler.h | |||
| @@ -0,0 +1,61 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-3.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include "common/common_types.h" | ||
| 7 | #include "core/hle/result.h" | ||
| 8 | #include "hid_core/hid_types.h" | ||
| 9 | |||
| 10 | namespace Service::HID { | ||
| 11 | class SixAxisResource; | ||
| 12 | struct AppletResourceHolder; | ||
| 13 | class NpadAbstractedPadHolder; | ||
| 14 | class NpadAbstractPropertiesHandler; | ||
| 15 | struct NpadSixAxisSensorLifo; | ||
| 16 | |||
| 17 | /// Handles Npad request from HID interfaces | ||
| 18 | class NpadAbstractSixAxisHandler final { | ||
| 19 | public: | ||
| 20 | explicit NpadAbstractSixAxisHandler(); | ||
| 21 | ~NpadAbstractSixAxisHandler(); | ||
| 22 | |||
| 23 | void SetAbstractPadHolder(NpadAbstractedPadHolder* holder); | ||
| 24 | void SetAppletResource(AppletResourceHolder* applet_resource); | ||
| 25 | void SetPropertiesHandler(NpadAbstractPropertiesHandler* handler); | ||
| 26 | void SetSixaxisResource(SixAxisResource* resource); | ||
| 27 | |||
| 28 | Result IncrementRefCounter(); | ||
| 29 | Result DecrementRefCounter(); | ||
| 30 | |||
| 31 | u64 IsFirmwareUpdateAvailable(); | ||
| 32 | |||
| 33 | Result UpdateSixAxisState(); | ||
| 34 | Result UpdateSixAxisState(u64 aruid); | ||
| 35 | Result UpdateSixAxisState2(u64 aruid); | ||
| 36 | |||
| 37 | private: | ||
| 38 | void UpdateSixaxisInternalState(NpadSharedMemoryEntry& npad_entry, u64 aruid, | ||
| 39 | bool is_sensor_enabled); | ||
| 40 | void UpdateSixaxisFullkeyLifo(Core::HID::NpadStyleTag style_tag, | ||
| 41 | NpadSixAxisSensorLifo& sensor_lifo, bool is_sensor_enabled); | ||
| 42 | void UpdateSixAxisPalmaLifo(Core::HID::NpadStyleTag style_tag, | ||
| 43 | NpadSixAxisSensorLifo& sensor_lifo, bool is_sensor_enabled); | ||
| 44 | void UpdateSixaxisHandheldLifo(Core::HID::NpadStyleTag style_tag, | ||
| 45 | NpadSixAxisSensorLifo& sensor_lifo, bool is_sensor_enabled); | ||
| 46 | void UpdateSixaxisDualLifo(Core::HID::NpadStyleTag style_tag, | ||
| 47 | NpadSixAxisSensorLifo& sensor_lifo, bool is_sensor_enabled); | ||
| 48 | void UpdateSixaxisLeftLifo(Core::HID::NpadStyleTag style_tag, | ||
| 49 | NpadSixAxisSensorLifo& sensor_lifo, bool is_sensor_enabled); | ||
| 50 | void UpdateSixaxisRightLifo(Core::HID::NpadStyleTag style_tag, | ||
| 51 | NpadSixAxisSensorLifo& sensor_lifo, bool is_sensor_enabled); | ||
| 52 | |||
| 53 | AppletResourceHolder* applet_resource_holder{nullptr}; | ||
| 54 | NpadAbstractedPadHolder* abstract_pad_holder{nullptr}; | ||
| 55 | NpadAbstractPropertiesHandler* properties_handler{nullptr}; | ||
| 56 | SixAxisResource* six_axis_resource{nullptr}; | ||
| 57 | |||
| 58 | s32 ref_counter{}; | ||
| 59 | }; | ||
| 60 | |||
| 61 | } // namespace Service::HID | ||
diff --git a/src/hid_core/resources/abstracted_pad/abstract_vibration_handler.cpp b/src/hid_core/resources/abstracted_pad/abstract_vibration_handler.cpp new file mode 100644 index 000000000..a00d6c9de --- /dev/null +++ b/src/hid_core/resources/abstracted_pad/abstract_vibration_handler.cpp | |||
| @@ -0,0 +1,73 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-3.0-or-later | ||
| 3 | |||
| 4 | #include "hid_core/hid_result.h" | ||
| 5 | #include "hid_core/hid_util.h" | ||
| 6 | #include "hid_core/resources/abstracted_pad/abstract_pad_holder.h" | ||
| 7 | #include "hid_core/resources/abstracted_pad/abstract_properties_handler.h" | ||
| 8 | #include "hid_core/resources/abstracted_pad/abstract_vibration_handler.h" | ||
| 9 | #include "hid_core/resources/applet_resource.h" | ||
| 10 | #include "hid_core/resources/npad/npad_vibration.h" | ||
| 11 | #include "hid_core/resources/vibration/gc_vibration_device.h" | ||
| 12 | #include "hid_core/resources/vibration/n64_vibration_device.h" | ||
| 13 | #include "hid_core/resources/vibration/vibration_device.h" | ||
| 14 | |||
| 15 | namespace Service::HID { | ||
| 16 | |||
| 17 | NpadAbstractVibrationHandler::NpadAbstractVibrationHandler() {} | ||
| 18 | |||
| 19 | NpadAbstractVibrationHandler::~NpadAbstractVibrationHandler() = default; | ||
| 20 | |||
| 21 | void NpadAbstractVibrationHandler::SetAbstractPadHolder(NpadAbstractedPadHolder* holder) { | ||
| 22 | abstract_pad_holder = holder; | ||
| 23 | } | ||
| 24 | |||
| 25 | void NpadAbstractVibrationHandler::SetAppletResource(AppletResourceHolder* applet_resource) { | ||
| 26 | applet_resource_holder = applet_resource; | ||
| 27 | } | ||
| 28 | |||
| 29 | void NpadAbstractVibrationHandler::SetPropertiesHandler(NpadAbstractPropertiesHandler* handler) { | ||
| 30 | properties_handler = handler; | ||
| 31 | } | ||
| 32 | |||
| 33 | void NpadAbstractVibrationHandler::SetN64Vibration(NpadN64VibrationDevice* n64_device) { | ||
| 34 | n64_vibration_device = n64_device; | ||
| 35 | } | ||
| 36 | |||
| 37 | void NpadAbstractVibrationHandler::SetVibration(std::span<NpadVibrationDevice*> device) { | ||
| 38 | for (std::size_t i = 0; i < device.size() && i < vibration_device.size(); i++) { | ||
| 39 | vibration_device[i] = device[i]; | ||
| 40 | } | ||
| 41 | } | ||
| 42 | |||
| 43 | void NpadAbstractVibrationHandler::SetGcVibration(NpadGcVibrationDevice* gc_device) { | ||
| 44 | gc_vibration_device = gc_device; | ||
| 45 | } | ||
| 46 | |||
| 47 | Result NpadAbstractVibrationHandler::IncrementRefCounter() { | ||
| 48 | if (ref_counter == std::numeric_limits<s32>::max() - 1) { | ||
| 49 | return ResultNpadHandlerOverflow; | ||
| 50 | } | ||
| 51 | ref_counter++; | ||
| 52 | return ResultSuccess; | ||
| 53 | } | ||
| 54 | |||
| 55 | Result NpadAbstractVibrationHandler::DecrementRefCounter() { | ||
| 56 | if (ref_counter == 0) { | ||
| 57 | return ResultNpadHandlerNotInitialized; | ||
| 58 | } | ||
| 59 | ref_counter--; | ||
| 60 | return ResultSuccess; | ||
| 61 | } | ||
| 62 | |||
| 63 | void NpadAbstractVibrationHandler::UpdateVibrationState() { | ||
| 64 | const bool is_handheld_hid_enabled = | ||
| 65 | applet_resource_holder->handheld_config->is_handheld_hid_enabled; | ||
| 66 | const bool is_force_handheld_style_vibration = | ||
| 67 | applet_resource_holder->handheld_config->is_force_handheld_style_vibration; | ||
| 68 | |||
| 69 | if (!is_handheld_hid_enabled && is_force_handheld_style_vibration) { | ||
| 70 | // TODO | ||
| 71 | } | ||
| 72 | } | ||
| 73 | } // namespace Service::HID | ||
diff --git a/src/hid_core/resources/abstracted_pad/abstract_vibration_handler.h b/src/hid_core/resources/abstracted_pad/abstract_vibration_handler.h new file mode 100644 index 000000000..aeb07ce86 --- /dev/null +++ b/src/hid_core/resources/abstracted_pad/abstract_vibration_handler.h | |||
| @@ -0,0 +1,51 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-3.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include <span> | ||
| 7 | |||
| 8 | #include "common/common_types.h" | ||
| 9 | #include "core/hle/result.h" | ||
| 10 | #include "hid_core/hid_types.h" | ||
| 11 | |||
| 12 | namespace Service::HID { | ||
| 13 | struct AppletResourceHolder; | ||
| 14 | class NpadAbstractedPadHolder; | ||
| 15 | class NpadAbstractPropertiesHandler; | ||
| 16 | class NpadGcVibrationDevice; | ||
| 17 | class NpadVibrationDevice; | ||
| 18 | class NpadN64VibrationDevice; | ||
| 19 | class NpadVibration; | ||
| 20 | |||
| 21 | /// Keeps track of battery levels and updates npad battery shared memory values | ||
| 22 | class NpadAbstractVibrationHandler final { | ||
| 23 | public: | ||
| 24 | explicit NpadAbstractVibrationHandler(); | ||
| 25 | ~NpadAbstractVibrationHandler(); | ||
| 26 | |||
| 27 | void SetAbstractPadHolder(NpadAbstractedPadHolder* holder); | ||
| 28 | void SetAppletResource(AppletResourceHolder* applet_resource); | ||
| 29 | void SetPropertiesHandler(NpadAbstractPropertiesHandler* handler); | ||
| 30 | |||
| 31 | void SetN64Vibration(NpadN64VibrationDevice* n64_device); | ||
| 32 | void SetVibration(std::span<NpadVibrationDevice*> device); | ||
| 33 | void SetGcVibration(NpadGcVibrationDevice* gc_device); | ||
| 34 | |||
| 35 | Result IncrementRefCounter(); | ||
| 36 | Result DecrementRefCounter(); | ||
| 37 | |||
| 38 | void UpdateVibrationState(); | ||
| 39 | |||
| 40 | private: | ||
| 41 | AppletResourceHolder* applet_resource_holder{nullptr}; | ||
| 42 | NpadAbstractedPadHolder* abstract_pad_holder{nullptr}; | ||
| 43 | NpadAbstractPropertiesHandler* properties_handler{nullptr}; | ||
| 44 | |||
| 45 | NpadN64VibrationDevice* n64_vibration_device{nullptr}; | ||
| 46 | std::array<NpadVibrationDevice*, 2> vibration_device{}; | ||
| 47 | NpadGcVibrationDevice* gc_vibration_device{nullptr}; | ||
| 48 | NpadVibration* vibration_handler{nullptr}; | ||
| 49 | s32 ref_counter{}; | ||
| 50 | }; | ||
| 51 | } // namespace Service::HID | ||
diff --git a/src/hid_core/resources/hid_firmware_settings.cpp b/src/hid_core/resources/hid_firmware_settings.cpp index e76b3a016..9fa0db17e 100644 --- a/src/hid_core/resources/hid_firmware_settings.cpp +++ b/src/hid_core/resources/hid_firmware_settings.cpp | |||
| @@ -14,7 +14,7 @@ void HidFirmwareSettings::Reload() { | |||
| 14 | } | 14 | } |
| 15 | 15 | ||
| 16 | void HidFirmwareSettings::LoadSettings(bool reload_config) { | 16 | void HidFirmwareSettings::LoadSettings(bool reload_config) { |
| 17 | if (is_initalized && !reload_config) { | 17 | if (is_initialized && !reload_config) { |
| 18 | return; | 18 | return; |
| 19 | } | 19 | } |
| 20 | 20 | ||
| @@ -33,7 +33,7 @@ void HidFirmwareSettings::LoadSettings(bool reload_config) { | |||
| 33 | is_handheld_forced = true; | 33 | is_handheld_forced = true; |
| 34 | features_per_id_disabled = {}; | 34 | features_per_id_disabled = {}; |
| 35 | is_touch_firmware_auto_update_disabled = false; | 35 | is_touch_firmware_auto_update_disabled = false; |
| 36 | is_initalized = true; | 36 | is_initialized = true; |
| 37 | } | 37 | } |
| 38 | 38 | ||
| 39 | bool HidFirmwareSettings::IsDebugPadEnabled() { | 39 | bool HidFirmwareSettings::IsDebugPadEnabled() { |
diff --git a/src/hid_core/resources/hid_firmware_settings.h b/src/hid_core/resources/hid_firmware_settings.h index 6c10c440b..00201fd94 100644 --- a/src/hid_core/resources/hid_firmware_settings.h +++ b/src/hid_core/resources/hid_firmware_settings.h | |||
| @@ -33,7 +33,7 @@ public: | |||
| 33 | FeaturesPerId FeaturesDisabledPerId(); | 33 | FeaturesPerId FeaturesDisabledPerId(); |
| 34 | 34 | ||
| 35 | private: | 35 | private: |
| 36 | bool is_initalized{}; | 36 | bool is_initialized{}; |
| 37 | 37 | ||
| 38 | // Debug settings | 38 | // Debug settings |
| 39 | bool is_debug_pad_enabled{}; | 39 | bool is_debug_pad_enabled{}; |
diff --git a/src/hid_core/resources/npad/npad.cpp b/src/hid_core/resources/npad/npad.cpp index 1f8a0f8ab..97537a2e2 100644 --- a/src/hid_core/resources/npad/npad.cpp +++ b/src/hid_core/resources/npad/npad.cpp | |||
| @@ -193,7 +193,7 @@ void NPad::InitNewlyAddedController(u64 aruid, Core::HID::NpadIdType npad_id) { | |||
| 193 | case Core::HID::NpadStyleIndex::None: | 193 | case Core::HID::NpadStyleIndex::None: |
| 194 | ASSERT(false); | 194 | ASSERT(false); |
| 195 | break; | 195 | break; |
| 196 | case Core::HID::NpadStyleIndex::ProController: | 196 | case Core::HID::NpadStyleIndex::Fullkey: |
| 197 | shared_memory->fullkey_color.attribute = ColorAttribute::Ok; | 197 | shared_memory->fullkey_color.attribute = ColorAttribute::Ok; |
| 198 | shared_memory->fullkey_color.fullkey = body_colors.fullkey; | 198 | shared_memory->fullkey_color.fullkey = body_colors.fullkey; |
| 199 | shared_memory->battery_level_dual = battery_level.dual.battery_level; | 199 | shared_memory->battery_level_dual = battery_level.dual.battery_level; |
| @@ -491,7 +491,7 @@ void NPad::OnUpdate(const Core::Timing::CoreTiming& core_timing) { | |||
| 491 | case Core::HID::NpadStyleIndex::None: | 491 | case Core::HID::NpadStyleIndex::None: |
| 492 | ASSERT(false); | 492 | ASSERT(false); |
| 493 | break; | 493 | break; |
| 494 | case Core::HID::NpadStyleIndex::ProController: | 494 | case Core::HID::NpadStyleIndex::Fullkey: |
| 495 | case Core::HID::NpadStyleIndex::NES: | 495 | case Core::HID::NpadStyleIndex::NES: |
| 496 | case Core::HID::NpadStyleIndex::SNES: | 496 | case Core::HID::NpadStyleIndex::SNES: |
| 497 | case Core::HID::NpadStyleIndex::N64: | 497 | case Core::HID::NpadStyleIndex::N64: |
| @@ -1292,7 +1292,7 @@ Core::HID::SixAxisSensorProperties& NPad::GetSixaxisProperties( | |||
| 1292 | u64 aruid, const Core::HID::SixAxisSensorHandle& sixaxis_handle) { | 1292 | u64 aruid, const Core::HID::SixAxisSensorHandle& sixaxis_handle) { |
| 1293 | auto& controller = GetControllerFromHandle(aruid, sixaxis_handle); | 1293 | auto& controller = GetControllerFromHandle(aruid, sixaxis_handle); |
| 1294 | switch (sixaxis_handle.npad_type) { | 1294 | switch (sixaxis_handle.npad_type) { |
| 1295 | case Core::HID::NpadStyleIndex::ProController: | 1295 | case Core::HID::NpadStyleIndex::Fullkey: |
| 1296 | case Core::HID::NpadStyleIndex::Pokeball: | 1296 | case Core::HID::NpadStyleIndex::Pokeball: |
| 1297 | return controller.shared_memory->sixaxis_fullkey_properties; | 1297 | return controller.shared_memory->sixaxis_fullkey_properties; |
| 1298 | case Core::HID::NpadStyleIndex::Handheld: | 1298 | case Core::HID::NpadStyleIndex::Handheld: |
| @@ -1315,7 +1315,7 @@ const Core::HID::SixAxisSensorProperties& NPad::GetSixaxisProperties( | |||
| 1315 | u64 aruid, const Core::HID::SixAxisSensorHandle& sixaxis_handle) const { | 1315 | u64 aruid, const Core::HID::SixAxisSensorHandle& sixaxis_handle) const { |
| 1316 | const auto& controller = GetControllerFromHandle(aruid, sixaxis_handle); | 1316 | const auto& controller = GetControllerFromHandle(aruid, sixaxis_handle); |
| 1317 | switch (sixaxis_handle.npad_type) { | 1317 | switch (sixaxis_handle.npad_type) { |
| 1318 | case Core::HID::NpadStyleIndex::ProController: | 1318 | case Core::HID::NpadStyleIndex::Fullkey: |
| 1319 | case Core::HID::NpadStyleIndex::Pokeball: | 1319 | case Core::HID::NpadStyleIndex::Pokeball: |
| 1320 | return controller.shared_memory->sixaxis_fullkey_properties; | 1320 | return controller.shared_memory->sixaxis_fullkey_properties; |
| 1321 | case Core::HID::NpadStyleIndex::Handheld: | 1321 | case Core::HID::NpadStyleIndex::Handheld: |
diff --git a/src/hid_core/resources/npad/npad_data.cpp b/src/hid_core/resources/npad/npad_data.cpp index c7e9760cb..29ad5cb08 100644 --- a/src/hid_core/resources/npad/npad_data.cpp +++ b/src/hid_core/resources/npad/npad_data.cpp | |||
| @@ -151,7 +151,7 @@ Core::HID::NpadStyleSet NPadData::GetSupportedNpadStyleSet() const { | |||
| 151 | bool NPadData::IsNpadStyleIndexSupported(Core::HID::NpadStyleIndex style_index) const { | 151 | bool NPadData::IsNpadStyleIndexSupported(Core::HID::NpadStyleIndex style_index) const { |
| 152 | Core::HID::NpadStyleTag style = {supported_npad_style_set}; | 152 | Core::HID::NpadStyleTag style = {supported_npad_style_set}; |
| 153 | switch (style_index) { | 153 | switch (style_index) { |
| 154 | case Core::HID::NpadStyleIndex::ProController: | 154 | case Core::HID::NpadStyleIndex::Fullkey: |
| 155 | return style.fullkey.As<bool>(); | 155 | return style.fullkey.As<bool>(); |
| 156 | case Core::HID::NpadStyleIndex::Handheld: | 156 | case Core::HID::NpadStyleIndex::Handheld: |
| 157 | return style.handheld.As<bool>(); | 157 | return style.handheld.As<bool>(); |
diff --git a/src/hid_core/resources/npad/npad_types.h b/src/hid_core/resources/npad/npad_types.h index a02f9cf16..fd86c8e40 100644 --- a/src/hid_core/resources/npad/npad_types.h +++ b/src/hid_core/resources/npad/npad_types.h | |||
| @@ -252,4 +252,103 @@ enum class NpadLagerType : u32 { | |||
| 252 | U, | 252 | U, |
| 253 | }; | 253 | }; |
| 254 | 254 | ||
| 255 | // nn::hidtypes::FeatureType | ||
| 256 | struct FeatureType { | ||
| 257 | union { | ||
| 258 | u64 raw{}; | ||
| 259 | BitField<0, 1, u64> has_left_analog_stick; | ||
| 260 | BitField<1, 1, u64> has_right_analog_stick; | ||
| 261 | BitField<2, 1, u64> has_left_joy_six_axis_sensor; | ||
| 262 | BitField<3, 1, u64> has_right_joy_six_axis_sensor; | ||
| 263 | BitField<4, 1, u64> has_fullkey_joy_six_axis_sensor; | ||
| 264 | BitField<5, 1, u64> has_left_lra_vibration_device; | ||
| 265 | BitField<6, 1, u64> has_right_lra_vibration_device; | ||
| 266 | BitField<7, 1, u64> has_gc_vibration_device; | ||
| 267 | BitField<8, 1, u64> has_erm_vibration_device; | ||
| 268 | BitField<9, 1, u64> has_left_joy_rail_bus; | ||
| 269 | BitField<10, 1, u64> has_right_joy_rail_bus; | ||
| 270 | BitField<11, 1, u64> has_internal_bus; | ||
| 271 | BitField<12, 1, u64> is_palma; | ||
| 272 | BitField<13, 1, u64> has_nfc; | ||
| 273 | BitField<14, 1, u64> has_ir_sensor; | ||
| 274 | BitField<15, 1, u64> is_analog_stick_calibration_supported; | ||
| 275 | BitField<16, 1, u64> is_six_axis_Sensor_user_calibration_supported; | ||
| 276 | BitField<17, 1, u64> has_left_right_joy_battery; | ||
| 277 | BitField<18, 1, u64> has_fullkey_battery; | ||
| 278 | BitField<19, 1, u64> is_disconnect_controller_if_battery_none; | ||
| 279 | BitField<20, 1, u64> has_controller_color; | ||
| 280 | BitField<21, 1, u64> has_grip_color; | ||
| 281 | BitField<22, 1, u64> has_identification_code; | ||
| 282 | BitField<23, 1, u64> has_bluetooth_address; | ||
| 283 | BitField<24, 1, u64> has_mcu; | ||
| 284 | BitField<25, 1, u64> has_notification_led; | ||
| 285 | BitField<26, 1, u64> has_directional_buttons; | ||
| 286 | BitField<27, 1, u64> has_indicator_led; | ||
| 287 | BitField<28, 1, u64> is_button_config_embedded_supported; | ||
| 288 | BitField<29, 1, u64> is_button_config_full_supported; | ||
| 289 | BitField<30, 1, u64> is_button_config_left_supported; | ||
| 290 | BitField<31, 1, u64> is_button_config_right_supported; | ||
| 291 | BitField<32, 1, u64> is_usb_hid_device; | ||
| 292 | BitField<33, 1, u64> is_kuina_device; | ||
| 293 | BitField<34, 1, u64> is_direct_usb_to_bt_switching_device; | ||
| 294 | BitField<35, 1, u64> is_normalize_analog_stick_with_inner_cross; | ||
| 295 | }; | ||
| 296 | }; | ||
| 297 | static_assert(sizeof(FeatureType) == 8, "FeatureType is an invalid size"); | ||
| 298 | |||
| 299 | // This is nn::hid::AssignmentStyle | ||
| 300 | struct AssignmentStyle { | ||
| 301 | union { | ||
| 302 | u32 raw{}; | ||
| 303 | BitField<0, 1, u32> is_external_assigned; | ||
| 304 | BitField<1, 1, u32> is_external_left_assigned; | ||
| 305 | BitField<2, 1, u32> is_external_right_assigned; | ||
| 306 | BitField<3, 1, u32> is_handheld_assigned; | ||
| 307 | BitField<4, 1, u32> is_handheld_left_assigned; | ||
| 308 | BitField<5, 1, u32> is_handheld_right_assigned; | ||
| 309 | }; | ||
| 310 | }; | ||
| 311 | static_assert(sizeof(AssignmentStyle) == 4, "AssignmentStyle is an invalid size"); | ||
| 312 | |||
| 313 | // This is nn::hid::server::IAbstractedPad::InternalFlags | ||
| 314 | struct InternalFlags { | ||
| 315 | union { | ||
| 316 | u32 raw{}; | ||
| 317 | BitField<0, 1, u32> is_bound; | ||
| 318 | BitField<1, 1, u32> is_connected; | ||
| 319 | BitField<2, 1, u32> is_battery_low_ovln_required; | ||
| 320 | BitField<3, 1, u32> is_battery_low_ovln_delay_required; | ||
| 321 | BitField<4, 1, u32> is_sample_received; | ||
| 322 | BitField<5, 1, u32> is_virtual_input; | ||
| 323 | BitField<6, 1, u32> is_wired; | ||
| 324 | BitField<8, 1, u32> use_center_clamp; | ||
| 325 | BitField<9, 1, u32> has_virtual_six_axis_sensor_acceleration; | ||
| 326 | BitField<10, 1, u32> has_virtual_six_axis_sensor_angle; | ||
| 327 | BitField<11, 1, u32> is_debug_pad; | ||
| 328 | }; | ||
| 329 | }; | ||
| 330 | static_assert(sizeof(InternalFlags) == 4, "InternalFlags is an invalid size"); | ||
| 331 | |||
| 332 | /// This is nn::hid::server::IAbstractedPad | ||
| 333 | struct IAbstractedPad { | ||
| 334 | InternalFlags internal_flags; | ||
| 335 | u64 controller_id; | ||
| 336 | u32 controller_number; | ||
| 337 | u64 low_battery_display_delay_time; | ||
| 338 | u64 low_battery_display_delay_interval; | ||
| 339 | FeatureType feature_set; | ||
| 340 | FeatureType disabled_feature_set; | ||
| 341 | AssignmentStyle assignment_style; | ||
| 342 | Core::HID::NpadStyleIndex device_type; | ||
| 343 | Core::HID::NpadInterfaceType interface_type; | ||
| 344 | Core::HID::NpadPowerInfo power_info; | ||
| 345 | u32 pad_state; | ||
| 346 | u32 button_mask; | ||
| 347 | u32 system_button_mask; | ||
| 348 | u8 indicator; | ||
| 349 | std::vector<f32> virtual_six_axis_sensor_acceleration; | ||
| 350 | std::vector<f32> virtual_six_axis_sensor_angle; | ||
| 351 | u64 xcd_handle; | ||
| 352 | u64 color; | ||
| 353 | }; | ||
| 255 | } // namespace Service::HID | 354 | } // namespace Service::HID |
diff --git a/src/hid_core/resources/npad/npad_vibration.cpp b/src/hid_core/resources/npad/npad_vibration.cpp new file mode 100644 index 000000000..7056e8eab --- /dev/null +++ b/src/hid_core/resources/npad/npad_vibration.cpp | |||
| @@ -0,0 +1,80 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-3.0-or-later | ||
| 3 | |||
| 4 | #include "hid_core/hid_result.h" | ||
| 5 | #include "hid_core/resources/npad/npad_vibration.h" | ||
| 6 | |||
| 7 | namespace Service::HID { | ||
| 8 | |||
| 9 | NpadVibration::NpadVibration() {} | ||
| 10 | |||
| 11 | NpadVibration::~NpadVibration() = default; | ||
| 12 | |||
| 13 | Result NpadVibration::Activate() { | ||
| 14 | std::scoped_lock lock{mutex}; | ||
| 15 | |||
| 16 | const f32 master_volume = 1.0f; // nn::settings::system::GetVibrationMasterVolume(); | ||
| 17 | // if (master_volume < 0.0f || master_volume > 1.0f) { | ||
| 18 | // return ResultVibrationStrengthOutOfRange; | ||
| 19 | // } | ||
| 20 | |||
| 21 | volume = master_volume; | ||
| 22 | return ResultSuccess; | ||
| 23 | } | ||
| 24 | |||
| 25 | Result NpadVibration::Deactivate() { | ||
| 26 | return ResultSuccess; | ||
| 27 | } | ||
| 28 | |||
| 29 | Result NpadVibration::SetVibrationMasterVolume(f32 master_volume) { | ||
| 30 | std::scoped_lock lock{mutex}; | ||
| 31 | |||
| 32 | if (master_volume < 0.0f && master_volume > 1.0f) { | ||
| 33 | return ResultVibrationStrengthOutOfRange; | ||
| 34 | } | ||
| 35 | |||
| 36 | volume = master_volume; | ||
| 37 | // nn::settings::system::SetVibrationMasterVolume(master_volume); | ||
| 38 | |||
| 39 | return ResultSuccess; | ||
| 40 | } | ||
| 41 | |||
| 42 | Result NpadVibration::GetVibrationVolume(f32& out_volume) const { | ||
| 43 | std::scoped_lock lock{mutex}; | ||
| 44 | out_volume = volume; | ||
| 45 | return ResultSuccess; | ||
| 46 | } | ||
| 47 | |||
| 48 | Result NpadVibration::GetVibrationMasterVolume(f32& out_volume) const { | ||
| 49 | std::scoped_lock lock{mutex}; | ||
| 50 | |||
| 51 | const f32 master_volume = 1.0f; // nn::settings::system::GetVibrationMasterVolume(); | ||
| 52 | // if (master_volume < 0.0f || master_volume > 1.0f) { | ||
| 53 | // return ResultVibrationStrengthOutOfRange; | ||
| 54 | // } | ||
| 55 | |||
| 56 | out_volume = master_volume; | ||
| 57 | return ResultSuccess; | ||
| 58 | } | ||
| 59 | |||
| 60 | Result NpadVibration::BeginPermitVibrationSession(u64 aruid) { | ||
| 61 | std::scoped_lock lock{mutex}; | ||
| 62 | session_aruid = aruid; | ||
| 63 | volume = 1.0; | ||
| 64 | return ResultSuccess; | ||
| 65 | } | ||
| 66 | |||
| 67 | Result NpadVibration::EndPermitVibrationSession() { | ||
| 68 | std::scoped_lock lock{mutex}; | ||
| 69 | |||
| 70 | const f32 master_volume = 1.0f; // nn::settings::system::GetVibrationMasterVolume(); | ||
| 71 | // if (master_volume < 0.0f || master_volume > 1.0f) { | ||
| 72 | // return ResultVibrationStrengthOutOfRange; | ||
| 73 | // } | ||
| 74 | |||
| 75 | volume = master_volume; | ||
| 76 | session_aruid = 0; | ||
| 77 | return ResultSuccess; | ||
| 78 | } | ||
| 79 | |||
| 80 | } // namespace Service::HID | ||
diff --git a/src/hid_core/resources/npad/npad_vibration.h b/src/hid_core/resources/npad/npad_vibration.h new file mode 100644 index 000000000..0748aeffc --- /dev/null +++ b/src/hid_core/resources/npad/npad_vibration.h | |||
| @@ -0,0 +1,34 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-3.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include <mutex> | ||
| 7 | |||
| 8 | #include "common/common_types.h" | ||
| 9 | #include "core/hle/result.h" | ||
| 10 | |||
| 11 | namespace Service::HID { | ||
| 12 | |||
| 13 | class NpadVibration final { | ||
| 14 | public: | ||
| 15 | explicit NpadVibration(); | ||
| 16 | ~NpadVibration(); | ||
| 17 | |||
| 18 | Result Activate(); | ||
| 19 | Result Deactivate(); | ||
| 20 | |||
| 21 | Result SetVibrationMasterVolume(f32 master_volume); | ||
| 22 | Result GetVibrationVolume(f32& out_volume) const; | ||
| 23 | Result GetVibrationMasterVolume(f32& out_volume) const; | ||
| 24 | |||
| 25 | Result BeginPermitVibrationSession(u64 aruid); | ||
| 26 | Result EndPermitVibrationSession(); | ||
| 27 | |||
| 28 | private: | ||
| 29 | f32 volume{}; | ||
| 30 | u64 session_aruid{}; | ||
| 31 | mutable std::mutex mutex; | ||
| 32 | }; | ||
| 33 | |||
| 34 | } // namespace Service::HID | ||
diff --git a/src/hid_core/resources/six_axis/six_axis.cpp b/src/hid_core/resources/six_axis/six_axis.cpp index 8a9677c50..abb6fd152 100644 --- a/src/hid_core/resources/six_axis/six_axis.cpp +++ b/src/hid_core/resources/six_axis/six_axis.cpp | |||
| @@ -114,7 +114,7 @@ void SixAxis::OnUpdate(const Core::Timing::CoreTiming& core_timing) { | |||
| 114 | case Core::HID::NpadStyleIndex::None: | 114 | case Core::HID::NpadStyleIndex::None: |
| 115 | ASSERT(false); | 115 | ASSERT(false); |
| 116 | break; | 116 | break; |
| 117 | case Core::HID::NpadStyleIndex::ProController: | 117 | case Core::HID::NpadStyleIndex::Fullkey: |
| 118 | set_motion_state(sixaxis_fullkey_state, motion_state[0]); | 118 | set_motion_state(sixaxis_fullkey_state, motion_state[0]); |
| 119 | break; | 119 | break; |
| 120 | case Core::HID::NpadStyleIndex::Handheld: | 120 | case Core::HID::NpadStyleIndex::Handheld: |
| @@ -249,7 +249,7 @@ Result SixAxis::EnableSixAxisSensorUnalteredPassthrough( | |||
| 249 | } | 249 | } |
| 250 | 250 | ||
| 251 | auto& sixaxis = GetSixaxisState(sixaxis_handle); | 251 | auto& sixaxis = GetSixaxisState(sixaxis_handle); |
| 252 | sixaxis.unaltered_passtrough = is_enabled; | 252 | sixaxis.unaltered_passthrough = is_enabled; |
| 253 | return ResultSuccess; | 253 | return ResultSuccess; |
| 254 | } | 254 | } |
| 255 | 255 | ||
| @@ -262,7 +262,7 @@ Result SixAxis::IsSixAxisSensorUnalteredPassthroughEnabled( | |||
| 262 | } | 262 | } |
| 263 | 263 | ||
| 264 | const auto& sixaxis = GetSixaxisState(sixaxis_handle); | 264 | const auto& sixaxis = GetSixaxisState(sixaxis_handle); |
| 265 | is_enabled = sixaxis.unaltered_passtrough; | 265 | is_enabled = sixaxis.unaltered_passthrough; |
| 266 | return ResultSuccess; | 266 | return ResultSuccess; |
| 267 | } | 267 | } |
| 268 | 268 | ||
| @@ -345,7 +345,7 @@ SixAxis::SixaxisParameters& SixAxis::GetSixaxisState( | |||
| 345 | const Core::HID::SixAxisSensorHandle& sixaxis_handle) { | 345 | const Core::HID::SixAxisSensorHandle& sixaxis_handle) { |
| 346 | auto& controller = GetControllerFromHandle(sixaxis_handle); | 346 | auto& controller = GetControllerFromHandle(sixaxis_handle); |
| 347 | switch (sixaxis_handle.npad_type) { | 347 | switch (sixaxis_handle.npad_type) { |
| 348 | case Core::HID::NpadStyleIndex::ProController: | 348 | case Core::HID::NpadStyleIndex::Fullkey: |
| 349 | case Core::HID::NpadStyleIndex::Pokeball: | 349 | case Core::HID::NpadStyleIndex::Pokeball: |
| 350 | return controller.sixaxis_fullkey; | 350 | return controller.sixaxis_fullkey; |
| 351 | case Core::HID::NpadStyleIndex::Handheld: | 351 | case Core::HID::NpadStyleIndex::Handheld: |
| @@ -368,7 +368,7 @@ const SixAxis::SixaxisParameters& SixAxis::GetSixaxisState( | |||
| 368 | const Core::HID::SixAxisSensorHandle& sixaxis_handle) const { | 368 | const Core::HID::SixAxisSensorHandle& sixaxis_handle) const { |
| 369 | const auto& controller = GetControllerFromHandle(sixaxis_handle); | 369 | const auto& controller = GetControllerFromHandle(sixaxis_handle); |
| 370 | switch (sixaxis_handle.npad_type) { | 370 | switch (sixaxis_handle.npad_type) { |
| 371 | case Core::HID::NpadStyleIndex::ProController: | 371 | case Core::HID::NpadStyleIndex::Fullkey: |
| 372 | case Core::HID::NpadStyleIndex::Pokeball: | 372 | case Core::HID::NpadStyleIndex::Pokeball: |
| 373 | return controller.sixaxis_fullkey; | 373 | return controller.sixaxis_fullkey; |
| 374 | case Core::HID::NpadStyleIndex::Handheld: | 374 | case Core::HID::NpadStyleIndex::Handheld: |
diff --git a/src/hid_core/resources/six_axis/six_axis.h b/src/hid_core/resources/six_axis/six_axis.h index 1054e1b27..b4b00a441 100644 --- a/src/hid_core/resources/six_axis/six_axis.h +++ b/src/hid_core/resources/six_axis/six_axis.h | |||
| @@ -62,7 +62,7 @@ private: | |||
| 62 | 62 | ||
| 63 | struct SixaxisParameters { | 63 | struct SixaxisParameters { |
| 64 | bool is_fusion_enabled{true}; | 64 | bool is_fusion_enabled{true}; |
| 65 | bool unaltered_passtrough{false}; | 65 | bool unaltered_passthrough{false}; |
| 66 | Core::HID::SixAxisSensorFusionParameters fusion{}; | 66 | Core::HID::SixAxisSensorFusionParameters fusion{}; |
| 67 | Core::HID::SixAxisSensorCalibrationParameter calibration{}; | 67 | Core::HID::SixAxisSensorCalibrationParameter calibration{}; |
| 68 | Core::HID::SixAxisSensorIcInformation ic_information{}; | 68 | Core::HID::SixAxisSensorIcInformation ic_information{}; |
diff --git a/src/hid_core/resources/vibration/gc_vibration_device.cpp b/src/hid_core/resources/vibration/gc_vibration_device.cpp new file mode 100644 index 000000000..f01f81b9a --- /dev/null +++ b/src/hid_core/resources/vibration/gc_vibration_device.cpp | |||
| @@ -0,0 +1,106 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-3.0-or-later | ||
| 3 | |||
| 4 | #include "hid_core/hid_result.h" | ||
| 5 | #include "hid_core/resources/npad/npad_types.h" | ||
| 6 | #include "hid_core/resources/npad/npad_vibration.h" | ||
| 7 | #include "hid_core/resources/vibration/gc_vibration_device.h" | ||
| 8 | |||
| 9 | namespace Service::HID { | ||
| 10 | |||
| 11 | NpadGcVibrationDevice::NpadGcVibrationDevice() {} | ||
| 12 | |||
| 13 | Result NpadGcVibrationDevice::IncrementRefCounter() { | ||
| 14 | if (ref_counter == 0 && is_mounted) { | ||
| 15 | f32 volume = 1.0f; | ||
| 16 | const auto result = vibration_handler->GetVibrationVolume(volume); | ||
| 17 | if (result.IsSuccess()) { | ||
| 18 | // TODO: SendVibrationGcErmCommand | ||
| 19 | } | ||
| 20 | } | ||
| 21 | ref_counter++; | ||
| 22 | return ResultSuccess; | ||
| 23 | } | ||
| 24 | |||
| 25 | Result NpadGcVibrationDevice::DecrementRefCounter() { | ||
| 26 | if (ref_counter == 1 && !is_mounted) { | ||
| 27 | f32 volume = 1.0f; | ||
| 28 | const auto result = vibration_handler->GetVibrationVolume(volume); | ||
| 29 | if (result.IsSuccess()) { | ||
| 30 | // TODO: SendVibrationGcErmCommand | ||
| 31 | } | ||
| 32 | } | ||
| 33 | |||
| 34 | if (ref_counter > 0) { | ||
| 35 | ref_counter--; | ||
| 36 | } | ||
| 37 | |||
| 38 | return ResultSuccess; | ||
| 39 | } | ||
| 40 | |||
| 41 | Result NpadGcVibrationDevice::SendVibrationGcErmCommand(Core::HID::VibrationGcErmCommand command) { | ||
| 42 | if (!is_mounted) { | ||
| 43 | return ResultSuccess; | ||
| 44 | } | ||
| 45 | f32 volume = 1.0f; | ||
| 46 | const auto result = vibration_handler->GetVibrationVolume(volume); | ||
| 47 | if (result.IsError()) { | ||
| 48 | return result; | ||
| 49 | } | ||
| 50 | if (volume == 0.0) { | ||
| 51 | command = Core::HID::VibrationGcErmCommand::Stop; | ||
| 52 | } else { | ||
| 53 | if (command > Core::HID::VibrationGcErmCommand::StopHard) { | ||
| 54 | // Abort | ||
| 55 | return ResultSuccess; | ||
| 56 | } | ||
| 57 | } | ||
| 58 | // TODO: SendVibrationGcErmCommand | ||
| 59 | return ResultSuccess; | ||
| 60 | } | ||
| 61 | |||
| 62 | Result NpadGcVibrationDevice::GetActualVibrationGcErmCommand( | ||
| 63 | Core::HID::VibrationGcErmCommand& out_command) { | ||
| 64 | if (!is_mounted) { | ||
| 65 | out_command = Core::HID::VibrationGcErmCommand::Stop; | ||
| 66 | return ResultSuccess; | ||
| 67 | } | ||
| 68 | |||
| 69 | f32 volume = 1.0f; | ||
| 70 | const auto result = vibration_handler->GetVibrationVolume(volume); | ||
| 71 | if (result.IsError()) { | ||
| 72 | return result; | ||
| 73 | } | ||
| 74 | if (volume == 0.0f) { | ||
| 75 | out_command = Core::HID::VibrationGcErmCommand::Stop; | ||
| 76 | return ResultSuccess; | ||
| 77 | } | ||
| 78 | |||
| 79 | // TODO: GetActualVibrationGcErmCommand | ||
| 80 | return ResultSuccess; | ||
| 81 | } | ||
| 82 | |||
| 83 | Result NpadGcVibrationDevice::SendVibrationNotificationPattern( | ||
| 84 | Core::HID::VibrationGcErmCommand command) { | ||
| 85 | if (!is_mounted) { | ||
| 86 | return ResultSuccess; | ||
| 87 | } | ||
| 88 | |||
| 89 | f32 volume = 1.0f; | ||
| 90 | const auto result = vibration_handler->GetVibrationVolume(volume); | ||
| 91 | if (result.IsError()) { | ||
| 92 | return result; | ||
| 93 | } | ||
| 94 | if (volume <= 0.0f) { | ||
| 95 | command = Core::HID::VibrationGcErmCommand::Stop; | ||
| 96 | } | ||
| 97 | if (command > Core::HID::VibrationGcErmCommand::StopHard) { | ||
| 98 | // Abort | ||
| 99 | return ResultSuccess; | ||
| 100 | } | ||
| 101 | |||
| 102 | // TODO: SendVibrationNotificationPattern | ||
| 103 | return ResultSuccess; | ||
| 104 | } | ||
| 105 | |||
| 106 | } // namespace Service::HID | ||
diff --git a/src/hid_core/resources/vibration/gc_vibration_device.h b/src/hid_core/resources/vibration/gc_vibration_device.h new file mode 100644 index 000000000..87abca57d --- /dev/null +++ b/src/hid_core/resources/vibration/gc_vibration_device.h | |||
| @@ -0,0 +1,31 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-3.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include <array> | ||
| 7 | #include <mutex> | ||
| 8 | |||
| 9 | #include "common/common_types.h" | ||
| 10 | #include "core/hle/result.h" | ||
| 11 | #include "hid_core/hid_types.h" | ||
| 12 | #include "hid_core/resources/npad/npad_types.h" | ||
| 13 | #include "hid_core/resources/vibration/vibration_base.h" | ||
| 14 | |||
| 15 | namespace Service::HID { | ||
| 16 | class NpadVibration; | ||
| 17 | |||
| 18 | /// Handles Npad request from HID interfaces | ||
| 19 | class NpadGcVibrationDevice final : public NpadVibrationBase { | ||
| 20 | public: | ||
| 21 | explicit NpadGcVibrationDevice(); | ||
| 22 | |||
| 23 | Result IncrementRefCounter() override; | ||
| 24 | Result DecrementRefCounter() override; | ||
| 25 | |||
| 26 | Result SendVibrationGcErmCommand(Core::HID::VibrationGcErmCommand command); | ||
| 27 | |||
| 28 | Result GetActualVibrationGcErmCommand(Core::HID::VibrationGcErmCommand& out_command); | ||
| 29 | Result SendVibrationNotificationPattern(Core::HID::VibrationGcErmCommand command); | ||
| 30 | }; | ||
| 31 | } // namespace Service::HID | ||
diff --git a/src/hid_core/resources/vibration/n64_vibration_device.cpp b/src/hid_core/resources/vibration/n64_vibration_device.cpp new file mode 100644 index 000000000..639f87abf --- /dev/null +++ b/src/hid_core/resources/vibration/n64_vibration_device.cpp | |||
| @@ -0,0 +1,80 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-3.0-or-later | ||
| 3 | |||
| 4 | #include "hid_core/hid_result.h" | ||
| 5 | #include "hid_core/resources/npad/npad_types.h" | ||
| 6 | #include "hid_core/resources/npad/npad_vibration.h" | ||
| 7 | #include "hid_core/resources/vibration/n64_vibration_device.h" | ||
| 8 | |||
| 9 | namespace Service::HID { | ||
| 10 | |||
| 11 | NpadN64VibrationDevice::NpadN64VibrationDevice() {} | ||
| 12 | |||
| 13 | Result NpadN64VibrationDevice::IncrementRefCounter() { | ||
| 14 | if (ref_counter == 0 && is_mounted) { | ||
| 15 | f32 volume = 1.0f; | ||
| 16 | const auto result = vibration_handler->GetVibrationVolume(volume); | ||
| 17 | if (result.IsSuccess()) { | ||
| 18 | // TODO: SendVibrationInBool | ||
| 19 | } | ||
| 20 | } | ||
| 21 | |||
| 22 | ref_counter++; | ||
| 23 | return ResultSuccess; | ||
| 24 | } | ||
| 25 | |||
| 26 | Result NpadN64VibrationDevice::DecrementRefCounter() { | ||
| 27 | if (ref_counter == 1) { | ||
| 28 | if (!is_mounted) { | ||
| 29 | ref_counter = 0; | ||
| 30 | if (is_mounted != false) { | ||
| 31 | // TODO: SendVibrationInBool | ||
| 32 | } | ||
| 33 | return ResultSuccess; | ||
| 34 | } | ||
| 35 | f32 volume = 1.0f; | ||
| 36 | const auto result = vibration_handler->GetVibrationVolume(volume); | ||
| 37 | if (result.IsSuccess()) { | ||
| 38 | // TODO | ||
| 39 | } | ||
| 40 | } | ||
| 41 | |||
| 42 | if (ref_counter > 0) { | ||
| 43 | ref_counter--; | ||
| 44 | } | ||
| 45 | |||
| 46 | return ResultSuccess; | ||
| 47 | } | ||
| 48 | |||
| 49 | Result NpadN64VibrationDevice::SendValueInBool(bool is_vibrating) { | ||
| 50 | if (ref_counter < 1) { | ||
| 51 | return ResultVibrationNotInitialized; | ||
| 52 | } | ||
| 53 | if (is_mounted) { | ||
| 54 | f32 volume = 1.0f; | ||
| 55 | const auto result = vibration_handler->GetVibrationVolume(volume); | ||
| 56 | if (result.IsError()) { | ||
| 57 | return result; | ||
| 58 | } | ||
| 59 | // TODO: SendVibrationInBool | ||
| 60 | } | ||
| 61 | return ResultSuccess; | ||
| 62 | } | ||
| 63 | |||
| 64 | Result NpadN64VibrationDevice::SendVibrationNotificationPattern([[maybe_unused]] u32 pattern) { | ||
| 65 | if (!is_mounted) { | ||
| 66 | return ResultSuccess; | ||
| 67 | } | ||
| 68 | f32 volume = 1.0f; | ||
| 69 | const auto result = vibration_handler->GetVibrationVolume(volume); | ||
| 70 | if (result.IsError()) { | ||
| 71 | return result; | ||
| 72 | } | ||
| 73 | if (volume <= 0.0) { | ||
| 74 | pattern = 0; | ||
| 75 | } | ||
| 76 | // TODO: SendVibrationNotificationPattern | ||
| 77 | return ResultSuccess; | ||
| 78 | } | ||
| 79 | |||
| 80 | } // namespace Service::HID | ||
diff --git a/src/hid_core/resources/vibration/n64_vibration_device.h b/src/hid_core/resources/vibration/n64_vibration_device.h new file mode 100644 index 000000000..54e6efc1a --- /dev/null +++ b/src/hid_core/resources/vibration/n64_vibration_device.h | |||
| @@ -0,0 +1,29 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-3.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include <array> | ||
| 7 | #include <mutex> | ||
| 8 | |||
| 9 | #include "common/common_types.h" | ||
| 10 | #include "core/hle/result.h" | ||
| 11 | #include "hid_core/hid_types.h" | ||
| 12 | #include "hid_core/resources/npad/npad_types.h" | ||
| 13 | #include "hid_core/resources/vibration/vibration_base.h" | ||
| 14 | |||
| 15 | namespace Service::HID { | ||
| 16 | class NpadVibration; | ||
| 17 | |||
| 18 | /// Handles Npad request from HID interfaces | ||
| 19 | class NpadN64VibrationDevice final : public NpadVibrationBase { | ||
| 20 | public: | ||
| 21 | explicit NpadN64VibrationDevice(); | ||
| 22 | |||
| 23 | Result IncrementRefCounter() override; | ||
| 24 | Result DecrementRefCounter() override; | ||
| 25 | |||
| 26 | Result SendValueInBool(bool is_vibrating); | ||
| 27 | Result SendVibrationNotificationPattern(u32 pattern); | ||
| 28 | }; | ||
| 29 | } // namespace Service::HID | ||
diff --git a/src/hid_core/resources/vibration/vibration_base.cpp b/src/hid_core/resources/vibration/vibration_base.cpp new file mode 100644 index 000000000..350f349c2 --- /dev/null +++ b/src/hid_core/resources/vibration/vibration_base.cpp | |||
| @@ -0,0 +1,30 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-3.0-or-later | ||
| 3 | |||
| 4 | #include "hid_core/hid_result.h" | ||
| 5 | #include "hid_core/resources/npad/npad_types.h" | ||
| 6 | #include "hid_core/resources/npad/npad_vibration.h" | ||
| 7 | #include "hid_core/resources/vibration/vibration_base.h" | ||
| 8 | |||
| 9 | namespace Service::HID { | ||
| 10 | |||
| 11 | NpadVibrationBase::NpadVibrationBase() {} | ||
| 12 | |||
| 13 | Result NpadVibrationBase::IncrementRefCounter() { | ||
| 14 | ref_counter++; | ||
| 15 | return ResultSuccess; | ||
| 16 | } | ||
| 17 | |||
| 18 | Result NpadVibrationBase::DecrementRefCounter() { | ||
| 19 | if (ref_counter > 0) { | ||
| 20 | ref_counter--; | ||
| 21 | } | ||
| 22 | |||
| 23 | return ResultSuccess; | ||
| 24 | } | ||
| 25 | |||
| 26 | bool NpadVibrationBase::IsVibrationMounted() const { | ||
| 27 | return is_mounted; | ||
| 28 | } | ||
| 29 | |||
| 30 | } // namespace Service::HID | ||
diff --git a/src/hid_core/resources/vibration/vibration_base.h b/src/hid_core/resources/vibration/vibration_base.h new file mode 100644 index 000000000..c6c5fc4d9 --- /dev/null +++ b/src/hid_core/resources/vibration/vibration_base.h | |||
| @@ -0,0 +1,28 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-3.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include "common/common_types.h" | ||
| 7 | #include "core/hle/result.h" | ||
| 8 | |||
| 9 | namespace Service::HID { | ||
| 10 | class NpadVibration; | ||
| 11 | |||
| 12 | /// Handles Npad request from HID interfaces | ||
| 13 | class NpadVibrationBase { | ||
| 14 | public: | ||
| 15 | explicit NpadVibrationBase(); | ||
| 16 | |||
| 17 | virtual Result IncrementRefCounter(); | ||
| 18 | virtual Result DecrementRefCounter(); | ||
| 19 | |||
| 20 | bool IsVibrationMounted() const; | ||
| 21 | |||
| 22 | protected: | ||
| 23 | u64 xcd_handle{}; | ||
| 24 | s32 ref_counter{}; | ||
| 25 | bool is_mounted{}; | ||
| 26 | NpadVibration* vibration_handler{nullptr}; | ||
| 27 | }; | ||
| 28 | } // namespace Service::HID | ||
diff --git a/src/hid_core/resources/vibration/vibration_device.cpp b/src/hid_core/resources/vibration/vibration_device.cpp new file mode 100644 index 000000000..888c3a7ed --- /dev/null +++ b/src/hid_core/resources/vibration/vibration_device.cpp | |||
| @@ -0,0 +1,84 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-3.0-or-later | ||
| 3 | |||
| 4 | #include "hid_core/hid_result.h" | ||
| 5 | #include "hid_core/resources/npad/npad_types.h" | ||
| 6 | #include "hid_core/resources/npad/npad_vibration.h" | ||
| 7 | #include "hid_core/resources/vibration/vibration_device.h" | ||
| 8 | |||
| 9 | namespace Service::HID { | ||
| 10 | |||
| 11 | NpadVibrationDevice::NpadVibrationDevice() {} | ||
| 12 | |||
| 13 | Result NpadVibrationDevice::IncrementRefCounter() { | ||
| 14 | ref_counter++; | ||
| 15 | return ResultSuccess; | ||
| 16 | } | ||
| 17 | |||
| 18 | Result NpadVibrationDevice::DecrementRefCounter() { | ||
| 19 | if (ref_counter > 0) { | ||
| 20 | ref_counter--; | ||
| 21 | } | ||
| 22 | |||
| 23 | return ResultSuccess; | ||
| 24 | } | ||
| 25 | |||
| 26 | Result NpadVibrationDevice::SendVibrationValue(const Core::HID::VibrationValue& value) { | ||
| 27 | if (ref_counter == 0) { | ||
| 28 | return ResultVibrationNotInitialized; | ||
| 29 | } | ||
| 30 | if (!is_mounted) { | ||
| 31 | return ResultSuccess; | ||
| 32 | } | ||
| 33 | |||
| 34 | f32 volume = 1.0f; | ||
| 35 | const auto result = vibration_handler->GetVibrationVolume(volume); | ||
| 36 | if (result.IsError()) { | ||
| 37 | return result; | ||
| 38 | } | ||
| 39 | if (volume <= 0.0f) { | ||
| 40 | // TODO: SendVibrationValue | ||
| 41 | return ResultSuccess; | ||
| 42 | } | ||
| 43 | |||
| 44 | Core::HID::VibrationValue vibration_value = value; | ||
| 45 | vibration_value.high_amplitude *= volume; | ||
| 46 | vibration_value.low_amplitude *= volume; | ||
| 47 | |||
| 48 | // TODO: SendVibrationValue | ||
| 49 | return ResultSuccess; | ||
| 50 | } | ||
| 51 | |||
| 52 | Result NpadVibrationDevice::SendVibrationNotificationPattern([[maybe_unused]] u32 pattern) { | ||
| 53 | if (!is_mounted) { | ||
| 54 | return ResultSuccess; | ||
| 55 | } | ||
| 56 | |||
| 57 | f32 volume = 1.0f; | ||
| 58 | const auto result = vibration_handler->GetVibrationVolume(volume); | ||
| 59 | if (result.IsError()) { | ||
| 60 | return result; | ||
| 61 | } | ||
| 62 | if (volume <= 0.0) { | ||
| 63 | pattern = 0; | ||
| 64 | } | ||
| 65 | |||
| 66 | // return xcd_handle->SendVibrationNotificationPattern(pattern); | ||
| 67 | return ResultSuccess; | ||
| 68 | } | ||
| 69 | |||
| 70 | Result NpadVibrationDevice::GetActualVibrationValue(Core::HID::VibrationValue& out_value) { | ||
| 71 | if (ref_counter < 1) { | ||
| 72 | return ResultVibrationNotInitialized; | ||
| 73 | } | ||
| 74 | |||
| 75 | out_value = Core::HID::DEFAULT_VIBRATION_VALUE; | ||
| 76 | if (!is_mounted) { | ||
| 77 | return ResultSuccess; | ||
| 78 | } | ||
| 79 | |||
| 80 | // TODO: SendVibrationValue | ||
| 81 | return ResultSuccess; | ||
| 82 | } | ||
| 83 | |||
| 84 | } // namespace Service::HID | ||
diff --git a/src/hid_core/resources/vibration/vibration_device.h b/src/hid_core/resources/vibration/vibration_device.h new file mode 100644 index 000000000..3574ad60b --- /dev/null +++ b/src/hid_core/resources/vibration/vibration_device.h | |||
| @@ -0,0 +1,35 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-3.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include <array> | ||
| 7 | #include <mutex> | ||
| 8 | |||
| 9 | #include "common/common_types.h" | ||
| 10 | #include "core/hle/result.h" | ||
| 11 | #include "hid_core/hid_types.h" | ||
| 12 | #include "hid_core/resources/npad/npad_types.h" | ||
| 13 | #include "hid_core/resources/vibration/vibration_base.h" | ||
| 14 | |||
| 15 | namespace Service::HID { | ||
| 16 | class NpadVibration; | ||
| 17 | |||
| 18 | /// Handles Npad request from HID interfaces | ||
| 19 | class NpadVibrationDevice final : public NpadVibrationBase { | ||
| 20 | public: | ||
| 21 | explicit NpadVibrationDevice(); | ||
| 22 | |||
| 23 | Result IncrementRefCounter(); | ||
| 24 | Result DecrementRefCounter(); | ||
| 25 | |||
| 26 | Result SendVibrationValue(const Core::HID::VibrationValue& value); | ||
| 27 | Result SendVibrationNotificationPattern(u32 pattern); | ||
| 28 | |||
| 29 | Result GetActualVibrationValue(Core::HID::VibrationValue& out_value); | ||
| 30 | |||
| 31 | private: | ||
| 32 | u32 device_index{}; | ||
| 33 | }; | ||
| 34 | |||
| 35 | } // namespace Service::HID | ||
diff --git a/src/input_common/drivers/gc_adapter.cpp b/src/input_common/drivers/gc_adapter.cpp index 1ff296af5..f1184a5fa 100644 --- a/src/input_common/drivers/gc_adapter.cpp +++ b/src/input_common/drivers/gc_adapter.cpp | |||
| @@ -451,11 +451,11 @@ ButtonMapping GCAdapter::GetButtonMappingForDevice(const Common::ParamPackage& p | |||
| 451 | std::tuple{Settings::NativeButton::ZL, PadButton::TriggerL, PadAxes::TriggerLeft}, | 451 | std::tuple{Settings::NativeButton::ZL, PadButton::TriggerL, PadAxes::TriggerLeft}, |
| 452 | {Settings::NativeButton::ZR, PadButton::TriggerR, PadAxes::TriggerRight}, | 452 | {Settings::NativeButton::ZR, PadButton::TriggerR, PadAxes::TriggerRight}, |
| 453 | }; | 453 | }; |
| 454 | for (const auto& [switch_button, gcadapter_buton, gcadapter_axis] : switch_to_gcadapter_axis) { | 454 | for (const auto& [switch_button, gcadapter_button, gcadapter_axis] : switch_to_gcadapter_axis) { |
| 455 | Common::ParamPackage button_params{}; | 455 | Common::ParamPackage button_params{}; |
| 456 | button_params.Set("engine", GetEngineName()); | 456 | button_params.Set("engine", GetEngineName()); |
| 457 | button_params.Set("port", params.Get("port", 0)); | 457 | button_params.Set("port", params.Get("port", 0)); |
| 458 | button_params.Set("button", static_cast<s32>(gcadapter_buton)); | 458 | button_params.Set("button", static_cast<s32>(gcadapter_button)); |
| 459 | button_params.Set("axis", static_cast<s32>(gcadapter_axis)); | 459 | button_params.Set("axis", static_cast<s32>(gcadapter_axis)); |
| 460 | button_params.Set("threshold", 0.5f); | 460 | button_params.Set("threshold", 0.5f); |
| 461 | button_params.Set("range", 1.9f); | 461 | button_params.Set("range", 1.9f); |
diff --git a/src/input_common/helpers/joycon_protocol/irs.cpp b/src/input_common/helpers/joycon_protocol/irs.cpp index 68b0589e3..5bf72114d 100644 --- a/src/input_common/helpers/joycon_protocol/irs.cpp +++ b/src/input_common/helpers/joycon_protocol/irs.cpp | |||
| @@ -236,9 +236,9 @@ Common::Input::DriverResult IrsProtocol::WriteRegistersStep2() { | |||
| 236 | .number_of_registers = 0x8, | 236 | .number_of_registers = 0x8, |
| 237 | .registers = | 237 | .registers = |
| 238 | { | 238 | { |
| 239 | IrsRegister{IrRegistersAddress::LedIntensitiyMSB, | 239 | IrsRegister{IrRegistersAddress::LedIntensityMSB, |
| 240 | static_cast<u8>(led_intensity >> 8)}, | 240 | static_cast<u8>(led_intensity >> 8)}, |
| 241 | {IrRegistersAddress::LedIntensitiyLSB, static_cast<u8>(led_intensity & 0xff)}, | 241 | {IrRegistersAddress::LedIntensityLSB, static_cast<u8>(led_intensity & 0xff)}, |
| 242 | {IrRegistersAddress::ImageFlip, static_cast<u8>(image_flip)}, | 242 | {IrRegistersAddress::ImageFlip, static_cast<u8>(image_flip)}, |
| 243 | {IrRegistersAddress::DenoiseSmoothing, static_cast<u8>((denoise >> 16) & 0xff)}, | 243 | {IrRegistersAddress::DenoiseSmoothing, static_cast<u8>((denoise >> 16) & 0xff)}, |
| 244 | {IrRegistersAddress::DenoiseEdge, static_cast<u8>((denoise >> 8) & 0xff)}, | 244 | {IrRegistersAddress::DenoiseEdge, static_cast<u8>((denoise >> 8) & 0xff)}, |
diff --git a/src/input_common/helpers/joycon_protocol/joycon_types.h b/src/input_common/helpers/joycon_protocol/joycon_types.h index 77a43c67a..792f124e1 100644 --- a/src/input_common/helpers/joycon_protocol/joycon_types.h +++ b/src/input_common/helpers/joycon_protocol/joycon_types.h | |||
| @@ -282,7 +282,7 @@ enum class NFCCommand : u8 { | |||
| 282 | CancelAll = 0x00, | 282 | CancelAll = 0x00, |
| 283 | StartPolling = 0x01, | 283 | StartPolling = 0x01, |
| 284 | StopPolling = 0x02, | 284 | StopPolling = 0x02, |
| 285 | StartWaitingRecieve = 0x04, | 285 | StartWaitingReceive = 0x04, |
| 286 | ReadNtag = 0x06, | 286 | ReadNtag = 0x06, |
| 287 | WriteNtag = 0x08, | 287 | WriteNtag = 0x08, |
| 288 | Mifare = 0x0F, | 288 | Mifare = 0x0F, |
| @@ -382,8 +382,8 @@ enum class IrRegistersAddress : u16 { | |||
| 382 | FinalizeConfig = 0x0700, | 382 | FinalizeConfig = 0x0700, |
| 383 | LedFilter = 0x0e00, | 383 | LedFilter = 0x0e00, |
| 384 | Leds = 0x1000, | 384 | Leds = 0x1000, |
| 385 | LedIntensitiyMSB = 0x1100, | 385 | LedIntensityMSB = 0x1100, |
| 386 | LedIntensitiyLSB = 0x1200, | 386 | LedIntensityLSB = 0x1200, |
| 387 | ImageFlip = 0x2d00, | 387 | ImageFlip = 0x2d00, |
| 388 | Resolution = 0x2e00, | 388 | Resolution = 0x2e00, |
| 389 | DigitalGainLSB = 0x2e01, | 389 | DigitalGainLSB = 0x2e01, |
diff --git a/src/input_common/helpers/joycon_protocol/nfc.cpp b/src/input_common/helpers/joycon_protocol/nfc.cpp index 09953394b..db83f9ef4 100644 --- a/src/input_common/helpers/joycon_protocol/nfc.cpp +++ b/src/input_common/helpers/joycon_protocol/nfc.cpp | |||
| @@ -519,13 +519,13 @@ Common::Input::DriverResult NfcProtocol::GetMifareData( | |||
| 519 | } | 519 | } |
| 520 | 520 | ||
| 521 | if (output.mcu_report == MCUReport::NFCState && output.mcu_data[1] == 0x10) { | 521 | if (output.mcu_report == MCUReport::NFCState && output.mcu_data[1] == 0x10) { |
| 522 | constexpr std::size_t DATA_LENGHT = 0x10 + 1; | 522 | constexpr std::size_t DATA_LENGTH = 0x10 + 1; |
| 523 | constexpr std::size_t DATA_START = 11; | 523 | constexpr std::size_t DATA_START = 11; |
| 524 | const u8 number_of_elements = output.mcu_data[10]; | 524 | const u8 number_of_elements = output.mcu_data[10]; |
| 525 | for (std::size_t i = 0; i < number_of_elements; i++) { | 525 | for (std::size_t i = 0; i < number_of_elements; i++) { |
| 526 | out_data[i].sector = output.mcu_data[DATA_START + (i * DATA_LENGHT)]; | 526 | out_data[i].sector = output.mcu_data[DATA_START + (i * DATA_LENGTH)]; |
| 527 | memcpy(out_data[i].data.data(), | 527 | memcpy(out_data[i].data.data(), |
| 528 | output.mcu_data.data() + DATA_START + 1 + (i * DATA_LENGHT), | 528 | output.mcu_data.data() + DATA_START + 1 + (i * DATA_LENGTH), |
| 529 | sizeof(MifareReadData::data)); | 529 | sizeof(MifareReadData::data)); |
| 530 | } | 530 | } |
| 531 | package_index++; | 531 | package_index++; |
| @@ -659,7 +659,7 @@ Common::Input::DriverResult NfcProtocol::SendStopPollingRequest(MCUCommandRespon | |||
| 659 | Common::Input::DriverResult NfcProtocol::SendNextPackageRequest(MCUCommandResponse& output, | 659 | Common::Input::DriverResult NfcProtocol::SendNextPackageRequest(MCUCommandResponse& output, |
| 660 | u8 packet_id) { | 660 | u8 packet_id) { |
| 661 | NFCRequestState request{ | 661 | NFCRequestState request{ |
| 662 | .command_argument = NFCCommand::StartWaitingRecieve, | 662 | .command_argument = NFCCommand::StartWaitingReceive, |
| 663 | .block_id = {}, | 663 | .block_id = {}, |
| 664 | .packet_id = packet_id, | 664 | .packet_id = packet_id, |
| 665 | .packet_flag = MCUPacketFlag::LastCommandPacket, | 665 | .packet_flag = MCUPacketFlag::LastCommandPacket, |
diff --git a/src/input_common/helpers/joycon_protocol/rumble.cpp b/src/input_common/helpers/joycon_protocol/rumble.cpp index 7647f505e..9fd0b8470 100644 --- a/src/input_common/helpers/joycon_protocol/rumble.cpp +++ b/src/input_common/helpers/joycon_protocol/rumble.cpp | |||
| @@ -67,7 +67,7 @@ u8 RumbleProtocol::EncodeHighAmplitude(f32 amplitude) const { | |||
| 67 | // More information about these values can be found here: | 67 | // More information about these values can be found here: |
| 68 | // https://github.com/dekuNukem/Nintendo_Switch_Reverse_Engineering/blob/master/rumble_data_table.md | 68 | // https://github.com/dekuNukem/Nintendo_Switch_Reverse_Engineering/blob/master/rumble_data_table.md |
| 69 | 69 | ||
| 70 | static constexpr std::array<std::pair<f32, int>, 101> high_fequency_amplitude{ | 70 | static constexpr std::array<std::pair<f32, int>, 101> high_frequency_amplitude{ |
| 71 | std::pair<f32, int>{0.0f, 0x0}, | 71 | std::pair<f32, int>{0.0f, 0x0}, |
| 72 | {0.01f, 0x2}, | 72 | {0.01f, 0x2}, |
| 73 | {0.012f, 0x4}, | 73 | {0.012f, 0x4}, |
| @@ -171,20 +171,20 @@ u8 RumbleProtocol::EncodeHighAmplitude(f32 amplitude) const { | |||
| 171 | {1.003f, 0xc8}, | 171 | {1.003f, 0xc8}, |
| 172 | }; | 172 | }; |
| 173 | 173 | ||
| 174 | for (const auto& [amplitude_value, code] : high_fequency_amplitude) { | 174 | for (const auto& [amplitude_value, code] : high_frequency_amplitude) { |
| 175 | if (amplitude <= amplitude_value) { | 175 | if (amplitude <= amplitude_value) { |
| 176 | return static_cast<u8>(code); | 176 | return static_cast<u8>(code); |
| 177 | } | 177 | } |
| 178 | } | 178 | } |
| 179 | 179 | ||
| 180 | return static_cast<u8>(high_fequency_amplitude[high_fequency_amplitude.size() - 1].second); | 180 | return static_cast<u8>(high_frequency_amplitude[high_frequency_amplitude.size() - 1].second); |
| 181 | } | 181 | } |
| 182 | 182 | ||
| 183 | u16 RumbleProtocol::EncodeLowAmplitude(f32 amplitude) const { | 183 | u16 RumbleProtocol::EncodeLowAmplitude(f32 amplitude) const { |
| 184 | // More information about these values can be found here: | 184 | // More information about these values can be found here: |
| 185 | // https://github.com/dekuNukem/Nintendo_Switch_Reverse_Engineering/blob/master/rumble_data_table.md | 185 | // https://github.com/dekuNukem/Nintendo_Switch_Reverse_Engineering/blob/master/rumble_data_table.md |
| 186 | 186 | ||
| 187 | static constexpr std::array<std::pair<f32, int>, 101> high_fequency_amplitude{ | 187 | static constexpr std::array<std::pair<f32, int>, 101> high_frequency_amplitude{ |
| 188 | std::pair<f32, int>{0.0f, 0x0040}, | 188 | std::pair<f32, int>{0.0f, 0x0040}, |
| 189 | {0.01f, 0x8040}, | 189 | {0.01f, 0x8040}, |
| 190 | {0.012f, 0x0041}, | 190 | {0.012f, 0x0041}, |
| @@ -288,13 +288,13 @@ u16 RumbleProtocol::EncodeLowAmplitude(f32 amplitude) const { | |||
| 288 | {1.003f, 0x0072}, | 288 | {1.003f, 0x0072}, |
| 289 | }; | 289 | }; |
| 290 | 290 | ||
| 291 | for (const auto& [amplitude_value, code] : high_fequency_amplitude) { | 291 | for (const auto& [amplitude_value, code] : high_frequency_amplitude) { |
| 292 | if (amplitude <= amplitude_value) { | 292 | if (amplitude <= amplitude_value) { |
| 293 | return static_cast<u16>(code); | 293 | return static_cast<u16>(code); |
| 294 | } | 294 | } |
| 295 | } | 295 | } |
| 296 | 296 | ||
| 297 | return static_cast<u16>(high_fequency_amplitude[high_fequency_amplitude.size() - 1].second); | 297 | return static_cast<u16>(high_frequency_amplitude[high_frequency_amplitude.size() - 1].second); |
| 298 | } | 298 | } |
| 299 | 299 | ||
| 300 | } // namespace InputCommon::Joycon | 300 | } // namespace InputCommon::Joycon |
diff --git a/src/input_common/helpers/udp_protocol.h b/src/input_common/helpers/udp_protocol.h index d9643ffe0..dba9f87d9 100644 --- a/src/input_common/helpers/udp_protocol.h +++ b/src/input_common/helpers/udp_protocol.h | |||
| @@ -78,7 +78,7 @@ namespace Request { | |||
| 78 | enum RegisterFlags : u8 { | 78 | enum RegisterFlags : u8 { |
| 79 | AllPads, | 79 | AllPads, |
| 80 | PadID, | 80 | PadID, |
| 81 | PadMACAdddress, | 81 | PadMACAddress, |
| 82 | }; | 82 | }; |
| 83 | 83 | ||
| 84 | struct Version {}; | 84 | struct Version {}; |
diff --git a/src/network/room_member.cpp b/src/network/room_member.cpp index b94cb24ad..a6845273c 100644 --- a/src/network/room_member.cpp +++ b/src/network/room_member.cpp | |||
| @@ -724,7 +724,7 @@ RoomMember::CallbackHandle<RoomInformation> RoomMember::BindOnRoomInformationCha | |||
| 724 | return room_member_impl->Bind(callback); | 724 | return room_member_impl->Bind(callback); |
| 725 | } | 725 | } |
| 726 | 726 | ||
| 727 | RoomMember::CallbackHandle<ChatEntry> RoomMember::BindOnChatMessageRecieved( | 727 | RoomMember::CallbackHandle<ChatEntry> RoomMember::BindOnChatMessageReceived( |
| 728 | std::function<void(const ChatEntry&)> callback) { | 728 | std::function<void(const ChatEntry&)> callback) { |
| 729 | return room_member_impl->Bind(callback); | 729 | return room_member_impl->Bind(callback); |
| 730 | } | 730 | } |
diff --git a/src/network/room_member.h b/src/network/room_member.h index 33ac18e72..37e9ea16a 100644 --- a/src/network/room_member.h +++ b/src/network/room_member.h | |||
| @@ -254,7 +254,7 @@ public: | |||
| 254 | * @param callback The function to call | 254 | * @param callback The function to call |
| 255 | * @return A handle used for removing the function from the registered list | 255 | * @return A handle used for removing the function from the registered list |
| 256 | */ | 256 | */ |
| 257 | CallbackHandle<ChatEntry> BindOnChatMessageRecieved( | 257 | CallbackHandle<ChatEntry> BindOnChatMessageReceived( |
| 258 | std::function<void(const ChatEntry&)> callback); | 258 | std::function<void(const ChatEntry&)> callback); |
| 259 | 259 | ||
| 260 | /** | 260 | /** |
diff --git a/src/shader_recompiler/backend/glsl/glsl_emit_context.cpp b/src/shader_recompiler/backend/glsl/glsl_emit_context.cpp index b2ceeefc4..c5ac7b8f2 100644 --- a/src/shader_recompiler/backend/glsl/glsl_emit_context.cpp +++ b/src/shader_recompiler/backend/glsl/glsl_emit_context.cpp | |||
| @@ -608,8 +608,8 @@ std::string EmitContext::DefineGlobalMemoryFunctions() { | |||
| 608 | const auto aligned_low_addr{fmt::format("{}&{}", addr_xy[0], ssbo_align_mask)}; | 608 | const auto aligned_low_addr{fmt::format("{}&{}", addr_xy[0], ssbo_align_mask)}; |
| 609 | const auto aligned_addr{fmt::format("uvec2({},{})", aligned_low_addr, addr_xy[1])}; | 609 | const auto aligned_addr{fmt::format("uvec2({},{})", aligned_low_addr, addr_xy[1])}; |
| 610 | const auto addr_pack{fmt::format("packUint2x32({})", aligned_addr)}; | 610 | const auto addr_pack{fmt::format("packUint2x32({})", aligned_addr)}; |
| 611 | const auto addr_statment{fmt::format("uint64_t {}={};", ssbo_addr, addr_pack)}; | 611 | const auto addr_statement{fmt::format("uint64_t {}={};", ssbo_addr, addr_pack)}; |
| 612 | func += addr_statment; | 612 | func += addr_statement; |
| 613 | 613 | ||
| 614 | const auto size_vec{fmt::format("uvec2({},{})", size_xy[0], size_xy[1])}; | 614 | const auto size_vec{fmt::format("uvec2({},{})", size_xy[0], size_xy[1])}; |
| 615 | const auto comp_lhs{fmt::format("(addr>={})", ssbo_addr)}; | 615 | const auto comp_lhs{fmt::format("(addr>={})", ssbo_addr)}; |
diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_memory.cpp b/src/shader_recompiler/backend/spirv/emit_spirv_memory.cpp index 8693801c7..bdcbccfde 100644 --- a/src/shader_recompiler/backend/spirv/emit_spirv_memory.cpp +++ b/src/shader_recompiler/backend/spirv/emit_spirv_memory.cpp | |||
| @@ -65,6 +65,14 @@ void WriteStorage32(EmitContext& ctx, const IR::Value& binding, const IR::Value& | |||
| 65 | WriteStorage(ctx, binding, offset, value, ctx.storage_types.U32, sizeof(u32), | 65 | WriteStorage(ctx, binding, offset, value, ctx.storage_types.U32, sizeof(u32), |
| 66 | &StorageDefinitions::U32, index_offset); | 66 | &StorageDefinitions::U32, index_offset); |
| 67 | } | 67 | } |
| 68 | |||
| 69 | void WriteStorageByCasLoop(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset, | ||
| 70 | Id value, Id bit_offset, Id bit_count) { | ||
| 71 | const Id pointer{StoragePointer(ctx, binding, offset, ctx.storage_types.U32, sizeof(u32), | ||
| 72 | &StorageDefinitions::U32)}; | ||
| 73 | ctx.OpFunctionCall(ctx.TypeVoid(), ctx.write_storage_cas_loop_func, pointer, value, bit_offset, | ||
| 74 | bit_count); | ||
| 75 | } | ||
| 68 | } // Anonymous namespace | 76 | } // Anonymous namespace |
| 69 | 77 | ||
| 70 | void EmitLoadGlobalU8(EmitContext&) { | 78 | void EmitLoadGlobalU8(EmitContext&) { |
| @@ -219,26 +227,42 @@ Id EmitLoadStorage128(EmitContext& ctx, const IR::Value& binding, const IR::Valu | |||
| 219 | 227 | ||
| 220 | void EmitWriteStorageU8(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset, | 228 | void EmitWriteStorageU8(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset, |
| 221 | Id value) { | 229 | Id value) { |
| 222 | WriteStorage(ctx, binding, offset, ctx.OpSConvert(ctx.U8, value), ctx.storage_types.U8, | 230 | if (ctx.profile.support_int8) { |
| 223 | sizeof(u8), &StorageDefinitions::U8); | 231 | WriteStorage(ctx, binding, offset, ctx.OpSConvert(ctx.U8, value), ctx.storage_types.U8, |
| 232 | sizeof(u8), &StorageDefinitions::U8); | ||
| 233 | } else { | ||
| 234 | WriteStorageByCasLoop(ctx, binding, offset, value, ctx.BitOffset8(offset), ctx.Const(8u)); | ||
| 235 | } | ||
| 224 | } | 236 | } |
| 225 | 237 | ||
| 226 | void EmitWriteStorageS8(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset, | 238 | void EmitWriteStorageS8(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset, |
| 227 | Id value) { | 239 | Id value) { |
| 228 | WriteStorage(ctx, binding, offset, ctx.OpSConvert(ctx.S8, value), ctx.storage_types.S8, | 240 | if (ctx.profile.support_int8) { |
| 229 | sizeof(s8), &StorageDefinitions::S8); | 241 | WriteStorage(ctx, binding, offset, ctx.OpSConvert(ctx.S8, value), ctx.storage_types.S8, |
| 242 | sizeof(s8), &StorageDefinitions::S8); | ||
| 243 | } else { | ||
| 244 | WriteStorageByCasLoop(ctx, binding, offset, value, ctx.BitOffset8(offset), ctx.Const(8u)); | ||
| 245 | } | ||
| 230 | } | 246 | } |
| 231 | 247 | ||
| 232 | void EmitWriteStorageU16(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset, | 248 | void EmitWriteStorageU16(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset, |
| 233 | Id value) { | 249 | Id value) { |
| 234 | WriteStorage(ctx, binding, offset, ctx.OpSConvert(ctx.U16, value), ctx.storage_types.U16, | 250 | if (ctx.profile.support_int16) { |
| 235 | sizeof(u16), &StorageDefinitions::U16); | 251 | WriteStorage(ctx, binding, offset, ctx.OpSConvert(ctx.U16, value), ctx.storage_types.U16, |
| 252 | sizeof(u16), &StorageDefinitions::U16); | ||
| 253 | } else { | ||
| 254 | WriteStorageByCasLoop(ctx, binding, offset, value, ctx.BitOffset16(offset), ctx.Const(16u)); | ||
| 255 | } | ||
| 236 | } | 256 | } |
| 237 | 257 | ||
| 238 | void EmitWriteStorageS16(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset, | 258 | void EmitWriteStorageS16(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset, |
| 239 | Id value) { | 259 | Id value) { |
| 240 | WriteStorage(ctx, binding, offset, ctx.OpSConvert(ctx.S16, value), ctx.storage_types.S16, | 260 | if (ctx.profile.support_int16) { |
| 241 | sizeof(s16), &StorageDefinitions::S16); | 261 | WriteStorage(ctx, binding, offset, ctx.OpSConvert(ctx.S16, value), ctx.storage_types.S16, |
| 262 | sizeof(s16), &StorageDefinitions::S16); | ||
| 263 | } else { | ||
| 264 | WriteStorageByCasLoop(ctx, binding, offset, value, ctx.BitOffset16(offset), ctx.Const(16u)); | ||
| 265 | } | ||
| 242 | } | 266 | } |
| 243 | 267 | ||
| 244 | void EmitWriteStorage32(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset, | 268 | void EmitWriteStorage32(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset, |
diff --git a/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp b/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp index 0442adc83..a27f2f73a 100644 --- a/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp +++ b/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp | |||
| @@ -480,6 +480,7 @@ EmitContext::EmitContext(const Profile& profile_, const RuntimeInfo& runtime_inf | |||
| 480 | DefineTextures(program.info, texture_binding, bindings.texture_scaling_index); | 480 | DefineTextures(program.info, texture_binding, bindings.texture_scaling_index); |
| 481 | DefineImages(program.info, image_binding, bindings.image_scaling_index); | 481 | DefineImages(program.info, image_binding, bindings.image_scaling_index); |
| 482 | DefineAttributeMemAccess(program.info); | 482 | DefineAttributeMemAccess(program.info); |
| 483 | DefineWriteStorageCasLoopFunction(program.info); | ||
| 483 | DefineGlobalMemoryFunctions(program.info); | 484 | DefineGlobalMemoryFunctions(program.info); |
| 484 | DefineRescalingInput(program.info); | 485 | DefineRescalingInput(program.info); |
| 485 | DefineRenderArea(program.info); | 486 | DefineRenderArea(program.info); |
| @@ -877,6 +878,56 @@ void EmitContext::DefineAttributeMemAccess(const Info& info) { | |||
| 877 | } | 878 | } |
| 878 | } | 879 | } |
| 879 | 880 | ||
| 881 | void EmitContext::DefineWriteStorageCasLoopFunction(const Info& info) { | ||
| 882 | if (profile.support_int8 && profile.support_int16) { | ||
| 883 | return; | ||
| 884 | } | ||
| 885 | if (!info.uses_int8 && !info.uses_int16) { | ||
| 886 | return; | ||
| 887 | } | ||
| 888 | |||
| 889 | AddCapability(spv::Capability::VariablePointersStorageBuffer); | ||
| 890 | |||
| 891 | const Id ptr_type{TypePointer(spv::StorageClass::StorageBuffer, U32[1])}; | ||
| 892 | const Id func_type{TypeFunction(void_id, ptr_type, U32[1], U32[1], U32[1])}; | ||
| 893 | const Id func{OpFunction(void_id, spv::FunctionControlMask::MaskNone, func_type)}; | ||
| 894 | const Id pointer{OpFunctionParameter(ptr_type)}; | ||
| 895 | const Id value{OpFunctionParameter(U32[1])}; | ||
| 896 | const Id bit_offset{OpFunctionParameter(U32[1])}; | ||
| 897 | const Id bit_count{OpFunctionParameter(U32[1])}; | ||
| 898 | |||
| 899 | AddLabel(); | ||
| 900 | const Id scope_device{Const(1u)}; | ||
| 901 | const Id ordering_relaxed{u32_zero_value}; | ||
| 902 | const Id body_label{OpLabel()}; | ||
| 903 | const Id continue_label{OpLabel()}; | ||
| 904 | const Id endloop_label{OpLabel()}; | ||
| 905 | const Id beginloop_label{OpLabel()}; | ||
| 906 | OpBranch(beginloop_label); | ||
| 907 | |||
| 908 | AddLabel(beginloop_label); | ||
| 909 | OpLoopMerge(endloop_label, continue_label, spv::LoopControlMask::MaskNone); | ||
| 910 | OpBranch(body_label); | ||
| 911 | |||
| 912 | AddLabel(body_label); | ||
| 913 | const Id expected_value{OpLoad(U32[1], pointer)}; | ||
| 914 | const Id desired_value{OpBitFieldInsert(U32[1], expected_value, value, bit_offset, bit_count)}; | ||
| 915 | const Id actual_value{OpAtomicCompareExchange(U32[1], pointer, scope_device, ordering_relaxed, | ||
| 916 | ordering_relaxed, desired_value, expected_value)}; | ||
| 917 | const Id store_successful{OpIEqual(U1, expected_value, actual_value)}; | ||
| 918 | OpBranchConditional(store_successful, endloop_label, continue_label); | ||
| 919 | |||
| 920 | AddLabel(endloop_label); | ||
| 921 | OpReturn(); | ||
| 922 | |||
| 923 | AddLabel(continue_label); | ||
| 924 | OpBranch(beginloop_label); | ||
| 925 | |||
| 926 | OpFunctionEnd(); | ||
| 927 | |||
| 928 | write_storage_cas_loop_func = func; | ||
| 929 | } | ||
| 930 | |||
| 880 | void EmitContext::DefineGlobalMemoryFunctions(const Info& info) { | 931 | void EmitContext::DefineGlobalMemoryFunctions(const Info& info) { |
| 881 | if (!info.uses_global_memory || !profile.support_int64) { | 932 | if (!info.uses_global_memory || !profile.support_int64) { |
| 882 | return; | 933 | return; |
diff --git a/src/shader_recompiler/backend/spirv/spirv_emit_context.h b/src/shader_recompiler/backend/spirv/spirv_emit_context.h index 56019ad89..40adcb6b6 100644 --- a/src/shader_recompiler/backend/spirv/spirv_emit_context.h +++ b/src/shader_recompiler/backend/spirv/spirv_emit_context.h | |||
| @@ -325,6 +325,8 @@ public: | |||
| 325 | Id f32x2_min_cas{}; | 325 | Id f32x2_min_cas{}; |
| 326 | Id f32x2_max_cas{}; | 326 | Id f32x2_max_cas{}; |
| 327 | 327 | ||
| 328 | Id write_storage_cas_loop_func{}; | ||
| 329 | |||
| 328 | Id load_global_func_u32{}; | 330 | Id load_global_func_u32{}; |
| 329 | Id load_global_func_u32x2{}; | 331 | Id load_global_func_u32x2{}; |
| 330 | Id load_global_func_u32x4{}; | 332 | Id load_global_func_u32x4{}; |
| @@ -372,6 +374,7 @@ private: | |||
| 372 | void DefineTextures(const Info& info, u32& binding, u32& scaling_index); | 374 | void DefineTextures(const Info& info, u32& binding, u32& scaling_index); |
| 373 | void DefineImages(const Info& info, u32& binding, u32& scaling_index); | 375 | void DefineImages(const Info& info, u32& binding, u32& scaling_index); |
| 374 | void DefineAttributeMemAccess(const Info& info); | 376 | void DefineAttributeMemAccess(const Info& info); |
| 377 | void DefineWriteStorageCasLoopFunction(const Info& info); | ||
| 375 | void DefineGlobalMemoryFunctions(const Info& info); | 378 | void DefineGlobalMemoryFunctions(const Info& info); |
| 376 | void DefineRescalingInput(const Info& info); | 379 | void DefineRescalingInput(const Info& info); |
| 377 | void DefineRescalingInputPushConstant(); | 380 | void DefineRescalingInputPushConstant(); |
diff --git a/src/video_core/renderer_vulkan/vk_scheduler.h b/src/video_core/renderer_vulkan/vk_scheduler.h index f8d8ca80a..51e7ab1e1 100644 --- a/src/video_core/renderer_vulkan/vk_scheduler.h +++ b/src/video_core/renderer_vulkan/vk_scheduler.h | |||
| @@ -55,7 +55,7 @@ public: | |||
| 55 | /// Requests to begin a renderpass. | 55 | /// Requests to begin a renderpass. |
| 56 | void RequestRenderpass(const Framebuffer* framebuffer); | 56 | void RequestRenderpass(const Framebuffer* framebuffer); |
| 57 | 57 | ||
| 58 | /// Requests the current executino context to be able to execute operations only allowed outside | 58 | /// Requests the current execution context to be able to execute operations only allowed outside |
| 59 | /// of a renderpass. | 59 | /// of a renderpass. |
| 60 | void RequestOutsideRenderPassOperationContext(); | 60 | void RequestOutsideRenderPassOperationContext(); |
| 61 | 61 | ||
diff --git a/src/yuzu/applets/qt_amiibo_settings.cpp b/src/yuzu/applets/qt_amiibo_settings.cpp index b457a736a..b91796dde 100644 --- a/src/yuzu/applets/qt_amiibo_settings.cpp +++ b/src/yuzu/applets/qt_amiibo_settings.cpp | |||
| @@ -36,7 +36,7 @@ QtAmiiboSettingsDialog::QtAmiiboSettingsDialog(QWidget* parent, | |||
| 36 | QtAmiiboSettingsDialog::~QtAmiiboSettingsDialog() = default; | 36 | QtAmiiboSettingsDialog::~QtAmiiboSettingsDialog() = default; |
| 37 | 37 | ||
| 38 | int QtAmiiboSettingsDialog::exec() { | 38 | int QtAmiiboSettingsDialog::exec() { |
| 39 | if (!is_initalized) { | 39 | if (!is_initialized) { |
| 40 | return QDialog::Rejected; | 40 | return QDialog::Rejected; |
| 41 | } | 41 | } |
| 42 | return QDialog::exec(); | 42 | return QDialog::exec(); |
| @@ -66,7 +66,7 @@ void QtAmiiboSettingsDialog::LoadInfo() { | |||
| 66 | QString::fromStdString(input_subsystem->GetVirtualAmiibo()->GetLastFilePath())); | 66 | QString::fromStdString(input_subsystem->GetVirtualAmiibo()->GetLastFilePath())); |
| 67 | 67 | ||
| 68 | SetSettingsDescription(); | 68 | SetSettingsDescription(); |
| 69 | is_initalized = true; | 69 | is_initialized = true; |
| 70 | } | 70 | } |
| 71 | 71 | ||
| 72 | void QtAmiiboSettingsDialog::LoadAmiiboInfo() { | 72 | void QtAmiiboSettingsDialog::LoadAmiiboInfo() { |
diff --git a/src/yuzu/applets/qt_amiibo_settings.h b/src/yuzu/applets/qt_amiibo_settings.h index ee66a0255..3833cf6f2 100644 --- a/src/yuzu/applets/qt_amiibo_settings.h +++ b/src/yuzu/applets/qt_amiibo_settings.h | |||
| @@ -58,7 +58,7 @@ private: | |||
| 58 | Core::Frontend::CabinetParameters parameters; | 58 | Core::Frontend::CabinetParameters parameters; |
| 59 | 59 | ||
| 60 | // If false amiibo settings failed to load | 60 | // If false amiibo settings failed to load |
| 61 | bool is_initalized{}; | 61 | bool is_initialized{}; |
| 62 | }; | 62 | }; |
| 63 | 63 | ||
| 64 | class QtAmiiboSettings final : public QObject, public Core::Frontend::CabinetApplet { | 64 | class QtAmiiboSettings final : public QObject, public Core::Frontend::CabinetApplet { |
diff --git a/src/yuzu/applets/qt_controller.cpp b/src/yuzu/applets/qt_controller.cpp index 8b340ee6c..48ce860ad 100644 --- a/src/yuzu/applets/qt_controller.cpp +++ b/src/yuzu/applets/qt_controller.cpp | |||
| @@ -41,7 +41,7 @@ void UpdateController(Core::HID::EmulatedController* controller, | |||
| 41 | bool IsControllerCompatible(Core::HID::NpadStyleIndex controller_type, | 41 | bool IsControllerCompatible(Core::HID::NpadStyleIndex controller_type, |
| 42 | Core::Frontend::ControllerParameters parameters) { | 42 | Core::Frontend::ControllerParameters parameters) { |
| 43 | switch (controller_type) { | 43 | switch (controller_type) { |
| 44 | case Core::HID::NpadStyleIndex::ProController: | 44 | case Core::HID::NpadStyleIndex::Fullkey: |
| 45 | return parameters.allow_pro_controller; | 45 | return parameters.allow_pro_controller; |
| 46 | case Core::HID::NpadStyleIndex::JoyconDual: | 46 | case Core::HID::NpadStyleIndex::JoyconDual: |
| 47 | return parameters.allow_dual_joycons; | 47 | return parameters.allow_dual_joycons; |
| @@ -462,7 +462,7 @@ void QtControllerSelectorDialog::SetEmulatedControllers(std::size_t player_index | |||
| 462 | }; | 462 | }; |
| 463 | 463 | ||
| 464 | if (npad_style_set.fullkey == 1) { | 464 | if (npad_style_set.fullkey == 1) { |
| 465 | add_item(Core::HID::NpadStyleIndex::ProController, tr("Pro Controller")); | 465 | add_item(Core::HID::NpadStyleIndex::Fullkey, tr("Pro Controller")); |
| 466 | } | 466 | } |
| 467 | 467 | ||
| 468 | if (npad_style_set.joycon_dual == 1) { | 468 | if (npad_style_set.joycon_dual == 1) { |
| @@ -519,7 +519,7 @@ Core::HID::NpadStyleIndex QtControllerSelectorDialog::GetControllerTypeFromIndex | |||
| 519 | [index](const auto& pair) { return pair.first == index; }); | 519 | [index](const auto& pair) { return pair.first == index; }); |
| 520 | 520 | ||
| 521 | if (it == pairs.end()) { | 521 | if (it == pairs.end()) { |
| 522 | return Core::HID::NpadStyleIndex::ProController; | 522 | return Core::HID::NpadStyleIndex::Fullkey; |
| 523 | } | 523 | } |
| 524 | 524 | ||
| 525 | return it->second; | 525 | return it->second; |
| @@ -549,7 +549,7 @@ void QtControllerSelectorDialog::UpdateControllerIcon(std::size_t player_index) | |||
| 549 | const QString stylesheet = [this, player_index] { | 549 | const QString stylesheet = [this, player_index] { |
| 550 | switch (GetControllerTypeFromIndex(emulated_controllers[player_index]->currentIndex(), | 550 | switch (GetControllerTypeFromIndex(emulated_controllers[player_index]->currentIndex(), |
| 551 | player_index)) { | 551 | player_index)) { |
| 552 | case Core::HID::NpadStyleIndex::ProController: | 552 | case Core::HID::NpadStyleIndex::Fullkey: |
| 553 | case Core::HID::NpadStyleIndex::GameCube: | 553 | case Core::HID::NpadStyleIndex::GameCube: |
| 554 | return QStringLiteral("image: url(:/controller/applet_pro_controller%0); "); | 554 | return QStringLiteral("image: url(:/controller/applet_pro_controller%0); "); |
| 555 | case Core::HID::NpadStyleIndex::JoyconDual: | 555 | case Core::HID::NpadStyleIndex::JoyconDual: |
diff --git a/src/yuzu/applets/qt_software_keyboard.cpp b/src/yuzu/applets/qt_software_keyboard.cpp index bbe17c35e..ac81ace9e 100644 --- a/src/yuzu/applets/qt_software_keyboard.cpp +++ b/src/yuzu/applets/qt_software_keyboard.cpp | |||
| @@ -832,7 +832,7 @@ void QtSoftwareKeyboardDialog::SetControllerImage() { | |||
| 832 | }(); | 832 | }(); |
| 833 | 833 | ||
| 834 | switch (controller_type) { | 834 | switch (controller_type) { |
| 835 | case Core::HID::NpadStyleIndex::ProController: | 835 | case Core::HID::NpadStyleIndex::Fullkey: |
| 836 | case Core::HID::NpadStyleIndex::GameCube: | 836 | case Core::HID::NpadStyleIndex::GameCube: |
| 837 | ui->icon_controller->setStyleSheet( | 837 | ui->icon_controller->setStyleSheet( |
| 838 | QStringLiteral("image: url(:/overlay/controller_pro%1.png);").arg(theme)); | 838 | QStringLiteral("image: url(:/overlay/controller_pro%1.png);").arg(theme)); |
diff --git a/src/yuzu/bootmanager.h b/src/yuzu/bootmanager.h index 60edd464c..ae12b3481 100644 --- a/src/yuzu/bootmanager.h +++ b/src/yuzu/bootmanager.h | |||
| @@ -170,7 +170,7 @@ public: | |||
| 170 | 170 | ||
| 171 | void resizeEvent(QResizeEvent* event) override; | 171 | void resizeEvent(QResizeEvent* event) override; |
| 172 | 172 | ||
| 173 | /// Converts a Qt keybard key into NativeKeyboard key | 173 | /// Converts a Qt keyboard key into NativeKeyboard key |
| 174 | static int QtKeyToSwitchKey(Qt::Key qt_keys); | 174 | static int QtKeyToSwitchKey(Qt::Key qt_keys); |
| 175 | 175 | ||
| 176 | /// Converts a Qt modifier keys into NativeKeyboard modifier keys | 176 | /// Converts a Qt modifier keys into NativeKeyboard modifier keys |
diff --git a/src/yuzu/configuration/configure_input_player.cpp b/src/yuzu/configuration/configure_input_player.cpp index 9745757c7..400917f9d 100644 --- a/src/yuzu/configuration/configure_input_player.cpp +++ b/src/yuzu/configuration/configure_input_player.cpp | |||
| @@ -1094,7 +1094,7 @@ void ConfigureInputPlayer::SetConnectableControllers() { | |||
| 1094 | }; | 1094 | }; |
| 1095 | 1095 | ||
| 1096 | if (npad_style_set.fullkey == 1) { | 1096 | if (npad_style_set.fullkey == 1) { |
| 1097 | add_item(Core::HID::NpadStyleIndex::ProController, tr("Pro Controller")); | 1097 | add_item(Core::HID::NpadStyleIndex::Fullkey, tr("Pro Controller")); |
| 1098 | } | 1098 | } |
| 1099 | 1099 | ||
| 1100 | if (npad_style_set.joycon_dual == 1) { | 1100 | if (npad_style_set.joycon_dual == 1) { |
| @@ -1149,7 +1149,7 @@ Core::HID::NpadStyleIndex ConfigureInputPlayer::GetControllerTypeFromIndex(int i | |||
| 1149 | [index](const auto& pair) { return pair.first == index; }); | 1149 | [index](const auto& pair) { return pair.first == index; }); |
| 1150 | 1150 | ||
| 1151 | if (it == index_controller_type_pairs.end()) { | 1151 | if (it == index_controller_type_pairs.end()) { |
| 1152 | return Core::HID::NpadStyleIndex::ProController; | 1152 | return Core::HID::NpadStyleIndex::Fullkey; |
| 1153 | } | 1153 | } |
| 1154 | 1154 | ||
| 1155 | return it->second; | 1155 | return it->second; |
| @@ -1178,7 +1178,7 @@ void ConfigureInputPlayer::UpdateInputDevices() { | |||
| 1178 | void ConfigureInputPlayer::UpdateControllerAvailableButtons() { | 1178 | void ConfigureInputPlayer::UpdateControllerAvailableButtons() { |
| 1179 | auto layout = GetControllerTypeFromIndex(ui->comboControllerType->currentIndex()); | 1179 | auto layout = GetControllerTypeFromIndex(ui->comboControllerType->currentIndex()); |
| 1180 | if (debug) { | 1180 | if (debug) { |
| 1181 | layout = Core::HID::NpadStyleIndex::ProController; | 1181 | layout = Core::HID::NpadStyleIndex::Fullkey; |
| 1182 | } | 1182 | } |
| 1183 | 1183 | ||
| 1184 | // List of all the widgets that will be hidden by any of the following layouts that need | 1184 | // List of all the widgets that will be hidden by any of the following layouts that need |
| @@ -1206,7 +1206,7 @@ void ConfigureInputPlayer::UpdateControllerAvailableButtons() { | |||
| 1206 | 1206 | ||
| 1207 | std::vector<QWidget*> layout_hidden; | 1207 | std::vector<QWidget*> layout_hidden; |
| 1208 | switch (layout) { | 1208 | switch (layout) { |
| 1209 | case Core::HID::NpadStyleIndex::ProController: | 1209 | case Core::HID::NpadStyleIndex::Fullkey: |
| 1210 | case Core::HID::NpadStyleIndex::Handheld: | 1210 | case Core::HID::NpadStyleIndex::Handheld: |
| 1211 | layout_hidden = { | 1211 | layout_hidden = { |
| 1212 | ui->buttonShoulderButtonsSLSRLeft, | 1212 | ui->buttonShoulderButtonsSLSRLeft, |
| @@ -1254,7 +1254,7 @@ void ConfigureInputPlayer::UpdateControllerAvailableButtons() { | |||
| 1254 | void ConfigureInputPlayer::UpdateControllerEnabledButtons() { | 1254 | void ConfigureInputPlayer::UpdateControllerEnabledButtons() { |
| 1255 | auto layout = GetControllerTypeFromIndex(ui->comboControllerType->currentIndex()); | 1255 | auto layout = GetControllerTypeFromIndex(ui->comboControllerType->currentIndex()); |
| 1256 | if (debug) { | 1256 | if (debug) { |
| 1257 | layout = Core::HID::NpadStyleIndex::ProController; | 1257 | layout = Core::HID::NpadStyleIndex::Fullkey; |
| 1258 | } | 1258 | } |
| 1259 | 1259 | ||
| 1260 | // List of all the widgets that will be disabled by any of the following layouts that need | 1260 | // List of all the widgets that will be disabled by any of the following layouts that need |
| @@ -1271,7 +1271,7 @@ void ConfigureInputPlayer::UpdateControllerEnabledButtons() { | |||
| 1271 | 1271 | ||
| 1272 | std::vector<QWidget*> layout_disable; | 1272 | std::vector<QWidget*> layout_disable; |
| 1273 | switch (layout) { | 1273 | switch (layout) { |
| 1274 | case Core::HID::NpadStyleIndex::ProController: | 1274 | case Core::HID::NpadStyleIndex::Fullkey: |
| 1275 | case Core::HID::NpadStyleIndex::JoyconDual: | 1275 | case Core::HID::NpadStyleIndex::JoyconDual: |
| 1276 | case Core::HID::NpadStyleIndex::Handheld: | 1276 | case Core::HID::NpadStyleIndex::Handheld: |
| 1277 | case Core::HID::NpadStyleIndex::JoyconLeft: | 1277 | case Core::HID::NpadStyleIndex::JoyconLeft: |
| @@ -1304,7 +1304,7 @@ void ConfigureInputPlayer::UpdateMotionButtons() { | |||
| 1304 | 1304 | ||
| 1305 | // Show/hide the "Motion 1/2" groupboxes depending on the currently selected controller. | 1305 | // Show/hide the "Motion 1/2" groupboxes depending on the currently selected controller. |
| 1306 | switch (GetControllerTypeFromIndex(ui->comboControllerType->currentIndex())) { | 1306 | switch (GetControllerTypeFromIndex(ui->comboControllerType->currentIndex())) { |
| 1307 | case Core::HID::NpadStyleIndex::ProController: | 1307 | case Core::HID::NpadStyleIndex::Fullkey: |
| 1308 | case Core::HID::NpadStyleIndex::JoyconLeft: | 1308 | case Core::HID::NpadStyleIndex::JoyconLeft: |
| 1309 | case Core::HID::NpadStyleIndex::Handheld: | 1309 | case Core::HID::NpadStyleIndex::Handheld: |
| 1310 | // Show "Motion 1" and hide "Motion 2". | 1310 | // Show "Motion 1" and hide "Motion 2". |
| @@ -1333,11 +1333,11 @@ void ConfigureInputPlayer::UpdateMotionButtons() { | |||
| 1333 | void ConfigureInputPlayer::UpdateControllerButtonNames() { | 1333 | void ConfigureInputPlayer::UpdateControllerButtonNames() { |
| 1334 | auto layout = GetControllerTypeFromIndex(ui->comboControllerType->currentIndex()); | 1334 | auto layout = GetControllerTypeFromIndex(ui->comboControllerType->currentIndex()); |
| 1335 | if (debug) { | 1335 | if (debug) { |
| 1336 | layout = Core::HID::NpadStyleIndex::ProController; | 1336 | layout = Core::HID::NpadStyleIndex::Fullkey; |
| 1337 | } | 1337 | } |
| 1338 | 1338 | ||
| 1339 | switch (layout) { | 1339 | switch (layout) { |
| 1340 | case Core::HID::NpadStyleIndex::ProController: | 1340 | case Core::HID::NpadStyleIndex::Fullkey: |
| 1341 | case Core::HID::NpadStyleIndex::JoyconDual: | 1341 | case Core::HID::NpadStyleIndex::JoyconDual: |
| 1342 | case Core::HID::NpadStyleIndex::Handheld: | 1342 | case Core::HID::NpadStyleIndex::Handheld: |
| 1343 | case Core::HID::NpadStyleIndex::JoyconLeft: | 1343 | case Core::HID::NpadStyleIndex::JoyconLeft: |
diff --git a/src/yuzu/configuration/configure_input_player_widget.cpp b/src/yuzu/configuration/configure_input_player_widget.cpp index 19fdca7d3..b3d9d8006 100644 --- a/src/yuzu/configuration/configure_input_player_widget.cpp +++ b/src/yuzu/configuration/configure_input_player_widget.cpp | |||
| @@ -244,7 +244,7 @@ void PlayerControlPreview::paintEvent(QPaintEvent* event) { | |||
| 244 | case Core::HID::NpadStyleIndex::GameCube: | 244 | case Core::HID::NpadStyleIndex::GameCube: |
| 245 | DrawGCController(p, center); | 245 | DrawGCController(p, center); |
| 246 | break; | 246 | break; |
| 247 | case Core::HID::NpadStyleIndex::ProController: | 247 | case Core::HID::NpadStyleIndex::Fullkey: |
| 248 | default: | 248 | default: |
| 249 | DrawProController(p, center); | 249 | DrawProController(p, center); |
| 250 | break; | 250 | break; |
| @@ -845,12 +845,12 @@ void PlayerControlPreview::DrawProController(QPainter& p, const QPointF center) | |||
| 845 | DrawSymbol(p, face_center + QPoint(-face_distance, 1), Symbol::Y, text_size); | 845 | DrawSymbol(p, face_center + QPoint(-face_distance, 1), Symbol::Y, text_size); |
| 846 | 846 | ||
| 847 | // D-pad buttons | 847 | // D-pad buttons |
| 848 | const QPointF dpad_postion = center + QPoint(-61, 0); | 848 | const QPointF dpad_position = center + QPoint(-61, 0); |
| 849 | DrawArrowButton(p, dpad_postion, Direction::Up, button_values[DUp]); | 849 | DrawArrowButton(p, dpad_position, Direction::Up, button_values[DUp]); |
| 850 | DrawArrowButton(p, dpad_postion, Direction::Left, button_values[DLeft]); | 850 | DrawArrowButton(p, dpad_position, Direction::Left, button_values[DLeft]); |
| 851 | DrawArrowButton(p, dpad_postion, Direction::Right, button_values[DRight]); | 851 | DrawArrowButton(p, dpad_position, Direction::Right, button_values[DRight]); |
| 852 | DrawArrowButton(p, dpad_postion, Direction::Down, button_values[DDown]); | 852 | DrawArrowButton(p, dpad_position, Direction::Down, button_values[DDown]); |
| 853 | DrawArrowButtonOutline(p, dpad_postion); | 853 | DrawArrowButtonOutline(p, dpad_position); |
| 854 | 854 | ||
| 855 | // ZL and ZR buttons | 855 | // ZL and ZR buttons |
| 856 | p.setPen(colors.outline); | 856 | p.setPen(colors.outline); |
| @@ -935,13 +935,13 @@ void PlayerControlPreview::DrawGCController(QPainter& p, const QPointF center) { | |||
| 935 | DrawSymbol(p, center + QPoint(100, -83), Symbol::Y, text_size); | 935 | DrawSymbol(p, center + QPoint(100, -83), Symbol::Y, text_size); |
| 936 | 936 | ||
| 937 | // D-pad buttons | 937 | // D-pad buttons |
| 938 | const QPointF dpad_postion = center + QPoint(-61, 37); | 938 | const QPointF dpad_position = center + QPoint(-61, 37); |
| 939 | const float dpad_size = 0.8f; | 939 | const float dpad_size = 0.8f; |
| 940 | DrawArrowButton(p, dpad_postion, Direction::Up, button_values[DUp], dpad_size); | 940 | DrawArrowButton(p, dpad_position, Direction::Up, button_values[DUp], dpad_size); |
| 941 | DrawArrowButton(p, dpad_postion, Direction::Left, button_values[DLeft], dpad_size); | 941 | DrawArrowButton(p, dpad_position, Direction::Left, button_values[DLeft], dpad_size); |
| 942 | DrawArrowButton(p, dpad_postion, Direction::Right, button_values[DRight], dpad_size); | 942 | DrawArrowButton(p, dpad_position, Direction::Right, button_values[DRight], dpad_size); |
| 943 | DrawArrowButton(p, dpad_postion, Direction::Down, button_values[DDown], dpad_size); | 943 | DrawArrowButton(p, dpad_position, Direction::Down, button_values[DDown], dpad_size); |
| 944 | DrawArrowButtonOutline(p, dpad_postion, dpad_size); | 944 | DrawArrowButtonOutline(p, dpad_position, dpad_size); |
| 945 | 945 | ||
| 946 | // Minus and Plus buttons | 946 | // Minus and Plus buttons |
| 947 | p.setPen(colors.outline); | 947 | p.setPen(colors.outline); |
diff --git a/src/yuzu/configuration/configure_profile_manager.cpp b/src/yuzu/configuration/configure_profile_manager.cpp index fa5f383d6..12a04b9a0 100644 --- a/src/yuzu/configuration/configure_profile_manager.cpp +++ b/src/yuzu/configuration/configure_profile_manager.cpp | |||
| @@ -205,6 +205,7 @@ void ConfigureProfileManager::AddUser() { | |||
| 205 | 205 | ||
| 206 | const auto uuid = Common::UUID::MakeRandom(); | 206 | const auto uuid = Common::UUID::MakeRandom(); |
| 207 | profile_manager.CreateNewUser(uuid, username.toStdString()); | 207 | profile_manager.CreateNewUser(uuid, username.toStdString()); |
| 208 | profile_manager.WriteUserSaveFile(); | ||
| 208 | 209 | ||
| 209 | item_model->appendRow(new QStandardItem{GetIcon(uuid), FormatUserEntryText(username, uuid)}); | 210 | item_model->appendRow(new QStandardItem{GetIcon(uuid), FormatUserEntryText(username, uuid)}); |
| 210 | } | 211 | } |
| @@ -228,6 +229,7 @@ void ConfigureProfileManager::RenameUser() { | |||
| 228 | std::copy(username_std.begin(), username_std.end(), profile.username.begin()); | 229 | std::copy(username_std.begin(), username_std.end(), profile.username.begin()); |
| 229 | 230 | ||
| 230 | profile_manager.SetProfileBase(*uuid, profile); | 231 | profile_manager.SetProfileBase(*uuid, profile); |
| 232 | profile_manager.WriteUserSaveFile(); | ||
| 231 | 233 | ||
| 232 | item_model->setItem( | 234 | item_model->setItem( |
| 233 | user, 0, | 235 | user, 0, |
| @@ -256,6 +258,8 @@ void ConfigureProfileManager::DeleteUser(const Common::UUID& uuid) { | |||
| 256 | return; | 258 | return; |
| 257 | } | 259 | } |
| 258 | 260 | ||
| 261 | profile_manager.WriteUserSaveFile(); | ||
| 262 | |||
| 259 | item_model->removeRows(tree_view->currentIndex().row(), 1); | 263 | item_model->removeRows(tree_view->currentIndex().row(), 1); |
| 260 | tree_view->clearSelection(); | 264 | tree_view->clearSelection(); |
| 261 | 265 | ||
diff --git a/src/yuzu/configuration/configure_system.cpp b/src/yuzu/configuration/configure_system.cpp index 7cbf43775..b0b84f967 100644 --- a/src/yuzu/configuration/configure_system.cpp +++ b/src/yuzu/configuration/configure_system.cpp | |||
| @@ -121,7 +121,7 @@ void ConfigureSystem::Setup(const ConfigurationShared::Builder& builder) { | |||
| 121 | } | 121 | } |
| 122 | 122 | ||
| 123 | if (setting->Id() == Settings::values.region_index.Id()) { | 123 | if (setting->Id() == Settings::values.region_index.Id()) { |
| 124 | // Keep track of the region_index (and langauge_index) combobox to validate the selected | 124 | // Keep track of the region_index (and language_index) combobox to validate the selected |
| 125 | // settings | 125 | // settings |
| 126 | combo_region = widget->combobox; | 126 | combo_region = widget->combobox; |
| 127 | } else if (setting->Id() == Settings::values.language_index.Id()) { | 127 | } else if (setting->Id() == Settings::values.language_index.Id()) { |
diff --git a/src/yuzu/configuration/shared_widget.cpp b/src/yuzu/configuration/shared_widget.cpp index 941683a43..85f4f7655 100644 --- a/src/yuzu/configuration/shared_widget.cpp +++ b/src/yuzu/configuration/shared_widget.cpp | |||
| @@ -750,12 +750,12 @@ Widget::Widget(Settings::BasicSetting* setting_, const TranslationMap& translati | |||
| 750 | } | 750 | } |
| 751 | 751 | ||
| 752 | apply_funcs.push_back([load_func, setting_](bool powered_on) { | 752 | apply_funcs.push_back([load_func, setting_](bool powered_on) { |
| 753 | if (setting_->RuntimeModfiable() || !powered_on) { | 753 | if (setting_->RuntimeModifiable() || !powered_on) { |
| 754 | load_func(); | 754 | load_func(); |
| 755 | } | 755 | } |
| 756 | }); | 756 | }); |
| 757 | 757 | ||
| 758 | bool enable = runtime_lock || setting.RuntimeModfiable(); | 758 | bool enable = runtime_lock || setting.RuntimeModifiable(); |
| 759 | if (setting.Switchable() && Settings::IsConfiguringGlobal() && !runtime_lock) { | 759 | if (setting.Switchable() && Settings::IsConfiguringGlobal() && !runtime_lock) { |
| 760 | enable &= setting.UsingGlobal(); | 760 | enable &= setting.UsingGlobal(); |
| 761 | } | 761 | } |
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index 4f4c75f5c..33756febf 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp | |||
| @@ -2292,14 +2292,14 @@ void GMainWindow::OnGameListOpenFolder(u64 program_id, GameListOpenTarget target | |||
| 2292 | ASSERT(user_id); | 2292 | ASSERT(user_id); |
| 2293 | 2293 | ||
| 2294 | const auto user_save_data_path = FileSys::SaveDataFactory::GetFullPath( | 2294 | const auto user_save_data_path = FileSys::SaveDataFactory::GetFullPath( |
| 2295 | *system, vfs_nand_dir, FileSys::SaveDataSpaceId::NandUser, | 2295 | {}, vfs_nand_dir, FileSys::SaveDataSpaceId::NandUser, |
| 2296 | FileSys::SaveDataType::SaveData, program_id, user_id->AsU128(), 0); | 2296 | FileSys::SaveDataType::SaveData, program_id, user_id->AsU128(), 0); |
| 2297 | 2297 | ||
| 2298 | path = Common::FS::ConcatPathSafe(nand_dir, user_save_data_path); | 2298 | path = Common::FS::ConcatPathSafe(nand_dir, user_save_data_path); |
| 2299 | } else { | 2299 | } else { |
| 2300 | // Device save data | 2300 | // Device save data |
| 2301 | const auto device_save_data_path = FileSys::SaveDataFactory::GetFullPath( | 2301 | const auto device_save_data_path = FileSys::SaveDataFactory::GetFullPath( |
| 2302 | *system, vfs_nand_dir, FileSys::SaveDataSpaceId::NandUser, | 2302 | {}, vfs_nand_dir, FileSys::SaveDataSpaceId::NandUser, |
| 2303 | FileSys::SaveDataType::SaveData, program_id, {}, 0); | 2303 | FileSys::SaveDataType::SaveData, program_id, {}, 0); |
| 2304 | 2304 | ||
| 2305 | path = Common::FS::ConcatPathSafe(nand_dir, device_save_data_path); | 2305 | path = Common::FS::ConcatPathSafe(nand_dir, device_save_data_path); |
| @@ -2662,8 +2662,8 @@ void GMainWindow::RemoveCacheStorage(u64 program_id) { | |||
| 2662 | vfs->OpenDirectory(Common::FS::PathToUTF8String(nand_dir), FileSys::Mode::Read); | 2662 | vfs->OpenDirectory(Common::FS::PathToUTF8String(nand_dir), FileSys::Mode::Read); |
| 2663 | 2663 | ||
| 2664 | const auto cache_storage_path = FileSys::SaveDataFactory::GetFullPath( | 2664 | const auto cache_storage_path = FileSys::SaveDataFactory::GetFullPath( |
| 2665 | *system, vfs_nand_dir, FileSys::SaveDataSpaceId::NandUser, | 2665 | {}, vfs_nand_dir, FileSys::SaveDataSpaceId::NandUser, FileSys::SaveDataType::CacheStorage, |
| 2666 | FileSys::SaveDataType::CacheStorage, 0 /* program_id */, {}, 0); | 2666 | 0 /* program_id */, {}, 0); |
| 2667 | 2667 | ||
| 2668 | const auto path = Common::FS::ConcatPathSafe(nand_dir, cache_storage_path); | 2668 | const auto path = Common::FS::ConcatPathSafe(nand_dir, cache_storage_path); |
| 2669 | 2669 | ||
| @@ -3988,7 +3988,7 @@ void GMainWindow::OnToggleDockedMode() { | |||
| 3988 | tr("Handheld controller can't be used on docked mode. Pro " | 3988 | tr("Handheld controller can't be used on docked mode. Pro " |
| 3989 | "controller will be selected.")); | 3989 | "controller will be selected.")); |
| 3990 | handheld->Disconnect(); | 3990 | handheld->Disconnect(); |
| 3991 | player_1->SetNpadStyleIndex(Core::HID::NpadStyleIndex::ProController); | 3991 | player_1->SetNpadStyleIndex(Core::HID::NpadStyleIndex::Fullkey); |
| 3992 | player_1->Connect(); | 3992 | player_1->Connect(); |
| 3993 | controller_dialog->refreshConfiguration(); | 3993 | controller_dialog->refreshConfiguration(); |
| 3994 | } | 3994 | } |
diff --git a/src/yuzu/multiplayer/chat_room.cpp b/src/yuzu/multiplayer/chat_room.cpp index dec9696c1..4463616b4 100644 --- a/src/yuzu/multiplayer/chat_room.cpp +++ b/src/yuzu/multiplayer/chat_room.cpp | |||
| @@ -206,7 +206,7 @@ void ChatRoom::Initialize(Network::RoomNetwork* room_network_) { | |||
| 206 | room_network = room_network_; | 206 | room_network = room_network_; |
| 207 | // setup the callbacks for network updates | 207 | // setup the callbacks for network updates |
| 208 | if (auto member = room_network->GetRoomMember().lock()) { | 208 | if (auto member = room_network->GetRoomMember().lock()) { |
| 209 | member->BindOnChatMessageRecieved( | 209 | member->BindOnChatMessageReceived( |
| 210 | [this](const Network::ChatEntry& chat) { emit ChatReceived(chat); }); | 210 | [this](const Network::ChatEntry& chat) { emit ChatReceived(chat); }); |
| 211 | member->BindOnStatusMessageReceived( | 211 | member->BindOnStatusMessageReceived( |
| 212 | [this](const Network::StatusMessageEntry& status_message) { | 212 | [this](const Network::StatusMessageEntry& status_message) { |
diff --git a/src/yuzu/util/controller_navigation.cpp b/src/yuzu/util/controller_navigation.cpp index 2690b075d..0dbfca243 100644 --- a/src/yuzu/util/controller_navigation.cpp +++ b/src/yuzu/util/controller_navigation.cpp | |||
| @@ -66,7 +66,7 @@ void ControllerNavigation::ControllerUpdateButton() { | |||
| 66 | } | 66 | } |
| 67 | 67 | ||
| 68 | switch (controller_type) { | 68 | switch (controller_type) { |
| 69 | case Core::HID::NpadStyleIndex::ProController: | 69 | case Core::HID::NpadStyleIndex::Fullkey: |
| 70 | case Core::HID::NpadStyleIndex::JoyconDual: | 70 | case Core::HID::NpadStyleIndex::JoyconDual: |
| 71 | case Core::HID::NpadStyleIndex::Handheld: | 71 | case Core::HID::NpadStyleIndex::Handheld: |
| 72 | case Core::HID::NpadStyleIndex::GameCube: | 72 | case Core::HID::NpadStyleIndex::GameCube: |
| @@ -116,7 +116,7 @@ void ControllerNavigation::ControllerUpdateStick() { | |||
| 116 | } | 116 | } |
| 117 | 117 | ||
| 118 | switch (controller_type) { | 118 | switch (controller_type) { |
| 119 | case Core::HID::NpadStyleIndex::ProController: | 119 | case Core::HID::NpadStyleIndex::Fullkey: |
| 120 | case Core::HID::NpadStyleIndex::JoyconDual: | 120 | case Core::HID::NpadStyleIndex::JoyconDual: |
| 121 | case Core::HID::NpadStyleIndex::Handheld: | 121 | case Core::HID::NpadStyleIndex::Handheld: |
| 122 | case Core::HID::NpadStyleIndex::GameCube: | 122 | case Core::HID::NpadStyleIndex::GameCube: |
diff --git a/src/yuzu_cmd/yuzu.cpp b/src/yuzu_cmd/yuzu.cpp index a81635fa4..c3cacf852 100644 --- a/src/yuzu_cmd/yuzu.cpp +++ b/src/yuzu_cmd/yuzu.cpp | |||
| @@ -401,7 +401,7 @@ int main(int argc, char** argv) { | |||
| 401 | 401 | ||
| 402 | if (use_multiplayer) { | 402 | if (use_multiplayer) { |
| 403 | if (auto member = system.GetRoomNetwork().GetRoomMember().lock()) { | 403 | if (auto member = system.GetRoomNetwork().GetRoomMember().lock()) { |
| 404 | member->BindOnChatMessageRecieved(OnMessageReceived); | 404 | member->BindOnChatMessageReceived(OnMessageReceived); |
| 405 | member->BindOnStatusMessageReceived(OnStatusMessageReceived); | 405 | member->BindOnStatusMessageReceived(OnStatusMessageReceived); |
| 406 | member->BindOnStateChanged(OnStateChanged); | 406 | member->BindOnStateChanged(OnStateChanged); |
| 407 | member->BindOnError(OnNetworkError); | 407 | member->BindOnError(OnNetworkError); |