Compare commits
96 Commits
__refs_pul
...
__refs_pul
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4677fd3f64 | ||
|
|
b206ea5cfe | ||
|
|
70590f79f8 | ||
|
|
fa12384350 | ||
|
|
78aac6b403 | ||
|
|
0cb413c3d3 | ||
|
|
962c82540c | ||
|
|
06fd7f2012 | ||
|
|
0cbb555e9a | ||
|
|
2e8c21ad2d | ||
|
|
f9a559d2b7 | ||
|
|
03a23c037a | ||
|
|
71e59bdcd8 | ||
|
|
0a1283f94f | ||
|
|
f049453dd6 | ||
|
|
cac37a6f6e | ||
|
|
263dfa95e4 | ||
|
|
bc9711cb1e | ||
|
|
b4d88a7bb4 | ||
|
|
ae833aa9c0 | ||
|
|
4463ded603 | ||
|
|
159dec01ee | ||
|
|
6319bafafa | ||
|
|
c000a5ff09 | ||
|
|
12f86f89fc | ||
|
|
9858ea79fb | ||
|
|
c10e720ba9 | ||
|
|
5016de3626 | ||
|
|
d5fb9fd12c | ||
|
|
c79b3af610 | ||
|
|
c0a383d960 | ||
|
|
b6106604c4 | ||
|
|
12b6162852 | ||
|
|
8f192b494a | ||
|
|
372897aac4 | ||
|
|
fa47ac1c9f | ||
|
|
a2f23746c2 | ||
|
|
215b13f2a2 | ||
|
|
35ed9425d7 | ||
|
|
74cc8721c7 | ||
|
|
8ef1db78b0 | ||
|
|
18c8f10ff2 | ||
|
|
96d881f087 | ||
|
|
0e950baf41 | ||
|
|
8113f55f4b | ||
|
|
f296a9ce9a | ||
|
|
ddbefc71cb | ||
|
|
0d5a3abeae | ||
|
|
85143e8376 | ||
|
|
504abbd6e0 | ||
|
|
accccc0cbf | ||
|
|
01ba6cf610 | ||
|
|
4841dc0b74 | ||
|
|
185125e4e4 | ||
|
|
99ea31faa8 | ||
|
|
9ade941de1 | ||
|
|
4cccbe7989 | ||
|
|
5eb5c96750 | ||
|
|
5da55cbac9 | ||
|
|
81cc4df1f9 | ||
|
|
25f3d358b1 | ||
|
|
a3c8bb251d | ||
|
|
327533be1f | ||
|
|
61ea2115c7 | ||
|
|
108a72ea8a | ||
|
|
fb3ef957bb | ||
|
|
78f72b3bf5 | ||
|
|
6baf965777 | ||
|
|
3f86b339f3 | ||
|
|
32d38a5df6 | ||
|
|
3ac46aeced | ||
|
|
58cf2ee1f9 | ||
|
|
c74b5f9ee6 | ||
|
|
11a8ef6640 | ||
|
|
b51b47e707 | ||
|
|
35e3c68028 | ||
|
|
f740d8b9be | ||
|
|
2c421a7046 | ||
|
|
a595e9e8a7 | ||
|
|
10cf058518 | ||
|
|
9bdf09bd76 | ||
|
|
d4de04584f | ||
|
|
dd2918efd8 | ||
|
|
2ed9586130 | ||
|
|
b78900e956 | ||
|
|
60ee29aac3 | ||
|
|
b90eff4bc6 | ||
|
|
0c2e5b64c9 | ||
|
|
9568b310be | ||
|
|
2b1dd3bef5 | ||
|
|
453091f611 | ||
|
|
80de01a5b4 | ||
|
|
442aad9b27 | ||
|
|
8e0f97ac96 | ||
|
|
345d691328 | ||
|
|
41149d061d |
21
.ci/scripts/android/eabuild.sh
Normal file
21
.ci/scripts/android/eabuild.sh
Normal file
@@ -0,0 +1,21 @@
|
||||
#!/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
|
||||
21
.ci/scripts/android/mainlinebuild.sh
Normal file
21
.ci/scripts/android/mainlinebuild.sh
Normal file
@@ -0,0 +1,21 @@
|
||||
#!/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
|
||||
66
.github/workflows/android-ea-play-release.yml
vendored
Normal file
66
.github/workflows/android-ea-play-release.yml
vendored
Normal file
@@ -0,0 +1,66 @@
|
||||
# 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 }}
|
||||
59
.github/workflows/android-mainline-play-release.yml
vendored
Normal file
59
.github/workflows/android-mainline-play-release.yml
vendored
Normal file
@@ -0,0 +1,59 @@
|
||||
# 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
|
||||
129
.github/workflows/android-merge.js
vendored
129
.github/workflows/android-merge.js
vendored
@@ -6,9 +6,12 @@
|
||||
|
||||
const fs = require("fs");
|
||||
// which label to check for changes
|
||||
const CHANGE_LABEL = 'android-merge';
|
||||
const CHANGE_LABEL_MAINLINE = 'android-merge';
|
||||
const CHANGE_LABEL_EA = 'android-ea-merge';
|
||||
// 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 BUILD_EA = process.env.BUILD_EA == 'true';
|
||||
const MAINLINE_TAG = process.env.MAINLINE_TAG;
|
||||
|
||||
async function checkBaseChanges(github) {
|
||||
// query the commit date of the latest commit on this branch
|
||||
@@ -40,20 +43,7 @@ async function checkBaseChanges(github) {
|
||||
|
||||
async function checkAndroidChanges(github) {
|
||||
if (checkBaseChanges(github)) return true;
|
||||
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;
|
||||
const pulls = getPulls(github, false);
|
||||
for (let i = 0; i < pulls.length; i++) {
|
||||
let pull = pulls[i];
|
||||
if (new Date() - new Date(pull.headRepository.pushedAt) <= DETECTION_TIME_FRAME) {
|
||||
@@ -83,7 +73,13 @@ async function tagAndPush(github, owner, repo, execa, commit=false) {
|
||||
};
|
||||
const tags = await github.graphql(query, variables);
|
||||
const tagList = tags.repository.refs.nodes;
|
||||
const lastTag = tagList[0] ? tagList[0].name : 'dummy-0';
|
||||
let lastTag = 'android-1';
|
||||
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 channel = repo.split('-')[1];
|
||||
const newTag = `${channel}-${tagNumber + 1}`;
|
||||
@@ -101,6 +97,48 @@ async function tagAndPush(github, owner, repo, execa, commit=false) {
|
||||
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) {
|
||||
let baseUrl = `https://github.com/${context.repo.owner}/${context.repo.repo}/`;
|
||||
let output =
|
||||
@@ -202,10 +240,7 @@ async function resetBranch(execa) {
|
||||
}
|
||||
}
|
||||
|
||||
async function mergebot(github, context, execa) {
|
||||
// Reset our local copy of master to what appears on yuzu-emu/yuzu - master
|
||||
await resetBranch(execa);
|
||||
|
||||
async function getPulls(github) {
|
||||
const query = `query ($owner:String!, $name:String!, $label:String!) {
|
||||
repository(name:$name, owner:$owner) {
|
||||
pullRequests(labels: [$label], states: OPEN, first: 100) {
|
||||
@@ -215,13 +250,49 @@ async function mergebot(github, context, execa) {
|
||||
}
|
||||
}
|
||||
}`;
|
||||
const variables = {
|
||||
const mainlineVariables = {
|
||||
owner: 'yuzu-emu',
|
||||
name: 'yuzu',
|
||||
label: CHANGE_LABEL,
|
||||
label: CHANGE_LABEL_MAINLINE,
|
||||
};
|
||||
const result = await github.graphql(query, variables);
|
||||
const pulls = result.repository.pullRequests.nodes;
|
||||
const mainlineResult = await github.graphql(query, mainlineVariables);
|
||||
const pulls = mainlineResult.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 = [];
|
||||
for (let i = 0; i < pulls.length; i++) {
|
||||
let pull = pulls[i];
|
||||
@@ -231,11 +302,17 @@ async function mergebot(github, context, execa) {
|
||||
console.table(displayList);
|
||||
await fetchPullRequests(pulls, "https://github.com/yuzu-emu/yuzu", execa);
|
||||
const mergeResults = await mergePullRequests(pulls, execa);
|
||||
await generateReadme(pulls, context, mergeResults, execa);
|
||||
await tagAndPush(github, 'yuzu-emu', `yuzu-android`, execa, true);
|
||||
|
||||
if (BUILD_EA) {
|
||||
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.checkAndroidChanges = checkAndroidChanges;
|
||||
module.exports.tagAndPush = tagAndPush;
|
||||
module.exports.checkBaseChanges = checkBaseChanges;
|
||||
module.exports.getMainlineTag = getMainlineTag;
|
||||
|
||||
4
.github/workflows/android-publish.yml
vendored
4
.github/workflows/android-publish.yml
vendored
@@ -1,4 +1,4 @@
|
||||
# SPDX-FileCopyrightText: 2023 yuzu Emulator Project
|
||||
# SPDX-FileCopyrightText: 2024 yuzu Emulator Project
|
||||
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
name: yuzu-android-publish
|
||||
@@ -16,7 +16,7 @@ on:
|
||||
jobs:
|
||||
android:
|
||||
runs-on: ubuntu-latest
|
||||
if: ${{ github.event.inputs.android != 'false' && github.repository == 'yuzu-emu/yuzu-android' }}
|
||||
if: ${{ github.event.inputs.android != 'false' && github.repository == 'yuzu-emu/yuzu' }}
|
||||
steps:
|
||||
# this checkout is required to make sure the GitHub Actions scripts are available
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
@@ -307,7 +307,7 @@ find_package(ZLIB 1.2 REQUIRED)
|
||||
find_package(zstd 1.5 REQUIRED)
|
||||
|
||||
if (NOT YUZU_USE_EXTERNAL_VULKAN_HEADERS)
|
||||
find_package(Vulkan 1.3.274 REQUIRED)
|
||||
find_package(VulkanHeaders 1.3.274 REQUIRED)
|
||||
endif()
|
||||
|
||||
if (NOT YUZU_USE_EXTERNAL_VULKAN_UTILITY_LIBRARIES)
|
||||
|
||||
1
dist/languages/.tx/config
vendored
1
dist/languages/.tx/config
vendored
@@ -11,3 +11,4 @@ type = QT
|
||||
file_filter = ../../src/android/app/src/main/res/values-<lang>/strings.xml
|
||||
source_file = ../../src/android/app/src/main/res/values/strings.xml
|
||||
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
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import kotlin.collections.setOf
|
||||
import org.jetbrains.kotlin.konan.properties.Properties
|
||||
import org.jlleitschuh.gradle.ktlint.reporter.ReporterType
|
||||
import com.github.triplet.gradle.androidpublisher.ReleaseStatus
|
||||
|
||||
plugins {
|
||||
id("com.android.application")
|
||||
@@ -13,6 +13,7 @@ plugins {
|
||||
kotlin("plugin.serialization") version "1.9.20"
|
||||
id("androidx.navigation.safeargs.kotlin")
|
||||
id("org.jlleitschuh.gradle.ktlint") version "11.4.0"
|
||||
id("com.github.triplet.play") version "3.8.6"
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -58,15 +59,7 @@ android {
|
||||
targetSdk = 34
|
||||
versionName = getGitVersion()
|
||||
|
||||
// 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") {
|
||||
versionCode = if (System.getenv("AUTO_VERSIONED") == "true") {
|
||||
autoVersion
|
||||
} else {
|
||||
1
|
||||
@@ -221,6 +214,15 @@ 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 {
|
||||
implementation("androidx.core:core-ktx:1.12.0")
|
||||
implementation("androidx.appcompat:appcompat:1.6.1")
|
||||
@@ -257,12 +259,18 @@ fun runGitCommand(command: List<String>): String {
|
||||
}
|
||||
|
||||
fun getGitVersion(): String {
|
||||
val gitVersion = runGitCommand(
|
||||
listOf(
|
||||
"git",
|
||||
"describe",
|
||||
"--always",
|
||||
"--long"
|
||||
)
|
||||
).replace(Regex("(-0)?-[^-]+$"), "")
|
||||
val versionName = if (System.getenv("GITHUB_ACTIONS") != null) {
|
||||
val gitTag = System.getenv("GIT_TAG_NAME") ?: ""
|
||||
gitTag
|
||||
System.getenv("GIT_TAG_NAME") ?: gitVersion
|
||||
} else {
|
||||
runGitCommand(listOf("git", "describe", "--always", "--long"))
|
||||
.replace(Regex("(-0)?-[^-]+$"), "")
|
||||
gitVersion
|
||||
}
|
||||
return versionName.ifEmpty { "0.0" }
|
||||
}
|
||||
|
||||
@@ -107,6 +107,8 @@ add_library(common STATIC
|
||||
quaternion.h
|
||||
range_map.h
|
||||
range_mutex.h
|
||||
range_sets.h
|
||||
range_sets.inc
|
||||
reader_writer_queue.h
|
||||
ring_buffer.h
|
||||
${CMAKE_CURRENT_BINARY_DIR}/scm_rev.cpp
|
||||
@@ -121,6 +123,7 @@ add_library(common STATIC
|
||||
settings_input.cpp
|
||||
settings_input.h
|
||||
settings_setting.h
|
||||
slot_vector.h
|
||||
socket_types.h
|
||||
spin_lock.cpp
|
||||
spin_lock.h
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <fmt/format.h>
|
||||
#include "common/assert.h"
|
||||
#include "common/common_types.h"
|
||||
|
||||
namespace Common {
|
||||
@@ -29,6 +30,8 @@ namespace Common {
|
||||
|
||||
template <std::size_t Size, bool le = false>
|
||||
[[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{};
|
||||
if constexpr (le) {
|
||||
for (std::size_t i = 2 * Size - 2; i <= 2 * Size; i -= 2) {
|
||||
|
||||
73
src/common/range_sets.h
Normal file
73
src/common/range_sets.h
Normal file
@@ -0,0 +1,73 @@
|
||||
// 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
|
||||
304
src/common/range_sets.inc
Normal file
304
src/common/range_sets.inc
Normal file
@@ -0,0 +1,304 @@
|
||||
// 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
|
||||
@@ -30,6 +30,7 @@ namespace Settings {
|
||||
#define SETTING(TYPE, RANGED) template class Setting<TYPE, RANGED>
|
||||
#define SWITCHABLE(TYPE, RANGED) template class SwitchableSetting<TYPE, RANGED>
|
||||
|
||||
SETTING(AppletMode, false);
|
||||
SETTING(AudioEngine, false);
|
||||
SETTING(bool, false);
|
||||
SETTING(int, false);
|
||||
@@ -215,6 +216,8 @@ const char* TranslateCategory(Category category) {
|
||||
return "Debugging";
|
||||
case Category::GpuDriver:
|
||||
return "GpuDriver";
|
||||
case Category::LibraryApplet:
|
||||
return "LibraryApplet";
|
||||
case Category::Miscellaneous:
|
||||
return "Miscellaneous";
|
||||
case Category::Network:
|
||||
|
||||
@@ -133,6 +133,38 @@ struct TouchFromButtonMap {
|
||||
struct Values {
|
||||
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
|
||||
SwitchableSetting<AudioEngine> sink_id{linkage, AudioEngine::Auto, "output_engine",
|
||||
Category::Audio, Specialization::RuntimeList};
|
||||
|
||||
@@ -44,6 +44,7 @@ enum class Category : u32 {
|
||||
Services,
|
||||
Paths,
|
||||
Linux,
|
||||
LibraryApplet,
|
||||
MaxEnum,
|
||||
};
|
||||
|
||||
|
||||
@@ -151,6 +151,8 @@ ENUM(AspectRatio, R16_9, R4_3, R21_9, R16_10, Stretch);
|
||||
|
||||
ENUM(ConsoleMode, Handheld, Docked);
|
||||
|
||||
ENUM(AppletMode, HLE, LLE);
|
||||
|
||||
template <typename Type>
|
||||
inline std::string CanonicalizeEnum(Type id) {
|
||||
const auto group = EnumMetadata<Type>::Canonicalizations();
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
#include "common/common_types.h"
|
||||
#include "common/polyfill_ranges.h"
|
||||
|
||||
namespace VideoCommon {
|
||||
namespace Common {
|
||||
|
||||
struct SlotId {
|
||||
static constexpr u32 INVALID_INDEX = std::numeric_limits<u32>::max();
|
||||
@@ -217,11 +217,11 @@ private:
|
||||
std::vector<u32> free_list;
|
||||
};
|
||||
|
||||
} // namespace VideoCommon
|
||||
} // namespace Common
|
||||
|
||||
template <>
|
||||
struct std::hash<VideoCommon::SlotId> {
|
||||
size_t operator()(const VideoCommon::SlotId& id) const noexcept {
|
||||
struct std::hash<Common::SlotId> {
|
||||
size_t operator()(const Common::SlotId& id) const noexcept {
|
||||
return std::hash<u32>{}(id.index);
|
||||
}
|
||||
};
|
||||
@@ -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<ProcessAddress>);
|
||||
|
||||
static_assert(Null<uint64_t> == 0);
|
||||
static_assert(Null<uint64_t> == 0U);
|
||||
static_assert(Null<PhysicalAddress> == Null<uint64_t>);
|
||||
static_assert(Null<VirtualAddress> == Null<uint64_t>);
|
||||
static_assert(Null<ProcessAddress> == Null<uint64_t>);
|
||||
|
||||
// Constructor/assignment validations.
|
||||
static_assert([] {
|
||||
const PhysicalAddress a(5);
|
||||
const PhysicalAddress a(5U);
|
||||
PhysicalAddress b(a);
|
||||
return b;
|
||||
}() == PhysicalAddress(5));
|
||||
}() == PhysicalAddress(5U));
|
||||
static_assert([] {
|
||||
const PhysicalAddress a(5);
|
||||
PhysicalAddress b(10);
|
||||
const PhysicalAddress a(5U);
|
||||
PhysicalAddress b(10U);
|
||||
b = a;
|
||||
return b;
|
||||
}() == PhysicalAddress(5));
|
||||
}() == PhysicalAddress(5U));
|
||||
|
||||
// Arithmetic validations.
|
||||
static_assert(PhysicalAddress(10) + 5 == PhysicalAddress(15));
|
||||
static_assert(PhysicalAddress(10) - 5 == PhysicalAddress(5));
|
||||
static_assert(PhysicalAddress(10U) + 5U == PhysicalAddress(15U));
|
||||
static_assert(PhysicalAddress(10U) - 5U == PhysicalAddress(5U));
|
||||
static_assert([] {
|
||||
PhysicalAddress v(10);
|
||||
v += 5;
|
||||
PhysicalAddress v(10U);
|
||||
v += 5U;
|
||||
return v;
|
||||
}() == PhysicalAddress(15));
|
||||
}() == PhysicalAddress(15U));
|
||||
static_assert([] {
|
||||
PhysicalAddress v(10);
|
||||
v -= 5;
|
||||
PhysicalAddress v(10U);
|
||||
v -= 5U;
|
||||
return v;
|
||||
}() == PhysicalAddress(5));
|
||||
static_assert(PhysicalAddress(10)++ == PhysicalAddress(10));
|
||||
static_assert(++PhysicalAddress(10) == PhysicalAddress(11));
|
||||
static_assert(PhysicalAddress(10)-- == PhysicalAddress(10));
|
||||
static_assert(--PhysicalAddress(10) == PhysicalAddress(9));
|
||||
}() == PhysicalAddress(5U));
|
||||
static_assert(PhysicalAddress(10U)++ == PhysicalAddress(10U));
|
||||
static_assert(++PhysicalAddress(10U) == PhysicalAddress(11U));
|
||||
static_assert(PhysicalAddress(10U)-- == PhysicalAddress(10U));
|
||||
static_assert(--PhysicalAddress(10U) == PhysicalAddress(9U));
|
||||
|
||||
// Logical validations.
|
||||
static_assert((PhysicalAddress(0b11111111) >> 1) == 0b01111111);
|
||||
static_assert((PhysicalAddress(0b10101010) >> 1) == 0b01010101);
|
||||
static_assert((PhysicalAddress(0b11111111) << 1) == 0b111111110);
|
||||
static_assert((PhysicalAddress(0b01010101) << 1) == 0b10101010);
|
||||
static_assert((PhysicalAddress(0b11111111) & 0b01010101) == 0b01010101);
|
||||
static_assert((PhysicalAddress(0b11111111) & 0b10101010) == 0b10101010);
|
||||
static_assert((PhysicalAddress(0b01010101) & 0b10101010) == 0b00000000);
|
||||
static_assert((PhysicalAddress(0b00000000) | 0b01010101) == 0b01010101);
|
||||
static_assert((PhysicalAddress(0b11111111) | 0b01010101) == 0b11111111);
|
||||
static_assert((PhysicalAddress(0b10101010) | 0b01010101) == 0b11111111);
|
||||
static_assert((PhysicalAddress(0b11111111U) >> 1) == 0b01111111U);
|
||||
static_assert((PhysicalAddress(0b10101010U) >> 1) == 0b01010101U);
|
||||
static_assert((PhysicalAddress(0b11111111U) << 1) == 0b111111110U);
|
||||
static_assert((PhysicalAddress(0b01010101U) << 1) == 0b10101010U);
|
||||
static_assert((PhysicalAddress(0b11111111U) & 0b01010101U) == 0b01010101U);
|
||||
static_assert((PhysicalAddress(0b11111111U) & 0b10101010U) == 0b10101010U);
|
||||
static_assert((PhysicalAddress(0b01010101U) & 0b10101010U) == 0b00000000U);
|
||||
static_assert((PhysicalAddress(0b00000000U) | 0b01010101U) == 0b01010101U);
|
||||
static_assert((PhysicalAddress(0b11111111U) | 0b01010101U) == 0b11111111U);
|
||||
static_assert((PhysicalAddress(0b10101010U) | 0b01010101U) == 0b11111111U);
|
||||
|
||||
// Comparisons.
|
||||
static_assert(PhysicalAddress(0) == PhysicalAddress(0));
|
||||
static_assert(PhysicalAddress(0) != PhysicalAddress(1));
|
||||
static_assert(PhysicalAddress(0) < PhysicalAddress(1));
|
||||
static_assert(PhysicalAddress(0) <= PhysicalAddress(1));
|
||||
static_assert(PhysicalAddress(1) > PhysicalAddress(0));
|
||||
static_assert(PhysicalAddress(1) >= PhysicalAddress(0));
|
||||
static_assert(PhysicalAddress(0U) == PhysicalAddress(0U));
|
||||
static_assert(PhysicalAddress(0U) != PhysicalAddress(1U));
|
||||
static_assert(PhysicalAddress(0U) < PhysicalAddress(1U));
|
||||
static_assert(PhysicalAddress(0U) <= PhysicalAddress(1U));
|
||||
static_assert(PhysicalAddress(1U) > PhysicalAddress(0U));
|
||||
static_assert(PhysicalAddress(1U) >= PhysicalAddress(0U));
|
||||
|
||||
static_assert(!(PhysicalAddress(0) == PhysicalAddress(1)));
|
||||
static_assert(!(PhysicalAddress(0) != PhysicalAddress(0)));
|
||||
static_assert(!(PhysicalAddress(1) < PhysicalAddress(0)));
|
||||
static_assert(!(PhysicalAddress(1) <= PhysicalAddress(0)));
|
||||
static_assert(!(PhysicalAddress(0) > PhysicalAddress(1)));
|
||||
static_assert(!(PhysicalAddress(0) >= PhysicalAddress(1)));
|
||||
static_assert(!(PhysicalAddress(0U) == PhysicalAddress(1U)));
|
||||
static_assert(!(PhysicalAddress(0U) != PhysicalAddress(0U)));
|
||||
static_assert(!(PhysicalAddress(1U) < PhysicalAddress(0U)));
|
||||
static_assert(!(PhysicalAddress(1U) <= PhysicalAddress(0U)));
|
||||
static_assert(!(PhysicalAddress(0U) > PhysicalAddress(1U)));
|
||||
static_assert(!(PhysicalAddress(0U) >= PhysicalAddress(1U)));
|
||||
|
||||
} // namespace Common
|
||||
|
||||
|
||||
@@ -775,6 +775,9 @@ add_library(core STATIC
|
||||
hle/service/nvnflinger/graphic_buffer_producer.h
|
||||
hle/service/nvnflinger/hos_binder_driver_server.cpp
|
||||
hle/service/nvnflinger/hos_binder_driver_server.h
|
||||
hle/service/nvnflinger/hardware_composer.cpp
|
||||
hle/service/nvnflinger/hardware_composer.h
|
||||
hle/service/nvnflinger/hwc_layer.h
|
||||
hle/service/nvnflinger/nvnflinger.cpp
|
||||
hle/service/nvnflinger/nvnflinger.h
|
||||
hle/service/nvnflinger/parcel.h
|
||||
|
||||
@@ -383,7 +383,7 @@ std::string GDBStubA32::RegRead(const Kernel::KThread* thread, size_t id) const
|
||||
} else if (id == CPSR_REGISTER) {
|
||||
return ValueToHex(context.pstate);
|
||||
} else if (id >= D0_REGISTER && id < Q0_REGISTER) {
|
||||
return ValueToHex(fprs[id - D0_REGISTER][0]);
|
||||
return ValueToHex(fprs[(id - D0_REGISTER) / 2][(id - D0_REGISTER) % 2]);
|
||||
} else if (id >= Q0_REGISTER && id < FPSCR_REGISTER) {
|
||||
return ValueToHex(fprs[id - Q0_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) {
|
||||
context.pstate = HexToValue<u32>(value);
|
||||
} else if (id >= D0_REGISTER && id < Q0_REGISTER) {
|
||||
fprs[id - D0_REGISTER] = {HexToValue<u64>(value), 0};
|
||||
fprs[(id - D0_REGISTER) / 2][(id - D0_REGISTER) % 2] = HexToValue<u64>(value);
|
||||
} else if (id >= Q0_REGISTER && id < FPSCR_REGISTER) {
|
||||
fprs[id - Q0_REGISTER] = HexToValue<u128>(value);
|
||||
} else if (id == FPSCR_REGISTER) {
|
||||
|
||||
@@ -532,6 +532,7 @@ void DeviceMemoryManager<Traits>::UpdatePagesCachedCount(DAddr addr, size_t size
|
||||
cache_bytes = 0;
|
||||
}
|
||||
};
|
||||
size_t old_vpage = (base_vaddress >> Memory::YUZU_PAGEBITS) - 1;
|
||||
for (; page != page_end; ++page) {
|
||||
CounterAtomicType& count = cached_pages->at(page >> subentries_shift).Count(page);
|
||||
auto [asid_2, vpage] = ExtractCPUBacking(page);
|
||||
@@ -547,6 +548,12 @@ void DeviceMemoryManager<Traits>::UpdatePagesCachedCount(DAddr addr, size_t size
|
||||
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
|
||||
count.fetch_add(static_cast<CounterType>(delta), std::memory_order_release);
|
||||
|
||||
|
||||
@@ -172,6 +172,10 @@ u32 NCA::GetSDKVersion() const {
|
||||
return reader->GetSdkAddonVersion();
|
||||
}
|
||||
|
||||
u8 NCA::GetKeyGeneration() const {
|
||||
return reader->GetKeyGeneration();
|
||||
}
|
||||
|
||||
bool NCA::IsUpdate() const {
|
||||
return is_update;
|
||||
}
|
||||
|
||||
@@ -77,6 +77,7 @@ public:
|
||||
u64 GetTitleId() const;
|
||||
RightsId GetRightsId() const;
|
||||
u32 GetSDKVersion() const;
|
||||
u8 GetKeyGeneration() const;
|
||||
bool IsUpdate() const;
|
||||
|
||||
VirtualFile GetRomFS() const;
|
||||
|
||||
@@ -4,8 +4,9 @@
|
||||
#include <random>
|
||||
#include "common/scope_exit.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/gpu_dirty_memory_manager.h"
|
||||
#include "core/hle/kernel/k_process.h"
|
||||
#include "core/hle/kernel/k_scoped_resource_reservation.h"
|
||||
#include "core/hle/kernel/k_shared_memory.h"
|
||||
@@ -1258,6 +1259,10 @@ void KProcess::InitializeInterfaces() {
|
||||
|
||||
#ifdef HAS_NCE
|
||||
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++) {
|
||||
m_arm_interfaces[i] = std::make_unique<Core::ArmNce>(m_kernel.System(), true, i);
|
||||
}
|
||||
|
||||
@@ -130,9 +130,9 @@ enum class AppletProgramId : u64 {
|
||||
|
||||
enum class LibraryAppletMode : u32 {
|
||||
AllForeground = 0,
|
||||
Background = 1,
|
||||
NoUI = 2,
|
||||
BackgroundIndirectDisplay = 3,
|
||||
PartialForeground = 1,
|
||||
NoUi = 2,
|
||||
PartialForegroundIndirectDisplay = 3,
|
||||
AllForegroundInitiallyHidden = 4,
|
||||
};
|
||||
|
||||
|
||||
@@ -68,9 +68,9 @@ void SoftwareKeyboard::Initialize() {
|
||||
case LibraryAppletMode::AllForeground:
|
||||
InitializeForeground();
|
||||
break;
|
||||
case LibraryAppletMode::Background:
|
||||
case LibraryAppletMode::BackgroundIndirectDisplay:
|
||||
InitializeBackground(applet_mode);
|
||||
case LibraryAppletMode::PartialForeground:
|
||||
case LibraryAppletMode::PartialForegroundIndirectDisplay:
|
||||
InitializePartialForeground(applet_mode);
|
||||
break;
|
||||
default:
|
||||
ASSERT_MSG(false, "Invalid LibraryAppletMode={}", applet_mode);
|
||||
@@ -243,7 +243,7 @@ void SoftwareKeyboard::InitializeForeground() {
|
||||
InitializeFrontendNormalKeyboard();
|
||||
}
|
||||
|
||||
void SoftwareKeyboard::InitializeBackground(LibraryAppletMode library_applet_mode) {
|
||||
void SoftwareKeyboard::InitializePartialForeground(LibraryAppletMode library_applet_mode) {
|
||||
LOG_INFO(Service_AM, "Initializing Inline Software Keyboard Applet.");
|
||||
|
||||
is_background = true;
|
||||
@@ -258,9 +258,9 @@ void SoftwareKeyboard::InitializeBackground(LibraryAppletMode library_applet_mod
|
||||
swkbd_inline_initialize_arg.size());
|
||||
|
||||
if (swkbd_initialize_arg.library_applet_mode_flag) {
|
||||
ASSERT(library_applet_mode == LibraryAppletMode::Background);
|
||||
ASSERT(library_applet_mode == LibraryAppletMode::PartialForeground);
|
||||
} else {
|
||||
ASSERT(library_applet_mode == LibraryAppletMode::BackgroundIndirectDisplay);
|
||||
ASSERT(library_applet_mode == LibraryAppletMode::PartialForegroundIndirectDisplay);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -62,7 +62,7 @@ private:
|
||||
void InitializeForeground();
|
||||
|
||||
/// Initializes the inline software keyboard.
|
||||
void InitializeBackground(LibraryAppletMode library_applet_mode);
|
||||
void InitializePartialForeground(LibraryAppletMode library_applet_mode);
|
||||
|
||||
/// Processes the text check sent by the application.
|
||||
void ProcessTextCheck();
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "common/settings.h"
|
||||
#include "core/hle/kernel/k_transfer_memory.h"
|
||||
#include "core/hle/service/am/applet_data_broker.h"
|
||||
#include "core/hle/service/am/applet_manager.h"
|
||||
@@ -16,6 +17,34 @@ namespace Service::AM {
|
||||
|
||||
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) {
|
||||
switch (applet_id) {
|
||||
case AppletId::OverlayDisplay:
|
||||
@@ -63,17 +92,26 @@ AppletProgramId AppletIdToProgramId(AppletId applet_id) {
|
||||
}
|
||||
}
|
||||
|
||||
[[maybe_unused]] std::shared_ptr<ILibraryAppletAccessor> CreateGuestApplet(
|
||||
Core::System& system, std::shared_ptr<Applet> caller_applet, AppletId applet_id,
|
||||
LibraryAppletMode mode) {
|
||||
std::shared_ptr<ILibraryAppletAccessor> CreateGuestApplet(Core::System& system,
|
||||
std::shared_ptr<Applet> caller_applet,
|
||||
AppletId applet_id,
|
||||
LibraryAppletMode mode) {
|
||||
const auto program_id = static_cast<u64>(AppletIdToProgramId(applet_id));
|
||||
if (program_id == 0) {
|
||||
// Unknown applet
|
||||
return {};
|
||||
}
|
||||
|
||||
// TODO: enable other versions of applets
|
||||
enum : u8 {
|
||||
Firmware1400 = 14,
|
||||
Firmware1500 = 15,
|
||||
Firmware1600 = 16,
|
||||
Firmware1700 = 17,
|
||||
};
|
||||
|
||||
auto process = std::make_unique<Process>(system);
|
||||
if (!process->Initialize(program_id)) {
|
||||
if (!process->Initialize(program_id, Firmware1400, Firmware1700)) {
|
||||
// Couldn't initialize the guest process
|
||||
return {};
|
||||
}
|
||||
@@ -87,24 +125,18 @@ AppletProgramId AppletIdToProgramId(AppletId applet_id) {
|
||||
// Set focus state
|
||||
switch (mode) {
|
||||
case LibraryAppletMode::AllForeground:
|
||||
case LibraryAppletMode::NoUI:
|
||||
applet->focus_state = FocusState::InFocus;
|
||||
case LibraryAppletMode::NoUi:
|
||||
case LibraryAppletMode::PartialForeground:
|
||||
case LibraryAppletMode::PartialForegroundIndirectDisplay:
|
||||
applet->hid_registration.EnableAppletToGetInput(true);
|
||||
applet->focus_state = FocusState::InFocus;
|
||||
applet->message_queue.PushMessage(AppletMessageQueue::AppletMessage::ChangeIntoForeground);
|
||||
applet->message_queue.PushMessage(AppletMessageQueue::AppletMessage::FocusStateChanged);
|
||||
break;
|
||||
case LibraryAppletMode::AllForegroundInitiallyHidden:
|
||||
applet->system_buffer_manager.SetWindowVisibility(false);
|
||||
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);
|
||||
applet->focus_state = FocusState::NotInFocus;
|
||||
applet->system_buffer_manager.SetWindowVisibility(false);
|
||||
applet->message_queue.PushMessage(AppletMessageQueue::AppletMessage::ChangeIntoBackground);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -117,9 +149,10 @@ AppletProgramId AppletIdToProgramId(AppletId applet_id) {
|
||||
return std::make_shared<ILibraryAppletAccessor>(system, broker, applet);
|
||||
}
|
||||
|
||||
[[maybe_unused]] std::shared_ptr<ILibraryAppletAccessor> CreateFrontendApplet(
|
||||
Core::System& system, std::shared_ptr<Applet> caller_applet, AppletId applet_id,
|
||||
LibraryAppletMode mode) {
|
||||
std::shared_ptr<ILibraryAppletAccessor> CreateFrontendApplet(Core::System& system,
|
||||
std::shared_ptr<Applet> caller_applet,
|
||||
AppletId applet_id,
|
||||
LibraryAppletMode mode) {
|
||||
const auto program_id = static_cast<u64>(AppletIdToProgramId(applet_id));
|
||||
|
||||
auto process = std::make_unique<Process>(system);
|
||||
@@ -163,7 +196,13 @@ void ILibraryAppletCreator::CreateLibraryApplet(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called with applet_id={:08X}, applet_mode={:08X}", applet_id,
|
||||
applet_mode);
|
||||
|
||||
auto library_applet = CreateFrontendApplet(system, applet, applet_id, applet_mode);
|
||||
std::shared_ptr<ILibraryAppletAccessor> library_applet;
|
||||
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) {
|
||||
LOG_ERROR(Service_AM, "Applet doesn't exist! applet_id={}", applet_id);
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
#include "common/scope_exit.h"
|
||||
|
||||
#include "core/file_sys/content_archive.h"
|
||||
#include "core/file_sys/nca_metadata.h"
|
||||
#include "core/file_sys/registered_cache.h"
|
||||
#include "core/hle/kernel/k_process.h"
|
||||
@@ -20,7 +21,7 @@ Process::~Process() {
|
||||
this->Finalize();
|
||||
}
|
||||
|
||||
bool Process::Initialize(u64 program_id) {
|
||||
bool Process::Initialize(u64 program_id, u8 minimum_key_generation, u8 maximum_key_generation) {
|
||||
// First, ensure we are not holding another process.
|
||||
this->Finalize();
|
||||
|
||||
@@ -29,21 +30,33 @@ bool Process::Initialize(u64 program_id) {
|
||||
|
||||
// Attempt to load program NCA.
|
||||
const FileSys::RegisteredCache* bis_system{};
|
||||
FileSys::VirtualFile nca{};
|
||||
FileSys::VirtualFile nca_raw{};
|
||||
|
||||
// Get the program NCA from built-in storage.
|
||||
bis_system = fsc.GetSystemNANDContents();
|
||||
if (bis_system) {
|
||||
nca = bis_system->GetEntryRaw(program_id, FileSys::ContentRecordType::Program);
|
||||
nca_raw = bis_system->GetEntryRaw(program_id, FileSys::ContentRecordType::Program);
|
||||
}
|
||||
|
||||
// Ensure we retrieved a program NCA.
|
||||
if (!nca) {
|
||||
if (!nca_raw) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Ensure we have a suitable version.
|
||||
if (minimum_key_generation > 0) {
|
||||
FileSys::NCA nca(nca_raw);
|
||||
if (nca.GetStatus() == Loader::ResultStatus::Success &&
|
||||
(nca.GetKeyGeneration() < minimum_key_generation ||
|
||||
nca.GetKeyGeneration() > maximum_key_generation)) {
|
||||
LOG_WARNING(Service_LDR, "Skipping program {:016X} with generation {}", program_id,
|
||||
nca.GetKeyGeneration());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Get the appropriate loader to parse this NCA.
|
||||
auto app_loader = Loader::GetLoader(m_system, nca, program_id, 0);
|
||||
auto app_loader = Loader::GetLoader(m_system, nca_raw, program_id, 0);
|
||||
|
||||
// Ensure we have a loader which can parse the NCA.
|
||||
if (!app_loader) {
|
||||
|
||||
@@ -21,7 +21,7 @@ public:
|
||||
explicit Process(Core::System& system);
|
||||
~Process();
|
||||
|
||||
bool Initialize(u64 program_id);
|
||||
bool Initialize(u64 program_id, u8 minimum_key_generation, u8 maximum_key_generation);
|
||||
void Finalize();
|
||||
|
||||
bool Run();
|
||||
|
||||
@@ -1,10 +1,13 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||
// 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/frontend/applets.h"
|
||||
#include "core/hle/service/am/self_controller.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/nvnflinger/fb_share_buffer_manager.h"
|
||||
#include "core/hle/service/nvnflinger/nvnflinger.h"
|
||||
@@ -47,7 +50,7 @@ ISelfController::ISelfController(Core::System& system_, std::shared_ptr<Applet>
|
||||
{50, &ISelfController::SetHandlesRequestToDisplay, "SetHandlesRequestToDisplay"},
|
||||
{51, &ISelfController::ApproveToDisplay, "ApproveToDisplay"},
|
||||
{60, nullptr, "OverrideAutoSleepTimeAndDimmingTime"},
|
||||
{61, nullptr, "SetMediaPlaybackState"},
|
||||
{61, &ISelfController::SetMediaPlaybackState, "SetMediaPlaybackState"},
|
||||
{62, &ISelfController::SetIdleTimeDetectionExtension, "SetIdleTimeDetectionExtension"},
|
||||
{63, &ISelfController::GetIdleTimeDetectionExtension, "GetIdleTimeDetectionExtension"},
|
||||
{64, nullptr, "SetInputDetectionSourceSet"},
|
||||
@@ -288,7 +291,8 @@ void ISelfController::GetSystemSharedBufferHandle(HLERequestContext& ctx) {
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -323,6 +327,16 @@ void ISelfController::ApproveToDisplay(HLERequestContext& ctx) {
|
||||
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) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "core/hle/service/hle_ipc.h"
|
||||
#include "core/hle/service/kernel_helpers.h"
|
||||
#include "core/hle/service/service.h"
|
||||
|
||||
@@ -38,6 +39,7 @@ private:
|
||||
void CreateManagedDisplaySeparableLayer(HLERequestContext& ctx);
|
||||
void SetHandlesRequestToDisplay(HLERequestContext& ctx);
|
||||
void ApproveToDisplay(HLERequestContext& ctx);
|
||||
void SetMediaPlaybackState(HLERequestContext& ctx);
|
||||
void SetIdleTimeDetectionExtension(HLERequestContext& ctx);
|
||||
void GetIdleTimeDetectionExtension(HLERequestContext& ctx);
|
||||
void ReportUserIsActive(HLERequestContext& ctx);
|
||||
|
||||
@@ -17,11 +17,12 @@ SystemBufferManager::~SystemBufferManager() {
|
||||
|
||||
// Clean up shared layers.
|
||||
if (m_buffer_sharing_enabled) {
|
||||
m_nvnflinger->GetSystemBufferManager().Finalize(m_process);
|
||||
}
|
||||
}
|
||||
|
||||
bool SystemBufferManager::Initialize(Nvnflinger::Nvnflinger* nvnflinger, Kernel::KProcess* process,
|
||||
AppletId applet_id) {
|
||||
AppletId applet_id, LibraryAppletMode mode) {
|
||||
if (m_nvnflinger) {
|
||||
return m_buffer_sharing_enabled;
|
||||
}
|
||||
@@ -36,9 +37,15 @@ bool SystemBufferManager::Initialize(Nvnflinger::Nvnflinger* nvnflinger, Kernel:
|
||||
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 res = m_nvnflinger->GetSystemBufferManager().Initialize(
|
||||
&m_system_shared_buffer_id, &m_system_shared_layer_id, display_id);
|
||||
m_process, &m_system_shared_buffer_id, &m_system_shared_layer_id, display_id, blending);
|
||||
|
||||
if (res.IsSuccess()) {
|
||||
m_buffer_sharing_enabled = true;
|
||||
@@ -62,8 +69,12 @@ void SystemBufferManager::SetWindowVisibility(bool visible) {
|
||||
|
||||
Result SystemBufferManager::WriteAppletCaptureBuffer(bool* out_was_written,
|
||||
s32* out_fbshare_layer_index) {
|
||||
// TODO
|
||||
R_SUCCEED();
|
||||
if (!m_buffer_sharing_enabled) {
|
||||
return VI::ResultPermissionDenied;
|
||||
}
|
||||
|
||||
return m_nvnflinger->GetSystemBufferManager().WriteAppletCaptureBuffer(out_was_written,
|
||||
out_fbshare_layer_index);
|
||||
}
|
||||
|
||||
} // namespace Service::AM
|
||||
|
||||
@@ -27,7 +27,8 @@ public:
|
||||
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,
|
||||
u64* out_system_shared_layer_id) {
|
||||
|
||||
@@ -62,12 +62,12 @@ void IWindowController::SetAppletWindowVisibility(HLERequestContext& ctx) {
|
||||
applet->hid_registration.EnableAppletToGetInput(visible);
|
||||
|
||||
if (visible) {
|
||||
applet->message_queue.PushMessage(AppletMessageQueue::AppletMessage::ChangeIntoForeground);
|
||||
applet->focus_state = FocusState::InFocus;
|
||||
applet->message_queue.PushMessage(AppletMessageQueue::AppletMessage::ChangeIntoForeground);
|
||||
} else {
|
||||
applet->focus_state = FocusState::NotInFocus;
|
||||
applet->message_queue.PushMessage(AppletMessageQueue::AppletMessage::ChangeIntoBackground);
|
||||
}
|
||||
applet->message_queue.PushMessage(AppletMessageQueue::AppletMessage::FocusStateChanged);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultSuccess);
|
||||
|
||||
@@ -115,6 +115,11 @@ struct ArgumentTraits {
|
||||
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 {
|
||||
u32 copy_handle_count;
|
||||
u32 move_handle_count;
|
||||
@@ -435,6 +440,7 @@ void CmifReplyWrapImpl(HLERequestContext& ctx, T& t, Result (T::*f)(A...)) {
|
||||
}
|
||||
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>...>;
|
||||
|
||||
OutTemporaryBuffers buffers{};
|
||||
|
||||
@@ -4,10 +4,9 @@
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <span>
|
||||
|
||||
#include "common/common_funcs.h"
|
||||
#include "common/common_types.h"
|
||||
#include "core/hle/service/hle_ipc.h"
|
||||
|
||||
namespace Service {
|
||||
|
||||
@@ -22,8 +21,10 @@ class Out {
|
||||
public:
|
||||
using Type = T;
|
||||
|
||||
/* implicit */ Out(const Out& t) : raw(t.raw) {}
|
||||
/* implicit */ Out(AutoOut<Type>& t) : raw(&t.raw) {}
|
||||
/* implicit */ Out(Type* t) : raw(t) {}
|
||||
Out& operator=(const Out&) = delete;
|
||||
|
||||
Type* Get() const {
|
||||
return raw;
|
||||
@@ -37,6 +38,10 @@ public:
|
||||
return raw;
|
||||
}
|
||||
|
||||
operator Type*() const {
|
||||
return raw;
|
||||
}
|
||||
|
||||
private:
|
||||
Type* raw;
|
||||
};
|
||||
@@ -113,8 +118,10 @@ class OutCopyHandle {
|
||||
public:
|
||||
using Type = T*;
|
||||
|
||||
/* implicit */ OutCopyHandle(const OutCopyHandle& t) : raw(t.raw) {}
|
||||
/* implicit */ OutCopyHandle(AutoOut<Type>& t) : raw(&t.raw) {}
|
||||
/* implicit */ OutCopyHandle(Type* t) : raw(t) {}
|
||||
OutCopyHandle& operator=(const OutCopyHandle&) = delete;
|
||||
|
||||
Type* Get() const {
|
||||
return raw;
|
||||
@@ -128,6 +135,10 @@ public:
|
||||
return raw;
|
||||
}
|
||||
|
||||
operator Type*() const {
|
||||
return raw;
|
||||
}
|
||||
|
||||
private:
|
||||
Type* raw;
|
||||
};
|
||||
@@ -137,8 +148,10 @@ class OutMoveHandle {
|
||||
public:
|
||||
using Type = T*;
|
||||
|
||||
/* implicit */ OutMoveHandle(const OutMoveHandle& t) : raw(t.raw) {}
|
||||
/* implicit */ OutMoveHandle(AutoOut<Type>& t) : raw(&t.raw) {}
|
||||
/* implicit */ OutMoveHandle(Type* t) : raw(t) {}
|
||||
OutMoveHandle& operator=(const OutMoveHandle&) = delete;
|
||||
|
||||
Type* Get() const {
|
||||
return raw;
|
||||
@@ -152,6 +165,10 @@ public:
|
||||
return raw;
|
||||
}
|
||||
|
||||
operator Type*() const {
|
||||
return raw;
|
||||
}
|
||||
|
||||
private:
|
||||
Type* raw;
|
||||
};
|
||||
@@ -245,11 +262,13 @@ class OutLargeData {
|
||||
public:
|
||||
static_assert(std::is_trivially_copyable_v<T>, "LargeData type must be trivially copyable");
|
||||
static_assert((A & BufferAttr_In) == 0, "OutLargeData attr must not be In");
|
||||
static constexpr BufferAttr Attr = static_cast<BufferAttr>(A | BufferAttr_In | BufferAttr_FixedSize);
|
||||
static constexpr BufferAttr Attr = static_cast<BufferAttr>(A | BufferAttr_Out | BufferAttr_FixedSize);
|
||||
using Type = T;
|
||||
|
||||
/* implicit */ OutLargeData(const OutLargeData& t) : raw(t.raw) {}
|
||||
/* implicit */ OutLargeData(Type* t) : raw(t) {}
|
||||
/* implicit */ OutLargeData(AutoOut<T>& t) : raw(&t.raw) {}
|
||||
OutLargeData& operator=(const OutLargeData&) = delete;
|
||||
|
||||
Type* Get() const {
|
||||
return raw;
|
||||
@@ -263,6 +282,10 @@ public:
|
||||
return raw;
|
||||
}
|
||||
|
||||
operator Type*() const {
|
||||
return raw;
|
||||
}
|
||||
|
||||
private:
|
||||
Type* raw;
|
||||
};
|
||||
|
||||
@@ -115,6 +115,11 @@ private:
|
||||
if (type->GetName() == "save") {
|
||||
for (const auto& save_id : type->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());
|
||||
auto user_id_numeric = Common::HexStringToArray<0x10>(user_id->GetName());
|
||||
std::reverse(user_id_numeric.begin(), user_id_numeric.end());
|
||||
@@ -160,6 +165,10 @@ private:
|
||||
} else if (space == FileSys::SaveDataSpaceId::TemporaryStorage) {
|
||||
// Temporary Storage
|
||||
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()) {
|
||||
if (!title_id->GetFiles().empty() ||
|
||||
!title_id->GetSubdirectories().empty()) {
|
||||
|
||||
@@ -31,8 +31,11 @@ void LoopProcess(Core::System& system) {
|
||||
// Error Context
|
||||
server_manager->RegisterNamedService("ectx:aw", std::make_shared<ECTX_AW>(system));
|
||||
|
||||
// Notification Services for application
|
||||
server_manager->RegisterNamedService("notif:a", std::make_shared<NOTIF_A>(system));
|
||||
// Notification Services
|
||||
server_manager->RegisterNamedService(
|
||||
"notif:a", std::make_shared<INotificationServicesForApplication>(system));
|
||||
server_manager->RegisterNamedService("notif:s",
|
||||
std::make_shared<INotificationServices>(system));
|
||||
|
||||
// Time
|
||||
auto time = std::make_shared<Time::TimeManager>(system);
|
||||
|
||||
@@ -6,48 +6,31 @@
|
||||
|
||||
#include "common/assert.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "core/hle/service/cmif_serialization.h"
|
||||
#include "core/hle/service/glue/notif.h"
|
||||
#include "core/hle/service/ipc_helpers.h"
|
||||
#include "core/hle/service/kernel_helpers.h"
|
||||
|
||||
namespace Service::Glue {
|
||||
|
||||
NOTIF_A::NOTIF_A(Core::System& system_) : ServiceFramework{system_, "notif:a"} {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{500, &NOTIF_A::RegisterAlarmSetting, "RegisterAlarmSetting"},
|
||||
{510, &NOTIF_A::UpdateAlarmSetting, "UpdateAlarmSetting"},
|
||||
{520, &NOTIF_A::ListAlarmSettings, "ListAlarmSettings"},
|
||||
{530, &NOTIF_A::LoadApplicationParameter, "LoadApplicationParameter"},
|
||||
{540, &NOTIF_A::DeleteAlarmSetting, "DeleteAlarmSetting"},
|
||||
{1000, &NOTIF_A::Initialize, "Initialize"},
|
||||
};
|
||||
// clang-format on
|
||||
namespace {
|
||||
|
||||
constexpr inline std::size_t MaxAlarms = 8;
|
||||
|
||||
RegisterHandlers(functions);
|
||||
}
|
||||
|
||||
NOTIF_A::~NOTIF_A() = default;
|
||||
|
||||
void NOTIF_A::RegisterAlarmSetting(HLERequestContext& ctx) {
|
||||
const auto alarm_setting_buffer_size = ctx.GetReadBufferSize(0);
|
||||
const auto application_parameter_size = ctx.GetReadBufferSize(1);
|
||||
|
||||
ASSERT_MSG(alarm_setting_buffer_size == sizeof(AlarmSetting),
|
||||
"alarm_setting_buffer_size is not 0x40 bytes");
|
||||
ASSERT_MSG(application_parameter_size <= sizeof(ApplicationParameter),
|
||||
"application_parameter_size is bigger than 0x400 bytes");
|
||||
|
||||
AlarmSetting new_alarm{};
|
||||
memcpy(&new_alarm, ctx.ReadBuffer(0).data(), sizeof(AlarmSetting));
|
||||
|
||||
// TODO: Count alarms per game id
|
||||
if (alarms.size() >= max_alarms) {
|
||||
Result NotificationServiceImpl::RegisterAlarmSetting(AlarmSettingId* out_alarm_setting_id,
|
||||
const AlarmSetting& alarm_setting,
|
||||
std::span<const u8> application_parameter) {
|
||||
if (alarms.size() > MaxAlarms) {
|
||||
LOG_ERROR(Service_NOTIF, "Alarm limit reached");
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultUnknown);
|
||||
return;
|
||||
R_THROW(ResultUnknown);
|
||||
}
|
||||
|
||||
ASSERT_MSG(application_parameter.size() <= sizeof(ApplicationParameter),
|
||||
"application_parameter_size is bigger than 0x400 bytes");
|
||||
|
||||
AlarmSetting new_alarm = alarm_setting;
|
||||
new_alarm.alarm_setting_id = last_alarm_setting_id++;
|
||||
alarms.push_back(new_alarm);
|
||||
|
||||
@@ -55,100 +38,82 @@ void NOTIF_A::RegisterAlarmSetting(HLERequestContext& ctx) {
|
||||
|
||||
LOG_WARNING(Service_NOTIF,
|
||||
"(STUBBED) called, application_parameter_size={}, setting_id={}, kind={}, muted={}",
|
||||
application_parameter_size, new_alarm.alarm_setting_id, new_alarm.kind,
|
||||
application_parameter.size(), new_alarm.alarm_setting_id, new_alarm.kind,
|
||||
new_alarm.muted);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.Push(new_alarm.alarm_setting_id);
|
||||
*out_alarm_setting_id = new_alarm.alarm_setting_id;
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
void NOTIF_A::UpdateAlarmSetting(HLERequestContext& ctx) {
|
||||
const auto alarm_setting_buffer_size = ctx.GetReadBufferSize(0);
|
||||
const auto application_parameter_size = ctx.GetReadBufferSize(1);
|
||||
|
||||
ASSERT_MSG(alarm_setting_buffer_size == sizeof(AlarmSetting),
|
||||
"alarm_setting_buffer_size is not 0x40 bytes");
|
||||
ASSERT_MSG(application_parameter_size <= sizeof(ApplicationParameter),
|
||||
Result NotificationServiceImpl::UpdateAlarmSetting(const AlarmSetting& alarm_setting,
|
||||
std::span<const u8> application_parameter) {
|
||||
ASSERT_MSG(application_parameter.size() <= sizeof(ApplicationParameter),
|
||||
"application_parameter_size is bigger than 0x400 bytes");
|
||||
|
||||
AlarmSetting alarm_setting{};
|
||||
memcpy(&alarm_setting, ctx.ReadBuffer(0).data(), sizeof(AlarmSetting));
|
||||
|
||||
const auto alarm_it = GetAlarmFromId(alarm_setting.alarm_setting_id);
|
||||
if (alarm_it != alarms.end()) {
|
||||
LOG_DEBUG(Service_NOTIF, "Alarm updated");
|
||||
*alarm_it = alarm_setting;
|
||||
// TODO: Save application parameter data
|
||||
}
|
||||
|
||||
LOG_WARNING(Service_NOTIF,
|
||||
"(STUBBED) called, application_parameter_size={}, setting_id={}, kind={}, muted={}",
|
||||
application_parameter_size, alarm_setting.alarm_setting_id, alarm_setting.kind,
|
||||
application_parameter.size(), alarm_setting.alarm_setting_id, alarm_setting.kind,
|
||||
alarm_setting.muted);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultSuccess);
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
void NOTIF_A::ListAlarmSettings(HLERequestContext& ctx) {
|
||||
Result NotificationServiceImpl::ListAlarmSettings(s32* out_count,
|
||||
std::span<AlarmSetting> out_alarms) {
|
||||
LOG_INFO(Service_NOTIF, "called, alarm_count={}", alarms.size());
|
||||
|
||||
// TODO: Only return alarms of this game id
|
||||
ctx.WriteBuffer(alarms);
|
||||
const auto count = std::min(out_alarms.size(), alarms.size());
|
||||
for (size_t i = 0; i < count; i++) {
|
||||
out_alarms[i] = alarms[i];
|
||||
}
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.Push(static_cast<u32>(alarms.size()));
|
||||
*out_count = static_cast<s32>(count);
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
void NOTIF_A::LoadApplicationParameter(HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto alarm_setting_id{rp.Pop<AlarmSettingId>()};
|
||||
|
||||
Result NotificationServiceImpl::LoadApplicationParameter(u32* out_size,
|
||||
std::span<u8> out_application_parameter,
|
||||
AlarmSettingId alarm_setting_id) {
|
||||
const auto alarm_it = GetAlarmFromId(alarm_setting_id);
|
||||
if (alarm_it == alarms.end()) {
|
||||
LOG_ERROR(Service_NOTIF, "Invalid alarm setting id={}", alarm_setting_id);
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultUnknown);
|
||||
return;
|
||||
R_THROW(ResultUnknown);
|
||||
}
|
||||
|
||||
// TODO: Read application parameter related to this setting id
|
||||
ApplicationParameter application_parameter{};
|
||||
|
||||
LOG_WARNING(Service_NOTIF, "(STUBBED) called, alarm_setting_id={}", alarm_setting_id);
|
||||
std::memcpy(out_application_parameter.data(), application_parameter.data(),
|
||||
std::min(sizeof(application_parameter), out_application_parameter.size()));
|
||||
|
||||
ctx.WriteBuffer(application_parameter);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.Push(static_cast<u32>(application_parameter.size()));
|
||||
*out_size = static_cast<u32>(application_parameter.size());
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
void NOTIF_A::DeleteAlarmSetting(HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto alarm_setting_id{rp.Pop<AlarmSettingId>()};
|
||||
|
||||
Result NotificationServiceImpl::DeleteAlarmSetting(AlarmSettingId alarm_setting_id) {
|
||||
std::erase_if(alarms, [alarm_setting_id](const AlarmSetting& alarm) {
|
||||
return alarm.alarm_setting_id == alarm_setting_id;
|
||||
});
|
||||
|
||||
LOG_INFO(Service_NOTIF, "called, alarm_setting_id={}", alarm_setting_id);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultSuccess);
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
void NOTIF_A::Initialize(HLERequestContext& ctx) {
|
||||
Result NotificationServiceImpl::Initialize(u64 aruid) {
|
||||
// TODO: Load previous alarms from config
|
||||
|
||||
LOG_WARNING(Service_NOTIF, "(STUBBED) called");
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultSuccess);
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
std::vector<NOTIF_A::AlarmSetting>::iterator NOTIF_A::GetAlarmFromId(
|
||||
std::vector<AlarmSetting>::iterator NotificationServiceImpl::GetAlarmFromId(
|
||||
AlarmSettingId alarm_setting_id) {
|
||||
return std::find_if(alarms.begin(), alarms.end(),
|
||||
[alarm_setting_id](const AlarmSetting& alarm) {
|
||||
@@ -156,4 +121,174 @@ std::vector<NOTIF_A::AlarmSetting>::iterator NOTIF_A::GetAlarmFromId(
|
||||
});
|
||||
}
|
||||
|
||||
INotificationServicesForApplication::INotificationServicesForApplication(Core::System& system_)
|
||||
: ServiceFramework{system_, "notif:a"} {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{500, D<&INotificationServicesForApplication::RegisterAlarmSetting>, "RegisterAlarmSetting"},
|
||||
{510, D<&INotificationServicesForApplication::UpdateAlarmSetting>, "UpdateAlarmSetting"},
|
||||
{520, D<&INotificationServicesForApplication::ListAlarmSettings>, "ListAlarmSettings"},
|
||||
{530, D<&INotificationServicesForApplication::LoadApplicationParameter>, "LoadApplicationParameter"},
|
||||
{540, D<&INotificationServicesForApplication::DeleteAlarmSetting>, "DeleteAlarmSetting"},
|
||||
{1000, D<&INotificationServicesForApplication::Initialize>, "Initialize"},
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
RegisterHandlers(functions);
|
||||
}
|
||||
|
||||
INotificationServicesForApplication::~INotificationServicesForApplication() = default;
|
||||
|
||||
Result INotificationServicesForApplication::RegisterAlarmSetting(
|
||||
Out<AlarmSettingId> out_alarm_setting_id,
|
||||
InLargeData<AlarmSetting, BufferAttr_HipcMapAlias> alarm_setting,
|
||||
InBuffer<BufferAttr_HipcMapAlias> application_parameter) {
|
||||
R_RETURN(impl.RegisterAlarmSetting(out_alarm_setting_id.Get(), *alarm_setting,
|
||||
application_parameter));
|
||||
}
|
||||
|
||||
Result INotificationServicesForApplication::UpdateAlarmSetting(
|
||||
InLargeData<AlarmSetting, BufferAttr_HipcMapAlias> alarm_setting,
|
||||
InBuffer<BufferAttr_HipcMapAlias> application_parameter) {
|
||||
R_RETURN(impl.UpdateAlarmSetting(*alarm_setting, application_parameter));
|
||||
}
|
||||
|
||||
Result INotificationServicesForApplication::ListAlarmSettings(
|
||||
Out<s32> out_count, OutArray<AlarmSetting, BufferAttr_HipcMapAlias> out_alarms) {
|
||||
R_RETURN(impl.ListAlarmSettings(out_count.Get(), out_alarms));
|
||||
}
|
||||
|
||||
Result INotificationServicesForApplication::LoadApplicationParameter(
|
||||
Out<u32> out_size, OutBuffer<BufferAttr_HipcMapAlias> out_application_parameter,
|
||||
AlarmSettingId alarm_setting_id) {
|
||||
R_RETURN(
|
||||
impl.LoadApplicationParameter(out_size.Get(), out_application_parameter, alarm_setting_id));
|
||||
}
|
||||
|
||||
Result INotificationServicesForApplication::DeleteAlarmSetting(AlarmSettingId alarm_setting_id) {
|
||||
R_RETURN(impl.DeleteAlarmSetting(alarm_setting_id));
|
||||
}
|
||||
|
||||
Result INotificationServicesForApplication::Initialize(ClientAppletResourceUserId aruid) {
|
||||
R_RETURN(impl.Initialize(*aruid));
|
||||
}
|
||||
|
||||
class INotificationSystemEventAccessor final
|
||||
: public ServiceFramework<INotificationSystemEventAccessor> {
|
||||
public:
|
||||
explicit INotificationSystemEventAccessor(Core::System& system_)
|
||||
: ServiceFramework{system_, "INotificationSystemEventAccessor"},
|
||||
service_context{system_, "INotificationSystemEventAccessor"} {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, D<&INotificationSystemEventAccessor::GetSystemEvent>, "GetSystemEvent"},
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
RegisterHandlers(functions);
|
||||
|
||||
notification_event =
|
||||
service_context.CreateEvent("INotificationSystemEventAccessor:NotificationEvent");
|
||||
}
|
||||
|
||||
~INotificationSystemEventAccessor() {
|
||||
service_context.CloseEvent(notification_event);
|
||||
}
|
||||
|
||||
private:
|
||||
Result GetSystemEvent(OutCopyHandle<Kernel::KReadableEvent> out_readable_event) {
|
||||
LOG_WARNING(Service_NOTIF, "(STUBBED) called");
|
||||
|
||||
*out_readable_event = ¬ification_event->GetReadableEvent();
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
KernelHelpers::ServiceContext service_context;
|
||||
Kernel::KEvent* notification_event;
|
||||
};
|
||||
|
||||
INotificationServices::INotificationServices(Core::System& system_)
|
||||
: ServiceFramework{system_, "notif:s"} {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{500, D<&INotificationServices::RegisterAlarmSetting>, "RegisterAlarmSetting"},
|
||||
{510, D<&INotificationServices::UpdateAlarmSetting>, "UpdateAlarmSetting"},
|
||||
{520, D<&INotificationServices::ListAlarmSettings>, "ListAlarmSettings"},
|
||||
{530, D<&INotificationServices::LoadApplicationParameter>, "LoadApplicationParameter"},
|
||||
{540, D<&INotificationServices::DeleteAlarmSetting>, "DeleteAlarmSetting"},
|
||||
{1000, D<&INotificationServices::Initialize>, "Initialize"},
|
||||
{1010, nullptr, "ListNotifications"},
|
||||
{1020, nullptr, "DeleteNotification"},
|
||||
{1030, nullptr, "ClearNotifications"},
|
||||
{1040, D<&INotificationServices::OpenNotificationSystemEventAccessor>, "OpenNotificationSystemEventAccessor"},
|
||||
{1500, nullptr, "SetNotificationPresentationSetting"},
|
||||
{1510, D<&INotificationServices::GetNotificationPresentationSetting>, "GetNotificationPresentationSetting"},
|
||||
{2000, nullptr, "GetAlarmSetting"},
|
||||
{2001, nullptr, "GetAlarmSettingWithApplicationParameter"},
|
||||
{2010, nullptr, "MuteAlarmSetting"},
|
||||
{2020, nullptr, "IsAlarmSettingReady"},
|
||||
{8000, nullptr, "RegisterAppletResourceUserId"},
|
||||
{8010, nullptr, "UnregisterAppletResourceUserId"},
|
||||
{8999, nullptr, "GetCurrentTime"},
|
||||
{9000, nullptr, "GetAlarmSettingNextNotificationTime"},
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
RegisterHandlers(functions);
|
||||
}
|
||||
|
||||
INotificationServices::~INotificationServices() = default;
|
||||
|
||||
Result INotificationServices::RegisterAlarmSetting(
|
||||
Out<AlarmSettingId> out_alarm_setting_id,
|
||||
InLargeData<AlarmSetting, BufferAttr_HipcMapAlias> alarm_setting,
|
||||
InBuffer<BufferAttr_HipcMapAlias> application_parameter) {
|
||||
R_RETURN(impl.RegisterAlarmSetting(out_alarm_setting_id.Get(), *alarm_setting,
|
||||
application_parameter));
|
||||
}
|
||||
|
||||
Result INotificationServices::UpdateAlarmSetting(
|
||||
InLargeData<AlarmSetting, BufferAttr_HipcMapAlias> alarm_setting,
|
||||
InBuffer<BufferAttr_HipcMapAlias> application_parameter) {
|
||||
R_RETURN(impl.UpdateAlarmSetting(*alarm_setting, application_parameter));
|
||||
}
|
||||
|
||||
Result INotificationServices::ListAlarmSettings(
|
||||
Out<s32> out_count, OutArray<AlarmSetting, BufferAttr_HipcMapAlias> out_alarms) {
|
||||
R_RETURN(impl.ListAlarmSettings(out_count.Get(), out_alarms));
|
||||
}
|
||||
|
||||
Result INotificationServices::LoadApplicationParameter(
|
||||
Out<u32> out_size, OutBuffer<BufferAttr_HipcMapAlias> out_application_parameter,
|
||||
AlarmSettingId alarm_setting_id) {
|
||||
R_RETURN(
|
||||
impl.LoadApplicationParameter(out_size.Get(), out_application_parameter, alarm_setting_id));
|
||||
}
|
||||
|
||||
Result INotificationServices::DeleteAlarmSetting(AlarmSettingId alarm_setting_id) {
|
||||
R_RETURN(impl.DeleteAlarmSetting(alarm_setting_id));
|
||||
}
|
||||
|
||||
Result INotificationServices::Initialize(ClientAppletResourceUserId aruid) {
|
||||
R_RETURN(impl.Initialize(*aruid));
|
||||
}
|
||||
|
||||
Result INotificationServices::OpenNotificationSystemEventAccessor(
|
||||
Out<SharedPointer<INotificationSystemEventAccessor>> out_notification_system_event_accessor) {
|
||||
LOG_WARNING(Service_NOTIF, "(STUBBED) called");
|
||||
|
||||
*out_notification_system_event_accessor =
|
||||
std::make_shared<INotificationSystemEventAccessor>(system);
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result INotificationServices::GetNotificationPresentationSetting(
|
||||
Out<NotificationPresentationSetting> out_notification_presentation_setting,
|
||||
NotificationChannel notification_channel) {
|
||||
LOG_WARNING(Service_NOTIF, "(STUBBED) called");
|
||||
|
||||
*out_notification_presentation_setting = {};
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
} // namespace Service::Glue
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include <vector>
|
||||
|
||||
#include "common/uuid.h"
|
||||
#include "core/hle/service/cmif_types.h"
|
||||
#include "core/hle/service/service.h"
|
||||
|
||||
namespace Core {
|
||||
@@ -15,58 +16,117 @@ class System;
|
||||
|
||||
namespace Service::Glue {
|
||||
|
||||
class NOTIF_A final : public ServiceFramework<NOTIF_A> {
|
||||
// This is nn::notification::AlarmSettingId
|
||||
using AlarmSettingId = u16;
|
||||
static_assert(sizeof(AlarmSettingId) == 0x2, "AlarmSettingId is an invalid size");
|
||||
|
||||
using ApplicationParameter = std::array<u8, 0x400>;
|
||||
static_assert(sizeof(ApplicationParameter) == 0x400, "ApplicationParameter is an invalid size");
|
||||
|
||||
struct DailyAlarmSetting {
|
||||
s8 hour;
|
||||
s8 minute;
|
||||
};
|
||||
static_assert(sizeof(DailyAlarmSetting) == 0x2, "DailyAlarmSetting is an invalid size");
|
||||
|
||||
struct WeeklyScheduleAlarmSetting {
|
||||
INSERT_PADDING_BYTES_NOINIT(0xA);
|
||||
std::array<DailyAlarmSetting, 0x7> day_of_week;
|
||||
};
|
||||
static_assert(sizeof(WeeklyScheduleAlarmSetting) == 0x18,
|
||||
"WeeklyScheduleAlarmSetting is an invalid size");
|
||||
|
||||
// This is nn::notification::AlarmSetting
|
||||
struct AlarmSetting {
|
||||
AlarmSettingId alarm_setting_id;
|
||||
u8 kind;
|
||||
u8 muted;
|
||||
INSERT_PADDING_BYTES_NOINIT(0x4);
|
||||
Common::UUID account_id;
|
||||
u64 application_id;
|
||||
INSERT_PADDING_BYTES_NOINIT(0x8);
|
||||
WeeklyScheduleAlarmSetting schedule;
|
||||
};
|
||||
static_assert(sizeof(AlarmSetting) == 0x40, "AlarmSetting is an invalid size");
|
||||
|
||||
enum class NotificationChannel : u8 {
|
||||
Unknown0 = 0,
|
||||
};
|
||||
|
||||
struct NotificationPresentationSetting {
|
||||
INSERT_PADDING_BYTES_NOINIT(0x10);
|
||||
};
|
||||
static_assert(sizeof(NotificationPresentationSetting) == 0x10,
|
||||
"NotificationPresentationSetting is an invalid size");
|
||||
|
||||
class NotificationServiceImpl {
|
||||
public:
|
||||
explicit NOTIF_A(Core::System& system_);
|
||||
~NOTIF_A() override;
|
||||
Result RegisterAlarmSetting(AlarmSettingId* out_alarm_setting_id,
|
||||
const AlarmSetting& alarm_setting,
|
||||
std::span<const u8> application_parameter);
|
||||
Result UpdateAlarmSetting(const AlarmSetting& alarm_setting,
|
||||
std::span<const u8> application_parameter);
|
||||
Result ListAlarmSettings(s32* out_count, std::span<AlarmSetting> out_alarms);
|
||||
Result LoadApplicationParameter(u32* out_size, std::span<u8> out_application_parameter,
|
||||
AlarmSettingId alarm_setting_id);
|
||||
Result DeleteAlarmSetting(AlarmSettingId alarm_setting_id);
|
||||
Result Initialize(u64 aruid);
|
||||
|
||||
private:
|
||||
static constexpr std::size_t max_alarms = 8;
|
||||
|
||||
// This is nn::notification::AlarmSettingId
|
||||
using AlarmSettingId = u16;
|
||||
static_assert(sizeof(AlarmSettingId) == 0x2, "AlarmSettingId is an invalid size");
|
||||
|
||||
using ApplicationParameter = std::array<u8, 0x400>;
|
||||
static_assert(sizeof(ApplicationParameter) == 0x400, "ApplicationParameter is an invalid size");
|
||||
|
||||
struct DailyAlarmSetting {
|
||||
s8 hour;
|
||||
s8 minute;
|
||||
};
|
||||
static_assert(sizeof(DailyAlarmSetting) == 0x2, "DailyAlarmSetting is an invalid size");
|
||||
|
||||
struct WeeklyScheduleAlarmSetting {
|
||||
INSERT_PADDING_BYTES(0xA);
|
||||
std::array<DailyAlarmSetting, 0x7> day_of_week;
|
||||
};
|
||||
static_assert(sizeof(WeeklyScheduleAlarmSetting) == 0x18,
|
||||
"WeeklyScheduleAlarmSetting is an invalid size");
|
||||
|
||||
// This is nn::notification::AlarmSetting
|
||||
struct AlarmSetting {
|
||||
AlarmSettingId alarm_setting_id;
|
||||
u8 kind;
|
||||
u8 muted;
|
||||
INSERT_PADDING_BYTES(0x4);
|
||||
Common::UUID account_id;
|
||||
u64 application_id;
|
||||
INSERT_PADDING_BYTES(0x8);
|
||||
WeeklyScheduleAlarmSetting schedule;
|
||||
};
|
||||
static_assert(sizeof(AlarmSetting) == 0x40, "AlarmSetting is an invalid size");
|
||||
|
||||
void RegisterAlarmSetting(HLERequestContext& ctx);
|
||||
void UpdateAlarmSetting(HLERequestContext& ctx);
|
||||
void ListAlarmSettings(HLERequestContext& ctx);
|
||||
void LoadApplicationParameter(HLERequestContext& ctx);
|
||||
void DeleteAlarmSetting(HLERequestContext& ctx);
|
||||
void Initialize(HLERequestContext& ctx);
|
||||
|
||||
std::vector<AlarmSetting>::iterator GetAlarmFromId(AlarmSettingId alarm_setting_id);
|
||||
|
||||
std::vector<AlarmSetting> alarms{};
|
||||
AlarmSettingId last_alarm_setting_id{};
|
||||
};
|
||||
|
||||
class INotificationServicesForApplication final
|
||||
: public ServiceFramework<INotificationServicesForApplication> {
|
||||
public:
|
||||
explicit INotificationServicesForApplication(Core::System& system_);
|
||||
~INotificationServicesForApplication() override;
|
||||
|
||||
private:
|
||||
Result RegisterAlarmSetting(Out<AlarmSettingId> out_alarm_setting_id,
|
||||
InLargeData<AlarmSetting, BufferAttr_HipcMapAlias> alarm_setting,
|
||||
InBuffer<BufferAttr_HipcMapAlias> application_parameter);
|
||||
Result UpdateAlarmSetting(InLargeData<AlarmSetting, BufferAttr_HipcMapAlias> alarm_setting,
|
||||
InBuffer<BufferAttr_HipcMapAlias> application_parameter);
|
||||
Result ListAlarmSettings(Out<s32> out_count,
|
||||
OutArray<AlarmSetting, BufferAttr_HipcMapAlias> out_alarms);
|
||||
Result LoadApplicationParameter(Out<u32> out_size,
|
||||
OutBuffer<BufferAttr_HipcMapAlias> out_application_parameter,
|
||||
AlarmSettingId alarm_setting_id);
|
||||
Result DeleteAlarmSetting(AlarmSettingId alarm_setting_id);
|
||||
Result Initialize(ClientAppletResourceUserId aruid);
|
||||
|
||||
NotificationServiceImpl impl;
|
||||
};
|
||||
|
||||
class INotificationSystemEventAccessor;
|
||||
|
||||
class INotificationServices final : public ServiceFramework<INotificationServices> {
|
||||
public:
|
||||
explicit INotificationServices(Core::System& system_);
|
||||
~INotificationServices() override;
|
||||
|
||||
private:
|
||||
Result RegisterAlarmSetting(Out<AlarmSettingId> out_alarm_setting_id,
|
||||
InLargeData<AlarmSetting, BufferAttr_HipcMapAlias> alarm_setting,
|
||||
InBuffer<BufferAttr_HipcMapAlias> application_parameter);
|
||||
Result UpdateAlarmSetting(InLargeData<AlarmSetting, BufferAttr_HipcMapAlias> alarm_setting,
|
||||
InBuffer<BufferAttr_HipcMapAlias> application_parameter);
|
||||
Result ListAlarmSettings(Out<s32> out_count,
|
||||
OutArray<AlarmSetting, BufferAttr_HipcMapAlias> out_alarms);
|
||||
Result LoadApplicationParameter(Out<u32> out_size,
|
||||
OutBuffer<BufferAttr_HipcMapAlias> out_application_parameter,
|
||||
AlarmSettingId alarm_setting_id);
|
||||
Result DeleteAlarmSetting(AlarmSettingId alarm_setting_id);
|
||||
Result Initialize(ClientAppletResourceUserId aruid);
|
||||
Result OpenNotificationSystemEventAccessor(Out<SharedPointer<INotificationSystemEventAccessor>>
|
||||
out_notification_system_event_accessor);
|
||||
Result GetNotificationPresentationSetting(
|
||||
Out<NotificationPresentationSetting> out_notification_presentation_setting,
|
||||
NotificationChannel notification_channel);
|
||||
|
||||
NotificationServiceImpl impl;
|
||||
};
|
||||
} // namespace Service::Glue
|
||||
|
||||
@@ -200,7 +200,7 @@ Result StaticService::GetStandardUserSystemClockAutomaticCorrectionUpdatedTime(
|
||||
}
|
||||
|
||||
Result StaticService::CalculateMonotonicSystemClockBaseTimePoint(
|
||||
Out<s64> out_time, Service::PSC::Time::SystemClockContext& context) {
|
||||
Out<s64> out_time, const Service::PSC::Time::SystemClockContext& context) {
|
||||
SCOPE_EXIT({ LOG_DEBUG(Service_Time, "called. context={} out_time={}", context, *out_time); });
|
||||
|
||||
R_RETURN(m_wrapped_service->CalculateMonotonicSystemClockBaseTimePoint(out_time, context));
|
||||
@@ -216,8 +216,8 @@ Result StaticService::GetClockSnapshot(OutClockSnapshot out_snapshot,
|
||||
|
||||
Result StaticService::GetClockSnapshotFromSystemClockContext(
|
||||
Service::PSC::Time::TimeType type, OutClockSnapshot out_snapshot,
|
||||
Service::PSC::Time::SystemClockContext& user_context,
|
||||
Service::PSC::Time::SystemClockContext& network_context) {
|
||||
const Service::PSC::Time::SystemClockContext& user_context,
|
||||
const Service::PSC::Time::SystemClockContext& network_context) {
|
||||
SCOPE_EXIT({
|
||||
LOG_DEBUG(Service_Time,
|
||||
"called. type={} out_snapshot={} user_context={} network_context={}", type,
|
||||
|
||||
@@ -58,12 +58,12 @@ public:
|
||||
Result GetStandardUserSystemClockAutomaticCorrectionUpdatedTime(
|
||||
Out<Service::PSC::Time::SteadyClockTimePoint> out_time_point);
|
||||
Result CalculateMonotonicSystemClockBaseTimePoint(
|
||||
Out<s64> out_time, Service::PSC::Time::SystemClockContext& context);
|
||||
Out<s64> out_time, const Service::PSC::Time::SystemClockContext& context);
|
||||
Result GetClockSnapshot(OutClockSnapshot out_snapshot, Service::PSC::Time::TimeType type);
|
||||
Result GetClockSnapshotFromSystemClockContext(
|
||||
Service::PSC::Time::TimeType type, OutClockSnapshot out_snapshot,
|
||||
Service::PSC::Time::SystemClockContext& user_context,
|
||||
Service::PSC::Time::SystemClockContext& network_context);
|
||||
const Service::PSC::Time::SystemClockContext& user_context,
|
||||
const Service::PSC::Time::SystemClockContext& network_context);
|
||||
Result CalculateStandardUserSystemClockDifferenceByUser(Out<s64> out_difference,
|
||||
InClockSnapshot a, InClockSnapshot b);
|
||||
Result CalculateSpanBetween(Out<s64> out_time, InClockSnapshot a, InClockSnapshot b);
|
||||
|
||||
@@ -62,7 +62,8 @@ Result TimeZoneService::GetDeviceLocationName(
|
||||
R_RETURN(m_wrapped_service->GetDeviceLocationName(out_location_name));
|
||||
}
|
||||
|
||||
Result TimeZoneService::SetDeviceLocationName(Service::PSC::Time::LocationName& location_name) {
|
||||
Result TimeZoneService::SetDeviceLocationName(
|
||||
const Service::PSC::Time::LocationName& location_name) {
|
||||
LOG_DEBUG(Service_Time, "called. location_name={}", location_name);
|
||||
|
||||
R_UNLESS(m_can_write_timezone_device_location, Service::PSC::Time::ResultPermissionDenied);
|
||||
@@ -110,7 +111,8 @@ Result TimeZoneService::LoadLocationNameList(
|
||||
R_RETURN(GetTimeZoneLocationList(*out_count, out_names, out_names.size(), index));
|
||||
}
|
||||
|
||||
Result TimeZoneService::LoadTimeZoneRule(OutRule out_rule, Service::PSC::Time::LocationName& name) {
|
||||
Result TimeZoneService::LoadTimeZoneRule(OutRule out_rule,
|
||||
const Service::PSC::Time::LocationName& name) {
|
||||
LOG_DEBUG(Service_Time, "called. name={}", name);
|
||||
|
||||
std::scoped_lock l{m_mutex};
|
||||
@@ -139,7 +141,8 @@ Result TimeZoneService::GetDeviceLocationNameAndUpdatedTime(
|
||||
}
|
||||
|
||||
Result TimeZoneService::SetDeviceLocationNameWithTimeZoneRule(
|
||||
Service::PSC::Time::LocationName& location_name, InBuffer<BufferAttr_HipcAutoSelect> binary) {
|
||||
const Service::PSC::Time::LocationName& location_name,
|
||||
InBuffer<BufferAttr_HipcAutoSelect> binary) {
|
||||
LOG_DEBUG(Service_Time, "called. location_name={}", location_name);
|
||||
|
||||
R_UNLESS(m_can_write_timezone_device_location, Service::PSC::Time::ResultPermissionDenied);
|
||||
|
||||
@@ -46,18 +46,20 @@ public:
|
||||
~TimeZoneService() override;
|
||||
|
||||
Result GetDeviceLocationName(Out<Service::PSC::Time::LocationName> out_location_name);
|
||||
Result SetDeviceLocationName(Service::PSC::Time::LocationName& location_name);
|
||||
Result SetDeviceLocationName(const Service::PSC::Time::LocationName& location_name);
|
||||
Result GetTotalLocationNameCount(Out<u32> out_count);
|
||||
Result LoadLocationNameList(
|
||||
Out<u32> out_count,
|
||||
OutArray<Service::PSC::Time::LocationName, BufferAttr_HipcMapAlias> out_names, u32 index);
|
||||
Result LoadTimeZoneRule(OutRule out_rule, Service::PSC::Time::LocationName& location_name);
|
||||
Result LoadTimeZoneRule(OutRule out_rule,
|
||||
const Service::PSC::Time::LocationName& location_name);
|
||||
Result GetTimeZoneRuleVersion(Out<Service::PSC::Time::RuleVersion> out_rule_version);
|
||||
Result GetDeviceLocationNameAndUpdatedTime(
|
||||
Out<Service::PSC::Time::LocationName> location_name,
|
||||
Out<Service::PSC::Time::SteadyClockTimePoint> out_time_point);
|
||||
Result SetDeviceLocationNameWithTimeZoneRule(Service::PSC::Time::LocationName& location_name,
|
||||
InBuffer<BufferAttr_HipcAutoSelect> binary);
|
||||
Result SetDeviceLocationNameWithTimeZoneRule(
|
||||
const Service::PSC::Time::LocationName& location_name,
|
||||
InBuffer<BufferAttr_HipcAutoSelect> binary);
|
||||
Result ParseTimeZoneBinary(OutRule out_rule, InBuffer<BufferAttr_HipcAutoSelect> binary);
|
||||
Result GetDeviceLocationNameOperationEventReadableHandle(
|
||||
OutCopyHandle<Kernel::KReadableEvent> out_event);
|
||||
|
||||
@@ -65,6 +65,7 @@ Result MountTimeZoneBinary(Core::System& system) {
|
||||
// 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
|
||||
// synthesise them instead.
|
||||
g_time_zone_binary_mount_result = ResultSuccess;
|
||||
Service::PSC::Time::LocationName name{"Etc/GMT"};
|
||||
if (!IsTimeZoneBinaryValid(name)) {
|
||||
ResetTimeZoneBinary();
|
||||
@@ -98,7 +99,7 @@ void GetTimeZoneBinaryVersionPath(std::string& out_path) {
|
||||
out_path = "/version.txt";
|
||||
}
|
||||
|
||||
void GetTimeZoneZonePath(std::string& out_path, Service::PSC::Time::LocationName& name) {
|
||||
void GetTimeZoneZonePath(std::string& out_path, const Service::PSC::Time::LocationName& name) {
|
||||
if (g_time_zone_binary_mount_result != ResultSuccess) {
|
||||
return;
|
||||
}
|
||||
@@ -106,7 +107,7 @@ void GetTimeZoneZonePath(std::string& out_path, Service::PSC::Time::LocationName
|
||||
out_path = fmt::format("/zoneinfo/{}", name.data());
|
||||
}
|
||||
|
||||
bool IsTimeZoneBinaryValid(Service::PSC::Time::LocationName& name) {
|
||||
bool IsTimeZoneBinaryValid(const Service::PSC::Time::LocationName& name) {
|
||||
std::string path{};
|
||||
GetTimeZoneZonePath(path, name);
|
||||
|
||||
@@ -155,7 +156,7 @@ Result GetTimeZoneVersion(Service::PSC::Time::RuleVersion& out_rule_version) {
|
||||
}
|
||||
|
||||
Result GetTimeZoneRule(std::span<const u8>& out_rule, size_t& out_rule_size,
|
||||
Service::PSC::Time::LocationName& name) {
|
||||
const Service::PSC::Time::LocationName& name) {
|
||||
std::string path{};
|
||||
GetTimeZoneZonePath(path, name);
|
||||
|
||||
|
||||
@@ -19,12 +19,12 @@ void ResetTimeZoneBinary();
|
||||
Result MountTimeZoneBinary(Core::System& system);
|
||||
void GetTimeZoneBinaryListPath(std::string& out_path);
|
||||
void GetTimeZoneBinaryVersionPath(std::string& out_path);
|
||||
void GetTimeZoneZonePath(std::string& out_path, Service::PSC::Time::LocationName& name);
|
||||
bool IsTimeZoneBinaryValid(Service::PSC::Time::LocationName& name);
|
||||
void GetTimeZoneZonePath(std::string& out_path, const Service::PSC::Time::LocationName& name);
|
||||
bool IsTimeZoneBinaryValid(const Service::PSC::Time::LocationName& name);
|
||||
u32 GetTimeZoneCount();
|
||||
Result GetTimeZoneVersion(Service::PSC::Time::RuleVersion& out_rule_version);
|
||||
Result GetTimeZoneRule(std::span<const u8>& out_rule, size_t& out_rule_size,
|
||||
Service::PSC::Time::LocationName& name);
|
||||
const Service::PSC::Time::LocationName& name);
|
||||
Result GetTimeZoneLocationList(u32& out_count,
|
||||
std::span<Service::PSC::Time::LocationName> out_names,
|
||||
size_t max_names, u32 index);
|
||||
|
||||
@@ -36,7 +36,7 @@ void LoopProcess(Core::System& system) {
|
||||
server_manager->RegisterNamedService(
|
||||
"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:sys", std::make_shared<IRS::IRS_SYS>(system));
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "core/hle/service/cmif_serialization.h"
|
||||
#include "core/hle/service/hid/hid_debug_server.h"
|
||||
#include "core/hle/service/ipc_helpers.h"
|
||||
#include "hid_core/hid_types.h"
|
||||
@@ -11,7 +12,6 @@
|
||||
|
||||
#include "hid_core/resources/touch_screen/gesture.h"
|
||||
#include "hid_core/resources/touch_screen/touch_screen.h"
|
||||
#include "hid_core/resources/touch_screen/touch_types.h"
|
||||
|
||||
namespace Service::HID {
|
||||
|
||||
@@ -24,14 +24,14 @@ IHidDebugServer::IHidDebugServer(Core::System& system_, std::shared_ptr<Resource
|
||||
{0, nullptr, "DeactivateDebugPad"},
|
||||
{1, nullptr, "SetDebugPadAutoPilotState"},
|
||||
{2, nullptr, "UnsetDebugPadAutoPilotState"},
|
||||
{10, &IHidDebugServer::DeactivateTouchScreen, "DeactivateTouchScreen"},
|
||||
{11, &IHidDebugServer::SetTouchScreenAutoPilotState, "SetTouchScreenAutoPilotState"},
|
||||
{12, &IHidDebugServer::UnsetTouchScreenAutoPilotState, "UnsetTouchScreenAutoPilotState"},
|
||||
{13, &IHidDebugServer::GetTouchScreenConfiguration, "GetTouchScreenConfiguration"},
|
||||
{14, &IHidDebugServer::ProcessTouchScreenAutoTune, "ProcessTouchScreenAutoTune"},
|
||||
{15, &IHidDebugServer::ForceStopTouchScreenManagement, "ForceStopTouchScreenManagement"},
|
||||
{16, &IHidDebugServer::ForceRestartTouchScreenManagement, "ForceRestartTouchScreenManagement"},
|
||||
{17, &IHidDebugServer::IsTouchScreenManaged, "IsTouchScreenManaged"},
|
||||
{10, C<&IHidDebugServer::DeactivateTouchScreen>, "DeactivateTouchScreen"},
|
||||
{11, C<&IHidDebugServer::SetTouchScreenAutoPilotState>, "SetTouchScreenAutoPilotState"},
|
||||
{12, C<&IHidDebugServer::UnsetTouchScreenAutoPilotState>, "UnsetTouchScreenAutoPilotState"},
|
||||
{13, C<&IHidDebugServer::GetTouchScreenConfiguration>, "GetTouchScreenConfiguration"},
|
||||
{14, C<&IHidDebugServer::ProcessTouchScreenAutoTune>, "ProcessTouchScreenAutoTune"},
|
||||
{15, C<&IHidDebugServer::ForceStopTouchScreenManagement>, "ForceStopTouchScreenManagement"},
|
||||
{16, C<&IHidDebugServer::ForceRestartTouchScreenManagement>, "ForceRestartTouchScreenManagement"},
|
||||
{17, C<&IHidDebugServer::IsTouchScreenManaged>, "IsTouchScreenManaged"},
|
||||
{20, nullptr, "DeactivateMouse"},
|
||||
{21, nullptr, "SetMouseAutoPilotState"},
|
||||
{22, nullptr, "UnsetMouseAutoPilotState"},
|
||||
@@ -47,7 +47,7 @@ IHidDebugServer::IHidDebugServer(Core::System& system_, std::shared_ptr<Resource
|
||||
{60, nullptr, "ClearNpadSystemCommonPolicy"},
|
||||
{61, nullptr, "DeactivateNpad"},
|
||||
{62, nullptr, "ForceDisconnectNpad"},
|
||||
{91, &IHidDebugServer::DeactivateGesture, "DeactivateGesture"},
|
||||
{91, C<&IHidDebugServer::DeactivateGesture>, "DeactivateGesture"},
|
||||
{110, nullptr, "DeactivateHomeButton"},
|
||||
{111, nullptr, "SetHomeButtonAutoPilotState"},
|
||||
{112, nullptr, "UnsetHomeButtonAutoPilotState"},
|
||||
@@ -160,169 +160,122 @@ IHidDebugServer::IHidDebugServer(Core::System& system_, std::shared_ptr<Resource
|
||||
}
|
||||
|
||||
IHidDebugServer::~IHidDebugServer() = default;
|
||||
void IHidDebugServer::DeactivateTouchScreen(HLERequestContext& ctx) {
|
||||
|
||||
Result IHidDebugServer::DeactivateTouchScreen() {
|
||||
LOG_INFO(Service_HID, "called");
|
||||
|
||||
Result result = ResultSuccess;
|
||||
|
||||
if (!firmware_settings->IsDeviceManaged()) {
|
||||
result = GetResourceManager()->GetTouchScreen()->Deactivate();
|
||||
R_RETURN(GetResourceManager()->GetTouchScreen()->Deactivate());
|
||||
}
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(result);
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
void IHidDebugServer::SetTouchScreenAutoPilotState(HLERequestContext& ctx) {
|
||||
Result IHidDebugServer::SetTouchScreenAutoPilotState(
|
||||
InArray<TouchState, BufferAttr_HipcMapAlias> auto_pilot_buffer) {
|
||||
AutoPilotState auto_pilot{};
|
||||
auto_pilot.count = ctx.GetReadBufferNumElements<TouchState>();
|
||||
const auto buffer = ctx.ReadBuffer();
|
||||
|
||||
auto_pilot.count = std::min(auto_pilot.count, static_cast<u64>(auto_pilot.state.size()));
|
||||
memcpy(auto_pilot.state.data(), buffer.data(), auto_pilot.count * sizeof(TouchState));
|
||||
auto_pilot.count =
|
||||
static_cast<u64>(std::min(auto_pilot_buffer.size(), auto_pilot.state.size()));
|
||||
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);
|
||||
|
||||
const Result result =
|
||||
GetResourceManager()->GetTouchScreen()->SetTouchScreenAutoPilotState(auto_pilot);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(result);
|
||||
R_RETURN(GetResourceManager()->GetTouchScreen()->SetTouchScreenAutoPilotState(auto_pilot));
|
||||
}
|
||||
|
||||
void IHidDebugServer::UnsetTouchScreenAutoPilotState(HLERequestContext& ctx) {
|
||||
Result IHidDebugServer::UnsetTouchScreenAutoPilotState() {
|
||||
LOG_INFO(Service_HID, "called");
|
||||
|
||||
const Result result = GetResourceManager()->GetTouchScreen()->UnsetTouchScreenAutoPilotState();
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(result);
|
||||
R_RETURN(GetResourceManager()->GetTouchScreen()->UnsetTouchScreenAutoPilotState());
|
||||
}
|
||||
|
||||
void IHidDebugServer::GetTouchScreenConfiguration(HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto applet_resource_user_id{rp.Pop<u64>()};
|
||||
Result IHidDebugServer::GetTouchScreenConfiguration(
|
||||
Out<Core::HID::TouchScreenConfigurationForNx> out_touchscreen_config,
|
||||
ClientAppletResourceUserId aruid) {
|
||||
LOG_INFO(Service_HID, "called, applet_resource_user_id={}", aruid.pid);
|
||||
|
||||
LOG_INFO(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
|
||||
R_TRY(GetResourceManager()->GetTouchScreen()->GetTouchScreenConfiguration(
|
||||
*out_touchscreen_config, aruid.pid));
|
||||
|
||||
Core::HID::TouchScreenConfigurationForNx touchscreen_config{};
|
||||
const Result result = GetResourceManager()->GetTouchScreen()->GetTouchScreenConfiguration(
|
||||
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;
|
||||
if (out_touchscreen_config->mode != Core::HID::TouchScreenModeForNx::Heat2 &&
|
||||
out_touchscreen_config->mode != Core::HID::TouchScreenModeForNx::Finger) {
|
||||
out_touchscreen_config->mode = Core::HID::TouchScreenModeForNx::UseSystemSetting;
|
||||
}
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 6};
|
||||
rb.Push(result);
|
||||
rb.PushRaw(touchscreen_config);
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
void IHidDebugServer::ProcessTouchScreenAutoTune(HLERequestContext& ctx) {
|
||||
Result IHidDebugServer::ProcessTouchScreenAutoTune() {
|
||||
LOG_INFO(Service_HID, "called");
|
||||
|
||||
Result result = GetResourceManager()->GetTouchScreen()->ProcessTouchScreenAutoTune();
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(result);
|
||||
R_RETURN(GetResourceManager()->GetTouchScreen()->ProcessTouchScreenAutoTune());
|
||||
}
|
||||
|
||||
void IHidDebugServer::ForceStopTouchScreenManagement(HLERequestContext& ctx) {
|
||||
Result IHidDebugServer::ForceStopTouchScreenManagement() {
|
||||
LOG_INFO(Service_HID, "called");
|
||||
|
||||
if (!firmware_settings->IsDeviceManaged()) {
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultSuccess);
|
||||
return;
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result result = ResultSuccess;
|
||||
bool is_touch_active{};
|
||||
bool is_gesture_active{};
|
||||
auto touch_screen = GetResourceManager()->GetTouchScreen();
|
||||
auto gesture = GetResourceManager()->GetGesture();
|
||||
|
||||
if (firmware_settings->IsTouchI2cManaged()) {
|
||||
result = touch_screen->IsActive(is_touch_active);
|
||||
if (result.IsSuccess()) {
|
||||
result = gesture->IsActive(is_gesture_active);
|
||||
bool is_touch_active{};
|
||||
bool is_gesture_active{};
|
||||
R_TRY(touch_screen->IsActive(is_touch_active));
|
||||
R_TRY(gesture->IsActive(is_gesture_active));
|
||||
|
||||
if (is_touch_active) {
|
||||
R_TRY(touch_screen->Deactivate());
|
||||
}
|
||||
if (result.IsSuccess() && is_touch_active) {
|
||||
result = touch_screen->Deactivate();
|
||||
}
|
||||
if (result.IsSuccess() && is_gesture_active) {
|
||||
result = gesture->Deactivate();
|
||||
if (is_gesture_active) {
|
||||
R_TRY(gesture->Deactivate());
|
||||
}
|
||||
}
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(result);
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
void IHidDebugServer::ForceRestartTouchScreenManagement(HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
struct Parameters {
|
||||
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>()};
|
||||
|
||||
Result IHidDebugServer::ForceRestartTouchScreenManagement(u32 basic_gesture_id,
|
||||
ClientAppletResourceUserId aruid) {
|
||||
LOG_INFO(Service_HID, "called, basic_gesture_id={}, applet_resource_user_id={}",
|
||||
parameters.basic_gesture_id, parameters.applet_resource_user_id);
|
||||
basic_gesture_id, aruid.pid);
|
||||
|
||||
Result result = ResultSuccess;
|
||||
auto touch_screen = GetResourceManager()->GetTouchScreen();
|
||||
auto gesture = GetResourceManager()->GetGesture();
|
||||
|
||||
if (firmware_settings->IsDeviceManaged() && firmware_settings->IsTouchI2cManaged()) {
|
||||
result = gesture->Activate();
|
||||
if (result.IsSuccess()) {
|
||||
result =
|
||||
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_TRY(gesture->Activate());
|
||||
R_TRY(gesture->Activate(aruid.pid, basic_gesture_id));
|
||||
R_TRY(touch_screen->Activate());
|
||||
R_TRY(touch_screen->Activate(aruid.pid));
|
||||
}
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(result);
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
void IHidDebugServer::IsTouchScreenManaged(HLERequestContext& ctx) {
|
||||
Result IHidDebugServer::IsTouchScreenManaged(Out<bool> out_is_managed) {
|
||||
LOG_INFO(Service_HID, "called");
|
||||
|
||||
bool is_touch_active{};
|
||||
bool is_gesture_active{};
|
||||
R_TRY(GetResourceManager()->GetTouchScreen()->IsActive(is_touch_active));
|
||||
R_TRY(GetResourceManager()->GetGesture()->IsActive(is_gesture_active));
|
||||
|
||||
Result result = GetResourceManager()->GetTouchScreen()->IsActive(is_touch_active);
|
||||
if (result.IsSuccess()) {
|
||||
result = GetResourceManager()->GetGesture()->IsActive(is_gesture_active);
|
||||
}
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(result);
|
||||
rb.Push(is_touch_active | is_gesture_active);
|
||||
*out_is_managed = is_touch_active || is_gesture_active;
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
void IHidDebugServer::DeactivateGesture(HLERequestContext& ctx) {
|
||||
Result IHidDebugServer::DeactivateGesture() {
|
||||
LOG_INFO(Service_HID, "called");
|
||||
|
||||
Result result = ResultSuccess;
|
||||
|
||||
if (!firmware_settings->IsDeviceManaged()) {
|
||||
result = GetResourceManager()->GetGesture()->Deactivate();
|
||||
R_RETURN(GetResourceManager()->GetGesture()->Deactivate());
|
||||
}
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(result);
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
std::shared_ptr<ResourceManager> IHidDebugServer::GetResourceManager() {
|
||||
|
||||
@@ -3,7 +3,9 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "core/hle/service/cmif_types.h"
|
||||
#include "core/hle/service/service.h"
|
||||
#include "hid_core/resources/touch_screen/touch_types.h"
|
||||
|
||||
namespace Core {
|
||||
class System;
|
||||
@@ -20,15 +22,19 @@ public:
|
||||
~IHidDebugServer() override;
|
||||
|
||||
private:
|
||||
void DeactivateTouchScreen(HLERequestContext& ctx);
|
||||
void SetTouchScreenAutoPilotState(HLERequestContext& ctx);
|
||||
void UnsetTouchScreenAutoPilotState(HLERequestContext& ctx);
|
||||
void GetTouchScreenConfiguration(HLERequestContext& ctx);
|
||||
void ProcessTouchScreenAutoTune(HLERequestContext& ctx);
|
||||
void ForceStopTouchScreenManagement(HLERequestContext& ctx);
|
||||
void ForceRestartTouchScreenManagement(HLERequestContext& ctx);
|
||||
void IsTouchScreenManaged(HLERequestContext& ctx);
|
||||
void DeactivateGesture(HLERequestContext& ctx);
|
||||
Result DeactivateTouchScreen();
|
||||
Result SetTouchScreenAutoPilotState(
|
||||
InArray<TouchState, BufferAttr_HipcMapAlias> auto_pilot_buffer);
|
||||
Result UnsetTouchScreenAutoPilotState();
|
||||
Result GetTouchScreenConfiguration(
|
||||
Out<Core::HID::TouchScreenConfigurationForNx> out_touchscreen_config,
|
||||
ClientAppletResourceUserId aruid);
|
||||
Result ProcessTouchScreenAutoTune();
|
||||
Result ForceStopTouchScreenManagement();
|
||||
Result ForceRestartTouchScreenManagement(u32 basic_gesture_id,
|
||||
ClientAppletResourceUserId aruid);
|
||||
Result IsTouchScreenManaged(Out<bool> out_is_managed);
|
||||
Result DeactivateGesture();
|
||||
|
||||
std::shared_ptr<ResourceManager> GetResourceManager();
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include "core/hle/kernel/k_readable_event.h"
|
||||
#include "core/hle/kernel/k_shared_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/ipc_helpers.h"
|
||||
#include "core/hle/service/service.h"
|
||||
@@ -22,25 +23,25 @@ namespace Service::HID {
|
||||
// (15ms, 66Hz)
|
||||
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} {
|
||||
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{1, &HidBus::GetBusHandle, "GetBusHandle"},
|
||||
{2, &HidBus::IsExternalDeviceConnected, "IsExternalDeviceConnected"},
|
||||
{3, &HidBus::Initialize, "Initialize"},
|
||||
{4, &HidBus::Finalize, "Finalize"},
|
||||
{5, &HidBus::EnableExternalDevice, "EnableExternalDevice"},
|
||||
{6, &HidBus::GetExternalDeviceId, "GetExternalDeviceId"},
|
||||
{7, &HidBus::SendCommandAsync, "SendCommandAsync"},
|
||||
{8, &HidBus::GetSendCommandAsynceResult, "GetSendCommandAsynceResult"},
|
||||
{9, &HidBus::SetEventForSendCommandAsycResult, "SetEventForSendCommandAsycResult"},
|
||||
{10, &HidBus::GetSharedMemoryHandle, "GetSharedMemoryHandle"},
|
||||
{11, &HidBus::EnableJoyPollingReceiveMode, "EnableJoyPollingReceiveMode"},
|
||||
{12, &HidBus::DisableJoyPollingReceiveMode, "DisableJoyPollingReceiveMode"},
|
||||
{1, C<&Hidbus::GetBusHandle>, "GetBusHandle"},
|
||||
{2, C<&Hidbus::IsExternalDeviceConnected>, "IsExternalDeviceConnected"},
|
||||
{3, C<&Hidbus::Initialize>, "Initialize"},
|
||||
{4, C<&Hidbus::Finalize>, "Finalize"},
|
||||
{5, C<&Hidbus::EnableExternalDevice>, "EnableExternalDevice"},
|
||||
{6, C<&Hidbus::GetExternalDeviceId>, "GetExternalDeviceId"},
|
||||
{7, C<&Hidbus::SendCommandAsync>, "SendCommandAsync"},
|
||||
{8, C<&Hidbus::GetSendCommandAsynceResult>, "GetSendCommandAsynceResult"},
|
||||
{9, C<&Hidbus::SetEventForSendCommandAsycResult>, "SetEventForSendCommandAsycResult"},
|
||||
{10, C<&Hidbus::GetSharedMemoryHandle>, "GetSharedMemoryHandle"},
|
||||
{11, C<&Hidbus::EnableJoyPollingReceiveMode>, "EnableJoyPollingReceiveMode"},
|
||||
{12, C<&Hidbus::DisableJoyPollingReceiveMode>, "DisableJoyPollingReceiveMode"},
|
||||
{13, nullptr, "GetPollingData"},
|
||||
{14, &HidBus::SetStatusManagerType, "SetStatusManagerType"},
|
||||
{14, C<&Hidbus::SetStatusManagerType>, "SetStatusManagerType"},
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
@@ -60,11 +61,11 @@ HidBus::HidBus(Core::System& system_)
|
||||
hidbus_update_event);
|
||||
}
|
||||
|
||||
HidBus::~HidBus() {
|
||||
Hidbus::~Hidbus() {
|
||||
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) {
|
||||
for (std::size_t i = 0; i < devices.size(); ++i) {
|
||||
if (!devices[i].is_device_initialized) {
|
||||
@@ -84,7 +85,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) {
|
||||
const auto& device_handle = devices[i].handle;
|
||||
if (handle.abstracted_pad_id == device_handle.abstracted_pad_id &&
|
||||
@@ -98,20 +99,11 @@ std::optional<std::size_t> HidBus::GetDeviceIndexFromHandle(BusHandle handle) co
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
void HidBus::GetBusHandle(HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
struct Parameters {
|
||||
Core::HID::NpadIdType npad_id;
|
||||
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);
|
||||
Result Hidbus::GetBusHandle(Out<bool> out_is_valid, Out<BusHandle> out_bus_handle,
|
||||
Core::HID::NpadIdType npad_id, BusType bus_type,
|
||||
AppletResourceUserId aruid) {
|
||||
LOG_INFO(Service_HID, "called, npad_id={}, bus_type={}, applet_resource_user_id={}", npad_id,
|
||||
bus_type, aruid.pid);
|
||||
|
||||
bool is_handle_found = 0;
|
||||
std::size_t handle_index = 0;
|
||||
@@ -121,8 +113,8 @@ void HidBus::GetBusHandle(HLERequestContext& ctx) {
|
||||
if (!handle.is_valid) {
|
||||
continue;
|
||||
}
|
||||
if (static_cast<Core::HID::NpadIdType>(handle.player_number) == parameters.npad_id &&
|
||||
handle.bus_type_id == static_cast<u8>(parameters.bus_type)) {
|
||||
if (handle.player_number.As<Core::HID::NpadIdType>() == npad_id &&
|
||||
handle.bus_type_id == static_cast<u8>(bus_type)) {
|
||||
is_handle_found = true;
|
||||
handle_index = i;
|
||||
break;
|
||||
@@ -135,388 +127,231 @@ void HidBus::GetBusHandle(HLERequestContext& ctx) {
|
||||
if (devices[i].handle.is_valid) {
|
||||
continue;
|
||||
}
|
||||
devices[i].handle = {
|
||||
.abstracted_pad_id = static_cast<u8>(i),
|
||||
.internal_index = static_cast<u8>(i),
|
||||
.player_number = static_cast<u8>(parameters.npad_id),
|
||||
.bus_type_id = static_cast<u8>(parameters.bus_type),
|
||||
.is_valid = true,
|
||||
};
|
||||
devices[i].handle.raw = 0;
|
||||
devices[i].handle.abstracted_pad_id.Assign(i);
|
||||
devices[i].handle.internal_index.Assign(i);
|
||||
devices[i].handle.player_number.Assign(static_cast<u8>(npad_id));
|
||||
devices[i].handle.bus_type_id.Assign(static_cast<u8>(bus_type));
|
||||
devices[i].handle.is_valid.Assign(true);
|
||||
handle_index = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
struct OutData {
|
||||
bool is_valid;
|
||||
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);
|
||||
*out_is_valid = true;
|
||||
*out_bus_handle = devices[handle_index].handle;
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
void HidBus::IsExternalDeviceConnected(HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto bus_handle_{rp.PopRaw<BusHandle>()};
|
||||
|
||||
Result Hidbus::IsExternalDeviceConnected(Out<bool> out_is_connected, BusHandle bus_handle) {
|
||||
LOG_INFO(Service_HID,
|
||||
"Called, abstracted_pad_id={}, bus_type={}, internal_index={}, "
|
||||
"player_number={}, is_valid={}",
|
||||
bus_handle_.abstracted_pad_id, bus_handle_.bus_type_id, bus_handle_.internal_index,
|
||||
bus_handle_.player_number, bus_handle_.is_valid);
|
||||
bus_handle.abstracted_pad_id, bus_handle.bus_type_id, 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);
|
||||
|
||||
if (device_index) {
|
||||
const auto& device = devices[device_index.value()].device;
|
||||
const bool is_attached = device->IsDeviceActivated();
|
||||
R_UNLESS(device_index.has_value(), ResultUnknown);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.Push(is_attached);
|
||||
return;
|
||||
}
|
||||
|
||||
LOG_ERROR(Service_HID, "Invalid handle");
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultUnknown);
|
||||
return;
|
||||
*out_is_connected = devices[device_index.value()].device->IsDeviceActivated();
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
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>()};
|
||||
|
||||
Result Hidbus::Initialize(BusHandle bus_handle, AppletResourceUserId aruid) {
|
||||
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);
|
||||
bus_handle.abstracted_pad_id, bus_handle.bus_type_id, bus_handle.internal_index,
|
||||
bus_handle.player_number, bus_handle.is_valid, aruid.pid);
|
||||
|
||||
is_hidbus_enabled = true;
|
||||
|
||||
const auto device_index = GetDeviceIndexFromHandle(bus_handle_);
|
||||
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];
|
||||
R_UNLESS(device_index.has_value(), ResultUnknown);
|
||||
|
||||
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_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();
|
||||
const auto entry_index = devices[device_index.value()].handle.internal_index;
|
||||
auto& cur_entry = hidbus_status.entries[entry_index];
|
||||
|
||||
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_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;
|
||||
std::memcpy(system.Kernel().GetHidBusSharedMem().GetPointer(), &hidbus_status,
|
||||
sizeof(hidbus_status));
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
void HidBus::EnableExternalDevice(HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
struct Parameters {
|
||||
bool enable;
|
||||
INSERT_PADDING_BYTES_NOINIT(7);
|
||||
BusHandle bus_handle;
|
||||
u64 inval;
|
||||
u64 applet_resource_user_id;
|
||||
};
|
||||
static_assert(sizeof(Parameters) == 0x20, "Parameters has incorrect size.");
|
||||
Result Hidbus::Finalize(BusHandle bus_handle, AppletResourceUserId aruid) {
|
||||
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, aruid.pid);
|
||||
|
||||
const auto parameters{rp.PopRaw<Parameters>()};
|
||||
const auto device_index = GetDeviceIndexFromHandle(bus_handle);
|
||||
|
||||
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,
|
||||
"called, enable={}, abstracted_pad_id={}, bus_type={}, internal_index={}, "
|
||||
"player_number={}, is_valid={}, inval={}, applet_resource_user_id{}",
|
||||
parameters.enable, parameters.bus_handle.abstracted_pad_id,
|
||||
parameters.bus_handle.bus_type_id, parameters.bus_handle.internal_index,
|
||||
parameters.bus_handle.player_number, parameters.bus_handle.is_valid, parameters.inval,
|
||||
parameters.applet_resource_user_id);
|
||||
is_enabled, bus_handle.abstracted_pad_id, bus_handle.bus_type_id,
|
||||
bus_handle.internal_index, bus_handle.player_number, bus_handle.is_valid, inval,
|
||||
aruid.pid);
|
||||
|
||||
const auto device_index = GetDeviceIndexFromHandle(parameters.bus_handle);
|
||||
const auto device_index = GetDeviceIndexFromHandle(bus_handle);
|
||||
|
||||
if (device_index) {
|
||||
auto& device = devices[device_index.value()].device;
|
||||
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;
|
||||
R_UNLESS(device_index.has_value(), ResultUnknown);
|
||||
devices[device_index.value()].device->Enable(is_enabled);
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
void HidBus::GetExternalDeviceId(HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto bus_handle_{rp.PopRaw<BusHandle>()};
|
||||
|
||||
Result Hidbus::GetExternalDeviceId(Out<u32> out_device_id, BusHandle bus_handle) {
|
||||
LOG_DEBUG(Service_HID,
|
||||
"called, abstracted_pad_id={}, bus_type={}, internal_index={}, player_number={}, "
|
||||
"is_valid={}",
|
||||
bus_handle_.abstracted_pad_id, bus_handle_.bus_type_id, bus_handle_.internal_index,
|
||||
bus_handle_.player_number, bus_handle_.is_valid);
|
||||
bus_handle.abstracted_pad_id, bus_handle.bus_type_id, 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);
|
||||
|
||||
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;
|
||||
}
|
||||
R_UNLESS(device_index.has_value(), ResultUnknown);
|
||||
|
||||
LOG_ERROR(Service_HID, "Invalid handle");
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultUnknown);
|
||||
return;
|
||||
*out_device_id = devices[device_index.value()].device->GetDeviceId();
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
void HidBus::SendCommandAsync(HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto data = ctx.ReadBuffer();
|
||||
const auto bus_handle_{rp.PopRaw<BusHandle>()};
|
||||
|
||||
Result Hidbus::SendCommandAsync(BusHandle bus_handle,
|
||||
InBuffer<BufferAttr_HipcAutoSelect> buffer_data) {
|
||||
LOG_DEBUG(Service_HID,
|
||||
"called, data_size={}, abstracted_pad_id={}, bus_type={}, internal_index={}, "
|
||||
"player_number={}, is_valid={}",
|
||||
data.size(), bus_handle_.abstracted_pad_id, bus_handle_.bus_type_id,
|
||||
bus_handle_.internal_index, bus_handle_.player_number, bus_handle_.is_valid);
|
||||
buffer_data.size(), bus_handle.abstracted_pad_id, bus_handle.bus_type_id,
|
||||
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);
|
||||
|
||||
if (device_index) {
|
||||
auto& device = devices[device_index.value()].device;
|
||||
device->SetCommand(data);
|
||||
R_UNLESS(device_index.has_value(), ResultUnknown);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultSuccess);
|
||||
return;
|
||||
}
|
||||
|
||||
LOG_ERROR(Service_HID, "Invalid handle");
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultUnknown);
|
||||
return;
|
||||
devices[device_index.value()].device->SetCommand(buffer_data);
|
||||
R_SUCCEED();
|
||||
};
|
||||
|
||||
void HidBus::GetSendCommandAsynceResult(HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto bus_handle_{rp.PopRaw<BusHandle>()};
|
||||
|
||||
Result Hidbus::GetSendCommandAsynceResult(Out<u64> out_data_size, BusHandle bus_handle,
|
||||
OutBuffer<BufferAttr_HipcAutoSelect> out_buffer_data) {
|
||||
LOG_DEBUG(Service_HID,
|
||||
"called, abstracted_pad_id={}, bus_type={}, internal_index={}, player_number={}, "
|
||||
"is_valid={}",
|
||||
bus_handle_.abstracted_pad_id, bus_handle_.bus_type_id, bus_handle_.internal_index,
|
||||
bus_handle_.player_number, bus_handle_.is_valid);
|
||||
bus_handle.abstracted_pad_id, bus_handle.bus_type_id, 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);
|
||||
|
||||
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);
|
||||
R_UNLESS(device_index.has_value(), ResultUnknown);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 4};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.Push<u64>(data_size);
|
||||
return;
|
||||
}
|
||||
|
||||
LOG_ERROR(Service_HID, "Invalid handle");
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultUnknown);
|
||||
return;
|
||||
*out_data_size = devices[device_index.value()].device->GetReply(out_buffer_data);
|
||||
R_SUCCEED();
|
||||
};
|
||||
|
||||
void HidBus::SetEventForSendCommandAsycResult(HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto bus_handle_{rp.PopRaw<BusHandle>()};
|
||||
|
||||
Result Hidbus::SetEventForSendCommandAsycResult(OutCopyHandle<Kernel::KReadableEvent> out_event,
|
||||
BusHandle bus_handle) {
|
||||
LOG_INFO(Service_HID,
|
||||
"called, abstracted_pad_id={}, bus_type={}, internal_index={}, player_number={}, "
|
||||
"is_valid={}",
|
||||
bus_handle_.abstracted_pad_id, bus_handle_.bus_type_id, bus_handle_.internal_index,
|
||||
bus_handle_.player_number, bus_handle_.is_valid);
|
||||
bus_handle.abstracted_pad_id, bus_handle.bus_type_id, 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);
|
||||
|
||||
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;
|
||||
}
|
||||
R_UNLESS(device_index.has_value(), ResultUnknown);
|
||||
|
||||
LOG_ERROR(Service_HID, "Invalid handle");
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultUnknown);
|
||||
return;
|
||||
*out_event = &devices[device_index.value()].device->GetSendCommandAsycEvent();
|
||||
R_SUCCEED();
|
||||
};
|
||||
|
||||
void HidBus::GetSharedMemoryHandle(HLERequestContext& ctx) {
|
||||
Result Hidbus::GetSharedMemoryHandle(OutCopyHandle<Kernel::KSharedMemory> out_shared_memory) {
|
||||
LOG_DEBUG(Service_HID, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 1};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushCopyObjects(&system.Kernel().GetHidBusSharedMem());
|
||||
*out_shared_memory = &system.Kernel().GetHidBusSharedMem();
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
void HidBus::EnableJoyPollingReceiveMode(HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
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>()};
|
||||
|
||||
Result Hidbus::EnableJoyPollingReceiveMode(u32 t_mem_size, JoyPollingMode polling_mode,
|
||||
BusHandle bus_handle,
|
||||
InCopyHandle<Kernel::KTransferMemory> t_mem) {
|
||||
ASSERT_MSG(t_mem_size == 0x1000, "t_mem_size is not 0x1000 bytes");
|
||||
|
||||
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");
|
||||
ASSERT_MSG(t_mem->GetSize() == t_mem_size, "t_mem has incorrect size");
|
||||
|
||||
LOG_INFO(Service_HID,
|
||||
"called, t_mem_handle=0x{:08X}, polling_mode={}, abstracted_pad_id={}, bus_type={}, "
|
||||
"called, polling_mode={}, abstracted_pad_id={}, bus_type={}, "
|
||||
"internal_index={}, player_number={}, is_valid={}",
|
||||
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);
|
||||
polling_mode, bus_handle.abstracted_pad_id, bus_handle.bus_type_id,
|
||||
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);
|
||||
|
||||
if (device_index) {
|
||||
auto& device = devices[device_index.value()].device;
|
||||
device->SetPollingMode(polling_mode_);
|
||||
device->SetTransferMemoryAddress(t_mem->GetSourceAddress());
|
||||
R_UNLESS(device_index.has_value(), ResultUnknown);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultSuccess);
|
||||
return;
|
||||
}
|
||||
|
||||
LOG_ERROR(Service_HID, "Invalid handle");
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultUnknown);
|
||||
return;
|
||||
auto& device = devices[device_index.value()].device;
|
||||
device->SetPollingMode(polling_mode);
|
||||
device->SetTransferMemoryAddress(t_mem->GetSourceAddress());
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
void HidBus::DisableJoyPollingReceiveMode(HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto bus_handle_{rp.PopRaw<BusHandle>()};
|
||||
|
||||
Result Hidbus::DisableJoyPollingReceiveMode(BusHandle bus_handle) {
|
||||
LOG_INFO(Service_HID,
|
||||
"called, abstracted_pad_id={}, bus_type={}, internal_index={}, player_number={}, "
|
||||
"is_valid={}",
|
||||
bus_handle_.abstracted_pad_id, bus_handle_.bus_type_id, bus_handle_.internal_index,
|
||||
bus_handle_.player_number, bus_handle_.is_valid);
|
||||
bus_handle.abstracted_pad_id, bus_handle.bus_type_id, 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);
|
||||
|
||||
if (device_index) {
|
||||
auto& device = devices[device_index.value()].device;
|
||||
device->DisablePollingMode();
|
||||
R_UNLESS(device_index.has_value(), ResultUnknown);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultSuccess);
|
||||
return;
|
||||
}
|
||||
|
||||
LOG_ERROR(Service_HID, "Invalid handle");
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultUnknown);
|
||||
return;
|
||||
auto& device = devices[device_index.value()].device;
|
||||
device->DisablePollingMode();
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
void HidBus::SetStatusManagerType(HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto manager_type{rp.PopEnum<StatusManagerType>()};
|
||||
|
||||
Result Hidbus::SetStatusManagerType(StatusManagerType manager_type) {
|
||||
LOG_WARNING(Service_HID, "(STUBBED) called, manager_type={}", manager_type);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultSuccess);
|
||||
R_SUCCEED();
|
||||
};
|
||||
|
||||
} // namespace Service::HID
|
||||
|
||||
@@ -5,8 +5,10 @@
|
||||
|
||||
#include <functional>
|
||||
|
||||
#include "core/hle/service/cmif_types.h"
|
||||
#include "core/hle/service/kernel_helpers.h"
|
||||
#include "core/hle/service/service.h"
|
||||
#include "hid_core/hid_types.h"
|
||||
#include "hid_core/hidbus/hidbus_base.h"
|
||||
|
||||
namespace Core::Timing {
|
||||
@@ -19,10 +21,10 @@ class System;
|
||||
|
||||
namespace Service::HID {
|
||||
|
||||
class HidBus final : public ServiceFramework<HidBus> {
|
||||
class Hidbus final : public ServiceFramework<Hidbus> {
|
||||
public:
|
||||
explicit HidBus(Core::System& system_);
|
||||
~HidBus() override;
|
||||
explicit Hidbus(Core::System& system_);
|
||||
~Hidbus() override;
|
||||
|
||||
private:
|
||||
static const std::size_t max_number_of_handles = 0x13;
|
||||
@@ -41,7 +43,7 @@ private:
|
||||
};
|
||||
|
||||
// This is nn::hidbus::BusType
|
||||
enum class BusType : u32 {
|
||||
enum class BusType : u64 {
|
||||
LeftJoyRail,
|
||||
RightJoyRail,
|
||||
InternalBus, // Lark microphone
|
||||
@@ -51,11 +53,15 @@ private:
|
||||
|
||||
// This is nn::hidbus::BusHandle
|
||||
struct BusHandle {
|
||||
u32 abstracted_pad_id;
|
||||
u8 internal_index;
|
||||
u8 player_number;
|
||||
u8 bus_type_id;
|
||||
bool is_valid;
|
||||
union {
|
||||
u64 raw{};
|
||||
|
||||
BitField<0, 32, u64> abstracted_pad_id;
|
||||
BitField<32, 8, u64> internal_index;
|
||||
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");
|
||||
|
||||
@@ -94,19 +100,38 @@ private:
|
||||
std::unique_ptr<HidbusBase> device{nullptr};
|
||||
};
|
||||
|
||||
void GetBusHandle(HLERequestContext& ctx);
|
||||
void IsExternalDeviceConnected(HLERequestContext& ctx);
|
||||
void Initialize(HLERequestContext& ctx);
|
||||
void Finalize(HLERequestContext& ctx);
|
||||
void EnableExternalDevice(HLERequestContext& ctx);
|
||||
void GetExternalDeviceId(HLERequestContext& ctx);
|
||||
void SendCommandAsync(HLERequestContext& ctx);
|
||||
void GetSendCommandAsynceResult(HLERequestContext& ctx);
|
||||
void SetEventForSendCommandAsycResult(HLERequestContext& ctx);
|
||||
void GetSharedMemoryHandle(HLERequestContext& ctx);
|
||||
void EnableJoyPollingReceiveMode(HLERequestContext& ctx);
|
||||
void DisableJoyPollingReceiveMode(HLERequestContext& ctx);
|
||||
void SetStatusManagerType(HLERequestContext& ctx);
|
||||
Result GetBusHandle(Out<bool> out_is_valid, Out<BusHandle> out_bus_handle,
|
||||
Core::HID::NpadIdType npad_id, BusType bus_type,
|
||||
AppletResourceUserId aruid);
|
||||
|
||||
Result IsExternalDeviceConnected(Out<bool> out_is_connected, BusHandle bus_handle);
|
||||
|
||||
Result Initialize(BusHandle bus_handle, AppletResourceUserId aruid);
|
||||
|
||||
Result Finalize(BusHandle bus_handle, AppletResourceUserId aruid);
|
||||
|
||||
Result EnableExternalDevice(bool is_enabled, BusHandle bus_handle, u64 inval,
|
||||
AppletResourceUserId aruid);
|
||||
|
||||
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);
|
||||
std::optional<std::size_t> GetDeviceIndexFromHandle(BusHandle handle) const;
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include "core/hle/kernel/k_shared_memory.h"
|
||||
#include "core/hle/kernel/k_transfer_memory.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/ipc_helpers.h"
|
||||
#include "core/memory.h"
|
||||
@@ -28,24 +29,24 @@ namespace Service::IRS {
|
||||
IRS::IRS(Core::System& system_) : ServiceFramework{system_, "irs"} {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{302, &IRS::ActivateIrsensor, "ActivateIrsensor"},
|
||||
{303, &IRS::DeactivateIrsensor, "DeactivateIrsensor"},
|
||||
{304, &IRS::GetIrsensorSharedMemoryHandle, "GetIrsensorSharedMemoryHandle"},
|
||||
{305, &IRS::StopImageProcessor, "StopImageProcessor"},
|
||||
{306, &IRS::RunMomentProcessor, "RunMomentProcessor"},
|
||||
{307, &IRS::RunClusteringProcessor, "RunClusteringProcessor"},
|
||||
{308, &IRS::RunImageTransferProcessor, "RunImageTransferProcessor"},
|
||||
{309, &IRS::GetImageTransferProcessorState, "GetImageTransferProcessorState"},
|
||||
{310, &IRS::RunTeraPluginProcessor, "RunTeraPluginProcessor"},
|
||||
{311, &IRS::GetNpadIrCameraHandle, "GetNpadIrCameraHandle"},
|
||||
{312, &IRS::RunPointingProcessor, "RunPointingProcessor"},
|
||||
{313, &IRS::SuspendImageProcessor, "SuspendImageProcessor"},
|
||||
{314, &IRS::CheckFirmwareVersion, "CheckFirmwareVersion"},
|
||||
{315, &IRS::SetFunctionLevel, "SetFunctionLevel"},
|
||||
{316, &IRS::RunImageTransferExProcessor, "RunImageTransferExProcessor"},
|
||||
{317, &IRS::RunIrLedProcessor, "RunIrLedProcessor"},
|
||||
{318, &IRS::StopImageProcessorAsync, "StopImageProcessorAsync"},
|
||||
{319, &IRS::ActivateIrsensorWithFunctionLevel, "ActivateIrsensorWithFunctionLevel"},
|
||||
{302, C<&IRS::ActivateIrsensor>, "ActivateIrsensor"},
|
||||
{303, C<&IRS::DeactivateIrsensor>, "DeactivateIrsensor"},
|
||||
{304, C<&IRS::GetIrsensorSharedMemoryHandle>, "GetIrsensorSharedMemoryHandle"},
|
||||
{305, C<&IRS::StopImageProcessor>, "StopImageProcessor"},
|
||||
{306, C<&IRS::RunMomentProcessor>, "RunMomentProcessor"},
|
||||
{307, C<&IRS::RunClusteringProcessor>, "RunClusteringProcessor"},
|
||||
{308, C<&IRS::RunImageTransferProcessor>, "RunImageTransferProcessor"},
|
||||
{309, C<&IRS::GetImageTransferProcessorState>, "GetImageTransferProcessorState"},
|
||||
{310, C<&IRS::RunTeraPluginProcessor>, "RunTeraPluginProcessor"},
|
||||
{311, C<&IRS::GetNpadIrCameraHandle>, "GetNpadIrCameraHandle"},
|
||||
{312, C<&IRS::RunPointingProcessor>, "RunPointingProcessor"},
|
||||
{313, C<&IRS::SuspendImageProcessor>, "SuspendImageProcessor"},
|
||||
{314, C<&IRS::CheckFirmwareVersion>, "CheckFirmwareVersion"},
|
||||
{315, C<&IRS::SetFunctionLevel>, "SetFunctionLevel"},
|
||||
{316, C<&IRS::RunImageTransferExProcessor>, "RunImageTransferExProcessor"},
|
||||
{317, C<&IRS::RunIrLedProcessor>, "RunIrLedProcessor"},
|
||||
{318, C<&IRS::StopImageProcessorAsync>, "StopImageProcessorAsync"},
|
||||
{319, C<&IRS::ActivateIrsensorWithFunctionLevel>, "ActivateIrsensorWithFunctionLevel"},
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
@@ -57,489 +58,292 @@ IRS::IRS(Core::System& system_) : ServiceFramework{system_, "irs"} {
|
||||
}
|
||||
IRS::~IRS() = default;
|
||||
|
||||
void IRS::ActivateIrsensor(HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
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::ActivateIrsensor(ClientAppletResourceUserId aruid) {
|
||||
LOG_WARNING(Service_IRS, "(STUBBED) called, applet_resource_user_id={}", aruid.pid);
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
void IRS::DeactivateIrsensor(HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
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) {
|
||||
LOG_WARNING(Service_IRS, "(STUBBED) called, applet_resource_user_id={}", aruid.pid);
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
void IRS::GetIrsensorSharedMemoryHandle(HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto applet_resource_user_id{rp.Pop<u64>()};
|
||||
Result IRS::GetIrsensorSharedMemoryHandle(OutCopyHandle<Kernel::KSharedMemory> out_shared_memory,
|
||||
ClientAppletResourceUserId aruid) {
|
||||
LOG_DEBUG(Service_IRS, "called, applet_resource_user_id={}", aruid.pid);
|
||||
|
||||
LOG_DEBUG(Service_IRS, "called, applet_resource_user_id={}", applet_resource_user_id);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 1};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushCopyObjects(&system.Kernel().GetIrsSharedMem());
|
||||
*out_shared_memory = &system.Kernel().GetIrsSharedMem();
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
void IRS::StopImageProcessor(HLERequestContext& ctx) {
|
||||
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>()};
|
||||
|
||||
Result IRS::StopImageProcessor(Core::IrSensor::IrCameraHandle camera_handle,
|
||||
ClientAppletResourceUserId aruid) {
|
||||
LOG_WARNING(Service_IRS,
|
||||
"(STUBBED) called, npad_type={}, npad_id={}, applet_resource_user_id={}",
|
||||
parameters.camera_handle.npad_type, parameters.camera_handle.npad_id,
|
||||
parameters.applet_resource_user_id);
|
||||
camera_handle.npad_type, camera_handle.npad_id, aruid.pid);
|
||||
|
||||
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;
|
||||
}
|
||||
R_TRY(IsIrCameraHandleValid(camera_handle));
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(result);
|
||||
// TODO: Stop Image processor
|
||||
npad_device->SetPollingMode(Core::HID::EmulatedDeviceIndex::RightIndex,
|
||||
Common::Input::PollingMode::Active);
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
void IRS::RunMomentProcessor(HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
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>()};
|
||||
|
||||
Result IRS::RunMomentProcessor(
|
||||
Core::IrSensor::IrCameraHandle camera_handle, ClientAppletResourceUserId aruid,
|
||||
const Core::IrSensor::PackedMomentProcessorConfig& processor_config) {
|
||||
LOG_WARNING(Service_IRS,
|
||||
"(STUBBED) called, npad_type={}, npad_id={}, applet_resource_user_id={}",
|
||||
parameters.camera_handle.npad_type, parameters.camera_handle.npad_id,
|
||||
parameters.applet_resource_user_id);
|
||||
camera_handle.npad_type, camera_handle.npad_id, aruid.pid);
|
||||
|
||||
const auto result = IsIrCameraHandleValid(parameters.camera_handle);
|
||||
R_TRY(IsIrCameraHandleValid(camera_handle));
|
||||
|
||||
if (result.IsSuccess()) {
|
||||
auto& device = GetIrCameraSharedMemoryDeviceEntry(parameters.camera_handle);
|
||||
MakeProcessorWithCoreContext<MomentProcessor>(parameters.camera_handle, device);
|
||||
auto& image_transfer_processor = GetProcessor<MomentProcessor>(parameters.camera_handle);
|
||||
image_transfer_processor.SetConfig(parameters.processor_config);
|
||||
npad_device->SetPollingMode(Core::HID::EmulatedDeviceIndex::RightIndex,
|
||||
Common::Input::PollingMode::IR);
|
||||
}
|
||||
auto& device = GetIrCameraSharedMemoryDeviceEntry(camera_handle);
|
||||
MakeProcessorWithCoreContext<MomentProcessor>(camera_handle, device);
|
||||
auto& image_transfer_processor = GetProcessor<MomentProcessor>(camera_handle);
|
||||
image_transfer_processor.SetConfig(processor_config);
|
||||
npad_device->SetPollingMode(Core::HID::EmulatedDeviceIndex::RightIndex,
|
||||
Common::Input::PollingMode::IR);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(result);
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
void IRS::RunClusteringProcessor(HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
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>()};
|
||||
|
||||
Result IRS::RunClusteringProcessor(
|
||||
Core::IrSensor::IrCameraHandle camera_handle, ClientAppletResourceUserId aruid,
|
||||
const Core::IrSensor::PackedClusteringProcessorConfig& processor_config) {
|
||||
LOG_WARNING(Service_IRS,
|
||||
"(STUBBED) called, npad_type={}, npad_id={}, applet_resource_user_id={}",
|
||||
parameters.camera_handle.npad_type, parameters.camera_handle.npad_id,
|
||||
parameters.applet_resource_user_id);
|
||||
camera_handle.npad_type, camera_handle.npad_id, aruid.pid);
|
||||
|
||||
auto result = IsIrCameraHandleValid(parameters.camera_handle);
|
||||
R_TRY(IsIrCameraHandleValid(camera_handle));
|
||||
|
||||
if (result.IsSuccess()) {
|
||||
auto& device = GetIrCameraSharedMemoryDeviceEntry(parameters.camera_handle);
|
||||
MakeProcessorWithCoreContext<ClusteringProcessor>(parameters.camera_handle, device);
|
||||
auto& image_transfer_processor =
|
||||
GetProcessor<ClusteringProcessor>(parameters.camera_handle);
|
||||
image_transfer_processor.SetConfig(parameters.processor_config);
|
||||
npad_device->SetPollingMode(Core::HID::EmulatedDeviceIndex::RightIndex,
|
||||
Common::Input::PollingMode::IR);
|
||||
}
|
||||
auto& device = GetIrCameraSharedMemoryDeviceEntry(camera_handle);
|
||||
MakeProcessorWithCoreContext<ClusteringProcessor>(camera_handle, device);
|
||||
auto& image_transfer_processor = GetProcessor<ClusteringProcessor>(camera_handle);
|
||||
image_transfer_processor.SetConfig(processor_config);
|
||||
npad_device->SetPollingMode(Core::HID::EmulatedDeviceIndex::RightIndex,
|
||||
Common::Input::PollingMode::IR);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(result);
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
void IRS::RunImageTransferProcessor(HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
struct Parameters {
|
||||
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.");
|
||||
Result IRS::RunImageTransferProcessor(
|
||||
Core::IrSensor::IrCameraHandle camera_handle, ClientAppletResourceUserId aruid,
|
||||
const Core::IrSensor::PackedImageTransferProcessorConfig& processor_config,
|
||||
u64 transfer_memory_size, InCopyHandle<Kernel::KTransferMemory> t_mem) {
|
||||
|
||||
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");
|
||||
ASSERT_MSG(t_mem->GetSize() == transfer_memory_size, "t_mem has incorrect size");
|
||||
|
||||
LOG_INFO(Service_IRS,
|
||||
"called, npad_type={}, npad_id={}, transfer_memory_size={}, transfer_memory_size={}, "
|
||||
"applet_resource_user_id={}",
|
||||
parameters.camera_handle.npad_type, parameters.camera_handle.npad_id,
|
||||
parameters.transfer_memory_size, t_mem->GetSize(), parameters.applet_resource_user_id);
|
||||
camera_handle.npad_type, camera_handle.npad_id, transfer_memory_size, t_mem->GetSize(),
|
||||
aruid.pid);
|
||||
|
||||
const auto result = IsIrCameraHandleValid(parameters.camera_handle);
|
||||
R_TRY(IsIrCameraHandleValid(camera_handle));
|
||||
|
||||
if (result.IsSuccess()) {
|
||||
auto& device = GetIrCameraSharedMemoryDeviceEntry(parameters.camera_handle);
|
||||
MakeProcessorWithCoreContext<ImageTransferProcessor>(parameters.camera_handle, device);
|
||||
auto& image_transfer_processor =
|
||||
GetProcessor<ImageTransferProcessor>(parameters.camera_handle);
|
||||
image_transfer_processor.SetConfig(parameters.processor_config);
|
||||
image_transfer_processor.SetTransferMemoryAddress(t_mem->GetSourceAddress());
|
||||
npad_device->SetPollingMode(Core::HID::EmulatedDeviceIndex::RightIndex,
|
||||
Common::Input::PollingMode::IR);
|
||||
}
|
||||
auto& device = GetIrCameraSharedMemoryDeviceEntry(camera_handle);
|
||||
MakeProcessorWithCoreContext<ImageTransferProcessor>(camera_handle, device);
|
||||
auto& image_transfer_processor = GetProcessor<ImageTransferProcessor>(camera_handle);
|
||||
image_transfer_processor.SetConfig(processor_config);
|
||||
image_transfer_processor.SetTransferMemoryAddress(t_mem->GetSourceAddress());
|
||||
npad_device->SetPollingMode(Core::HID::EmulatedDeviceIndex::RightIndex,
|
||||
Common::Input::PollingMode::IR);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(result);
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
void IRS::GetImageTransferProcessorState(HLERequestContext& ctx) {
|
||||
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>()};
|
||||
|
||||
Result IRS::GetImageTransferProcessorState(
|
||||
Out<Core::IrSensor::ImageTransferProcessorState> out_state,
|
||||
Core::IrSensor::IrCameraHandle camera_handle, ClientAppletResourceUserId aruid,
|
||||
OutBuffer<BufferAttr_HipcMapAlias> out_buffer_data) {
|
||||
LOG_DEBUG(Service_IRS, "(STUBBED) called, npad_type={}, npad_id={}, applet_resource_user_id={}",
|
||||
parameters.camera_handle.npad_type, parameters.camera_handle.npad_id,
|
||||
parameters.applet_resource_user_id);
|
||||
camera_handle.npad_type, camera_handle.npad_id, aruid.pid);
|
||||
|
||||
const auto result = IsIrCameraHandleValid(parameters.camera_handle);
|
||||
if (result.IsError()) {
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(result);
|
||||
return;
|
||||
}
|
||||
R_TRY(IsIrCameraHandleValid(camera_handle));
|
||||
|
||||
const auto& device = GetIrCameraSharedMemoryDeviceEntry(parameters.camera_handle);
|
||||
const auto& device = GetIrCameraSharedMemoryDeviceEntry(camera_handle);
|
||||
|
||||
if (device.mode != Core::IrSensor::IrSensorMode::ImageTransferProcessor) {
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(InvalidProcessorState);
|
||||
return;
|
||||
}
|
||||
R_TRY(IsIrCameraHandleValid(camera_handle));
|
||||
R_UNLESS(device.mode == Core::IrSensor::IrSensorMode::ImageTransferProcessor,
|
||||
InvalidProcessorState);
|
||||
|
||||
std::vector<u8> data{};
|
||||
const auto& image_transfer_processor =
|
||||
GetProcessor<ImageTransferProcessor>(parameters.camera_handle);
|
||||
const auto& state = image_transfer_processor.GetState(data);
|
||||
*out_state = GetProcessor<ImageTransferProcessor>(camera_handle).GetState(out_buffer_data);
|
||||
|
||||
ctx.WriteBuffer(data);
|
||||
IPC::ResponseBuilder rb{ctx, 6};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushRaw(state);
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
void IRS::RunTeraPluginProcessor(HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
struct Parameters {
|
||||
Core::IrSensor::IrCameraHandle camera_handle;
|
||||
Core::IrSensor::PackedTeraPluginProcessorConfig processor_config;
|
||||
INSERT_PADDING_WORDS_NOINIT(1);
|
||||
u64 applet_resource_user_id;
|
||||
};
|
||||
static_assert(sizeof(Parameters) == 0x18, "Parameters has incorrect size.");
|
||||
Result IRS::RunTeraPluginProcessor(Core::IrSensor::IrCameraHandle camera_handle,
|
||||
Core::IrSensor::PackedTeraPluginProcessorConfig processor_config,
|
||||
ClientAppletResourceUserId aruid) {
|
||||
LOG_WARNING(Service_IRS,
|
||||
"(STUBBED) called, npad_type={}, npad_id={}, mode={}, mcu_version={}.{}, "
|
||||
"applet_resource_user_id={}",
|
||||
camera_handle.npad_type, camera_handle.npad_id, processor_config.mode,
|
||||
processor_config.required_mcu_version.major,
|
||||
processor_config.required_mcu_version.minor, aruid.pid);
|
||||
|
||||
const auto parameters{rp.PopRaw<Parameters>()};
|
||||
R_TRY(IsIrCameraHandleValid(camera_handle));
|
||||
|
||||
LOG_WARNING(
|
||||
Service_IRS,
|
||||
"(STUBBED) called, npad_type={}, npad_id={}, mode={}, mcu_version={}.{}, "
|
||||
"applet_resource_user_id={}",
|
||||
parameters.camera_handle.npad_type, parameters.camera_handle.npad_id,
|
||||
parameters.processor_config.mode, parameters.processor_config.required_mcu_version.major,
|
||||
parameters.processor_config.required_mcu_version.minor, parameters.applet_resource_user_id);
|
||||
auto& device = GetIrCameraSharedMemoryDeviceEntry(camera_handle);
|
||||
MakeProcessor<TeraPluginProcessor>(camera_handle, device);
|
||||
auto& image_transfer_processor = GetProcessor<TeraPluginProcessor>(camera_handle);
|
||||
image_transfer_processor.SetConfig(processor_config);
|
||||
npad_device->SetPollingMode(Core::HID::EmulatedDeviceIndex::RightIndex,
|
||||
Common::Input::PollingMode::IR);
|
||||
|
||||
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);
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
void IRS::GetNpadIrCameraHandle(HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto npad_id{rp.PopEnum<Core::HID::NpadIdType>()};
|
||||
Result IRS::GetNpadIrCameraHandle(Out<Core::IrSensor::IrCameraHandle> out_camera_handle,
|
||||
Core::HID::NpadIdType npad_id) {
|
||||
R_UNLESS(HID::IsNpadIdValid(npad_id), HID::ResultInvalidNpadId);
|
||||
|
||||
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{
|
||||
*out_camera_handle = {
|
||||
.npad_id = static_cast<u8>(HID::NpadIdTypeToIndex(npad_id)),
|
||||
.npad_type = Core::HID::NpadStyleIndex::None,
|
||||
};
|
||||
|
||||
LOG_INFO(Service_IRS, "called, npad_id={}, camera_npad_id={}, camera_npad_type={}", npad_id,
|
||||
camera_handle.npad_id, camera_handle.npad_type);
|
||||
out_camera_handle->npad_id, out_camera_handle->npad_type);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushRaw(camera_handle);
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
void IRS::RunPointingProcessor(HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto camera_handle{rp.PopRaw<Core::IrSensor::IrCameraHandle>()};
|
||||
const auto processor_config{rp.PopRaw<Core::IrSensor::PackedPointingProcessorConfig>()};
|
||||
const auto applet_resource_user_id{rp.Pop<u64>()};
|
||||
|
||||
Result IRS::RunPointingProcessor(
|
||||
Core::IrSensor::IrCameraHandle camera_handle,
|
||||
const Core::IrSensor::PackedPointingProcessorConfig& processor_config,
|
||||
ClientAppletResourceUserId aruid) {
|
||||
LOG_WARNING(
|
||||
Service_IRS,
|
||||
"(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,
|
||||
processor_config.required_mcu_version.minor, applet_resource_user_id);
|
||||
processor_config.required_mcu_version.minor, aruid.pid);
|
||||
|
||||
auto result = IsIrCameraHandleValid(camera_handle);
|
||||
R_TRY(IsIrCameraHandleValid(camera_handle));
|
||||
|
||||
if (result.IsSuccess()) {
|
||||
auto& device = GetIrCameraSharedMemoryDeviceEntry(camera_handle);
|
||||
MakeProcessor<PointingProcessor>(camera_handle, device);
|
||||
auto& image_transfer_processor = GetProcessor<PointingProcessor>(camera_handle);
|
||||
image_transfer_processor.SetConfig(processor_config);
|
||||
npad_device->SetPollingMode(Core::HID::EmulatedDeviceIndex::RightIndex,
|
||||
Common::Input::PollingMode::IR);
|
||||
}
|
||||
auto& device = GetIrCameraSharedMemoryDeviceEntry(camera_handle);
|
||||
MakeProcessor<PointingProcessor>(camera_handle, device);
|
||||
auto& image_transfer_processor = GetProcessor<PointingProcessor>(camera_handle);
|
||||
image_transfer_processor.SetConfig(processor_config);
|
||||
npad_device->SetPollingMode(Core::HID::EmulatedDeviceIndex::RightIndex,
|
||||
Common::Input::PollingMode::IR);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(result);
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
void IRS::SuspendImageProcessor(HLERequestContext& ctx) {
|
||||
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>()};
|
||||
|
||||
Result IRS::SuspendImageProcessor(Core::IrSensor::IrCameraHandle camera_handle,
|
||||
ClientAppletResourceUserId aruid) {
|
||||
LOG_WARNING(Service_IRS,
|
||||
"(STUBBED) called, npad_type={}, npad_id={}, applet_resource_user_id={}",
|
||||
parameters.camera_handle.npad_type, parameters.camera_handle.npad_id,
|
||||
parameters.applet_resource_user_id);
|
||||
camera_handle.npad_type, camera_handle.npad_id, aruid.pid);
|
||||
|
||||
auto result = IsIrCameraHandleValid(parameters.camera_handle);
|
||||
if (result.IsSuccess()) {
|
||||
// TODO: Suspend image processor
|
||||
result = ResultSuccess;
|
||||
}
|
||||
R_TRY(IsIrCameraHandleValid(camera_handle));
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(result);
|
||||
// TODO: Suspend image processor
|
||||
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
void IRS::CheckFirmwareVersion(HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
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>()};
|
||||
|
||||
Result IRS::CheckFirmwareVersion(Core::IrSensor::IrCameraHandle camera_handle,
|
||||
Core::IrSensor::PackedMcuVersion mcu_version,
|
||||
ClientAppletResourceUserId aruid) {
|
||||
LOG_WARNING(
|
||||
Service_IRS,
|
||||
"(STUBBED) called, npad_type={}, npad_id={}, applet_resource_user_id={}, mcu_version={}.{}",
|
||||
camera_handle.npad_type, camera_handle.npad_id, applet_resource_user_id, mcu_version.major,
|
||||
camera_handle.npad_type, camera_handle.npad_id, aruid.pid, mcu_version.major,
|
||||
mcu_version.minor);
|
||||
|
||||
auto result = IsIrCameraHandleValid(camera_handle);
|
||||
if (result.IsSuccess()) {
|
||||
// TODO: Check firmware version
|
||||
result = ResultSuccess;
|
||||
}
|
||||
R_TRY(IsIrCameraHandleValid(camera_handle));
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(result);
|
||||
// TODO: Check firmware version
|
||||
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
void IRS::SetFunctionLevel(HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
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>()};
|
||||
|
||||
Result IRS::SetFunctionLevel(Core::IrSensor::IrCameraHandle camera_handle,
|
||||
Core::IrSensor::PackedFunctionLevel function_level,
|
||||
ClientAppletResourceUserId aruid) {
|
||||
LOG_WARNING(
|
||||
Service_IRS,
|
||||
"(STUBBED) called, npad_type={}, npad_id={}, function_level={}, applet_resource_user_id={}",
|
||||
camera_handle.npad_type, camera_handle.npad_id, function_level.function_level,
|
||||
applet_resource_user_id);
|
||||
camera_handle.npad_type, camera_handle.npad_id, function_level.function_level, aruid.pid);
|
||||
|
||||
auto result = IsIrCameraHandleValid(camera_handle);
|
||||
if (result.IsSuccess()) {
|
||||
// TODO: Set Function level
|
||||
result = ResultSuccess;
|
||||
}
|
||||
R_TRY(IsIrCameraHandleValid(camera_handle));
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(result);
|
||||
// TODO: Set Function level
|
||||
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
void IRS::RunImageTransferExProcessor(HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
struct Parameters {
|
||||
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.");
|
||||
Result IRS::RunImageTransferExProcessor(
|
||||
Core::IrSensor::IrCameraHandle camera_handle, ClientAppletResourceUserId aruid,
|
||||
const Core::IrSensor::PackedImageTransferProcessorExConfig& processor_config,
|
||||
u64 transfer_memory_size, InCopyHandle<Kernel::KTransferMemory> t_mem) {
|
||||
|
||||
const auto parameters{rp.PopRaw<Parameters>()};
|
||||
const auto t_mem_handle{ctx.GetCopyHandle(0)};
|
||||
|
||||
auto t_mem = ctx.GetObjectFromHandle<Kernel::KTransferMemory>(t_mem_handle);
|
||||
ASSERT_MSG(t_mem->GetSize() == transfer_memory_size, "t_mem has incorrect size");
|
||||
|
||||
LOG_INFO(Service_IRS,
|
||||
"called, npad_type={}, npad_id={}, transfer_memory_size={}, "
|
||||
"applet_resource_user_id={}",
|
||||
parameters.camera_handle.npad_type, parameters.camera_handle.npad_id,
|
||||
parameters.transfer_memory_size, parameters.applet_resource_user_id);
|
||||
camera_handle.npad_type, camera_handle.npad_id, transfer_memory_size, aruid.pid);
|
||||
|
||||
auto result = IsIrCameraHandleValid(parameters.camera_handle);
|
||||
R_TRY(IsIrCameraHandleValid(camera_handle));
|
||||
|
||||
if (result.IsSuccess()) {
|
||||
auto& device = GetIrCameraSharedMemoryDeviceEntry(parameters.camera_handle);
|
||||
MakeProcessorWithCoreContext<ImageTransferProcessor>(parameters.camera_handle, device);
|
||||
auto& image_transfer_processor =
|
||||
GetProcessor<ImageTransferProcessor>(parameters.camera_handle);
|
||||
image_transfer_processor.SetConfig(parameters.processor_config);
|
||||
image_transfer_processor.SetTransferMemoryAddress(t_mem->GetSourceAddress());
|
||||
npad_device->SetPollingMode(Core::HID::EmulatedDeviceIndex::RightIndex,
|
||||
Common::Input::PollingMode::IR);
|
||||
}
|
||||
auto& device = GetIrCameraSharedMemoryDeviceEntry(camera_handle);
|
||||
MakeProcessorWithCoreContext<ImageTransferProcessor>(camera_handle, device);
|
||||
auto& image_transfer_processor = GetProcessor<ImageTransferProcessor>(camera_handle);
|
||||
image_transfer_processor.SetConfig(processor_config);
|
||||
image_transfer_processor.SetTransferMemoryAddress(t_mem->GetSourceAddress());
|
||||
npad_device->SetPollingMode(Core::HID::EmulatedDeviceIndex::RightIndex,
|
||||
Common::Input::PollingMode::IR);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(result);
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
void IRS::RunIrLedProcessor(HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
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>()};
|
||||
|
||||
Result IRS::RunIrLedProcessor(Core::IrSensor::IrCameraHandle camera_handle,
|
||||
Core::IrSensor::PackedIrLedProcessorConfig processor_config,
|
||||
ClientAppletResourceUserId aruid) {
|
||||
LOG_WARNING(Service_IRS,
|
||||
"(STUBBED) called, npad_type={}, npad_id={}, light_target={}, mcu_version={}.{} "
|
||||
"applet_resource_user_id={}",
|
||||
camera_handle.npad_type, camera_handle.npad_id, processor_config.light_target,
|
||||
processor_config.required_mcu_version.major,
|
||||
processor_config.required_mcu_version.minor, applet_resource_user_id);
|
||||
processor_config.required_mcu_version.minor, aruid.pid);
|
||||
|
||||
auto result = IsIrCameraHandleValid(camera_handle);
|
||||
R_TRY(IsIrCameraHandleValid(camera_handle));
|
||||
|
||||
if (result.IsSuccess()) {
|
||||
auto& device = GetIrCameraSharedMemoryDeviceEntry(camera_handle);
|
||||
MakeProcessor<IrLedProcessor>(camera_handle, device);
|
||||
auto& image_transfer_processor = GetProcessor<IrLedProcessor>(camera_handle);
|
||||
image_transfer_processor.SetConfig(processor_config);
|
||||
npad_device->SetPollingMode(Core::HID::EmulatedDeviceIndex::RightIndex,
|
||||
Common::Input::PollingMode::IR);
|
||||
}
|
||||
auto& device = GetIrCameraSharedMemoryDeviceEntry(camera_handle);
|
||||
MakeProcessor<IrLedProcessor>(camera_handle, device);
|
||||
auto& image_transfer_processor = GetProcessor<IrLedProcessor>(camera_handle);
|
||||
image_transfer_processor.SetConfig(processor_config);
|
||||
npad_device->SetPollingMode(Core::HID::EmulatedDeviceIndex::RightIndex,
|
||||
Common::Input::PollingMode::IR);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(result);
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
void IRS::StopImageProcessorAsync(HLERequestContext& ctx) {
|
||||
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>()};
|
||||
|
||||
Result IRS::StopImageProcessorAsync(Core::IrSensor::IrCameraHandle camera_handle,
|
||||
ClientAppletResourceUserId aruid) {
|
||||
LOG_WARNING(Service_IRS,
|
||||
"(STUBBED) called, npad_type={}, npad_id={}, applet_resource_user_id={}",
|
||||
parameters.camera_handle.npad_type, parameters.camera_handle.npad_id,
|
||||
parameters.applet_resource_user_id);
|
||||
camera_handle.npad_type, camera_handle.npad_id, aruid.pid);
|
||||
|
||||
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;
|
||||
}
|
||||
R_TRY(IsIrCameraHandleValid(camera_handle));
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(result);
|
||||
// TODO: Stop image processor async
|
||||
npad_device->SetPollingMode(Core::HID::EmulatedDeviceIndex::RightIndex,
|
||||
Common::Input::PollingMode::Active);
|
||||
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
void IRS::ActivateIrsensorWithFunctionLevel(HLERequestContext& ctx) {
|
||||
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>()};
|
||||
|
||||
Result IRS::ActivateIrsensorWithFunctionLevel(Core::IrSensor::PackedFunctionLevel function_level,
|
||||
ClientAppletResourceUserId aruid) {
|
||||
LOG_WARNING(Service_IRS, "(STUBBED) called, function_level={}, applet_resource_user_id={}",
|
||||
parameters.function_level.function_level, parameters.applet_resource_user_id);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultSuccess);
|
||||
function_level.function_level, aruid.pid);
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result IRS::IsIrCameraHandleValid(const Core::IrSensor::IrCameraHandle& camera_handle) const {
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "core/core.h"
|
||||
#include "core/hle/service/cmif_types.h"
|
||||
#include "core/hle/service/service.h"
|
||||
#include "hid_core/hid_types.h"
|
||||
#include "hid_core/irsensor/irs_types.h"
|
||||
@@ -35,26 +36,73 @@ private:
|
||||
};
|
||||
static_assert(sizeof(StatusManager) == 0x8000, "StatusManager is an invalid size");
|
||||
|
||||
void ActivateIrsensor(HLERequestContext& ctx);
|
||||
void DeactivateIrsensor(HLERequestContext& ctx);
|
||||
void GetIrsensorSharedMemoryHandle(HLERequestContext& ctx);
|
||||
void StopImageProcessor(HLERequestContext& ctx);
|
||||
void RunMomentProcessor(HLERequestContext& ctx);
|
||||
void RunClusteringProcessor(HLERequestContext& ctx);
|
||||
void RunImageTransferProcessor(HLERequestContext& ctx);
|
||||
void GetImageTransferProcessorState(HLERequestContext& ctx);
|
||||
void RunTeraPluginProcessor(HLERequestContext& ctx);
|
||||
void GetNpadIrCameraHandle(HLERequestContext& ctx);
|
||||
void RunPointingProcessor(HLERequestContext& ctx);
|
||||
void SuspendImageProcessor(HLERequestContext& ctx);
|
||||
void CheckFirmwareVersion(HLERequestContext& ctx);
|
||||
void SetFunctionLevel(HLERequestContext& ctx);
|
||||
void RunImageTransferExProcessor(HLERequestContext& ctx);
|
||||
void RunIrLedProcessor(HLERequestContext& ctx);
|
||||
void StopImageProcessorAsync(HLERequestContext& ctx);
|
||||
void ActivateIrsensorWithFunctionLevel(HLERequestContext& ctx);
|
||||
Result ActivateIrsensor(ClientAppletResourceUserId aruid);
|
||||
|
||||
Result DeactivateIrsensor(ClientAppletResourceUserId aruid);
|
||||
|
||||
Result GetIrsensorSharedMemoryHandle(OutCopyHandle<Kernel::KSharedMemory> out_shared_memory,
|
||||
ClientAppletResourceUserId aruid);
|
||||
Result StopImageProcessor(Core::IrSensor::IrCameraHandle camera_handle,
|
||||
ClientAppletResourceUserId aruid);
|
||||
|
||||
Result RunMomentProcessor(Core::IrSensor::IrCameraHandle camera_handle,
|
||||
ClientAppletResourceUserId aruid,
|
||||
const Core::IrSensor::PackedMomentProcessorConfig& processor_config);
|
||||
|
||||
Result RunClusteringProcessor(
|
||||
Core::IrSensor::IrCameraHandle camera_handle, ClientAppletResourceUserId aruid,
|
||||
const Core::IrSensor::PackedClusteringProcessorConfig& processor_config);
|
||||
|
||||
Result RunImageTransferProcessor(
|
||||
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;
|
||||
|
||||
Core::IrSensor::DeviceFormat& GetIrCameraSharedMemoryDeviceEntry(
|
||||
const Core::IrSensor::IrCameraHandle& camera_handle);
|
||||
|
||||
|
||||
@@ -126,7 +126,7 @@ public:
|
||||
R_THROW(ResultUnknown);
|
||||
}
|
||||
|
||||
Result LoadPlugin(u64 tmem_size, InCopyHandle<Kernel::KTransferMemory>& tmem,
|
||||
Result LoadPlugin(u64 tmem_size, InCopyHandle<Kernel::KTransferMemory> tmem,
|
||||
InBuffer<BufferAttr_HipcMapAlias> nrr,
|
||||
InBuffer<BufferAttr_HipcMapAlias> nro) {
|
||||
if (!tmem) {
|
||||
@@ -268,9 +268,9 @@ public:
|
||||
|
||||
private:
|
||||
Result CreateJitEnvironment(Out<SharedPointer<IJitEnvironment>> out_jit_environment,
|
||||
u64 rx_size, u64 ro_size, InCopyHandle<Kernel::KProcess>& process,
|
||||
InCopyHandle<Kernel::KCodeMemory>& rx_mem,
|
||||
InCopyHandle<Kernel::KCodeMemory>& ro_mem) {
|
||||
u64 rx_size, u64 ro_size, InCopyHandle<Kernel::KProcess> process,
|
||||
InCopyHandle<Kernel::KCodeMemory> rx_mem,
|
||||
InCopyHandle<Kernel::KCodeMemory> ro_mem) {
|
||||
if (!process) {
|
||||
LOG_ERROR(Service_JIT, "process is null");
|
||||
R_THROW(ResultUnknown);
|
||||
|
||||
@@ -189,7 +189,7 @@ private:
|
||||
R_RETURN(manager->Move(metadata, new_index, create_id));
|
||||
}
|
||||
|
||||
Result AddOrReplace(StoreData& store_data) {
|
||||
Result AddOrReplace(const StoreData& store_data) {
|
||||
LOG_INFO(Service_Mii, "called");
|
||||
R_UNLESS(is_system, ResultPermissionDenied);
|
||||
|
||||
|
||||
@@ -49,6 +49,7 @@ SessionId Container::OpenSession(Kernel::KProcess* process) {
|
||||
continue;
|
||||
}
|
||||
if (session.process == process) {
|
||||
session.ref_count++;
|
||||
return session.id;
|
||||
}
|
||||
}
|
||||
@@ -66,6 +67,7 @@ SessionId Container::OpenSession(Kernel::KProcess* process) {
|
||||
}
|
||||
auto& session = impl->sessions[new_id];
|
||||
session.is_active = true;
|
||||
session.ref_count = 1;
|
||||
// Optimization
|
||||
if (process->IsApplication()) {
|
||||
auto& page_table = process->GetPageTable().GetBasePageTable();
|
||||
@@ -114,8 +116,11 @@ SessionId Container::OpenSession(Kernel::KProcess* process) {
|
||||
|
||||
void Container::CloseSession(SessionId session_id) {
|
||||
std::scoped_lock lk(impl->session_guard);
|
||||
impl->file.UnmapAllHandles(session_id);
|
||||
auto& session = impl->sessions[session_id.id];
|
||||
if (--session.ref_count > 0) {
|
||||
return;
|
||||
}
|
||||
impl->file.UnmapAllHandles(session_id);
|
||||
auto& smmu = impl->host1x.MemoryManager();
|
||||
if (session.has_preallocated_area) {
|
||||
const DAddr region_start = session.mapper->GetRegionStart();
|
||||
|
||||
@@ -46,6 +46,7 @@ struct Session {
|
||||
bool has_preallocated_area{};
|
||||
std::unique_ptr<HeapMapper> mapper{};
|
||||
bool is_active{};
|
||||
s32 ref_count{};
|
||||
};
|
||||
|
||||
class Container {
|
||||
|
||||
@@ -3,110 +3,21 @@
|
||||
|
||||
#include <mutex>
|
||||
|
||||
#include <boost/container/small_vector.hpp>
|
||||
#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 "common/range_sets.h"
|
||||
#include "common/range_sets.inc"
|
||||
#include "core/hle/service/nvdrv/core/heap_mapper.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 {
|
||||
|
||||
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 {
|
||||
HeapMapperInternal(Tegra::Host1x::Host1x& host1x) : device_memory{host1x.MemoryManager()} {}
|
||||
HeapMapperInternal(Tegra::Host1x::Host1x& host1x) : m_device_memory{host1x.MemoryManager()} {}
|
||||
~HeapMapperInternal() = default;
|
||||
|
||||
template <typename Func>
|
||||
void ForEachInOverlapCounter(OverlapCounter& current_range, VAddr cpu_addr, u64 size,
|
||||
Func&& func) {
|
||||
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;
|
||||
Common::RangeSet<VAddr> m_temporary_set;
|
||||
Common::OverlapRangeSet<VAddr> m_mapped_ranges;
|
||||
Tegra::MaxwellDeviceMemoryManager& m_device_memory;
|
||||
std::mutex m_guard;
|
||||
};
|
||||
|
||||
HeapMapper::HeapMapper(VAddr start_vaddress, DAddr start_daddress, size_t size, Core::Asid asid,
|
||||
@@ -116,60 +27,48 @@ HeapMapper::HeapMapper(VAddr start_vaddress, DAddr start_daddress, size_t size,
|
||||
}
|
||||
|
||||
HeapMapper::~HeapMapper() {
|
||||
m_internal->device_memory.Unmap(m_daddress, m_size);
|
||||
// Unmap whatever has been mapped.
|
||||
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) {
|
||||
std::scoped_lock lk(m_internal->guard);
|
||||
m_internal->base_set.clear();
|
||||
const IntervalType interval{start, start + size};
|
||||
m_internal->base_set.insert(interval);
|
||||
m_internal->ForEachInOverlapCounter(m_internal->mapping_overlaps, start, size,
|
||||
[this](VAddr start_addr, VAddr end_addr, int) {
|
||||
const IntervalType other{start_addr, end_addr};
|
||||
m_internal->base_set.subtract(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.Map(m_daddress + offset, m_vaddress + offset, sub_size,
|
||||
m_asid);
|
||||
}
|
||||
}
|
||||
m_internal->mapping_overlaps += std::make_pair(interval, 1);
|
||||
m_internal->base_set.clear();
|
||||
return m_daddress + (start - m_vaddress);
|
||||
std::scoped_lock lk(m_internal->m_guard);
|
||||
// Add the mapping range to a temporary range set.
|
||||
m_internal->m_temporary_set.Clear();
|
||||
m_internal->m_temporary_set.Add(start, size);
|
||||
|
||||
// Remove anything that's already mapped from the temporary range set.
|
||||
m_internal->m_mapped_ranges.ForEachInRange(
|
||||
start, size, [this](VAddr start_addr, VAddr end_addr, s32) {
|
||||
m_internal->m_temporary_set.Subtract(start_addr, end_addr - start_addr);
|
||||
});
|
||||
|
||||
// Map anything that has not been mapped yet.
|
||||
m_internal->m_temporary_set.ForEach([this](VAddr start_addr, VAddr end_addr) {
|
||||
const size_t sub_size = end_addr - start_addr;
|
||||
const size_t offset = start_addr - m_vaddress;
|
||||
m_internal->m_device_memory.Map(m_daddress + offset, m_vaddress + offset, sub_size, m_asid);
|
||||
});
|
||||
|
||||
// Add the mapping range to the split map, to register the map and overlaps.
|
||||
m_internal->m_mapped_ranges.Add(start, size);
|
||||
m_internal->m_temporary_set.Clear();
|
||||
return m_daddress + static_cast<DAddr>(start - m_vaddress);
|
||||
}
|
||||
|
||||
void HeapMapper::Unmap(VAddr start, size_t size) {
|
||||
std::scoped_lock lk(m_internal->guard);
|
||||
m_internal->base_set.clear();
|
||||
m_internal->ForEachInOverlapCounter(m_internal->mapping_overlaps, start, size,
|
||||
[this](VAddr start_addr, VAddr end_addr, int value) {
|
||||
if (value <= 1) {
|
||||
const IntervalType other{start_addr, end_addr};
|
||||
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();
|
||||
std::scoped_lock lk(m_internal->m_guard);
|
||||
|
||||
// Just subtract the range and whatever is deleted, unmap it.
|
||||
m_internal->m_mapped_ranges.Subtract(start, size, [this](VAddr start_addr, VAddr end_addr) {
|
||||
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);
|
||||
});
|
||||
}
|
||||
|
||||
} // namespace Service::Nvidia::NvCore
|
||||
|
||||
@@ -333,9 +333,13 @@ void NvMap::UnmapAllHandles(NvCore::SessionId session_id) {
|
||||
}();
|
||||
|
||||
for (auto& [id, handle] : handles_copy) {
|
||||
if (handle->session_id.id == session_id.id) {
|
||||
FreeHandle(id, false);
|
||||
{
|
||||
std::scoped_lock lk{handle->mutex};
|
||||
if (handle->session_id.id != session_id.id || handle->dupes <= 0) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
FreeHandle(id, false);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include <boost/container/small_vector.hpp>
|
||||
|
||||
#include "common/assert.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "core/core.h"
|
||||
@@ -13,6 +15,22 @@
|
||||
|
||||
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)
|
||||
: nvdevice{system_}, container{core}, nvmap{core.GetNvMapFile()} {}
|
||||
nvdisp_disp0::~nvdisp_disp0() = default;
|
||||
@@ -38,19 +56,31 @@ NvResult nvdisp_disp0::Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> in
|
||||
void nvdisp_disp0::OnOpen(NvCore::SessionId session_id, DeviceFD fd) {}
|
||||
void nvdisp_disp0::OnClose(DeviceFD fd) {}
|
||||
|
||||
void nvdisp_disp0::flip(u32 buffer_handle, u32 offset, android::PixelFormat format, u32 width,
|
||||
u32 height, u32 stride, android::BufferTransformFlags transform,
|
||||
const Common::Rectangle<int>& crop_rect,
|
||||
std::array<Service::Nvidia::NvFence, 4>& fences, u32 num_fences) {
|
||||
const DAddr addr = nvmap.GetHandleAddress(buffer_handle);
|
||||
LOG_TRACE(Service,
|
||||
"Drawing from address {:X} offset {:08X} Width {} Height {} Stride {} Format {}",
|
||||
addr, offset, width, height, stride, format);
|
||||
void nvdisp_disp0::Composite(std::span<const Nvnflinger::HwcLayer> sorted_layers) {
|
||||
std::vector<Tegra::FramebufferConfig> output_layers;
|
||||
std::vector<Service::Nvidia::NvFence> output_fences;
|
||||
output_layers.reserve(sorted_layers.size());
|
||||
output_fences.reserve(sorted_layers.size());
|
||||
|
||||
const Tegra::FramebufferConfig framebuffer{addr, offset, width, height,
|
||||
stride, format, transform, crop_rect};
|
||||
for (auto& layer : sorted_layers) {
|
||||
output_layers.emplace_back(Tegra::FramebufferConfig{
|
||||
.address = nvmap.GetHandleAddress(layer.buffer_handle),
|
||||
.offset = layer.offset,
|
||||
.width = layer.width,
|
||||
.height = layer.height,
|
||||
.stride = layer.stride,
|
||||
.pixel_format = layer.format,
|
||||
.transform_flags = layer.transform,
|
||||
.crop_rect = layer.crop_rect,
|
||||
.blending = ConvertBlending(layer.blending),
|
||||
});
|
||||
|
||||
system.GPU().RequestSwapBuffers(&framebuffer, fences, num_fences);
|
||||
for (size_t i = 0; i < layer.acquire_fence.num_fences; i++) {
|
||||
output_fences.push_back(layer.acquire_fence.fences[i]);
|
||||
}
|
||||
}
|
||||
|
||||
system.GPU().RequestComposite(std::move(output_layers), std::move(output_fences));
|
||||
system.SpeedLimiter().DoSpeedLimiting(system.CoreTiming().GetGlobalTimeUs());
|
||||
system.GetPerfStats().EndSystemFrame();
|
||||
system.GetPerfStats().BeginSystemFrame();
|
||||
|
||||
@@ -8,8 +8,7 @@
|
||||
#include "common/common_types.h"
|
||||
#include "common/math_util.h"
|
||||
#include "core/hle/service/nvdrv/devices/nvdevice.h"
|
||||
#include "core/hle/service/nvnflinger/buffer_transform_flags.h"
|
||||
#include "core/hle/service/nvnflinger/pixel_format.h"
|
||||
#include "core/hle/service/nvnflinger/hwc_layer.h"
|
||||
|
||||
namespace Service::Nvidia::NvCore {
|
||||
class Container;
|
||||
@@ -35,11 +34,8 @@ public:
|
||||
void OnOpen(NvCore::SessionId session_id, DeviceFD fd) override;
|
||||
void OnClose(DeviceFD fd) override;
|
||||
|
||||
/// Performs a screen flip, drawing the buffer pointed to by the handle.
|
||||
void flip(u32 buffer_handle, u32 offset, android::PixelFormat format, u32 width, u32 height,
|
||||
u32 stride, android::BufferTransformFlags transform,
|
||||
const Common::Rectangle<int>& crop_rect,
|
||||
std::array<Service::Nvidia::NvFence, 4>& fences, u32 num_fences);
|
||||
/// Performs a screen flip, compositing each buffer.
|
||||
void Composite(std::span<const Nvnflinger::HwcLayer> sorted_layers);
|
||||
|
||||
Kernel::KEvent* QueryEvent(u32 event_id) override;
|
||||
|
||||
|
||||
@@ -123,6 +123,8 @@ NvResult nvhost_as_gpu::AllocAsEx(IoctlAllocAsEx& params) {
|
||||
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 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);
|
||||
@@ -132,8 +134,8 @@ NvResult nvhost_as_gpu::AllocAsEx(IoctlAllocAsEx& params) {
|
||||
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);
|
||||
|
||||
gmmu = std::make_shared<Tegra::MemoryManager>(system, 40, vm.big_page_size_bits,
|
||||
VM::PAGE_SIZE_BITS);
|
||||
gmmu = std::make_shared<Tegra::MemoryManager>(system, max_big_page_bits, vm.va_range_split,
|
||||
vm.big_page_size_bits, VM::PAGE_SIZE_BITS);
|
||||
system.GPU().InitAddressSpace(*gmmu);
|
||||
vm.initialised = true;
|
||||
|
||||
|
||||
@@ -14,24 +14,20 @@
|
||||
#include "core/hle/service/nvnflinger/ui/graphic_buffer.h"
|
||||
#include "core/hle/service/vi/layer/vi_layer.h"
|
||||
#include "core/hle/service/vi/vi_results.h"
|
||||
#include "video_core/gpu.h"
|
||||
#include "video_core/host1x/host1x.h"
|
||||
|
||||
namespace Service::Nvnflinger {
|
||||
|
||||
namespace {
|
||||
|
||||
Result AllocateIoForProcessAddressSpace(Common::ProcessAddress* out_map_address,
|
||||
std::unique_ptr<Kernel::KPageGroup>* out_page_group,
|
||||
Core::System& system, u32 size) {
|
||||
Result AllocateSharedBufferMemory(std::unique_ptr<Kernel::KPageGroup>* out_page_group,
|
||||
Core::System& system, u32 size) {
|
||||
using Core::Memory::YUZU_PAGESIZE;
|
||||
|
||||
// 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.
|
||||
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.
|
||||
auto pg = std::make_unique<Kernel::KPageGroup>(
|
||||
@@ -43,6 +39,30 @@ Result AllocateIoForProcessAddressSpace(Common::ProcessAddress* out_map_address,
|
||||
Kernel::KMemoryManager::EncodeOption(Kernel::KMemoryManager::Pool::Secure,
|
||||
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.
|
||||
const VAddr alias_code_begin = GetInteger(page_table.GetAliasCodeRegionStart());
|
||||
const VAddr alias_code_size = page_table.GetAliasCodeRegionSize() / YUZU_PAGESIZE;
|
||||
@@ -64,9 +84,6 @@ Result AllocateIoForProcessAddressSpace(Common::ProcessAddress* out_map_address,
|
||||
// Return failure, if necessary
|
||||
R_UNLESS(i < 64, res);
|
||||
|
||||
// Return the mapped page group.
|
||||
*out_page_group = std::move(pg);
|
||||
|
||||
// We succeeded.
|
||||
R_SUCCEED();
|
||||
}
|
||||
@@ -135,6 +152,13 @@ Result AllocateHandleForBuffer(u32* out_handle, Nvidia::Module& nvdrv, Nvidia::D
|
||||
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 u32 SharedBufferBlockLinearBpp = 4;
|
||||
|
||||
@@ -186,53 +210,97 @@ FbShareBufferManager::FbShareBufferManager(Core::System& system, Nvnflinger& fli
|
||||
|
||||
FbShareBufferManager::~FbShareBufferManager() = default;
|
||||
|
||||
Result FbShareBufferManager::Initialize(u64* out_buffer_id, u64* out_layer_id, u64 display_id) {
|
||||
Result FbShareBufferManager::Initialize(Kernel::KProcess* owner_process, u64* out_buffer_id,
|
||||
u64* out_layer_handle, u64 display_id,
|
||||
LayerBlending blending) {
|
||||
std::scoped_lock lk{m_guard};
|
||||
|
||||
// Ensure we have not already created a buffer.
|
||||
R_UNLESS(m_buffer_id == 0, VI::ResultOperationFailed);
|
||||
// Ensure we haven't already created.
|
||||
const u64 aruid = owner_process->GetProcessId();
|
||||
R_UNLESS(!m_sessions.contains(aruid), VI::ResultPermissionDenied);
|
||||
|
||||
// Allocate memory and space for the shared buffer.
|
||||
Common::ProcessAddress map_address;
|
||||
R_TRY(AllocateIoForProcessAddressSpace(std::addressof(map_address),
|
||||
std::addressof(m_buffer_page_group), m_system,
|
||||
SharedBufferSize));
|
||||
// Allocate memory for the shared buffer if needed.
|
||||
if (!m_buffer_page_group) {
|
||||
R_TRY(AllocateSharedBufferMemory(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();
|
||||
m_session_id = container.OpenSession(m_system.ApplicationProcess());
|
||||
m_nvmap_fd = m_nvdrv->Open("/dev/nvmap", m_session_id);
|
||||
session.session_id = container.OpenSession(owner_process);
|
||||
session.nvmap_fd = m_nvdrv->Open("/dev/nvmap", session.session_id);
|
||||
|
||||
// Create an nvmap handle for the buffer and assign the memory to it.
|
||||
R_TRY(AllocateHandleForBuffer(std::addressof(m_buffer_nvmap_handle), *m_nvdrv, m_nvmap_fd,
|
||||
map_address, SharedBufferSize));
|
||||
|
||||
// Record the display id.
|
||||
m_display_id = display_id;
|
||||
R_TRY(AllocateHandleForBuffer(std::addressof(session.buffer_nvmap_handle), *m_nvdrv,
|
||||
session.nvmap_fd, map_address, SharedBufferSize));
|
||||
|
||||
// Create and open a layer for the display.
|
||||
m_layer_id = m_flinger.CreateLayer(m_display_id).value();
|
||||
m_flinger.OpenLayer(m_layer_id);
|
||||
|
||||
// Set up the buffer.
|
||||
m_buffer_id = m_next_buffer_id++;
|
||||
session.layer_id = m_flinger.CreateLayer(m_display_id, blending).value();
|
||||
m_flinger.OpenLayer(session.layer_id);
|
||||
|
||||
// Get the layer.
|
||||
VI::Layer* layer = m_flinger.FindLayer(m_display_id, m_layer_id);
|
||||
VI::Layer* layer = m_flinger.FindLayer(m_display_id, session.layer_id);
|
||||
ASSERT(layer != nullptr);
|
||||
|
||||
// Get the producer and set preallocated buffers.
|
||||
auto& producer = layer->GetBufferQueue();
|
||||
MakeGraphicBuffer(producer, 0, m_buffer_nvmap_handle);
|
||||
MakeGraphicBuffer(producer, 1, m_buffer_nvmap_handle);
|
||||
MakeGraphicBuffer(producer, 0, session.buffer_nvmap_handle);
|
||||
MakeGraphicBuffer(producer, 1, session.buffer_nvmap_handle);
|
||||
|
||||
// Assign outputs.
|
||||
*out_buffer_id = m_buffer_id;
|
||||
*out_layer_id = m_layer_id;
|
||||
*out_layer_handle = session.layer_id;
|
||||
|
||||
// We succeeded.
|
||||
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,
|
||||
s32* out_nvmap_handle,
|
||||
SharedMemoryPoolLayout* out_pool_layout,
|
||||
@@ -242,17 +310,18 @@ Result FbShareBufferManager::GetSharedBufferMemoryHandleId(u64* out_buffer_size,
|
||||
|
||||
R_UNLESS(m_buffer_id > 0, 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_buffer_size = SharedBufferSize;
|
||||
*out_nvmap_handle = m_buffer_nvmap_handle;
|
||||
*out_nvmap_handle = m_sessions[applet_resource_user_id].buffer_nvmap_handle;
|
||||
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result FbShareBufferManager::GetLayerFromId(VI::Layer** out_layer, u64 layer_id) {
|
||||
// Ensure the layer id is valid.
|
||||
R_UNLESS(m_layer_id > 0 && layer_id == m_layer_id, VI::ResultNotFound);
|
||||
R_UNLESS(layer_id > 0, VI::ResultNotFound);
|
||||
|
||||
// Get the layer.
|
||||
VI::Layer* layer = m_flinger.FindLayer(m_display_id, layer_id);
|
||||
@@ -309,6 +378,10 @@ Result FbShareBufferManager::PresentSharedFrameBuffer(android::Fence fence,
|
||||
android::Status::NoError,
|
||||
VI::ResultOperationFailed);
|
||||
|
||||
ON_RESULT_FAILURE {
|
||||
producer.CancelBuffer(static_cast<s32>(slot), fence);
|
||||
};
|
||||
|
||||
// Queue the buffer to the producer.
|
||||
android::QueueBufferInput input{};
|
||||
android::QueueBufferOutput output{};
|
||||
@@ -342,4 +415,33 @@ Result FbShareBufferManager::GetSharedFrameBufferAcquirableEvent(Kernel::KReadab
|
||||
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
|
||||
|
||||
@@ -3,9 +3,12 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <map>
|
||||
|
||||
#include "common/math_util.h"
|
||||
#include "core/hle/service/nvdrv/core/container.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/ui/fence.h"
|
||||
|
||||
@@ -29,13 +32,18 @@ struct SharedMemoryPoolLayout {
|
||||
};
|
||||
static_assert(sizeof(SharedMemoryPoolLayout) == 0x188, "SharedMemoryPoolLayout has wrong size");
|
||||
|
||||
struct FbShareSession;
|
||||
|
||||
class FbShareBufferManager final {
|
||||
public:
|
||||
explicit FbShareBufferManager(Core::System& system, Nvnflinger& flinger,
|
||||
std::shared_ptr<Nvidia::Module> nvdrv);
|
||||
~FbShareBufferManager();
|
||||
|
||||
Result Initialize(u64* out_buffer_id, u64* out_layer_handle, u64 display_id);
|
||||
Result Initialize(Kernel::KProcess* owner_process, u64* out_buffer_id, u64* out_layer_handle,
|
||||
u64 display_id, LayerBlending blending);
|
||||
void Finalize(Kernel::KProcess* owner_process);
|
||||
|
||||
Result GetSharedBufferMemoryHandleId(u64* out_buffer_size, s32* out_nvmap_handle,
|
||||
SharedMemoryPoolLayout* out_pool_layout, u64 buffer_id,
|
||||
u64 applet_resource_user_id);
|
||||
@@ -45,6 +53,8 @@ public:
|
||||
u32 transform, s32 swap_interval, u64 layer_id, s64 slot);
|
||||
Result GetSharedFrameBufferAcquirableEvent(Kernel::KReadableEvent** out_event, u64 layer_id);
|
||||
|
||||
Result WriteAppletCaptureBuffer(bool* out_was_written, s32* out_layer_index);
|
||||
|
||||
private:
|
||||
Result GetLayerFromId(VI::Layer** out_layer, u64 layer_id);
|
||||
|
||||
@@ -52,11 +62,8 @@ private:
|
||||
u64 m_next_buffer_id = 1;
|
||||
u64 m_display_id = 0;
|
||||
u64 m_buffer_id = 0;
|
||||
u64 m_layer_id = 0;
|
||||
u32 m_buffer_nvmap_handle = 0;
|
||||
SharedMemoryPoolLayout m_pool_layout = {};
|
||||
Nvidia::DeviceFD m_nvmap_fd = {};
|
||||
Nvidia::NvCore::SessionId m_session_id = {};
|
||||
std::map<u64, FbShareSession> m_sessions;
|
||||
std::unique_ptr<Kernel::KPageGroup> m_buffer_page_group;
|
||||
|
||||
std::mutex m_guard;
|
||||
@@ -65,4 +72,11 @@ private:
|
||||
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
|
||||
|
||||
216
src/core/hle/service/nvnflinger/hardware_composer.cpp
Normal file
216
src/core/hle/service/nvnflinger/hardware_composer.cpp
Normal file
@@ -0,0 +1,216 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#include <boost/container/small_vector.hpp>
|
||||
|
||||
#include "common/microprofile.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_consumer.h"
|
||||
#include "core/hle/service/nvnflinger/hardware_composer.h"
|
||||
#include "core/hle/service/nvnflinger/hwc_layer.h"
|
||||
#include "core/hle/service/nvnflinger/ui/graphic_buffer.h"
|
||||
#include "core/hle/service/vi/display/vi_display.h"
|
||||
#include "core/hle/service/vi/layer/vi_layer.h"
|
||||
|
||||
namespace Service::Nvnflinger {
|
||||
|
||||
namespace {
|
||||
|
||||
s32 NormalizeSwapInterval(f32* out_speed_scale, s32 swap_interval) {
|
||||
if (swap_interval <= 0) {
|
||||
// As an extension, treat nonpositive swap interval as speed multiplier.
|
||||
if (out_speed_scale) {
|
||||
*out_speed_scale = 2.f * static_cast<f32>(1 - swap_interval);
|
||||
}
|
||||
|
||||
swap_interval = 1;
|
||||
}
|
||||
|
||||
if (swap_interval >= 5) {
|
||||
// As an extension, treat high swap interval as precise speed control.
|
||||
if (out_speed_scale) {
|
||||
*out_speed_scale = static_cast<f32>(swap_interval) / 100.f;
|
||||
}
|
||||
|
||||
swap_interval = 1;
|
||||
}
|
||||
|
||||
return swap_interval;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
HardwareComposer::HardwareComposer() = default;
|
||||
HardwareComposer::~HardwareComposer() = default;
|
||||
|
||||
u32 HardwareComposer::ComposeLocked(f32* out_speed_scale, VI::Display& display,
|
||||
Nvidia::Devices::nvdisp_disp0& nvdisp) {
|
||||
boost::container::small_vector<HwcLayer, 2> composition_stack;
|
||||
|
||||
// Set default speed limit to 100%.
|
||||
*out_speed_scale = 1.0f;
|
||||
|
||||
// Determine the number of vsync periods to wait before composing again.
|
||||
std::optional<s32> swap_interval{};
|
||||
bool has_acquired_buffer{};
|
||||
|
||||
// Acquire all necessary framebuffers.
|
||||
for (size_t i = 0; i < display.GetNumLayers(); i++) {
|
||||
auto& layer = display.GetLayer(i);
|
||||
auto layer_id = layer.GetLayerId();
|
||||
|
||||
// Try to fetch the framebuffer (either new or stale).
|
||||
const auto result = this->CacheFramebufferLocked(layer, layer_id);
|
||||
|
||||
// If we failed, skip this layer.
|
||||
if (result == CacheStatus::NoBufferAvailable) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// If we acquired a new buffer, we need to present.
|
||||
if (result == CacheStatus::BufferAcquired) {
|
||||
has_acquired_buffer = true;
|
||||
}
|
||||
|
||||
const auto& buffer = m_framebuffers[layer_id];
|
||||
const auto& item = buffer.item;
|
||||
const auto& igbp_buffer = *item.graphic_buffer;
|
||||
|
||||
// TODO: get proper Z-index from layer
|
||||
composition_stack.emplace_back(HwcLayer{
|
||||
.buffer_handle = igbp_buffer.BufferId(),
|
||||
.offset = igbp_buffer.Offset(),
|
||||
.format = igbp_buffer.ExternalFormat(),
|
||||
.width = igbp_buffer.Width(),
|
||||
.height = igbp_buffer.Height(),
|
||||
.stride = igbp_buffer.Stride(),
|
||||
.z_index = 0,
|
||||
.blending = layer.GetBlending(),
|
||||
.transform = static_cast<android::BufferTransformFlags>(item.transform),
|
||||
.crop_rect = item.crop,
|
||||
.acquire_fence = item.fence,
|
||||
});
|
||||
|
||||
// We need to compose again either before this frame is supposed to
|
||||
// be released, or exactly on the vsync period it should be released.
|
||||
const s32 item_swap_interval = NormalizeSwapInterval(out_speed_scale, item.swap_interval);
|
||||
|
||||
// TODO: handle cases where swap intervals are relatively prime. So far,
|
||||
// only swap intervals of 0, 1 and 2 have been observed, but if 3 were
|
||||
// to be introduced, this would cause an issue.
|
||||
if (swap_interval) {
|
||||
swap_interval = std::min(*swap_interval, item_swap_interval);
|
||||
} else {
|
||||
swap_interval = item_swap_interval;
|
||||
}
|
||||
}
|
||||
|
||||
// If any new buffers were acquired, we can present.
|
||||
if (has_acquired_buffer) {
|
||||
// Sort by Z-index.
|
||||
std::stable_sort(composition_stack.begin(), composition_stack.end(),
|
||||
[&](auto& l, auto& r) { return l.z_index < r.z_index; });
|
||||
|
||||
// Composite.
|
||||
nvdisp.Composite(composition_stack);
|
||||
}
|
||||
|
||||
// Render MicroProfile.
|
||||
MicroProfileFlip();
|
||||
|
||||
// Advance by at least one frame.
|
||||
const u32 frame_advance = 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) {
|
||||
// Check if we are tracking a slot with this layer_id.
|
||||
const auto it = m_framebuffers.find(layer_id);
|
||||
if (it == m_framebuffers.end()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Try to release the buffer item.
|
||||
auto* const layer = display.FindLayer(layer_id);
|
||||
if (layer && it->second.is_acquired) {
|
||||
layer->GetConsumer().ReleaseBuffer(it->second.item, android::Fence::NoFence());
|
||||
}
|
||||
|
||||
// Erase the slot.
|
||||
m_framebuffers.erase(it);
|
||||
}
|
||||
|
||||
bool HardwareComposer::TryAcquireFramebufferLocked(VI::Layer& layer, Framebuffer& framebuffer) {
|
||||
// Attempt the update.
|
||||
const auto status = layer.GetConsumer().AcquireBuffer(&framebuffer.item, {}, false);
|
||||
if (status != android::Status::NoError) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// We succeeded, so set the new release frame info.
|
||||
framebuffer.release_frame_number =
|
||||
NormalizeSwapInterval(nullptr, framebuffer.item.swap_interval);
|
||||
framebuffer.is_acquired = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
HardwareComposer::CacheStatus HardwareComposer::CacheFramebufferLocked(VI::Layer& layer,
|
||||
LayerId layer_id) {
|
||||
// Check if this framebuffer is already present.
|
||||
const auto it = m_framebuffers.find(layer_id);
|
||||
if (it != m_framebuffers.end()) {
|
||||
// If it's currently still acquired, we are done.
|
||||
if (it->second.is_acquired) {
|
||||
return CacheStatus::CachedBufferReused;
|
||||
}
|
||||
|
||||
// Try to acquire a new item.
|
||||
if (this->TryAcquireFramebufferLocked(layer, it->second)) {
|
||||
// We got a new item.
|
||||
return CacheStatus::BufferAcquired;
|
||||
} else {
|
||||
// We didn't acquire a new item, but we can reuse the slot.
|
||||
return CacheStatus::CachedBufferReused;
|
||||
}
|
||||
}
|
||||
|
||||
// Framebuffer is not present, so try to create it.
|
||||
Framebuffer framebuffer{};
|
||||
|
||||
if (this->TryAcquireFramebufferLocked(layer, framebuffer)) {
|
||||
// Move the buffer item into a new slot.
|
||||
m_framebuffers.emplace(layer_id, std::move(framebuffer));
|
||||
|
||||
// We succeeded.
|
||||
return CacheStatus::BufferAcquired;
|
||||
}
|
||||
|
||||
// We couldn't acquire the buffer item, so don't create a slot.
|
||||
return CacheStatus::NoBufferAvailable;
|
||||
}
|
||||
|
||||
} // namespace Service::Nvnflinger
|
||||
59
src/core/hle/service/nvnflinger/hardware_composer.h
Normal file
59
src/core/hle/service/nvnflinger/hardware_composer.h
Normal file
@@ -0,0 +1,59 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <boost/container/flat_map.hpp>
|
||||
|
||||
#include "core/hle/service/nvnflinger/buffer_item.h"
|
||||
|
||||
namespace Service::Nvidia::Devices {
|
||||
class nvdisp_disp0;
|
||||
}
|
||||
|
||||
namespace Service::VI {
|
||||
class Display;
|
||||
class Layer;
|
||||
} // namespace Service::VI
|
||||
|
||||
namespace Service::Nvnflinger {
|
||||
|
||||
using LayerId = u64;
|
||||
|
||||
class HardwareComposer {
|
||||
public:
|
||||
explicit HardwareComposer();
|
||||
~HardwareComposer();
|
||||
|
||||
u32 ComposeLocked(f32* out_speed_scale, VI::Display& display,
|
||||
Nvidia::Devices::nvdisp_disp0& nvdisp);
|
||||
void RemoveLayerLocked(VI::Display& display, LayerId layer_id);
|
||||
|
||||
private:
|
||||
// TODO: do we want to track frame number in vi instead?
|
||||
u64 m_frame_number{0};
|
||||
|
||||
private:
|
||||
using ReleaseFrameNumber = u64;
|
||||
|
||||
struct Framebuffer {
|
||||
android::BufferItem item{};
|
||||
ReleaseFrameNumber release_frame_number{};
|
||||
bool is_acquired{false};
|
||||
};
|
||||
|
||||
enum class CacheStatus : u32 {
|
||||
NoBufferAvailable,
|
||||
BufferAcquired,
|
||||
CachedBufferReused,
|
||||
};
|
||||
|
||||
boost::container::flat_map<LayerId, Framebuffer> m_framebuffers{};
|
||||
|
||||
private:
|
||||
bool TryAcquireFramebufferLocked(VI::Layer& layer, Framebuffer& framebuffer);
|
||||
CacheStatus CacheFramebufferLocked(VI::Layer& layer, LayerId layer_id);
|
||||
};
|
||||
|
||||
} // namespace Service::Nvnflinger
|
||||
40
src/core/hle/service/nvnflinger/hwc_layer.h
Normal file
40
src/core/hle/service/nvnflinger/hwc_layer.h
Normal file
@@ -0,0 +1,40 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "common/math_util.h"
|
||||
#include "core/hle/service/nvdrv/nvdata.h"
|
||||
#include "core/hle/service/nvnflinger/buffer_transform_flags.h"
|
||||
#include "core/hle/service/nvnflinger/pixel_format.h"
|
||||
#include "core/hle/service/nvnflinger/ui/fence.h"
|
||||
|
||||
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 {
|
||||
u32 buffer_handle;
|
||||
u32 offset;
|
||||
android::PixelFormat format;
|
||||
u32 width;
|
||||
u32 height;
|
||||
u32 stride;
|
||||
s32 z_index;
|
||||
LayerBlending blending;
|
||||
android::BufferTransformFlags transform;
|
||||
Common::Rectangle<int> crop_rect;
|
||||
android::Fence acquire_fence;
|
||||
};
|
||||
|
||||
} // namespace Service::Nvnflinger
|
||||
@@ -18,6 +18,7 @@
|
||||
#include "core/hle/service/nvnflinger/buffer_item_consumer.h"
|
||||
#include "core/hle/service/nvnflinger/buffer_queue_core.h"
|
||||
#include "core/hle/service/nvnflinger/fb_share_buffer_manager.h"
|
||||
#include "core/hle/service/nvnflinger/hardware_composer.h"
|
||||
#include "core/hle/service/nvnflinger/hos_binder_driver_server.h"
|
||||
#include "core/hle/service/nvnflinger/nvnflinger.h"
|
||||
#include "core/hle/service/nvnflinger/ui/graphic_buffer.h"
|
||||
@@ -156,7 +157,7 @@ bool Nvnflinger::CloseDisplay(u64 display_id) {
|
||||
return true;
|
||||
}
|
||||
|
||||
std::optional<u64> Nvnflinger::CreateLayer(u64 display_id) {
|
||||
std::optional<u64> Nvnflinger::CreateLayer(u64 display_id, LayerBlending blending) {
|
||||
const auto lock_guard = Lock();
|
||||
auto* const display = FindDisplay(display_id);
|
||||
|
||||
@@ -165,13 +166,14 @@ std::optional<u64> Nvnflinger::CreateLayer(u64 display_id) {
|
||||
}
|
||||
|
||||
const u64 layer_id = next_layer_id++;
|
||||
CreateLayerAtId(*display, layer_id);
|
||||
CreateLayerAtId(*display, layer_id, blending);
|
||||
return layer_id;
|
||||
}
|
||||
|
||||
void Nvnflinger::CreateLayerAtId(VI::Display& display, u64 layer_id) {
|
||||
void Nvnflinger::CreateLayerAtId(VI::Display& display, u64 layer_id, LayerBlending blending) {
|
||||
const auto buffer_id = next_buffer_queue_id++;
|
||||
display.CreateLayer(layer_id, buffer_id, nvdrv->container);
|
||||
display.FindLayer(layer_id)->SetBlending(blending);
|
||||
}
|
||||
|
||||
bool Nvnflinger::OpenLayer(u64 layer_id) {
|
||||
@@ -279,45 +281,18 @@ void Nvnflinger::Compose() {
|
||||
SCOPE_EXIT({ display.SignalVSyncEvent(); });
|
||||
|
||||
// Don't do anything for displays without layers.
|
||||
if (!display.HasLayers())
|
||||
continue;
|
||||
|
||||
// TODO(Subv): Support more than 1 layer.
|
||||
VI::Layer& layer = display.GetLayer(0);
|
||||
|
||||
android::BufferItem buffer{};
|
||||
const auto status = layer.GetConsumer().AcquireBuffer(&buffer, {}, false);
|
||||
|
||||
if (status != android::Status::NoError) {
|
||||
if (!display.HasLayers()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const auto& igbp_buffer = *buffer.graphic_buffer;
|
||||
|
||||
if (!system.IsPoweredOn()) {
|
||||
return; // We are likely shutting down
|
||||
}
|
||||
|
||||
// Now send the buffer to the GPU for drawing.
|
||||
// TODO(Subv): Support more than just disp0. The display device selection is probably based
|
||||
// on which display we're drawing (Default, Internal, External, etc)
|
||||
auto nvdisp = nvdrv->GetDevice<Nvidia::Devices::nvdisp_disp0>(disp_fd);
|
||||
ASSERT(nvdisp);
|
||||
|
||||
Common::Rectangle<int> crop_rect{
|
||||
static_cast<int>(buffer.crop.Left()), static_cast<int>(buffer.crop.Top()),
|
||||
static_cast<int>(buffer.crop.Right()), static_cast<int>(buffer.crop.Bottom())};
|
||||
|
||||
nvdisp->flip(igbp_buffer.BufferId(), igbp_buffer.Offset(), igbp_buffer.ExternalFormat(),
|
||||
igbp_buffer.Width(), igbp_buffer.Height(), igbp_buffer.Stride(),
|
||||
static_cast<android::BufferTransformFlags>(buffer.transform), crop_rect,
|
||||
buffer.fence.fences, buffer.fence.num_fences);
|
||||
|
||||
MicroProfileFlip();
|
||||
|
||||
swap_interval = buffer.swap_interval;
|
||||
|
||||
layer.GetConsumer().ReleaseBuffer(buffer, android::Fence::NoFence());
|
||||
swap_interval = display.GetComposer().ComposeLocked(&compose_speed_scale, display, *nvdisp);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -334,15 +309,16 @@ s64 Nvnflinger::GetNextTicks() const {
|
||||
speed_scale = 0.01f;
|
||||
}
|
||||
}
|
||||
|
||||
// Adjust by speed limit determined during composition.
|
||||
speed_scale /= compose_speed_scale;
|
||||
|
||||
if (system.GetNVDECActive() && settings.use_video_framerate.GetValue()) {
|
||||
// Run at intended presentation rate during video playback.
|
||||
speed_scale = 1.f;
|
||||
}
|
||||
|
||||
// As an extension, treat nonpositive swap interval as framerate multiplier.
|
||||
const f32 effective_fps = swap_interval <= 0 ? 120.f * static_cast<f32>(1 - swap_interval)
|
||||
: 60.f / static_cast<f32>(swap_interval);
|
||||
|
||||
const f32 effective_fps = 60.f / static_cast<f32>(swap_interval);
|
||||
return static_cast<s64>(speed_scale * (1000000000.f / effective_fps));
|
||||
}
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
#include "common/thread.h"
|
||||
#include "core/hle/result.h"
|
||||
#include "core/hle/service/kernel_helpers.h"
|
||||
#include "core/hle/service/nvnflinger/hwc_layer.h"
|
||||
|
||||
namespace Common {
|
||||
class Event;
|
||||
@@ -46,6 +47,7 @@ class BufferQueueProducer;
|
||||
namespace Service::Nvnflinger {
|
||||
|
||||
class FbShareBufferManager;
|
||||
class HardwareComposer;
|
||||
class HosBinderDriverServer;
|
||||
|
||||
class Nvnflinger final {
|
||||
@@ -71,7 +73,8 @@ public:
|
||||
/// 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.
|
||||
[[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.
|
||||
bool OpenLayer(u64 layer_id);
|
||||
@@ -127,7 +130,7 @@ private:
|
||||
[[nodiscard]] VI::Layer* FindLayer(u64 display_id, u64 layer_id);
|
||||
|
||||
/// Creates a layer with the specified layer ID in the desired display.
|
||||
void CreateLayerAtId(VI::Display& display, u64 layer_id);
|
||||
void CreateLayerAtId(VI::Display& display, u64 layer_id, LayerBlending blending);
|
||||
|
||||
void SplitVSync(std::stop_token stop_token);
|
||||
|
||||
@@ -143,6 +146,7 @@ private:
|
||||
u32 next_buffer_queue_id = 1;
|
||||
|
||||
s32 swap_interval = 1;
|
||||
f32 compose_speed_scale = 1.0f;
|
||||
|
||||
bool is_abandoned = false;
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@ LocalSystemClockContextWriter::LocalSystemClockContextWriter(Core::System& syste
|
||||
SharedMemory& shared_memory)
|
||||
: m_system{system}, m_shared_memory{shared_memory} {}
|
||||
|
||||
Result LocalSystemClockContextWriter::Write(SystemClockContext& context) {
|
||||
Result LocalSystemClockContextWriter::Write(const SystemClockContext& context) {
|
||||
if (m_in_use) {
|
||||
R_SUCCEED_IF(context == m_context);
|
||||
m_context = context;
|
||||
@@ -43,7 +43,7 @@ NetworkSystemClockContextWriter::NetworkSystemClockContextWriter(Core::System& s
|
||||
SystemClockCore& system_clock)
|
||||
: m_system{system}, m_shared_memory{shared_memory}, m_system_clock{system_clock} {}
|
||||
|
||||
Result NetworkSystemClockContextWriter::Write(SystemClockContext& context) {
|
||||
Result NetworkSystemClockContextWriter::Write(const SystemClockContext& context) {
|
||||
s64 time{};
|
||||
[[maybe_unused]] auto res = m_system_clock.GetCurrentTime(&time);
|
||||
|
||||
@@ -66,7 +66,7 @@ EphemeralNetworkSystemClockContextWriter::EphemeralNetworkSystemClockContextWrit
|
||||
Core::System& system)
|
||||
: m_system{system} {}
|
||||
|
||||
Result EphemeralNetworkSystemClockContextWriter::Write(SystemClockContext& context) {
|
||||
Result EphemeralNetworkSystemClockContextWriter::Write(const SystemClockContext& context) {
|
||||
if (m_in_use) {
|
||||
R_SUCCEED_IF(context == m_context);
|
||||
m_context = context;
|
||||
|
||||
@@ -24,7 +24,7 @@ private:
|
||||
public:
|
||||
virtual ~ContextWriter() = default;
|
||||
|
||||
virtual Result Write(SystemClockContext& context) = 0;
|
||||
virtual Result Write(const SystemClockContext& context) = 0;
|
||||
void SignalAllNodes();
|
||||
void Link(OperationEvent& operation_event);
|
||||
|
||||
@@ -37,7 +37,7 @@ class LocalSystemClockContextWriter : public ContextWriter {
|
||||
public:
|
||||
explicit LocalSystemClockContextWriter(Core::System& system, SharedMemory& shared_memory);
|
||||
|
||||
Result Write(SystemClockContext& context) override;
|
||||
Result Write(const SystemClockContext& context) override;
|
||||
|
||||
private:
|
||||
Core::System& m_system;
|
||||
@@ -52,7 +52,7 @@ public:
|
||||
explicit NetworkSystemClockContextWriter(Core::System& system, SharedMemory& shared_memory,
|
||||
SystemClockCore& system_clock);
|
||||
|
||||
Result Write(SystemClockContext& context) override;
|
||||
Result Write(const SystemClockContext& context) override;
|
||||
|
||||
private:
|
||||
Core::System& m_system;
|
||||
@@ -67,7 +67,7 @@ class EphemeralNetworkSystemClockContextWriter : public ContextWriter {
|
||||
public:
|
||||
EphemeralNetworkSystemClockContextWriter(Core::System& system);
|
||||
|
||||
Result Write(SystemClockContext& context) override;
|
||||
Result Write(const SystemClockContext& context) override;
|
||||
|
||||
private:
|
||||
Core::System& m_system;
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
namespace Service::PSC::Time {
|
||||
|
||||
void StandardLocalSystemClockCore::Initialize(SystemClockContext& context, s64 time) {
|
||||
void StandardLocalSystemClockCore::Initialize(const SystemClockContext& context, s64 time) {
|
||||
SteadyClockTimePoint time_point{};
|
||||
if (GetCurrentTimePoint(time_point) == ResultSuccess &&
|
||||
context.steady_time_point.IdMatches(time_point)) {
|
||||
|
||||
@@ -17,7 +17,7 @@ public:
|
||||
: SystemClockCore{steady_clock} {}
|
||||
~StandardLocalSystemClockCore() override = default;
|
||||
|
||||
void Initialize(SystemClockContext& context, s64 time);
|
||||
void Initialize(const SystemClockContext& context, s64 time);
|
||||
};
|
||||
|
||||
} // namespace Service::PSC::Time
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
namespace Service::PSC::Time {
|
||||
|
||||
void StandardNetworkSystemClockCore::Initialize(SystemClockContext& context, s64 accuracy) {
|
||||
void StandardNetworkSystemClockCore::Initialize(const SystemClockContext& context, s64 accuracy) {
|
||||
if (SetContextAndWrite(context) != ResultSuccess) {
|
||||
LOG_ERROR(Service_Time, "Failed to SetContext");
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ public:
|
||||
: SystemClockCore{steady_clock} {}
|
||||
~StandardNetworkSystemClockCore() override = default;
|
||||
|
||||
void Initialize(SystemClockContext& context, s64 accuracy);
|
||||
void Initialize(const SystemClockContext& context, s64 accuracy);
|
||||
bool IsAccuracySufficient();
|
||||
|
||||
private:
|
||||
|
||||
@@ -46,7 +46,7 @@ Result StandardUserSystemClockCore::GetContext(SystemClockContext& out_context)
|
||||
R_RETURN(m_local_system_clock.GetContext(out_context));
|
||||
}
|
||||
|
||||
Result StandardUserSystemClockCore::SetContext(SystemClockContext& context) {
|
||||
Result StandardUserSystemClockCore::SetContext(const SystemClockContext& context) {
|
||||
R_RETURN(ResultNotImplemented);
|
||||
}
|
||||
|
||||
|
||||
@@ -36,7 +36,7 @@ public:
|
||||
Result SetAutomaticCorrection(bool automatic_correction);
|
||||
|
||||
Result GetContext(SystemClockContext& out_context) const override;
|
||||
Result SetContext(SystemClockContext& context) override;
|
||||
Result SetContext(const SystemClockContext& context) override;
|
||||
|
||||
Result GetTimePoint(SteadyClockTimePoint& out_time_point);
|
||||
void SetTimePointAndSignal(SteadyClockTimePoint& time_point);
|
||||
|
||||
@@ -51,12 +51,12 @@ Result SystemClockCore::GetContext(SystemClockContext& out_context) const {
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result SystemClockCore::SetContext(SystemClockContext& context) {
|
||||
Result SystemClockCore::SetContext(const SystemClockContext& context) {
|
||||
m_context = context;
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result SystemClockCore::SetContextAndWrite(SystemClockContext& context) {
|
||||
Result SystemClockCore::SetContextAndWrite(const SystemClockContext& context) {
|
||||
R_TRY(SetContext(context));
|
||||
|
||||
if (m_context_writer) {
|
||||
|
||||
@@ -41,8 +41,8 @@ public:
|
||||
}
|
||||
|
||||
virtual Result GetContext(SystemClockContext& out_context) const;
|
||||
virtual Result SetContext(SystemClockContext& context);
|
||||
Result SetContextAndWrite(SystemClockContext& context);
|
||||
virtual Result SetContext(const SystemClockContext& context);
|
||||
Result SetContextAndWrite(const SystemClockContext& context);
|
||||
|
||||
void LinkOperationEvent(OperationEvent& operation_event);
|
||||
|
||||
|
||||
@@ -78,8 +78,9 @@ Result ServiceManager::GetStaticServiceAsServiceManager(OutInterface<StaticServi
|
||||
}
|
||||
|
||||
Result ServiceManager::SetupStandardSteadyClockCore(bool is_rtc_reset_detected,
|
||||
Common::UUID& clock_source_id, s64 rtc_offset,
|
||||
s64 internal_offset, s64 test_offset) {
|
||||
const Common::UUID& clock_source_id,
|
||||
s64 rtc_offset, s64 internal_offset,
|
||||
s64 test_offset) {
|
||||
LOG_DEBUG(Service_Time,
|
||||
"called. is_rtc_reset_detected={} clock_source_id={} rtc_offset={} "
|
||||
"internal_offset={} test_offset={}",
|
||||
@@ -102,7 +103,8 @@ Result ServiceManager::SetupStandardSteadyClockCore(bool is_rtc_reset_detected,
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result ServiceManager::SetupStandardLocalSystemClockCore(SystemClockContext& context, s64 time) {
|
||||
Result ServiceManager::SetupStandardLocalSystemClockCore(const SystemClockContext& context,
|
||||
s64 time) {
|
||||
LOG_DEBUG(Service_Time,
|
||||
"called. context={} context.steady_time_point.clock_source_id={} time={}", context,
|
||||
context.steady_time_point.clock_source_id.RawString(), time);
|
||||
@@ -114,7 +116,7 @@ Result ServiceManager::SetupStandardLocalSystemClockCore(SystemClockContext& con
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result ServiceManager::SetupStandardNetworkSystemClockCore(SystemClockContext& context,
|
||||
Result ServiceManager::SetupStandardNetworkSystemClockCore(SystemClockContext context,
|
||||
s64 accuracy) {
|
||||
LOG_DEBUG(Service_Time, "called. context={} steady_time_point.clock_source_id={} accuracy={}",
|
||||
context, context.steady_time_point.clock_source_id.RawString(), accuracy);
|
||||
@@ -131,7 +133,7 @@ Result ServiceManager::SetupStandardNetworkSystemClockCore(SystemClockContext& c
|
||||
}
|
||||
|
||||
Result ServiceManager::SetupStandardUserSystemClockCore(bool automatic_correction,
|
||||
SteadyClockTimePoint& time_point) {
|
||||
SteadyClockTimePoint time_point) {
|
||||
LOG_DEBUG(Service_Time, "called. automatic_correction={} time_point={} clock_source_id={}",
|
||||
automatic_correction, time_point, time_point.clock_source_id.RawString());
|
||||
|
||||
@@ -144,9 +146,9 @@ Result ServiceManager::SetupStandardUserSystemClockCore(bool automatic_correctio
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result ServiceManager::SetupTimeZoneServiceCore(LocationName& name, RuleVersion& rule_version,
|
||||
u32 location_count,
|
||||
SteadyClockTimePoint& time_point,
|
||||
Result ServiceManager::SetupTimeZoneServiceCore(const LocationName& name,
|
||||
const RuleVersion& rule_version, u32 location_count,
|
||||
const SteadyClockTimePoint& time_point,
|
||||
InBuffer<BufferAttr_HipcAutoSelect> rule_buffer) {
|
||||
LOG_DEBUG(Service_Time,
|
||||
"called. name={} rule_version={} location_count={} time_point={} "
|
||||
|
||||
@@ -34,14 +34,15 @@ public:
|
||||
Result GetStaticServiceAsAdmin(OutInterface<StaticService> out_service);
|
||||
Result GetStaticServiceAsRepair(OutInterface<StaticService> out_service);
|
||||
Result GetStaticServiceAsServiceManager(OutInterface<StaticService> out_service);
|
||||
Result SetupStandardSteadyClockCore(bool is_rtc_reset_detected, Common::UUID& clock_source_id,
|
||||
s64 rtc_offset, s64 internal_offset, s64 test_offset);
|
||||
Result SetupStandardLocalSystemClockCore(SystemClockContext& context, s64 time);
|
||||
Result SetupStandardNetworkSystemClockCore(SystemClockContext& context, s64 accuracy);
|
||||
Result SetupStandardSteadyClockCore(bool is_rtc_reset_detected,
|
||||
const Common::UUID& clock_source_id, s64 rtc_offset,
|
||||
s64 internal_offset, s64 test_offset);
|
||||
Result SetupStandardLocalSystemClockCore(const SystemClockContext& context, s64 time);
|
||||
Result SetupStandardNetworkSystemClockCore(SystemClockContext context, s64 accuracy);
|
||||
Result SetupStandardUserSystemClockCore(bool automatic_correction,
|
||||
SteadyClockTimePoint& time_point);
|
||||
Result SetupTimeZoneServiceCore(LocationName& name, RuleVersion& rule_version,
|
||||
u32 location_count, SteadyClockTimePoint& time_point,
|
||||
SteadyClockTimePoint time_point);
|
||||
Result SetupTimeZoneServiceCore(const LocationName& name, const RuleVersion& rule_version,
|
||||
u32 location_count, const SteadyClockTimePoint& time_point,
|
||||
InBuffer<BufferAttr_HipcAutoSelect> rule_buffer);
|
||||
Result SetupEphemeralNetworkSystemClockCore();
|
||||
Result GetStandardLocalClockOperationEvent(OutCopyHandle<Kernel::KReadableEvent> out_event);
|
||||
|
||||
@@ -51,11 +51,11 @@ SharedMemory::SharedMemory(Core::System& system)
|
||||
std::memset(m_shared_memory_ptr, 0, sizeof(*m_shared_memory_ptr));
|
||||
}
|
||||
|
||||
void SharedMemory::SetLocalSystemContext(SystemClockContext& context) {
|
||||
void SharedMemory::SetLocalSystemContext(const SystemClockContext& context) {
|
||||
WriteToLockFreeAtomicType(&m_shared_memory_ptr->local_system_clock_contexts, context);
|
||||
}
|
||||
|
||||
void SharedMemory::SetNetworkSystemContext(SystemClockContext& context) {
|
||||
void SharedMemory::SetNetworkSystemContext(const SystemClockContext& context) {
|
||||
WriteToLockFreeAtomicType(&m_shared_memory_ptr->network_system_clock_contexts, context);
|
||||
}
|
||||
|
||||
@@ -64,7 +64,7 @@ void SharedMemory::SetSteadyClockTimePoint(ClockSourceId clock_source_id, s64 ti
|
||||
{time_point, clock_source_id});
|
||||
}
|
||||
|
||||
void SharedMemory::SetContinuousAdjustment(ContinuousAdjustmentTimePoint& time_point) {
|
||||
void SharedMemory::SetContinuousAdjustment(const ContinuousAdjustmentTimePoint& time_point) {
|
||||
WriteToLockFreeAtomicType(&m_shared_memory_ptr->continuous_adjustment_time_points, time_point);
|
||||
}
|
||||
|
||||
|
||||
@@ -54,10 +54,10 @@ public:
|
||||
return m_k_shared_memory;
|
||||
}
|
||||
|
||||
void SetLocalSystemContext(SystemClockContext& context);
|
||||
void SetNetworkSystemContext(SystemClockContext& context);
|
||||
void SetLocalSystemContext(const SystemClockContext& context);
|
||||
void SetNetworkSystemContext(const SystemClockContext& context);
|
||||
void SetSteadyClockTimePoint(ClockSourceId clock_source_id, s64 time_diff);
|
||||
void SetContinuousAdjustment(ContinuousAdjustmentTimePoint& time_point);
|
||||
void SetContinuousAdjustment(const ContinuousAdjustmentTimePoint& time_point);
|
||||
void SetAutomaticCorrection(bool automatic_correction);
|
||||
void UpdateBaseTime(s64 time);
|
||||
|
||||
|
||||
@@ -198,8 +198,8 @@ Result StaticService::GetStandardUserSystemClockAutomaticCorrectionUpdatedTime(
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result StaticService::CalculateMonotonicSystemClockBaseTimePoint(Out<s64> out_time,
|
||||
SystemClockContext& context) {
|
||||
Result StaticService::CalculateMonotonicSystemClockBaseTimePoint(
|
||||
Out<s64> out_time, const SystemClockContext& context) {
|
||||
SCOPE_EXIT({ LOG_DEBUG(Service_Time, "called. context={} out_time={}", context, *out_time); });
|
||||
|
||||
R_UNLESS(m_time->m_standard_steady_clock.IsInitialized(), ResultClockUninitialized);
|
||||
@@ -231,10 +231,9 @@ Result StaticService::GetClockSnapshot(OutClockSnapshot out_snapshot, TimeType t
|
||||
R_RETURN(GetClockSnapshotImpl(out_snapshot, user_context, network_context, type));
|
||||
}
|
||||
|
||||
Result StaticService::GetClockSnapshotFromSystemClockContext(TimeType type,
|
||||
OutClockSnapshot out_snapshot,
|
||||
SystemClockContext& user_context,
|
||||
SystemClockContext& network_context) {
|
||||
Result StaticService::GetClockSnapshotFromSystemClockContext(
|
||||
TimeType type, OutClockSnapshot out_snapshot, const SystemClockContext& user_context,
|
||||
const SystemClockContext& network_context) {
|
||||
SCOPE_EXIT({
|
||||
LOG_DEBUG(Service_Time,
|
||||
"called. type={} user_context={} network_context={} out_snapshot={}", type,
|
||||
@@ -294,8 +293,9 @@ Result StaticService::CalculateSpanBetween(Out<s64> out_time, InClockSnapshot a,
|
||||
}
|
||||
|
||||
Result StaticService::GetClockSnapshotImpl(OutClockSnapshot out_snapshot,
|
||||
SystemClockContext& user_context,
|
||||
SystemClockContext& network_context, TimeType type) {
|
||||
const SystemClockContext& user_context,
|
||||
const SystemClockContext& network_context,
|
||||
TimeType type) {
|
||||
out_snapshot->user_context = user_context;
|
||||
out_snapshot->network_context = network_context;
|
||||
|
||||
|
||||
@@ -55,18 +55,19 @@ public:
|
||||
Result GetStandardUserSystemClockAutomaticCorrectionUpdatedTime(
|
||||
Out<SteadyClockTimePoint> out_time_point);
|
||||
Result CalculateMonotonicSystemClockBaseTimePoint(Out<s64> out_time,
|
||||
SystemClockContext& context);
|
||||
const SystemClockContext& context);
|
||||
Result GetClockSnapshot(OutClockSnapshot out_snapshot, TimeType type);
|
||||
Result GetClockSnapshotFromSystemClockContext(TimeType type, OutClockSnapshot out_snapshot,
|
||||
SystemClockContext& user_context,
|
||||
SystemClockContext& network_context);
|
||||
const SystemClockContext& user_context,
|
||||
const SystemClockContext& network_context);
|
||||
Result CalculateStandardUserSystemClockDifferenceByUser(Out<s64> out_difference,
|
||||
InClockSnapshot a, InClockSnapshot b);
|
||||
Result CalculateSpanBetween(Out<s64> out_time, InClockSnapshot a, InClockSnapshot b);
|
||||
|
||||
private:
|
||||
Result GetClockSnapshotImpl(OutClockSnapshot out_snapshot, SystemClockContext& user_context,
|
||||
SystemClockContext& network_context, TimeType type);
|
||||
Result GetClockSnapshotImpl(OutClockSnapshot out_snapshot,
|
||||
const SystemClockContext& user_context,
|
||||
const SystemClockContext& network_context, TimeType type);
|
||||
|
||||
Core::System& m_system;
|
||||
StaticServiceSetupInfo m_setup_info;
|
||||
|
||||
@@ -53,7 +53,7 @@ Result SystemClock::GetSystemClockContext(Out<SystemClockContext> out_context) {
|
||||
R_RETURN(m_clock_core.GetContext(*out_context));
|
||||
}
|
||||
|
||||
Result SystemClock::SetSystemClockContext(SystemClockContext& context) {
|
||||
Result SystemClock::SetSystemClockContext(const SystemClockContext& context) {
|
||||
LOG_DEBUG(Service_Time, "called. context={}", context);
|
||||
|
||||
R_UNLESS(m_can_write_clock, ResultPermissionDenied);
|
||||
|
||||
@@ -26,7 +26,7 @@ public:
|
||||
Result GetCurrentTime(Out<s64> out_time);
|
||||
Result SetCurrentTime(s64 time);
|
||||
Result GetSystemClockContext(Out<SystemClockContext> out_context);
|
||||
Result SetSystemClockContext(SystemClockContext& context);
|
||||
Result SetSystemClockContext(const SystemClockContext& context);
|
||||
Result GetOperationEventReadableHandle(OutCopyHandle<Kernel::KReadableEvent> out_event);
|
||||
|
||||
private:
|
||||
|
||||
@@ -55,7 +55,7 @@ constexpr bool GetTimeZoneTime(s64& out_time, const Tz::Rule& rule, s64 time, s3
|
||||
}
|
||||
} // namespace
|
||||
|
||||
void TimeZone::SetTimePoint(SteadyClockTimePoint& time_point) {
|
||||
void TimeZone::SetTimePoint(const SteadyClockTimePoint& time_point) {
|
||||
std::scoped_lock l{m_mutex};
|
||||
m_steady_clock_time_point = time_point;
|
||||
}
|
||||
@@ -65,7 +65,7 @@ void TimeZone::SetTotalLocationNameCount(u32 count) {
|
||||
m_total_location_name_count = count;
|
||||
}
|
||||
|
||||
void TimeZone::SetRuleVersion(RuleVersion& rule_version) {
|
||||
void TimeZone::SetRuleVersion(const RuleVersion& rule_version) {
|
||||
std::scoped_lock l{m_mutex};
|
||||
m_rule_version = rule_version;
|
||||
}
|
||||
@@ -123,7 +123,7 @@ Result TimeZone::ToCalendarTimeWithMyRule(CalendarTime& calendar_time,
|
||||
R_RETURN(ToCalendarTimeImpl(calendar_time, calendar_additional, time, m_my_rule));
|
||||
}
|
||||
|
||||
Result TimeZone::ParseBinary(LocationName& name, std::span<const u8> binary) {
|
||||
Result TimeZone::ParseBinary(const LocationName& name, std::span<const u8> binary) {
|
||||
std::scoped_lock l{m_mutex};
|
||||
|
||||
Tz::Rule tmp_rule{};
|
||||
|
||||
@@ -23,9 +23,9 @@ public:
|
||||
m_initialized = true;
|
||||
}
|
||||
|
||||
void SetTimePoint(SteadyClockTimePoint& time_point);
|
||||
void SetTimePoint(const SteadyClockTimePoint& time_point);
|
||||
void SetTotalLocationNameCount(u32 count);
|
||||
void SetRuleVersion(RuleVersion& rule_version);
|
||||
void SetRuleVersion(const RuleVersion& rule_version);
|
||||
Result GetLocationName(LocationName& out_name);
|
||||
Result GetTotalLocationCount(u32& out_count);
|
||||
Result GetRuleVersion(RuleVersion& out_rule_version);
|
||||
@@ -36,7 +36,7 @@ public:
|
||||
const Tz::Rule& rule);
|
||||
Result ToCalendarTimeWithMyRule(CalendarTime& calendar_time,
|
||||
CalendarAdditionalInfo& calendar_additional, s64 time);
|
||||
Result ParseBinary(LocationName& name, std::span<const u8> binary);
|
||||
Result ParseBinary(const LocationName& name, std::span<const u8> binary);
|
||||
Result ParseBinaryInto(Tz::Rule& out_rule, std::span<const u8> binary);
|
||||
Result ToPosixTime(u32& out_count, std::span<s64> out_times, size_t out_times_max_count,
|
||||
const CalendarTime& calendar, const Tz::Rule& rule);
|
||||
|
||||
@@ -42,7 +42,7 @@ Result TimeZoneService::GetDeviceLocationName(Out<LocationName> out_location_nam
|
||||
R_RETURN(m_time_zone.GetLocationName(*out_location_name));
|
||||
}
|
||||
|
||||
Result TimeZoneService::SetDeviceLocationName(LocationName& location_name) {
|
||||
Result TimeZoneService::SetDeviceLocationName(const LocationName& location_name) {
|
||||
LOG_DEBUG(Service_Time, "called. This function is not implemented!");
|
||||
|
||||
R_UNLESS(m_can_write_timezone_device_location, ResultPermissionDenied);
|
||||
@@ -62,7 +62,7 @@ Result TimeZoneService::LoadLocationNameList(
|
||||
R_RETURN(ResultNotImplemented);
|
||||
}
|
||||
|
||||
Result TimeZoneService::LoadTimeZoneRule(OutRule out_rule, LocationName& location_name) {
|
||||
Result TimeZoneService::LoadTimeZoneRule(OutRule out_rule, const LocationName& location_name) {
|
||||
LOG_DEBUG(Service_Time, "called. This function is not implemented!");
|
||||
|
||||
R_RETURN(ResultNotImplemented);
|
||||
@@ -86,7 +86,7 @@ Result TimeZoneService::GetDeviceLocationNameAndUpdatedTime(
|
||||
}
|
||||
|
||||
Result TimeZoneService::SetDeviceLocationNameWithTimeZoneRule(
|
||||
LocationName& location_name, InBuffer<BufferAttr_HipcAutoSelect> binary) {
|
||||
const LocationName& location_name, InBuffer<BufferAttr_HipcAutoSelect> binary) {
|
||||
LOG_DEBUG(Service_Time, "called. location_name={}", location_name);
|
||||
|
||||
R_UNLESS(m_can_write_timezone_device_location, ResultPermissionDenied);
|
||||
|
||||
@@ -31,16 +31,16 @@ public:
|
||||
~TimeZoneService() override = default;
|
||||
|
||||
Result GetDeviceLocationName(Out<LocationName> out_location_name);
|
||||
Result SetDeviceLocationName(LocationName& location_name);
|
||||
Result SetDeviceLocationName(const LocationName& location_name);
|
||||
Result GetTotalLocationNameCount(Out<u32> out_count);
|
||||
Result LoadLocationNameList(Out<u32> out_count,
|
||||
OutArray<LocationName, BufferAttr_HipcMapAlias> out_names,
|
||||
u32 index);
|
||||
Result LoadTimeZoneRule(OutRule out_rule, LocationName& location_name);
|
||||
Result LoadTimeZoneRule(OutRule out_rule, const LocationName& location_name);
|
||||
Result GetTimeZoneRuleVersion(Out<RuleVersion> out_rule_version);
|
||||
Result GetDeviceLocationNameAndUpdatedTime(Out<LocationName> location_name,
|
||||
Out<SteadyClockTimePoint> out_time_point);
|
||||
Result SetDeviceLocationNameWithTimeZoneRule(LocationName& location_name,
|
||||
Result SetDeviceLocationNameWithTimeZoneRule(const LocationName& location_name,
|
||||
InBuffer<BufferAttr_HipcAutoSelect> binary);
|
||||
Result ParseTimeZoneBinary(OutRule out_rule, InBuffer<BufferAttr_HipcAutoSelect> binary);
|
||||
Result GetDeviceLocationNameOperationEventReadableHandle(
|
||||
|
||||
@@ -549,13 +549,13 @@ public:
|
||||
}
|
||||
|
||||
Result RegisterProcessHandle(ClientProcessId client_pid,
|
||||
InCopyHandle<Kernel::KProcess>& process) {
|
||||
InCopyHandle<Kernel::KProcess> process) {
|
||||
// Register the process.
|
||||
R_RETURN(m_ro->RegisterProcess(std::addressof(m_context_id), process.Get(), *client_pid));
|
||||
}
|
||||
|
||||
Result RegisterProcessModuleInfo(ClientProcessId client_pid, u64 nrr_address, u64 nrr_size,
|
||||
InCopyHandle<Kernel::KProcess>& process) {
|
||||
InCopyHandle<Kernel::KProcess> process) {
|
||||
// Validate the process.
|
||||
R_TRY(m_ro->ValidateProcess(m_context_id, *client_pid));
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
#include "core/hle/service/nvnflinger/buffer_queue_consumer.h"
|
||||
#include "core/hle/service/nvnflinger/buffer_queue_core.h"
|
||||
#include "core/hle/service/nvnflinger/buffer_queue_producer.h"
|
||||
#include "core/hle/service/nvnflinger/hardware_composer.h"
|
||||
#include "core/hle/service/nvnflinger/hos_binder_driver_server.h"
|
||||
#include "core/hle/service/vi/display/vi_display.h"
|
||||
#include "core/hle/service/vi/layer/vi_layer.h"
|
||||
@@ -43,6 +44,7 @@ Display::Display(u64 id, std::string name_,
|
||||
KernelHelpers::ServiceContext& service_context_, Core::System& system_)
|
||||
: display_id{id}, name{std::move(name_)}, hos_binder_driver_server{hos_binder_driver_server_},
|
||||
service_context{service_context_} {
|
||||
hardware_composer = std::make_unique<Nvnflinger::HardwareComposer>();
|
||||
vsync_event = service_context.CreateEvent(fmt::format("Display VSync Event {}", id));
|
||||
}
|
||||
|
||||
@@ -81,8 +83,6 @@ void Display::SignalVSyncEvent() {
|
||||
|
||||
void Display::CreateLayer(u64 layer_id, u32 binder_id,
|
||||
Service::Nvidia::NvCore::Container& nv_core) {
|
||||
ASSERT_MSG(layers.empty(), "Only one layer is supported per display at the moment");
|
||||
|
||||
auto [core, producer, consumer] = CreateBufferQueue(service_context, nv_core.GetNvMapFile());
|
||||
|
||||
auto buffer_item_consumer = std::make_shared<android::BufferItemConsumer>(std::move(consumer));
|
||||
|
||||
@@ -11,9 +11,14 @@
|
||||
#include "common/common_types.h"
|
||||
#include "core/hle/result.h"
|
||||
|
||||
namespace Core {
|
||||
class System;
|
||||
}
|
||||
|
||||
namespace Kernel {
|
||||
class KEvent;
|
||||
}
|
||||
class KReadableEvent;
|
||||
} // namespace Kernel
|
||||
|
||||
namespace Service::android {
|
||||
class BufferQueueProducer;
|
||||
@@ -24,8 +29,9 @@ class ServiceContext;
|
||||
}
|
||||
|
||||
namespace Service::Nvnflinger {
|
||||
class HardwareComposer;
|
||||
class HosBinderDriverServer;
|
||||
}
|
||||
} // namespace Service::Nvnflinger
|
||||
|
||||
namespace Service::Nvidia::NvCore {
|
||||
class Container;
|
||||
@@ -118,6 +124,10 @@ public:
|
||||
///
|
||||
const Layer* FindLayer(u64 layer_id) const;
|
||||
|
||||
Nvnflinger::HardwareComposer& GetComposer() const {
|
||||
return *hardware_composer;
|
||||
}
|
||||
|
||||
private:
|
||||
u64 display_id;
|
||||
std::string name;
|
||||
@@ -125,6 +135,7 @@ private:
|
||||
KernelHelpers::ServiceContext& service_context;
|
||||
|
||||
std::vector<std::unique_ptr<Layer>> layers;
|
||||
std::unique_ptr<Nvnflinger::HardwareComposer> hardware_composer;
|
||||
Kernel::KEvent* vsync_event{};
|
||||
bool is_abandoned{};
|
||||
};
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
|
||||
// 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"
|
||||
|
||||
namespace Service::VI {
|
||||
@@ -8,8 +9,9 @@ namespace Service::VI {
|
||||
Layer::Layer(u64 layer_id_, u32 binder_id_, android::BufferQueueCore& core_,
|
||||
android::BufferQueueProducer& binder_,
|
||||
std::shared_ptr<android::BufferItemConsumer>&& consumer_)
|
||||
: layer_id{layer_id_}, binder_id{binder_id_}, core{core_}, binder{binder_},
|
||||
consumer{std::move(consumer_)}, open{false}, visible{true} {}
|
||||
: layer_id{layer_id_}, binder_id{binder_id_}, core{core_}, binder{binder_}, consumer{std::move(
|
||||
consumer_)},
|
||||
blending{Nvnflinger::LayerBlending::None}, open{false}, visible{true} {}
|
||||
|
||||
Layer::~Layer() = default;
|
||||
|
||||
|
||||
@@ -14,6 +14,10 @@ class BufferQueueCore;
|
||||
class BufferQueueProducer;
|
||||
} // namespace Service::android
|
||||
|
||||
namespace Service::Nvnflinger {
|
||||
enum class LayerBlending : u32;
|
||||
}
|
||||
|
||||
namespace Service::VI {
|
||||
|
||||
/// Represents a single display layer.
|
||||
@@ -92,12 +96,21 @@ public:
|
||||
return !std::exchange(open, true);
|
||||
}
|
||||
|
||||
Nvnflinger::LayerBlending GetBlending() {
|
||||
return blending;
|
||||
}
|
||||
|
||||
void SetBlending(Nvnflinger::LayerBlending b) {
|
||||
blending = b;
|
||||
}
|
||||
|
||||
private:
|
||||
const u64 layer_id;
|
||||
const u32 binder_id;
|
||||
android::BufferQueueCore& core;
|
||||
android::BufferQueueProducer& binder;
|
||||
std::shared_ptr<android::BufferItemConsumer> consumer;
|
||||
Service::Nvnflinger::LayerBlending blending;
|
||||
bool open;
|
||||
bool visible;
|
||||
};
|
||||
|
||||
@@ -195,8 +195,9 @@ private:
|
||||
void GetSharedBufferMemoryHandleId(HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
const u64 buffer_id = rp.PopRaw<u64>();
|
||||
const u64 aruid = ctx.GetPID();
|
||||
|
||||
LOG_INFO(Service_VI, "called. buffer_id={:#x}", buffer_id);
|
||||
LOG_INFO(Service_VI, "called. buffer_id={:#x}, aruid={:#x}", buffer_id, aruid);
|
||||
|
||||
struct OutputParameters {
|
||||
s32 nvmap_handle;
|
||||
@@ -206,7 +207,7 @@ private:
|
||||
OutputParameters out{};
|
||||
Nvnflinger::SharedMemoryPoolLayout layout{};
|
||||
const auto result = nvnflinger.GetSystemBufferManager().GetSharedBufferMemoryHandleId(
|
||||
&out.size, &out.nvmap_handle, &layout, buffer_id, 0);
|
||||
&out.size, &out.nvmap_handle, &layout, buffer_id, aruid);
|
||||
|
||||
ctx.WriteBuffer(&layout, sizeof(layout));
|
||||
|
||||
|
||||
@@ -5,10 +5,12 @@
|
||||
#include "common/hex_util.h"
|
||||
#include "common/microprofile.h"
|
||||
#include "common/swap.h"
|
||||
#include "core/arm/debug.h"
|
||||
#include "core/core.h"
|
||||
#include "core/core_timing.h"
|
||||
#include "core/hle/kernel/k_page_table.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/sm/sm.h"
|
||||
#include "core/memory.h"
|
||||
@@ -46,12 +48,25 @@ StandardVmCallbacks::StandardVmCallbacks(System& system_, const CheatProcessMeta
|
||||
|
||||
StandardVmCallbacks::~StandardVmCallbacks() = default;
|
||||
|
||||
void StandardVmCallbacks::MemoryRead(VAddr address, void* data, u64 size) {
|
||||
system.ApplicationMemory().ReadBlock(SanitizeAddress(address), data, size);
|
||||
void StandardVmCallbacks::MemoryReadUnsafe(VAddr address, void* data, u64 size) {
|
||||
// Return zero on invalid address
|
||||
if (!IsAddressInRange(address) || !system.ApplicationMemory().IsValidVirtualAddress(address)) {
|
||||
std::memset(data, 0, size);
|
||||
return;
|
||||
}
|
||||
|
||||
system.ApplicationMemory().ReadBlock(address, data, size);
|
||||
}
|
||||
|
||||
void StandardVmCallbacks::MemoryWrite(VAddr address, const void* data, u64 size) {
|
||||
system.ApplicationMemory().WriteBlock(SanitizeAddress(address), data, size);
|
||||
void StandardVmCallbacks::MemoryWriteUnsafe(VAddr address, const void* data, u64 size) {
|
||||
// Skip invalid memory write address
|
||||
if (!IsAddressInRange(address) || !system.ApplicationMemory().IsValidVirtualAddress(address)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (system.ApplicationMemory().WriteBlock(address, data, size)) {
|
||||
Core::InvalidateInstructionCacheRange(system.ApplicationProcess(), address, size);
|
||||
}
|
||||
}
|
||||
|
||||
u64 StandardVmCallbacks::HidKeysDown() {
|
||||
@@ -81,21 +96,25 @@ void StandardVmCallbacks::CommandLog(std::string_view data) {
|
||||
data.back() == '\n' ? data.substr(0, data.size() - 1) : data);
|
||||
}
|
||||
|
||||
VAddr StandardVmCallbacks::SanitizeAddress(VAddr in) const {
|
||||
bool StandardVmCallbacks::IsAddressInRange(VAddr in) const {
|
||||
if ((in < metadata.main_nso_extents.base ||
|
||||
in >= metadata.main_nso_extents.base + metadata.main_nso_extents.size) &&
|
||||
(in < metadata.heap_extents.base ||
|
||||
in >= metadata.heap_extents.base + metadata.heap_extents.size)) {
|
||||
LOG_ERROR(CheatEngine,
|
||||
in >= metadata.heap_extents.base + metadata.heap_extents.size) &&
|
||||
(in < metadata.alias_extents.base ||
|
||||
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 "
|
||||
"persists, "
|
||||
"the cheat may be incorrect. However, this may be normal early in execution if "
|
||||
"the game has not properly set up yet.",
|
||||
in);
|
||||
return 0; ///< Invalid addresses will hard crash
|
||||
return false; ///< Invalid addresses will hard crash
|
||||
}
|
||||
|
||||
return in;
|
||||
return true;
|
||||
}
|
||||
|
||||
CheatParser::~CheatParser() = default;
|
||||
@@ -211,16 +230,14 @@ void CheatEngine::Initialize() {
|
||||
.base = GetInteger(page_table.GetHeapRegionStart()),
|
||||
.size = page_table.GetHeapRegionSize(),
|
||||
};
|
||||
|
||||
metadata.address_space_extents = {
|
||||
.base = GetInteger(page_table.GetAddressSpaceStart()),
|
||||
.size = page_table.GetAddressSpaceSize(),
|
||||
};
|
||||
|
||||
metadata.alias_extents = {
|
||||
metadata.aslr_extents = {
|
||||
.base = GetInteger(page_table.GetAliasCodeRegionStart()),
|
||||
.size = page_table.GetAliasCodeRegionSize(),
|
||||
};
|
||||
metadata.alias_extents = {
|
||||
.base = GetInteger(page_table.GetAliasRegionStart()),
|
||||
.size = page_table.GetAliasRegionSize(),
|
||||
};
|
||||
|
||||
is_pending_reload.exchange(true);
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user