Compare commits

..

6 Commits

Author SHA1 Message Date
2b4211823b Android 223 2024-02-02 01:00:23 +00:00
e3e6f5d0d3 Merge yuzu-emu#12874 2024-02-02 01:00:23 +00:00
541418894d Merge yuzu-emu#12857 2024-02-02 01:00:23 +00:00
20c7316220 Merge yuzu-emu#12845 2024-02-02 01:00:23 +00:00
b89aec5fb2 Merge yuzu-emu#12761 2024-02-02 01:00:23 +00:00
64c9fbd5f9 Merge yuzu-emu#12749 2024-02-02 01:00:23 +00:00
216 changed files with 3806 additions and 6609 deletions

View File

@ -1,21 +0,0 @@
#!/bin/bash -ex
# SPDX-FileCopyrightText: 2024 yuzu Emulator Project
# SPDX-License-Identifier: GPL-3.0-or-later
export NDK_CCACHE="$(which ccache)"
ccache -s
export ANDROID_KEYSTORE_FILE="${GITHUB_WORKSPACE}/ks.jks"
base64 --decode <<< "${EA_PLAY_ANDROID_KEYSTORE_B64}" > "${ANDROID_KEYSTORE_FILE}"
export ANDROID_KEY_ALIAS="${PLAY_ANDROID_KEY_ALIAS}"
export ANDROID_KEYSTORE_PASS="${PLAY_ANDROID_KEYSTORE_PASS}"
export SERVICE_ACCOUNT_KEY_PATH="${GITHUB_WORKSPACE}/sa.json"
base64 --decode <<< "${EA_SERVICE_ACCOUNT_KEY_B64}" > "${SERVICE_ACCOUNT_KEY_PATH}"
./gradlew "publishEaReleaseBundle"
ccache -s
if [ ! -z "${ANDROID_KEYSTORE_B64}" ]; then
rm "${ANDROID_KEYSTORE_FILE}"
fi

View File

@ -1,21 +0,0 @@
#!/bin/bash -ex
# SPDX-FileCopyrightText: 2024 yuzu Emulator Project
# SPDX-License-Identifier: GPL-3.0-or-later
export NDK_CCACHE="$(which ccache)"
ccache -s
export ANDROID_KEYSTORE_FILE="${GITHUB_WORKSPACE}/ks.jks"
base64 --decode <<< "${MAINLINE_PLAY_ANDROID_KEYSTORE_B64}" > "${ANDROID_KEYSTORE_FILE}"
export ANDROID_KEY_ALIAS="${PLAY_ANDROID_KEY_ALIAS}"
export ANDROID_KEYSTORE_PASS="${PLAY_ANDROID_KEYSTORE_PASS}"
export SERVICE_ACCOUNT_KEY_PATH="${GITHUB_WORKSPACE}/sa.json"
base64 --decode <<< "${MAINLINE_SERVICE_ACCOUNT_KEY_B64}" > "${SERVICE_ACCOUNT_KEY_PATH}"
./gradlew "publishMainlineReleaseBundle"
ccache -s
if [ ! -z "${ANDROID_KEYSTORE_B64}" ]; then
rm "${ANDROID_KEYSTORE_FILE}"
fi

View File

@ -1,66 +0,0 @@
# SPDX-FileCopyrightText: 2024 yuzu Emulator Project
# SPDX-License-Identifier: GPL-2.0-or-later
name: yuzu-android-ea-play-release
on:
workflow_dispatch:
inputs:
release-track:
description: 'Play store release track (internal/alpha/beta/production)'
required: true
default: 'alpha'
jobs:
android:
runs-on: ubuntu-latest
if: ${{ github.repository == 'yuzu-emu/yuzu' }}
steps:
- uses: actions/checkout@v3
name: Checkout
with:
fetch-depth: 0
submodules: true
token: ${{ secrets.ALT_GITHUB_TOKEN }}
- run: npm install execa@5
- uses: actions/github-script@v5
name: 'Merge and publish Android EA changes'
env:
ALT_GITHUB_TOKEN: ${{ secrets.ALT_GITHUB_TOKEN }}
BUILD_EA: true
with:
script: |
const execa = require("execa");
const mergebot = require('./.github/workflows/android-merge.js').mergebot;
process.chdir('${{ github.workspace }}');
mergebot(github, context, execa);
- name: Get tag name
run: echo "GIT_TAG_NAME=$(cat tag-name.txt)" >> $GITHUB_ENV
- name: Set up JDK 17
uses: actions/setup-java@v3
with:
java-version: '17'
distribution: 'temurin'
- name: Install dependencies
run: |
sudo apt-get update
sudo apt-get install -y ccache apksigner glslang-dev glslang-tools
- name: Build
run: ./.ci/scripts/android/eabuild.sh
env:
EA_PLAY_ANDROID_KEYSTORE_B64: ${{ secrets.PLAY_ANDROID_KEYSTORE_B64 }}
PLAY_ANDROID_KEY_ALIAS: ${{ secrets.PLAY_ANDROID_KEY_ALIAS }}
PLAY_ANDROID_KEYSTORE_PASS: ${{ secrets.PLAY_ANDROID_KEYSTORE_PASS }}
EA_SERVICE_ACCOUNT_KEY_B64: ${{ secrets.EA_SERVICE_ACCOUNT_KEY_B64 }}
STORE_TRACK: ${{ github.event.inputs.release-track }}
AUTO_VERSIONED: true
BUILD_EA: true
- name: Create release
uses: softprops/action-gh-release@v1
with:
tag_name: ${{ env.EA_TAG_NAME }}
name: ${{ env.EA_TAG_NAME }}
draft: false
prerelease: false
repository: yuzu/yuzu-android
token: ${{ secrets.ALT_GITHUB_TOKEN }}

View File

@ -1,59 +0,0 @@
# SPDX-FileCopyrightText: 2024 yuzu Emulator Project
# SPDX-License-Identifier: GPL-2.0-or-later
name: yuzu-android-mainline-play-release
on:
workflow_dispatch:
inputs:
release-tag:
description: 'Tag # from yuzu-android that you want to build and publish'
required: true
default: '200'
release-track:
description: 'Play store release track (internal/alpha/beta/production)'
required: true
default: 'alpha'
jobs:
android:
runs-on: ubuntu-latest
if: ${{ github.repository == 'yuzu-emu/yuzu' }}
steps:
- uses: actions/checkout@v3
name: Checkout
with:
fetch-depth: 0
submodules: true
token: ${{ secrets.ALT_GITHUB_TOKEN }}
- run: npm install execa@5
- uses: actions/github-script@v5
name: 'Pull mainline tag'
env:
MAINLINE_TAG: ${{ github.event.inputs.release-tag }}
with:
script: |
const execa = require("execa");
const mergebot = require('./.github/workflows/android-merge.js').getMainlineTag;
process.chdir('${{ github.workspace }}');
mergebot(execa);
- name: Set up JDK 17
uses: actions/setup-java@v3
with:
java-version: '17'
distribution: 'temurin'
- name: Install dependencies
run: |
sudo apt-get update
sudo apt-get install -y ccache apksigner glslang-dev glslang-tools
- name: Build
run: |
echo "GIT_TAG_NAME=android-${{ github.event.inputs.releast-tag }}" >> $GITHUB_ENV
./.ci/scripts/android/mainlinebuild.sh
env:
MAINLINE_PLAY_ANDROID_KEYSTORE_B64: ${{ secrets.PLAY_ANDROID_KEYSTORE_B64 }}
PLAY_ANDROID_KEY_ALIAS: ${{ secrets.PLAY_ANDROID_KEY_ALIAS }}
PLAY_ANDROID_KEYSTORE_PASS: ${{ secrets.PLAY_ANDROID_KEYSTORE_PASS }}
SERVICE_ACCOUNT_KEY_B64: ${{ secrets.MAINLINE_SERVICE_ACCOUNT_KEY_B64 }}
STORE_TRACK: ${{ github.event.inputs.release-track }}
AUTO_VERSIONED: true

View File

@ -6,12 +6,9 @@
const fs = require("fs"); const fs = require("fs");
// which label to check for changes // which label to check for changes
const CHANGE_LABEL_MAINLINE = 'android-merge'; const CHANGE_LABEL = 'android-merge';
const CHANGE_LABEL_EA = 'android-ea-merge';
// how far back in time should we consider the changes are "recent"? (default: 24 hours) // how far back in time should we consider the changes are "recent"? (default: 24 hours)
const DETECTION_TIME_FRAME = (parseInt(process.env.DETECTION_TIME_FRAME)) || (24 * 3600 * 1000); const DETECTION_TIME_FRAME = (parseInt(process.env.DETECTION_TIME_FRAME)) || (24 * 3600 * 1000);
const BUILD_EA = process.env.BUILD_EA == 'true';
const MAINLINE_TAG = process.env.MAINLINE_TAG;
async function checkBaseChanges(github) { async function checkBaseChanges(github) {
// query the commit date of the latest commit on this branch // query the commit date of the latest commit on this branch
@ -43,7 +40,20 @@ async function checkBaseChanges(github) {
async function checkAndroidChanges(github) { async function checkAndroidChanges(github) {
if (checkBaseChanges(github)) return true; if (checkBaseChanges(github)) return true;
const pulls = getPulls(github, false); const query = `query($owner:String!, $name:String!, $label:String!) {
repository(name:$name, owner:$owner) {
pullRequests(labels: [$label], states: OPEN, first: 100) {
nodes { number headRepository { pushedAt } }
}
}
}`;
const variables = {
owner: 'yuzu-emu',
name: 'yuzu',
label: CHANGE_LABEL,
};
const result = await github.graphql(query, variables);
const pulls = result.repository.pullRequests.nodes;
for (let i = 0; i < pulls.length; i++) { for (let i = 0; i < pulls.length; i++) {
let pull = pulls[i]; let pull = pulls[i];
if (new Date() - new Date(pull.headRepository.pushedAt) <= DETECTION_TIME_FRAME) { if (new Date() - new Date(pull.headRepository.pushedAt) <= DETECTION_TIME_FRAME) {
@ -73,13 +83,7 @@ async function tagAndPush(github, owner, repo, execa, commit=false) {
}; };
const tags = await github.graphql(query, variables); const tags = await github.graphql(query, variables);
const tagList = tags.repository.refs.nodes; const tagList = tags.repository.refs.nodes;
let lastTag = 'android-1'; const lastTag = tagList[0] ? tagList[0].name : 'dummy-0';
for (let i = 0; i < tagList.length; ++i) {
if (tagList[i].name.includes('android-')) {
lastTag = tagList[i].name;
break;
}
}
const tagNumber = /\w+-(\d+)/.exec(lastTag)[1] | 0; const tagNumber = /\w+-(\d+)/.exec(lastTag)[1] | 0;
const channel = repo.split('-')[1]; const channel = repo.split('-')[1];
const newTag = `${channel}-${tagNumber + 1}`; const newTag = `${channel}-${tagNumber + 1}`;
@ -97,48 +101,6 @@ async function tagAndPush(github, owner, repo, execa, commit=false) {
console.info('Successfully pushed new changes.'); console.info('Successfully pushed new changes.');
} }
async function tagAndPushEA(github, owner, repo, execa) {
let altToken = process.env.ALT_GITHUB_TOKEN;
if (!altToken) {
throw `Please set ALT_GITHUB_TOKEN environment variable. This token should have write access to ${owner}/${repo}.`;
}
const query = `query ($owner:String!, $name:String!) {
repository(name:$name, owner:$owner) {
refs(refPrefix: "refs/tags/", orderBy: {field: TAG_COMMIT_DATE, direction: DESC}, first: 10) {
nodes { name }
}
}
}`;
const variables = {
owner: owner,
name: repo,
};
const tags = await github.graphql(query, variables);
const tagList = tags.repository.refs.nodes;
let lastTag = 'ea-1';
for (let i = 0; i < tagList.length; ++i) {
if (tagList[i].name.includes('ea-')) {
lastTag = tagList[i].name;
break;
}
}
const tagNumber = /\w+-(\d+)/.exec(lastTag)[1] | 0;
const newTag = `ea-${tagNumber + 1}`;
console.log(`New tag: ${newTag}`);
console.info('Pushing tags to GitHub ...');
await execa("git", ["remote", "add", "android", "https://github.com/yuzu-emu/yuzu-android.git"]);
await execa("git", ["fetch", "android"]);
await execa("git", ['tag', newTag]);
await execa("git", ['push', 'android', `${newTag}`]);
fs.writeFile('tag-name.txt', newTag, (err) => {
if (err) throw 'Could not write tag name to file!'
})
console.info('Successfully pushed new changes.');
}
async function generateReadme(pulls, context, mergeResults, execa) { async function generateReadme(pulls, context, mergeResults, execa) {
let baseUrl = `https://github.com/${context.repo.owner}/${context.repo.repo}/`; let baseUrl = `https://github.com/${context.repo.owner}/${context.repo.repo}/`;
let output = let output =
@ -240,7 +202,10 @@ async function resetBranch(execa) {
} }
} }
async function getPulls(github) { async function mergebot(github, context, execa) {
// Reset our local copy of master to what appears on yuzu-emu/yuzu - master
await resetBranch(execa);
const query = `query ($owner:String!, $name:String!, $label:String!) { const query = `query ($owner:String!, $name:String!, $label:String!) {
repository(name:$name, owner:$owner) { repository(name:$name, owner:$owner) {
pullRequests(labels: [$label], states: OPEN, first: 100) { pullRequests(labels: [$label], states: OPEN, first: 100) {
@ -250,49 +215,13 @@ async function getPulls(github) {
} }
} }
}`; }`;
const mainlineVariables = { const variables = {
owner: 'yuzu-emu', owner: 'yuzu-emu',
name: 'yuzu', name: 'yuzu',
label: CHANGE_LABEL_MAINLINE, label: CHANGE_LABEL,
}; };
const mainlineResult = await github.graphql(query, mainlineVariables); const result = await github.graphql(query, variables);
const pulls = mainlineResult.repository.pullRequests.nodes; const pulls = result.repository.pullRequests.nodes;
if (BUILD_EA) {
const eaVariables = {
owner: 'yuzu-emu',
name: 'yuzu',
label: CHANGE_LABEL_EA,
};
const eaResult = await github.graphql(query, eaVariables);
const eaPulls = eaResult.repository.pullRequests.nodes;
return pulls.concat(eaPulls);
}
return pulls;
}
async function getMainlineTag(execa) {
console.log(`::group::Getting mainline tag android-${MAINLINE_TAG}`);
let hasFailed = false;
try {
await execa("git", ["remote", "add", "mainline", "https://github.com/yuzu-emu/yuzu-android.git"]);
await execa("git", ["fetch", "mainline", "--tags"]);
await execa("git", ["checkout", `tags/android-${MAINLINE_TAG}`]);
await execa("git", ["submodule", "update", "--init", "--recursive"]);
} catch (err) {
console.log('::error title=Failed pull tag');
hasFailed = true;
}
console.log("::endgroup::");
if (hasFailed) {
throw 'Failed pull mainline tag. Aborting!';
}
}
async function mergebot(github, context, execa) {
// Reset our local copy of master to what appears on yuzu-emu/yuzu - master
await resetBranch(execa);
const pulls = await getPulls(github);
let displayList = []; let displayList = [];
for (let i = 0; i < pulls.length; i++) { for (let i = 0; i < pulls.length; i++) {
let pull = pulls[i]; let pull = pulls[i];
@ -302,17 +231,11 @@ async function mergebot(github, context, execa) {
console.table(displayList); console.table(displayList);
await fetchPullRequests(pulls, "https://github.com/yuzu-emu/yuzu", execa); await fetchPullRequests(pulls, "https://github.com/yuzu-emu/yuzu", execa);
const mergeResults = await mergePullRequests(pulls, execa); const mergeResults = await mergePullRequests(pulls, execa);
await generateReadme(pulls, context, mergeResults, execa);
if (BUILD_EA) { await tagAndPush(github, 'yuzu-emu', `yuzu-android`, execa, true);
await tagAndPushEA(github, 'yuzu-emu', `yuzu-android`, execa);
} else {
await generateReadme(pulls, context, mergeResults, execa);
await tagAndPush(github, 'yuzu-emu', `yuzu-android`, execa, true);
}
} }
module.exports.mergebot = mergebot; module.exports.mergebot = mergebot;
module.exports.checkAndroidChanges = checkAndroidChanges; module.exports.checkAndroidChanges = checkAndroidChanges;
module.exports.tagAndPush = tagAndPush; module.exports.tagAndPush = tagAndPush;
module.exports.checkBaseChanges = checkBaseChanges; module.exports.checkBaseChanges = checkBaseChanges;
module.exports.getMainlineTag = getMainlineTag;

View File

@ -1,4 +1,4 @@
# SPDX-FileCopyrightText: 2024 yuzu Emulator Project # SPDX-FileCopyrightText: 2023 yuzu Emulator Project
# SPDX-License-Identifier: GPL-2.0-or-later # SPDX-License-Identifier: GPL-2.0-or-later
name: yuzu-android-publish name: yuzu-android-publish
@ -16,7 +16,7 @@ on:
jobs: jobs:
android: android:
runs-on: ubuntu-latest runs-on: ubuntu-latest
if: ${{ github.event.inputs.android != 'false' && github.repository == 'yuzu-emu/yuzu' }} if: ${{ github.event.inputs.android != 'false' && github.repository == 'yuzu-emu/yuzu-android' }}
steps: steps:
# this checkout is required to make sure the GitHub Actions scripts are available # this checkout is required to make sure the GitHub Actions scripts are available
- uses: actions/checkout@v3 - uses: actions/checkout@v3

View File

@ -307,7 +307,7 @@ find_package(ZLIB 1.2 REQUIRED)
find_package(zstd 1.5 REQUIRED) find_package(zstd 1.5 REQUIRED)
if (NOT YUZU_USE_EXTERNAL_VULKAN_HEADERS) if (NOT YUZU_USE_EXTERNAL_VULKAN_HEADERS)
find_package(VulkanHeaders 1.3.274 REQUIRED) find_package(Vulkan 1.3.274 REQUIRED)
endif() endif()
if (NOT YUZU_USE_EXTERNAL_VULKAN_UTILITY_LIBRARIES) if (NOT YUZU_USE_EXTERNAL_VULKAN_UTILITY_LIBRARIES)

View File

@ -1,12 +1,10 @@
| Pull Request | Commit | Title | Author | Merged? | | Pull Request | Commit | Title | Author | Merged? |
|----|----|----|----|----| |----|----|----|----|----|
| [12461](https://github.com/yuzu-emu/yuzu//pull/12461) | [`54eb8dcc9`](https://github.com/yuzu-emu/yuzu//pull/12461/files) | Rework Nvdec and VIC to fix out-of-order videos, and speed up decoding. | [Kelebek1](https://github.com/Kelebek1/) | Yes | | [12749](https://github.com/yuzu-emu/yuzu-android//pull/12749) | [`aad4b0d6f`](https://github.com/yuzu-emu/yuzu-android//pull/12749/files) | general: workarounds for SMMU syncing issues | [liamwhite](https://github.com/liamwhite/) | Yes |
| [12749](https://github.com/yuzu-emu/yuzu//pull/12749) | [`aad4b0d6f`](https://github.com/yuzu-emu/yuzu//pull/12749/files) | general: workarounds for SMMU syncing issues | [liamwhite](https://github.com/liamwhite/) | Yes | | [12761](https://github.com/yuzu-emu/yuzu-android//pull/12761) | [`2c421a704`](https://github.com/yuzu-emu/yuzu-android//pull/12761/files) | video_core: rewrite presentation for layer composition | [liamwhite](https://github.com/liamwhite/) | Yes |
| [12756](https://github.com/yuzu-emu/yuzu//pull/12756) | [`cd3de0848`](https://github.com/yuzu-emu/yuzu//pull/12756/files) | general: applet multiprocess | [liamwhite](https://github.com/liamwhite/) | Yes | | [12845](https://github.com/yuzu-emu/yuzu-android//pull/12845) | [`41149d061`](https://github.com/yuzu-emu/yuzu-android//pull/12845/files) | notif: rewrite for new IPC | [liamwhite](https://github.com/liamwhite/) | Yes |
| [12920](https://github.com/yuzu-emu/yuzu//pull/12920) | [`2600ac65c`](https://github.com/yuzu-emu/yuzu//pull/12920/files) | android: Move JNI setup and helpers to common | [t895](https://github.com/t895/) | Yes | | [12857](https://github.com/yuzu-emu/yuzu-android//pull/12857) | [`35e3c6802`](https://github.com/yuzu-emu/yuzu-android//pull/12857/files) | service: use const references for input raw data | [liamwhite](https://github.com/liamwhite/) | Yes |
| [12951](https://github.com/yuzu-emu/yuzu//pull/12951) | [`fee263c59`](https://github.com/yuzu-emu/yuzu//pull/12951/files) | ipc: additional fixes | [liamwhite](https://github.com/liamwhite/) | Yes | | [12874](https://github.com/yuzu-emu/yuzu-android//pull/12874) | [`f410cf681`](https://github.com/yuzu-emu/yuzu-android//pull/12874/files) | Revert "shader_recompiler: fix Offset operand usage for non-OpImage*Gather" | [liamwhite](https://github.com/liamwhite/) | Yes |
| [12955](https://github.com/yuzu-emu/yuzu//pull/12955) | [`8d2ad3d8f`](https://github.com/yuzu-emu/yuzu//pull/12955/files) | dmnt: cheat: Avoid invalidating cache on 32bit | [german77](https://github.com/german77/) | Yes |
| [12964](https://github.com/yuzu-emu/yuzu//pull/12964) | [`d93459db6`](https://github.com/yuzu-emu/yuzu//pull/12964/files) | android: Remove foreground service | [t895](https://github.com/t895/) | Yes |
End of merge log. You can find the original README.md below the break. End of merge log. You can find the original README.md below the break.

View File

@ -11,4 +11,3 @@ type = QT
file_filter = ../../src/android/app/src/main/res/values-<lang>/strings.xml file_filter = ../../src/android/app/src/main/res/values-<lang>/strings.xml
source_file = ../../src/android/app/src/main/res/values/strings.xml source_file = ../../src/android/app/src/main/res/values/strings.xml
type = ANDROID type = ANDROID
lang_map = ja_JP:ja, ko_KR:ko, pt_BR:pt-rBR, pt_PT:pt-rPT, ru_RU:ru, vi_VN:vi, zh_CN:zh-rCN, zh_TW:zh-rTW

View File

@ -164,7 +164,6 @@ else()
if (MINGW) if (MINGW)
add_definitions(-DMINGW_HAS_SECURE_API) add_definitions(-DMINGW_HAS_SECURE_API)
add_compile_options("-msse4.1")
if (MINGW_STATIC_BUILD) if (MINGW_STATIC_BUILD)
add_definitions(-DQT_STATICPLUGIN) add_definitions(-DQT_STATICPLUGIN)

View File

@ -3,8 +3,8 @@
import android.annotation.SuppressLint import android.annotation.SuppressLint
import kotlin.collections.setOf import kotlin.collections.setOf
import org.jetbrains.kotlin.konan.properties.Properties
import org.jlleitschuh.gradle.ktlint.reporter.ReporterType import org.jlleitschuh.gradle.ktlint.reporter.ReporterType
import com.github.triplet.gradle.androidpublisher.ReleaseStatus
plugins { plugins {
id("com.android.application") id("com.android.application")
@ -13,7 +13,6 @@ plugins {
kotlin("plugin.serialization") version "1.9.20" kotlin("plugin.serialization") version "1.9.20"
id("androidx.navigation.safeargs.kotlin") id("androidx.navigation.safeargs.kotlin")
id("org.jlleitschuh.gradle.ktlint") version "11.4.0" id("org.jlleitschuh.gradle.ktlint") version "11.4.0"
id("com.github.triplet.play") version "3.8.6"
} }
/** /**
@ -59,7 +58,15 @@ android {
targetSdk = 34 targetSdk = 34
versionName = getGitVersion() versionName = getGitVersion()
versionCode = if (System.getenv("AUTO_VERSIONED") == "true") { // If you want to use autoVersion for the versionCode, create a property in local.properties
// named "autoVersioned" and set it to "true"
val properties = Properties()
val versionProperty = try {
properties.load(project.rootProject.file("local.properties").inputStream())
properties.getProperty("autoVersioned") ?: ""
} catch (e: Exception) { "" }
versionCode = if (versionProperty == "true") {
autoVersion autoVersion
} else { } else {
1 1
@ -214,15 +221,6 @@ ktlint {
} }
} }
play {
val keyPath = System.getenv("SERVICE_ACCOUNT_KEY_PATH")
if (keyPath != null) {
serviceAccountCredentials.set(File(keyPath))
}
track.set(System.getenv("STORE_TRACK") ?: "internal")
releaseStatus.set(ReleaseStatus.COMPLETED)
}
dependencies { dependencies {
implementation("androidx.core:core-ktx:1.12.0") implementation("androidx.core:core-ktx:1.12.0")
implementation("androidx.appcompat:appcompat:1.6.1") implementation("androidx.appcompat:appcompat:1.6.1")
@ -259,18 +257,12 @@ fun runGitCommand(command: List<String>): String {
} }
fun getGitVersion(): String { fun getGitVersion(): String {
val gitVersion = runGitCommand(
listOf(
"git",
"describe",
"--always",
"--long"
)
).replace(Regex("(-0)?-[^-]+$"), "")
val versionName = if (System.getenv("GITHUB_ACTIONS") != null) { val versionName = if (System.getenv("GITHUB_ACTIONS") != null) {
System.getenv("GIT_TAG_NAME") ?: gitVersion val gitTag = System.getenv("GIT_TAG_NAME") ?: ""
gitTag
} else { } else {
gitVersion runGitCommand(listOf("git", "describe", "--always", "--long"))
.replace(Regex("(-0)?-[^-]+$"), "")
} }
return versionName.ifEmpty { "0.0" } return versionName.ifEmpty { "0.0" }
} }

View File

@ -12,6 +12,8 @@ SPDX-License-Identifier: GPL-3.0-or-later
<uses-feature android:name="android.hardware.vulkan.version" android:version="0x401000" android:required="true" /> <uses-feature android:name="android.hardware.vulkan.version" android:version="0x401000" android:required="true" />
<uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_SPECIAL_USE" />
<uses-permission android:name="android.permission.NFC" /> <uses-permission android:name="android.permission.NFC" />
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" /> <uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
@ -78,6 +80,10 @@ SPDX-License-Identifier: GPL-3.0-or-later
android:resource="@xml/nfc_tech_filter" /> android:resource="@xml/nfc_tech_filter" />
</activity> </activity>
<service android:name="org.yuzu.yuzu_emu.utils.ForegroundService" android:foregroundServiceType="specialUse">
<property android:name="android.app.PROPERTY_SPECIAL_USE_FGS_SUBTYPE" android:value="Keep emulation running in background"/>
</service>
<provider <provider
android:name=".features.DocumentProvider" android:name=".features.DocumentProvider"
android:authorities="${applicationId}.user" android:authorities="${applicationId}.user"

View File

@ -17,6 +17,17 @@ fun Context.getPublicFilesDir(): File = getExternalFilesDir(null) ?: filesDir
class YuzuApplication : Application() { class YuzuApplication : Application() {
private fun createNotificationChannels() { private fun createNotificationChannels() {
val emulationChannel = NotificationChannel(
getString(R.string.emulation_notification_channel_id),
getString(R.string.emulation_notification_channel_name),
NotificationManager.IMPORTANCE_LOW
)
emulationChannel.description = getString(
R.string.emulation_notification_channel_description
)
emulationChannel.setSound(null, null)
emulationChannel.vibrationPattern = null
val noticeChannel = NotificationChannel( val noticeChannel = NotificationChannel(
getString(R.string.notice_notification_channel_id), getString(R.string.notice_notification_channel_id),
getString(R.string.notice_notification_channel_name), getString(R.string.notice_notification_channel_name),
@ -28,6 +39,7 @@ class YuzuApplication : Application() {
// Register the channel with the system; you can't change the importance // Register the channel with the system; you can't change the importance
// or other notification behaviors after this // or other notification behaviors after this
val notificationManager = getSystemService(NotificationManager::class.java) val notificationManager = getSystemService(NotificationManager::class.java)
notificationManager.createNotificationChannel(emulationChannel)
notificationManager.createNotificationChannel(noticeChannel) notificationManager.createNotificationChannel(noticeChannel)
} }

View File

@ -4,6 +4,7 @@
package org.yuzu.yuzu_emu.activities package org.yuzu.yuzu_emu.activities
import android.annotation.SuppressLint import android.annotation.SuppressLint
import android.app.Activity
import android.app.PendingIntent import android.app.PendingIntent
import android.app.PictureInPictureParams import android.app.PictureInPictureParams
import android.app.RemoteAction import android.app.RemoteAction
@ -44,6 +45,7 @@ import org.yuzu.yuzu_emu.features.settings.model.IntSetting
import org.yuzu.yuzu_emu.features.settings.model.Settings import org.yuzu.yuzu_emu.features.settings.model.Settings
import org.yuzu.yuzu_emu.model.EmulationViewModel import org.yuzu.yuzu_emu.model.EmulationViewModel
import org.yuzu.yuzu_emu.model.Game import org.yuzu.yuzu_emu.model.Game
import org.yuzu.yuzu_emu.utils.ForegroundService
import org.yuzu.yuzu_emu.utils.InputHandler import org.yuzu.yuzu_emu.utils.InputHandler
import org.yuzu.yuzu_emu.utils.Log import org.yuzu.yuzu_emu.utils.Log
import org.yuzu.yuzu_emu.utils.MemoryUtil import org.yuzu.yuzu_emu.utils.MemoryUtil
@ -72,6 +74,11 @@ class EmulationActivity : AppCompatActivity(), SensorEventListener {
private val emulationViewModel: EmulationViewModel by viewModels() private val emulationViewModel: EmulationViewModel by viewModels()
override fun onDestroy() {
stopForegroundService(this)
super.onDestroy()
}
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
Log.gameLaunched = true Log.gameLaunched = true
ThemeHelper.setTheme(this) ThemeHelper.setTheme(this)
@ -118,6 +125,10 @@ class EmulationActivity : AppCompatActivity(), SensorEventListener {
.apply() .apply()
} }
} }
// Start a foreground service to prevent the app from getting killed in the background
val startIntent = Intent(this, ForegroundService::class.java)
startForegroundService(startIntent)
} }
override fun onKeyDown(keyCode: Int, event: KeyEvent): Boolean { override fun onKeyDown(keyCode: Int, event: KeyEvent): Boolean {
@ -470,6 +481,12 @@ class EmulationActivity : AppCompatActivity(), SensorEventListener {
activity.startActivity(launcher) activity.startActivity(launcher)
} }
fun stopForegroundService(activity: Activity) {
val startIntent = Intent(activity, ForegroundService::class.java)
startIntent.action = ForegroundService.ACTION_STOP
activity.startForegroundService(startIntent)
}
private fun areCoordinatesOutside(view: View?, x: Float, y: Float): Boolean { private fun areCoordinatesOutside(view: View?, x: Float, y: Float): Boolean {
if (view == null) { if (view == null) {
return true return true

View File

@ -34,6 +34,7 @@ import kotlinx.coroutines.launch
import org.yuzu.yuzu_emu.HomeNavigationDirections import org.yuzu.yuzu_emu.HomeNavigationDirections
import org.yuzu.yuzu_emu.NativeLibrary import org.yuzu.yuzu_emu.NativeLibrary
import org.yuzu.yuzu_emu.R import org.yuzu.yuzu_emu.R
import org.yuzu.yuzu_emu.activities.EmulationActivity
import org.yuzu.yuzu_emu.databinding.ActivityMainBinding import org.yuzu.yuzu_emu.databinding.ActivityMainBinding
import org.yuzu.yuzu_emu.features.settings.model.Settings import org.yuzu.yuzu_emu.features.settings.model.Settings
import org.yuzu.yuzu_emu.fragments.AddGameFolderDialogFragment import org.yuzu.yuzu_emu.fragments.AddGameFolderDialogFragment
@ -176,6 +177,9 @@ class MainActivity : AppCompatActivity(), ThemeProvider {
} }
} }
// Dismiss previous notifications (should not happen unless a crash occurred)
EmulationActivity.stopForegroundService(this)
setInsets() setInsets()
} }
@ -294,6 +298,11 @@ class MainActivity : AppCompatActivity(), ThemeProvider {
super.onResume() super.onResume()
} }
override fun onDestroy() {
EmulationActivity.stopForegroundService(this)
super.onDestroy()
}
private fun setInsets() = private fun setInsets() =
ViewCompat.setOnApplyWindowInsetsListener( ViewCompat.setOnApplyWindowInsetsListener(
binding.root binding.root

View File

@ -0,0 +1,70 @@
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
package org.yuzu.yuzu_emu.utils
import android.app.PendingIntent
import android.app.Service
import android.content.Intent
import android.os.IBinder
import androidx.core.app.NotificationCompat
import androidx.core.app.NotificationManagerCompat
import org.yuzu.yuzu_emu.R
import org.yuzu.yuzu_emu.activities.EmulationActivity
/**
* A service that shows a permanent notification in the background to avoid the app getting
* cleared from memory by the system.
*/
class ForegroundService : Service() {
companion object {
const val EMULATION_RUNNING_NOTIFICATION = 0x1000
const val ACTION_STOP = "stop"
}
private fun showRunningNotification() {
// Intent is used to resume emulation if the notification is clicked
val contentIntent = PendingIntent.getActivity(
this,
0,
Intent(this, EmulationActivity::class.java),
PendingIntent.FLAG_IMMUTABLE
)
val builder =
NotificationCompat.Builder(this, getString(R.string.emulation_notification_channel_id))
.setSmallIcon(R.drawable.ic_stat_notification_logo)
.setContentTitle(getString(R.string.app_name))
.setContentText(getString(R.string.emulation_notification_running))
.setPriority(NotificationCompat.PRIORITY_LOW)
.setOngoing(true)
.setVibrate(null)
.setSound(null)
.setContentIntent(contentIntent)
startForeground(EMULATION_RUNNING_NOTIFICATION, builder.build())
}
override fun onBind(intent: Intent): IBinder? {
return null
}
override fun onCreate() {
showRunningNotification()
}
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
if (intent == null) {
return START_NOT_STICKY
}
if (intent.action == ACTION_STOP) {
NotificationManagerCompat.from(this).cancel(EMULATION_RUNNING_NOTIFICATION)
stopForeground(STOP_FOREGROUND_REMOVE)
stopSelfResult(startId)
}
return START_STICKY
}
override fun onDestroy() {
NotificationManagerCompat.from(this).cancel(EMULATION_RUNNING_NOTIFICATION)
}
}

View File

@ -2,8 +2,14 @@
# SPDX-License-Identifier: GPL-3.0-or-later # SPDX-License-Identifier: GPL-3.0-or-later
add_library(yuzu-android SHARED add_library(yuzu-android SHARED
android_common/android_common.cpp
android_common/android_common.h
applets/software_keyboard.cpp
applets/software_keyboard.h
emu_window/emu_window.cpp emu_window/emu_window.cpp
emu_window/emu_window.h emu_window/emu_window.h
id_cache.cpp
id_cache.h
native.cpp native.cpp
native.h native.h
native_config.cpp native_config.cpp

View File

@ -1,17 +1,15 @@
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#include "android_common.h" #include "jni/android_common/android_common.h"
#include <string> #include <string>
#include <string_view> #include <string_view>
#include <jni.h> #include <jni.h>
#include "common/android/id_cache.h"
#include "common/string_util.h" #include "common/string_util.h"
#include "jni/id_cache.h"
namespace Common::Android {
std::string GetJString(JNIEnv* env, jstring jstr) { std::string GetJString(JNIEnv* env, jstring jstr) {
if (!jstr) { if (!jstr) {
@ -20,8 +18,7 @@ std::string GetJString(JNIEnv* env, jstring jstr) {
const jchar* jchars = env->GetStringChars(jstr, nullptr); const jchar* jchars = env->GetStringChars(jstr, nullptr);
const jsize length = env->GetStringLength(jstr); const jsize length = env->GetStringLength(jstr);
const std::u16string_view string_view(reinterpret_cast<const char16_t*>(jchars), const std::u16string_view string_view(reinterpret_cast<const char16_t*>(jchars), length);
static_cast<u32>(length));
const std::string converted_string = Common::UTF16ToUTF8(string_view); const std::string converted_string = Common::UTF16ToUTF8(string_view);
env->ReleaseStringChars(jstr, jchars); env->ReleaseStringChars(jstr, jchars);
@ -39,27 +36,25 @@ jstring ToJString(JNIEnv* env, std::u16string_view str) {
} }
double GetJDouble(JNIEnv* env, jobject jdouble) { double GetJDouble(JNIEnv* env, jobject jdouble) {
return env->GetDoubleField(jdouble, GetDoubleValueField()); return env->GetDoubleField(jdouble, IDCache::GetDoubleValueField());
} }
jobject ToJDouble(JNIEnv* env, double value) { jobject ToJDouble(JNIEnv* env, double value) {
return env->NewObject(GetDoubleClass(), GetDoubleConstructor(), value); return env->NewObject(IDCache::GetDoubleClass(), IDCache::GetDoubleConstructor(), value);
} }
s32 GetJInteger(JNIEnv* env, jobject jinteger) { s32 GetJInteger(JNIEnv* env, jobject jinteger) {
return env->GetIntField(jinteger, GetIntegerValueField()); return env->GetIntField(jinteger, IDCache::GetIntegerValueField());
} }
jobject ToJInteger(JNIEnv* env, s32 value) { jobject ToJInteger(JNIEnv* env, s32 value) {
return env->NewObject(GetIntegerClass(), GetIntegerConstructor(), value); return env->NewObject(IDCache::GetIntegerClass(), IDCache::GetIntegerConstructor(), value);
} }
bool GetJBoolean(JNIEnv* env, jobject jboolean) { bool GetJBoolean(JNIEnv* env, jobject jboolean) {
return env->GetBooleanField(jboolean, GetBooleanValueField()); return env->GetBooleanField(jboolean, IDCache::GetBooleanValueField());
} }
jobject ToJBoolean(JNIEnv* env, bool value) { jobject ToJBoolean(JNIEnv* env, bool value) {
return env->NewObject(GetBooleanClass(), GetBooleanConstructor(), value); return env->NewObject(IDCache::GetBooleanClass(), IDCache::GetBooleanConstructor(), value);
} }
} // namespace Common::Android

View File

@ -8,8 +8,6 @@
#include <jni.h> #include <jni.h>
#include "common/common_types.h" #include "common/common_types.h"
namespace Common::Android {
std::string GetJString(JNIEnv* env, jstring jstr); std::string GetJString(JNIEnv* env, jstring jstr);
jstring ToJString(JNIEnv* env, std::string_view str); jstring ToJString(JNIEnv* env, std::string_view str);
jstring ToJString(JNIEnv* env, std::u16string_view str); jstring ToJString(JNIEnv* env, std::u16string_view str);
@ -22,5 +20,3 @@ jobject ToJInteger(JNIEnv* env, s32 value);
bool GetJBoolean(JNIEnv* env, jobject jboolean); bool GetJBoolean(JNIEnv* env, jobject jboolean);
jobject ToJBoolean(JNIEnv* env, bool value); jobject ToJBoolean(JNIEnv* env, bool value);
} // namespace Common::Android

View File

@ -6,12 +6,12 @@
#include <jni.h> #include <jni.h>
#include "common/android/android_common.h"
#include "common/android/applets/software_keyboard.h"
#include "common/android/id_cache.h"
#include "common/logging/log.h" #include "common/logging/log.h"
#include "common/string_util.h" #include "common/string_util.h"
#include "core/core.h" #include "core/core.h"
#include "jni/android_common/android_common.h"
#include "jni/applets/software_keyboard.h"
#include "jni/id_cache.h"
static jclass s_software_keyboard_class; static jclass s_software_keyboard_class;
static jclass s_keyboard_config_class; static jclass s_keyboard_config_class;
@ -19,10 +19,10 @@ static jclass s_keyboard_data_class;
static jmethodID s_swkbd_execute_normal; static jmethodID s_swkbd_execute_normal;
static jmethodID s_swkbd_execute_inline; static jmethodID s_swkbd_execute_inline;
namespace Common::Android::SoftwareKeyboard { namespace SoftwareKeyboard {
static jobject ToJKeyboardParams(const Core::Frontend::KeyboardInitializeParameters& config) { static jobject ToJKeyboardParams(const Core::Frontend::KeyboardInitializeParameters& config) {
JNIEnv* env = GetEnvForThread(); JNIEnv* env = IDCache::GetEnvForThread();
jobject object = env->AllocObject(s_keyboard_config_class); jobject object = env->AllocObject(s_keyboard_config_class);
env->SetObjectField(object, env->SetObjectField(object,
@ -78,7 +78,7 @@ static jobject ToJKeyboardParams(const Core::Frontend::KeyboardInitializeParamet
} }
AndroidKeyboard::ResultData AndroidKeyboard::ResultData::CreateFromFrontend(jobject object) { AndroidKeyboard::ResultData AndroidKeyboard::ResultData::CreateFromFrontend(jobject object) {
JNIEnv* env = GetEnvForThread(); JNIEnv* env = IDCache::GetEnvForThread();
const jstring string = reinterpret_cast<jstring>(env->GetObjectField( const jstring string = reinterpret_cast<jstring>(env->GetObjectField(
object, env->GetFieldID(s_keyboard_data_class, "text", "Ljava/lang/String;"))); object, env->GetFieldID(s_keyboard_data_class, "text", "Ljava/lang/String;")));
return ResultData{GetJString(env, string), return ResultData{GetJString(env, string),
@ -141,7 +141,7 @@ void AndroidKeyboard::ShowNormalKeyboard() const {
// Pivot to a new thread, as we cannot call GetEnvForThread() from a Fiber. // Pivot to a new thread, as we cannot call GetEnvForThread() from a Fiber.
std::thread([&] { std::thread([&] {
data = ResultData::CreateFromFrontend(GetEnvForThread()->CallStaticObjectMethod( data = ResultData::CreateFromFrontend(IDCache::GetEnvForThread()->CallStaticObjectMethod(
s_software_keyboard_class, s_swkbd_execute_normal, ToJKeyboardParams(parameters))); s_software_keyboard_class, s_swkbd_execute_normal, ToJKeyboardParams(parameters)));
}).join(); }).join();
@ -183,8 +183,8 @@ void AndroidKeyboard::ShowInlineKeyboard(
// Pivot to a new thread, as we cannot call GetEnvForThread() from a Fiber. // Pivot to a new thread, as we cannot call GetEnvForThread() from a Fiber.
m_is_inline_active = true; m_is_inline_active = true;
std::thread([&] { std::thread([&] {
GetEnvForThread()->CallStaticVoidMethod(s_software_keyboard_class, s_swkbd_execute_inline, IDCache::GetEnvForThread()->CallStaticVoidMethod(
ToJKeyboardParams(parameters)); s_software_keyboard_class, s_swkbd_execute_inline, ToJKeyboardParams(parameters));
}).join(); }).join();
} }
@ -220,7 +220,7 @@ void AndroidKeyboard::SubmitInlineKeyboardText(std::u16string submitted_text) {
m_current_text += submitted_text; m_current_text += submitted_text;
submit_inline_callback(Service::AM::Frontend::SwkbdReplyType::ChangedString, m_current_text, submit_inline_callback(Service::AM::Frontend::SwkbdReplyType::ChangedString, m_current_text,
static_cast<int>(m_current_text.size())); m_current_text.size());
} }
void AndroidKeyboard::SubmitInlineKeyboardInput(int key_code) { void AndroidKeyboard::SubmitInlineKeyboardInput(int key_code) {
@ -242,7 +242,7 @@ void AndroidKeyboard::SubmitInlineKeyboardInput(int key_code) {
case KEYCODE_DEL: case KEYCODE_DEL:
m_current_text.pop_back(); m_current_text.pop_back();
submit_inline_callback(Service::AM::Frontend::SwkbdReplyType::ChangedString, m_current_text, submit_inline_callback(Service::AM::Frontend::SwkbdReplyType::ChangedString, m_current_text,
static_cast<int>(m_current_text.size())); m_current_text.size());
break; break;
} }
} }
@ -274,4 +274,4 @@ void CleanupJNI(JNIEnv* env) {
env->DeleteGlobalRef(s_keyboard_data_class); env->DeleteGlobalRef(s_keyboard_data_class);
} }
} // namespace Common::Android::SoftwareKeyboard } // namespace SoftwareKeyboard

View File

@ -7,7 +7,7 @@
#include "core/frontend/applets/software_keyboard.h" #include "core/frontend/applets/software_keyboard.h"
namespace Common::Android::SoftwareKeyboard { namespace SoftwareKeyboard {
class AndroidKeyboard final : public Core::Frontend::SoftwareKeyboardApplet { class AndroidKeyboard final : public Core::Frontend::SoftwareKeyboardApplet {
public: public:
@ -66,7 +66,7 @@ void InitJNI(JNIEnv* env);
// Should be called in JNI_Unload // Should be called in JNI_Unload
void CleanupJNI(JNIEnv* env); void CleanupJNI(JNIEnv* env);
} // namespace Common::Android::SoftwareKeyboard } // namespace SoftwareKeyboard
// Native function calls // Native function calls
extern "C" { extern "C" {

View File

@ -3,7 +3,6 @@
#include <android/native_window_jni.h> #include <android/native_window_jni.h>
#include "common/android/id_cache.h"
#include "common/logging/log.h" #include "common/logging/log.h"
#include "input_common/drivers/touch_screen.h" #include "input_common/drivers/touch_screen.h"
#include "input_common/drivers/virtual_amiibo.h" #include "input_common/drivers/virtual_amiibo.h"
@ -61,8 +60,7 @@ void EmuWindow_Android::OnRemoveNfcTag() {
void EmuWindow_Android::OnFrameDisplayed() { void EmuWindow_Android::OnFrameDisplayed() {
if (!m_first_frame) { if (!m_first_frame) {
Common::Android::RunJNIOnFiber<void>( EmulationSession::GetInstance().OnEmulationStarted();
[&](JNIEnv* env) { EmulationSession::GetInstance().OnEmulationStarted(); });
m_first_frame = true; m_first_frame = true;
} }
} }

View File

@ -1,12 +1,13 @@
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#include "common/android/android_common.h"
#include "core/core.h" #include "core/core.h"
#include "core/file_sys/fs_filesystem.h" #include "core/file_sys/fs_filesystem.h"
#include "core/file_sys/patch_manager.h" #include "core/file_sys/patch_manager.h"
#include "core/loader/loader.h" #include "core/loader/loader.h"
#include "core/loader/nro.h" #include "core/loader/nro.h"
#include "jni.h"
#include "jni/android_common/android_common.h"
#include "native.h" #include "native.h"
struct RomMetadata { struct RomMetadata {
@ -78,7 +79,7 @@ extern "C" {
jboolean Java_org_yuzu_yuzu_1emu_utils_GameMetadata_getIsValid(JNIEnv* env, jobject obj, jboolean Java_org_yuzu_yuzu_1emu_utils_GameMetadata_getIsValid(JNIEnv* env, jobject obj,
jstring jpath) { jstring jpath) {
const auto file = EmulationSession::GetInstance().System().GetFilesystem()->OpenFile( const auto file = EmulationSession::GetInstance().System().GetFilesystem()->OpenFile(
Common::Android::GetJString(env, jpath), FileSys::OpenMode::Read); GetJString(env, jpath), FileSys::OpenMode::Read);
if (!file) { if (!file) {
return false; return false;
} }
@ -103,31 +104,27 @@ jboolean Java_org_yuzu_yuzu_1emu_utils_GameMetadata_getIsValid(JNIEnv* env, jobj
jstring Java_org_yuzu_yuzu_1emu_utils_GameMetadata_getTitle(JNIEnv* env, jobject obj, jstring Java_org_yuzu_yuzu_1emu_utils_GameMetadata_getTitle(JNIEnv* env, jobject obj,
jstring jpath) { jstring jpath) {
return Common::Android::ToJString( return ToJString(env, GetRomMetadata(GetJString(env, jpath)).title);
env, GetRomMetadata(Common::Android::GetJString(env, jpath)).title);
} }
jstring Java_org_yuzu_yuzu_1emu_utils_GameMetadata_getProgramId(JNIEnv* env, jobject obj, jstring Java_org_yuzu_yuzu_1emu_utils_GameMetadata_getProgramId(JNIEnv* env, jobject obj,
jstring jpath) { jstring jpath) {
return Common::Android::ToJString( return ToJString(env, std::to_string(GetRomMetadata(GetJString(env, jpath)).programId));
env, std::to_string(GetRomMetadata(Common::Android::GetJString(env, jpath)).programId));
} }
jstring Java_org_yuzu_yuzu_1emu_utils_GameMetadata_getDeveloper(JNIEnv* env, jobject obj, jstring Java_org_yuzu_yuzu_1emu_utils_GameMetadata_getDeveloper(JNIEnv* env, jobject obj,
jstring jpath) { jstring jpath) {
return Common::Android::ToJString( return ToJString(env, GetRomMetadata(GetJString(env, jpath)).developer);
env, GetRomMetadata(Common::Android::GetJString(env, jpath)).developer);
} }
jstring Java_org_yuzu_yuzu_1emu_utils_GameMetadata_getVersion(JNIEnv* env, jobject obj, jstring Java_org_yuzu_yuzu_1emu_utils_GameMetadata_getVersion(JNIEnv* env, jobject obj,
jstring jpath, jboolean jreload) { jstring jpath, jboolean jreload) {
return Common::Android::ToJString( return ToJString(env, GetRomMetadata(GetJString(env, jpath), jreload).version);
env, GetRomMetadata(Common::Android::GetJString(env, jpath), jreload).version);
} }
jbyteArray Java_org_yuzu_yuzu_1emu_utils_GameMetadata_getIcon(JNIEnv* env, jobject obj, jbyteArray Java_org_yuzu_yuzu_1emu_utils_GameMetadata_getIcon(JNIEnv* env, jobject obj,
jstring jpath) { jstring jpath) {
auto icon_data = GetRomMetadata(Common::Android::GetJString(env, jpath)).icon; auto icon_data = GetRomMetadata(GetJString(env, jpath)).icon;
jbyteArray icon = env->NewByteArray(static_cast<jsize>(icon_data.size())); jbyteArray icon = env->NewByteArray(static_cast<jsize>(icon_data.size()));
env->SetByteArrayRegion(icon, 0, env->GetArrayLength(icon), env->SetByteArrayRegion(icon, 0, env->GetArrayLength(icon),
reinterpret_cast<jbyte*>(icon_data.data())); reinterpret_cast<jbyte*>(icon_data.data()));
@ -136,8 +133,7 @@ jbyteArray Java_org_yuzu_yuzu_1emu_utils_GameMetadata_getIcon(JNIEnv* env, jobje
jboolean Java_org_yuzu_yuzu_1emu_utils_GameMetadata_getIsHomebrew(JNIEnv* env, jobject obj, jboolean Java_org_yuzu_yuzu_1emu_utils_GameMetadata_getIsHomebrew(JNIEnv* env, jobject obj,
jstring jpath) { jstring jpath) {
return static_cast<jboolean>( return static_cast<jboolean>(GetRomMetadata(GetJString(env, jpath)).isHomebrew);
GetRomMetadata(Common::Android::GetJString(env, jpath)).isHomebrew);
} }
void Java_org_yuzu_yuzu_1emu_utils_GameMetadata_resetMetadata(JNIEnv* env, jobject obj) { void Java_org_yuzu_yuzu_1emu_utils_GameMetadata_resetMetadata(JNIEnv* env, jobject obj) {

View File

@ -3,10 +3,10 @@
#include <jni.h> #include <jni.h>
#include "applets/software_keyboard.h"
#include "common/android/id_cache.h"
#include "common/assert.h" #include "common/assert.h"
#include "common/fs/fs_android.h" #include "common/fs/fs_android.h"
#include "jni/applets/software_keyboard.h"
#include "jni/id_cache.h"
#include "video_core/rasterizer_interface.h" #include "video_core/rasterizer_interface.h"
static JavaVM* s_java_vm; static JavaVM* s_java_vm;
@ -67,7 +67,7 @@ static jfieldID s_boolean_value_field;
static constexpr jint JNI_VERSION = JNI_VERSION_1_6; static constexpr jint JNI_VERSION = JNI_VERSION_1_6;
namespace Common::Android { namespace IDCache {
JNIEnv* GetEnvForThread() { JNIEnv* GetEnvForThread() {
thread_local static struct OwnedEnv { thread_local static struct OwnedEnv {
@ -276,6 +276,8 @@ jfieldID GetBooleanValueField() {
return s_boolean_value_field; return s_boolean_value_field;
} }
} // namespace IDCache
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
@ -391,7 +393,7 @@ jint JNI_OnLoad(JavaVM* vm, void* reserved) {
Common::FS::Android::RegisterCallbacks(env, s_native_library_class); Common::FS::Android::RegisterCallbacks(env, s_native_library_class);
// Initialize applets // Initialize applets
Common::Android::SoftwareKeyboard::InitJNI(env); SoftwareKeyboard::InitJNI(env);
return JNI_VERSION; return JNI_VERSION;
} }
@ -424,5 +426,3 @@ void JNI_OnUnload(JavaVM* vm, void* reserved) {
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif
} // namespace Common::Android

View File

@ -3,40 +3,20 @@
#pragma once #pragma once
#include <future>
#include <jni.h> #include <jni.h>
#include "video_core/rasterizer_interface.h" #include "video_core/rasterizer_interface.h"
namespace Common::Android { namespace IDCache {
JNIEnv* GetEnvForThread(); JNIEnv* GetEnvForThread();
/**
* Starts a new thread to run JNI. Intended to be used when you must run JNI from a fiber.
* @tparam T Typename of the return value for the work param
* @param work Lambda that runs JNI code. This function will take care of attaching this thread to
* the JVM
* @return The result from the work lambda param
*/
template <typename T = void>
T RunJNIOnFiber(const std::function<T(JNIEnv*)>& work) {
std::future<T> j_result = std::async(std::launch::async, [&] {
auto env = GetEnvForThread();
return work(env);
});
return j_result.get();
}
jclass GetNativeLibraryClass(); jclass GetNativeLibraryClass();
jclass GetDiskCacheProgressClass(); jclass GetDiskCacheProgressClass();
jclass GetDiskCacheLoadCallbackStageClass(); jclass GetDiskCacheLoadCallbackStageClass();
jclass GetGameDirClass(); jclass GetGameDirClass();
jmethodID GetGameDirConstructor(); jmethodID GetGameDirConstructor();
jmethodID GetDiskCacheLoadProgress();
jmethodID GetExitEmulationActivity(); jmethodID GetExitEmulationActivity();
jmethodID GetDiskCacheLoadProgress();
jmethodID GetOnEmulationStarted(); jmethodID GetOnEmulationStarted();
jmethodID GetOnEmulationStopped(); jmethodID GetOnEmulationStopped();
jmethodID GetOnProgramChanged(); jmethodID GetOnProgramChanged();
@ -85,4 +65,4 @@ jclass GetBooleanClass();
jmethodID GetBooleanConstructor(); jmethodID GetBooleanConstructor();
jfieldID GetBooleanValueField(); jfieldID GetBooleanValueField();
} // namespace Common::Android } // namespace IDCache

View File

@ -20,8 +20,6 @@
#include <frontend_common/content_manager.h> #include <frontend_common/content_manager.h>
#include <jni.h> #include <jni.h>
#include "common/android/android_common.h"
#include "common/android/id_cache.h"
#include "common/detached_tasks.h" #include "common/detached_tasks.h"
#include "common/dynamic_library.h" #include "common/dynamic_library.h"
#include "common/fs/path_util.h" #include "common/fs/path_util.h"
@ -59,6 +57,8 @@
#include "hid_core/frontend/emulated_controller.h" #include "hid_core/frontend/emulated_controller.h"
#include "hid_core/hid_core.h" #include "hid_core/hid_core.h"
#include "hid_core/hid_types.h" #include "hid_core/hid_types.h"
#include "jni/android_common/android_common.h"
#include "jni/id_cache.h"
#include "jni/native.h" #include "jni/native.h"
#include "video_core/renderer_base.h" #include "video_core/renderer_base.h"
#include "video_core/renderer_vulkan/renderer_vulkan.h" #include "video_core/renderer_vulkan/renderer_vulkan.h"
@ -228,7 +228,7 @@ Core::SystemResultStatus EmulationSession::InitializeEmulation(const std::string
std::make_unique<EmuWindow_Android>(&m_input_subsystem, m_native_window, m_vulkan_library); std::make_unique<EmuWindow_Android>(&m_input_subsystem, m_native_window, m_vulkan_library);
// Initialize system. // Initialize system.
jauto android_keyboard = std::make_unique<Common::Android::SoftwareKeyboard::AndroidKeyboard>(); jauto android_keyboard = std::make_unique<SoftwareKeyboard::AndroidKeyboard>();
m_software_keyboard = android_keyboard.get(); m_software_keyboard = android_keyboard.get();
m_system.SetShuttingDown(false); m_system.SetShuttingDown(false);
m_system.ApplySettings(); m_system.ApplySettings();
@ -411,39 +411,37 @@ void EmulationSession::OnGamepadDisconnectEvent([[maybe_unused]] int index) {
controller->Disconnect(); controller->Disconnect();
} }
Common::Android::SoftwareKeyboard::AndroidKeyboard* EmulationSession::SoftwareKeyboard() { SoftwareKeyboard::AndroidKeyboard* EmulationSession::SoftwareKeyboard() {
return m_software_keyboard; return m_software_keyboard;
} }
void EmulationSession::LoadDiskCacheProgress(VideoCore::LoadCallbackStage stage, int progress, void EmulationSession::LoadDiskCacheProgress(VideoCore::LoadCallbackStage stage, int progress,
int max) { int max) {
JNIEnv* env = Common::Android::GetEnvForThread(); JNIEnv* env = IDCache::GetEnvForThread();
env->CallStaticVoidMethod(Common::Android::GetDiskCacheProgressClass(), env->CallStaticVoidMethod(IDCache::GetDiskCacheProgressClass(),
Common::Android::GetDiskCacheLoadProgress(), static_cast<jint>(stage), IDCache::GetDiskCacheLoadProgress(), static_cast<jint>(stage),
static_cast<jint>(progress), static_cast<jint>(max)); static_cast<jint>(progress), static_cast<jint>(max));
} }
void EmulationSession::OnEmulationStarted() { void EmulationSession::OnEmulationStarted() {
JNIEnv* env = Common::Android::GetEnvForThread(); JNIEnv* env = IDCache::GetEnvForThread();
env->CallStaticVoidMethod(Common::Android::GetNativeLibraryClass(), env->CallStaticVoidMethod(IDCache::GetNativeLibraryClass(), IDCache::GetOnEmulationStarted());
Common::Android::GetOnEmulationStarted());
} }
void EmulationSession::OnEmulationStopped(Core::SystemResultStatus result) { void EmulationSession::OnEmulationStopped(Core::SystemResultStatus result) {
JNIEnv* env = Common::Android::GetEnvForThread(); JNIEnv* env = IDCache::GetEnvForThread();
env->CallStaticVoidMethod(Common::Android::GetNativeLibraryClass(), env->CallStaticVoidMethod(IDCache::GetNativeLibraryClass(), IDCache::GetOnEmulationStopped(),
Common::Android::GetOnEmulationStopped(), static_cast<jint>(result)); static_cast<jint>(result));
} }
void EmulationSession::ChangeProgram(std::size_t program_index) { void EmulationSession::ChangeProgram(std::size_t program_index) {
JNIEnv* env = Common::Android::GetEnvForThread(); JNIEnv* env = IDCache::GetEnvForThread();
env->CallStaticVoidMethod(Common::Android::GetNativeLibraryClass(), env->CallStaticVoidMethod(IDCache::GetNativeLibraryClass(), IDCache::GetOnProgramChanged(),
Common::Android::GetOnProgramChanged(),
static_cast<jint>(program_index)); static_cast<jint>(program_index));
} }
u64 EmulationSession::GetProgramId(JNIEnv* env, jstring jprogramId) { u64 EmulationSession::GetProgramId(JNIEnv* env, jstring jprogramId) {
auto program_id_string = Common::Android::GetJString(env, jprogramId); auto program_id_string = GetJString(env, jprogramId);
try { try {
return std::stoull(program_id_string); return std::stoull(program_id_string);
} catch (...) { } catch (...) {
@ -493,7 +491,7 @@ void Java_org_yuzu_yuzu_1emu_NativeLibrary_surfaceDestroyed(JNIEnv* env, jobject
void Java_org_yuzu_yuzu_1emu_NativeLibrary_setAppDirectory(JNIEnv* env, jobject instance, void Java_org_yuzu_yuzu_1emu_NativeLibrary_setAppDirectory(JNIEnv* env, jobject instance,
[[maybe_unused]] jstring j_directory) { [[maybe_unused]] jstring j_directory) {
Common::FS::SetAppDirectory(Common::Android::GetJString(env, j_directory)); Common::FS::SetAppDirectory(GetJString(env, j_directory));
} }
int Java_org_yuzu_yuzu_1emu_NativeLibrary_installFileToNand(JNIEnv* env, jobject instance, int Java_org_yuzu_yuzu_1emu_NativeLibrary_installFileToNand(JNIEnv* env, jobject instance,
@ -503,22 +501,21 @@ int Java_org_yuzu_yuzu_1emu_NativeLibrary_installFileToNand(JNIEnv* env, jobject
jlambdaClass, "invoke", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;"); jlambdaClass, "invoke", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");
const auto callback = [env, jcallback, jlambdaInvokeMethod](size_t max, size_t progress) { const auto callback = [env, jcallback, jlambdaInvokeMethod](size_t max, size_t progress) {
auto jwasCancelled = env->CallObjectMethod(jcallback, jlambdaInvokeMethod, auto jwasCancelled = env->CallObjectMethod(jcallback, jlambdaInvokeMethod,
Common::Android::ToJDouble(env, max), ToJDouble(env, max), ToJDouble(env, progress));
Common::Android::ToJDouble(env, progress)); return GetJBoolean(env, jwasCancelled);
return Common::Android::GetJBoolean(env, jwasCancelled);
}; };
return static_cast<int>( return static_cast<int>(
ContentManager::InstallNSP(EmulationSession::GetInstance().System(), ContentManager::InstallNSP(EmulationSession::GetInstance().System(),
*EmulationSession::GetInstance().System().GetFilesystem(), *EmulationSession::GetInstance().System().GetFilesystem(),
Common::Android::GetJString(env, j_file), callback)); GetJString(env, j_file), callback));
} }
jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_doesUpdateMatchProgram(JNIEnv* env, jobject jobj, jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_doesUpdateMatchProgram(JNIEnv* env, jobject jobj,
jstring jprogramId, jstring jprogramId,
jstring jupdatePath) { jstring jupdatePath) {
u64 program_id = EmulationSession::GetProgramId(env, jprogramId); u64 program_id = EmulationSession::GetProgramId(env, jprogramId);
std::string updatePath = Common::Android::GetJString(env, jupdatePath); std::string updatePath = GetJString(env, jupdatePath);
std::shared_ptr<FileSys::NSP> nsp = std::make_shared<FileSys::NSP>( std::shared_ptr<FileSys::NSP> nsp = std::make_shared<FileSys::NSP>(
EmulationSession::GetInstance().System().GetFilesystem()->OpenFile( EmulationSession::GetInstance().System().GetFilesystem()->OpenFile(
updatePath, FileSys::OpenMode::Read)); updatePath, FileSys::OpenMode::Read));
@ -541,10 +538,8 @@ void JNICALL Java_org_yuzu_yuzu_1emu_NativeLibrary_initializeGpuDriver(JNIEnv* e
jstring custom_driver_name, jstring custom_driver_name,
jstring file_redirect_dir) { jstring file_redirect_dir) {
EmulationSession::GetInstance().InitializeGpuDriver( EmulationSession::GetInstance().InitializeGpuDriver(
Common::Android::GetJString(env, hook_lib_dir), GetJString(env, hook_lib_dir), GetJString(env, custom_driver_dir),
Common::Android::GetJString(env, custom_driver_dir), GetJString(env, custom_driver_name), GetJString(env, file_redirect_dir));
Common::Android::GetJString(env, custom_driver_name),
Common::Android::GetJString(env, file_redirect_dir));
} }
[[maybe_unused]] static bool CheckKgslPresent() { [[maybe_unused]] static bool CheckKgslPresent() {
@ -571,7 +566,7 @@ jobjectArray Java_org_yuzu_yuzu_1emu_utils_GpuDriverHelper_getSystemDriverInfo(
JNIEnv* env, jobject j_obj, jobject j_surf, jstring j_hook_lib_dir) { JNIEnv* env, jobject j_obj, jobject j_surf, jstring j_hook_lib_dir) {
const char* file_redirect_dir_{}; const char* file_redirect_dir_{};
int featureFlags{}; int featureFlags{};
std::string hook_lib_dir = Common::Android::GetJString(env, j_hook_lib_dir); std::string hook_lib_dir = GetJString(env, j_hook_lib_dir);
auto handle = adrenotools_open_libvulkan(RTLD_NOW, featureFlags, nullptr, hook_lib_dir.c_str(), auto handle = adrenotools_open_libvulkan(RTLD_NOW, featureFlags, nullptr, hook_lib_dir.c_str(),
nullptr, nullptr, file_redirect_dir_, nullptr); nullptr, nullptr, file_redirect_dir_, nullptr);
auto driver_library = std::make_shared<Common::DynamicLibrary>(handle); auto driver_library = std::make_shared<Common::DynamicLibrary>(handle);
@ -592,10 +587,9 @@ jobjectArray Java_org_yuzu_yuzu_1emu_utils_GpuDriverHelper_getSystemDriverInfo(
fmt::format("{}.{}.{}", VK_API_VERSION_MAJOR(driver_version), fmt::format("{}.{}.{}", VK_API_VERSION_MAJOR(driver_version),
VK_API_VERSION_MINOR(driver_version), VK_API_VERSION_PATCH(driver_version)); VK_API_VERSION_MINOR(driver_version), VK_API_VERSION_PATCH(driver_version));
jobjectArray j_driver_info = env->NewObjectArray( jobjectArray j_driver_info =
2, Common::Android::GetStringClass(), Common::Android::ToJString(env, version_string)); env->NewObjectArray(2, IDCache::GetStringClass(), ToJString(env, version_string));
env->SetObjectArrayElement(j_driver_info, 1, env->SetObjectArrayElement(j_driver_info, 1, ToJString(env, device.GetDriverName()));
Common::Android::ToJString(env, device.GetDriverName()));
return j_driver_info; return j_driver_info;
} }
@ -748,15 +742,15 @@ jdoubleArray Java_org_yuzu_yuzu_1emu_NativeLibrary_getPerfStats(JNIEnv* env, jcl
jstring Java_org_yuzu_yuzu_1emu_NativeLibrary_getCpuBackend(JNIEnv* env, jclass clazz) { jstring Java_org_yuzu_yuzu_1emu_NativeLibrary_getCpuBackend(JNIEnv* env, jclass clazz) {
if (Settings::IsNceEnabled()) { if (Settings::IsNceEnabled()) {
return Common::Android::ToJString(env, "NCE"); return ToJString(env, "NCE");
} }
return Common::Android::ToJString(env, "JIT"); return ToJString(env, "JIT");
} }
jstring Java_org_yuzu_yuzu_1emu_NativeLibrary_getGpuDriver(JNIEnv* env, jobject jobj) { jstring Java_org_yuzu_yuzu_1emu_NativeLibrary_getGpuDriver(JNIEnv* env, jobject jobj) {
return Common::Android::ToJString( return ToJString(env,
env, EmulationSession::GetInstance().System().GPU().Renderer().GetDeviceVendor()); EmulationSession::GetInstance().System().GPU().Renderer().GetDeviceVendor());
} }
void Java_org_yuzu_yuzu_1emu_NativeLibrary_applySettings(JNIEnv* env, jobject jobj) { void Java_org_yuzu_yuzu_1emu_NativeLibrary_applySettings(JNIEnv* env, jobject jobj) {
@ -770,14 +764,13 @@ void Java_org_yuzu_yuzu_1emu_NativeLibrary_logSettings(JNIEnv* env, jobject jobj
void Java_org_yuzu_yuzu_1emu_NativeLibrary_run(JNIEnv* env, jobject jobj, jstring j_path, void Java_org_yuzu_yuzu_1emu_NativeLibrary_run(JNIEnv* env, jobject jobj, jstring j_path,
jint j_program_index, jint j_program_index,
jboolean j_frontend_initiated) { jboolean j_frontend_initiated) {
const std::string path = Common::Android::GetJString(env, j_path); const std::string path = GetJString(env, j_path);
const Core::SystemResultStatus result{ const Core::SystemResultStatus result{
RunEmulation(path, j_program_index, j_frontend_initiated)}; RunEmulation(path, j_program_index, j_frontend_initiated)};
if (result != Core::SystemResultStatus::Success) { if (result != Core::SystemResultStatus::Success) {
env->CallStaticVoidMethod(Common::Android::GetNativeLibraryClass(), env->CallStaticVoidMethod(IDCache::GetNativeLibraryClass(),
Common::Android::GetExitEmulationActivity(), IDCache::GetExitEmulationActivity(), static_cast<int>(result));
static_cast<int>(result));
} }
} }
@ -788,7 +781,7 @@ void Java_org_yuzu_yuzu_1emu_NativeLibrary_logDeviceInfo(JNIEnv* env, jclass cla
void Java_org_yuzu_yuzu_1emu_NativeLibrary_submitInlineKeyboardText(JNIEnv* env, jclass clazz, void Java_org_yuzu_yuzu_1emu_NativeLibrary_submitInlineKeyboardText(JNIEnv* env, jclass clazz,
jstring j_text) { jstring j_text) {
const std::u16string input = Common::UTF8ToUTF16(Common::Android::GetJString(env, j_text)); const std::u16string input = Common::UTF8ToUTF16(GetJString(env, j_text));
EmulationSession::GetInstance().SoftwareKeyboard()->SubmitInlineKeyboardText(input); EmulationSession::GetInstance().SoftwareKeyboard()->SubmitInlineKeyboardText(input);
} }
@ -822,16 +815,16 @@ jstring Java_org_yuzu_yuzu_1emu_NativeLibrary_getAppletLaunchPath(JNIEnv* env, j
auto bis_system = auto bis_system =
EmulationSession::GetInstance().System().GetFileSystemController().GetSystemNANDContents(); EmulationSession::GetInstance().System().GetFileSystemController().GetSystemNANDContents();
if (!bis_system) { if (!bis_system) {
return Common::Android::ToJString(env, ""); return ToJString(env, "");
} }
auto applet_nca = auto applet_nca =
bis_system->GetEntry(static_cast<u64>(jid), FileSys::ContentRecordType::Program); bis_system->GetEntry(static_cast<u64>(jid), FileSys::ContentRecordType::Program);
if (!applet_nca) { if (!applet_nca) {
return Common::Android::ToJString(env, ""); return ToJString(env, "");
} }
return Common::Android::ToJString(env, applet_nca->GetFullPath()); return ToJString(env, applet_nca->GetFullPath());
} }
void Java_org_yuzu_yuzu_1emu_NativeLibrary_setCurrentAppletId(JNIEnv* env, jclass clazz, void Java_org_yuzu_yuzu_1emu_NativeLibrary_setCurrentAppletId(JNIEnv* env, jclass clazz,
@ -864,7 +857,7 @@ jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_isFirmwareAvailable(JNIEnv* env,
jobjectArray Java_org_yuzu_yuzu_1emu_NativeLibrary_getPatchesForFile(JNIEnv* env, jobject jobj, jobjectArray Java_org_yuzu_yuzu_1emu_NativeLibrary_getPatchesForFile(JNIEnv* env, jobject jobj,
jstring jpath, jstring jpath,
jstring jprogramId) { jstring jprogramId) {
const auto path = Common::Android::GetJString(env, jpath); const auto path = GetJString(env, jpath);
const auto vFile = const auto vFile =
Core::GetGameFileFromPath(EmulationSession::GetInstance().System().GetFilesystem(), path); Core::GetGameFileFromPath(EmulationSession::GetInstance().System().GetFilesystem(), path);
if (vFile == nullptr) { if (vFile == nullptr) {
@ -882,15 +875,14 @@ jobjectArray Java_org_yuzu_yuzu_1emu_NativeLibrary_getPatchesForFile(JNIEnv* env
auto patches = pm.GetPatches(update_raw); auto patches = pm.GetPatches(update_raw);
jobjectArray jpatchArray = jobjectArray jpatchArray =
env->NewObjectArray(patches.size(), Common::Android::GetPatchClass(), nullptr); env->NewObjectArray(patches.size(), IDCache::GetPatchClass(), nullptr);
int i = 0; int i = 0;
for (const auto& patch : patches) { for (const auto& patch : patches) {
jobject jpatch = env->NewObject( jobject jpatch = env->NewObject(
Common::Android::GetPatchClass(), Common::Android::GetPatchConstructor(), patch.enabled, IDCache::GetPatchClass(), IDCache::GetPatchConstructor(), patch.enabled,
Common::Android::ToJString(env, patch.name), ToJString(env, patch.name), ToJString(env, patch.version),
Common::Android::ToJString(env, patch.version), static_cast<jint>(patch.type), static_cast<jint>(patch.type), ToJString(env, std::to_string(patch.program_id)),
Common::Android::ToJString(env, std::to_string(patch.program_id)), ToJString(env, std::to_string(patch.title_id)));
Common::Android::ToJString(env, std::to_string(patch.title_id)));
env->SetObjectArrayElement(jpatchArray, i, jpatch); env->SetObjectArrayElement(jpatchArray, i, jpatch);
++i; ++i;
} }
@ -914,7 +906,7 @@ void Java_org_yuzu_yuzu_1emu_NativeLibrary_removeMod(JNIEnv* env, jobject jobj,
jstring jname) { jstring jname) {
auto program_id = EmulationSession::GetProgramId(env, jprogramId); auto program_id = EmulationSession::GetProgramId(env, jprogramId);
ContentManager::RemoveMod(EmulationSession::GetInstance().System().GetFileSystemController(), ContentManager::RemoveMod(EmulationSession::GetInstance().System().GetFileSystemController(),
program_id, Common::Android::GetJString(env, jname)); program_id, GetJString(env, jname));
} }
jobjectArray Java_org_yuzu_yuzu_1emu_NativeLibrary_verifyInstalledContents(JNIEnv* env, jobjectArray Java_org_yuzu_yuzu_1emu_NativeLibrary_verifyInstalledContents(JNIEnv* env,
@ -925,18 +917,17 @@ jobjectArray Java_org_yuzu_yuzu_1emu_NativeLibrary_verifyInstalledContents(JNIEn
jlambdaClass, "invoke", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;"); jlambdaClass, "invoke", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");
const auto callback = [env, jcallback, jlambdaInvokeMethod](size_t max, size_t progress) { const auto callback = [env, jcallback, jlambdaInvokeMethod](size_t max, size_t progress) {
auto jwasCancelled = env->CallObjectMethod(jcallback, jlambdaInvokeMethod, auto jwasCancelled = env->CallObjectMethod(jcallback, jlambdaInvokeMethod,
Common::Android::ToJDouble(env, max), ToJDouble(env, max), ToJDouble(env, progress));
Common::Android::ToJDouble(env, progress)); return GetJBoolean(env, jwasCancelled);
return Common::Android::GetJBoolean(env, jwasCancelled);
}; };
auto& session = EmulationSession::GetInstance(); auto& session = EmulationSession::GetInstance();
std::vector<std::string> result = ContentManager::VerifyInstalledContents( std::vector<std::string> result = ContentManager::VerifyInstalledContents(
session.System(), *session.GetContentProvider(), callback); session.System(), *session.GetContentProvider(), callback);
jobjectArray jresult = env->NewObjectArray(result.size(), Common::Android::GetStringClass(), jobjectArray jresult =
Common::Android::ToJString(env, "")); env->NewObjectArray(result.size(), IDCache::GetStringClass(), ToJString(env, ""));
for (size_t i = 0; i < result.size(); ++i) { for (size_t i = 0; i < result.size(); ++i) {
env->SetObjectArrayElement(jresult, i, Common::Android::ToJString(env, result[i])); env->SetObjectArrayElement(jresult, i, ToJString(env, result[i]));
} }
return jresult; return jresult;
} }
@ -948,20 +939,19 @@ jint Java_org_yuzu_yuzu_1emu_NativeLibrary_verifyGameContents(JNIEnv* env, jobje
jlambdaClass, "invoke", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;"); jlambdaClass, "invoke", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");
const auto callback = [env, jcallback, jlambdaInvokeMethod](size_t max, size_t progress) { const auto callback = [env, jcallback, jlambdaInvokeMethod](size_t max, size_t progress) {
auto jwasCancelled = env->CallObjectMethod(jcallback, jlambdaInvokeMethod, auto jwasCancelled = env->CallObjectMethod(jcallback, jlambdaInvokeMethod,
Common::Android::ToJDouble(env, max), ToJDouble(env, max), ToJDouble(env, progress));
Common::Android::ToJDouble(env, progress)); return GetJBoolean(env, jwasCancelled);
return Common::Android::GetJBoolean(env, jwasCancelled);
}; };
auto& session = EmulationSession::GetInstance(); auto& session = EmulationSession::GetInstance();
return static_cast<jint>(ContentManager::VerifyGameContents( return static_cast<jint>(
session.System(), Common::Android::GetJString(env, jpath), callback)); ContentManager::VerifyGameContents(session.System(), GetJString(env, jpath), callback));
} }
jstring Java_org_yuzu_yuzu_1emu_NativeLibrary_getSavePath(JNIEnv* env, jobject jobj, jstring Java_org_yuzu_yuzu_1emu_NativeLibrary_getSavePath(JNIEnv* env, jobject jobj,
jstring jprogramId) { jstring jprogramId) {
auto program_id = EmulationSession::GetProgramId(env, jprogramId); auto program_id = EmulationSession::GetProgramId(env, jprogramId);
if (program_id == 0) { if (program_id == 0) {
return Common::Android::ToJString(env, ""); return ToJString(env, "");
} }
auto& system = EmulationSession::GetInstance().System(); auto& system = EmulationSession::GetInstance().System();
@ -978,7 +968,7 @@ jstring Java_org_yuzu_yuzu_1emu_NativeLibrary_getSavePath(JNIEnv* env, jobject j
const auto user_save_data_path = FileSys::SaveDataFactory::GetFullPath( const auto user_save_data_path = FileSys::SaveDataFactory::GetFullPath(
{}, vfsNandDir, FileSys::SaveDataSpaceId::NandUser, FileSys::SaveDataType::SaveData, {}, vfsNandDir, FileSys::SaveDataSpaceId::NandUser, FileSys::SaveDataType::SaveData,
program_id, user_id->AsU128(), 0); program_id, user_id->AsU128(), 0);
return Common::Android::ToJString(env, user_save_data_path); return ToJString(env, user_save_data_path);
} }
jstring Java_org_yuzu_yuzu_1emu_NativeLibrary_getDefaultProfileSaveDataRoot(JNIEnv* env, jstring Java_org_yuzu_yuzu_1emu_NativeLibrary_getDefaultProfileSaveDataRoot(JNIEnv* env,
@ -991,13 +981,12 @@ jstring Java_org_yuzu_yuzu_1emu_NativeLibrary_getDefaultProfileSaveDataRoot(JNIE
const auto user_save_data_root = const auto user_save_data_root =
FileSys::SaveDataFactory::GetUserGameSaveDataRoot(user_id->AsU128(), jfuture); FileSys::SaveDataFactory::GetUserGameSaveDataRoot(user_id->AsU128(), jfuture);
return Common::Android::ToJString(env, user_save_data_root); return ToJString(env, user_save_data_root);
} }
void Java_org_yuzu_yuzu_1emu_NativeLibrary_addFileToFilesystemProvider(JNIEnv* env, jobject jobj, void Java_org_yuzu_yuzu_1emu_NativeLibrary_addFileToFilesystemProvider(JNIEnv* env, jobject jobj,
jstring jpath) { jstring jpath) {
EmulationSession::GetInstance().ConfigureFilesystemProvider( EmulationSession::GetInstance().ConfigureFilesystemProvider(GetJString(env, jpath));
Common::Android::GetJString(env, jpath));
} }
void Java_org_yuzu_yuzu_1emu_NativeLibrary_clearFilesystemProvider(JNIEnv* env, jobject jobj) { void Java_org_yuzu_yuzu_1emu_NativeLibrary_clearFilesystemProvider(JNIEnv* env, jobject jobj) {

View File

@ -2,13 +2,13 @@
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#include <android/native_window_jni.h> #include <android/native_window_jni.h>
#include "common/android/applets/software_keyboard.h"
#include "common/detached_tasks.h" #include "common/detached_tasks.h"
#include "core/core.h" #include "core/core.h"
#include "core/file_sys/registered_cache.h" #include "core/file_sys/registered_cache.h"
#include "core/hle/service/acc/profile_manager.h" #include "core/hle/service/acc/profile_manager.h"
#include "core/perf_stats.h" #include "core/perf_stats.h"
#include "frontend_common/content_manager.h" #include "frontend_common/content_manager.h"
#include "jni/applets/software_keyboard.h"
#include "jni/emu_window/emu_window.h" #include "jni/emu_window/emu_window.h"
#include "video_core/rasterizer_interface.h" #include "video_core/rasterizer_interface.h"
@ -54,7 +54,7 @@ public:
void SetDeviceType([[maybe_unused]] int index, int type); void SetDeviceType([[maybe_unused]] int index, int type);
void OnGamepadConnectEvent([[maybe_unused]] int index); void OnGamepadConnectEvent([[maybe_unused]] int index);
void OnGamepadDisconnectEvent([[maybe_unused]] int index); void OnGamepadDisconnectEvent([[maybe_unused]] int index);
Common::Android::SoftwareKeyboard::AndroidKeyboard* SoftwareKeyboard(); SoftwareKeyboard::AndroidKeyboard* SoftwareKeyboard();
static void OnEmulationStarted(); static void OnEmulationStarted();
@ -79,7 +79,7 @@ private:
Core::SystemResultStatus m_load_result{Core::SystemResultStatus::ErrorNotInitialized}; Core::SystemResultStatus m_load_result{Core::SystemResultStatus::ErrorNotInitialized};
std::atomic<bool> m_is_running = false; std::atomic<bool> m_is_running = false;
std::atomic<bool> m_is_paused = false; std::atomic<bool> m_is_paused = false;
Common::Android::SoftwareKeyboard::AndroidKeyboard* m_software_keyboard{}; SoftwareKeyboard::AndroidKeyboard* m_software_keyboard{};
std::unique_ptr<FileSys::ManualContentProvider> m_manual_provider; std::unique_ptr<FileSys::ManualContentProvider> m_manual_provider;
int m_applet_id{1}; int m_applet_id{1};

View File

@ -8,11 +8,11 @@
#include "android_config.h" #include "android_config.h"
#include "android_settings.h" #include "android_settings.h"
#include "common/android/android_common.h"
#include "common/android/id_cache.h"
#include "common/logging/log.h" #include "common/logging/log.h"
#include "common/settings.h" #include "common/settings.h"
#include "frontend_common/config.h" #include "frontend_common/config.h"
#include "jni/android_common/android_common.h"
#include "jni/id_cache.h"
#include "native.h" #include "native.h"
std::unique_ptr<AndroidConfig> global_config; std::unique_ptr<AndroidConfig> global_config;
@ -20,7 +20,7 @@ std::unique_ptr<AndroidConfig> per_game_config;
template <typename T> template <typename T>
Settings::Setting<T>* getSetting(JNIEnv* env, jstring jkey) { Settings::Setting<T>* getSetting(JNIEnv* env, jstring jkey) {
auto key = Common::Android::GetJString(env, jkey); auto key = GetJString(env, jkey);
auto basic_setting = Settings::values.linkage.by_key[key]; auto basic_setting = Settings::values.linkage.by_key[key];
if (basic_setting != 0) { if (basic_setting != 0) {
return static_cast<Settings::Setting<T>*>(basic_setting); return static_cast<Settings::Setting<T>*>(basic_setting);
@ -55,7 +55,7 @@ void Java_org_yuzu_yuzu_1emu_utils_NativeConfig_initializePerGameConfig(JNIEnv*
jstring jprogramId, jstring jprogramId,
jstring jfileName) { jstring jfileName) {
auto program_id = EmulationSession::GetProgramId(env, jprogramId); auto program_id = EmulationSession::GetProgramId(env, jprogramId);
auto file_name = Common::Android::GetJString(env, jfileName); auto file_name = GetJString(env, jfileName);
const auto config_file_name = program_id == 0 ? file_name : fmt::format("{:016X}", program_id); const auto config_file_name = program_id == 0 ? file_name : fmt::format("{:016X}", program_id);
per_game_config = per_game_config =
std::make_unique<AndroidConfig>(config_file_name, Config::ConfigType::PerGameConfig); std::make_unique<AndroidConfig>(config_file_name, Config::ConfigType::PerGameConfig);
@ -186,9 +186,9 @@ jstring Java_org_yuzu_yuzu_1emu_utils_NativeConfig_getString(JNIEnv* env, jobjec
jboolean needGlobal) { jboolean needGlobal) {
auto setting = getSetting<std::string>(env, jkey); auto setting = getSetting<std::string>(env, jkey);
if (setting == nullptr) { if (setting == nullptr) {
return Common::Android::ToJString(env, ""); return ToJString(env, "");
} }
return Common::Android::ToJString(env, setting->GetValue(static_cast<bool>(needGlobal))); return ToJString(env, setting->GetValue(static_cast<bool>(needGlobal)));
} }
void Java_org_yuzu_yuzu_1emu_utils_NativeConfig_setString(JNIEnv* env, jobject obj, jstring jkey, void Java_org_yuzu_yuzu_1emu_utils_NativeConfig_setString(JNIEnv* env, jobject obj, jstring jkey,
@ -198,7 +198,7 @@ void Java_org_yuzu_yuzu_1emu_utils_NativeConfig_setString(JNIEnv* env, jobject o
return; return;
} }
setting->SetValue(Common::Android::GetJString(env, value)); setting->SetValue(GetJString(env, value));
} }
jboolean Java_org_yuzu_yuzu_1emu_utils_NativeConfig_getIsRuntimeModifiable(JNIEnv* env, jobject obj, jboolean Java_org_yuzu_yuzu_1emu_utils_NativeConfig_getIsRuntimeModifiable(JNIEnv* env, jobject obj,
@ -214,13 +214,13 @@ jstring Java_org_yuzu_yuzu_1emu_utils_NativeConfig_getPairedSettingKey(JNIEnv* e
jstring jkey) { jstring jkey) {
auto setting = getSetting<std::string>(env, jkey); auto setting = getSetting<std::string>(env, jkey);
if (setting == nullptr) { if (setting == nullptr) {
return Common::Android::ToJString(env, ""); return ToJString(env, "");
} }
if (setting->PairedSetting() == nullptr) { if (setting->PairedSetting() == nullptr) {
return Common::Android::ToJString(env, ""); return ToJString(env, "");
} }
return Common::Android::ToJString(env, setting->PairedSetting()->GetLabel()); return ToJString(env, setting->PairedSetting()->GetLabel());
} }
jboolean Java_org_yuzu_yuzu_1emu_utils_NativeConfig_getIsSwitchable(JNIEnv* env, jobject obj, jboolean Java_org_yuzu_yuzu_1emu_utils_NativeConfig_getIsSwitchable(JNIEnv* env, jobject obj,
@ -262,21 +262,21 @@ jstring Java_org_yuzu_yuzu_1emu_utils_NativeConfig_getDefaultToString(JNIEnv* en
jstring jkey) { jstring jkey) {
auto setting = getSetting<std::string>(env, jkey); auto setting = getSetting<std::string>(env, jkey);
if (setting != nullptr) { if (setting != nullptr) {
return Common::Android::ToJString(env, setting->DefaultToString()); return ToJString(env, setting->DefaultToString());
} }
return Common::Android::ToJString(env, ""); return ToJString(env, "");
} }
jobjectArray Java_org_yuzu_yuzu_1emu_utils_NativeConfig_getGameDirs(JNIEnv* env, jobject obj) { jobjectArray Java_org_yuzu_yuzu_1emu_utils_NativeConfig_getGameDirs(JNIEnv* env, jobject obj) {
jclass gameDirClass = Common::Android::GetGameDirClass(); jclass gameDirClass = IDCache::GetGameDirClass();
jmethodID gameDirConstructor = Common::Android::GetGameDirConstructor(); jmethodID gameDirConstructor = IDCache::GetGameDirConstructor();
jobjectArray jgameDirArray = jobjectArray jgameDirArray =
env->NewObjectArray(AndroidSettings::values.game_dirs.size(), gameDirClass, nullptr); env->NewObjectArray(AndroidSettings::values.game_dirs.size(), gameDirClass, nullptr);
for (size_t i = 0; i < AndroidSettings::values.game_dirs.size(); ++i) { for (size_t i = 0; i < AndroidSettings::values.game_dirs.size(); ++i) {
jobject jgameDir = env->NewObject( jobject jgameDir =
gameDirClass, gameDirConstructor, env->NewObject(gameDirClass, gameDirConstructor,
Common::Android::ToJString(env, AndroidSettings::values.game_dirs[i].path), ToJString(env, AndroidSettings::values.game_dirs[i].path),
static_cast<jboolean>(AndroidSettings::values.game_dirs[i].deep_scan)); static_cast<jboolean>(AndroidSettings::values.game_dirs[i].deep_scan));
env->SetObjectArrayElement(jgameDirArray, i, jgameDir); env->SetObjectArrayElement(jgameDirArray, i, jgameDir);
} }
return jgameDirArray; return jgameDirArray;
@ -292,14 +292,14 @@ void Java_org_yuzu_yuzu_1emu_utils_NativeConfig_setGameDirs(JNIEnv* env, jobject
} }
jobject dir = env->GetObjectArrayElement(gameDirs, 0); jobject dir = env->GetObjectArrayElement(gameDirs, 0);
jclass gameDirClass = Common::Android::GetGameDirClass(); jclass gameDirClass = IDCache::GetGameDirClass();
jfieldID uriStringField = env->GetFieldID(gameDirClass, "uriString", "Ljava/lang/String;"); jfieldID uriStringField = env->GetFieldID(gameDirClass, "uriString", "Ljava/lang/String;");
jfieldID deepScanBooleanField = env->GetFieldID(gameDirClass, "deepScan", "Z"); jfieldID deepScanBooleanField = env->GetFieldID(gameDirClass, "deepScan", "Z");
for (int i = 0; i < size; ++i) { for (int i = 0; i < size; ++i) {
dir = env->GetObjectArrayElement(gameDirs, i); dir = env->GetObjectArrayElement(gameDirs, i);
jstring juriString = static_cast<jstring>(env->GetObjectField(dir, uriStringField)); jstring juriString = static_cast<jstring>(env->GetObjectField(dir, uriStringField));
jboolean jdeepScanBoolean = env->GetBooleanField(dir, deepScanBooleanField); jboolean jdeepScanBoolean = env->GetBooleanField(dir, deepScanBooleanField);
std::string uriString = Common::Android::GetJString(env, juriString); std::string uriString = GetJString(env, juriString);
AndroidSettings::values.game_dirs.push_back( AndroidSettings::values.game_dirs.push_back(
AndroidSettings::GameDir{uriString, static_cast<bool>(jdeepScanBoolean)}); AndroidSettings::GameDir{uriString, static_cast<bool>(jdeepScanBoolean)});
} }
@ -307,13 +307,13 @@ void Java_org_yuzu_yuzu_1emu_utils_NativeConfig_setGameDirs(JNIEnv* env, jobject
void Java_org_yuzu_yuzu_1emu_utils_NativeConfig_addGameDir(JNIEnv* env, jobject obj, void Java_org_yuzu_yuzu_1emu_utils_NativeConfig_addGameDir(JNIEnv* env, jobject obj,
jobject gameDir) { jobject gameDir) {
jclass gameDirClass = Common::Android::GetGameDirClass(); jclass gameDirClass = IDCache::GetGameDirClass();
jfieldID uriStringField = env->GetFieldID(gameDirClass, "uriString", "Ljava/lang/String;"); jfieldID uriStringField = env->GetFieldID(gameDirClass, "uriString", "Ljava/lang/String;");
jfieldID deepScanBooleanField = env->GetFieldID(gameDirClass, "deepScan", "Z"); jfieldID deepScanBooleanField = env->GetFieldID(gameDirClass, "deepScan", "Z");
jstring juriString = static_cast<jstring>(env->GetObjectField(gameDir, uriStringField)); jstring juriString = static_cast<jstring>(env->GetObjectField(gameDir, uriStringField));
jboolean jdeepScanBoolean = env->GetBooleanField(gameDir, deepScanBooleanField); jboolean jdeepScanBoolean = env->GetBooleanField(gameDir, deepScanBooleanField);
std::string uriString = Common::Android::GetJString(env, juriString); std::string uriString = GetJString(env, juriString);
AndroidSettings::values.game_dirs.push_back( AndroidSettings::values.game_dirs.push_back(
AndroidSettings::GameDir{uriString, static_cast<bool>(jdeepScanBoolean)}); AndroidSettings::GameDir{uriString, static_cast<bool>(jdeepScanBoolean)});
} }
@ -323,11 +323,9 @@ jobjectArray Java_org_yuzu_yuzu_1emu_utils_NativeConfig_getDisabledAddons(JNIEnv
auto program_id = EmulationSession::GetProgramId(env, jprogramId); auto program_id = EmulationSession::GetProgramId(env, jprogramId);
auto& disabledAddons = Settings::values.disabled_addons[program_id]; auto& disabledAddons = Settings::values.disabled_addons[program_id];
jobjectArray jdisabledAddonsArray = jobjectArray jdisabledAddonsArray =
env->NewObjectArray(disabledAddons.size(), Common::Android::GetStringClass(), env->NewObjectArray(disabledAddons.size(), IDCache::GetStringClass(), ToJString(env, ""));
Common::Android::ToJString(env, ""));
for (size_t i = 0; i < disabledAddons.size(); ++i) { for (size_t i = 0; i < disabledAddons.size(); ++i) {
env->SetObjectArrayElement(jdisabledAddonsArray, i, env->SetObjectArrayElement(jdisabledAddonsArray, i, ToJString(env, disabledAddons[i]));
Common::Android::ToJString(env, disabledAddons[i]));
} }
return jdisabledAddonsArray; return jdisabledAddonsArray;
} }
@ -341,7 +339,7 @@ void Java_org_yuzu_yuzu_1emu_utils_NativeConfig_setDisabledAddons(JNIEnv* env, j
const int size = env->GetArrayLength(jdisabledAddons); const int size = env->GetArrayLength(jdisabledAddons);
for (int i = 0; i < size; ++i) { for (int i = 0; i < size; ++i) {
auto jaddon = static_cast<jstring>(env->GetObjectArrayElement(jdisabledAddons, i)); auto jaddon = static_cast<jstring>(env->GetObjectArrayElement(jdisabledAddons, i));
disabled_addons.push_back(Common::Android::GetJString(env, jaddon)); disabled_addons.push_back(GetJString(env, jaddon));
} }
Settings::values.disabled_addons[program_id] = disabled_addons; Settings::values.disabled_addons[program_id] = disabled_addons;
} }
@ -350,27 +348,26 @@ jobjectArray Java_org_yuzu_yuzu_1emu_utils_NativeConfig_getOverlayControlData(JN
jobject obj) { jobject obj) {
jobjectArray joverlayControlDataArray = jobjectArray joverlayControlDataArray =
env->NewObjectArray(AndroidSettings::values.overlay_control_data.size(), env->NewObjectArray(AndroidSettings::values.overlay_control_data.size(),
Common::Android::GetOverlayControlDataClass(), nullptr); IDCache::GetOverlayControlDataClass(), nullptr);
for (size_t i = 0; i < AndroidSettings::values.overlay_control_data.size(); ++i) { for (size_t i = 0; i < AndroidSettings::values.overlay_control_data.size(); ++i) {
const auto& control_data = AndroidSettings::values.overlay_control_data[i]; const auto& control_data = AndroidSettings::values.overlay_control_data[i];
jobject jlandscapePosition = jobject jlandscapePosition =
env->NewObject(Common::Android::GetPairClass(), Common::Android::GetPairConstructor(), env->NewObject(IDCache::GetPairClass(), IDCache::GetPairConstructor(),
Common::Android::ToJDouble(env, control_data.landscape_position.first), ToJDouble(env, control_data.landscape_position.first),
Common::Android::ToJDouble(env, control_data.landscape_position.second)); ToJDouble(env, control_data.landscape_position.second));
jobject jportraitPosition = jobject jportraitPosition =
env->NewObject(Common::Android::GetPairClass(), Common::Android::GetPairConstructor(), env->NewObject(IDCache::GetPairClass(), IDCache::GetPairConstructor(),
Common::Android::ToJDouble(env, control_data.portrait_position.first), ToJDouble(env, control_data.portrait_position.first),
Common::Android::ToJDouble(env, control_data.portrait_position.second)); ToJDouble(env, control_data.portrait_position.second));
jobject jfoldablePosition = jobject jfoldablePosition =
env->NewObject(Common::Android::GetPairClass(), Common::Android::GetPairConstructor(), env->NewObject(IDCache::GetPairClass(), IDCache::GetPairConstructor(),
Common::Android::ToJDouble(env, control_data.foldable_position.first), ToJDouble(env, control_data.foldable_position.first),
Common::Android::ToJDouble(env, control_data.foldable_position.second)); ToJDouble(env, control_data.foldable_position.second));
jobject jcontrolData = jobject jcontrolData = env->NewObject(
env->NewObject(Common::Android::GetOverlayControlDataClass(), IDCache::GetOverlayControlDataClass(), IDCache::GetOverlayControlDataConstructor(),
Common::Android::GetOverlayControlDataConstructor(), ToJString(env, control_data.id), control_data.enabled, jlandscapePosition,
Common::Android::ToJString(env, control_data.id), control_data.enabled, jportraitPosition, jfoldablePosition);
jlandscapePosition, jportraitPosition, jfoldablePosition);
env->SetObjectArrayElement(joverlayControlDataArray, i, jcontrolData); env->SetObjectArrayElement(joverlayControlDataArray, i, jcontrolData);
} }
return joverlayControlDataArray; return joverlayControlDataArray;
@ -387,41 +384,33 @@ void Java_org_yuzu_yuzu_1emu_utils_NativeConfig_setOverlayControlData(
for (int i = 0; i < size; ++i) { for (int i = 0; i < size; ++i) {
jobject joverlayControlData = env->GetObjectArrayElement(joverlayControlDataArray, i); jobject joverlayControlData = env->GetObjectArrayElement(joverlayControlDataArray, i);
jstring jidString = static_cast<jstring>(env->GetObjectField( jstring jidString = static_cast<jstring>(
joverlayControlData, Common::Android::GetOverlayControlDataIdField())); env->GetObjectField(joverlayControlData, IDCache::GetOverlayControlDataIdField()));
bool enabled = static_cast<bool>(env->GetBooleanField( bool enabled = static_cast<bool>(env->GetBooleanField(
joverlayControlData, Common::Android::GetOverlayControlDataEnabledField())); joverlayControlData, IDCache::GetOverlayControlDataEnabledField()));
jobject jlandscapePosition = env->GetObjectField( jobject jlandscapePosition = env->GetObjectField(
joverlayControlData, Common::Android::GetOverlayControlDataLandscapePositionField()); joverlayControlData, IDCache::GetOverlayControlDataLandscapePositionField());
std::pair<double, double> landscape_position = std::make_pair( std::pair<double, double> landscape_position = std::make_pair(
Common::Android::GetJDouble( GetJDouble(env, env->GetObjectField(jlandscapePosition, IDCache::GetPairFirstField())),
env, env->GetObjectField(jlandscapePosition, Common::Android::GetPairFirstField())), GetJDouble(env,
Common::Android::GetJDouble( env->GetObjectField(jlandscapePosition, IDCache::GetPairSecondField())));
env,
env->GetObjectField(jlandscapePosition, Common::Android::GetPairSecondField())));
jobject jportraitPosition = env->GetObjectField( jobject jportraitPosition = env->GetObjectField(
joverlayControlData, Common::Android::GetOverlayControlDataPortraitPositionField()); joverlayControlData, IDCache::GetOverlayControlDataPortraitPositionField());
std::pair<double, double> portrait_position = std::make_pair( std::pair<double, double> portrait_position = std::make_pair(
Common::Android::GetJDouble( GetJDouble(env, env->GetObjectField(jportraitPosition, IDCache::GetPairFirstField())),
env, env->GetObjectField(jportraitPosition, Common::Android::GetPairFirstField())), GetJDouble(env, env->GetObjectField(jportraitPosition, IDCache::GetPairSecondField())));
Common::Android::GetJDouble(
env,
env->GetObjectField(jportraitPosition, Common::Android::GetPairSecondField())));
jobject jfoldablePosition = env->GetObjectField( jobject jfoldablePosition = env->GetObjectField(
joverlayControlData, Common::Android::GetOverlayControlDataFoldablePositionField()); joverlayControlData, IDCache::GetOverlayControlDataFoldablePositionField());
std::pair<double, double> foldable_position = std::make_pair( std::pair<double, double> foldable_position = std::make_pair(
Common::Android::GetJDouble( GetJDouble(env, env->GetObjectField(jfoldablePosition, IDCache::GetPairFirstField())),
env, env->GetObjectField(jfoldablePosition, Common::Android::GetPairFirstField())), GetJDouble(env, env->GetObjectField(jfoldablePosition, IDCache::GetPairSecondField())));
Common::Android::GetJDouble(
env,
env->GetObjectField(jfoldablePosition, Common::Android::GetPairSecondField())));
AndroidSettings::values.overlay_control_data.push_back(AndroidSettings::OverlayControlData{ AndroidSettings::values.overlay_control_data.push_back(AndroidSettings::OverlayControlData{
Common::Android::GetJString(env, jidString), enabled, landscape_position, GetJString(env, jidString), enabled, landscape_position, portrait_position,
portrait_position, foldable_position}); foldable_position});
} }
} }

View File

@ -1,30 +1,31 @@
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project // SPDX-FileCopyrightText: 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#include <common/android/android_common.h>
#include <common/logging/log.h> #include <common/logging/log.h>
#include <jni.h> #include <jni.h>
#include "android_common/android_common.h"
extern "C" { extern "C" {
void Java_org_yuzu_yuzu_1emu_utils_Log_debug(JNIEnv* env, jobject obj, jstring jmessage) { void Java_org_yuzu_yuzu_1emu_utils_Log_debug(JNIEnv* env, jobject obj, jstring jmessage) {
LOG_DEBUG(Frontend, "{}", Common::Android::GetJString(env, jmessage)); LOG_DEBUG(Frontend, "{}", GetJString(env, jmessage));
} }
void Java_org_yuzu_yuzu_1emu_utils_Log_warning(JNIEnv* env, jobject obj, jstring jmessage) { void Java_org_yuzu_yuzu_1emu_utils_Log_warning(JNIEnv* env, jobject obj, jstring jmessage) {
LOG_WARNING(Frontend, "{}", Common::Android::GetJString(env, jmessage)); LOG_WARNING(Frontend, "{}", GetJString(env, jmessage));
} }
void Java_org_yuzu_yuzu_1emu_utils_Log_info(JNIEnv* env, jobject obj, jstring jmessage) { void Java_org_yuzu_yuzu_1emu_utils_Log_info(JNIEnv* env, jobject obj, jstring jmessage) {
LOG_INFO(Frontend, "{}", Common::Android::GetJString(env, jmessage)); LOG_INFO(Frontend, "{}", GetJString(env, jmessage));
} }
void Java_org_yuzu_yuzu_1emu_utils_Log_error(JNIEnv* env, jobject obj, jstring jmessage) { void Java_org_yuzu_yuzu_1emu_utils_Log_error(JNIEnv* env, jobject obj, jstring jmessage) {
LOG_ERROR(Frontend, "{}", Common::Android::GetJString(env, jmessage)); LOG_ERROR(Frontend, "{}", GetJString(env, jmessage));
} }
void Java_org_yuzu_yuzu_1emu_utils_Log_critical(JNIEnv* env, jobject obj, jstring jmessage) { void Java_org_yuzu_yuzu_1emu_utils_Log_critical(JNIEnv* env, jobject obj, jstring jmessage) {
LOG_CRITICAL(Frontend, "{}", Common::Android::GetJString(env, jmessage)); LOG_CRITICAL(Frontend, "{}", GetJString(env, jmessage));
} }
} // extern "C" } // extern "C"

View File

@ -4,6 +4,10 @@
<!-- General application strings --> <!-- General application strings -->
<string name="app_name" translatable="false">yuzu</string> <string name="app_name" translatable="false">yuzu</string>
<string name="app_disclaimer">This software will run games for the Nintendo Switch game console. No game titles or keys are included.&lt;br /&gt;&lt;br /&gt;Before you begin, please locate your <![CDATA[<b> prod.keys </b>]]> file on your device storage.&lt;br /&gt;&lt;br /&gt;<![CDATA[<a href="https://yuzu-emu.org/help/quickstart">Learn more</a>]]></string> <string name="app_disclaimer">This software will run games for the Nintendo Switch game console. No game titles or keys are included.&lt;br /&gt;&lt;br /&gt;Before you begin, please locate your <![CDATA[<b> prod.keys </b>]]> file on your device storage.&lt;br /&gt;&lt;br /&gt;<![CDATA[<a href="https://yuzu-emu.org/help/quickstart">Learn more</a>]]></string>
<string name="emulation_notification_channel_name">Emulation is Active</string>
<string name="emulation_notification_channel_id" translatable="false">emulationIsActive</string>
<string name="emulation_notification_channel_description">Shows a persistent notification when emulation is running.</string>
<string name="emulation_notification_running">yuzu is running</string>
<string name="notice_notification_channel_name">Notices and errors</string> <string name="notice_notification_channel_name">Notices and errors</string>
<string name="notice_notification_channel_id" translatable="false">noticesAndErrors</string> <string name="notice_notification_channel_id" translatable="false">noticesAndErrors</string>
<string name="notice_notification_channel_description">Shows notifications when something goes wrong.</string> <string name="notice_notification_channel_description">Shows notifications when something goes wrong.</string>

View File

@ -107,8 +107,6 @@ add_library(common STATIC
quaternion.h quaternion.h
range_map.h range_map.h
range_mutex.h range_mutex.h
range_sets.h
range_sets.inc
reader_writer_queue.h reader_writer_queue.h
ring_buffer.h ring_buffer.h
${CMAKE_CURRENT_BINARY_DIR}/scm_rev.cpp ${CMAKE_CURRENT_BINARY_DIR}/scm_rev.cpp
@ -123,7 +121,6 @@ add_library(common STATIC
settings_input.cpp settings_input.cpp
settings_input.h settings_input.h
settings_setting.h settings_setting.h
slot_vector.h
socket_types.h socket_types.h
spin_lock.cpp spin_lock.cpp
spin_lock.h spin_lock.h
@ -182,15 +179,9 @@ endif()
if(ANDROID) if(ANDROID)
target_sources(common target_sources(common
PUBLIC PRIVATE
fs/fs_android.cpp fs/fs_android.cpp
fs/fs_android.h fs/fs_android.h
android/android_common.cpp
android/android_common.h
android/id_cache.cpp
android/id_cache.h
android/applets/software_keyboard.cpp
android/applets/software_keyboard.h
) )
endif() endif()

View File

@ -1,38 +1,63 @@
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#include "common/android/android_common.h"
#include "common/android/id_cache.h"
#include "common/assert.h"
#include "common/fs/fs_android.h" #include "common/fs/fs_android.h"
#include "common/string_util.h" #include "common/string_util.h"
namespace Common::FS::Android { namespace Common::FS::Android {
JNIEnv* GetEnvForThread() {
thread_local static struct OwnedEnv {
OwnedEnv() {
status = g_jvm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6);
if (status == JNI_EDETACHED)
g_jvm->AttachCurrentThread(&env, nullptr);
}
~OwnedEnv() {
if (status == JNI_EDETACHED)
g_jvm->DetachCurrentThread();
}
int status;
JNIEnv* env = nullptr;
} owned;
return owned.env;
}
void RegisterCallbacks(JNIEnv* env, jclass clazz) { void RegisterCallbacks(JNIEnv* env, jclass clazz) {
env->GetJavaVM(&g_jvm); env->GetJavaVM(&g_jvm);
native_library = clazz; native_library = clazz;
s_get_parent_directory = env->GetStaticMethodID(native_library, "getParentDirectory", #define FH(FunctionName, JMethodID, Caller, JMethodName, Signature) \
"(Ljava/lang/String;)Ljava/lang/String;"); F(JMethodID, JMethodName, Signature)
s_get_filename = env->GetStaticMethodID(native_library, "getFilename", #define FR(FunctionName, ReturnValue, JMethodID, Caller, JMethodName, Signature) \
"(Ljava/lang/String;)Ljava/lang/String;"); F(JMethodID, JMethodName, Signature)
s_get_size = env->GetStaticMethodID(native_library, "getSize", "(Ljava/lang/String;)J"); #define FS(FunctionName, ReturnValue, Parameters, JMethodID, JMethodName, Signature) \
s_is_directory = env->GetStaticMethodID(native_library, "isDirectory", "(Ljava/lang/String;)Z"); F(JMethodID, JMethodName, Signature)
s_file_exists = env->GetStaticMethodID(native_library, "exists", "(Ljava/lang/String;)Z"); #define F(JMethodID, JMethodName, Signature) \
s_open_content_uri = env->GetStaticMethodID(native_library, "openContentUri", JMethodID = env->GetStaticMethodID(native_library, JMethodName, Signature);
"(Ljava/lang/String;Ljava/lang/String;)I"); ANDROID_SINGLE_PATH_HELPER_FUNCTIONS(FH)
ANDROID_SINGLE_PATH_DETERMINE_FUNCTIONS(FR)
ANDROID_STORAGE_FUNCTIONS(FS)
#undef F
#undef FS
#undef FR
#undef FH
} }
void UnRegisterCallbacks() { void UnRegisterCallbacks() {
s_get_parent_directory = nullptr; #define FH(FunctionName, JMethodID, Caller, JMethodName, Signature) F(JMethodID)
s_get_filename = nullptr; #define FR(FunctionName, ReturnValue, JMethodID, Caller, JMethodName, Signature) F(JMethodID)
#define FS(FunctionName, ReturnValue, Parameters, JMethodID, JMethodName, Signature) F(JMethodID)
s_get_size = nullptr; #define F(JMethodID) JMethodID = nullptr;
s_is_directory = nullptr; ANDROID_SINGLE_PATH_HELPER_FUNCTIONS(FH)
s_file_exists = nullptr; ANDROID_SINGLE_PATH_DETERMINE_FUNCTIONS(FR)
ANDROID_STORAGE_FUNCTIONS(FS)
s_open_content_uri = nullptr; #undef F
#undef FS
#undef FR
#undef FH
} }
bool IsContentUri(const std::string& path) { bool IsContentUri(const std::string& path) {
@ -44,8 +69,8 @@ bool IsContentUri(const std::string& path) {
return path.find(prefix) == 0; return path.find(prefix) == 0;
} }
s32 OpenContentUri(const std::string& filepath, OpenMode openmode) { int OpenContentUri(const std::string& filepath, OpenMode openmode) {
if (s_open_content_uri == nullptr) if (open_content_uri == nullptr)
return -1; return -1;
const char* mode = ""; const char* mode = "";
@ -57,66 +82,50 @@ s32 OpenContentUri(const std::string& filepath, OpenMode openmode) {
UNIMPLEMENTED(); UNIMPLEMENTED();
return -1; return -1;
} }
auto env = Common::Android::GetEnvForThread(); auto env = GetEnvForThread();
jstring j_filepath = Common::Android::ToJString(env, filepath); jstring j_filepath = env->NewStringUTF(filepath.c_str());
jstring j_mode = Common::Android::ToJString(env, mode); jstring j_mode = env->NewStringUTF(mode);
return env->CallStaticIntMethod(native_library, s_open_content_uri, j_filepath, j_mode); return env->CallStaticIntMethod(native_library, open_content_uri, j_filepath, j_mode);
} }
u64 GetSize(const std::string& filepath) { #define FR(FunctionName, ReturnValue, JMethodID, Caller, JMethodName, Signature) \
if (s_get_size == nullptr) { F(FunctionName, ReturnValue, JMethodID, Caller)
return 0; #define F(FunctionName, ReturnValue, JMethodID, Caller) \
ReturnValue FunctionName(const std::string& filepath) { \
if (JMethodID == nullptr) { \
return 0; \
} \
auto env = GetEnvForThread(); \
jstring j_filepath = env->NewStringUTF(filepath.c_str()); \
return env->Caller(native_library, JMethodID, j_filepath); \
} }
auto env = Common::Android::GetEnvForThread(); ANDROID_SINGLE_PATH_DETERMINE_FUNCTIONS(FR)
return static_cast<u64>(env->CallStaticLongMethod( #undef F
native_library, s_get_size, #undef FR
Common::Android::ToJString(Common::Android::GetEnvForThread(), filepath)));
}
bool IsDirectory(const std::string& filepath) { #define FH(FunctionName, JMethodID, Caller, JMethodName, Signature) \
if (s_is_directory == nullptr) { F(FunctionName, JMethodID, Caller)
return 0; #define F(FunctionName, JMethodID, Caller) \
std::string FunctionName(const std::string& filepath) { \
if (JMethodID == nullptr) { \
return 0; \
} \
auto env = GetEnvForThread(); \
jstring j_filepath = env->NewStringUTF(filepath.c_str()); \
jstring j_return = \
static_cast<jstring>(env->Caller(native_library, JMethodID, j_filepath)); \
if (!j_return) { \
return {}; \
} \
const jchar* jchars = env->GetStringChars(j_return, nullptr); \
const jsize length = env->GetStringLength(j_return); \
const std::u16string_view string_view(reinterpret_cast<const char16_t*>(jchars), length); \
const std::string converted_string = Common::UTF16ToUTF8(string_view); \
env->ReleaseStringChars(j_return, jchars); \
return converted_string; \
} }
auto env = Common::Android::GetEnvForThread(); ANDROID_SINGLE_PATH_HELPER_FUNCTIONS(FH)
return env->CallStaticBooleanMethod( #undef F
native_library, s_is_directory, #undef FH
Common::Android::ToJString(Common::Android::GetEnvForThread(), filepath));
}
bool Exists(const std::string& filepath) {
if (s_file_exists == nullptr) {
return 0;
}
auto env = Common::Android::GetEnvForThread();
return env->CallStaticBooleanMethod(
native_library, s_file_exists,
Common::Android::ToJString(Common::Android::GetEnvForThread(), filepath));
}
std::string GetParentDirectory(const std::string& filepath) {
if (s_get_parent_directory == nullptr) {
return 0;
}
auto env = Common::Android::GetEnvForThread();
jstring j_return = static_cast<jstring>(env->CallStaticObjectMethod(
native_library, s_get_parent_directory, Common::Android::ToJString(env, filepath)));
if (!j_return) {
return {};
}
return Common::Android::GetJString(env, j_return);
}
std::string GetFilename(const std::string& filepath) {
if (s_get_filename == nullptr) {
return 0;
}
auto env = Common::Android::GetEnvForThread();
jstring j_return = static_cast<jstring>(env->CallStaticObjectMethod(
native_library, s_get_filename, Common::Android::ToJString(env, filepath)));
if (!j_return) {
return {};
}
return Common::Android::GetJString(env, j_return);
}
} // namespace Common::FS::Android } // namespace Common::FS::Android

View File

@ -7,17 +7,38 @@
#include <vector> #include <vector>
#include <jni.h> #include <jni.h>
#define ANDROID_STORAGE_FUNCTIONS(V) \
V(OpenContentUri, int, (const std::string& filepath, OpenMode openmode), open_content_uri, \
"openContentUri", "(Ljava/lang/String;Ljava/lang/String;)I")
#define ANDROID_SINGLE_PATH_DETERMINE_FUNCTIONS(V) \
V(GetSize, std::uint64_t, get_size, CallStaticLongMethod, "getSize", "(Ljava/lang/String;)J") \
V(IsDirectory, bool, is_directory, CallStaticBooleanMethod, "isDirectory", \
"(Ljava/lang/String;)Z") \
V(Exists, bool, file_exists, CallStaticBooleanMethod, "exists", "(Ljava/lang/String;)Z")
#define ANDROID_SINGLE_PATH_HELPER_FUNCTIONS(V) \
V(GetParentDirectory, get_parent_directory, CallStaticObjectMethod, "getParentDirectory", \
"(Ljava/lang/String;)Ljava/lang/String;") \
V(GetFilename, get_filename, CallStaticObjectMethod, "getFilename", \
"(Ljava/lang/String;)Ljava/lang/String;")
namespace Common::FS::Android { namespace Common::FS::Android {
static JavaVM* g_jvm = nullptr; static JavaVM* g_jvm = nullptr;
static jclass native_library = nullptr; static jclass native_library = nullptr;
static jmethodID s_get_parent_directory; #define FH(FunctionName, JMethodID, Caller, JMethodName, Signature) F(JMethodID)
static jmethodID s_get_filename; #define FR(FunctionName, ReturnValue, JMethodID, Caller, JMethodName, Signature) F(JMethodID)
static jmethodID s_get_size; #define FS(FunctionName, ReturnValue, Parameters, JMethodID, JMethodName, Signature) F(JMethodID)
static jmethodID s_is_directory; #define F(JMethodID) static jmethodID JMethodID = nullptr;
static jmethodID s_file_exists; ANDROID_SINGLE_PATH_HELPER_FUNCTIONS(FH)
static jmethodID s_open_content_uri; ANDROID_SINGLE_PATH_DETERMINE_FUNCTIONS(FR)
ANDROID_STORAGE_FUNCTIONS(FS)
#undef F
#undef FS
#undef FR
#undef FH
enum class OpenMode { enum class OpenMode {
Read, Read,
@ -36,11 +57,24 @@ void UnRegisterCallbacks();
bool IsContentUri(const std::string& path); bool IsContentUri(const std::string& path);
int OpenContentUri(const std::string& filepath, OpenMode openmode); #define FS(FunctionName, ReturnValue, Parameters, JMethodID, JMethodName, Signature) \
std::uint64_t GetSize(const std::string& filepath); F(FunctionName, Parameters, ReturnValue)
bool IsDirectory(const std::string& filepath); #define F(FunctionName, Parameters, ReturnValue) ReturnValue FunctionName Parameters;
bool Exists(const std::string& filepath); ANDROID_STORAGE_FUNCTIONS(FS)
std::string GetParentDirectory(const std::string& filepath); #undef F
std::string GetFilename(const std::string& filepath); #undef FS
#define FR(FunctionName, ReturnValue, JMethodID, Caller, JMethodName, Signature) \
F(FunctionName, ReturnValue)
#define F(FunctionName, ReturnValue) ReturnValue FunctionName(const std::string& filepath);
ANDROID_SINGLE_PATH_DETERMINE_FUNCTIONS(FR)
#undef F
#undef FR
#define FH(FunctionName, JMethodID, Caller, JMethodName, Signature) F(FunctionName)
#define F(FunctionName) std::string FunctionName(const std::string& filepath);
ANDROID_SINGLE_PATH_HELPER_FUNCTIONS(FH)
#undef F
#undef FH
} // namespace Common::FS::Android } // namespace Common::FS::Android

View File

@ -9,7 +9,6 @@
#include <string> #include <string>
#include <vector> #include <vector>
#include <fmt/format.h> #include <fmt/format.h>
#include "common/assert.h"
#include "common/common_types.h" #include "common/common_types.h"
namespace Common { namespace Common {
@ -30,8 +29,6 @@ namespace Common {
template <std::size_t Size, bool le = false> template <std::size_t Size, bool le = false>
[[nodiscard]] constexpr std::array<u8, Size> HexStringToArray(std::string_view str) { [[nodiscard]] constexpr std::array<u8, Size> HexStringToArray(std::string_view str) {
ASSERT_MSG(Size * 2 <= str.size(), "Invalid string size");
std::array<u8, Size> out{}; std::array<u8, Size> out{};
if constexpr (le) { if constexpr (le) {
for (std::size_t i = 2 * Size - 2; i <= 2 * Size; i -= 2) { for (std::size_t i = 2 * Size - 2; i <= 2 * Size; i -= 2) {

View File

@ -1,73 +0,0 @@
// SPDX-FileCopyrightText: 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <memory>
#include "common/common_types.h"
namespace Common {
template <typename AddressType>
class RangeSet {
public:
RangeSet();
~RangeSet();
RangeSet(RangeSet const&) = delete;
RangeSet& operator=(RangeSet const&) = delete;
RangeSet(RangeSet&& other);
RangeSet& operator=(RangeSet&& other);
void Add(AddressType base_address, size_t size);
void Subtract(AddressType base_address, size_t size);
void Clear();
bool Empty() const;
template <typename Func>
void ForEach(Func&& func) const;
template <typename Func>
void ForEachInRange(AddressType device_addr, size_t size, Func&& func) const;
private:
struct RangeSetImpl;
std::unique_ptr<RangeSetImpl> m_impl;
};
template <typename AddressType>
class OverlapRangeSet {
public:
OverlapRangeSet();
~OverlapRangeSet();
OverlapRangeSet(OverlapRangeSet const&) = delete;
OverlapRangeSet& operator=(OverlapRangeSet const&) = delete;
OverlapRangeSet(OverlapRangeSet&& other);
OverlapRangeSet& operator=(OverlapRangeSet&& other);
void Add(AddressType base_address, size_t size);
void Subtract(AddressType base_address, size_t size);
template <typename Func>
void Subtract(AddressType base_address, size_t size, Func&& on_delete);
void DeleteAll(AddressType base_address, size_t size);
void Clear();
bool Empty() const;
template <typename Func>
void ForEach(Func&& func) const;
template <typename Func>
void ForEachInRange(AddressType device_addr, size_t size, Func&& func) const;
private:
struct OverlapRangeSetImpl;
std::unique_ptr<OverlapRangeSetImpl> m_impl;
};
} // namespace Common

View File

@ -1,304 +0,0 @@
// SPDX-FileCopyrightText: 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <limits>
#include <utility>
#include <boost/icl/interval.hpp>
#include <boost/icl/interval_base_set.hpp>
#include <boost/icl/interval_map.hpp>
#include <boost/icl/interval_set.hpp>
#include <boost/icl/split_interval_map.hpp>
#include <boost/pool/pool.hpp>
#include <boost/pool/pool_alloc.hpp>
#include <boost/pool/poolfwd.hpp>
#include "common/range_sets.h"
namespace Common {
namespace {
template <class T>
using RangeSetsAllocator =
boost::fast_pool_allocator<T, boost::default_user_allocator_new_delete,
boost::details::pool::default_mutex, 1024, 2048>;
}
template <typename AddressType>
struct RangeSet<AddressType>::RangeSetImpl {
using IntervalSet = boost::icl::interval_set<
AddressType, std::less, ICL_INTERVAL_INSTANCE(ICL_INTERVAL_DEFAULT, AddressType, std::less),
RangeSetsAllocator>;
using IntervalType = typename IntervalSet::interval_type;
RangeSetImpl() = default;
~RangeSetImpl() = default;
void Add(AddressType base_address, size_t size) {
AddressType end_address = base_address + static_cast<AddressType>(size);
IntervalType interval{base_address, end_address};
m_ranges_set.add(interval);
}
void Subtract(AddressType base_address, size_t size) {
AddressType end_address = base_address + static_cast<AddressType>(size);
IntervalType interval{base_address, end_address};
m_ranges_set.subtract(interval);
}
template <typename Func>
void ForEach(Func&& func) const {
if (m_ranges_set.empty()) {
return;
}
auto it = m_ranges_set.begin();
auto end_it = m_ranges_set.end();
for (; it != end_it; it++) {
const AddressType inter_addr_end = it->upper();
const AddressType inter_addr = it->lower();
func(inter_addr, inter_addr_end);
}
}
template <typename Func>
void ForEachInRange(AddressType base_addr, size_t size, Func&& func) const {
if (m_ranges_set.empty()) {
return;
}
const AddressType start_address = base_addr;
const AddressType end_address = start_address + size;
const RangeSetImpl::IntervalType search_interval{start_address, end_address};
auto it = m_ranges_set.lower_bound(search_interval);
if (it == m_ranges_set.end()) {
return;
}
auto end_it = m_ranges_set.upper_bound(search_interval);
for (; it != end_it; it++) {
AddressType inter_addr_end = it->upper();
AddressType inter_addr = it->lower();
if (inter_addr_end > end_address) {
inter_addr_end = end_address;
}
if (inter_addr < start_address) {
inter_addr = start_address;
}
func(inter_addr, inter_addr_end);
}
}
IntervalSet m_ranges_set;
};
template <typename AddressType>
struct OverlapRangeSet<AddressType>::OverlapRangeSetImpl {
using IntervalSet = boost::icl::split_interval_map<
AddressType, s32, boost::icl::partial_enricher, std::less, boost::icl::inplace_plus,
boost::icl::inter_section,
ICL_INTERVAL_INSTANCE(ICL_INTERVAL_DEFAULT, AddressType, std::less), RangeSetsAllocator>;
using IntervalType = typename IntervalSet::interval_type;
OverlapRangeSetImpl() = default;
~OverlapRangeSetImpl() = default;
void Add(AddressType base_address, size_t size) {
AddressType end_address = base_address + static_cast<AddressType>(size);
IntervalType interval{base_address, end_address};
m_split_ranges_set += std::make_pair(interval, 1);
}
template <bool has_on_delete, typename Func>
void Subtract(AddressType base_address, size_t size, s32 amount,
[[maybe_unused]] Func&& on_delete) {
if (m_split_ranges_set.empty()) {
return;
}
AddressType end_address = base_address + static_cast<AddressType>(size);
IntervalType interval{base_address, end_address};
bool any_removals = false;
m_split_ranges_set += std::make_pair(interval, -amount);
do {
any_removals = false;
auto it = m_split_ranges_set.lower_bound(interval);
if (it == m_split_ranges_set.end()) {
return;
}
auto end_it = m_split_ranges_set.upper_bound(interval);
for (; it != end_it; it++) {
if (it->second <= 0) {
if constexpr (has_on_delete) {
if (it->second == 0) {
on_delete(it->first.lower(), it->first.upper());
}
}
any_removals = true;
m_split_ranges_set.erase(it);
break;
}
}
} while (any_removals);
}
template <typename Func>
void ForEach(Func&& func) const {
if (m_split_ranges_set.empty()) {
return;
}
auto it = m_split_ranges_set.begin();
auto end_it = m_split_ranges_set.end();
for (; it != end_it; it++) {
const AddressType inter_addr_end = it->first.upper();
const AddressType inter_addr = it->first.lower();
func(inter_addr, inter_addr_end, it->second);
}
}
template <typename Func>
void ForEachInRange(AddressType base_address, size_t size, Func&& func) const {
if (m_split_ranges_set.empty()) {
return;
}
const AddressType start_address = base_address;
const AddressType end_address = start_address + size;
const OverlapRangeSetImpl::IntervalType search_interval{start_address, end_address};
auto it = m_split_ranges_set.lower_bound(search_interval);
if (it == m_split_ranges_set.end()) {
return;
}
auto end_it = m_split_ranges_set.upper_bound(search_interval);
for (; it != end_it; it++) {
auto& inter = it->first;
AddressType inter_addr_end = inter.upper();
AddressType inter_addr = inter.lower();
if (inter_addr_end > end_address) {
inter_addr_end = end_address;
}
if (inter_addr < start_address) {
inter_addr = start_address;
}
func(inter_addr, inter_addr_end, it->second);
}
}
IntervalSet m_split_ranges_set;
};
template <typename AddressType>
RangeSet<AddressType>::RangeSet() {
m_impl = std::make_unique<RangeSet<AddressType>::RangeSetImpl>();
}
template <typename AddressType>
RangeSet<AddressType>::~RangeSet() = default;
template <typename AddressType>
RangeSet<AddressType>::RangeSet(RangeSet&& other) {
m_impl = std::make_unique<RangeSet<AddressType>::RangeSetImpl>();
m_impl->m_ranges_set = std::move(other.m_impl->m_ranges_set);
}
template <typename AddressType>
RangeSet<AddressType>& RangeSet<AddressType>::operator=(RangeSet&& other) {
m_impl->m_ranges_set = std::move(other.m_impl->m_ranges_set);
}
template <typename AddressType>
void RangeSet<AddressType>::Add(AddressType base_address, size_t size) {
m_impl->Add(base_address, size);
}
template <typename AddressType>
void RangeSet<AddressType>::Subtract(AddressType base_address, size_t size) {
m_impl->Subtract(base_address, size);
}
template <typename AddressType>
void RangeSet<AddressType>::Clear() {
m_impl->m_ranges_set.clear();
}
template <typename AddressType>
bool RangeSet<AddressType>::Empty() const {
return m_impl->m_ranges_set.empty();
}
template <typename AddressType>
template <typename Func>
void RangeSet<AddressType>::ForEach(Func&& func) const {
m_impl->ForEach(std::move(func));
}
template <typename AddressType>
template <typename Func>
void RangeSet<AddressType>::ForEachInRange(AddressType base_address, size_t size,
Func&& func) const {
m_impl->ForEachInRange(base_address, size, std::move(func));
}
template <typename AddressType>
OverlapRangeSet<AddressType>::OverlapRangeSet() {
m_impl = std::make_unique<OverlapRangeSet<AddressType>::OverlapRangeSetImpl>();
}
template <typename AddressType>
OverlapRangeSet<AddressType>::~OverlapRangeSet() = default;
template <typename AddressType>
OverlapRangeSet<AddressType>::OverlapRangeSet(OverlapRangeSet&& other) {
m_impl = std::make_unique<OverlapRangeSet<AddressType>::OverlapRangeSetImpl>();
m_impl->m_split_ranges_set = std::move(other.m_impl->m_split_ranges_set);
}
template <typename AddressType>
OverlapRangeSet<AddressType>& OverlapRangeSet<AddressType>::operator=(OverlapRangeSet&& other) {
m_impl->m_split_ranges_set = std::move(other.m_impl->m_split_ranges_set);
}
template <typename AddressType>
void OverlapRangeSet<AddressType>::Add(AddressType base_address, size_t size) {
m_impl->Add(base_address, size);
}
template <typename AddressType>
void OverlapRangeSet<AddressType>::Subtract(AddressType base_address, size_t size) {
m_impl->template Subtract<false>(base_address, size, 1, [](AddressType, AddressType) {});
}
template <typename AddressType>
template <typename Func>
void OverlapRangeSet<AddressType>::Subtract(AddressType base_address, size_t size,
Func&& on_delete) {
m_impl->template Subtract<true, Func>(base_address, size, 1, std::move(on_delete));
}
template <typename AddressType>
void OverlapRangeSet<AddressType>::DeleteAll(AddressType base_address, size_t size) {
m_impl->template Subtract<false>(base_address, size, std::numeric_limits<s32>::max(),
[](AddressType, AddressType) {});
}
template <typename AddressType>
void OverlapRangeSet<AddressType>::Clear() {
m_impl->m_split_ranges_set.clear();
}
template <typename AddressType>
bool OverlapRangeSet<AddressType>::Empty() const {
return m_impl->m_split_ranges_set.empty();
}
template <typename AddressType>
template <typename Func>
void OverlapRangeSet<AddressType>::ForEach(Func&& func) const {
m_impl->ForEach(func);
}
template <typename AddressType>
template <typename Func>
void OverlapRangeSet<AddressType>::ForEachInRange(AddressType base_address, size_t size,
Func&& func) const {
m_impl->ForEachInRange(base_address, size, std::move(func));
}
} // namespace Common

View File

@ -30,7 +30,6 @@ namespace Settings {
#define SETTING(TYPE, RANGED) template class Setting<TYPE, RANGED> #define SETTING(TYPE, RANGED) template class Setting<TYPE, RANGED>
#define SWITCHABLE(TYPE, RANGED) template class SwitchableSetting<TYPE, RANGED> #define SWITCHABLE(TYPE, RANGED) template class SwitchableSetting<TYPE, RANGED>
SETTING(AppletMode, false);
SETTING(AudioEngine, false); SETTING(AudioEngine, false);
SETTING(bool, false); SETTING(bool, false);
SETTING(int, false); SETTING(int, false);
@ -216,8 +215,6 @@ const char* TranslateCategory(Category category) {
return "Debugging"; return "Debugging";
case Category::GpuDriver: case Category::GpuDriver:
return "GpuDriver"; return "GpuDriver";
case Category::LibraryApplet:
return "LibraryApplet";
case Category::Miscellaneous: case Category::Miscellaneous:
return "Miscellaneous"; return "Miscellaneous";
case Category::Network: case Category::Network:

View File

@ -133,38 +133,6 @@ struct TouchFromButtonMap {
struct Values { struct Values {
Linkage linkage{}; Linkage linkage{};
// Applet
Setting<AppletMode> cabinet_applet_mode{linkage, AppletMode::LLE, "cabinet_applet_mode",
Category::LibraryApplet};
Setting<AppletMode> controller_applet_mode{linkage, AppletMode::HLE, "controller_applet_mode",
Category::LibraryApplet};
Setting<AppletMode> data_erase_applet_mode{linkage, AppletMode::HLE, "data_erase_applet_mode",
Category::LibraryApplet};
Setting<AppletMode> error_applet_mode{linkage, AppletMode::HLE, "error_applet_mode",
Category::LibraryApplet};
Setting<AppletMode> net_connect_applet_mode{linkage, AppletMode::HLE, "net_connect_applet_mode",
Category::LibraryApplet};
Setting<AppletMode> player_select_applet_mode{
linkage, AppletMode::HLE, "player_select_applet_mode", Category::LibraryApplet};
Setting<AppletMode> swkbd_applet_mode{linkage, AppletMode::LLE, "swkbd_applet_mode",
Category::LibraryApplet};
Setting<AppletMode> mii_edit_applet_mode{linkage, AppletMode::LLE, "mii_edit_applet_mode",
Category::LibraryApplet};
Setting<AppletMode> web_applet_mode{linkage, AppletMode::HLE, "web_applet_mode",
Category::LibraryApplet};
Setting<AppletMode> shop_applet_mode{linkage, AppletMode::HLE, "shop_applet_mode",
Category::LibraryApplet};
Setting<AppletMode> photo_viewer_applet_mode{
linkage, AppletMode::LLE, "photo_viewer_applet_mode", Category::LibraryApplet};
Setting<AppletMode> offline_web_applet_mode{linkage, AppletMode::LLE, "offline_web_applet_mode",
Category::LibraryApplet};
Setting<AppletMode> login_share_applet_mode{linkage, AppletMode::HLE, "login_share_applet_mode",
Category::LibraryApplet};
Setting<AppletMode> wifi_web_auth_applet_mode{
linkage, AppletMode::HLE, "wifi_web_auth_applet_mode", Category::LibraryApplet};
Setting<AppletMode> my_page_applet_mode{linkage, AppletMode::LLE, "my_page_applet_mode",
Category::LibraryApplet};
// Audio // Audio
SwitchableSetting<AudioEngine> sink_id{linkage, AudioEngine::Auto, "output_engine", SwitchableSetting<AudioEngine> sink_id{linkage, AudioEngine::Auto, "output_engine",
Category::Audio, Specialization::RuntimeList}; Category::Audio, Specialization::RuntimeList};

View File

@ -44,7 +44,6 @@ enum class Category : u32 {
Services, Services,
Paths, Paths,
Linux, Linux,
LibraryApplet,
MaxEnum, MaxEnum,
}; };

View File

@ -151,8 +151,6 @@ ENUM(AspectRatio, R16_9, R4_3, R21_9, R16_10, Stretch);
ENUM(ConsoleMode, Handheld, Docked); ENUM(ConsoleMode, Handheld, Docked);
ENUM(AppletMode, HLE, LLE);
template <typename Type> template <typename Type>
inline std::string CanonicalizeEnum(Type id) { inline std::string CanonicalizeEnum(Type id) {
const auto group = EnumMetadata<Type>::Canonicalizations(); const auto group = EnumMetadata<Type>::Canonicalizations();

View File

@ -186,68 +186,68 @@ static_assert(std::is_trivially_destructible_v<PhysicalAddress>);
static_assert(std::is_trivially_destructible_v<VirtualAddress>); static_assert(std::is_trivially_destructible_v<VirtualAddress>);
static_assert(std::is_trivially_destructible_v<ProcessAddress>); static_assert(std::is_trivially_destructible_v<ProcessAddress>);
static_assert(Null<uint64_t> == 0U); static_assert(Null<uint64_t> == 0);
static_assert(Null<PhysicalAddress> == Null<uint64_t>); static_assert(Null<PhysicalAddress> == Null<uint64_t>);
static_assert(Null<VirtualAddress> == Null<uint64_t>); static_assert(Null<VirtualAddress> == Null<uint64_t>);
static_assert(Null<ProcessAddress> == Null<uint64_t>); static_assert(Null<ProcessAddress> == Null<uint64_t>);
// Constructor/assignment validations. // Constructor/assignment validations.
static_assert([] { static_assert([] {
const PhysicalAddress a(5U); const PhysicalAddress a(5);
PhysicalAddress b(a); PhysicalAddress b(a);
return b; return b;
}() == PhysicalAddress(5U)); }() == PhysicalAddress(5));
static_assert([] { static_assert([] {
const PhysicalAddress a(5U); const PhysicalAddress a(5);
PhysicalAddress b(10U); PhysicalAddress b(10);
b = a; b = a;
return b; return b;
}() == PhysicalAddress(5U)); }() == PhysicalAddress(5));
// Arithmetic validations. // Arithmetic validations.
static_assert(PhysicalAddress(10U) + 5U == PhysicalAddress(15U)); static_assert(PhysicalAddress(10) + 5 == PhysicalAddress(15));
static_assert(PhysicalAddress(10U) - 5U == PhysicalAddress(5U)); static_assert(PhysicalAddress(10) - 5 == PhysicalAddress(5));
static_assert([] { static_assert([] {
PhysicalAddress v(10U); PhysicalAddress v(10);
v += 5U; v += 5;
return v; return v;
}() == PhysicalAddress(15U)); }() == PhysicalAddress(15));
static_assert([] { static_assert([] {
PhysicalAddress v(10U); PhysicalAddress v(10);
v -= 5U; v -= 5;
return v; return v;
}() == PhysicalAddress(5U)); }() == PhysicalAddress(5));
static_assert(PhysicalAddress(10U)++ == PhysicalAddress(10U)); static_assert(PhysicalAddress(10)++ == PhysicalAddress(10));
static_assert(++PhysicalAddress(10U) == PhysicalAddress(11U)); static_assert(++PhysicalAddress(10) == PhysicalAddress(11));
static_assert(PhysicalAddress(10U)-- == PhysicalAddress(10U)); static_assert(PhysicalAddress(10)-- == PhysicalAddress(10));
static_assert(--PhysicalAddress(10U) == PhysicalAddress(9U)); static_assert(--PhysicalAddress(10) == PhysicalAddress(9));
// Logical validations. // Logical validations.
static_assert((PhysicalAddress(0b11111111U) >> 1) == 0b01111111U); static_assert((PhysicalAddress(0b11111111) >> 1) == 0b01111111);
static_assert((PhysicalAddress(0b10101010U) >> 1) == 0b01010101U); static_assert((PhysicalAddress(0b10101010) >> 1) == 0b01010101);
static_assert((PhysicalAddress(0b11111111U) << 1) == 0b111111110U); static_assert((PhysicalAddress(0b11111111) << 1) == 0b111111110);
static_assert((PhysicalAddress(0b01010101U) << 1) == 0b10101010U); static_assert((PhysicalAddress(0b01010101) << 1) == 0b10101010);
static_assert((PhysicalAddress(0b11111111U) & 0b01010101U) == 0b01010101U); static_assert((PhysicalAddress(0b11111111) & 0b01010101) == 0b01010101);
static_assert((PhysicalAddress(0b11111111U) & 0b10101010U) == 0b10101010U); static_assert((PhysicalAddress(0b11111111) & 0b10101010) == 0b10101010);
static_assert((PhysicalAddress(0b01010101U) & 0b10101010U) == 0b00000000U); static_assert((PhysicalAddress(0b01010101) & 0b10101010) == 0b00000000);
static_assert((PhysicalAddress(0b00000000U) | 0b01010101U) == 0b01010101U); static_assert((PhysicalAddress(0b00000000) | 0b01010101) == 0b01010101);
static_assert((PhysicalAddress(0b11111111U) | 0b01010101U) == 0b11111111U); static_assert((PhysicalAddress(0b11111111) | 0b01010101) == 0b11111111);
static_assert((PhysicalAddress(0b10101010U) | 0b01010101U) == 0b11111111U); static_assert((PhysicalAddress(0b10101010) | 0b01010101) == 0b11111111);
// Comparisons. // Comparisons.
static_assert(PhysicalAddress(0U) == PhysicalAddress(0U)); static_assert(PhysicalAddress(0) == PhysicalAddress(0));
static_assert(PhysicalAddress(0U) != PhysicalAddress(1U)); static_assert(PhysicalAddress(0) != PhysicalAddress(1));
static_assert(PhysicalAddress(0U) < PhysicalAddress(1U)); static_assert(PhysicalAddress(0) < PhysicalAddress(1));
static_assert(PhysicalAddress(0U) <= PhysicalAddress(1U)); static_assert(PhysicalAddress(0) <= PhysicalAddress(1));
static_assert(PhysicalAddress(1U) > PhysicalAddress(0U)); static_assert(PhysicalAddress(1) > PhysicalAddress(0));
static_assert(PhysicalAddress(1U) >= PhysicalAddress(0U)); static_assert(PhysicalAddress(1) >= PhysicalAddress(0));
static_assert(!(PhysicalAddress(0U) == PhysicalAddress(1U))); static_assert(!(PhysicalAddress(0) == PhysicalAddress(1)));
static_assert(!(PhysicalAddress(0U) != PhysicalAddress(0U))); static_assert(!(PhysicalAddress(0) != PhysicalAddress(0)));
static_assert(!(PhysicalAddress(1U) < PhysicalAddress(0U))); static_assert(!(PhysicalAddress(1) < PhysicalAddress(0)));
static_assert(!(PhysicalAddress(1U) <= PhysicalAddress(0U))); static_assert(!(PhysicalAddress(1) <= PhysicalAddress(0)));
static_assert(!(PhysicalAddress(0U) > PhysicalAddress(1U))); static_assert(!(PhysicalAddress(0) > PhysicalAddress(1)));
static_assert(!(PhysicalAddress(0U) >= PhysicalAddress(1U))); static_assert(!(PhysicalAddress(0) >= PhysicalAddress(1)));
} // namespace Common } // namespace Common

View File

@ -383,7 +383,7 @@ std::string GDBStubA32::RegRead(const Kernel::KThread* thread, size_t id) const
} else if (id == CPSR_REGISTER) { } else if (id == CPSR_REGISTER) {
return ValueToHex(context.pstate); return ValueToHex(context.pstate);
} else if (id >= D0_REGISTER && id < Q0_REGISTER) { } else if (id >= D0_REGISTER && id < Q0_REGISTER) {
return ValueToHex(fprs[(id - D0_REGISTER) / 2][(id - D0_REGISTER) % 2]); return ValueToHex(fprs[id - D0_REGISTER][0]);
} else if (id >= Q0_REGISTER && id < FPSCR_REGISTER) { } else if (id >= Q0_REGISTER && id < FPSCR_REGISTER) {
return ValueToHex(fprs[id - Q0_REGISTER]); return ValueToHex(fprs[id - Q0_REGISTER]);
} else if (id == FPSCR_REGISTER) { } else if (id == FPSCR_REGISTER) {
@ -406,7 +406,7 @@ void GDBStubA32::RegWrite(Kernel::KThread* thread, size_t id, std::string_view v
} else if (id == CPSR_REGISTER) { } else if (id == CPSR_REGISTER) {
context.pstate = HexToValue<u32>(value); context.pstate = HexToValue<u32>(value);
} else if (id >= D0_REGISTER && id < Q0_REGISTER) { } else if (id >= D0_REGISTER && id < Q0_REGISTER) {
fprs[(id - D0_REGISTER) / 2][(id - D0_REGISTER) % 2] = HexToValue<u64>(value); fprs[id - D0_REGISTER] = {HexToValue<u64>(value), 0};
} else if (id >= Q0_REGISTER && id < FPSCR_REGISTER) { } else if (id >= Q0_REGISTER && id < FPSCR_REGISTER) {
fprs[id - Q0_REGISTER] = HexToValue<u128>(value); fprs[id - Q0_REGISTER] = HexToValue<u128>(value);
} else if (id == FPSCR_REGISTER) { } else if (id == FPSCR_REGISTER) {

View File

@ -43,8 +43,6 @@ public:
DeviceMemoryManager(const DeviceMemory& device_memory); DeviceMemoryManager(const DeviceMemory& device_memory);
~DeviceMemoryManager(); ~DeviceMemoryManager();
static constexpr bool HAS_FLUSH_INVALIDATION = true;
void BindInterface(DeviceInterface* device_inter); void BindInterface(DeviceInterface* device_inter);
DAddr Allocate(size_t size); DAddr Allocate(size_t size);

View File

@ -532,7 +532,6 @@ void DeviceMemoryManager<Traits>::UpdatePagesCachedCount(DAddr addr, size_t size
cache_bytes = 0; cache_bytes = 0;
} }
}; };
size_t old_vpage = (base_vaddress >> Memory::YUZU_PAGEBITS) - 1;
for (; page != page_end; ++page) { for (; page != page_end; ++page) {
CounterAtomicType& count = cached_pages->at(page >> subentries_shift).Count(page); CounterAtomicType& count = cached_pages->at(page >> subentries_shift).Count(page);
auto [asid_2, vpage] = ExtractCPUBacking(page); auto [asid_2, vpage] = ExtractCPUBacking(page);
@ -548,12 +547,6 @@ void DeviceMemoryManager<Traits>::UpdatePagesCachedCount(DAddr addr, size_t size
memory_device_inter = registered_processes[asid_2.id]; memory_device_inter = registered_processes[asid_2.id];
} }
if (vpage != old_vpage + 1) [[unlikely]] {
release_pending();
}
old_vpage = vpage;
// Adds or subtracts 1, as count is a unsigned 8-bit value // Adds or subtracts 1, as count is a unsigned 8-bit value
count.fetch_add(static_cast<CounterType>(delta), std::memory_order_release); count.fetch_add(static_cast<CounterType>(delta), std::memory_order_release);

View File

@ -44,32 +44,15 @@ public:
GuestMemory() = delete; GuestMemory() = delete;
explicit GuestMemory(M& memory, u64 addr, std::size_t size, explicit GuestMemory(M& memory, u64 addr, std::size_t size,
Common::ScratchBuffer<T>* backup = nullptr) Common::ScratchBuffer<T>* backup = nullptr)
: m_memory{&memory}, m_addr{addr}, m_size{size} { : m_memory{memory}, m_addr{addr}, m_size{size} {
static_assert(FLAGS & GuestMemoryFlags::Read || FLAGS & GuestMemoryFlags::Write); static_assert(FLAGS & GuestMemoryFlags::Read || FLAGS & GuestMemoryFlags::Write);
if constexpr (!(FLAGS & GuestMemoryFlags::Read)) { if constexpr (FLAGS & GuestMemoryFlags::Read) {
if (!this->TrySetSpan()) {
if (backup) {
backup->resize_destructive(this->size());
m_data_span = *backup;
m_span_valid = true;
m_is_data_copy = true;
} else {
m_data_copy.resize(this->size());
m_data_span = std::span(m_data_copy);
m_span_valid = true;
m_is_data_copy = true;
}
}
} else if constexpr (FLAGS & GuestMemoryFlags::Read) {
Read(addr, size, backup); Read(addr, size, backup);
} }
} }
~GuestMemory() = default; ~GuestMemory() = default;
GuestMemory(GuestMemory&& rhs) = default;
GuestMemory& operator=(GuestMemory&& rhs) = default;
T* data() noexcept { T* data() noexcept {
return m_data_span.data(); return m_data_span.data();
} }
@ -126,8 +109,8 @@ public:
} }
if (this->TrySetSpan()) { if (this->TrySetSpan()) {
if constexpr (FLAGS & GuestMemoryFlags::Safe && M::HAS_FLUSH_INVALIDATION) { if constexpr (FLAGS & GuestMemoryFlags::Safe) {
m_memory->FlushRegion(m_addr, this->size_bytes()); m_memory.FlushRegion(m_addr, this->size_bytes());
} }
} else { } else {
if (backup) { if (backup) {
@ -140,9 +123,9 @@ public:
m_is_data_copy = true; m_is_data_copy = true;
m_span_valid = true; m_span_valid = true;
if constexpr (FLAGS & GuestMemoryFlags::Safe) { if constexpr (FLAGS & GuestMemoryFlags::Safe) {
m_memory->ReadBlock(m_addr, this->data(), this->size_bytes()); m_memory.ReadBlock(m_addr, this->data(), this->size_bytes());
} else { } else {
m_memory->ReadBlockUnsafe(m_addr, this->data(), this->size_bytes()); m_memory.ReadBlockUnsafe(m_addr, this->data(), this->size_bytes());
} }
} }
return m_data_span; return m_data_span;
@ -150,19 +133,18 @@ public:
void Write(std::span<T> write_data) noexcept { void Write(std::span<T> write_data) noexcept {
if constexpr (FLAGS & GuestMemoryFlags::Cached) { if constexpr (FLAGS & GuestMemoryFlags::Cached) {
m_memory->WriteBlockCached(m_addr, write_data.data(), this->size_bytes()); m_memory.WriteBlockCached(m_addr, write_data.data(), this->size_bytes());
} else if constexpr (FLAGS & GuestMemoryFlags::Safe) { } else if constexpr (FLAGS & GuestMemoryFlags::Safe) {
m_memory->WriteBlock(m_addr, write_data.data(), this->size_bytes()); m_memory.WriteBlock(m_addr, write_data.data(), this->size_bytes());
} else { } else {
m_memory->WriteBlockUnsafe(m_addr, write_data.data(), this->size_bytes()); m_memory.WriteBlockUnsafe(m_addr, write_data.data(), this->size_bytes());
} }
} }
bool TrySetSpan() noexcept { bool TrySetSpan() noexcept {
if (u8* ptr = m_memory->GetSpan(m_addr, this->size_bytes()); ptr) { if (u8* ptr = m_memory.GetSpan(m_addr, this->size_bytes()); ptr) {
m_data_span = {reinterpret_cast<T*>(ptr), this->size()}; m_data_span = {reinterpret_cast<T*>(ptr), this->size()};
m_span_valid = true; m_span_valid = true;
m_is_data_copy = false;
return true; return true;
} }
return false; return false;
@ -177,7 +159,7 @@ protected:
return m_addr_changed; return m_addr_changed;
} }
M* m_memory; M& m_memory;
u64 m_addr{}; u64 m_addr{};
size_t m_size{}; size_t m_size{};
std::span<T> m_data_span{}; std::span<T> m_data_span{};
@ -193,7 +175,17 @@ public:
GuestMemoryScoped() = delete; GuestMemoryScoped() = delete;
explicit GuestMemoryScoped(M& memory, u64 addr, std::size_t size, explicit GuestMemoryScoped(M& memory, u64 addr, std::size_t size,
Common::ScratchBuffer<T>* backup = nullptr) Common::ScratchBuffer<T>* backup = nullptr)
: GuestMemory<M, T, FLAGS>(memory, addr, size, backup) {} : GuestMemory<M, T, FLAGS>(memory, addr, size, backup) {
if constexpr (!(FLAGS & GuestMemoryFlags::Read)) {
if (!this->TrySetSpan()) {
if (backup) {
this->m_data_span = *backup;
this->m_span_valid = true;
this->m_is_data_copy = true;
}
}
}
}
~GuestMemoryScoped() { ~GuestMemoryScoped() {
if constexpr (FLAGS & GuestMemoryFlags::Write) { if constexpr (FLAGS & GuestMemoryFlags::Write) {
@ -204,17 +196,15 @@ public:
if (this->AddressChanged() || this->IsDataCopy()) { if (this->AddressChanged() || this->IsDataCopy()) {
ASSERT(this->m_span_valid); ASSERT(this->m_span_valid);
if constexpr (FLAGS & GuestMemoryFlags::Cached) { if constexpr (FLAGS & GuestMemoryFlags::Cached) {
this->m_memory->WriteBlockCached(this->m_addr, this->data(), this->m_memory.WriteBlockCached(this->m_addr, this->data(), this->size_bytes());
this->size_bytes());
} else if constexpr (FLAGS & GuestMemoryFlags::Safe) { } else if constexpr (FLAGS & GuestMemoryFlags::Safe) {
this->m_memory->WriteBlock(this->m_addr, this->data(), this->size_bytes()); this->m_memory.WriteBlock(this->m_addr, this->data(), this->size_bytes());
} else { } else {
this->m_memory->WriteBlockUnsafe(this->m_addr, this->data(), this->m_memory.WriteBlockUnsafe(this->m_addr, this->data(), this->size_bytes());
this->size_bytes());
} }
} else if constexpr ((FLAGS & GuestMemoryFlags::Safe) || } else if constexpr ((FLAGS & GuestMemoryFlags::Safe) ||
(FLAGS & GuestMemoryFlags::Cached)) { (FLAGS & GuestMemoryFlags::Cached)) {
this->m_memory->InvalidateRegion(this->m_addr, this->size_bytes()); this->m_memory.InvalidateRegion(this->m_addr, this->size_bytes());
} }
} }
} }

View File

@ -4,9 +4,8 @@
#include <random> #include <random>
#include "common/scope_exit.h" #include "common/scope_exit.h"
#include "common/settings.h" #include "common/settings.h"
#include "core/arm/dynarmic/arm_dynarmic.h"
#include "core/arm/dynarmic/dynarmic_exclusive_monitor.h"
#include "core/core.h" #include "core/core.h"
#include "core/gpu_dirty_memory_manager.h"
#include "core/hle/kernel/k_process.h" #include "core/hle/kernel/k_process.h"
#include "core/hle/kernel/k_scoped_resource_reservation.h" #include "core/hle/kernel/k_scoped_resource_reservation.h"
#include "core/hle/kernel/k_shared_memory.h" #include "core/hle/kernel/k_shared_memory.h"
@ -1259,10 +1258,6 @@ void KProcess::InitializeInterfaces() {
#ifdef HAS_NCE #ifdef HAS_NCE
if (this->IsApplication() && Settings::IsNceEnabled()) { if (this->IsApplication() && Settings::IsNceEnabled()) {
// Register the scoped JIT handler before creating any NCE instances
// so that its signal handler will appear first in the signal chain.
Core::ScopedJitExecution::RegisterHandler();
for (size_t i = 0; i < Core::Hardware::NUM_CPU_CORES; i++) { for (size_t i = 0; i < Core::Hardware::NUM_CPU_CORES; i++) {
m_arm_interfaces[i] = std::make_unique<Core::ArmNce>(m_kernel.System(), true, i); m_arm_interfaces[i] = std::make_unique<Core::ArmNce>(m_kernel.System(), true, i);
} }

View File

@ -130,9 +130,9 @@ enum class AppletProgramId : u64 {
enum class LibraryAppletMode : u32 { enum class LibraryAppletMode : u32 {
AllForeground = 0, AllForeground = 0,
PartialForeground = 1, Background = 1,
NoUi = 2, NoUI = 2,
PartialForegroundIndirectDisplay = 3, BackgroundIndirectDisplay = 3,
AllForegroundInitiallyHidden = 4, AllForegroundInitiallyHidden = 4,
}; };

View File

@ -68,9 +68,9 @@ void SoftwareKeyboard::Initialize() {
case LibraryAppletMode::AllForeground: case LibraryAppletMode::AllForeground:
InitializeForeground(); InitializeForeground();
break; break;
case LibraryAppletMode::PartialForeground: case LibraryAppletMode::Background:
case LibraryAppletMode::PartialForegroundIndirectDisplay: case LibraryAppletMode::BackgroundIndirectDisplay:
InitializePartialForeground(applet_mode); InitializeBackground(applet_mode);
break; break;
default: default:
ASSERT_MSG(false, "Invalid LibraryAppletMode={}", applet_mode); ASSERT_MSG(false, "Invalid LibraryAppletMode={}", applet_mode);
@ -243,7 +243,7 @@ void SoftwareKeyboard::InitializeForeground() {
InitializeFrontendNormalKeyboard(); InitializeFrontendNormalKeyboard();
} }
void SoftwareKeyboard::InitializePartialForeground(LibraryAppletMode library_applet_mode) { void SoftwareKeyboard::InitializeBackground(LibraryAppletMode library_applet_mode) {
LOG_INFO(Service_AM, "Initializing Inline Software Keyboard Applet."); LOG_INFO(Service_AM, "Initializing Inline Software Keyboard Applet.");
is_background = true; is_background = true;
@ -258,9 +258,9 @@ void SoftwareKeyboard::InitializePartialForeground(LibraryAppletMode library_app
swkbd_inline_initialize_arg.size()); swkbd_inline_initialize_arg.size());
if (swkbd_initialize_arg.library_applet_mode_flag) { if (swkbd_initialize_arg.library_applet_mode_flag) {
ASSERT(library_applet_mode == LibraryAppletMode::PartialForeground); ASSERT(library_applet_mode == LibraryAppletMode::Background);
} else { } else {
ASSERT(library_applet_mode == LibraryAppletMode::PartialForegroundIndirectDisplay); ASSERT(library_applet_mode == LibraryAppletMode::BackgroundIndirectDisplay);
} }
} }

View File

@ -62,7 +62,7 @@ private:
void InitializeForeground(); void InitializeForeground();
/// Initializes the inline software keyboard. /// Initializes the inline software keyboard.
void InitializePartialForeground(LibraryAppletMode library_applet_mode); void InitializeBackground(LibraryAppletMode library_applet_mode);
/// Processes the text check sent by the application. /// Processes the text check sent by the application.
void ProcessTextCheck(); void ProcessTextCheck();

View File

@ -1,7 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#include "common/settings.h"
#include "core/hle/kernel/k_transfer_memory.h" #include "core/hle/kernel/k_transfer_memory.h"
#include "core/hle/service/am/applet_data_broker.h" #include "core/hle/service/am/applet_data_broker.h"
#include "core/hle/service/am/applet_manager.h" #include "core/hle/service/am/applet_manager.h"
@ -17,34 +16,6 @@ namespace Service::AM {
namespace { namespace {
bool ShouldCreateGuestApplet(AppletId applet_id) {
#define X(Name, name) \
if (applet_id == AppletId::Name && \
Settings::values.name##_applet_mode.GetValue() != Settings::AppletMode::LLE) { \
return false; \
}
X(Cabinet, cabinet)
X(Controller, controller)
X(DataErase, data_erase)
X(Error, error)
X(NetConnect, net_connect)
X(ProfileSelect, player_select)
X(SoftwareKeyboard, swkbd)
X(MiiEdit, mii_edit)
X(Web, web)
X(Shop, shop)
X(PhotoViewer, photo_viewer)
X(OfflineWeb, offline_web)
X(LoginShare, login_share)
X(WebAuth, wifi_web_auth)
X(MyPage, my_page)
#undef X
return true;
}
AppletProgramId AppletIdToProgramId(AppletId applet_id) { AppletProgramId AppletIdToProgramId(AppletId applet_id) {
switch (applet_id) { switch (applet_id) {
case AppletId::OverlayDisplay: case AppletId::OverlayDisplay:
@ -92,10 +63,9 @@ AppletProgramId AppletIdToProgramId(AppletId applet_id) {
} }
} }
std::shared_ptr<ILibraryAppletAccessor> CreateGuestApplet(Core::System& system, [[maybe_unused]] std::shared_ptr<ILibraryAppletAccessor> CreateGuestApplet(
std::shared_ptr<Applet> caller_applet, Core::System& system, std::shared_ptr<Applet> caller_applet, AppletId applet_id,
AppletId applet_id, LibraryAppletMode mode) {
LibraryAppletMode mode) {
const auto program_id = static_cast<u64>(AppletIdToProgramId(applet_id)); const auto program_id = static_cast<u64>(AppletIdToProgramId(applet_id));
if (program_id == 0) { if (program_id == 0) {
// Unknown applet // Unknown applet
@ -117,18 +87,24 @@ std::shared_ptr<ILibraryAppletAccessor> CreateGuestApplet(Core::System& system,
// Set focus state // Set focus state
switch (mode) { switch (mode) {
case LibraryAppletMode::AllForeground: case LibraryAppletMode::AllForeground:
case LibraryAppletMode::NoUi: case LibraryAppletMode::NoUI:
case LibraryAppletMode::PartialForeground:
case LibraryAppletMode::PartialForegroundIndirectDisplay:
applet->hid_registration.EnableAppletToGetInput(true);
applet->focus_state = FocusState::InFocus; applet->focus_state = FocusState::InFocus;
applet->hid_registration.EnableAppletToGetInput(true);
applet->message_queue.PushMessage(AppletMessageQueue::AppletMessage::ChangeIntoForeground); applet->message_queue.PushMessage(AppletMessageQueue::AppletMessage::ChangeIntoForeground);
applet->message_queue.PushMessage(AppletMessageQueue::AppletMessage::FocusStateChanged);
break; break;
case LibraryAppletMode::AllForegroundInitiallyHidden: case LibraryAppletMode::AllForegroundInitiallyHidden:
applet->hid_registration.EnableAppletToGetInput(false);
applet->focus_state = FocusState::NotInFocus;
applet->system_buffer_manager.SetWindowVisibility(false); applet->system_buffer_manager.SetWindowVisibility(false);
applet->message_queue.PushMessage(AppletMessageQueue::AppletMessage::ChangeIntoBackground); applet->focus_state = FocusState::NotInFocus;
applet->hid_registration.EnableAppletToGetInput(false);
applet->message_queue.PushMessage(AppletMessageQueue::AppletMessage::FocusStateChanged);
break;
case LibraryAppletMode::Background:
case LibraryAppletMode::BackgroundIndirectDisplay:
default:
applet->focus_state = FocusState::Background;
applet->hid_registration.EnableAppletToGetInput(true);
applet->message_queue.PushMessage(AppletMessageQueue::AppletMessage::FocusStateChanged);
break; break;
} }
@ -141,10 +117,9 @@ std::shared_ptr<ILibraryAppletAccessor> CreateGuestApplet(Core::System& system,
return std::make_shared<ILibraryAppletAccessor>(system, broker, applet); return std::make_shared<ILibraryAppletAccessor>(system, broker, applet);
} }
std::shared_ptr<ILibraryAppletAccessor> CreateFrontendApplet(Core::System& system, [[maybe_unused]] std::shared_ptr<ILibraryAppletAccessor> CreateFrontendApplet(
std::shared_ptr<Applet> caller_applet, Core::System& system, std::shared_ptr<Applet> caller_applet, AppletId applet_id,
AppletId applet_id, LibraryAppletMode mode) {
LibraryAppletMode mode) {
const auto program_id = static_cast<u64>(AppletIdToProgramId(applet_id)); const auto program_id = static_cast<u64>(AppletIdToProgramId(applet_id));
auto process = std::make_unique<Process>(system); auto process = std::make_unique<Process>(system);
@ -188,13 +163,7 @@ void ILibraryAppletCreator::CreateLibraryApplet(HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "called with applet_id={:08X}, applet_mode={:08X}", applet_id, LOG_DEBUG(Service_AM, "called with applet_id={:08X}, applet_mode={:08X}", applet_id,
applet_mode); applet_mode);
std::shared_ptr<ILibraryAppletAccessor> library_applet; auto library_applet = CreateFrontendApplet(system, applet, applet_id, applet_mode);
if (ShouldCreateGuestApplet(applet_id)) {
library_applet = CreateGuestApplet(system, applet, applet_id, applet_mode);
}
if (!library_applet) {
library_applet = CreateFrontendApplet(system, applet, applet_id, applet_mode);
}
if (!library_applet) { if (!library_applet) {
LOG_ERROR(Service_AM, "Applet doesn't exist! applet_id={}", applet_id); LOG_ERROR(Service_AM, "Applet doesn't exist! applet_id={}", applet_id);

View File

@ -1,13 +1,10 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#include "common/logging/log.h"
#include "core/hle/result.h"
#include "core/hle/service/am/am_results.h" #include "core/hle/service/am/am_results.h"
#include "core/hle/service/am/frontend/applets.h" #include "core/hle/service/am/frontend/applets.h"
#include "core/hle/service/am/self_controller.h" #include "core/hle/service/am/self_controller.h"
#include "core/hle/service/caps/caps_su.h" #include "core/hle/service/caps/caps_su.h"
#include "core/hle/service/hle_ipc.h"
#include "core/hle/service/ipc_helpers.h" #include "core/hle/service/ipc_helpers.h"
#include "core/hle/service/nvnflinger/fb_share_buffer_manager.h" #include "core/hle/service/nvnflinger/fb_share_buffer_manager.h"
#include "core/hle/service/nvnflinger/nvnflinger.h" #include "core/hle/service/nvnflinger/nvnflinger.h"
@ -50,7 +47,7 @@ ISelfController::ISelfController(Core::System& system_, std::shared_ptr<Applet>
{50, &ISelfController::SetHandlesRequestToDisplay, "SetHandlesRequestToDisplay"}, {50, &ISelfController::SetHandlesRequestToDisplay, "SetHandlesRequestToDisplay"},
{51, &ISelfController::ApproveToDisplay, "ApproveToDisplay"}, {51, &ISelfController::ApproveToDisplay, "ApproveToDisplay"},
{60, nullptr, "OverrideAutoSleepTimeAndDimmingTime"}, {60, nullptr, "OverrideAutoSleepTimeAndDimmingTime"},
{61, &ISelfController::SetMediaPlaybackState, "SetMediaPlaybackState"}, {61, nullptr, "SetMediaPlaybackState"},
{62, &ISelfController::SetIdleTimeDetectionExtension, "SetIdleTimeDetectionExtension"}, {62, &ISelfController::SetIdleTimeDetectionExtension, "SetIdleTimeDetectionExtension"},
{63, &ISelfController::GetIdleTimeDetectionExtension, "GetIdleTimeDetectionExtension"}, {63, &ISelfController::GetIdleTimeDetectionExtension, "GetIdleTimeDetectionExtension"},
{64, nullptr, "SetInputDetectionSourceSet"}, {64, nullptr, "SetInputDetectionSourceSet"},
@ -291,8 +288,7 @@ void ISelfController::GetSystemSharedBufferHandle(HLERequestContext& ctx) {
} }
Result ISelfController::EnsureBufferSharingEnabled(Kernel::KProcess* process) { Result ISelfController::EnsureBufferSharingEnabled(Kernel::KProcess* process) {
if (applet->system_buffer_manager.Initialize(&nvnflinger, process, applet->applet_id, if (applet->system_buffer_manager.Initialize(&nvnflinger, process, applet->applet_id)) {
applet->library_applet_mode)) {
return ResultSuccess; return ResultSuccess;
} }
@ -327,16 +323,6 @@ void ISelfController::ApproveToDisplay(HLERequestContext& ctx) {
rb.Push(ResultSuccess); rb.Push(ResultSuccess);
} }
void ISelfController::SetMediaPlaybackState(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const u8 state = rp.Pop<u8>();
LOG_WARNING(Service_AM, "(STUBBED) called, state={}", state);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
void ISelfController::SetIdleTimeDetectionExtension(HLERequestContext& ctx) { void ISelfController::SetIdleTimeDetectionExtension(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx}; IPC::RequestParser rp{ctx};

View File

@ -3,7 +3,6 @@
#pragma once #pragma once
#include "core/hle/service/hle_ipc.h"
#include "core/hle/service/kernel_helpers.h" #include "core/hle/service/kernel_helpers.h"
#include "core/hle/service/service.h" #include "core/hle/service/service.h"
@ -39,7 +38,6 @@ private:
void CreateManagedDisplaySeparableLayer(HLERequestContext& ctx); void CreateManagedDisplaySeparableLayer(HLERequestContext& ctx);
void SetHandlesRequestToDisplay(HLERequestContext& ctx); void SetHandlesRequestToDisplay(HLERequestContext& ctx);
void ApproveToDisplay(HLERequestContext& ctx); void ApproveToDisplay(HLERequestContext& ctx);
void SetMediaPlaybackState(HLERequestContext& ctx);
void SetIdleTimeDetectionExtension(HLERequestContext& ctx); void SetIdleTimeDetectionExtension(HLERequestContext& ctx);
void GetIdleTimeDetectionExtension(HLERequestContext& ctx); void GetIdleTimeDetectionExtension(HLERequestContext& ctx);
void ReportUserIsActive(HLERequestContext& ctx); void ReportUserIsActive(HLERequestContext& ctx);

View File

@ -17,12 +17,11 @@ SystemBufferManager::~SystemBufferManager() {
// Clean up shared layers. // Clean up shared layers.
if (m_buffer_sharing_enabled) { if (m_buffer_sharing_enabled) {
m_nvnflinger->GetSystemBufferManager().Finalize(m_process);
} }
} }
bool SystemBufferManager::Initialize(Nvnflinger::Nvnflinger* nvnflinger, Kernel::KProcess* process, bool SystemBufferManager::Initialize(Nvnflinger::Nvnflinger* nvnflinger, Kernel::KProcess* process,
AppletId applet_id, LibraryAppletMode mode) { AppletId applet_id) {
if (m_nvnflinger) { if (m_nvnflinger) {
return m_buffer_sharing_enabled; return m_buffer_sharing_enabled;
} }
@ -37,15 +36,9 @@ bool SystemBufferManager::Initialize(Nvnflinger::Nvnflinger* nvnflinger, Kernel:
return false; return false;
} }
Nvnflinger::LayerBlending blending = Nvnflinger::LayerBlending::None;
if (mode == LibraryAppletMode::PartialForeground ||
mode == LibraryAppletMode::PartialForegroundIndirectDisplay) {
blending = Nvnflinger::LayerBlending::Coverage;
}
const auto display_id = m_nvnflinger->OpenDisplay("Default").value(); const auto display_id = m_nvnflinger->OpenDisplay("Default").value();
const auto res = m_nvnflinger->GetSystemBufferManager().Initialize( const auto res = m_nvnflinger->GetSystemBufferManager().Initialize(
m_process, &m_system_shared_buffer_id, &m_system_shared_layer_id, display_id, blending); &m_system_shared_buffer_id, &m_system_shared_layer_id, display_id);
if (res.IsSuccess()) { if (res.IsSuccess()) {
m_buffer_sharing_enabled = true; m_buffer_sharing_enabled = true;
@ -69,12 +62,8 @@ void SystemBufferManager::SetWindowVisibility(bool visible) {
Result SystemBufferManager::WriteAppletCaptureBuffer(bool* out_was_written, Result SystemBufferManager::WriteAppletCaptureBuffer(bool* out_was_written,
s32* out_fbshare_layer_index) { s32* out_fbshare_layer_index) {
if (!m_buffer_sharing_enabled) { // TODO
return VI::ResultPermissionDenied; R_SUCCEED();
}
return m_nvnflinger->GetSystemBufferManager().WriteAppletCaptureBuffer(out_was_written,
out_fbshare_layer_index);
} }
} // namespace Service::AM } // namespace Service::AM

View File

@ -27,8 +27,7 @@ public:
SystemBufferManager(); SystemBufferManager();
~SystemBufferManager(); ~SystemBufferManager();
bool Initialize(Nvnflinger::Nvnflinger* flinger, Kernel::KProcess* process, AppletId applet_id, bool Initialize(Nvnflinger::Nvnflinger* flinger, Kernel::KProcess* process, AppletId applet_id);
LibraryAppletMode mode);
void GetSystemSharedLayerHandle(u64* out_system_shared_buffer_id, void GetSystemSharedLayerHandle(u64* out_system_shared_buffer_id,
u64* out_system_shared_layer_id) { u64* out_system_shared_layer_id) {

View File

@ -62,12 +62,12 @@ void IWindowController::SetAppletWindowVisibility(HLERequestContext& ctx) {
applet->hid_registration.EnableAppletToGetInput(visible); applet->hid_registration.EnableAppletToGetInput(visible);
if (visible) { if (visible) {
applet->focus_state = FocusState::InFocus;
applet->message_queue.PushMessage(AppletMessageQueue::AppletMessage::ChangeIntoForeground); applet->message_queue.PushMessage(AppletMessageQueue::AppletMessage::ChangeIntoForeground);
applet->focus_state = FocusState::InFocus;
} else { } else {
applet->focus_state = FocusState::NotInFocus; applet->focus_state = FocusState::NotInFocus;
applet->message_queue.PushMessage(AppletMessageQueue::AppletMessage::ChangeIntoBackground);
} }
applet->message_queue.PushMessage(AppletMessageQueue::AppletMessage::FocusStateChanged);
IPC::ResponseBuilder rb{ctx, 2}; IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess); rb.Push(ResultSuccess);

View File

@ -115,11 +115,6 @@ struct ArgumentTraits {
static constexpr ArgumentType Type = ArgumentType::InData; static constexpr ArgumentType Type = ArgumentType::InData;
}; };
template <typename... Ts>
consteval bool ConstIfReference() {
return ((!std::is_reference_v<Ts> || std::is_const_v<std::remove_reference_t<Ts>>) && ... && true);
}
struct RequestLayout { struct RequestLayout {
u32 copy_handle_count; u32 copy_handle_count;
u32 move_handle_count; u32 move_handle_count;
@ -280,7 +275,7 @@ void ReadInArgument(bool is_domain, CallArguments& args, const u8* raw_data, HLE
u32 value{}; u32 value{};
std::memcpy(&value, raw_data + ArgOffset, ArgSize); std::memcpy(&value, raw_data + ArgOffset, ArgSize);
std::get<ArgIndex>(args) = ctx.GetDomainHandler<typename ArgType::element_type>(value - 1); std::get<ArgIndex>(args) = ctx.GetDomainHandler<ArgType::Type>(value - 1);
return ReadInArgument<MethodArguments, CallArguments, ArgAlign, ArgEnd, HandleIndex, InBufferIndex, OutBufferIndex, true, ArgIndex + 1>(is_domain, args, raw_data, ctx, temp); return ReadInArgument<MethodArguments, CallArguments, ArgAlign, ArgEnd, HandleIndex, InBufferIndex, OutBufferIndex, true, ArgIndex + 1>(is_domain, args, raw_data, ctx, temp);
} else if constexpr (ArgumentTraits<ArgType>::Type == ArgumentType::InCopyHandle) { } else if constexpr (ArgumentTraits<ArgType>::Type == ArgumentType::InCopyHandle) {
@ -440,7 +435,6 @@ void CmifReplyWrapImpl(HLERequestContext& ctx, T& t, Result (T::*f)(A...)) {
} }
const bool is_domain = Domain ? ctx.GetManager()->IsDomain() : false; const bool is_domain = Domain ? ctx.GetManager()->IsDomain() : false;
static_assert(ConstIfReference<A...>(), "Arguments taken by reference must be const");
using MethodArguments = std::tuple<std::remove_cvref_t<A>...>; using MethodArguments = std::tuple<std::remove_cvref_t<A>...>;
OutTemporaryBuffers buffers{}; OutTemporaryBuffers buffers{};

View File

@ -4,9 +4,10 @@
#pragma once #pragma once
#include <memory> #include <memory>
#include <span>
#include "common/common_funcs.h"
#include "common/common_types.h" #include "common/common_types.h"
#include "core/hle/service/hle_ipc.h"
namespace Service { namespace Service {
@ -21,10 +22,8 @@ class Out {
public: public:
using Type = T; using Type = T;
/* implicit */ Out(const Out& t) : raw(t.raw) {}
/* implicit */ Out(AutoOut<Type>& t) : raw(&t.raw) {} /* implicit */ Out(AutoOut<Type>& t) : raw(&t.raw) {}
/* implicit */ Out(Type* t) : raw(t) {} /* implicit */ Out(Type* t) : raw(t) {}
Out& operator=(const Out&) = delete;
Type* Get() const { Type* Get() const {
return raw; return raw;
@ -38,10 +37,6 @@ public:
return raw; return raw;
} }
operator Type*() const {
return raw;
}
private: private:
Type* raw; Type* raw;
}; };
@ -65,14 +60,6 @@ struct ClientProcessId {
}; };
struct ProcessId { struct ProcessId {
explicit ProcessId() : pid() {}
explicit ProcessId(u64 p) : pid(p) {}
/* implicit */ ProcessId(const ClientProcessId& c) : pid(c.pid) {}
bool operator==(const ProcessId& rhs) const {
return pid == rhs.pid;
}
explicit operator bool() const { explicit operator bool() const {
return pid != 0; return pid != 0;
} }
@ -126,10 +113,8 @@ class OutCopyHandle {
public: public:
using Type = T*; using Type = T*;
/* implicit */ OutCopyHandle(const OutCopyHandle& t) : raw(t.raw) {}
/* implicit */ OutCopyHandle(AutoOut<Type>& t) : raw(&t.raw) {} /* implicit */ OutCopyHandle(AutoOut<Type>& t) : raw(&t.raw) {}
/* implicit */ OutCopyHandle(Type* t) : raw(t) {} /* implicit */ OutCopyHandle(Type* t) : raw(t) {}
OutCopyHandle& operator=(const OutCopyHandle&) = delete;
Type* Get() const { Type* Get() const {
return raw; return raw;
@ -143,10 +128,6 @@ public:
return raw; return raw;
} }
operator Type*() const {
return raw;
}
private: private:
Type* raw; Type* raw;
}; };
@ -156,10 +137,8 @@ class OutMoveHandle {
public: public:
using Type = T*; using Type = T*;
/* implicit */ OutMoveHandle(const OutMoveHandle& t) : raw(t.raw) {}
/* implicit */ OutMoveHandle(AutoOut<Type>& t) : raw(&t.raw) {} /* implicit */ OutMoveHandle(AutoOut<Type>& t) : raw(&t.raw) {}
/* implicit */ OutMoveHandle(Type* t) : raw(t) {} /* implicit */ OutMoveHandle(Type* t) : raw(t) {}
OutMoveHandle& operator=(const OutMoveHandle&) = delete;
Type* Get() const { Type* Get() const {
return raw; return raw;
@ -173,10 +152,6 @@ public:
return raw; return raw;
} }
operator Type*() const {
return raw;
}
private: private:
Type* raw; Type* raw;
}; };
@ -273,10 +248,8 @@ public:
static constexpr BufferAttr Attr = static_cast<BufferAttr>(A | BufferAttr_In | BufferAttr_FixedSize); static constexpr BufferAttr Attr = static_cast<BufferAttr>(A | BufferAttr_In | BufferAttr_FixedSize);
using Type = T; using Type = T;
/* implicit */ OutLargeData(const OutLargeData& t) : raw(t.raw) {}
/* implicit */ OutLargeData(Type* t) : raw(t) {} /* implicit */ OutLargeData(Type* t) : raw(t) {}
/* implicit */ OutLargeData(AutoOut<T>& t) : raw(&t.raw) {} /* implicit */ OutLargeData(AutoOut<T>& t) : raw(&t.raw) {}
OutLargeData& operator=(const OutLargeData&) = delete;
Type* Get() const { Type* Get() const {
return raw; return raw;
@ -290,13 +263,9 @@ public:
return raw; return raw;
} }
operator Type*() const {
return raw;
}
private: private:
Type* raw; Type* raw;
}; };
// clang-format on // clang-format on
} // namespace Service } // namespace Service

View File

@ -115,11 +115,6 @@ private:
if (type->GetName() == "save") { if (type->GetName() == "save") {
for (const auto& save_id : type->GetSubdirectories()) { for (const auto& save_id : type->GetSubdirectories()) {
for (const auto& user_id : save_id->GetSubdirectories()) { for (const auto& user_id : save_id->GetSubdirectories()) {
// Skip non user id subdirectories
if (user_id->GetName().size() != 0x20) {
continue;
}
const auto save_id_numeric = stoull_be(save_id->GetName()); const auto save_id_numeric = stoull_be(save_id->GetName());
auto user_id_numeric = Common::HexStringToArray<0x10>(user_id->GetName()); auto user_id_numeric = Common::HexStringToArray<0x10>(user_id->GetName());
std::reverse(user_id_numeric.begin(), user_id_numeric.end()); std::reverse(user_id_numeric.begin(), user_id_numeric.end());
@ -165,10 +160,6 @@ private:
} else if (space == FileSys::SaveDataSpaceId::TemporaryStorage) { } else if (space == FileSys::SaveDataSpaceId::TemporaryStorage) {
// Temporary Storage // Temporary Storage
for (const auto& user_id : type->GetSubdirectories()) { for (const auto& user_id : type->GetSubdirectories()) {
// Skip non user id subdirectories
if (user_id->GetName().size() != 0x20) {
continue;
}
for (const auto& title_id : user_id->GetSubdirectories()) { for (const auto& title_id : user_id->GetSubdirectories()) {
if (!title_id->GetFiles().empty() || if (!title_id->GetFiles().empty() ||
!title_id->GetSubdirectories().empty()) { !title_id->GetSubdirectories().empty()) {

View File

@ -65,7 +65,6 @@ Result MountTimeZoneBinary(Core::System& system) {
// Validate that the romfs is readable, using invalid firmware keys can cause this to get // Validate that the romfs is readable, using invalid firmware keys can cause this to get
// set but the files to be garbage. In that case, we want to hit the next path and // set but the files to be garbage. In that case, we want to hit the next path and
// synthesise them instead. // synthesise them instead.
g_time_zone_binary_mount_result = ResultSuccess;
Service::PSC::Time::LocationName name{"Etc/GMT"}; Service::PSC::Time::LocationName name{"Etc/GMT"};
if (!IsTimeZoneBinaryValid(name)) { if (!IsTimeZoneBinaryValid(name)) {
ResetTimeZoneBinary(); ResetTimeZoneBinary();

View File

@ -36,7 +36,7 @@ void LoopProcess(Core::System& system) {
server_manager->RegisterNamedService( server_manager->RegisterNamedService(
"hid:sys", std::make_shared<IHidSystemServer>(system, resource_manager, firmware_settings)); "hid:sys", std::make_shared<IHidSystemServer>(system, resource_manager, firmware_settings));
server_manager->RegisterNamedService("hidbus", std::make_shared<Hidbus>(system)); server_manager->RegisterNamedService("hidbus", std::make_shared<HidBus>(system));
server_manager->RegisterNamedService("irs", std::make_shared<IRS::IRS>(system)); server_manager->RegisterNamedService("irs", std::make_shared<IRS::IRS>(system));
server_manager->RegisterNamedService("irs:sys", std::make_shared<IRS::IRS_SYS>(system)); server_manager->RegisterNamedService("irs:sys", std::make_shared<IRS::IRS_SYS>(system));

View File

@ -3,7 +3,6 @@
#include <algorithm> #include <algorithm>
#include "core/hle/service/cmif_serialization.h"
#include "core/hle/service/hid/hid_debug_server.h" #include "core/hle/service/hid/hid_debug_server.h"
#include "core/hle/service/ipc_helpers.h" #include "core/hle/service/ipc_helpers.h"
#include "hid_core/hid_types.h" #include "hid_core/hid_types.h"
@ -12,6 +11,7 @@
#include "hid_core/resources/touch_screen/gesture.h" #include "hid_core/resources/touch_screen/gesture.h"
#include "hid_core/resources/touch_screen/touch_screen.h" #include "hid_core/resources/touch_screen/touch_screen.h"
#include "hid_core/resources/touch_screen/touch_types.h"
namespace Service::HID { namespace Service::HID {
@ -24,14 +24,14 @@ IHidDebugServer::IHidDebugServer(Core::System& system_, std::shared_ptr<Resource
{0, nullptr, "DeactivateDebugPad"}, {0, nullptr, "DeactivateDebugPad"},
{1, nullptr, "SetDebugPadAutoPilotState"}, {1, nullptr, "SetDebugPadAutoPilotState"},
{2, nullptr, "UnsetDebugPadAutoPilotState"}, {2, nullptr, "UnsetDebugPadAutoPilotState"},
{10, C<&IHidDebugServer::DeactivateTouchScreen>, "DeactivateTouchScreen"}, {10, &IHidDebugServer::DeactivateTouchScreen, "DeactivateTouchScreen"},
{11, C<&IHidDebugServer::SetTouchScreenAutoPilotState>, "SetTouchScreenAutoPilotState"}, {11, &IHidDebugServer::SetTouchScreenAutoPilotState, "SetTouchScreenAutoPilotState"},
{12, C<&IHidDebugServer::UnsetTouchScreenAutoPilotState>, "UnsetTouchScreenAutoPilotState"}, {12, &IHidDebugServer::UnsetTouchScreenAutoPilotState, "UnsetTouchScreenAutoPilotState"},
{13, C<&IHidDebugServer::GetTouchScreenConfiguration>, "GetTouchScreenConfiguration"}, {13, &IHidDebugServer::GetTouchScreenConfiguration, "GetTouchScreenConfiguration"},
{14, C<&IHidDebugServer::ProcessTouchScreenAutoTune>, "ProcessTouchScreenAutoTune"}, {14, &IHidDebugServer::ProcessTouchScreenAutoTune, "ProcessTouchScreenAutoTune"},
{15, C<&IHidDebugServer::ForceStopTouchScreenManagement>, "ForceStopTouchScreenManagement"}, {15, &IHidDebugServer::ForceStopTouchScreenManagement, "ForceStopTouchScreenManagement"},
{16, C<&IHidDebugServer::ForceRestartTouchScreenManagement>, "ForceRestartTouchScreenManagement"}, {16, &IHidDebugServer::ForceRestartTouchScreenManagement, "ForceRestartTouchScreenManagement"},
{17, C<&IHidDebugServer::IsTouchScreenManaged>, "IsTouchScreenManaged"}, {17, &IHidDebugServer::IsTouchScreenManaged, "IsTouchScreenManaged"},
{20, nullptr, "DeactivateMouse"}, {20, nullptr, "DeactivateMouse"},
{21, nullptr, "SetMouseAutoPilotState"}, {21, nullptr, "SetMouseAutoPilotState"},
{22, nullptr, "UnsetMouseAutoPilotState"}, {22, nullptr, "UnsetMouseAutoPilotState"},
@ -47,7 +47,7 @@ IHidDebugServer::IHidDebugServer(Core::System& system_, std::shared_ptr<Resource
{60, nullptr, "ClearNpadSystemCommonPolicy"}, {60, nullptr, "ClearNpadSystemCommonPolicy"},
{61, nullptr, "DeactivateNpad"}, {61, nullptr, "DeactivateNpad"},
{62, nullptr, "ForceDisconnectNpad"}, {62, nullptr, "ForceDisconnectNpad"},
{91, C<&IHidDebugServer::DeactivateGesture>, "DeactivateGesture"}, {91, &IHidDebugServer::DeactivateGesture, "DeactivateGesture"},
{110, nullptr, "DeactivateHomeButton"}, {110, nullptr, "DeactivateHomeButton"},
{111, nullptr, "SetHomeButtonAutoPilotState"}, {111, nullptr, "SetHomeButtonAutoPilotState"},
{112, nullptr, "UnsetHomeButtonAutoPilotState"}, {112, nullptr, "UnsetHomeButtonAutoPilotState"},
@ -160,122 +160,169 @@ IHidDebugServer::IHidDebugServer(Core::System& system_, std::shared_ptr<Resource
} }
IHidDebugServer::~IHidDebugServer() = default; IHidDebugServer::~IHidDebugServer() = default;
void IHidDebugServer::DeactivateTouchScreen(HLERequestContext& ctx) {
Result IHidDebugServer::DeactivateTouchScreen() {
LOG_INFO(Service_HID, "called"); LOG_INFO(Service_HID, "called");
Result result = ResultSuccess;
if (!firmware_settings->IsDeviceManaged()) { if (!firmware_settings->IsDeviceManaged()) {
R_RETURN(GetResourceManager()->GetTouchScreen()->Deactivate()); result = GetResourceManager()->GetTouchScreen()->Deactivate();
} }
R_SUCCEED(); IPC::ResponseBuilder rb{ctx, 2};
rb.Push(result);
} }
Result IHidDebugServer::SetTouchScreenAutoPilotState( void IHidDebugServer::SetTouchScreenAutoPilotState(HLERequestContext& ctx) {
InArray<TouchState, BufferAttr_HipcMapAlias> auto_pilot_buffer) {
AutoPilotState auto_pilot{}; AutoPilotState auto_pilot{};
auto_pilot.count = ctx.GetReadBufferNumElements<TouchState>();
const auto buffer = ctx.ReadBuffer();
auto_pilot.count = auto_pilot.count = std::min(auto_pilot.count, static_cast<u64>(auto_pilot.state.size()));
static_cast<u64>(std::min(auto_pilot_buffer.size(), auto_pilot.state.size())); memcpy(auto_pilot.state.data(), buffer.data(), auto_pilot.count * sizeof(TouchState));
memcpy(auto_pilot.state.data(), auto_pilot_buffer.data(),
auto_pilot.count * sizeof(TouchState));
LOG_INFO(Service_HID, "called, auto_pilot_count={}", auto_pilot.count); LOG_INFO(Service_HID, "called, auto_pilot_count={}", auto_pilot.count);
R_RETURN(GetResourceManager()->GetTouchScreen()->SetTouchScreenAutoPilotState(auto_pilot)); const Result result =
GetResourceManager()->GetTouchScreen()->SetTouchScreenAutoPilotState(auto_pilot);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(result);
} }
Result IHidDebugServer::UnsetTouchScreenAutoPilotState() { void IHidDebugServer::UnsetTouchScreenAutoPilotState(HLERequestContext& ctx) {
LOG_INFO(Service_HID, "called"); LOG_INFO(Service_HID, "called");
R_RETURN(GetResourceManager()->GetTouchScreen()->UnsetTouchScreenAutoPilotState());
const Result result = GetResourceManager()->GetTouchScreen()->UnsetTouchScreenAutoPilotState();
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(result);
} }
Result IHidDebugServer::GetTouchScreenConfiguration( void IHidDebugServer::GetTouchScreenConfiguration(HLERequestContext& ctx) {
Out<Core::HID::TouchScreenConfigurationForNx> out_touchscreen_config, IPC::RequestParser rp{ctx};
ClientAppletResourceUserId aruid) { const auto applet_resource_user_id{rp.Pop<u64>()};
LOG_INFO(Service_HID, "called, applet_resource_user_id={}", aruid.pid);
R_TRY(GetResourceManager()->GetTouchScreen()->GetTouchScreenConfiguration( LOG_INFO(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
*out_touchscreen_config, aruid.pid));
if (out_touchscreen_config->mode != Core::HID::TouchScreenModeForNx::Heat2 && Core::HID::TouchScreenConfigurationForNx touchscreen_config{};
out_touchscreen_config->mode != Core::HID::TouchScreenModeForNx::Finger) { const Result result = GetResourceManager()->GetTouchScreen()->GetTouchScreenConfiguration(
out_touchscreen_config->mode = Core::HID::TouchScreenModeForNx::UseSystemSetting; touchscreen_config, applet_resource_user_id);
if (touchscreen_config.mode != Core::HID::TouchScreenModeForNx::Heat2 &&
touchscreen_config.mode != Core::HID::TouchScreenModeForNx::Finger) {
touchscreen_config.mode = Core::HID::TouchScreenModeForNx::UseSystemSetting;
} }
R_SUCCEED(); IPC::ResponseBuilder rb{ctx, 6};
rb.Push(result);
rb.PushRaw(touchscreen_config);
} }
Result IHidDebugServer::ProcessTouchScreenAutoTune() { void IHidDebugServer::ProcessTouchScreenAutoTune(HLERequestContext& ctx) {
LOG_INFO(Service_HID, "called"); LOG_INFO(Service_HID, "called");
R_RETURN(GetResourceManager()->GetTouchScreen()->ProcessTouchScreenAutoTune());
Result result = GetResourceManager()->GetTouchScreen()->ProcessTouchScreenAutoTune();
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(result);
} }
Result IHidDebugServer::ForceStopTouchScreenManagement() { void IHidDebugServer::ForceStopTouchScreenManagement(HLERequestContext& ctx) {
LOG_INFO(Service_HID, "called"); LOG_INFO(Service_HID, "called");
if (!firmware_settings->IsDeviceManaged()) { if (!firmware_settings->IsDeviceManaged()) {
R_SUCCEED(); IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
return;
} }
Result result = ResultSuccess;
bool is_touch_active{};
bool is_gesture_active{};
auto touch_screen = GetResourceManager()->GetTouchScreen(); auto touch_screen = GetResourceManager()->GetTouchScreen();
auto gesture = GetResourceManager()->GetGesture(); auto gesture = GetResourceManager()->GetGesture();
if (firmware_settings->IsTouchI2cManaged()) { if (firmware_settings->IsTouchI2cManaged()) {
bool is_touch_active{}; result = touch_screen->IsActive(is_touch_active);
bool is_gesture_active{}; if (result.IsSuccess()) {
R_TRY(touch_screen->IsActive(is_touch_active)); result = gesture->IsActive(is_gesture_active);
R_TRY(gesture->IsActive(is_gesture_active));
if (is_touch_active) {
R_TRY(touch_screen->Deactivate());
} }
if (is_gesture_active) { if (result.IsSuccess() && is_touch_active) {
R_TRY(gesture->Deactivate()); result = touch_screen->Deactivate();
}
if (result.IsSuccess() && is_gesture_active) {
result = gesture->Deactivate();
} }
} }
R_SUCCEED(); IPC::ResponseBuilder rb{ctx, 2};
rb.Push(result);
} }
Result IHidDebugServer::ForceRestartTouchScreenManagement(u32 basic_gesture_id, void IHidDebugServer::ForceRestartTouchScreenManagement(HLERequestContext& ctx) {
ClientAppletResourceUserId aruid) { IPC::RequestParser rp{ctx};
LOG_INFO(Service_HID, "called, basic_gesture_id={}, applet_resource_user_id={}", struct Parameters {
basic_gesture_id, aruid.pid); u32 basic_gesture_id;
INSERT_PADDING_WORDS_NOINIT(1);
u64 applet_resource_user_id;
};
static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
const auto parameters{rp.PopRaw<Parameters>()};
LOG_INFO(Service_HID, "called, basic_gesture_id={}, applet_resource_user_id={}",
parameters.basic_gesture_id, parameters.applet_resource_user_id);
Result result = ResultSuccess;
auto touch_screen = GetResourceManager()->GetTouchScreen(); auto touch_screen = GetResourceManager()->GetTouchScreen();
auto gesture = GetResourceManager()->GetGesture(); auto gesture = GetResourceManager()->GetGesture();
if (firmware_settings->IsDeviceManaged() && firmware_settings->IsTouchI2cManaged()) { if (firmware_settings->IsDeviceManaged() && firmware_settings->IsTouchI2cManaged()) {
R_TRY(gesture->Activate()); result = gesture->Activate();
R_TRY(gesture->Activate(aruid.pid, basic_gesture_id)); if (result.IsSuccess()) {
R_TRY(touch_screen->Activate()); result =
R_TRY(touch_screen->Activate(aruid.pid)); gesture->Activate(parameters.applet_resource_user_id, parameters.basic_gesture_id);
}
if (result.IsSuccess()) {
result = touch_screen->Activate();
}
if (result.IsSuccess()) {
result = touch_screen->Activate(parameters.applet_resource_user_id);
}
} }
R_SUCCEED(); IPC::ResponseBuilder rb{ctx, 2};
rb.Push(result);
} }
Result IHidDebugServer::IsTouchScreenManaged(Out<bool> out_is_managed) { void IHidDebugServer::IsTouchScreenManaged(HLERequestContext& ctx) {
LOG_INFO(Service_HID, "called"); LOG_INFO(Service_HID, "called");
bool is_touch_active{}; bool is_touch_active{};
bool is_gesture_active{}; bool is_gesture_active{};
R_TRY(GetResourceManager()->GetTouchScreen()->IsActive(is_touch_active));
R_TRY(GetResourceManager()->GetGesture()->IsActive(is_gesture_active));
*out_is_managed = is_touch_active || is_gesture_active; Result result = GetResourceManager()->GetTouchScreen()->IsActive(is_touch_active);
R_SUCCEED(); if (result.IsSuccess()) {
} result = GetResourceManager()->GetGesture()->IsActive(is_gesture_active);
Result IHidDebugServer::DeactivateGesture() {
LOG_INFO(Service_HID, "called");
if (!firmware_settings->IsDeviceManaged()) {
R_RETURN(GetResourceManager()->GetGesture()->Deactivate());
} }
R_SUCCEED(); IPC::ResponseBuilder rb{ctx, 3};
rb.Push(result);
rb.Push(is_touch_active | is_gesture_active);
}
void IHidDebugServer::DeactivateGesture(HLERequestContext& ctx) {
LOG_INFO(Service_HID, "called");
Result result = ResultSuccess;
if (!firmware_settings->IsDeviceManaged()) {
result = GetResourceManager()->GetGesture()->Deactivate();
}
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(result);
} }
std::shared_ptr<ResourceManager> IHidDebugServer::GetResourceManager() { std::shared_ptr<ResourceManager> IHidDebugServer::GetResourceManager() {

View File

@ -3,9 +3,7 @@
#pragma once #pragma once
#include "core/hle/service/cmif_types.h"
#include "core/hle/service/service.h" #include "core/hle/service/service.h"
#include "hid_core/resources/touch_screen/touch_types.h"
namespace Core { namespace Core {
class System; class System;
@ -22,19 +20,15 @@ public:
~IHidDebugServer() override; ~IHidDebugServer() override;
private: private:
Result DeactivateTouchScreen(); void DeactivateTouchScreen(HLERequestContext& ctx);
Result SetTouchScreenAutoPilotState( void SetTouchScreenAutoPilotState(HLERequestContext& ctx);
InArray<TouchState, BufferAttr_HipcMapAlias> auto_pilot_buffer); void UnsetTouchScreenAutoPilotState(HLERequestContext& ctx);
Result UnsetTouchScreenAutoPilotState(); void GetTouchScreenConfiguration(HLERequestContext& ctx);
Result GetTouchScreenConfiguration( void ProcessTouchScreenAutoTune(HLERequestContext& ctx);
Out<Core::HID::TouchScreenConfigurationForNx> out_touchscreen_config, void ForceStopTouchScreenManagement(HLERequestContext& ctx);
ClientAppletResourceUserId aruid); void ForceRestartTouchScreenManagement(HLERequestContext& ctx);
Result ProcessTouchScreenAutoTune(); void IsTouchScreenManaged(HLERequestContext& ctx);
Result ForceStopTouchScreenManagement(); void DeactivateGesture(HLERequestContext& ctx);
Result ForceRestartTouchScreenManagement(u32 basic_gesture_id,
ClientAppletResourceUserId aruid);
Result IsTouchScreenManaged(Out<bool> out_is_managed);
Result DeactivateGesture();
std::shared_ptr<ResourceManager> GetResourceManager(); std::shared_ptr<ResourceManager> GetResourceManager();

View File

@ -9,7 +9,6 @@
#include "core/hle/kernel/k_readable_event.h" #include "core/hle/kernel/k_readable_event.h"
#include "core/hle/kernel/k_shared_memory.h" #include "core/hle/kernel/k_shared_memory.h"
#include "core/hle/kernel/k_transfer_memory.h" #include "core/hle/kernel/k_transfer_memory.h"
#include "core/hle/service/cmif_serialization.h"
#include "core/hle/service/hid/hidbus.h" #include "core/hle/service/hid/hidbus.h"
#include "core/hle/service/ipc_helpers.h" #include "core/hle/service/ipc_helpers.h"
#include "core/hle/service/service.h" #include "core/hle/service/service.h"
@ -23,25 +22,25 @@ namespace Service::HID {
// (15ms, 66Hz) // (15ms, 66Hz)
constexpr auto hidbus_update_ns = std::chrono::nanoseconds{15 * 1000 * 1000}; constexpr auto hidbus_update_ns = std::chrono::nanoseconds{15 * 1000 * 1000};
Hidbus::Hidbus(Core::System& system_) HidBus::HidBus(Core::System& system_)
: ServiceFramework{system_, "hidbus"}, service_context{system_, service_name} { : ServiceFramework{system_, "hidbus"}, service_context{system_, service_name} {
// clang-format off // clang-format off
static const FunctionInfo functions[] = { static const FunctionInfo functions[] = {
{1, C<&Hidbus::GetBusHandle>, "GetBusHandle"}, {1, &HidBus::GetBusHandle, "GetBusHandle"},
{2, C<&Hidbus::IsExternalDeviceConnected>, "IsExternalDeviceConnected"}, {2, &HidBus::IsExternalDeviceConnected, "IsExternalDeviceConnected"},
{3, C<&Hidbus::Initialize>, "Initialize"}, {3, &HidBus::Initialize, "Initialize"},
{4, C<&Hidbus::Finalize>, "Finalize"}, {4, &HidBus::Finalize, "Finalize"},
{5, C<&Hidbus::EnableExternalDevice>, "EnableExternalDevice"}, {5, &HidBus::EnableExternalDevice, "EnableExternalDevice"},
{6, C<&Hidbus::GetExternalDeviceId>, "GetExternalDeviceId"}, {6, &HidBus::GetExternalDeviceId, "GetExternalDeviceId"},
{7, C<&Hidbus::SendCommandAsync>, "SendCommandAsync"}, {7, &HidBus::SendCommandAsync, "SendCommandAsync"},
{8, C<&Hidbus::GetSendCommandAsynceResult>, "GetSendCommandAsynceResult"}, {8, &HidBus::GetSendCommandAsynceResult, "GetSendCommandAsynceResult"},
{9, C<&Hidbus::SetEventForSendCommandAsycResult>, "SetEventForSendCommandAsycResult"}, {9, &HidBus::SetEventForSendCommandAsycResult, "SetEventForSendCommandAsycResult"},
{10, C<&Hidbus::GetSharedMemoryHandle>, "GetSharedMemoryHandle"}, {10, &HidBus::GetSharedMemoryHandle, "GetSharedMemoryHandle"},
{11, C<&Hidbus::EnableJoyPollingReceiveMode>, "EnableJoyPollingReceiveMode"}, {11, &HidBus::EnableJoyPollingReceiveMode, "EnableJoyPollingReceiveMode"},
{12, C<&Hidbus::DisableJoyPollingReceiveMode>, "DisableJoyPollingReceiveMode"}, {12, &HidBus::DisableJoyPollingReceiveMode, "DisableJoyPollingReceiveMode"},
{13, nullptr, "GetPollingData"}, {13, nullptr, "GetPollingData"},
{14, C<&Hidbus::SetStatusManagerType>, "SetStatusManagerType"}, {14, &HidBus::SetStatusManagerType, "SetStatusManagerType"},
}; };
// clang-format on // clang-format on
@ -61,11 +60,11 @@ Hidbus::Hidbus(Core::System& system_)
hidbus_update_event); hidbus_update_event);
} }
Hidbus::~Hidbus() { HidBus::~HidBus() {
system.CoreTiming().UnscheduleEvent(hidbus_update_event); system.CoreTiming().UnscheduleEvent(hidbus_update_event);
} }
void Hidbus::UpdateHidbus(std::chrono::nanoseconds ns_late) { void HidBus::UpdateHidbus(std::chrono::nanoseconds ns_late) {
if (is_hidbus_enabled) { if (is_hidbus_enabled) {
for (std::size_t i = 0; i < devices.size(); ++i) { for (std::size_t i = 0; i < devices.size(); ++i) {
if (!devices[i].is_device_initialized) { if (!devices[i].is_device_initialized) {
@ -85,7 +84,7 @@ void Hidbus::UpdateHidbus(std::chrono::nanoseconds ns_late) {
} }
} }
std::optional<std::size_t> Hidbus::GetDeviceIndexFromHandle(BusHandle handle) const { std::optional<std::size_t> HidBus::GetDeviceIndexFromHandle(BusHandle handle) const {
for (std::size_t i = 0; i < devices.size(); ++i) { for (std::size_t i = 0; i < devices.size(); ++i) {
const auto& device_handle = devices[i].handle; const auto& device_handle = devices[i].handle;
if (handle.abstracted_pad_id == device_handle.abstracted_pad_id && if (handle.abstracted_pad_id == device_handle.abstracted_pad_id &&
@ -99,11 +98,20 @@ std::optional<std::size_t> Hidbus::GetDeviceIndexFromHandle(BusHandle handle) co
return std::nullopt; return std::nullopt;
} }
Result Hidbus::GetBusHandle(Out<bool> out_is_valid, Out<BusHandle> out_bus_handle, void HidBus::GetBusHandle(HLERequestContext& ctx) {
Core::HID::NpadIdType npad_id, BusType bus_type, IPC::RequestParser rp{ctx};
AppletResourceUserId aruid) { struct Parameters {
LOG_INFO(Service_HID, "called, npad_id={}, bus_type={}, applet_resource_user_id={}", npad_id, Core::HID::NpadIdType npad_id;
bus_type, aruid.pid); INSERT_PADDING_WORDS_NOINIT(1);
BusType bus_type;
u64 applet_resource_user_id;
};
static_assert(sizeof(Parameters) == 0x18, "Parameters has incorrect size.");
const auto parameters{rp.PopRaw<Parameters>()};
LOG_INFO(Service_HID, "called, npad_id={}, bus_type={}, applet_resource_user_id={}",
parameters.npad_id, parameters.bus_type, parameters.applet_resource_user_id);
bool is_handle_found = 0; bool is_handle_found = 0;
std::size_t handle_index = 0; std::size_t handle_index = 0;
@ -113,8 +121,8 @@ Result Hidbus::GetBusHandle(Out<bool> out_is_valid, Out<BusHandle> out_bus_handl
if (!handle.is_valid) { if (!handle.is_valid) {
continue; continue;
} }
if (handle.player_number.As<Core::HID::NpadIdType>() == npad_id && if (static_cast<Core::HID::NpadIdType>(handle.player_number) == parameters.npad_id &&
handle.bus_type_id == static_cast<u8>(bus_type)) { handle.bus_type_id == static_cast<u8>(parameters.bus_type)) {
is_handle_found = true; is_handle_found = true;
handle_index = i; handle_index = i;
break; break;
@ -127,231 +135,388 @@ Result Hidbus::GetBusHandle(Out<bool> out_is_valid, Out<BusHandle> out_bus_handl
if (devices[i].handle.is_valid) { if (devices[i].handle.is_valid) {
continue; continue;
} }
devices[i].handle.raw = 0; devices[i].handle = {
devices[i].handle.abstracted_pad_id.Assign(i); .abstracted_pad_id = static_cast<u8>(i),
devices[i].handle.internal_index.Assign(i); .internal_index = static_cast<u8>(i),
devices[i].handle.player_number.Assign(static_cast<u8>(npad_id)); .player_number = static_cast<u8>(parameters.npad_id),
devices[i].handle.bus_type_id.Assign(static_cast<u8>(bus_type)); .bus_type_id = static_cast<u8>(parameters.bus_type),
devices[i].handle.is_valid.Assign(true); .is_valid = true,
};
handle_index = i; handle_index = i;
break; break;
} }
} }
*out_is_valid = true; struct OutData {
*out_bus_handle = devices[handle_index].handle; bool is_valid;
R_SUCCEED(); INSERT_PADDING_BYTES(7);
BusHandle handle;
};
static_assert(sizeof(OutData) == 0x10, "OutData has incorrect size.");
const OutData out_data{
.is_valid = true,
.handle = devices[handle_index].handle,
};
IPC::ResponseBuilder rb{ctx, 6};
rb.Push(ResultSuccess);
rb.PushRaw(out_data);
} }
Result Hidbus::IsExternalDeviceConnected(Out<bool> out_is_connected, BusHandle bus_handle) { void HidBus::IsExternalDeviceConnected(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto bus_handle_{rp.PopRaw<BusHandle>()};
LOG_INFO(Service_HID, LOG_INFO(Service_HID,
"Called, abstracted_pad_id={}, bus_type={}, internal_index={}, " "Called, abstracted_pad_id={}, bus_type={}, internal_index={}, "
"player_number={}, is_valid={}", "player_number={}, is_valid={}",
bus_handle.abstracted_pad_id, bus_handle.bus_type_id, bus_handle.internal_index, bus_handle_.abstracted_pad_id, bus_handle_.bus_type_id, bus_handle_.internal_index,
bus_handle.player_number, bus_handle.is_valid); bus_handle_.player_number, bus_handle_.is_valid);
const auto device_index = GetDeviceIndexFromHandle(bus_handle); const auto device_index = GetDeviceIndexFromHandle(bus_handle_);
R_UNLESS(device_index.has_value(), ResultUnknown); if (device_index) {
const auto& device = devices[device_index.value()].device;
const bool is_attached = device->IsDeviceActivated();
*out_is_connected = devices[device_index.value()].device->IsDeviceActivated(); IPC::ResponseBuilder rb{ctx, 3};
R_SUCCEED(); rb.Push(ResultSuccess);
rb.Push(is_attached);
return;
}
LOG_ERROR(Service_HID, "Invalid handle");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultUnknown);
return;
} }
Result Hidbus::Initialize(BusHandle bus_handle, AppletResourceUserId aruid) { void HidBus::Initialize(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto bus_handle_{rp.PopRaw<BusHandle>()};
const auto applet_resource_user_id{rp.Pop<u64>()};
LOG_INFO(Service_HID, LOG_INFO(Service_HID,
"called, abstracted_pad_id={} bus_type={} internal_index={} " "called, abstracted_pad_id={} bus_type={} internal_index={} "
"player_number={} is_valid={}, applet_resource_user_id={}", "player_number={} is_valid={}, applet_resource_user_id={}",
bus_handle.abstracted_pad_id, bus_handle.bus_type_id, bus_handle.internal_index, bus_handle_.abstracted_pad_id, bus_handle_.bus_type_id, bus_handle_.internal_index,
bus_handle.player_number, bus_handle.is_valid, aruid.pid); bus_handle_.player_number, bus_handle_.is_valid, applet_resource_user_id);
is_hidbus_enabled = true; is_hidbus_enabled = true;
const auto device_index = GetDeviceIndexFromHandle(bus_handle); const auto device_index = GetDeviceIndexFromHandle(bus_handle_);
R_UNLESS(device_index.has_value(), ResultUnknown); if (device_index) {
const auto entry_index = devices[device_index.value()].handle.internal_index;
auto& cur_entry = hidbus_status.entries[entry_index];
const auto entry_index = devices[device_index.value()].handle.internal_index; if (bus_handle_.internal_index == 0 && Settings::values.enable_ring_controller) {
auto& cur_entry = hidbus_status.entries[entry_index]; MakeDevice<RingController>(bus_handle_);
devices[device_index.value()].is_device_initialized = true;
devices[device_index.value()].device->ActivateDevice();
cur_entry.is_in_focus = true;
cur_entry.is_connected = true;
cur_entry.is_connected_result = ResultSuccess;
cur_entry.is_enabled = false;
cur_entry.is_polling_mode = false;
} else {
MakeDevice<HidbusStubbed>(bus_handle_);
devices[device_index.value()].is_device_initialized = true;
cur_entry.is_in_focus = true;
cur_entry.is_connected = false;
cur_entry.is_connected_result = ResultSuccess;
cur_entry.is_enabled = false;
cur_entry.is_polling_mode = false;
}
std::memcpy(system.Kernel().GetHidBusSharedMem().GetPointer(), &hidbus_status,
sizeof(hidbus_status));
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
return;
}
LOG_ERROR(Service_HID, "Invalid handle");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultUnknown);
return;
}
void HidBus::Finalize(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto bus_handle_{rp.PopRaw<BusHandle>()};
const auto applet_resource_user_id{rp.Pop<u64>()};
LOG_INFO(Service_HID,
"called, abstracted_pad_id={}, bus_type={}, internal_index={}, "
"player_number={}, is_valid={}, applet_resource_user_id={}",
bus_handle_.abstracted_pad_id, bus_handle_.bus_type_id, bus_handle_.internal_index,
bus_handle_.player_number, bus_handle_.is_valid, applet_resource_user_id);
const auto device_index = GetDeviceIndexFromHandle(bus_handle_);
if (device_index) {
const auto entry_index = devices[device_index.value()].handle.internal_index;
auto& cur_entry = hidbus_status.entries[entry_index];
auto& device = devices[device_index.value()].device;
devices[device_index.value()].is_device_initialized = false;
device->DeactivateDevice();
if (bus_handle.internal_index == 0 && Settings::values.enable_ring_controller) {
MakeDevice<RingController>(bus_handle);
devices[device_index.value()].is_device_initialized = true;
devices[device_index.value()].device->ActivateDevice();
cur_entry.is_in_focus = true;
cur_entry.is_connected = true;
cur_entry.is_connected_result = ResultSuccess;
cur_entry.is_enabled = false;
cur_entry.is_polling_mode = false;
} else {
MakeDevice<HidbusStubbed>(bus_handle);
devices[device_index.value()].is_device_initialized = true;
cur_entry.is_in_focus = true; cur_entry.is_in_focus = true;
cur_entry.is_connected = false; cur_entry.is_connected = false;
cur_entry.is_connected_result = ResultSuccess; cur_entry.is_connected_result = ResultSuccess;
cur_entry.is_enabled = false; cur_entry.is_enabled = false;
cur_entry.is_polling_mode = false; cur_entry.is_polling_mode = false;
std::memcpy(system.Kernel().GetHidBusSharedMem().GetPointer(), &hidbus_status,
sizeof(hidbus_status));
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
return;
} }
std::memcpy(system.Kernel().GetHidBusSharedMem().GetPointer(), &hidbus_status, LOG_ERROR(Service_HID, "Invalid handle");
sizeof(hidbus_status)); IPC::ResponseBuilder rb{ctx, 2};
R_SUCCEED(); rb.Push(ResultUnknown);
return;
} }
Result Hidbus::Finalize(BusHandle bus_handle, AppletResourceUserId aruid) { void HidBus::EnableExternalDevice(HLERequestContext& ctx) {
LOG_INFO(Service_HID, IPC::RequestParser rp{ctx};
"called, abstracted_pad_id={}, bus_type={}, internal_index={}, " struct Parameters {
"player_number={}, is_valid={}, applet_resource_user_id={}", bool enable;
bus_handle.abstracted_pad_id, bus_handle.bus_type_id, bus_handle.internal_index, INSERT_PADDING_BYTES_NOINIT(7);
bus_handle.player_number, bus_handle.is_valid, aruid.pid); BusHandle bus_handle;
u64 inval;
u64 applet_resource_user_id;
};
static_assert(sizeof(Parameters) == 0x20, "Parameters has incorrect size.");
const auto device_index = GetDeviceIndexFromHandle(bus_handle); const auto parameters{rp.PopRaw<Parameters>()};
R_UNLESS(device_index.has_value(), ResultUnknown);
const auto entry_index = devices[device_index.value()].handle.internal_index;
auto& cur_entry = hidbus_status.entries[entry_index];
auto& device = devices[device_index.value()].device;
devices[device_index.value()].is_device_initialized = false;
device->DeactivateDevice();
cur_entry.is_in_focus = true;
cur_entry.is_connected = false;
cur_entry.is_connected_result = ResultSuccess;
cur_entry.is_enabled = false;
cur_entry.is_polling_mode = false;
std::memcpy(system.Kernel().GetHidBusSharedMem().GetPointer(), &hidbus_status,
sizeof(hidbus_status));
R_SUCCEED();
}
Result Hidbus::EnableExternalDevice(bool is_enabled, BusHandle bus_handle, u64 inval,
AppletResourceUserId aruid) {
LOG_DEBUG(Service_HID, LOG_DEBUG(Service_HID,
"called, enable={}, abstracted_pad_id={}, bus_type={}, internal_index={}, " "called, enable={}, abstracted_pad_id={}, bus_type={}, internal_index={}, "
"player_number={}, is_valid={}, inval={}, applet_resource_user_id{}", "player_number={}, is_valid={}, inval={}, applet_resource_user_id{}",
is_enabled, bus_handle.abstracted_pad_id, bus_handle.bus_type_id, parameters.enable, parameters.bus_handle.abstracted_pad_id,
bus_handle.internal_index, bus_handle.player_number, bus_handle.is_valid, inval, parameters.bus_handle.bus_type_id, parameters.bus_handle.internal_index,
aruid.pid); parameters.bus_handle.player_number, parameters.bus_handle.is_valid, parameters.inval,
parameters.applet_resource_user_id);
const auto device_index = GetDeviceIndexFromHandle(bus_handle); const auto device_index = GetDeviceIndexFromHandle(parameters.bus_handle);
R_UNLESS(device_index.has_value(), ResultUnknown); if (device_index) {
devices[device_index.value()].device->Enable(is_enabled); auto& device = devices[device_index.value()].device;
R_SUCCEED(); device->Enable(parameters.enable);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
return;
}
LOG_ERROR(Service_HID, "Invalid handle");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultUnknown);
return;
} }
Result Hidbus::GetExternalDeviceId(Out<u32> out_device_id, BusHandle bus_handle) { void HidBus::GetExternalDeviceId(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto bus_handle_{rp.PopRaw<BusHandle>()};
LOG_DEBUG(Service_HID, LOG_DEBUG(Service_HID,
"called, abstracted_pad_id={}, bus_type={}, internal_index={}, player_number={}, " "called, abstracted_pad_id={}, bus_type={}, internal_index={}, player_number={}, "
"is_valid={}", "is_valid={}",
bus_handle.abstracted_pad_id, bus_handle.bus_type_id, bus_handle.internal_index, bus_handle_.abstracted_pad_id, bus_handle_.bus_type_id, bus_handle_.internal_index,
bus_handle.player_number, bus_handle.is_valid); bus_handle_.player_number, bus_handle_.is_valid);
const auto device_index = GetDeviceIndexFromHandle(bus_handle); const auto device_index = GetDeviceIndexFromHandle(bus_handle_);
R_UNLESS(device_index.has_value(), ResultUnknown); if (device_index) {
const auto& device = devices[device_index.value()].device;
u32 device_id = device->GetDeviceId();
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
rb.Push<u32>(device_id);
return;
}
*out_device_id = devices[device_index.value()].device->GetDeviceId(); LOG_ERROR(Service_HID, "Invalid handle");
R_SUCCEED(); IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultUnknown);
return;
} }
Result Hidbus::SendCommandAsync(BusHandle bus_handle, void HidBus::SendCommandAsync(HLERequestContext& ctx) {
InBuffer<BufferAttr_HipcAutoSelect> buffer_data) { IPC::RequestParser rp{ctx};
const auto data = ctx.ReadBuffer();
const auto bus_handle_{rp.PopRaw<BusHandle>()};
LOG_DEBUG(Service_HID, LOG_DEBUG(Service_HID,
"called, data_size={}, abstracted_pad_id={}, bus_type={}, internal_index={}, " "called, data_size={}, abstracted_pad_id={}, bus_type={}, internal_index={}, "
"player_number={}, is_valid={}", "player_number={}, is_valid={}",
buffer_data.size(), bus_handle.abstracted_pad_id, bus_handle.bus_type_id, data.size(), bus_handle_.abstracted_pad_id, bus_handle_.bus_type_id,
bus_handle.internal_index, bus_handle.player_number, bus_handle.is_valid); bus_handle_.internal_index, bus_handle_.player_number, bus_handle_.is_valid);
const auto device_index = GetDeviceIndexFromHandle(bus_handle); const auto device_index = GetDeviceIndexFromHandle(bus_handle_);
R_UNLESS(device_index.has_value(), ResultUnknown); if (device_index) {
auto& device = devices[device_index.value()].device;
device->SetCommand(data);
devices[device_index.value()].device->SetCommand(buffer_data); IPC::ResponseBuilder rb{ctx, 2};
R_SUCCEED(); rb.Push(ResultSuccess);
return;
}
LOG_ERROR(Service_HID, "Invalid handle");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultUnknown);
return;
}; };
Result Hidbus::GetSendCommandAsynceResult(Out<u64> out_data_size, BusHandle bus_handle, void HidBus::GetSendCommandAsynceResult(HLERequestContext& ctx) {
OutBuffer<BufferAttr_HipcAutoSelect> out_buffer_data) { IPC::RequestParser rp{ctx};
const auto bus_handle_{rp.PopRaw<BusHandle>()};
LOG_DEBUG(Service_HID, LOG_DEBUG(Service_HID,
"called, abstracted_pad_id={}, bus_type={}, internal_index={}, player_number={}, " "called, abstracted_pad_id={}, bus_type={}, internal_index={}, player_number={}, "
"is_valid={}", "is_valid={}",
bus_handle.abstracted_pad_id, bus_handle.bus_type_id, bus_handle.internal_index, bus_handle_.abstracted_pad_id, bus_handle_.bus_type_id, bus_handle_.internal_index,
bus_handle.player_number, bus_handle.is_valid); bus_handle_.player_number, bus_handle_.is_valid);
const auto device_index = GetDeviceIndexFromHandle(bus_handle); const auto device_index = GetDeviceIndexFromHandle(bus_handle_);
R_UNLESS(device_index.has_value(), ResultUnknown); if (device_index) {
const auto& device = devices[device_index.value()].device;
const std::vector<u8> data = device->GetReply();
const u64 data_size = ctx.WriteBuffer(data);
*out_data_size = devices[device_index.value()].device->GetReply(out_buffer_data); IPC::ResponseBuilder rb{ctx, 4};
R_SUCCEED(); rb.Push(ResultSuccess);
rb.Push<u64>(data_size);
return;
}
LOG_ERROR(Service_HID, "Invalid handle");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultUnknown);
return;
}; };
Result Hidbus::SetEventForSendCommandAsycResult(OutCopyHandle<Kernel::KReadableEvent> out_event, void HidBus::SetEventForSendCommandAsycResult(HLERequestContext& ctx) {
BusHandle bus_handle) { IPC::RequestParser rp{ctx};
const auto bus_handle_{rp.PopRaw<BusHandle>()};
LOG_INFO(Service_HID, LOG_INFO(Service_HID,
"called, abstracted_pad_id={}, bus_type={}, internal_index={}, player_number={}, " "called, abstracted_pad_id={}, bus_type={}, internal_index={}, player_number={}, "
"is_valid={}", "is_valid={}",
bus_handle.abstracted_pad_id, bus_handle.bus_type_id, bus_handle.internal_index, bus_handle_.abstracted_pad_id, bus_handle_.bus_type_id, bus_handle_.internal_index,
bus_handle.player_number, bus_handle.is_valid); bus_handle_.player_number, bus_handle_.is_valid);
const auto device_index = GetDeviceIndexFromHandle(bus_handle); const auto device_index = GetDeviceIndexFromHandle(bus_handle_);
R_UNLESS(device_index.has_value(), ResultUnknown); if (device_index) {
const auto& device = devices[device_index.value()].device;
IPC::ResponseBuilder rb{ctx, 2, 1};
rb.Push(ResultSuccess);
rb.PushCopyObjects(device->GetSendCommandAsycEvent());
return;
}
*out_event = &devices[device_index.value()].device->GetSendCommandAsycEvent(); LOG_ERROR(Service_HID, "Invalid handle");
R_SUCCEED(); IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultUnknown);
return;
}; };
Result Hidbus::GetSharedMemoryHandle(OutCopyHandle<Kernel::KSharedMemory> out_shared_memory) { void HidBus::GetSharedMemoryHandle(HLERequestContext& ctx) {
LOG_DEBUG(Service_HID, "called"); LOG_DEBUG(Service_HID, "called");
*out_shared_memory = &system.Kernel().GetHidBusSharedMem(); IPC::ResponseBuilder rb{ctx, 2, 1};
R_SUCCEED(); rb.Push(ResultSuccess);
rb.PushCopyObjects(&system.Kernel().GetHidBusSharedMem());
} }
Result Hidbus::EnableJoyPollingReceiveMode(u32 t_mem_size, JoyPollingMode polling_mode, void HidBus::EnableJoyPollingReceiveMode(HLERequestContext& ctx) {
BusHandle bus_handle, IPC::RequestParser rp{ctx};
InCopyHandle<Kernel::KTransferMemory> t_mem) { const auto t_mem_size{rp.Pop<u32>()};
const auto t_mem_handle{ctx.GetCopyHandle(0)};
const auto polling_mode_{rp.PopEnum<JoyPollingMode>()};
const auto bus_handle_{rp.PopRaw<BusHandle>()};
ASSERT_MSG(t_mem_size == 0x1000, "t_mem_size is not 0x1000 bytes"); ASSERT_MSG(t_mem_size == 0x1000, "t_mem_size is not 0x1000 bytes");
ASSERT_MSG(t_mem->GetSize() == t_mem_size, "t_mem has incorrect size");
auto t_mem = ctx.GetObjectFromHandle<Kernel::KTransferMemory>(t_mem_handle);
if (t_mem.IsNull()) {
LOG_ERROR(Service_HID, "t_mem is a nullptr for handle=0x{:08X}", t_mem_handle);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultUnknown);
return;
}
ASSERT_MSG(t_mem->GetSize() == 0x1000, "t_mem has incorrect size");
LOG_INFO(Service_HID, LOG_INFO(Service_HID,
"called, polling_mode={}, abstracted_pad_id={}, bus_type={}, " "called, t_mem_handle=0x{:08X}, polling_mode={}, abstracted_pad_id={}, bus_type={}, "
"internal_index={}, player_number={}, is_valid={}", "internal_index={}, player_number={}, is_valid={}",
polling_mode, bus_handle.abstracted_pad_id, bus_handle.bus_type_id, t_mem_handle, polling_mode_, bus_handle_.abstracted_pad_id, bus_handle_.bus_type_id,
bus_handle.internal_index, bus_handle.player_number, bus_handle.is_valid); bus_handle_.internal_index, bus_handle_.player_number, bus_handle_.is_valid);
const auto device_index = GetDeviceIndexFromHandle(bus_handle); const auto device_index = GetDeviceIndexFromHandle(bus_handle_);
R_UNLESS(device_index.has_value(), ResultUnknown); if (device_index) {
auto& device = devices[device_index.value()].device;
device->SetPollingMode(polling_mode_);
device->SetTransferMemoryAddress(t_mem->GetSourceAddress());
auto& device = devices[device_index.value()].device; IPC::ResponseBuilder rb{ctx, 2};
device->SetPollingMode(polling_mode); rb.Push(ResultSuccess);
device->SetTransferMemoryAddress(t_mem->GetSourceAddress()); return;
R_SUCCEED(); }
LOG_ERROR(Service_HID, "Invalid handle");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultUnknown);
return;
} }
Result Hidbus::DisableJoyPollingReceiveMode(BusHandle bus_handle) { void HidBus::DisableJoyPollingReceiveMode(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto bus_handle_{rp.PopRaw<BusHandle>()};
LOG_INFO(Service_HID, LOG_INFO(Service_HID,
"called, abstracted_pad_id={}, bus_type={}, internal_index={}, player_number={}, " "called, abstracted_pad_id={}, bus_type={}, internal_index={}, player_number={}, "
"is_valid={}", "is_valid={}",
bus_handle.abstracted_pad_id, bus_handle.bus_type_id, bus_handle.internal_index, bus_handle_.abstracted_pad_id, bus_handle_.bus_type_id, bus_handle_.internal_index,
bus_handle.player_number, bus_handle.is_valid); bus_handle_.player_number, bus_handle_.is_valid);
const auto device_index = GetDeviceIndexFromHandle(bus_handle); const auto device_index = GetDeviceIndexFromHandle(bus_handle_);
R_UNLESS(device_index.has_value(), ResultUnknown); if (device_index) {
auto& device = devices[device_index.value()].device;
device->DisablePollingMode();
auto& device = devices[device_index.value()].device; IPC::ResponseBuilder rb{ctx, 2};
device->DisablePollingMode(); rb.Push(ResultSuccess);
R_SUCCEED(); return;
}
LOG_ERROR(Service_HID, "Invalid handle");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultUnknown);
return;
} }
Result Hidbus::SetStatusManagerType(StatusManagerType manager_type) { void HidBus::SetStatusManagerType(HLERequestContext& ctx) {
LOG_WARNING(Service_HID, "(STUBBED) called, manager_type={}", manager_type); IPC::RequestParser rp{ctx};
R_SUCCEED(); const auto manager_type{rp.PopEnum<StatusManagerType>()};
};
LOG_WARNING(Service_HID, "(STUBBED) called, manager_type={}", manager_type);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
};
} // namespace Service::HID } // namespace Service::HID

View File

@ -5,10 +5,8 @@
#include <functional> #include <functional>
#include "core/hle/service/cmif_types.h"
#include "core/hle/service/kernel_helpers.h" #include "core/hle/service/kernel_helpers.h"
#include "core/hle/service/service.h" #include "core/hle/service/service.h"
#include "hid_core/hid_types.h"
#include "hid_core/hidbus/hidbus_base.h" #include "hid_core/hidbus/hidbus_base.h"
namespace Core::Timing { namespace Core::Timing {
@ -21,10 +19,10 @@ class System;
namespace Service::HID { namespace Service::HID {
class Hidbus final : public ServiceFramework<Hidbus> { class HidBus final : public ServiceFramework<HidBus> {
public: public:
explicit Hidbus(Core::System& system_); explicit HidBus(Core::System& system_);
~Hidbus() override; ~HidBus() override;
private: private:
static const std::size_t max_number_of_handles = 0x13; static const std::size_t max_number_of_handles = 0x13;
@ -43,7 +41,7 @@ private:
}; };
// This is nn::hidbus::BusType // This is nn::hidbus::BusType
enum class BusType : u64 { enum class BusType : u32 {
LeftJoyRail, LeftJoyRail,
RightJoyRail, RightJoyRail,
InternalBus, // Lark microphone InternalBus, // Lark microphone
@ -53,15 +51,11 @@ private:
// This is nn::hidbus::BusHandle // This is nn::hidbus::BusHandle
struct BusHandle { struct BusHandle {
union { u32 abstracted_pad_id;
u64 raw{}; u8 internal_index;
u8 player_number;
BitField<0, 32, u64> abstracted_pad_id; u8 bus_type_id;
BitField<32, 8, u64> internal_index; bool is_valid;
BitField<40, 8, u64> player_number;
BitField<48, 8, u64> bus_type_id;
BitField<56, 1, u64> is_valid;
};
}; };
static_assert(sizeof(BusHandle) == 0x8, "BusHandle is an invalid size"); static_assert(sizeof(BusHandle) == 0x8, "BusHandle is an invalid size");
@ -100,38 +94,19 @@ private:
std::unique_ptr<HidbusBase> device{nullptr}; std::unique_ptr<HidbusBase> device{nullptr};
}; };
Result GetBusHandle(Out<bool> out_is_valid, Out<BusHandle> out_bus_handle, void GetBusHandle(HLERequestContext& ctx);
Core::HID::NpadIdType npad_id, BusType bus_type, void IsExternalDeviceConnected(HLERequestContext& ctx);
AppletResourceUserId aruid); void Initialize(HLERequestContext& ctx);
void Finalize(HLERequestContext& ctx);
Result IsExternalDeviceConnected(Out<bool> out_is_connected, BusHandle bus_handle); void EnableExternalDevice(HLERequestContext& ctx);
void GetExternalDeviceId(HLERequestContext& ctx);
Result Initialize(BusHandle bus_handle, AppletResourceUserId aruid); void SendCommandAsync(HLERequestContext& ctx);
void GetSendCommandAsynceResult(HLERequestContext& ctx);
Result Finalize(BusHandle bus_handle, AppletResourceUserId aruid); void SetEventForSendCommandAsycResult(HLERequestContext& ctx);
void GetSharedMemoryHandle(HLERequestContext& ctx);
Result EnableExternalDevice(bool is_enabled, BusHandle bus_handle, u64 inval, void EnableJoyPollingReceiveMode(HLERequestContext& ctx);
AppletResourceUserId aruid); void DisableJoyPollingReceiveMode(HLERequestContext& ctx);
void SetStatusManagerType(HLERequestContext& ctx);
Result GetExternalDeviceId(Out<u32> out_device_id, BusHandle bus_handle);
Result SendCommandAsync(BusHandle bus_handle, InBuffer<BufferAttr_HipcAutoSelect> buffer_data);
Result GetSendCommandAsynceResult(Out<u64> out_data_size, BusHandle bus_handle,
OutBuffer<BufferAttr_HipcAutoSelect> out_buffer_data);
Result SetEventForSendCommandAsycResult(OutCopyHandle<Kernel::KReadableEvent> out_event,
BusHandle bus_handle);
Result GetSharedMemoryHandle(OutCopyHandle<Kernel::KSharedMemory> out_shared_memory);
Result EnableJoyPollingReceiveMode(u32 t_mem_size, JoyPollingMode polling_mode,
BusHandle bus_handle,
InCopyHandle<Kernel::KTransferMemory> t_mem);
Result DisableJoyPollingReceiveMode(BusHandle bus_handle);
Result SetStatusManagerType(StatusManagerType manager_type);
void UpdateHidbus(std::chrono::nanoseconds ns_late); void UpdateHidbus(std::chrono::nanoseconds ns_late);
std::optional<std::size_t> GetDeviceIndexFromHandle(BusHandle handle) const; std::optional<std::size_t> GetDeviceIndexFromHandle(BusHandle handle) const;

View File

@ -9,7 +9,6 @@
#include "core/hle/kernel/k_shared_memory.h" #include "core/hle/kernel/k_shared_memory.h"
#include "core/hle/kernel/k_transfer_memory.h" #include "core/hle/kernel/k_transfer_memory.h"
#include "core/hle/kernel/kernel.h" #include "core/hle/kernel/kernel.h"
#include "core/hle/service/cmif_serialization.h"
#include "core/hle/service/hid/irs.h" #include "core/hle/service/hid/irs.h"
#include "core/hle/service/ipc_helpers.h" #include "core/hle/service/ipc_helpers.h"
#include "core/memory.h" #include "core/memory.h"
@ -29,24 +28,24 @@ namespace Service::IRS {
IRS::IRS(Core::System& system_) : ServiceFramework{system_, "irs"} { IRS::IRS(Core::System& system_) : ServiceFramework{system_, "irs"} {
// clang-format off // clang-format off
static const FunctionInfo functions[] = { static const FunctionInfo functions[] = {
{302, C<&IRS::ActivateIrsensor>, "ActivateIrsensor"}, {302, &IRS::ActivateIrsensor, "ActivateIrsensor"},
{303, C<&IRS::DeactivateIrsensor>, "DeactivateIrsensor"}, {303, &IRS::DeactivateIrsensor, "DeactivateIrsensor"},
{304, C<&IRS::GetIrsensorSharedMemoryHandle>, "GetIrsensorSharedMemoryHandle"}, {304, &IRS::GetIrsensorSharedMemoryHandle, "GetIrsensorSharedMemoryHandle"},
{305, C<&IRS::StopImageProcessor>, "StopImageProcessor"}, {305, &IRS::StopImageProcessor, "StopImageProcessor"},
{306, C<&IRS::RunMomentProcessor>, "RunMomentProcessor"}, {306, &IRS::RunMomentProcessor, "RunMomentProcessor"},
{307, C<&IRS::RunClusteringProcessor>, "RunClusteringProcessor"}, {307, &IRS::RunClusteringProcessor, "RunClusteringProcessor"},
{308, C<&IRS::RunImageTransferProcessor>, "RunImageTransferProcessor"}, {308, &IRS::RunImageTransferProcessor, "RunImageTransferProcessor"},
{309, C<&IRS::GetImageTransferProcessorState>, "GetImageTransferProcessorState"}, {309, &IRS::GetImageTransferProcessorState, "GetImageTransferProcessorState"},
{310, C<&IRS::RunTeraPluginProcessor>, "RunTeraPluginProcessor"}, {310, &IRS::RunTeraPluginProcessor, "RunTeraPluginProcessor"},
{311, C<&IRS::GetNpadIrCameraHandle>, "GetNpadIrCameraHandle"}, {311, &IRS::GetNpadIrCameraHandle, "GetNpadIrCameraHandle"},
{312, C<&IRS::RunPointingProcessor>, "RunPointingProcessor"}, {312, &IRS::RunPointingProcessor, "RunPointingProcessor"},
{313, C<&IRS::SuspendImageProcessor>, "SuspendImageProcessor"}, {313, &IRS::SuspendImageProcessor, "SuspendImageProcessor"},
{314, C<&IRS::CheckFirmwareVersion>, "CheckFirmwareVersion"}, {314, &IRS::CheckFirmwareVersion, "CheckFirmwareVersion"},
{315, C<&IRS::SetFunctionLevel>, "SetFunctionLevel"}, {315, &IRS::SetFunctionLevel, "SetFunctionLevel"},
{316, C<&IRS::RunImageTransferExProcessor>, "RunImageTransferExProcessor"}, {316, &IRS::RunImageTransferExProcessor, "RunImageTransferExProcessor"},
{317, C<&IRS::RunIrLedProcessor>, "RunIrLedProcessor"}, {317, &IRS::RunIrLedProcessor, "RunIrLedProcessor"},
{318, C<&IRS::StopImageProcessorAsync>, "StopImageProcessorAsync"}, {318, &IRS::StopImageProcessorAsync, "StopImageProcessorAsync"},
{319, C<&IRS::ActivateIrsensorWithFunctionLevel>, "ActivateIrsensorWithFunctionLevel"}, {319, &IRS::ActivateIrsensorWithFunctionLevel, "ActivateIrsensorWithFunctionLevel"},
}; };
// clang-format on // clang-format on
@ -58,292 +57,489 @@ IRS::IRS(Core::System& system_) : ServiceFramework{system_, "irs"} {
} }
IRS::~IRS() = default; IRS::~IRS() = default;
Result IRS::ActivateIrsensor(ClientAppletResourceUserId aruid) { void IRS::ActivateIrsensor(HLERequestContext& ctx) {
LOG_WARNING(Service_IRS, "(STUBBED) called, applet_resource_user_id={}", aruid.pid); IPC::RequestParser rp{ctx};
R_SUCCEED(); const auto applet_resource_user_id{rp.Pop<u64>()};
LOG_WARNING(Service_IRS, "(STUBBED) called, applet_resource_user_id={}",
applet_resource_user_id);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
} }
Result IRS::DeactivateIrsensor(ClientAppletResourceUserId aruid) { void IRS::DeactivateIrsensor(HLERequestContext& ctx) {
LOG_WARNING(Service_IRS, "(STUBBED) called, applet_resource_user_id={}", aruid.pid); IPC::RequestParser rp{ctx};
R_SUCCEED(); const auto applet_resource_user_id{rp.Pop<u64>()};
LOG_WARNING(Service_IRS, "(STUBBED) called, applet_resource_user_id={}",
applet_resource_user_id);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
} }
Result IRS::GetIrsensorSharedMemoryHandle(OutCopyHandle<Kernel::KSharedMemory> out_shared_memory, void IRS::GetIrsensorSharedMemoryHandle(HLERequestContext& ctx) {
ClientAppletResourceUserId aruid) { IPC::RequestParser rp{ctx};
LOG_DEBUG(Service_IRS, "called, applet_resource_user_id={}", aruid.pid); const auto applet_resource_user_id{rp.Pop<u64>()};
*out_shared_memory = &system.Kernel().GetIrsSharedMem(); LOG_DEBUG(Service_IRS, "called, applet_resource_user_id={}", applet_resource_user_id);
R_SUCCEED();
IPC::ResponseBuilder rb{ctx, 2, 1};
rb.Push(ResultSuccess);
rb.PushCopyObjects(&system.Kernel().GetIrsSharedMem());
} }
Result IRS::StopImageProcessor(Core::IrSensor::IrCameraHandle camera_handle, void IRS::StopImageProcessor(HLERequestContext& ctx) {
ClientAppletResourceUserId aruid) { IPC::RequestParser rp{ctx};
struct Parameters {
Core::IrSensor::IrCameraHandle camera_handle;
INSERT_PADDING_WORDS_NOINIT(1);
u64 applet_resource_user_id;
};
static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
const auto parameters{rp.PopRaw<Parameters>()};
LOG_WARNING(Service_IRS, LOG_WARNING(Service_IRS,
"(STUBBED) called, npad_type={}, npad_id={}, applet_resource_user_id={}", "(STUBBED) called, npad_type={}, npad_id={}, applet_resource_user_id={}",
camera_handle.npad_type, camera_handle.npad_id, aruid.pid); parameters.camera_handle.npad_type, parameters.camera_handle.npad_id,
parameters.applet_resource_user_id);
R_TRY(IsIrCameraHandleValid(camera_handle)); auto result = IsIrCameraHandleValid(parameters.camera_handle);
if (result.IsSuccess()) {
// TODO: Stop Image processor
npad_device->SetPollingMode(Core::HID::EmulatedDeviceIndex::RightIndex,
Common::Input::PollingMode::Active);
result = ResultSuccess;
}
// TODO: Stop Image processor IPC::ResponseBuilder rb{ctx, 2};
npad_device->SetPollingMode(Core::HID::EmulatedDeviceIndex::RightIndex, rb.Push(result);
Common::Input::PollingMode::Active);
R_SUCCEED();
} }
Result IRS::RunMomentProcessor( void IRS::RunMomentProcessor(HLERequestContext& ctx) {
Core::IrSensor::IrCameraHandle camera_handle, ClientAppletResourceUserId aruid, IPC::RequestParser rp{ctx};
const Core::IrSensor::PackedMomentProcessorConfig& processor_config) { struct Parameters {
Core::IrSensor::IrCameraHandle camera_handle;
INSERT_PADDING_WORDS_NOINIT(1);
u64 applet_resource_user_id;
Core::IrSensor::PackedMomentProcessorConfig processor_config;
};
static_assert(sizeof(Parameters) == 0x30, "Parameters has incorrect size.");
const auto parameters{rp.PopRaw<Parameters>()};
LOG_WARNING(Service_IRS, LOG_WARNING(Service_IRS,
"(STUBBED) called, npad_type={}, npad_id={}, applet_resource_user_id={}", "(STUBBED) called, npad_type={}, npad_id={}, applet_resource_user_id={}",
camera_handle.npad_type, camera_handle.npad_id, aruid.pid); parameters.camera_handle.npad_type, parameters.camera_handle.npad_id,
parameters.applet_resource_user_id);
R_TRY(IsIrCameraHandleValid(camera_handle)); const auto result = IsIrCameraHandleValid(parameters.camera_handle);
auto& device = GetIrCameraSharedMemoryDeviceEntry(camera_handle); if (result.IsSuccess()) {
MakeProcessorWithCoreContext<MomentProcessor>(camera_handle, device); auto& device = GetIrCameraSharedMemoryDeviceEntry(parameters.camera_handle);
auto& image_transfer_processor = GetProcessor<MomentProcessor>(camera_handle); MakeProcessorWithCoreContext<MomentProcessor>(parameters.camera_handle, device);
image_transfer_processor.SetConfig(processor_config); auto& image_transfer_processor = GetProcessor<MomentProcessor>(parameters.camera_handle);
npad_device->SetPollingMode(Core::HID::EmulatedDeviceIndex::RightIndex, image_transfer_processor.SetConfig(parameters.processor_config);
Common::Input::PollingMode::IR); npad_device->SetPollingMode(Core::HID::EmulatedDeviceIndex::RightIndex,
Common::Input::PollingMode::IR);
}
R_SUCCEED(); IPC::ResponseBuilder rb{ctx, 2};
rb.Push(result);
} }
Result IRS::RunClusteringProcessor( void IRS::RunClusteringProcessor(HLERequestContext& ctx) {
Core::IrSensor::IrCameraHandle camera_handle, ClientAppletResourceUserId aruid, IPC::RequestParser rp{ctx};
const Core::IrSensor::PackedClusteringProcessorConfig& processor_config) { struct Parameters {
Core::IrSensor::IrCameraHandle camera_handle;
INSERT_PADDING_WORDS_NOINIT(1);
u64 applet_resource_user_id;
Core::IrSensor::PackedClusteringProcessorConfig processor_config;
};
static_assert(sizeof(Parameters) == 0x38, "Parameters has incorrect size.");
const auto parameters{rp.PopRaw<Parameters>()};
LOG_WARNING(Service_IRS, LOG_WARNING(Service_IRS,
"(STUBBED) called, npad_type={}, npad_id={}, applet_resource_user_id={}", "(STUBBED) called, npad_type={}, npad_id={}, applet_resource_user_id={}",
camera_handle.npad_type, camera_handle.npad_id, aruid.pid); parameters.camera_handle.npad_type, parameters.camera_handle.npad_id,
parameters.applet_resource_user_id);
R_TRY(IsIrCameraHandleValid(camera_handle)); auto result = IsIrCameraHandleValid(parameters.camera_handle);
auto& device = GetIrCameraSharedMemoryDeviceEntry(camera_handle); if (result.IsSuccess()) {
MakeProcessorWithCoreContext<ClusteringProcessor>(camera_handle, device); auto& device = GetIrCameraSharedMemoryDeviceEntry(parameters.camera_handle);
auto& image_transfer_processor = GetProcessor<ClusteringProcessor>(camera_handle); MakeProcessorWithCoreContext<ClusteringProcessor>(parameters.camera_handle, device);
image_transfer_processor.SetConfig(processor_config); auto& image_transfer_processor =
npad_device->SetPollingMode(Core::HID::EmulatedDeviceIndex::RightIndex, GetProcessor<ClusteringProcessor>(parameters.camera_handle);
Common::Input::PollingMode::IR); image_transfer_processor.SetConfig(parameters.processor_config);
npad_device->SetPollingMode(Core::HID::EmulatedDeviceIndex::RightIndex,
Common::Input::PollingMode::IR);
}
R_SUCCEED(); IPC::ResponseBuilder rb{ctx, 2};
rb.Push(result);
} }
Result IRS::RunImageTransferProcessor( void IRS::RunImageTransferProcessor(HLERequestContext& ctx) {
Core::IrSensor::IrCameraHandle camera_handle, ClientAppletResourceUserId aruid, IPC::RequestParser rp{ctx};
const Core::IrSensor::PackedImageTransferProcessorConfig& processor_config, struct Parameters {
u64 transfer_memory_size, InCopyHandle<Kernel::KTransferMemory> t_mem) { Core::IrSensor::IrCameraHandle camera_handle;
INSERT_PADDING_WORDS_NOINIT(1);
u64 applet_resource_user_id;
Core::IrSensor::PackedImageTransferProcessorConfig processor_config;
u32 transfer_memory_size;
};
static_assert(sizeof(Parameters) == 0x30, "Parameters has incorrect size.");
ASSERT_MSG(t_mem->GetSize() == transfer_memory_size, "t_mem has incorrect size"); const auto parameters{rp.PopRaw<Parameters>()};
const auto t_mem_handle{ctx.GetCopyHandle(0)};
auto t_mem = ctx.GetObjectFromHandle<Kernel::KTransferMemory>(t_mem_handle);
if (t_mem.IsNull()) {
LOG_ERROR(Service_IRS, "t_mem is a nullptr for handle=0x{:08X}", t_mem_handle);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultUnknown);
return;
}
ASSERT_MSG(t_mem->GetSize() == parameters.transfer_memory_size, "t_mem has incorrect size");
LOG_INFO(Service_IRS, LOG_INFO(Service_IRS,
"called, npad_type={}, npad_id={}, transfer_memory_size={}, transfer_memory_size={}, " "called, npad_type={}, npad_id={}, transfer_memory_size={}, transfer_memory_size={}, "
"applet_resource_user_id={}", "applet_resource_user_id={}",
camera_handle.npad_type, camera_handle.npad_id, transfer_memory_size, t_mem->GetSize(), parameters.camera_handle.npad_type, parameters.camera_handle.npad_id,
aruid.pid); parameters.transfer_memory_size, t_mem->GetSize(), parameters.applet_resource_user_id);
R_TRY(IsIrCameraHandleValid(camera_handle)); const auto result = IsIrCameraHandleValid(parameters.camera_handle);
auto& device = GetIrCameraSharedMemoryDeviceEntry(camera_handle); if (result.IsSuccess()) {
MakeProcessorWithCoreContext<ImageTransferProcessor>(camera_handle, device); auto& device = GetIrCameraSharedMemoryDeviceEntry(parameters.camera_handle);
auto& image_transfer_processor = GetProcessor<ImageTransferProcessor>(camera_handle); MakeProcessorWithCoreContext<ImageTransferProcessor>(parameters.camera_handle, device);
image_transfer_processor.SetConfig(processor_config); auto& image_transfer_processor =
image_transfer_processor.SetTransferMemoryAddress(t_mem->GetSourceAddress()); GetProcessor<ImageTransferProcessor>(parameters.camera_handle);
npad_device->SetPollingMode(Core::HID::EmulatedDeviceIndex::RightIndex, image_transfer_processor.SetConfig(parameters.processor_config);
Common::Input::PollingMode::IR); image_transfer_processor.SetTransferMemoryAddress(t_mem->GetSourceAddress());
npad_device->SetPollingMode(Core::HID::EmulatedDeviceIndex::RightIndex,
Common::Input::PollingMode::IR);
}
R_SUCCEED(); IPC::ResponseBuilder rb{ctx, 2};
rb.Push(result);
} }
Result IRS::GetImageTransferProcessorState( void IRS::GetImageTransferProcessorState(HLERequestContext& ctx) {
Out<Core::IrSensor::ImageTransferProcessorState> out_state, IPC::RequestParser rp{ctx};
Core::IrSensor::IrCameraHandle camera_handle, ClientAppletResourceUserId aruid, struct Parameters {
OutBuffer<BufferAttr_HipcMapAlias> out_buffer_data) { Core::IrSensor::IrCameraHandle camera_handle;
INSERT_PADDING_WORDS_NOINIT(1);
u64 applet_resource_user_id;
};
static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
const auto parameters{rp.PopRaw<Parameters>()};
LOG_DEBUG(Service_IRS, "(STUBBED) called, npad_type={}, npad_id={}, applet_resource_user_id={}", LOG_DEBUG(Service_IRS, "(STUBBED) called, npad_type={}, npad_id={}, applet_resource_user_id={}",
camera_handle.npad_type, camera_handle.npad_id, aruid.pid); parameters.camera_handle.npad_type, parameters.camera_handle.npad_id,
parameters.applet_resource_user_id);
R_TRY(IsIrCameraHandleValid(camera_handle)); const auto result = IsIrCameraHandleValid(parameters.camera_handle);
if (result.IsError()) {
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(result);
return;
}
const auto& device = GetIrCameraSharedMemoryDeviceEntry(camera_handle); const auto& device = GetIrCameraSharedMemoryDeviceEntry(parameters.camera_handle);
R_TRY(IsIrCameraHandleValid(camera_handle)); if (device.mode != Core::IrSensor::IrSensorMode::ImageTransferProcessor) {
R_UNLESS(device.mode == Core::IrSensor::IrSensorMode::ImageTransferProcessor, IPC::ResponseBuilder rb{ctx, 2};
InvalidProcessorState); rb.Push(InvalidProcessorState);
return;
}
*out_state = GetProcessor<ImageTransferProcessor>(camera_handle).GetState(out_buffer_data); std::vector<u8> data{};
const auto& image_transfer_processor =
GetProcessor<ImageTransferProcessor>(parameters.camera_handle);
const auto& state = image_transfer_processor.GetState(data);
R_SUCCEED(); ctx.WriteBuffer(data);
IPC::ResponseBuilder rb{ctx, 6};
rb.Push(ResultSuccess);
rb.PushRaw(state);
} }
Result IRS::RunTeraPluginProcessor(Core::IrSensor::IrCameraHandle camera_handle, void IRS::RunTeraPluginProcessor(HLERequestContext& ctx) {
Core::IrSensor::PackedTeraPluginProcessorConfig processor_config, IPC::RequestParser rp{ctx};
ClientAppletResourceUserId aruid) { struct Parameters {
LOG_WARNING(Service_IRS, Core::IrSensor::IrCameraHandle camera_handle;
"(STUBBED) called, npad_type={}, npad_id={}, mode={}, mcu_version={}.{}, " Core::IrSensor::PackedTeraPluginProcessorConfig processor_config;
"applet_resource_user_id={}", INSERT_PADDING_WORDS_NOINIT(1);
camera_handle.npad_type, camera_handle.npad_id, processor_config.mode, u64 applet_resource_user_id;
processor_config.required_mcu_version.major, };
processor_config.required_mcu_version.minor, aruid.pid); static_assert(sizeof(Parameters) == 0x18, "Parameters has incorrect size.");
R_TRY(IsIrCameraHandleValid(camera_handle)); const auto parameters{rp.PopRaw<Parameters>()};
auto& device = GetIrCameraSharedMemoryDeviceEntry(camera_handle); LOG_WARNING(
MakeProcessor<TeraPluginProcessor>(camera_handle, device); Service_IRS,
auto& image_transfer_processor = GetProcessor<TeraPluginProcessor>(camera_handle); "(STUBBED) called, npad_type={}, npad_id={}, mode={}, mcu_version={}.{}, "
image_transfer_processor.SetConfig(processor_config); "applet_resource_user_id={}",
npad_device->SetPollingMode(Core::HID::EmulatedDeviceIndex::RightIndex, parameters.camera_handle.npad_type, parameters.camera_handle.npad_id,
Common::Input::PollingMode::IR); parameters.processor_config.mode, parameters.processor_config.required_mcu_version.major,
parameters.processor_config.required_mcu_version.minor, parameters.applet_resource_user_id);
R_SUCCEED(); const auto result = IsIrCameraHandleValid(parameters.camera_handle);
if (result.IsSuccess()) {
auto& device = GetIrCameraSharedMemoryDeviceEntry(parameters.camera_handle);
MakeProcessor<TeraPluginProcessor>(parameters.camera_handle, device);
auto& image_transfer_processor =
GetProcessor<TeraPluginProcessor>(parameters.camera_handle);
image_transfer_processor.SetConfig(parameters.processor_config);
npad_device->SetPollingMode(Core::HID::EmulatedDeviceIndex::RightIndex,
Common::Input::PollingMode::IR);
}
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(result);
} }
Result IRS::GetNpadIrCameraHandle(Out<Core::IrSensor::IrCameraHandle> out_camera_handle, void IRS::GetNpadIrCameraHandle(HLERequestContext& ctx) {
Core::HID::NpadIdType npad_id) { IPC::RequestParser rp{ctx};
R_UNLESS(HID::IsNpadIdValid(npad_id), HID::ResultInvalidNpadId); const auto npad_id{rp.PopEnum<Core::HID::NpadIdType>()};
*out_camera_handle = { if (npad_id > Core::HID::NpadIdType::Player8 && npad_id != Core::HID::NpadIdType::Invalid &&
npad_id != Core::HID::NpadIdType::Handheld) {
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(Service::HID::ResultInvalidNpadId);
return;
}
Core::IrSensor::IrCameraHandle camera_handle{
.npad_id = static_cast<u8>(HID::NpadIdTypeToIndex(npad_id)), .npad_id = static_cast<u8>(HID::NpadIdTypeToIndex(npad_id)),
.npad_type = Core::HID::NpadStyleIndex::None, .npad_type = Core::HID::NpadStyleIndex::None,
}; };
LOG_INFO(Service_IRS, "called, npad_id={}, camera_npad_id={}, camera_npad_type={}", npad_id, LOG_INFO(Service_IRS, "called, npad_id={}, camera_npad_id={}, camera_npad_type={}", npad_id,
out_camera_handle->npad_id, out_camera_handle->npad_type); camera_handle.npad_id, camera_handle.npad_type);
R_SUCCEED(); IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
rb.PushRaw(camera_handle);
} }
Result IRS::RunPointingProcessor( void IRS::RunPointingProcessor(HLERequestContext& ctx) {
Core::IrSensor::IrCameraHandle camera_handle, IPC::RequestParser rp{ctx};
const Core::IrSensor::PackedPointingProcessorConfig& processor_config, const auto camera_handle{rp.PopRaw<Core::IrSensor::IrCameraHandle>()};
ClientAppletResourceUserId aruid) { const auto processor_config{rp.PopRaw<Core::IrSensor::PackedPointingProcessorConfig>()};
const auto applet_resource_user_id{rp.Pop<u64>()};
LOG_WARNING( LOG_WARNING(
Service_IRS, Service_IRS,
"(STUBBED) called, npad_type={}, npad_id={}, mcu_version={}.{}, applet_resource_user_id={}", "(STUBBED) called, npad_type={}, npad_id={}, mcu_version={}.{}, applet_resource_user_id={}",
camera_handle.npad_type, camera_handle.npad_id, processor_config.required_mcu_version.major, camera_handle.npad_type, camera_handle.npad_id, processor_config.required_mcu_version.major,
processor_config.required_mcu_version.minor, aruid.pid); processor_config.required_mcu_version.minor, applet_resource_user_id);
R_TRY(IsIrCameraHandleValid(camera_handle)); auto result = IsIrCameraHandleValid(camera_handle);
auto& device = GetIrCameraSharedMemoryDeviceEntry(camera_handle); if (result.IsSuccess()) {
MakeProcessor<PointingProcessor>(camera_handle, device); auto& device = GetIrCameraSharedMemoryDeviceEntry(camera_handle);
auto& image_transfer_processor = GetProcessor<PointingProcessor>(camera_handle); MakeProcessor<PointingProcessor>(camera_handle, device);
image_transfer_processor.SetConfig(processor_config); auto& image_transfer_processor = GetProcessor<PointingProcessor>(camera_handle);
npad_device->SetPollingMode(Core::HID::EmulatedDeviceIndex::RightIndex, image_transfer_processor.SetConfig(processor_config);
Common::Input::PollingMode::IR); npad_device->SetPollingMode(Core::HID::EmulatedDeviceIndex::RightIndex,
Common::Input::PollingMode::IR);
}
R_SUCCEED(); IPC::ResponseBuilder rb{ctx, 2};
rb.Push(result);
} }
Result IRS::SuspendImageProcessor(Core::IrSensor::IrCameraHandle camera_handle, void IRS::SuspendImageProcessor(HLERequestContext& ctx) {
ClientAppletResourceUserId aruid) { IPC::RequestParser rp{ctx};
struct Parameters {
Core::IrSensor::IrCameraHandle camera_handle;
INSERT_PADDING_WORDS_NOINIT(1);
u64 applet_resource_user_id;
};
static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
const auto parameters{rp.PopRaw<Parameters>()};
LOG_WARNING(Service_IRS, LOG_WARNING(Service_IRS,
"(STUBBED) called, npad_type={}, npad_id={}, applet_resource_user_id={}", "(STUBBED) called, npad_type={}, npad_id={}, applet_resource_user_id={}",
camera_handle.npad_type, camera_handle.npad_id, aruid.pid); parameters.camera_handle.npad_type, parameters.camera_handle.npad_id,
parameters.applet_resource_user_id);
R_TRY(IsIrCameraHandleValid(camera_handle)); auto result = IsIrCameraHandleValid(parameters.camera_handle);
if (result.IsSuccess()) {
// TODO: Suspend image processor
result = ResultSuccess;
}
// TODO: Suspend image processor IPC::ResponseBuilder rb{ctx, 2};
rb.Push(result);
R_SUCCEED();
} }
Result IRS::CheckFirmwareVersion(Core::IrSensor::IrCameraHandle camera_handle, void IRS::CheckFirmwareVersion(HLERequestContext& ctx) {
Core::IrSensor::PackedMcuVersion mcu_version, IPC::RequestParser rp{ctx};
ClientAppletResourceUserId aruid) { const auto camera_handle{rp.PopRaw<Core::IrSensor::IrCameraHandle>()};
const auto mcu_version{rp.PopRaw<Core::IrSensor::PackedMcuVersion>()};
const auto applet_resource_user_id{rp.Pop<u64>()};
LOG_WARNING( LOG_WARNING(
Service_IRS, Service_IRS,
"(STUBBED) called, npad_type={}, npad_id={}, applet_resource_user_id={}, mcu_version={}.{}", "(STUBBED) called, npad_type={}, npad_id={}, applet_resource_user_id={}, mcu_version={}.{}",
camera_handle.npad_type, camera_handle.npad_id, aruid.pid, mcu_version.major, camera_handle.npad_type, camera_handle.npad_id, applet_resource_user_id, mcu_version.major,
mcu_version.minor); mcu_version.minor);
R_TRY(IsIrCameraHandleValid(camera_handle)); auto result = IsIrCameraHandleValid(camera_handle);
if (result.IsSuccess()) {
// TODO: Check firmware version
result = ResultSuccess;
}
// TODO: Check firmware version IPC::ResponseBuilder rb{ctx, 2};
rb.Push(result);
R_SUCCEED();
} }
Result IRS::SetFunctionLevel(Core::IrSensor::IrCameraHandle camera_handle, void IRS::SetFunctionLevel(HLERequestContext& ctx) {
Core::IrSensor::PackedFunctionLevel function_level, IPC::RequestParser rp{ctx};
ClientAppletResourceUserId aruid) { const auto camera_handle{rp.PopRaw<Core::IrSensor::IrCameraHandle>()};
const auto function_level{rp.PopRaw<Core::IrSensor::PackedFunctionLevel>()};
const auto applet_resource_user_id{rp.Pop<u64>()};
LOG_WARNING( LOG_WARNING(
Service_IRS, Service_IRS,
"(STUBBED) called, npad_type={}, npad_id={}, function_level={}, applet_resource_user_id={}", "(STUBBED) called, npad_type={}, npad_id={}, function_level={}, applet_resource_user_id={}",
camera_handle.npad_type, camera_handle.npad_id, function_level.function_level, aruid.pid); camera_handle.npad_type, camera_handle.npad_id, function_level.function_level,
applet_resource_user_id);
R_TRY(IsIrCameraHandleValid(camera_handle)); auto result = IsIrCameraHandleValid(camera_handle);
if (result.IsSuccess()) {
// TODO: Set Function level
result = ResultSuccess;
}
// TODO: Set Function level IPC::ResponseBuilder rb{ctx, 2};
rb.Push(result);
R_SUCCEED();
} }
Result IRS::RunImageTransferExProcessor( void IRS::RunImageTransferExProcessor(HLERequestContext& ctx) {
Core::IrSensor::IrCameraHandle camera_handle, ClientAppletResourceUserId aruid, IPC::RequestParser rp{ctx};
const Core::IrSensor::PackedImageTransferProcessorExConfig& processor_config, struct Parameters {
u64 transfer_memory_size, InCopyHandle<Kernel::KTransferMemory> t_mem) { Core::IrSensor::IrCameraHandle camera_handle;
INSERT_PADDING_WORDS_NOINIT(1);
u64 applet_resource_user_id;
Core::IrSensor::PackedImageTransferProcessorExConfig processor_config;
u64 transfer_memory_size;
};
static_assert(sizeof(Parameters) == 0x38, "Parameters has incorrect size.");
ASSERT_MSG(t_mem->GetSize() == transfer_memory_size, "t_mem has incorrect size"); const auto parameters{rp.PopRaw<Parameters>()};
const auto t_mem_handle{ctx.GetCopyHandle(0)};
auto t_mem = ctx.GetObjectFromHandle<Kernel::KTransferMemory>(t_mem_handle);
LOG_INFO(Service_IRS, LOG_INFO(Service_IRS,
"called, npad_type={}, npad_id={}, transfer_memory_size={}, " "called, npad_type={}, npad_id={}, transfer_memory_size={}, "
"applet_resource_user_id={}", "applet_resource_user_id={}",
camera_handle.npad_type, camera_handle.npad_id, transfer_memory_size, aruid.pid); parameters.camera_handle.npad_type, parameters.camera_handle.npad_id,
parameters.transfer_memory_size, parameters.applet_resource_user_id);
R_TRY(IsIrCameraHandleValid(camera_handle)); auto result = IsIrCameraHandleValid(parameters.camera_handle);
auto& device = GetIrCameraSharedMemoryDeviceEntry(camera_handle); if (result.IsSuccess()) {
MakeProcessorWithCoreContext<ImageTransferProcessor>(camera_handle, device); auto& device = GetIrCameraSharedMemoryDeviceEntry(parameters.camera_handle);
auto& image_transfer_processor = GetProcessor<ImageTransferProcessor>(camera_handle); MakeProcessorWithCoreContext<ImageTransferProcessor>(parameters.camera_handle, device);
image_transfer_processor.SetConfig(processor_config); auto& image_transfer_processor =
image_transfer_processor.SetTransferMemoryAddress(t_mem->GetSourceAddress()); GetProcessor<ImageTransferProcessor>(parameters.camera_handle);
npad_device->SetPollingMode(Core::HID::EmulatedDeviceIndex::RightIndex, image_transfer_processor.SetConfig(parameters.processor_config);
Common::Input::PollingMode::IR); image_transfer_processor.SetTransferMemoryAddress(t_mem->GetSourceAddress());
npad_device->SetPollingMode(Core::HID::EmulatedDeviceIndex::RightIndex,
Common::Input::PollingMode::IR);
}
R_SUCCEED(); IPC::ResponseBuilder rb{ctx, 2};
rb.Push(result);
} }
Result IRS::RunIrLedProcessor(Core::IrSensor::IrCameraHandle camera_handle, void IRS::RunIrLedProcessor(HLERequestContext& ctx) {
Core::IrSensor::PackedIrLedProcessorConfig processor_config, IPC::RequestParser rp{ctx};
ClientAppletResourceUserId aruid) { const auto camera_handle{rp.PopRaw<Core::IrSensor::IrCameraHandle>()};
const auto processor_config{rp.PopRaw<Core::IrSensor::PackedIrLedProcessorConfig>()};
const auto applet_resource_user_id{rp.Pop<u64>()};
LOG_WARNING(Service_IRS, LOG_WARNING(Service_IRS,
"(STUBBED) called, npad_type={}, npad_id={}, light_target={}, mcu_version={}.{} " "(STUBBED) called, npad_type={}, npad_id={}, light_target={}, mcu_version={}.{} "
"applet_resource_user_id={}", "applet_resource_user_id={}",
camera_handle.npad_type, camera_handle.npad_id, processor_config.light_target, camera_handle.npad_type, camera_handle.npad_id, processor_config.light_target,
processor_config.required_mcu_version.major, processor_config.required_mcu_version.major,
processor_config.required_mcu_version.minor, aruid.pid); processor_config.required_mcu_version.minor, applet_resource_user_id);
R_TRY(IsIrCameraHandleValid(camera_handle)); auto result = IsIrCameraHandleValid(camera_handle);
auto& device = GetIrCameraSharedMemoryDeviceEntry(camera_handle); if (result.IsSuccess()) {
MakeProcessor<IrLedProcessor>(camera_handle, device); auto& device = GetIrCameraSharedMemoryDeviceEntry(camera_handle);
auto& image_transfer_processor = GetProcessor<IrLedProcessor>(camera_handle); MakeProcessor<IrLedProcessor>(camera_handle, device);
image_transfer_processor.SetConfig(processor_config); auto& image_transfer_processor = GetProcessor<IrLedProcessor>(camera_handle);
npad_device->SetPollingMode(Core::HID::EmulatedDeviceIndex::RightIndex, image_transfer_processor.SetConfig(processor_config);
Common::Input::PollingMode::IR); npad_device->SetPollingMode(Core::HID::EmulatedDeviceIndex::RightIndex,
Common::Input::PollingMode::IR);
}
R_SUCCEED(); IPC::ResponseBuilder rb{ctx, 2};
rb.Push(result);
} }
Result IRS::StopImageProcessorAsync(Core::IrSensor::IrCameraHandle camera_handle, void IRS::StopImageProcessorAsync(HLERequestContext& ctx) {
ClientAppletResourceUserId aruid) { IPC::RequestParser rp{ctx};
struct Parameters {
Core::IrSensor::IrCameraHandle camera_handle;
INSERT_PADDING_WORDS_NOINIT(1);
u64 applet_resource_user_id;
};
static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
const auto parameters{rp.PopRaw<Parameters>()};
LOG_WARNING(Service_IRS, LOG_WARNING(Service_IRS,
"(STUBBED) called, npad_type={}, npad_id={}, applet_resource_user_id={}", "(STUBBED) called, npad_type={}, npad_id={}, applet_resource_user_id={}",
camera_handle.npad_type, camera_handle.npad_id, aruid.pid); parameters.camera_handle.npad_type, parameters.camera_handle.npad_id,
parameters.applet_resource_user_id);
R_TRY(IsIrCameraHandleValid(camera_handle)); auto result = IsIrCameraHandleValid(parameters.camera_handle);
if (result.IsSuccess()) {
// TODO: Stop image processor async
npad_device->SetPollingMode(Core::HID::EmulatedDeviceIndex::RightIndex,
Common::Input::PollingMode::Active);
result = ResultSuccess;
}
// TODO: Stop image processor async IPC::ResponseBuilder rb{ctx, 2};
npad_device->SetPollingMode(Core::HID::EmulatedDeviceIndex::RightIndex, rb.Push(result);
Common::Input::PollingMode::Active);
R_SUCCEED();
} }
Result IRS::ActivateIrsensorWithFunctionLevel(Core::IrSensor::PackedFunctionLevel function_level, void IRS::ActivateIrsensorWithFunctionLevel(HLERequestContext& ctx) {
ClientAppletResourceUserId aruid) { IPC::RequestParser rp{ctx};
struct Parameters {
Core::IrSensor::PackedFunctionLevel function_level;
INSERT_PADDING_WORDS_NOINIT(1);
u64 applet_resource_user_id;
};
static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
const auto parameters{rp.PopRaw<Parameters>()};
LOG_WARNING(Service_IRS, "(STUBBED) called, function_level={}, applet_resource_user_id={}", LOG_WARNING(Service_IRS, "(STUBBED) called, function_level={}, applet_resource_user_id={}",
function_level.function_level, aruid.pid); parameters.function_level.function_level, parameters.applet_resource_user_id);
R_SUCCEED();
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
} }
Result IRS::IsIrCameraHandleValid(const Core::IrSensor::IrCameraHandle& camera_handle) const { Result IRS::IsIrCameraHandleValid(const Core::IrSensor::IrCameraHandle& camera_handle) const {

View File

@ -4,7 +4,6 @@
#pragma once #pragma once
#include "core/core.h" #include "core/core.h"
#include "core/hle/service/cmif_types.h"
#include "core/hle/service/service.h" #include "core/hle/service/service.h"
#include "hid_core/hid_types.h" #include "hid_core/hid_types.h"
#include "hid_core/irsensor/irs_types.h" #include "hid_core/irsensor/irs_types.h"
@ -36,73 +35,26 @@ private:
}; };
static_assert(sizeof(StatusManager) == 0x8000, "StatusManager is an invalid size"); static_assert(sizeof(StatusManager) == 0x8000, "StatusManager is an invalid size");
Result ActivateIrsensor(ClientAppletResourceUserId aruid); void ActivateIrsensor(HLERequestContext& ctx);
void DeactivateIrsensor(HLERequestContext& ctx);
Result DeactivateIrsensor(ClientAppletResourceUserId aruid); void GetIrsensorSharedMemoryHandle(HLERequestContext& ctx);
void StopImageProcessor(HLERequestContext& ctx);
Result GetIrsensorSharedMemoryHandle(OutCopyHandle<Kernel::KSharedMemory> out_shared_memory, void RunMomentProcessor(HLERequestContext& ctx);
ClientAppletResourceUserId aruid); void RunClusteringProcessor(HLERequestContext& ctx);
Result StopImageProcessor(Core::IrSensor::IrCameraHandle camera_handle, void RunImageTransferProcessor(HLERequestContext& ctx);
ClientAppletResourceUserId aruid); void GetImageTransferProcessorState(HLERequestContext& ctx);
void RunTeraPluginProcessor(HLERequestContext& ctx);
Result RunMomentProcessor(Core::IrSensor::IrCameraHandle camera_handle, void GetNpadIrCameraHandle(HLERequestContext& ctx);
ClientAppletResourceUserId aruid, void RunPointingProcessor(HLERequestContext& ctx);
const Core::IrSensor::PackedMomentProcessorConfig& processor_config); void SuspendImageProcessor(HLERequestContext& ctx);
void CheckFirmwareVersion(HLERequestContext& ctx);
Result RunClusteringProcessor( void SetFunctionLevel(HLERequestContext& ctx);
Core::IrSensor::IrCameraHandle camera_handle, ClientAppletResourceUserId aruid, void RunImageTransferExProcessor(HLERequestContext& ctx);
const Core::IrSensor::PackedClusteringProcessorConfig& processor_config); void RunIrLedProcessor(HLERequestContext& ctx);
void StopImageProcessorAsync(HLERequestContext& ctx);
Result RunImageTransferProcessor( void ActivateIrsensorWithFunctionLevel(HLERequestContext& ctx);
Core::IrSensor::IrCameraHandle camera_handle, ClientAppletResourceUserId aruid,
const Core::IrSensor::PackedImageTransferProcessorConfig& processor_config,
u64 transfer_memory_size, InCopyHandle<Kernel::KTransferMemory> t_mem);
Result GetImageTransferProcessorState(
Out<Core::IrSensor::ImageTransferProcessorState> out_state,
Core::IrSensor::IrCameraHandle camera_handle, ClientAppletResourceUserId aruid,
OutBuffer<BufferAttr_HipcMapAlias> out_buffer_data);
Result RunTeraPluginProcessor(Core::IrSensor::IrCameraHandle camera_handle,
Core::IrSensor::PackedTeraPluginProcessorConfig processor_config,
ClientAppletResourceUserId aruid);
Result GetNpadIrCameraHandle(Out<Core::IrSensor::IrCameraHandle> out_camera_handle,
Core::HID::NpadIdType npad_id);
Result RunPointingProcessor(
Core::IrSensor::IrCameraHandle camera_handle,
const Core::IrSensor::PackedPointingProcessorConfig& processor_config,
ClientAppletResourceUserId aruid);
Result SuspendImageProcessor(Core::IrSensor::IrCameraHandle camera_handle,
ClientAppletResourceUserId aruid);
Result CheckFirmwareVersion(Core::IrSensor::IrCameraHandle camera_handle,
Core::IrSensor::PackedMcuVersion mcu_version,
ClientAppletResourceUserId aruid);
Result SetFunctionLevel(Core::IrSensor::IrCameraHandle camera_handle,
Core::IrSensor::PackedFunctionLevel function_level,
ClientAppletResourceUserId aruid);
Result RunImageTransferExProcessor(
Core::IrSensor::IrCameraHandle camera_handle, ClientAppletResourceUserId aruid,
const Core::IrSensor::PackedImageTransferProcessorExConfig& processor_config,
u64 transfer_memory_size, InCopyHandle<Kernel::KTransferMemory> t_mem);
Result RunIrLedProcessor(Core::IrSensor::IrCameraHandle camera_handle,
Core::IrSensor::PackedIrLedProcessorConfig processor_config,
ClientAppletResourceUserId aruid);
Result StopImageProcessorAsync(Core::IrSensor::IrCameraHandle camera_handle,
ClientAppletResourceUserId aruid);
Result ActivateIrsensorWithFunctionLevel(Core::IrSensor::PackedFunctionLevel function_level,
ClientAppletResourceUserId aruid);
Result IsIrCameraHandleValid(const Core::IrSensor::IrCameraHandle& camera_handle) const; Result IsIrCameraHandleValid(const Core::IrSensor::IrCameraHandle& camera_handle) const;
Core::IrSensor::DeviceFormat& GetIrCameraSharedMemoryDeviceEntry( Core::IrSensor::DeviceFormat& GetIrCameraSharedMemoryDeviceEntry(
const Core::IrSensor::IrCameraHandle& camera_handle); const Core::IrSensor::IrCameraHandle& camera_handle);

View File

@ -299,12 +299,8 @@ Result HLERequestContext::WriteToOutgoingCommandBuffer() {
if (GetManager()->IsDomain()) { if (GetManager()->IsDomain()) {
current_offset = domain_offset - static_cast<u32>(outgoing_domain_objects.size()); current_offset = domain_offset - static_cast<u32>(outgoing_domain_objects.size());
for (auto& object : outgoing_domain_objects) { for (auto& object : outgoing_domain_objects) {
if (object) { GetManager()->AppendDomainHandler(std::move(object));
GetManager()->AppendDomainHandler(std::move(object)); cmd_buf[current_offset++] = static_cast<u32_le>(GetManager()->DomainHandlerCount());
cmd_buf[current_offset++] = static_cast<u32_le>(GetManager()->DomainHandlerCount());
} else {
cmd_buf[current_offset++] = 0;
}
} }
} }

View File

@ -49,7 +49,6 @@ SessionId Container::OpenSession(Kernel::KProcess* process) {
continue; continue;
} }
if (session.process == process) { if (session.process == process) {
session.ref_count++;
return session.id; return session.id;
} }
} }
@ -67,7 +66,6 @@ SessionId Container::OpenSession(Kernel::KProcess* process) {
} }
auto& session = impl->sessions[new_id]; auto& session = impl->sessions[new_id];
session.is_active = true; session.is_active = true;
session.ref_count = 1;
// Optimization // Optimization
if (process->IsApplication()) { if (process->IsApplication()) {
auto& page_table = process->GetPageTable().GetBasePageTable(); auto& page_table = process->GetPageTable().GetBasePageTable();
@ -116,11 +114,8 @@ SessionId Container::OpenSession(Kernel::KProcess* process) {
void Container::CloseSession(SessionId session_id) { void Container::CloseSession(SessionId session_id) {
std::scoped_lock lk(impl->session_guard); std::scoped_lock lk(impl->session_guard);
auto& session = impl->sessions[session_id.id];
if (--session.ref_count > 0) {
return;
}
impl->file.UnmapAllHandles(session_id); impl->file.UnmapAllHandles(session_id);
auto& session = impl->sessions[session_id.id];
auto& smmu = impl->host1x.MemoryManager(); auto& smmu = impl->host1x.MemoryManager();
if (session.has_preallocated_area) { if (session.has_preallocated_area) {
const DAddr region_start = session.mapper->GetRegionStart(); const DAddr region_start = session.mapper->GetRegionStart();

View File

@ -46,7 +46,6 @@ struct Session {
bool has_preallocated_area{}; bool has_preallocated_area{};
std::unique_ptr<HeapMapper> mapper{}; std::unique_ptr<HeapMapper> mapper{};
bool is_active{}; bool is_active{};
s32 ref_count{};
}; };
class Container { class Container {
@ -68,7 +67,10 @@ public:
const SyncpointManager& GetSyncpointManager() const; const SyncpointManager& GetSyncpointManager() const;
struct Host1xDeviceFileData { struct Host1xDeviceFileData {
std::unordered_map<DeviceFD, u32> fd_to_id{};
std::deque<u32> syncpts_accumulated{}; std::deque<u32> syncpts_accumulated{};
u32 nvdec_next_id{};
u32 vic_next_id{};
}; };
Host1xDeviceFileData& Host1xDeviceFile(); Host1xDeviceFileData& Host1xDeviceFile();

View File

@ -3,21 +3,110 @@
#include <mutex> #include <mutex>
#include "common/range_sets.h" #include <boost/container/small_vector.hpp>
#include "common/range_sets.inc" #define BOOST_NO_MT
#include <boost/pool/detail/mutex.hpp>
#undef BOOST_NO_MT
#include <boost/icl/interval.hpp>
#include <boost/icl/interval_base_set.hpp>
#include <boost/icl/interval_set.hpp>
#include <boost/icl/split_interval_map.hpp>
#include <boost/pool/pool.hpp>
#include <boost/pool/pool_alloc.hpp>
#include <boost/pool/poolfwd.hpp>
#include "core/hle/service/nvdrv/core/heap_mapper.h" #include "core/hle/service/nvdrv/core/heap_mapper.h"
#include "video_core/host1x/host1x.h" #include "video_core/host1x/host1x.h"
namespace boost {
template <typename T>
class fast_pool_allocator<T, default_user_allocator_new_delete, details::pool::null_mutex, 4096, 0>;
}
namespace Service::Nvidia::NvCore { namespace Service::Nvidia::NvCore {
using IntervalCompare = std::less<DAddr>;
using IntervalInstance = boost::icl::interval_type_default<DAddr, std::less>;
using IntervalAllocator = boost::fast_pool_allocator<DAddr>;
using IntervalSet = boost::icl::interval_set<DAddr>;
using IntervalType = typename IntervalSet::interval_type;
template <typename Type>
struct counter_add_functor : public boost::icl::identity_based_inplace_combine<Type> {
// types
typedef counter_add_functor<Type> type;
typedef boost::icl::identity_based_inplace_combine<Type> base_type;
// public member functions
void operator()(Type& current, const Type& added) const {
current += added;
if (current < base_type::identity_element()) {
current = base_type::identity_element();
}
}
// public static functions
static void version(Type&){};
};
using OverlapCombine = counter_add_functor<int>;
using OverlapSection = boost::icl::inter_section<int>;
using OverlapCounter = boost::icl::split_interval_map<DAddr, int>;
struct HeapMapper::HeapMapperInternal { struct HeapMapper::HeapMapperInternal {
HeapMapperInternal(Tegra::Host1x::Host1x& host1x) : m_device_memory{host1x.MemoryManager()} {} HeapMapperInternal(Tegra::Host1x::Host1x& host1x) : device_memory{host1x.MemoryManager()} {}
~HeapMapperInternal() = default; ~HeapMapperInternal() = default;
Common::RangeSet<VAddr> m_temporary_set; template <typename Func>
Common::OverlapRangeSet<VAddr> m_mapped_ranges; void ForEachInOverlapCounter(OverlapCounter& current_range, VAddr cpu_addr, u64 size,
Tegra::MaxwellDeviceMemoryManager& m_device_memory; Func&& func) {
std::mutex m_guard; const DAddr start_address = cpu_addr;
const DAddr end_address = start_address + size;
const IntervalType search_interval{start_address, end_address};
auto it = current_range.lower_bound(search_interval);
if (it == current_range.end()) {
return;
}
auto end_it = current_range.upper_bound(search_interval);
for (; it != end_it; it++) {
auto& inter = it->first;
DAddr inter_addr_end = inter.upper();
DAddr inter_addr = inter.lower();
if (inter_addr_end > end_address) {
inter_addr_end = end_address;
}
if (inter_addr < start_address) {
inter_addr = start_address;
}
func(inter_addr, inter_addr_end, it->second);
}
}
void RemoveEachInOverlapCounter(OverlapCounter& current_range,
const IntervalType search_interval, int subtract_value) {
bool any_removals = false;
current_range.add(std::make_pair(search_interval, subtract_value));
do {
any_removals = false;
auto it = current_range.lower_bound(search_interval);
if (it == current_range.end()) {
return;
}
auto end_it = current_range.upper_bound(search_interval);
for (; it != end_it; it++) {
if (it->second <= 0) {
any_removals = true;
current_range.erase(it);
break;
}
}
} while (any_removals);
}
IntervalSet base_set;
OverlapCounter mapping_overlaps;
Tegra::MaxwellDeviceMemoryManager& device_memory;
std::mutex guard;
}; };
HeapMapper::HeapMapper(VAddr start_vaddress, DAddr start_daddress, size_t size, Core::Asid asid, HeapMapper::HeapMapper(VAddr start_vaddress, DAddr start_daddress, size_t size, Core::Asid asid,
@ -27,48 +116,60 @@ HeapMapper::HeapMapper(VAddr start_vaddress, DAddr start_daddress, size_t size,
} }
HeapMapper::~HeapMapper() { HeapMapper::~HeapMapper() {
// Unmap whatever has been mapped. m_internal->device_memory.Unmap(m_daddress, m_size);
m_internal->m_mapped_ranges.ForEach([this](VAddr start_addr, VAddr end_addr, s32 count) {
const size_t sub_size = end_addr - start_addr;
const size_t offset = start_addr - m_vaddress;
m_internal->m_device_memory.Unmap(m_daddress + offset, sub_size);
});
} }
DAddr HeapMapper::Map(VAddr start, size_t size) { DAddr HeapMapper::Map(VAddr start, size_t size) {
std::scoped_lock lk(m_internal->m_guard); std::scoped_lock lk(m_internal->guard);
// Add the mapping range to a temporary range set. m_internal->base_set.clear();
m_internal->m_temporary_set.Clear(); const IntervalType interval{start, start + size};
m_internal->m_temporary_set.Add(start, size); m_internal->base_set.insert(interval);
m_internal->ForEachInOverlapCounter(m_internal->mapping_overlaps, start, size,
// Remove anything that's already mapped from the temporary range set. [this](VAddr start_addr, VAddr end_addr, int) {
m_internal->m_mapped_ranges.ForEachInRange( const IntervalType other{start_addr, end_addr};
start, size, [this](VAddr start_addr, VAddr end_addr, s32) { m_internal->base_set.subtract(other);
m_internal->m_temporary_set.Subtract(start_addr, end_addr - start_addr); });
}); if (!m_internal->base_set.empty()) {
auto it = m_internal->base_set.begin();
// Map anything that has not been mapped yet. auto end_it = m_internal->base_set.end();
m_internal->m_temporary_set.ForEach([this](VAddr start_addr, VAddr end_addr) { for (; it != end_it; it++) {
const size_t sub_size = end_addr - start_addr; const VAddr inter_addr_end = it->upper();
const size_t offset = start_addr - m_vaddress; const VAddr inter_addr = it->lower();
m_internal->m_device_memory.Map(m_daddress + offset, m_vaddress + offset, sub_size, m_asid); const size_t offset = inter_addr - m_vaddress;
}); const size_t sub_size = inter_addr_end - inter_addr;
m_internal->device_memory.Map(m_daddress + offset, m_vaddress + offset, sub_size,
// Add the mapping range to the split map, to register the map and overlaps. m_asid);
m_internal->m_mapped_ranges.Add(start, size); }
m_internal->m_temporary_set.Clear(); }
return m_daddress + static_cast<DAddr>(start - m_vaddress); m_internal->mapping_overlaps += std::make_pair(interval, 1);
m_internal->base_set.clear();
return m_daddress + (start - m_vaddress);
} }
void HeapMapper::Unmap(VAddr start, size_t size) { void HeapMapper::Unmap(VAddr start, size_t size) {
std::scoped_lock lk(m_internal->m_guard); std::scoped_lock lk(m_internal->guard);
m_internal->base_set.clear();
// Just subtract the range and whatever is deleted, unmap it. m_internal->ForEachInOverlapCounter(m_internal->mapping_overlaps, start, size,
m_internal->m_mapped_ranges.Subtract(start, size, [this](VAddr start_addr, VAddr end_addr) { [this](VAddr start_addr, VAddr end_addr, int value) {
const size_t sub_size = end_addr - start_addr; if (value <= 1) {
const size_t offset = start_addr - m_vaddress; const IntervalType other{start_addr, end_addr};
m_internal->m_device_memory.Unmap(m_daddress + offset, sub_size); m_internal->base_set.insert(other);
}); }
});
if (!m_internal->base_set.empty()) {
auto it = m_internal->base_set.begin();
auto end_it = m_internal->base_set.end();
for (; it != end_it; it++) {
const VAddr inter_addr_end = it->upper();
const VAddr inter_addr = it->lower();
const size_t offset = inter_addr - m_vaddress;
const size_t sub_size = inter_addr_end - inter_addr;
m_internal->device_memory.Unmap(m_daddress + offset, sub_size);
}
}
const IntervalType to_remove{start, start + size};
m_internal->RemoveEachInOverlapCounter(m_internal->mapping_overlaps, to_remove, -1);
m_internal->base_set.clear();
} }
} // namespace Service::Nvidia::NvCore } // namespace Service::Nvidia::NvCore

View File

@ -333,13 +333,9 @@ void NvMap::UnmapAllHandles(NvCore::SessionId session_id) {
}(); }();
for (auto& [id, handle] : handles_copy) { for (auto& [id, handle] : handles_copy) {
{ if (handle->session_id.id == session_id.id) {
std::scoped_lock lk{handle->mutex}; FreeHandle(id, false);
if (handle->session_id.id != session_id.id || handle->dupes <= 0) {
continue;
}
} }
FreeHandle(id, false);
} }
} }

View File

@ -15,22 +15,6 @@
namespace Service::Nvidia::Devices { namespace Service::Nvidia::Devices {
namespace {
Tegra::BlendMode ConvertBlending(Service::Nvnflinger::LayerBlending blending) {
switch (blending) {
case Service::Nvnflinger::LayerBlending::None:
default:
return Tegra::BlendMode::Opaque;
case Service::Nvnflinger::LayerBlending::Premultiplied:
return Tegra::BlendMode::Premultiplied;
case Service::Nvnflinger::LayerBlending::Coverage:
return Tegra::BlendMode::Coverage;
}
}
} // namespace
nvdisp_disp0::nvdisp_disp0(Core::System& system_, NvCore::Container& core) nvdisp_disp0::nvdisp_disp0(Core::System& system_, NvCore::Container& core)
: nvdevice{system_}, container{core}, nvmap{core.GetNvMapFile()} {} : nvdevice{system_}, container{core}, nvmap{core.GetNvMapFile()} {}
nvdisp_disp0::~nvdisp_disp0() = default; nvdisp_disp0::~nvdisp_disp0() = default;
@ -72,7 +56,6 @@ void nvdisp_disp0::Composite(std::span<const Nvnflinger::HwcLayer> sorted_layers
.pixel_format = layer.format, .pixel_format = layer.format,
.transform_flags = layer.transform, .transform_flags = layer.transform,
.crop_rect = layer.crop_rect, .crop_rect = layer.crop_rect,
.blending = ConvertBlending(layer.blending),
}); });
for (size_t i = 0; i < layer.acquire_fence.num_fences; i++) { for (size_t i = 0; i < layer.acquire_fence.num_fences; i++) {

View File

@ -123,8 +123,6 @@ NvResult nvhost_as_gpu::AllocAsEx(IoctlAllocAsEx& params) {
vm.va_range_end = params.va_range_end; vm.va_range_end = params.va_range_end;
} }
const u64 max_big_page_bits = Common::Log2Ceil64(vm.va_range_end);
const auto start_pages{static_cast<u32>(vm.va_range_start >> VM::PAGE_SIZE_BITS)}; const auto start_pages{static_cast<u32>(vm.va_range_start >> VM::PAGE_SIZE_BITS)};
const auto end_pages{static_cast<u32>(vm.va_range_split >> VM::PAGE_SIZE_BITS)}; const auto end_pages{static_cast<u32>(vm.va_range_split >> VM::PAGE_SIZE_BITS)};
vm.small_page_allocator = std::make_shared<VM::Allocator>(start_pages, end_pages); vm.small_page_allocator = std::make_shared<VM::Allocator>(start_pages, end_pages);
@ -134,8 +132,8 @@ NvResult nvhost_as_gpu::AllocAsEx(IoctlAllocAsEx& params) {
static_cast<u32>((vm.va_range_end - vm.va_range_split) >> vm.big_page_size_bits)}; static_cast<u32>((vm.va_range_end - vm.va_range_split) >> vm.big_page_size_bits)};
vm.big_page_allocator = std::make_unique<VM::Allocator>(start_big_pages, end_big_pages); vm.big_page_allocator = std::make_unique<VM::Allocator>(start_big_pages, end_big_pages);
gmmu = std::make_shared<Tegra::MemoryManager>(system, max_big_page_bits, vm.va_range_split, gmmu = std::make_shared<Tegra::MemoryManager>(system, 40, vm.big_page_size_bits,
vm.big_page_size_bits, VM::PAGE_SIZE_BITS); VM::PAGE_SIZE_BITS);
system.GPU().InitAddressSpace(*gmmu); system.GPU().InitAddressSpace(*gmmu);
vm.initialised = true; vm.initialised = true;

View File

@ -8,7 +8,6 @@
#include "core/hle/service/nvdrv/core/container.h" #include "core/hle/service/nvdrv/core/container.h"
#include "core/hle/service/nvdrv/devices/ioctl_serialization.h" #include "core/hle/service/nvdrv/devices/ioctl_serialization.h"
#include "core/hle/service/nvdrv/devices/nvhost_nvdec.h" #include "core/hle/service/nvdrv/devices/nvhost_nvdec.h"
#include "video_core/host1x/host1x.h"
#include "video_core/renderer_base.h" #include "video_core/renderer_base.h"
namespace Service::Nvidia::Devices { namespace Service::Nvidia::Devices {
@ -22,8 +21,13 @@ NvResult nvhost_nvdec::Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> in
switch (command.group) { switch (command.group) {
case 0x0: case 0x0:
switch (command.cmd) { switch (command.cmd) {
case 0x1: case 0x1: {
auto& host1x_file = core.Host1xDeviceFile();
if (!host1x_file.fd_to_id.contains(fd)) {
host1x_file.fd_to_id[fd] = host1x_file.nvdec_next_id++;
}
return WrapFixedVariable(this, &nvhost_nvdec::Submit, input, output, fd); return WrapFixedVariable(this, &nvhost_nvdec::Submit, input, output, fd);
}
case 0x2: case 0x2:
return WrapFixed(this, &nvhost_nvdec::GetSyncpoint, input, output); return WrapFixed(this, &nvhost_nvdec::GetSyncpoint, input, output);
case 0x3: case 0x3:
@ -68,12 +72,15 @@ void nvhost_nvdec::OnOpen(NvCore::SessionId session_id, DeviceFD fd) {
LOG_INFO(Service_NVDRV, "NVDEC video stream started"); LOG_INFO(Service_NVDRV, "NVDEC video stream started");
system.SetNVDECActive(true); system.SetNVDECActive(true);
sessions[fd] = session_id; sessions[fd] = session_id;
host1x.StartDevice(fd, Tegra::Host1x::ChannelType::NvDec, channel_syncpoint);
} }
void nvhost_nvdec::OnClose(DeviceFD fd) { void nvhost_nvdec::OnClose(DeviceFD fd) {
LOG_INFO(Service_NVDRV, "NVDEC video stream ended"); LOG_INFO(Service_NVDRV, "NVDEC video stream ended");
host1x.StopDevice(fd, Tegra::Host1x::ChannelType::NvDec); auto& host1x_file = core.Host1xDeviceFile();
const auto iter = host1x_file.fd_to_id.find(fd);
if (iter != host1x_file.fd_to_id.end()) {
system.GPU().ClearCdmaInstance(iter->second);
}
system.SetNVDECActive(false); system.SetNVDECActive(false);
auto it = sessions.find(fd); auto it = sessions.find(fd);
if (it != sessions.end()) { if (it != sessions.end()) {

View File

@ -55,9 +55,8 @@ std::size_t WriteVectors(std::span<u8> dst, const std::vector<T>& src, std::size
nvhost_nvdec_common::nvhost_nvdec_common(Core::System& system_, NvCore::Container& core_, nvhost_nvdec_common::nvhost_nvdec_common(Core::System& system_, NvCore::Container& core_,
NvCore::ChannelType channel_type_) NvCore::ChannelType channel_type_)
: nvdevice{system_}, host1x{system_.Host1x()}, core{core_}, : nvdevice{system_}, core{core_}, syncpoint_manager{core.GetSyncpointManager()},
syncpoint_manager{core.GetSyncpointManager()}, nvmap{core.GetNvMapFile()}, nvmap{core.GetNvMapFile()}, channel_type{channel_type_} {
channel_type{channel_type_} {
auto& syncpts_accumulated = core.Host1xDeviceFile().syncpts_accumulated; auto& syncpts_accumulated = core.Host1xDeviceFile().syncpts_accumulated;
if (syncpts_accumulated.empty()) { if (syncpts_accumulated.empty()) {
channel_syncpoint = syncpoint_manager.AllocateSyncpoint(false); channel_syncpoint = syncpoint_manager.AllocateSyncpoint(false);
@ -96,24 +95,24 @@ NvResult nvhost_nvdec_common::Submit(IoctlSubmit& params, std::span<u8> data, De
offset += SliceVectors(data, syncpt_increments, params.syncpoint_count, offset); offset += SliceVectors(data, syncpt_increments, params.syncpoint_count, offset);
offset += SliceVectors(data, fence_thresholds, params.fence_count, offset); offset += SliceVectors(data, fence_thresholds, params.fence_count, offset);
auto& gpu = system.GPU();
auto* session = core.GetSession(sessions[fd]); auto* session = core.GetSession(sessions[fd]);
for (std::size_t i = 0; i < syncpt_increments.size(); i++) { if (gpu.UseNvdec()) {
const SyncptIncr& syncpt_incr = syncpt_increments[i]; for (std::size_t i = 0; i < syncpt_increments.size(); i++) {
fence_thresholds[i] = const SyncptIncr& syncpt_incr = syncpt_increments[i];
syncpoint_manager.IncrementSyncpointMaxExt(syncpt_incr.id, syncpt_incr.increments); fence_thresholds[i] =
syncpoint_manager.IncrementSyncpointMaxExt(syncpt_incr.id, syncpt_incr.increments);
}
} }
for (const auto& cmd_buffer : command_buffers) { for (const auto& cmd_buffer : command_buffers) {
const auto object = nvmap.GetHandle(cmd_buffer.memory_id); const auto object = nvmap.GetHandle(cmd_buffer.memory_id);
ASSERT_OR_EXECUTE(object, return NvResult::InvalidState;); ASSERT_OR_EXECUTE(object, return NvResult::InvalidState;);
Core::Memory::CpuGuestMemory<Tegra::ChCommandHeader, Tegra::ChCommandHeaderList cmdlist(cmd_buffer.word_count);
Core::Memory::GuestMemoryFlags::SafeRead> session->process->GetMemory().ReadBlock(object->address + cmd_buffer.offset, cmdlist.data(),
cmdlist(session->process->GetMemory(), object->address + cmd_buffer.offset, cmdlist.size() * sizeof(u32));
cmd_buffer.word_count); gpu.PushCommandBuffer(core.Host1xDeviceFile().fd_to_id[fd], cmdlist);
host1x.PushEntries(fd, std::move(cmdlist));
} }
// Some games expect command_buffers to be written back // Some games expect command_buffers to be written back
offset = 0; offset = 0;
offset += WriteVectors(data, command_buffers, offset); offset += WriteVectors(data, command_buffers, offset);

View File

@ -119,7 +119,6 @@ protected:
Kernel::KEvent* QueryEvent(u32 event_id) override; Kernel::KEvent* QueryEvent(u32 event_id) override;
Tegra::Host1x::Host1x& host1x;
u32 channel_syncpoint; u32 channel_syncpoint;
s32_le nvmap_fd{}; s32_le nvmap_fd{};
u32_le submit_timeout{}; u32_le submit_timeout{};

View File

@ -7,7 +7,6 @@
#include "core/hle/service/nvdrv/core/container.h" #include "core/hle/service/nvdrv/core/container.h"
#include "core/hle/service/nvdrv/devices/ioctl_serialization.h" #include "core/hle/service/nvdrv/devices/ioctl_serialization.h"
#include "core/hle/service/nvdrv/devices/nvhost_vic.h" #include "core/hle/service/nvdrv/devices/nvhost_vic.h"
#include "video_core/host1x/host1x.h"
#include "video_core/renderer_base.h" #include "video_core/renderer_base.h"
namespace Service::Nvidia::Devices { namespace Service::Nvidia::Devices {
@ -22,8 +21,13 @@ NvResult nvhost_vic::Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> inpu
switch (command.group) { switch (command.group) {
case 0x0: case 0x0:
switch (command.cmd) { switch (command.cmd) {
case 0x1: case 0x1: {
auto& host1x_file = core.Host1xDeviceFile();
if (!host1x_file.fd_to_id.contains(fd)) {
host1x_file.fd_to_id[fd] = host1x_file.vic_next_id++;
}
return WrapFixedVariable(this, &nvhost_vic::Submit, input, output, fd); return WrapFixedVariable(this, &nvhost_vic::Submit, input, output, fd);
}
case 0x2: case 0x2:
return WrapFixed(this, &nvhost_vic::GetSyncpoint, input, output); return WrapFixed(this, &nvhost_vic::GetSyncpoint, input, output);
case 0x3: case 0x3:
@ -66,11 +70,14 @@ NvResult nvhost_vic::Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> inpu
void nvhost_vic::OnOpen(NvCore::SessionId session_id, DeviceFD fd) { void nvhost_vic::OnOpen(NvCore::SessionId session_id, DeviceFD fd) {
sessions[fd] = session_id; sessions[fd] = session_id;
host1x.StartDevice(fd, Tegra::Host1x::ChannelType::VIC, channel_syncpoint);
} }
void nvhost_vic::OnClose(DeviceFD fd) { void nvhost_vic::OnClose(DeviceFD fd) {
host1x.StopDevice(fd, Tegra::Host1x::ChannelType::VIC); auto& host1x_file = core.Host1xDeviceFile();
const auto iter = host1x_file.fd_to_id.find(fd);
if (iter != host1x_file.fd_to_id.end()) {
system.GPU().ClearCdmaInstance(iter->second);
}
sessions.erase(fd); sessions.erase(fd);
} }

View File

@ -14,20 +14,24 @@
#include "core/hle/service/nvnflinger/ui/graphic_buffer.h" #include "core/hle/service/nvnflinger/ui/graphic_buffer.h"
#include "core/hle/service/vi/layer/vi_layer.h" #include "core/hle/service/vi/layer/vi_layer.h"
#include "core/hle/service/vi/vi_results.h" #include "core/hle/service/vi/vi_results.h"
#include "video_core/gpu.h"
#include "video_core/host1x/host1x.h"
namespace Service::Nvnflinger { namespace Service::Nvnflinger {
namespace { namespace {
Result AllocateSharedBufferMemory(std::unique_ptr<Kernel::KPageGroup>* out_page_group, Result AllocateIoForProcessAddressSpace(Common::ProcessAddress* out_map_address,
Core::System& system, u32 size) { std::unique_ptr<Kernel::KPageGroup>* out_page_group,
Core::System& system, u32 size) {
using Core::Memory::YUZU_PAGESIZE; using Core::Memory::YUZU_PAGESIZE;
// Allocate memory for the system shared buffer. // Allocate memory for the system shared buffer.
// FIXME: Because the gmmu can only point to cpu addresses, we need
// to map this in the application space to allow it to be used.
// FIXME: Add proper smmu emulation.
// FIXME: This memory belongs to vi's .data section. // FIXME: This memory belongs to vi's .data section.
auto& kernel = system.Kernel(); auto& kernel = system.Kernel();
auto* process = system.ApplicationProcess();
auto& page_table = process->GetPageTable();
// Hold a temporary page group reference while we try to map it. // Hold a temporary page group reference while we try to map it.
auto pg = std::make_unique<Kernel::KPageGroup>( auto pg = std::make_unique<Kernel::KPageGroup>(
@ -39,30 +43,6 @@ Result AllocateSharedBufferMemory(std::unique_ptr<Kernel::KPageGroup>* out_page_
Kernel::KMemoryManager::EncodeOption(Kernel::KMemoryManager::Pool::Secure, Kernel::KMemoryManager::EncodeOption(Kernel::KMemoryManager::Pool::Secure,
Kernel::KMemoryManager::Direction::FromBack))); Kernel::KMemoryManager::Direction::FromBack)));
// Fill the output data with red.
for (auto& block : *pg) {
u32* start = system.DeviceMemory().GetPointer<u32>(block.GetAddress());
u32* end = system.DeviceMemory().GetPointer<u32>(block.GetAddress() + block.GetSize());
for (; start < end; start++) {
*start = 0xFF0000FF;
}
}
// Return the mapped page group.
*out_page_group = std::move(pg);
// We succeeded.
R_SUCCEED();
}
Result MapSharedBufferIntoProcessAddressSpace(Common::ProcessAddress* out_map_address,
std::unique_ptr<Kernel::KPageGroup>& pg,
Kernel::KProcess* process, Core::System& system) {
using Core::Memory::YUZU_PAGESIZE;
auto& page_table = process->GetPageTable();
// Get bounds of where mapping is possible. // Get bounds of where mapping is possible.
const VAddr alias_code_begin = GetInteger(page_table.GetAliasCodeRegionStart()); const VAddr alias_code_begin = GetInteger(page_table.GetAliasCodeRegionStart());
const VAddr alias_code_size = page_table.GetAliasCodeRegionSize() / YUZU_PAGESIZE; const VAddr alias_code_size = page_table.GetAliasCodeRegionSize() / YUZU_PAGESIZE;
@ -84,6 +64,9 @@ Result MapSharedBufferIntoProcessAddressSpace(Common::ProcessAddress* out_map_ad
// Return failure, if necessary // Return failure, if necessary
R_UNLESS(i < 64, res); R_UNLESS(i < 64, res);
// Return the mapped page group.
*out_page_group = std::move(pg);
// We succeeded. // We succeeded.
R_SUCCEED(); R_SUCCEED();
} }
@ -152,13 +135,6 @@ Result AllocateHandleForBuffer(u32* out_handle, Nvidia::Module& nvdrv, Nvidia::D
R_RETURN(AllocNvMapHandle(*nvmap, *out_handle, buffer, size, nvmap_fd)); R_RETURN(AllocNvMapHandle(*nvmap, *out_handle, buffer, size, nvmap_fd));
} }
void FreeHandle(u32 handle, Nvidia::Module& nvdrv, Nvidia::DeviceFD nvmap_fd) {
auto nvmap = nvdrv.GetDevice<Nvidia::Devices::nvmap>(nvmap_fd);
ASSERT(nvmap != nullptr);
R_ASSERT(FreeNvMapHandle(*nvmap, handle, nvmap_fd));
}
constexpr auto SharedBufferBlockLinearFormat = android::PixelFormat::Rgba8888; constexpr auto SharedBufferBlockLinearFormat = android::PixelFormat::Rgba8888;
constexpr u32 SharedBufferBlockLinearBpp = 4; constexpr u32 SharedBufferBlockLinearBpp = 4;
@ -210,97 +186,53 @@ FbShareBufferManager::FbShareBufferManager(Core::System& system, Nvnflinger& fli
FbShareBufferManager::~FbShareBufferManager() = default; FbShareBufferManager::~FbShareBufferManager() = default;
Result FbShareBufferManager::Initialize(Kernel::KProcess* owner_process, u64* out_buffer_id, Result FbShareBufferManager::Initialize(u64* out_buffer_id, u64* out_layer_id, u64 display_id) {
u64* out_layer_handle, u64 display_id,
LayerBlending blending) {
std::scoped_lock lk{m_guard}; std::scoped_lock lk{m_guard};
// Ensure we haven't already created. // Ensure we have not already created a buffer.
const u64 aruid = owner_process->GetProcessId(); R_UNLESS(m_buffer_id == 0, VI::ResultOperationFailed);
R_UNLESS(!m_sessions.contains(aruid), VI::ResultPermissionDenied);
// Allocate memory for the shared buffer if needed. // Allocate memory and space for the shared buffer.
if (!m_buffer_page_group) { Common::ProcessAddress map_address;
R_TRY(AllocateSharedBufferMemory(std::addressof(m_buffer_page_group), m_system, R_TRY(AllocateIoForProcessAddressSpace(std::addressof(map_address),
SharedBufferSize)); std::addressof(m_buffer_page_group), m_system,
SharedBufferSize));
// Record buffer id.
m_buffer_id = m_next_buffer_id++;
// Record display id.
m_display_id = display_id;
}
// Map into process.
Common::ProcessAddress map_address{};
R_TRY(MapSharedBufferIntoProcessAddressSpace(std::addressof(map_address), m_buffer_page_group,
owner_process, m_system));
// Create new session.
auto [it, was_emplaced] = m_sessions.emplace(aruid, FbShareSession{});
auto& session = it->second;
auto& container = m_nvdrv->GetContainer(); auto& container = m_nvdrv->GetContainer();
session.session_id = container.OpenSession(owner_process); m_session_id = container.OpenSession(m_system.ApplicationProcess());
session.nvmap_fd = m_nvdrv->Open("/dev/nvmap", session.session_id); m_nvmap_fd = m_nvdrv->Open("/dev/nvmap", m_session_id);
// Create an nvmap handle for the buffer and assign the memory to it. // Create an nvmap handle for the buffer and assign the memory to it.
R_TRY(AllocateHandleForBuffer(std::addressof(session.buffer_nvmap_handle), *m_nvdrv, R_TRY(AllocateHandleForBuffer(std::addressof(m_buffer_nvmap_handle), *m_nvdrv, m_nvmap_fd,
session.nvmap_fd, map_address, SharedBufferSize)); map_address, SharedBufferSize));
// Record the display id.
m_display_id = display_id;
// Create and open a layer for the display. // Create and open a layer for the display.
session.layer_id = m_flinger.CreateLayer(m_display_id, blending).value(); m_layer_id = m_flinger.CreateLayer(m_display_id).value();
m_flinger.OpenLayer(session.layer_id); m_flinger.OpenLayer(m_layer_id);
// Set up the buffer.
m_buffer_id = m_next_buffer_id++;
// Get the layer. // Get the layer.
VI::Layer* layer = m_flinger.FindLayer(m_display_id, session.layer_id); VI::Layer* layer = m_flinger.FindLayer(m_display_id, m_layer_id);
ASSERT(layer != nullptr); ASSERT(layer != nullptr);
// Get the producer and set preallocated buffers. // Get the producer and set preallocated buffers.
auto& producer = layer->GetBufferQueue(); auto& producer = layer->GetBufferQueue();
MakeGraphicBuffer(producer, 0, session.buffer_nvmap_handle); MakeGraphicBuffer(producer, 0, m_buffer_nvmap_handle);
MakeGraphicBuffer(producer, 1, session.buffer_nvmap_handle); MakeGraphicBuffer(producer, 1, m_buffer_nvmap_handle);
// Assign outputs. // Assign outputs.
*out_buffer_id = m_buffer_id; *out_buffer_id = m_buffer_id;
*out_layer_handle = session.layer_id; *out_layer_id = m_layer_id;
// We succeeded. // We succeeded.
R_SUCCEED(); R_SUCCEED();
} }
void FbShareBufferManager::Finalize(Kernel::KProcess* owner_process) {
std::scoped_lock lk{m_guard};
if (m_buffer_id == 0) {
return;
}
const u64 aruid = owner_process->GetProcessId();
const auto it = m_sessions.find(aruid);
if (it == m_sessions.end()) {
return;
}
auto& session = it->second;
// Destroy the layer.
m_flinger.DestroyLayer(session.layer_id);
// Close nvmap handle.
FreeHandle(session.buffer_nvmap_handle, *m_nvdrv, session.nvmap_fd);
// Close nvmap device.
m_nvdrv->Close(session.nvmap_fd);
// Close session.
auto& container = m_nvdrv->GetContainer();
container.CloseSession(session.session_id);
// Erase.
m_sessions.erase(it);
}
Result FbShareBufferManager::GetSharedBufferMemoryHandleId(u64* out_buffer_size, Result FbShareBufferManager::GetSharedBufferMemoryHandleId(u64* out_buffer_size,
s32* out_nvmap_handle, s32* out_nvmap_handle,
SharedMemoryPoolLayout* out_pool_layout, SharedMemoryPoolLayout* out_pool_layout,
@ -310,18 +242,17 @@ Result FbShareBufferManager::GetSharedBufferMemoryHandleId(u64* out_buffer_size,
R_UNLESS(m_buffer_id > 0, VI::ResultNotFound); R_UNLESS(m_buffer_id > 0, VI::ResultNotFound);
R_UNLESS(buffer_id == m_buffer_id, VI::ResultNotFound); R_UNLESS(buffer_id == m_buffer_id, VI::ResultNotFound);
R_UNLESS(m_sessions.contains(applet_resource_user_id), VI::ResultNotFound);
*out_pool_layout = SharedBufferPoolLayout; *out_pool_layout = SharedBufferPoolLayout;
*out_buffer_size = SharedBufferSize; *out_buffer_size = SharedBufferSize;
*out_nvmap_handle = m_sessions[applet_resource_user_id].buffer_nvmap_handle; *out_nvmap_handle = m_buffer_nvmap_handle;
R_SUCCEED(); R_SUCCEED();
} }
Result FbShareBufferManager::GetLayerFromId(VI::Layer** out_layer, u64 layer_id) { Result FbShareBufferManager::GetLayerFromId(VI::Layer** out_layer, u64 layer_id) {
// Ensure the layer id is valid. // Ensure the layer id is valid.
R_UNLESS(layer_id > 0, VI::ResultNotFound); R_UNLESS(m_layer_id > 0 && layer_id == m_layer_id, VI::ResultNotFound);
// Get the layer. // Get the layer.
VI::Layer* layer = m_flinger.FindLayer(m_display_id, layer_id); VI::Layer* layer = m_flinger.FindLayer(m_display_id, layer_id);
@ -378,10 +309,6 @@ Result FbShareBufferManager::PresentSharedFrameBuffer(android::Fence fence,
android::Status::NoError, android::Status::NoError,
VI::ResultOperationFailed); VI::ResultOperationFailed);
ON_RESULT_FAILURE {
producer.CancelBuffer(static_cast<s32>(slot), fence);
};
// Queue the buffer to the producer. // Queue the buffer to the producer.
android::QueueBufferInput input{}; android::QueueBufferInput input{};
android::QueueBufferOutput output{}; android::QueueBufferOutput output{};
@ -415,33 +342,4 @@ Result FbShareBufferManager::GetSharedFrameBufferAcquirableEvent(Kernel::KReadab
R_SUCCEED(); R_SUCCEED();
} }
Result FbShareBufferManager::WriteAppletCaptureBuffer(bool* out_was_written, s32* out_layer_index) {
std::vector<u8> capture_buffer(m_system.GPU().GetAppletCaptureBuffer());
Common::ScratchBuffer<u32> scratch;
// TODO: this could be optimized
s64 e = -1280 * 768 * 4;
for (auto& block : *m_buffer_page_group) {
u8* start = m_system.DeviceMemory().GetPointer<u8>(block.GetAddress());
u8* end = m_system.DeviceMemory().GetPointer<u8>(block.GetAddress() + block.GetSize());
for (; start < end; start++) {
*start = 0;
if (e >= 0 && e < static_cast<s64>(capture_buffer.size())) {
*start = capture_buffer[e];
}
e++;
}
m_system.GPU().Host1x().MemoryManager().ApplyOpOnPointer(start, scratch, [&](DAddr addr) {
m_system.GPU().InvalidateRegion(addr, end - start);
});
}
*out_was_written = true;
*out_layer_index = 1;
R_SUCCEED();
}
} // namespace Service::Nvnflinger } // namespace Service::Nvnflinger

View File

@ -3,12 +3,9 @@
#pragma once #pragma once
#include <map>
#include "common/math_util.h" #include "common/math_util.h"
#include "core/hle/service/nvdrv/core/container.h" #include "core/hle/service/nvdrv/core/container.h"
#include "core/hle/service/nvdrv/nvdata.h" #include "core/hle/service/nvdrv/nvdata.h"
#include "core/hle/service/nvnflinger/hwc_layer.h"
#include "core/hle/service/nvnflinger/nvnflinger.h" #include "core/hle/service/nvnflinger/nvnflinger.h"
#include "core/hle/service/nvnflinger/ui/fence.h" #include "core/hle/service/nvnflinger/ui/fence.h"
@ -32,18 +29,13 @@ struct SharedMemoryPoolLayout {
}; };
static_assert(sizeof(SharedMemoryPoolLayout) == 0x188, "SharedMemoryPoolLayout has wrong size"); static_assert(sizeof(SharedMemoryPoolLayout) == 0x188, "SharedMemoryPoolLayout has wrong size");
struct FbShareSession;
class FbShareBufferManager final { class FbShareBufferManager final {
public: public:
explicit FbShareBufferManager(Core::System& system, Nvnflinger& flinger, explicit FbShareBufferManager(Core::System& system, Nvnflinger& flinger,
std::shared_ptr<Nvidia::Module> nvdrv); std::shared_ptr<Nvidia::Module> nvdrv);
~FbShareBufferManager(); ~FbShareBufferManager();
Result Initialize(Kernel::KProcess* owner_process, u64* out_buffer_id, u64* out_layer_handle, Result Initialize(u64* out_buffer_id, u64* out_layer_handle, u64 display_id);
u64 display_id, LayerBlending blending);
void Finalize(Kernel::KProcess* owner_process);
Result GetSharedBufferMemoryHandleId(u64* out_buffer_size, s32* out_nvmap_handle, Result GetSharedBufferMemoryHandleId(u64* out_buffer_size, s32* out_nvmap_handle,
SharedMemoryPoolLayout* out_pool_layout, u64 buffer_id, SharedMemoryPoolLayout* out_pool_layout, u64 buffer_id,
u64 applet_resource_user_id); u64 applet_resource_user_id);
@ -53,8 +45,6 @@ public:
u32 transform, s32 swap_interval, u64 layer_id, s64 slot); u32 transform, s32 swap_interval, u64 layer_id, s64 slot);
Result GetSharedFrameBufferAcquirableEvent(Kernel::KReadableEvent** out_event, u64 layer_id); Result GetSharedFrameBufferAcquirableEvent(Kernel::KReadableEvent** out_event, u64 layer_id);
Result WriteAppletCaptureBuffer(bool* out_was_written, s32* out_layer_index);
private: private:
Result GetLayerFromId(VI::Layer** out_layer, u64 layer_id); Result GetLayerFromId(VI::Layer** out_layer, u64 layer_id);
@ -62,8 +52,11 @@ private:
u64 m_next_buffer_id = 1; u64 m_next_buffer_id = 1;
u64 m_display_id = 0; u64 m_display_id = 0;
u64 m_buffer_id = 0; u64 m_buffer_id = 0;
u64 m_layer_id = 0;
u32 m_buffer_nvmap_handle = 0;
SharedMemoryPoolLayout m_pool_layout = {}; SharedMemoryPoolLayout m_pool_layout = {};
std::map<u64, FbShareSession> m_sessions; Nvidia::DeviceFD m_nvmap_fd = {};
Nvidia::NvCore::SessionId m_session_id = {};
std::unique_ptr<Kernel::KPageGroup> m_buffer_page_group; std::unique_ptr<Kernel::KPageGroup> m_buffer_page_group;
std::mutex m_guard; std::mutex m_guard;
@ -72,11 +65,4 @@ private:
std::shared_ptr<Nvidia::Module> m_nvdrv; std::shared_ptr<Nvidia::Module> m_nvdrv;
}; };
struct FbShareSession {
Nvidia::DeviceFD nvmap_fd = {};
Nvidia::NvCore::SessionId session_id = {};
u64 layer_id = {};
u32 buffer_nvmap_handle = 0;
};
} // namespace Service::Nvnflinger } // namespace Service::Nvnflinger

View File

@ -7,6 +7,7 @@
#include "core/hle/service/nvdrv/devices/nvdisp_disp0.h" #include "core/hle/service/nvdrv/devices/nvdisp_disp0.h"
#include "core/hle/service/nvnflinger/buffer_item.h" #include "core/hle/service/nvnflinger/buffer_item.h"
#include "core/hle/service/nvnflinger/buffer_item_consumer.h" #include "core/hle/service/nvnflinger/buffer_item_consumer.h"
#include "core/hle/service/nvnflinger/buffer_queue_producer.h"
#include "core/hle/service/nvnflinger/hardware_composer.h" #include "core/hle/service/nvnflinger/hardware_composer.h"
#include "core/hle/service/nvnflinger/hwc_layer.h" #include "core/hle/service/nvnflinger/hwc_layer.h"
#include "core/hle/service/nvnflinger/ui/graphic_buffer.h" #include "core/hle/service/nvnflinger/ui/graphic_buffer.h"
@ -45,9 +46,31 @@ HardwareComposer::HardwareComposer() = default;
HardwareComposer::~HardwareComposer() = default; HardwareComposer::~HardwareComposer() = default;
u32 HardwareComposer::ComposeLocked(f32* out_speed_scale, VI::Display& display, u32 HardwareComposer::ComposeLocked(f32* out_speed_scale, VI::Display& display,
Nvidia::Devices::nvdisp_disp0& nvdisp) { Nvidia::Devices::nvdisp_disp0& nvdisp, u32 frame_advance) {
boost::container::small_vector<HwcLayer, 2> composition_stack; boost::container::small_vector<HwcLayer, 2> composition_stack;
m_frame_number += frame_advance;
// Release any necessary framebuffers.
for (auto& [layer_id, framebuffer] : m_framebuffers) {
if (framebuffer.release_frame_number > m_frame_number) {
// Not yet ready to release this framebuffer.
continue;
}
if (!framebuffer.is_acquired) {
// Already released.
continue;
}
if (auto* layer = display.FindLayer(layer_id); layer != nullptr) {
// TODO: support release fence
// This is needed to prevent screen tearing
layer->GetConsumer().ReleaseBuffer(framebuffer.item, android::Fence::NoFence());
framebuffer.is_acquired = false;
}
}
// Set default speed limit to 100%. // Set default speed limit to 100%.
*out_speed_scale = 1.0f; *out_speed_scale = 1.0f;
@ -86,7 +109,6 @@ u32 HardwareComposer::ComposeLocked(f32* out_speed_scale, VI::Display& display,
.height = igbp_buffer.Height(), .height = igbp_buffer.Height(),
.stride = igbp_buffer.Stride(), .stride = igbp_buffer.Stride(),
.z_index = 0, .z_index = 0,
.blending = layer.GetBlending(),
.transform = static_cast<android::BufferTransformFlags>(item.transform), .transform = static_cast<android::BufferTransformFlags>(item.transform),
.crop_rect = item.crop, .crop_rect = item.crop,
.acquire_fence = item.fence, .acquire_fence = item.fence,
@ -120,30 +142,7 @@ u32 HardwareComposer::ComposeLocked(f32* out_speed_scale, VI::Display& display,
MicroProfileFlip(); MicroProfileFlip();
// Advance by at least one frame. // Advance by at least one frame.
const u32 frame_advance = swap_interval.value_or(1); return swap_interval.value_or(1);
m_frame_number += frame_advance;
// Release any necessary framebuffers.
for (auto& [layer_id, framebuffer] : m_framebuffers) {
if (framebuffer.release_frame_number > m_frame_number) {
// Not yet ready to release this framebuffer.
continue;
}
if (!framebuffer.is_acquired) {
// Already released.
continue;
}
if (auto* layer = display.FindLayer(layer_id); layer != nullptr) {
// TODO: support release fence
// This is needed to prevent screen tearing
layer->GetConsumer().ReleaseBuffer(framebuffer.item, android::Fence::NoFence());
framebuffer.is_acquired = false;
}
}
return frame_advance;
} }
void HardwareComposer::RemoveLayerLocked(VI::Display& display, LayerId layer_id) { void HardwareComposer::RemoveLayerLocked(VI::Display& display, LayerId layer_id) {

View File

@ -27,7 +27,7 @@ public:
~HardwareComposer(); ~HardwareComposer();
u32 ComposeLocked(f32* out_speed_scale, VI::Display& display, u32 ComposeLocked(f32* out_speed_scale, VI::Display& display,
Nvidia::Devices::nvdisp_disp0& nvdisp); Nvidia::Devices::nvdisp_disp0& nvdisp, u32 frame_advance);
void RemoveLayerLocked(VI::Display& display, LayerId layer_id); void RemoveLayerLocked(VI::Display& display, LayerId layer_id);
private: private:

View File

@ -11,18 +11,6 @@
namespace Service::Nvnflinger { namespace Service::Nvnflinger {
// hwc_layer_t::blending values
enum class LayerBlending : u32 {
// No blending
None = 0x100,
// ONE / ONE_MINUS_SRC_ALPHA
Premultiplied = 0x105,
// SRC_ALPHA / ONE_MINUS_SRC_ALPHA
Coverage = 0x405,
};
struct HwcLayer { struct HwcLayer {
u32 buffer_handle; u32 buffer_handle;
u32 offset; u32 offset;
@ -31,7 +19,6 @@ struct HwcLayer {
u32 height; u32 height;
u32 stride; u32 stride;
s32 z_index; s32 z_index;
LayerBlending blending;
android::BufferTransformFlags transform; android::BufferTransformFlags transform;
Common::Rectangle<int> crop_rect; Common::Rectangle<int> crop_rect;
android::Fence acquire_fence; android::Fence acquire_fence;

View File

@ -157,7 +157,7 @@ bool Nvnflinger::CloseDisplay(u64 display_id) {
return true; return true;
} }
std::optional<u64> Nvnflinger::CreateLayer(u64 display_id, LayerBlending blending) { std::optional<u64> Nvnflinger::CreateLayer(u64 display_id) {
const auto lock_guard = Lock(); const auto lock_guard = Lock();
auto* const display = FindDisplay(display_id); auto* const display = FindDisplay(display_id);
@ -166,14 +166,13 @@ std::optional<u64> Nvnflinger::CreateLayer(u64 display_id, LayerBlending blendin
} }
const u64 layer_id = next_layer_id++; const u64 layer_id = next_layer_id++;
CreateLayerAtId(*display, layer_id, blending); CreateLayerAtId(*display, layer_id);
return layer_id; return layer_id;
} }
void Nvnflinger::CreateLayerAtId(VI::Display& display, u64 layer_id, LayerBlending blending) { void Nvnflinger::CreateLayerAtId(VI::Display& display, u64 layer_id) {
const auto buffer_id = next_buffer_queue_id++; const auto buffer_id = next_buffer_queue_id++;
display.CreateLayer(layer_id, buffer_id, nvdrv->container); display.CreateLayer(layer_id, buffer_id, nvdrv->container);
display.FindLayer(layer_id)->SetBlending(blending);
} }
bool Nvnflinger::OpenLayer(u64 layer_id) { bool Nvnflinger::OpenLayer(u64 layer_id) {
@ -292,7 +291,8 @@ void Nvnflinger::Compose() {
auto nvdisp = nvdrv->GetDevice<Nvidia::Devices::nvdisp_disp0>(disp_fd); auto nvdisp = nvdrv->GetDevice<Nvidia::Devices::nvdisp_disp0>(disp_fd);
ASSERT(nvdisp); ASSERT(nvdisp);
swap_interval = display.GetComposer().ComposeLocked(&compose_speed_scale, display, *nvdisp); swap_interval = display.GetComposer().ComposeLocked(&compose_speed_scale, display, *nvdisp,
swap_interval);
} }
} }

View File

@ -15,7 +15,6 @@
#include "common/thread.h" #include "common/thread.h"
#include "core/hle/result.h" #include "core/hle/result.h"
#include "core/hle/service/kernel_helpers.h" #include "core/hle/service/kernel_helpers.h"
#include "core/hle/service/nvnflinger/hwc_layer.h"
namespace Common { namespace Common {
class Event; class Event;
@ -73,8 +72,7 @@ public:
/// Creates a layer on the specified display and returns the layer ID. /// Creates a layer on the specified display and returns the layer ID.
/// ///
/// If an invalid display ID is specified, then an empty optional is returned. /// If an invalid display ID is specified, then an empty optional is returned.
[[nodiscard]] std::optional<u64> CreateLayer(u64 display_id, [[nodiscard]] std::optional<u64> CreateLayer(u64 display_id);
LayerBlending blending = LayerBlending::None);
/// Opens a layer on all displays for the given layer ID. /// Opens a layer on all displays for the given layer ID.
bool OpenLayer(u64 layer_id); bool OpenLayer(u64 layer_id);
@ -130,7 +128,7 @@ private:
[[nodiscard]] VI::Layer* FindLayer(u64 display_id, u64 layer_id); [[nodiscard]] VI::Layer* FindLayer(u64 display_id, u64 layer_id);
/// Creates a layer with the specified layer ID in the desired display. /// Creates a layer with the specified layer ID in the desired display.
void CreateLayerAtId(VI::Display& display, u64 layer_id, LayerBlending blending); void CreateLayerAtId(VI::Display& display, u64 layer_id);
void SplitVSync(std::stop_token stop_token); void SplitVSync(std::stop_token stop_token);

View File

@ -1,7 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#include "core/hle/service/nvnflinger/hwc_layer.h"
#include "core/hle/service/vi/layer/vi_layer.h" #include "core/hle/service/vi/layer/vi_layer.h"
namespace Service::VI { namespace Service::VI {
@ -9,9 +8,8 @@ namespace Service::VI {
Layer::Layer(u64 layer_id_, u32 binder_id_, android::BufferQueueCore& core_, Layer::Layer(u64 layer_id_, u32 binder_id_, android::BufferQueueCore& core_,
android::BufferQueueProducer& binder_, android::BufferQueueProducer& binder_,
std::shared_ptr<android::BufferItemConsumer>&& consumer_) std::shared_ptr<android::BufferItemConsumer>&& consumer_)
: layer_id{layer_id_}, binder_id{binder_id_}, core{core_}, binder{binder_}, consumer{std::move( : layer_id{layer_id_}, binder_id{binder_id_}, core{core_}, binder{binder_},
consumer_)}, consumer{std::move(consumer_)}, open{false}, visible{true} {}
blending{Nvnflinger::LayerBlending::None}, open{false}, visible{true} {}
Layer::~Layer() = default; Layer::~Layer() = default;

View File

@ -14,10 +14,6 @@ class BufferQueueCore;
class BufferQueueProducer; class BufferQueueProducer;
} // namespace Service::android } // namespace Service::android
namespace Service::Nvnflinger {
enum class LayerBlending : u32;
}
namespace Service::VI { namespace Service::VI {
/// Represents a single display layer. /// Represents a single display layer.
@ -96,21 +92,12 @@ public:
return !std::exchange(open, true); return !std::exchange(open, true);
} }
Nvnflinger::LayerBlending GetBlending() {
return blending;
}
void SetBlending(Nvnflinger::LayerBlending b) {
blending = b;
}
private: private:
const u64 layer_id; const u64 layer_id;
const u32 binder_id; const u32 binder_id;
android::BufferQueueCore& core; android::BufferQueueCore& core;
android::BufferQueueProducer& binder; android::BufferQueueProducer& binder;
std::shared_ptr<android::BufferItemConsumer> consumer; std::shared_ptr<android::BufferItemConsumer> consumer;
Service::Nvnflinger::LayerBlending blending;
bool open; bool open;
bool visible; bool visible;
}; };

View File

@ -64,8 +64,6 @@ public:
Memory(Memory&&) = default; Memory(Memory&&) = default;
Memory& operator=(Memory&&) = delete; Memory& operator=(Memory&&) = delete;
static constexpr bool HAS_FLUSH_INVALIDATION = false;
/** /**
* Resets the state of the Memory system. * Resets the state of the Memory system.
*/ */

View File

@ -5,12 +5,10 @@
#include "common/hex_util.h" #include "common/hex_util.h"
#include "common/microprofile.h" #include "common/microprofile.h"
#include "common/swap.h" #include "common/swap.h"
#include "core/arm/debug.h"
#include "core/core.h" #include "core/core.h"
#include "core/core_timing.h" #include "core/core_timing.h"
#include "core/hle/kernel/k_page_table.h" #include "core/hle/kernel/k_page_table.h"
#include "core/hle/kernel/k_process.h" #include "core/hle/kernel/k_process.h"
#include "core/hle/kernel/k_process_page_table.h"
#include "core/hle/service/hid/hid_server.h" #include "core/hle/service/hid/hid_server.h"
#include "core/hle/service/sm/sm.h" #include "core/hle/service/sm/sm.h"
#include "core/memory.h" #include "core/memory.h"
@ -48,26 +46,12 @@ StandardVmCallbacks::StandardVmCallbacks(System& system_, const CheatProcessMeta
StandardVmCallbacks::~StandardVmCallbacks() = default; StandardVmCallbacks::~StandardVmCallbacks() = default;
void StandardVmCallbacks::MemoryReadUnsafe(VAddr address, void* data, u64 size) { void StandardVmCallbacks::MemoryRead(VAddr address, void* data, u64 size) {
// Return zero on invalid address system.ApplicationMemory().ReadBlock(SanitizeAddress(address), data, size);
if (!IsAddressInRange(address) || !system.ApplicationMemory().IsValidVirtualAddress(address)) {
std::memset(data, 0, size);
return;
}
system.ApplicationMemory().ReadBlock(address, data, size);
} }
void StandardVmCallbacks::MemoryWriteUnsafe(VAddr address, const void* data, u64 size) { void StandardVmCallbacks::MemoryWrite(VAddr address, const void* data, u64 size) {
// Skip invalid memory write address system.ApplicationMemory().WriteBlock(SanitizeAddress(address), data, size);
if (!IsAddressInRange(address) || !system.ApplicationMemory().IsValidVirtualAddress(address)) {
return;
}
if (system.ApplicationMemory().WriteBlock(address, data, size) &&
system.ApplicationProcess()->Is64Bit()) {
Core::InvalidateInstructionCacheRange(system.ApplicationProcess(), address, size);
}
} }
u64 StandardVmCallbacks::HidKeysDown() { u64 StandardVmCallbacks::HidKeysDown() {
@ -97,25 +81,21 @@ void StandardVmCallbacks::CommandLog(std::string_view data) {
data.back() == '\n' ? data.substr(0, data.size() - 1) : data); data.back() == '\n' ? data.substr(0, data.size() - 1) : data);
} }
bool StandardVmCallbacks::IsAddressInRange(VAddr in) const { VAddr StandardVmCallbacks::SanitizeAddress(VAddr in) const {
if ((in < metadata.main_nso_extents.base || if ((in < metadata.main_nso_extents.base ||
in >= metadata.main_nso_extents.base + metadata.main_nso_extents.size) && in >= metadata.main_nso_extents.base + metadata.main_nso_extents.size) &&
(in < metadata.heap_extents.base || (in < metadata.heap_extents.base ||
in >= metadata.heap_extents.base + metadata.heap_extents.size) && in >= metadata.heap_extents.base + metadata.heap_extents.size)) {
(in < metadata.alias_extents.base || LOG_ERROR(CheatEngine,
in >= metadata.heap_extents.base + metadata.alias_extents.size) &&
(in < metadata.aslr_extents.base ||
in >= metadata.heap_extents.base + metadata.aslr_extents.size)) {
LOG_DEBUG(CheatEngine,
"Cheat attempting to access memory at invalid address={:016X}, if this " "Cheat attempting to access memory at invalid address={:016X}, if this "
"persists, " "persists, "
"the cheat may be incorrect. However, this may be normal early in execution if " "the cheat may be incorrect. However, this may be normal early in execution if "
"the game has not properly set up yet.", "the game has not properly set up yet.",
in); in);
return false; ///< Invalid addresses will hard crash return 0; ///< Invalid addresses will hard crash
} }
return true; return in;
} }
CheatParser::~CheatParser() = default; CheatParser::~CheatParser() = default;
@ -231,14 +211,16 @@ void CheatEngine::Initialize() {
.base = GetInteger(page_table.GetHeapRegionStart()), .base = GetInteger(page_table.GetHeapRegionStart()),
.size = page_table.GetHeapRegionSize(), .size = page_table.GetHeapRegionSize(),
}; };
metadata.aslr_extents = {
metadata.address_space_extents = {
.base = GetInteger(page_table.GetAddressSpaceStart()),
.size = page_table.GetAddressSpaceSize(),
};
metadata.alias_extents = {
.base = GetInteger(page_table.GetAliasCodeRegionStart()), .base = GetInteger(page_table.GetAliasCodeRegionStart()),
.size = page_table.GetAliasCodeRegionSize(), .size = page_table.GetAliasCodeRegionSize(),
}; };
metadata.alias_extents = {
.base = GetInteger(page_table.GetAliasRegionStart()),
.size = page_table.GetAliasRegionSize(),
};
is_pending_reload.exchange(true); is_pending_reload.exchange(true);
} }

View File

@ -27,17 +27,17 @@ public:
StandardVmCallbacks(System& system_, const CheatProcessMetadata& metadata_); StandardVmCallbacks(System& system_, const CheatProcessMetadata& metadata_);
~StandardVmCallbacks() override; ~StandardVmCallbacks() override;
void MemoryReadUnsafe(VAddr address, void* data, u64 size) override; void MemoryRead(VAddr address, void* data, u64 size) override;
void MemoryWriteUnsafe(VAddr address, const void* data, u64 size) override; void MemoryWrite(VAddr address, const void* data, u64 size) override;
u64 HidKeysDown() override; u64 HidKeysDown() override;
void DebugLog(u8 id, u64 value) override; void DebugLog(u8 id, u64 value) override;
void CommandLog(std::string_view data) override; void CommandLog(std::string_view data) override;
private: private:
bool IsAddressInRange(VAddr address) const; VAddr SanitizeAddress(VAddr address) const;
const CheatProcessMetadata& metadata; const CheatProcessMetadata& metadata;
Core::System& system; System& system;
}; };
// Intermediary class that parses a text file or other disk format for storing cheats into a // Intermediary class that parses a text file or other disk format for storing cheats into a

View File

@ -18,7 +18,7 @@ struct CheatProcessMetadata {
MemoryRegionExtents main_nso_extents{}; MemoryRegionExtents main_nso_extents{};
MemoryRegionExtents heap_extents{}; MemoryRegionExtents heap_extents{};
MemoryRegionExtents alias_extents{}; MemoryRegionExtents alias_extents{};
MemoryRegionExtents aslr_extents{}; MemoryRegionExtents address_space_extents{};
std::array<u8, 0x20> main_nso_build_id{}; std::array<u8, 0x20> main_nso_build_id{};
}; };

View File

@ -322,9 +322,8 @@ bool DmntCheatVm::DecodeNextOpcode(CheatVmOpcode& out) {
} break; } break;
case CheatVmOpcodeType::EndConditionalBlock: { case CheatVmOpcodeType::EndConditionalBlock: {
// 20000000 // 20000000
opcode.opcode = EndConditionalOpcode{ // There's actually nothing left to process here!
.is_else = ((first_dword >> 24) & 0xf) == 1, opcode.opcode = EndConditionalOpcode{};
};
} break; } break;
case CheatVmOpcodeType::ControlLoop: { case CheatVmOpcodeType::ControlLoop: {
// 300R0000 VVVVVVVV // 300R0000 VVVVVVVV
@ -556,18 +555,6 @@ bool DmntCheatVm::DecodeNextOpcode(CheatVmOpcode& out) {
.idx = first_dword & 0xF, .idx = first_dword & 0xF,
}; };
} break; } break;
case CheatVmOpcodeType::PauseProcess: {
/* FF0????? */
/* FF0 = opcode 0xFF0 */
/* Pauses the current process. */
opcode.opcode = PauseProcessOpcode{};
} break;
case CheatVmOpcodeType::ResumeProcess: {
/* FF0????? */
/* FF0 = opcode 0xFF0 */
/* Pauses the current process. */
opcode.opcode = ResumeProcessOpcode{};
} break;
case CheatVmOpcodeType::DebugLog: { case CheatVmOpcodeType::DebugLog: {
// FFFTIX## // FFFTIX##
// FFFTI0Ma aaaaaaaa // FFFTI0Ma aaaaaaaa
@ -634,7 +621,7 @@ bool DmntCheatVm::DecodeNextOpcode(CheatVmOpcode& out) {
return valid; return valid;
} }
void DmntCheatVm::SkipConditionalBlock(bool is_if) { void DmntCheatVm::SkipConditionalBlock() {
if (condition_depth > 0) { if (condition_depth > 0) {
// We want to continue until we're out of the current block. // We want to continue until we're out of the current block.
const std::size_t desired_depth = condition_depth - 1; const std::size_t desired_depth = condition_depth - 1;
@ -650,12 +637,8 @@ void DmntCheatVm::SkipConditionalBlock(bool is_if) {
// We also support nesting of conditional blocks, and Gateway does not. // We also support nesting of conditional blocks, and Gateway does not.
if (skip_opcode.begin_conditional_block) { if (skip_opcode.begin_conditional_block) {
condition_depth++; condition_depth++;
} else if (auto end_cond = std::get_if<EndConditionalOpcode>(&skip_opcode.opcode)) { } else if (std::holds_alternative<EndConditionalOpcode>(skip_opcode.opcode)) {
if (!end_cond->is_else) { condition_depth--;
condition_depth--;
} else if (is_if && condition_depth - 1 == desired_depth) {
break;
}
} }
} }
} else { } else {
@ -692,10 +675,6 @@ u64 DmntCheatVm::GetCheatProcessAddress(const CheatProcessMetadata& metadata,
return metadata.main_nso_extents.base + rel_address; return metadata.main_nso_extents.base + rel_address;
case MemoryAccessType::Heap: case MemoryAccessType::Heap:
return metadata.heap_extents.base + rel_address; return metadata.heap_extents.base + rel_address;
case MemoryAccessType::Alias:
return metadata.alias_extents.base + rel_address;
case MemoryAccessType::Aslr:
return metadata.aslr_extents.base + rel_address;
} }
} }
@ -703,6 +682,7 @@ void DmntCheatVm::ResetState() {
registers.fill(0); registers.fill(0);
saved_values.fill(0); saved_values.fill(0);
loop_tops.fill(0); loop_tops.fill(0);
static_registers.fill(0);
instruction_ptr = 0; instruction_ptr = 0;
condition_depth = 0; condition_depth = 0;
decode_success = true; decode_success = true;
@ -773,7 +753,7 @@ void DmntCheatVm::Execute(const CheatProcessMetadata& metadata) {
case 2: case 2:
case 4: case 4:
case 8: case 8:
callbacks->MemoryWriteUnsafe(dst_address, &dst_value, store_static->bit_width); callbacks->MemoryWrite(dst_address, &dst_value, store_static->bit_width);
break; break;
} }
} else if (auto begin_cond = std::get_if<BeginConditionalOpcode>(&cur_opcode.opcode)) { } else if (auto begin_cond = std::get_if<BeginConditionalOpcode>(&cur_opcode.opcode)) {
@ -786,7 +766,7 @@ void DmntCheatVm::Execute(const CheatProcessMetadata& metadata) {
case 2: case 2:
case 4: case 4:
case 8: case 8:
callbacks->MemoryReadUnsafe(src_address, &src_value, begin_cond->bit_width); callbacks->MemoryRead(src_address, &src_value, begin_cond->bit_width);
break; break;
} }
// Check against condition. // Check against condition.
@ -814,18 +794,13 @@ void DmntCheatVm::Execute(const CheatProcessMetadata& metadata) {
} }
// Skip conditional block if condition not met. // Skip conditional block if condition not met.
if (!cond_met) { if (!cond_met) {
SkipConditionalBlock(true); SkipConditionalBlock();
} }
} else if (auto end_cond = std::get_if<EndConditionalOpcode>(&cur_opcode.opcode)) { } else if (std::holds_alternative<EndConditionalOpcode>(cur_opcode.opcode)) {
if (end_cond->is_else) { // Decrement the condition depth.
/* Skip to the end of the conditional block. */ // We will assume, graciously, that mismatched conditional block ends are a nop.
this->SkipConditionalBlock(false); if (condition_depth > 0) {
} else { condition_depth--;
/* Decrement the condition depth. */
/* We will assume, graciously, that mismatched conditional block ends are a nop. */
if (condition_depth > 0) {
condition_depth--;
}
} }
} else if (auto ctrl_loop = std::get_if<ControlLoopOpcode>(&cur_opcode.opcode)) { } else if (auto ctrl_loop = std::get_if<ControlLoopOpcode>(&cur_opcode.opcode)) {
if (ctrl_loop->start_loop) { if (ctrl_loop->start_loop) {
@ -857,8 +832,8 @@ void DmntCheatVm::Execute(const CheatProcessMetadata& metadata) {
case 2: case 2:
case 4: case 4:
case 8: case 8:
callbacks->MemoryReadUnsafe(src_address, &registers[ldr_memory->reg_index], callbacks->MemoryRead(src_address, &registers[ldr_memory->reg_index],
ldr_memory->bit_width); ldr_memory->bit_width);
break; break;
} }
} else if (auto str_static = std::get_if<StoreStaticToAddressOpcode>(&cur_opcode.opcode)) { } else if (auto str_static = std::get_if<StoreStaticToAddressOpcode>(&cur_opcode.opcode)) {
@ -874,7 +849,7 @@ void DmntCheatVm::Execute(const CheatProcessMetadata& metadata) {
case 2: case 2:
case 4: case 4:
case 8: case 8:
callbacks->MemoryWriteUnsafe(dst_address, &dst_value, str_static->bit_width); callbacks->MemoryWrite(dst_address, &dst_value, str_static->bit_width);
break; break;
} }
// Increment register if relevant. // Increment register if relevant.
@ -933,7 +908,7 @@ void DmntCheatVm::Execute(const CheatProcessMetadata& metadata) {
// Check for keypress. // Check for keypress.
if ((begin_keypress_cond->key_mask & kDown) != begin_keypress_cond->key_mask) { if ((begin_keypress_cond->key_mask & kDown) != begin_keypress_cond->key_mask) {
// Keys not pressed. Skip conditional block. // Keys not pressed. Skip conditional block.
SkipConditionalBlock(true); SkipConditionalBlock();
} }
} else if (auto perform_math_reg = } else if (auto perform_math_reg =
std::get_if<PerformArithmeticRegisterOpcode>(&cur_opcode.opcode)) { std::get_if<PerformArithmeticRegisterOpcode>(&cur_opcode.opcode)) {
@ -1032,7 +1007,7 @@ void DmntCheatVm::Execute(const CheatProcessMetadata& metadata) {
case 2: case 2:
case 4: case 4:
case 8: case 8:
callbacks->MemoryWriteUnsafe(dst_address, &dst_value, str_register->bit_width); callbacks->MemoryWrite(dst_address, &dst_value, str_register->bit_width);
break; break;
} }
@ -1111,8 +1086,7 @@ void DmntCheatVm::Execute(const CheatProcessMetadata& metadata) {
case 2: case 2:
case 4: case 4:
case 8: case 8:
callbacks->MemoryReadUnsafe(cond_address, &cond_value, callbacks->MemoryRead(cond_address, &cond_value, begin_reg_cond->bit_width);
begin_reg_cond->bit_width);
break; break;
} }
} }
@ -1142,7 +1116,7 @@ void DmntCheatVm::Execute(const CheatProcessMetadata& metadata) {
// Skip conditional block if condition not met. // Skip conditional block if condition not met.
if (!cond_met) { if (!cond_met) {
SkipConditionalBlock(true); SkipConditionalBlock();
} }
} else if (auto save_restore_reg = } else if (auto save_restore_reg =
std::get_if<SaveRestoreRegisterOpcode>(&cur_opcode.opcode)) { std::get_if<SaveRestoreRegisterOpcode>(&cur_opcode.opcode)) {
@ -1204,10 +1178,6 @@ void DmntCheatVm::Execute(const CheatProcessMetadata& metadata) {
// Store a register to a static register. // Store a register to a static register.
static_registers[rw_static_reg->static_idx] = registers[rw_static_reg->idx]; static_registers[rw_static_reg->static_idx] = registers[rw_static_reg->idx];
} }
} else if (std::holds_alternative<PauseProcessOpcode>(cur_opcode.opcode)) {
// TODO: Pause cheat process
} else if (std::holds_alternative<ResumeProcessOpcode>(cur_opcode.opcode)) {
// TODO: Resume cheat process
} else if (auto debug_log = std::get_if<DebugLogOpcode>(&cur_opcode.opcode)) { } else if (auto debug_log = std::get_if<DebugLogOpcode>(&cur_opcode.opcode)) {
// Read value from memory. // Read value from memory.
u64 log_value = 0; u64 log_value = 0;
@ -1254,7 +1224,7 @@ void DmntCheatVm::Execute(const CheatProcessMetadata& metadata) {
case 2: case 2:
case 4: case 4:
case 8: case 8:
callbacks->MemoryReadUnsafe(val_address, &log_value, debug_log->bit_width); callbacks->MemoryRead(val_address, &log_value, debug_log->bit_width);
break; break;
} }
} }

View File

@ -42,16 +42,12 @@ enum class CheatVmOpcodeType : u32 {
DoubleExtendedWidth = 0xF0, DoubleExtendedWidth = 0xF0,
// Double-extended width opcodes. // Double-extended width opcodes.
PauseProcess = 0xFF0,
ResumeProcess = 0xFF1,
DebugLog = 0xFFF, DebugLog = 0xFFF,
}; };
enum class MemoryAccessType : u32 { enum class MemoryAccessType : u32 {
MainNso = 0, MainNso = 0,
Heap = 1, Heap = 1,
Alias = 2,
Aslr = 3,
}; };
enum class ConditionalComparisonType : u32 { enum class ConditionalComparisonType : u32 {
@ -135,9 +131,7 @@ struct BeginConditionalOpcode {
VmInt value{}; VmInt value{};
}; };
struct EndConditionalOpcode { struct EndConditionalOpcode {};
bool is_else;
};
struct ControlLoopOpcode { struct ControlLoopOpcode {
bool start_loop{}; bool start_loop{};
@ -228,10 +222,6 @@ struct ReadWriteStaticRegisterOpcode {
u32 idx{}; u32 idx{};
}; };
struct PauseProcessOpcode {};
struct ResumeProcessOpcode {};
struct DebugLogOpcode { struct DebugLogOpcode {
u32 bit_width{}; u32 bit_width{};
u32 log_id{}; u32 log_id{};
@ -254,8 +244,8 @@ struct CheatVmOpcode {
PerformArithmeticStaticOpcode, BeginKeypressConditionalOpcode, PerformArithmeticStaticOpcode, BeginKeypressConditionalOpcode,
PerformArithmeticRegisterOpcode, StoreRegisterToAddressOpcode, PerformArithmeticRegisterOpcode, StoreRegisterToAddressOpcode,
BeginRegisterConditionalOpcode, SaveRestoreRegisterOpcode, BeginRegisterConditionalOpcode, SaveRestoreRegisterOpcode,
SaveRestoreRegisterMaskOpcode, ReadWriteStaticRegisterOpcode, PauseProcessOpcode, SaveRestoreRegisterMaskOpcode, ReadWriteStaticRegisterOpcode, DebugLogOpcode,
ResumeProcessOpcode, DebugLogOpcode, UnrecognizedInstruction> UnrecognizedInstruction>
opcode{}; opcode{};
}; };
@ -266,8 +256,8 @@ public:
public: public:
virtual ~Callbacks(); virtual ~Callbacks();
virtual void MemoryReadUnsafe(VAddr address, void* data, u64 size) = 0; virtual void MemoryRead(VAddr address, void* data, u64 size) = 0;
virtual void MemoryWriteUnsafe(VAddr address, const void* data, u64 size) = 0; virtual void MemoryWrite(VAddr address, const void* data, u64 size) = 0;
virtual u64 HidKeysDown() = 0; virtual u64 HidKeysDown() = 0;
@ -306,7 +296,7 @@ private:
std::array<std::size_t, NumRegisters> loop_tops{}; std::array<std::size_t, NumRegisters> loop_tops{};
bool DecodeNextOpcode(CheatVmOpcode& out); bool DecodeNextOpcode(CheatVmOpcode& out);
void SkipConditionalBlock(bool is_if); void SkipConditionalBlock();
void ResetState(); void ResetState();
// For implementing the DebugLog opcode. // For implementing the DebugLog opcode.

View File

@ -401,14 +401,6 @@ void Config::ReadNetworkValues() {
EndGroup(); EndGroup();
} }
void Config::ReadLibraryAppletValues() {
BeginGroup(Settings::TranslateCategory(Settings::Category::LibraryApplet));
ReadCategory(Settings::Category::LibraryApplet);
EndGroup();
}
void Config::ReadValues() { void Config::ReadValues() {
if (global) { if (global) {
ReadDataStorageValues(); ReadDataStorageValues();
@ -418,7 +410,6 @@ void Config::ReadValues() {
ReadServiceValues(); ReadServiceValues();
ReadWebServiceValues(); ReadWebServiceValues();
ReadMiscellaneousValues(); ReadMiscellaneousValues();
ReadLibraryAppletValues();
} }
ReadControlValues(); ReadControlValues();
ReadCoreValues(); ReadCoreValues();
@ -520,7 +511,6 @@ void Config::SaveValues() {
SaveNetworkValues(); SaveNetworkValues();
SaveWebServiceValues(); SaveWebServiceValues();
SaveMiscellaneousValues(); SaveMiscellaneousValues();
SaveLibraryAppletValues();
} else { } else {
LOG_DEBUG(Config, "Saving only generic configuration values"); LOG_DEBUG(Config, "Saving only generic configuration values");
} }
@ -701,14 +691,6 @@ void Config::SaveWebServiceValues() {
EndGroup(); EndGroup();
} }
void Config::SaveLibraryAppletValues() {
BeginGroup(Settings::TranslateCategory(Settings::Category::LibraryApplet));
WriteCategory(Settings::Category::LibraryApplet);
EndGroup();
}
bool Config::ReadBooleanSetting(const std::string& key, const std::optional<bool> default_value) { bool Config::ReadBooleanSetting(const std::string& key, const std::optional<bool> default_value) {
std::string full_key = GetFullKey(key, false); std::string full_key = GetFullKey(key, false);
if (!default_value.has_value()) { if (!default_value.has_value()) {

View File

@ -88,7 +88,6 @@ protected:
void ReadSystemValues(); void ReadSystemValues();
void ReadWebServiceValues(); void ReadWebServiceValues();
void ReadNetworkValues(); void ReadNetworkValues();
void ReadLibraryAppletValues();
// Read platform specific sections // Read platform specific sections
virtual void ReadHidbusValues() = 0; virtual void ReadHidbusValues() = 0;
@ -122,7 +121,6 @@ protected:
void SaveScreenshotValues(); void SaveScreenshotValues();
void SaveSystemValues(); void SaveSystemValues();
void SaveWebServiceValues(); void SaveWebServiceValues();
void SaveLibraryAppletValues();
// Save platform specific sections // Save platform specific sections
virtual void SaveHidbusValues() = 0; virtual void SaveHidbusValues() = 0;

View File

@ -160,7 +160,7 @@ public:
} }
// Returns a reply from a command // Returns a reply from a command
virtual u64 GetReply(std::span<u8> out_data) const { virtual std::vector<u8> GetReply() const {
return {}; return {};
} }

View File

@ -90,32 +90,32 @@ u8 RingController::GetDeviceId() const {
return device_id; return device_id;
} }
u64 RingController::GetReply(std::span<u8> out_data) const { std::vector<u8> RingController::GetReply() const {
const RingConCommands current_command = command; const RingConCommands current_command = command;
switch (current_command) { switch (current_command) {
case RingConCommands::GetFirmwareVersion: case RingConCommands::GetFirmwareVersion:
return GetFirmwareVersionReply(out_data); return GetFirmwareVersionReply();
case RingConCommands::ReadId: case RingConCommands::ReadId:
return GetReadIdReply(out_data); return GetReadIdReply();
case RingConCommands::c20105: case RingConCommands::c20105:
return GetC020105Reply(out_data); return GetC020105Reply();
case RingConCommands::ReadUnkCal: case RingConCommands::ReadUnkCal:
return GetReadUnkCalReply(out_data); return GetReadUnkCalReply();
case RingConCommands::ReadFactoryCal: case RingConCommands::ReadFactoryCal:
return GetReadFactoryCalReply(out_data); return GetReadFactoryCalReply();
case RingConCommands::ReadUserCal: case RingConCommands::ReadUserCal:
return GetReadUserCalReply(out_data); return GetReadUserCalReply();
case RingConCommands::ReadRepCount: case RingConCommands::ReadRepCount:
return GetReadRepCountReply(out_data); return GetReadRepCountReply();
case RingConCommands::ReadTotalPushCount: case RingConCommands::ReadTotalPushCount:
return GetReadTotalPushCountReply(out_data); return GetReadTotalPushCountReply();
case RingConCommands::ResetRepCount: case RingConCommands::ResetRepCount:
return GetResetRepCountReply(out_data); return GetResetRepCountReply();
case RingConCommands::SaveCalData: case RingConCommands::SaveCalData:
return GetSaveDataReply(out_data); return GetSaveDataReply();
default: default:
return GetErrorReply(out_data); return GetErrorReply();
} }
} }
@ -163,16 +163,16 @@ bool RingController::SetCommand(std::span<const u8> data) {
} }
} }
u64 RingController::GetFirmwareVersionReply(std::span<u8> out_data) const { std::vector<u8> RingController::GetFirmwareVersionReply() const {
const FirmwareVersionReply reply{ const FirmwareVersionReply reply{
.status = DataValid::Valid, .status = DataValid::Valid,
.firmware = version, .firmware = version,
}; };
return GetData(reply, out_data); return GetDataVector(reply);
} }
u64 RingController::GetReadIdReply(std::span<u8> out_data) const { std::vector<u8> RingController::GetReadIdReply() const {
// The values are hardcoded from a real joycon // The values are hardcoded from a real joycon
const ReadIdReply reply{ const ReadIdReply reply{
.status = DataValid::Valid, .status = DataValid::Valid,
@ -184,83 +184,83 @@ u64 RingController::GetReadIdReply(std::span<u8> out_data) const {
.id_h_x4 = 8245, .id_h_x4 = 8245,
}; };
return GetData(reply, out_data); return GetDataVector(reply);
} }
u64 RingController::GetC020105Reply(std::span<u8> out_data) const { std::vector<u8> RingController::GetC020105Reply() const {
const Cmd020105Reply reply{ const Cmd020105Reply reply{
.status = DataValid::Valid, .status = DataValid::Valid,
.data = 1, .data = 1,
}; };
return GetData(reply, out_data); return GetDataVector(reply);
} }
u64 RingController::GetReadUnkCalReply(std::span<u8> out_data) const { std::vector<u8> RingController::GetReadUnkCalReply() const {
const ReadUnkCalReply reply{ const ReadUnkCalReply reply{
.status = DataValid::Valid, .status = DataValid::Valid,
.data = 0, .data = 0,
}; };
return GetData(reply, out_data); return GetDataVector(reply);
} }
u64 RingController::GetReadFactoryCalReply(std::span<u8> out_data) const { std::vector<u8> RingController::GetReadFactoryCalReply() const {
const ReadFactoryCalReply reply{ const ReadFactoryCalReply reply{
.status = DataValid::Valid, .status = DataValid::Valid,
.calibration = factory_calibration, .calibration = factory_calibration,
}; };
return GetData(reply, out_data); return GetDataVector(reply);
} }
u64 RingController::GetReadUserCalReply(std::span<u8> out_data) const { std::vector<u8> RingController::GetReadUserCalReply() const {
const ReadUserCalReply reply{ const ReadUserCalReply reply{
.status = DataValid::Valid, .status = DataValid::Valid,
.calibration = user_calibration, .calibration = user_calibration,
}; };
return GetData(reply, out_data); return GetDataVector(reply);
} }
u64 RingController::GetReadRepCountReply(std::span<u8> out_data) const { std::vector<u8> RingController::GetReadRepCountReply() const {
const GetThreeByteReply reply{ const GetThreeByteReply reply{
.status = DataValid::Valid, .status = DataValid::Valid,
.data = {total_rep_count, 0, 0}, .data = {total_rep_count, 0, 0},
.crc = GetCrcValue({total_rep_count, 0, 0, 0}), .crc = GetCrcValue({total_rep_count, 0, 0, 0}),
}; };
return GetData(reply, out_data); return GetDataVector(reply);
} }
u64 RingController::GetReadTotalPushCountReply(std::span<u8> out_data) const { std::vector<u8> RingController::GetReadTotalPushCountReply() const {
const GetThreeByteReply reply{ const GetThreeByteReply reply{
.status = DataValid::Valid, .status = DataValid::Valid,
.data = {total_push_count, 0, 0}, .data = {total_push_count, 0, 0},
.crc = GetCrcValue({total_push_count, 0, 0, 0}), .crc = GetCrcValue({total_push_count, 0, 0, 0}),
}; };
return GetData(reply, out_data); return GetDataVector(reply);
} }
u64 RingController::GetResetRepCountReply(std::span<u8> out_data) const { std::vector<u8> RingController::GetResetRepCountReply() const {
return GetReadRepCountReply(out_data); return GetReadRepCountReply();
} }
u64 RingController::GetSaveDataReply(std::span<u8> out_data) const { std::vector<u8> RingController::GetSaveDataReply() const {
const StatusReply reply{ const StatusReply reply{
.status = DataValid::Valid, .status = DataValid::Valid,
}; };
return GetData(reply, out_data); return GetDataVector(reply);
} }
u64 RingController::GetErrorReply(std::span<u8> out_data) const { std::vector<u8> RingController::GetErrorReply() const {
const ErrorReply reply{ const ErrorReply reply{
.status = DataValid::BadCRC, .status = DataValid::BadCRC,
}; };
return GetData(reply, out_data); return GetDataVector(reply);
} }
u8 RingController::GetCrcValue(const std::vector<u8>& data) const { u8 RingController::GetCrcValue(const std::vector<u8>& data) const {
@ -281,11 +281,12 @@ u8 RingController::GetCrcValue(const std::vector<u8>& data) const {
} }
template <typename T> template <typename T>
u64 RingController::GetData(const T& reply, std::span<u8> out_data) const { std::vector<u8> RingController::GetDataVector(const T& reply) const {
static_assert(std::is_trivially_copyable_v<T>); static_assert(std::is_trivially_copyable_v<T>);
const auto data_size = static_cast<u64>(std::min(sizeof(reply), out_data.size())); std::vector<u8> data;
std::memcpy(out_data.data(), &reply, data_size); data.resize(sizeof(reply));
return data_size; std::memcpy(data.data(), &reply, sizeof(reply));
return data;
} }
} // namespace Service::HID } // namespace Service::HID

View File

@ -34,7 +34,7 @@ public:
bool SetCommand(std::span<const u8> data) override; bool SetCommand(std::span<const u8> data) override;
// Returns a reply from a command // Returns a reply from a command
u64 GetReply(std::span<u8> data) const override; std::vector<u8> GetReply() const override;
private: private:
// These values are obtained from a real ring controller // These values are obtained from a real ring controller
@ -184,44 +184,44 @@ private:
RingConData GetSensorValue() const; RingConData GetSensorValue() const;
// Returns 8 byte reply with firmware version // Returns 8 byte reply with firmware version
u64 GetFirmwareVersionReply(std::span<u8> out_data) const; std::vector<u8> GetFirmwareVersionReply() const;
// Returns 16 byte reply with ID values // Returns 16 byte reply with ID values
u64 GetReadIdReply(std::span<u8> out_data) const; std::vector<u8> GetReadIdReply() const;
// (STUBBED) Returns 8 byte reply // (STUBBED) Returns 8 byte reply
u64 GetC020105Reply(std::span<u8> out_data) const; std::vector<u8> GetC020105Reply() const;
// (STUBBED) Returns 8 byte empty reply // (STUBBED) Returns 8 byte empty reply
u64 GetReadUnkCalReply(std::span<u8> out_data) const; std::vector<u8> GetReadUnkCalReply() const;
// Returns 20 byte reply with factory calibration values // Returns 20 byte reply with factory calibration values
u64 GetReadFactoryCalReply(std::span<u8> out_data) const; std::vector<u8> GetReadFactoryCalReply() const;
// Returns 20 byte reply with user calibration values // Returns 20 byte reply with user calibration values
u64 GetReadUserCalReply(std::span<u8> out_data) const; std::vector<u8> GetReadUserCalReply() const;
// Returns 8 byte reply // Returns 8 byte reply
u64 GetReadRepCountReply(std::span<u8> out_data) const; std::vector<u8> GetReadRepCountReply() const;
// Returns 8 byte reply // Returns 8 byte reply
u64 GetReadTotalPushCountReply(std::span<u8> out_data) const; std::vector<u8> GetReadTotalPushCountReply() const;
// Returns 8 byte reply // Returns 8 byte reply
u64 GetResetRepCountReply(std::span<u8> out_data) const; std::vector<u8> GetResetRepCountReply() const;
// Returns 4 byte save data reply // Returns 4 byte save data reply
u64 GetSaveDataReply(std::span<u8> out_data) const; std::vector<u8> GetSaveDataReply() const;
// Returns 8 byte error reply // Returns 8 byte error reply
u64 GetErrorReply(std::span<u8> out_data) const; std::vector<u8> GetErrorReply() const;
// Returns 8 bit redundancy check from provided data // Returns 8 bit redundancy check from provided data
u8 GetCrcValue(const std::vector<u8>& data) const; u8 GetCrcValue(const std::vector<u8>& data) const;
// Converts structs to an u8 vector equivalent // Converts structs to an u8 vector equivalent
template <typename T> template <typename T>
u64 GetData(const T& reply, std::span<u8> out_data) const; std::vector<u8> GetDataVector(const T& reply) const;
RingConCommands command{RingConCommands::Error}; RingConCommands command{RingConCommands::Error};

View File

@ -38,7 +38,7 @@ u8 Starlink::GetDeviceId() const {
return DEVICE_ID; return DEVICE_ID;
} }
u64 Starlink::GetReply(std::span<u8> out_data) const { std::vector<u8> Starlink::GetReply() const {
return {}; return {};
} }

View File

@ -31,7 +31,7 @@ public:
bool SetCommand(std::span<const u8> data) override; bool SetCommand(std::span<const u8> data) override;
// Returns a reply from a command // Returns a reply from a command
u64 GetReply(std::span<u8> out_data) const override; std::vector<u8> GetReply() const override;
}; };
} // namespace Service::HID } // namespace Service::HID

View File

@ -38,7 +38,7 @@ u8 HidbusStubbed::GetDeviceId() const {
return DEVICE_ID; return DEVICE_ID;
} }
u64 HidbusStubbed::GetReply(std::span<u8> out_data) const { std::vector<u8> HidbusStubbed::GetReply() const {
return {}; return {};
} }

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