Compare commits

...

99 Commits

Author SHA1 Message Date
Narr the Reg ee847f8ff0 hid_core: Move hid to it's own subproject 2024-01-05 11:41:15 -06:00
liamwhite 92a331af76 Merge pull request #12437 from ameerj/gl-amd-fixes
OpenGL: Fixes and workaround updates for AMD
2024-01-04 15:53:44 -05:00
liamwhite a8f62bff43 Merge pull request #12575 from t895/inconsistent-settings-application
frontend_common: config: Only write setting related to opened config file
2024-01-04 15:51:24 -05:00
liamwhite 519904e8a8 Merge pull request #12571 from t895/apply-orientation-on-start
android: Expose more orientation options
2024-01-04 15:51:08 -05:00
liamwhite 8d3463dbdd Merge pull request #12570 from t895/generic-config-pain
frontend_common: config: Move WriteIntegerSetting definition to header
2024-01-04 15:51:00 -05:00
liamwhite b125cb97a2 Merge pull request #12568 from t895/actions-button
actions: android: Allow for manually triggering Android builds
2024-01-04 15:50:54 -05:00
liamwhite d7e7a69e00 Merge pull request #12558 from t895/zip-storage-method
android: Disable compression for zip exports
2024-01-04 15:50:47 -05:00
liamwhite 246cffb624 Merge pull request #12557 from merryhime/termination-ipi
KThread: Send termination interrupt to all cores a thread has affinity to
2024-01-04 15:50:40 -05:00
liamwhite 0e93cad4f0 Merge pull request #12549 from german77/npadresource
service: hid: Implement NpadResource and NpadData
2024-01-04 15:50:33 -05:00
t895 39d28a5131 android: Save global config synchronously in onCloseGameFoldersFragment
Could cause multiple global saves at once that went untracked previously
2024-01-03 22:50:21 -05:00
t895 fa04dea7c4 frontend_common: config: Only write setting related to opened config file
If we tried to write a switchable setting to config that was not using global in the global config instance, we could write the per-game setting accidentally. This ensures that we always use the global setting for global config and the currently applied setting for custom config.
2024-01-03 22:49:41 -05:00
t895 1c278974a8 android: Don't save settings on config destruction
Android doesn't have a proper way of destroying its config object so it's best to stick to the built-in methods to control saving config
2024-01-03 22:12:15 -05:00
t895 2b838b6d06 android: Update orientation on emulation fragment start 2024-01-03 21:35:45 -05:00
t895 82ea082997 android: Expose all orientation locking options 2024-01-03 21:35:45 -05:00
Narr the Reg 5562322290 service: hid: Remove data races when handling shared memory 2024-01-03 20:21:16 -06:00
Narr the Reg 6a244465ce service: hid: Implement NpadResource and NpadData 2024-01-03 20:21:14 -06:00
t895 bdf87ba0f8 frontend_common: config: Move WriteIntegerSetting definition to header
Fixes a compiler error where the compiler could not see the definition of the method in qt_config and others.
2024-01-03 17:57:20 -05:00
t895 3b314a68a1 actions: android: Prevent resolving tag commit to PR link 2024-01-03 17:01:31 -05:00
t895 06c68fb196 actions: android: Resolve PR commits to link 2024-01-03 17:00:49 -05:00
t895 9a31122c82 actions: android: Move trigger logic to be yuzu-android specific 2024-01-03 03:15:07 -05:00
t895 dace726d08 android: Add internal option to disable compression for zip exports
Disables compression for user data and save exports
2024-01-02 18:11:22 -05:00
Merry 0f7fc94111 KThread: Send termination interrupt to all cores a thread has affinity to
KThread::RequestTerminate may run from a thread which is not the CurrentCore, and thus
masking this out is erroneous.
2024-01-02 21:34:34 +00:00
liamwhite 148ad0cf0b Merge pull request #12554 from german77/directconnect
yuzu: Use displayed port on direct connect
2024-01-02 13:09:53 -05:00
Narr the Reg 1b4cf7fc27 yuzu: Use displayed port on direct connect 2024-01-02 10:17:26 -06:00
liamwhite cec91c5fd6 Merge pull request #12551 from t895/dpad-save-fix
android: Fix dpad position saving
2024-01-02 10:44:26 -05:00
liamwhite 974ccb6f00 Merge pull request #12552 from t895/i-am-a-dummy
android: Use case-insensitive check for addon directory
2024-01-02 10:44:15 -05:00
t895 3c78926d75 android: Use case-insensitive check for addon directory 2024-01-01 22:51:32 -05:00
t895 466cdeb8a0 android: Fix dpad position saving
Was using the wrong key previously
2024-01-01 22:48:10 -05:00
liamwhite 29b983398c Merge pull request #12544 from zhaobot/tx-update-20240101021433
Update translations (2024-01-01)
2024-01-01 15:02:28 -05:00
liamwhite 15cf34cd62 Merge pull request #12543 from FernandoS27/stop-liking-posts-from-ur-friends-ex
VideoCore: A few fixes to DMA and swapchain
2024-01-01 15:02:20 -05:00
liamwhite 59d81ae614 Merge pull request #12536 from german77/npad_interface
service: hid: Use applet resource to get latest shared memory handle
2024-01-01 15:02:13 -05:00
liamwhite c3c676b7d6 Merge pull request #12518 from t895/theme-settings
android: Migrate remaining settings to ini
2024-01-01 15:02:06 -05:00
Narr the Reg aa9ff2ffc2 Merge pull request #12454 from liamwhite/ct-stuff
core_timing: minor refactors
2024-01-01 13:56:31 -06:00
Narr the Reg f0f92edbd0 Merge pull request #12466 from liamwhite/sh2
core: track separate heap allocation for linux
2024-01-01 13:56:16 -06:00
Narr the Reg 4d49f095b3 Merge pull request #12501 from liamwhite/ips
ips_layer: prevent out of bounds access with offset exceeding module size
2024-01-01 13:56:06 -06:00
Narr the Reg f47d618e54 Merge pull request #12513 from liamwhite/jit-fix
jit: use code memory handles correctly
2024-01-01 13:55:51 -06:00
The yuzu Community 583e04bdd6 Update translations (2024-01-01) 2024-01-01 02:14:51 +00:00
Fernando Sahmkow 737e6e531c Vulkan: Only recreate swapchain if the frame is bigger than the swap image. 2023-12-31 21:03:46 +01:00
Fernando Sahmkow d07397931a MaxwellDMA: Don't flush the outputs of a dma copy. 2023-12-31 21:00:01 +01:00
Narr the Reg 865abfc37c service: hid: Use applet resource to get latest shared memory handle 2023-12-31 10:51:01 -06:00
t895 aa4d15594f android: Expose touchscreen toggle 2023-12-30 15:11:36 -05:00
t895 278cafb76c android: Don't apply material you below android 12
Since you can manually change the config file now, users can force the material you theme under Android 12 and that will result in crashing on startup. This swaps to the default theme if that happens.
2023-12-30 15:11:36 -05:00
t895 24a78dba31 frontend_common: config: Do not count "." as a special character
It would break reading floating point settings
2023-12-30 15:11:36 -05:00
t895 d163b18208 android: Migrate in-game overlay settings to ini 2023-12-30 15:11:36 -05:00
t895 051afd21e7 frontend_common: config: Refactor WriteSetting to stricter types
Previously this could cause problems if a version of the template generated for WriteSetting didn't use the type you needed (e.g. floating point values). Now these are all ready without having to be used within frontend_common first.
2023-12-30 15:11:36 -05:00
t895 d3f38ce56c android: Migrate theme settings to ini 2023-12-30 15:11:35 -05:00
t895 b2b4742e61 android: Update Kotlin version to 1.9.20 2023-12-30 15:11:00 -05:00
liamwhite 09bfc852dc Merge pull request #12509 from liamwhite/ktrace
k_capabilities: simplify KTrace map skip logic
2023-12-30 14:59:09 -05:00
liamwhite ace74bd066 Merge pull request #12486 from t895/debug-ci
actions: android: Build relWithDebInfo on main repo
2023-12-30 14:59:04 -05:00
liamwhite f6ee53af14 Merge pull request #12527 from DCNick3/log-more-sdl-errors
Report more SDL errors
2023-12-30 14:58:58 -05:00
liamwhite 6c6cb5745f Merge pull request #12521 from ReillyBrogan/fix-wayland-appid
Fix Wayland appId
2023-12-30 14:58:52 -05:00
liamwhite 3262c0f747 Merge pull request #12520 from t895/settings-tomfoolery
android: Small settings tweaks
2023-12-30 14:58:45 -05:00
Nikita Strygin 9323a1f9b2 yuzu_cmd: Report more SDL errors 2023-12-30 13:32:33 +03:00
Fernando S f02a8d0ae9 Merge pull request #12479 from GPUCode/linear-bcn
video_core: Fix buffer_row_length for linear compressed textures
2023-12-30 06:56:08 +01:00
Fernando S 8517d7cb44 Merge pull request #12487 from liamwhite/clip3
shader_recompiler: use default value for clip distances array
2023-12-30 06:54:44 +01:00
Reilly Brogan cb4b4f3d6e Fix Wayland appId
On compliant Wayland compositors windows are matched to their .desktop files by comparing the appId window property to the name of the .desktop file without the .deskop extension.

Qt5/6 by default set this property to the basename of the binary (IE `yuzu`) which does not match the expected value `org.yuzu_emu.yuzu`. We can fix this and fix window associations on compliant compositors (like Plasma) by using the `setDesktopFileName()` function which will set the appId window property. This is a no-op on X11 so is safe to be ran without guards.
2023-12-29 20:32:08 -06:00
t895 21e7f86697 android: Expose anisotropic filtering setting 2023-12-29 17:43:36 -05:00
t895 347b3bd18d android: Center switch setting title when no description is present 2023-12-29 17:28:01 -05:00
t895 755c45777f android: Pair fastmem toggle to CPU Debug toggle
Hides fastmem toggle when CPU Debugging is disabled
2023-12-29 17:27:36 -05:00
Liam 558192abf4 jit: use code memory handles correctly 2023-12-29 01:07:47 -05:00
t895 d677052e8c actions: android: Build relWithDebInfo on main repo 2023-12-28 20:53:16 -05:00
Liam 95bfc542aa k_capabilities: simplify KTrace map skip logic 2023-12-28 01:22:57 -05:00
Liam d1c99c5d52 ips_layer: prevent out of bounds access with offset exceeding module size 2023-12-28 01:16:51 -05:00
Liam adb2af0a2b heap_tracker: use linear-time mapping eviction 2023-12-27 10:42:27 -05:00
Liam d0c60605ab shader_recompiler: use default value for clip distances array 2023-12-26 19:32:47 -05:00
Liam 6697b665ca shader_recompiler: respect clip distance limits in indexed store 2023-12-26 19:10:25 -05:00
liamwhite 12178c694a Merge pull request #12455 from liamwhite/end-wait
kernel: use simple mutex for object list container
2023-12-26 11:46:19 -05:00
liamwhite de1e5584b3 Merge pull request #12465 from liamwhite/proper-handle-table
service: fetch objects from the client handle table
2023-12-26 11:46:11 -05:00
liamwhite 1559984f77 Merge pull request #12471 from FearlessTobi/port-7146
Port citra-emu/citra#7146: "assert/logging: Stop the logging thread and flush the backends before crashing"
2023-12-26 11:46:04 -05:00
liamwhite 467ac4fdfe Merge pull request #12472 from FearlessTobi/port-7239
Port citra-emu/citra#7239: "common: Miscellaneous cleanups"
2023-12-26 11:45:57 -05:00
liamwhite 69b7100dac Merge pull request #12449 from liamwhite/debug-utils
renderer_vulkan: skip SetObjectNameEXT on unsupported driver
2023-12-26 11:45:39 -05:00
liamwhite 14dc41d4b3 Merge pull request #12448 from liamwhite/format-assert
renderer_vulkan: demote format assert to error log
2023-12-26 11:45:33 -05:00
liamwhite ad049f13aa Merge pull request #12415 from ameerj/ogl-draw-auto
gl_rasterizer: Implement DrawTransformFeedback macro
2023-12-26 11:45:25 -05:00
GPUCode 20e0407235 video_core: Fix buffer_row_length computation for linear compressed textures 2023-12-26 16:33:03 +02:00
FearlessTobi 4f569fd568 assert/logging: Stop the logging thread and flush the backends before crashing
Co-Authored-By: SachinVin <26602104+SachinVin@users.noreply.github.com>
2023-12-26 10:35:14 +01:00
Liam ddda76f9b0 core: track separate heap allocation for linux 2023-12-25 23:30:56 -05:00
FearlessTobi 553dac2ae0 ring_buffer: Use feature macro
Co-Authored-By: GPUCode <47210458+GPUCode@users.noreply.github.com>
2023-12-25 14:10:40 +01:00
FearlessTobi 96abe0d7d3 main: Remove unused enum
Co-Authored-By: GPUCode <47210458+GPUCode@users.noreply.github.com>
2023-12-25 14:10:05 +01:00
Liam 47e44a6693 am/jit: reference memory instance from context 2023-12-24 19:36:42 -05:00
Liam cf8c7d4ed3 kernel: remove unecessary process member from handle table 2023-12-24 19:23:03 -05:00
Liam 5165ed9efd service: fetch objects from the client handle table 2023-12-24 19:20:43 -05:00
Fernando S 05e3db3ac9 Merge pull request #12394 from liamwhite/per-process-memory
general: properly support multiple memory instances
2023-12-24 16:23:14 +01:00
Liam e3491a9ee8 kernel: use simple mutex for object list container 2023-12-23 16:26:07 -05:00
Liam 3a4e7d45f1 core_timing: block advance thread while clearing and signal after 2023-12-23 15:36:46 -05:00
Liam 05eda56e66 core_timing: handle concurrent unscheduling of looping events 2023-12-23 15:36:46 -05:00
Liam 575db04172 core_timing: use static typing for no-wait unschedule 2023-12-23 15:36:46 -05:00
Liam f34d3d7e84 core_timing: remove user data value 2023-12-23 15:36:44 -05:00
Liam 6a1ddc5028 renderer_vulkan: skip SetObjectNameEXT on unsupported driver 2023-12-23 11:08:02 -05:00
Liam c57ae803a6 kernel: fix resource limit imbalance 2023-12-22 21:52:49 -05:00
Liam db7b2bc8f1 kernel: restrict nce to applications 2023-12-22 21:52:49 -05:00
Liam 31bf57a310 general: properly support multiple memory instances 2023-12-22 21:52:49 -05:00
Liam cae675343c k_server_session: remove scratch buffer usage in favor of direct copy 2023-12-22 21:52:49 -05:00
Liam 35501ba41c k_server_session: process for guest servers 2023-12-22 21:52:49 -05:00
Liam 419055e484 kernel: instantiate memory separately for each guest process 2023-12-22 21:52:49 -05:00
Ameer J 139b4cc9ea Settings: Indicate AMD's compatibility with SPIR-V on OGL 2023-12-21 22:00:49 -05:00
Ameer J d5d0d2cb0e spirv_emit_context: Fix BaseInstance for OGL spirv 2023-12-21 21:53:24 -05:00
Ameer J a5b2b8b91b emit_glsl_image: Use inlined texelFetch offsets 2023-12-20 19:24:11 -05:00
Ameer J b4b301d22e gl_device: Remove AMD blacklists that are no longer applicable 2023-12-20 18:19:15 -05:00
Ameer J bbc0ed118d gl_rasterizer: Implement DrawTransformFeedback macro 2023-12-19 19:54:57 -05:00
317 changed files with 15350 additions and 11265 deletions
+7 -2
View File
@@ -6,7 +6,12 @@
export NDK_CCACHE="$(which ccache)"
ccache -s
BUILD_FLAVOR=mainline
BUILD_FLAVOR="mainline"
BUILD_TYPE="release"
if [ "${GITHUB_REPOSITORY}" == "yuzu-emu/yuzu" ]; then
BUILD_TYPE="relWithDebInfo"
fi
if [ ! -z "${ANDROID_KEYSTORE_B64}" ]; then
export ANDROID_KEYSTORE_FILE="${GITHUB_WORKSPACE}/ks.jks"
@@ -15,7 +20,7 @@ fi
cd src/android
chmod +x ./gradlew
./gradlew "assemble${BUILD_FLAVOR}Release" "bundle${BUILD_FLAVOR}Release"
./gradlew "assemble${BUILD_FLAVOR}${BUILD_TYPE}" "bundle${BUILD_FLAVOR}${BUILD_TYPE}"
ccache -s
+10 -3
View File
@@ -7,9 +7,16 @@
REV_NAME="yuzu-${GITDATE}-${GITREV}"
BUILD_FLAVOR=mainline
BUILD_FLAVOR="mainline"
cp src/android/app/build/outputs/apk/"${BUILD_FLAVOR}/release/app-${BUILD_FLAVOR}-release.apk" \
BUILD_TYPE_LOWER="release"
BUILD_TYPE_UPPER="Release"
if [ "${GITHUB_REPOSITORY}" == "yuzu-emu/yuzu" ]; then
BUILD_TYPE_LOWER="relWithDebInfo"
BUILD_TYPE_UPPER="RelWithDebInfo"
fi
cp src/android/app/build/outputs/apk/"${BUILD_FLAVOR}/${BUILD_TYPE_LOWER}/app-${BUILD_FLAVOR}-${BUILD_TYPE_LOWER}.apk" \
"artifacts/${REV_NAME}.apk"
cp src/android/app/build/outputs/bundle/"${BUILD_FLAVOR}Release"/"app-${BUILD_FLAVOR}-release.aab" \
cp src/android/app/build/outputs/bundle/"${BUILD_FLAVOR}${BUILD_TYPE_UPPER}"/"app-${BUILD_FLAVOR}-${BUILD_TYPE_LOWER}.aab" \
"artifacts/${REV_NAME}.aab"
+36 -13
View File
@@ -10,7 +10,7 @@ const CHANGE_LABEL = 'android-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);
async function checkBaseChanges(github, context) {
async function checkBaseChanges(github) {
// query the commit date of the latest commit on this branch
const query = `query($owner:String!, $name:String!, $ref:String!) {
repository(name:$name, owner:$owner) {
@@ -22,8 +22,8 @@ async function checkBaseChanges(github, context) {
}
}`;
const variables = {
owner: context.repo.owner,
name: context.repo.repo,
owner: 'yuzu-emu',
name: 'yuzu',
ref: 'refs/heads/master',
};
const result = await github.graphql(query, variables);
@@ -38,8 +38,8 @@ async function checkBaseChanges(github, context) {
return false;
}
async function checkAndroidChanges(github, context) {
if (checkBaseChanges(github, context)) return true;
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) {
@@ -48,8 +48,8 @@ async function checkAndroidChanges(github, context) {
}
}`;
const variables = {
owner: context.repo.owner,
name: context.repo.repo,
owner: 'yuzu-emu',
name: 'yuzu',
label: CHANGE_LABEL,
};
const result = await github.graphql(query, variables);
@@ -90,8 +90,8 @@ async function tagAndPush(github, owner, repo, execa, commit=false) {
console.log(`New tag: ${newTag}`);
if (commit) {
let channelName = channel[0].toUpperCase() + channel.slice(1);
console.info(`Committing pending commit as ${channelName} #${tagNumber + 1}`);
await execa("git", ['commit', '-m', `${channelName} #${tagNumber + 1}`]);
console.info(`Committing pending commit as ${channelName} ${tagNumber + 1}`);
await execa("git", ['commit', '-m', `${channelName} ${tagNumber + 1}`]);
}
console.info('Pushing tags to GitHub ...');
await execa("git", ['tag', newTag]);
@@ -157,7 +157,7 @@ async function mergePullRequests(pulls, execa) {
process1.stdout.pipe(process.stdout);
await process1;
const process2 = execa("git", ["commit", "-m", `Merge PR ${pr}`]);
const process2 = execa("git", ["commit", "-m", `Merge yuzu-emu#${pr}`]);
process2.stdout.pipe(process.stdout);
await process2;
@@ -182,7 +182,30 @@ async function mergePullRequests(pulls, execa) {
return mergeResults;
}
async function resetBranch(execa) {
console.log("::group::Reset master branch");
let hasFailed = false;
try {
await execa("git", ["remote", "add", "source", "https://github.com/yuzu-emu/yuzu.git"]);
await execa("git", ["fetch", "source"]);
const process1 = await execa("git", ["rev-parse", "source/master"]);
const headCommit = process1.stdout;
await execa("git", ["reset", "--hard", headCommit]);
} catch (err) {
console.log(`::error title=Failed to reset master branch`);
hasFailed = true;
}
console.log("::endgroup::");
if (hasFailed) {
throw 'Failed to reset the master branch. 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 query = `query ($owner:String!, $name:String!, $label:String!) {
repository(name:$name, owner:$owner) {
pullRequests(labels: [$label], states: OPEN, first: 100) {
@@ -193,8 +216,8 @@ async function mergebot(github, context, execa) {
}
}`;
const variables = {
owner: context.repo.owner,
name: context.repo.repo,
owner: 'yuzu-emu',
name: 'yuzu',
label: CHANGE_LABEL,
};
const result = await github.graphql(query, variables);
@@ -209,7 +232,7 @@ async function mergebot(github, context, execa) {
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, context.repo.owner, `${context.repo.repo}-android`, execa, true);
await tagAndPush(github, 'yuzu-emu', `yuzu-android`, execa, true);
}
module.exports.mergebot = mergebot;
+2 -2
View File
@@ -16,7 +16,7 @@ on:
jobs:
android:
runs-on: ubuntu-latest
if: ${{ github.event.inputs.android != 'false' && github.repository == 'yuzu-emu/yuzu' }}
if: ${{ github.event.inputs.android != 'false' && github.repository == 'yuzu-emu/yuzu-android' }}
steps:
# this checkout is required to make sure the GitHub Actions scripts are available
- uses: actions/checkout@v3
@@ -33,7 +33,7 @@ jobs:
script: |
if (context.payload.inputs && context.payload.inputs.android === 'true') return true;
const checkAndroidChanges = require('./.github/workflows/android-merge.js').checkAndroidChanges;
return checkAndroidChanges(github, context);
return checkAndroidChanges(github);
- run: npm install execa@5
if: ${{ steps.check-changes.outputs.result == 'true' }}
- uses: actions/checkout@v3
+290 -290
View File
File diff suppressed because it is too large Load Diff
+282 -282
View File
File diff suppressed because it is too large Load Diff
+424 -417
View File
File diff suppressed because it is too large Load Diff
+282 -282
View File
File diff suppressed because it is too large Load Diff
+305 -305
View File
File diff suppressed because it is too large Load Diff
+282 -282
View File
File diff suppressed because it is too large Load Diff
+347 -345
View File
File diff suppressed because it is too large Load Diff
+296 -296
View File
File diff suppressed because it is too large Load Diff
+329 -328
View File
File diff suppressed because it is too large Load Diff
+282 -282
View File
File diff suppressed because it is too large Load Diff
+283 -283
View File
File diff suppressed because it is too large Load Diff
+282 -282
View File
File diff suppressed because it is too large Load Diff
+282 -282
View File
File diff suppressed because it is too large Load Diff
+282 -282
View File
File diff suppressed because it is too large Load Diff
+282 -282
View File
File diff suppressed because it is too large Load Diff
+283 -283
View File
File diff suppressed because it is too large Load Diff
+331 -326
View File
File diff suppressed because it is too large Load Diff
+331 -326
View File
File diff suppressed because it is too large Load Diff
+282 -282
View File
File diff suppressed because it is too large Load Diff
+282 -282
View File
File diff suppressed because it is too large Load Diff
+282 -282
View File
File diff suppressed because it is too large Load Diff
+282 -282
View File
File diff suppressed because it is too large Load Diff
+282 -282
View File
File diff suppressed because it is too large Load Diff
+282 -282
View File
File diff suppressed because it is too large Load Diff
+282 -282
View File
File diff suppressed because it is too large Load Diff
+283 -283
View File
File diff suppressed because it is too large Load Diff
+1
View File
@@ -185,6 +185,7 @@ add_subdirectory(common)
add_subdirectory(core)
add_subdirectory(audio_core)
add_subdirectory(video_core)
add_subdirectory(hid_core)
add_subdirectory(network)
add_subdirectory(input_common)
add_subdirectory(frontend_common)
+1 -1
View File
@@ -10,7 +10,7 @@ plugins {
id("com.android.application")
id("org.jetbrains.kotlin.android")
id("kotlin-parcelize")
kotlin("plugin.serialization") version "1.8.21"
kotlin("plugin.serialization") version "1.9.20"
id("androidx.navigation.safeargs.kotlin")
id("org.jlleitschuh.gradle.ktlint") version "11.4.0"
}
@@ -49,6 +49,7 @@ import org.yuzu.yuzu_emu.utils.ForegroundService
import org.yuzu.yuzu_emu.utils.InputHandler
import org.yuzu.yuzu_emu.utils.Log
import org.yuzu.yuzu_emu.utils.MemoryUtil
import org.yuzu.yuzu_emu.utils.NativeConfig
import org.yuzu.yuzu_emu.utils.NfcReader
import org.yuzu.yuzu_emu.utils.ThemeHelper
import java.text.NumberFormat
@@ -170,6 +171,11 @@ class EmulationActivity : AppCompatActivity(), SensorEventListener {
stopMotionSensorListener()
}
override fun onStop() {
super.onStop()
NativeConfig.saveGlobalConfig()
}
override fun onUserLeaveHint() {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.S) {
if (BooleanSetting.PICTURE_IN_PICTURE.getBoolean() && !isInPictureInPictureMode) {
@@ -18,7 +18,14 @@ enum class BooleanSetting(override val key: String) : AbstractBooleanSetting {
RENDERER_REACTIVE_FLUSHING("use_reactive_flushing"),
RENDERER_DEBUG("debug"),
PICTURE_IN_PICTURE("picture_in_picture"),
USE_CUSTOM_RTC("custom_rtc_enabled");
USE_CUSTOM_RTC("custom_rtc_enabled"),
BLACK_BACKGROUNDS("black_backgrounds"),
JOYSTICK_REL_CENTER("joystick_rel_center"),
DPAD_SLIDE("dpad_slide"),
HAPTIC_FEEDBACK("haptic_feedback"),
SHOW_PERFORMANCE_OVERLAY("show_performance_overlay"),
SHOW_INPUT_OVERLAY("show_input_overlay"),
TOUCHSCREEN("touchscreen");
override fun getBoolean(needsGlobal: Boolean): Boolean =
NativeConfig.getBoolean(key, needsGlobal)
@@ -18,7 +18,12 @@ enum class IntSetting(override val key: String) : AbstractIntSetting {
RENDERER_ANTI_ALIASING("anti_aliasing"),
RENDERER_SCREEN_LAYOUT("screen_layout"),
RENDERER_ASPECT_RATIO("aspect_ratio"),
AUDIO_OUTPUT_ENGINE("output_engine");
AUDIO_OUTPUT_ENGINE("output_engine"),
MAX_ANISOTROPY("max_anisotropy"),
THEME("theme"),
THEME_MODE("theme_mode"),
OVERLAY_SCALE("control_scale"),
OVERLAY_OPACITY("control_opacity");
override fun getInt(needsGlobal: Boolean): Int = NativeConfig.getInt(key, needsGlobal)
@@ -15,18 +15,10 @@ object Settings {
SECTION_DEBUG(R.string.preferences_debug);
}
const val PREF_FIRST_APP_LAUNCH = "FirstApplicationLaunch"
const val PREF_MEMORY_WARNING_SHOWN = "MemoryWarningShown"
const val PREF_OVERLAY_VERSION = "OverlayVersion"
const val PREF_LANDSCAPE_OVERLAY_VERSION = "LandscapeOverlayVersion"
const val PREF_PORTRAIT_OVERLAY_VERSION = "PortraitOverlayVersion"
const val PREF_FOLDABLE_OVERLAY_VERSION = "FoldableOverlayVersion"
val overlayLayoutPrefs = listOf(
PREF_LANDSCAPE_OVERLAY_VERSION,
PREF_PORTRAIT_OVERLAY_VERSION,
PREF_FOLDABLE_OVERLAY_VERSION
)
// Deprecated input overlay preference keys
const val PREF_CONTROL_SCALE = "controlScale"
const val PREF_CONTROL_OPACITY = "controlOpacity"
const val PREF_TOUCH_ENABLED = "isTouchEnabled"
@@ -47,23 +39,12 @@ object Settings {
const val PREF_BUTTON_STICK_R = "buttonToggle14"
const val PREF_BUTTON_HOME = "buttonToggle15"
const val PREF_BUTTON_SCREENSHOT = "buttonToggle16"
const val PREF_MENU_SETTINGS_JOYSTICK_REL_CENTER = "EmulationMenuSettings_JoystickRelCenter"
const val PREF_MENU_SETTINGS_DPAD_SLIDE = "EmulationMenuSettings_DpadSlideEnable"
const val PREF_MENU_SETTINGS_HAPTICS = "EmulationMenuSettings_Haptics"
const val PREF_MENU_SETTINGS_SHOW_FPS = "EmulationMenuSettings_ShowFps"
const val PREF_MENU_SETTINGS_SHOW_OVERLAY = "EmulationMenuSettings_ShowOverlay"
const val PREF_FIRST_APP_LAUNCH = "FirstApplicationLaunch"
const val PREF_THEME = "Theme"
const val PREF_THEME_MODE = "ThemeMode"
const val PREF_BLACK_BACKGROUNDS = "BlackBackgrounds"
val overlayPreferences = listOf(
PREF_OVERLAY_VERSION,
PREF_CONTROL_SCALE,
PREF_CONTROL_OPACITY,
PREF_TOUCH_ENABLED,
PREF_BUTTON_A,
PREF_BUTTON_B,
PREF_BUTTON_X,
@@ -83,7 +64,33 @@ object Settings {
PREF_BUTTON_STICK_R
)
const val LayoutOption_Unspecified = 0
const val LayoutOption_MobilePortrait = 4
const val LayoutOption_MobileLandscape = 5
// Deprecated layout preference keys
const val PREF_LANDSCAPE_SUFFIX = "_Landscape"
const val PREF_PORTRAIT_SUFFIX = "_Portrait"
const val PREF_FOLDABLE_SUFFIX = "_Foldable"
val overlayLayoutSuffixes = listOf(
PREF_LANDSCAPE_SUFFIX,
PREF_PORTRAIT_SUFFIX,
PREF_FOLDABLE_SUFFIX
)
// Deprecated theme preference keys
const val PREF_THEME = "Theme"
const val PREF_THEME_MODE = "ThemeMode"
const val PREF_BLACK_BACKGROUNDS = "BlackBackgrounds"
enum class EmulationOrientation(val int: Int) {
Unspecified(0),
SensorLandscape(5),
Landscape(1),
ReverseLandscape(2),
SensorPortrait(6),
Portrait(4),
ReversePortrait(3);
companion object {
fun from(int: Int): EmulationOrientation =
entries.firstOrNull { it.int == int } ?: Unspecified
}
}
}
@@ -243,6 +243,15 @@ abstract class SettingsItem(
R.string.renderer_reactive_flushing_description
)
)
put(
SingleChoiceSetting(
IntSetting.MAX_ANISOTROPY,
R.string.anisotropic_filtering,
R.string.anisotropic_filtering_description,
R.array.anisoEntries,
R.array.anisoValues
)
)
put(
SingleChoiceSetting(
IntSetting.AUDIO_OUTPUT_ENGINE,
@@ -298,6 +307,7 @@ abstract class SettingsItem(
override val key: String = FASTMEM_COMBINED
override val isRuntimeModifiable: Boolean = false
override val pairedSettingKey = BooleanSetting.CPU_DEBUG_MODE.key
override val defaultValue: Boolean = true
override val isSwitchable: Boolean = true
override var global: Boolean
@@ -3,10 +3,8 @@
package org.yuzu.yuzu_emu.features.settings.ui
import android.content.SharedPreferences
import android.os.Build
import android.widget.Toast
import androidx.preference.PreferenceManager
import org.yuzu.yuzu_emu.NativeLibrary
import org.yuzu.yuzu_emu.R
import org.yuzu.yuzu_emu.YuzuApplication
@@ -29,9 +27,6 @@ class SettingsFragmentPresenter(
) {
private var settingsList = ArrayList<SettingsItem>()
private val preferences: SharedPreferences
get() = PreferenceManager.getDefaultSharedPreferences(YuzuApplication.appContext)
// Extension for altering settings list based on each setting's properties
fun ArrayList<SettingsItem>.add(key: String) {
val item = SettingsItem.settingsItems[key]!!
@@ -149,6 +144,7 @@ class SettingsFragmentPresenter(
add(IntSetting.RENDERER_VSYNC.key)
add(IntSetting.RENDERER_SCALING_FILTER.key)
add(IntSetting.RENDERER_ANTI_ALIASING.key)
add(IntSetting.MAX_ANISOTROPY.key)
add(IntSetting.RENDERER_SCREEN_LAYOUT.key)
add(IntSetting.RENDERER_ASPECT_RATIO.key)
add(BooleanSetting.PICTURE_IN_PICTURE.key)
@@ -169,25 +165,19 @@ class SettingsFragmentPresenter(
private fun addThemeSettings(sl: ArrayList<SettingsItem>) {
sl.apply {
val theme: AbstractIntSetting = object : AbstractIntSetting {
override fun getInt(needsGlobal: Boolean): Int =
preferences.getInt(Settings.PREF_THEME, 0)
override fun getInt(needsGlobal: Boolean): Int = IntSetting.THEME.getInt()
override fun setInt(value: Int) {
preferences.edit()
.putInt(Settings.PREF_THEME, value)
.apply()
IntSetting.THEME.setInt(value)
settingsViewModel.setShouldRecreate(true)
}
override val key: String = Settings.PREF_THEME
override val isRuntimeModifiable: Boolean = false
override fun getValueAsString(needsGlobal: Boolean): String = getInt().toString()
override val defaultValue: Int = 0
override fun reset() {
preferences.edit()
.putInt(Settings.PREF_THEME, defaultValue)
.apply()
}
override val key: String = IntSetting.THEME.key
override val isRuntimeModifiable: Boolean = IntSetting.THEME.isRuntimeModifiable
override fun getValueAsString(needsGlobal: Boolean): String =
IntSetting.THEME.getValueAsString()
override val defaultValue: Int = IntSetting.THEME.defaultValue
override fun reset() = IntSetting.THEME.setInt(defaultValue)
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
@@ -213,24 +203,22 @@ class SettingsFragmentPresenter(
}
val themeMode: AbstractIntSetting = object : AbstractIntSetting {
override fun getInt(needsGlobal: Boolean): Int =
preferences.getInt(Settings.PREF_THEME_MODE, -1)
override fun getInt(needsGlobal: Boolean): Int = IntSetting.THEME_MODE.getInt()
override fun setInt(value: Int) {
preferences.edit()
.putInt(Settings.PREF_THEME_MODE, value)
.apply()
IntSetting.THEME_MODE.setInt(value)
settingsViewModel.setShouldRecreate(true)
}
override val key: String = Settings.PREF_THEME_MODE
override val isRuntimeModifiable: Boolean = false
override fun getValueAsString(needsGlobal: Boolean): String = getInt().toString()
override val defaultValue: Int = -1
override val key: String = IntSetting.THEME_MODE.key
override val isRuntimeModifiable: Boolean =
IntSetting.THEME_MODE.isRuntimeModifiable
override fun getValueAsString(needsGlobal: Boolean): String =
IntSetting.THEME_MODE.getValueAsString()
override val defaultValue: Int = IntSetting.THEME_MODE.defaultValue
override fun reset() {
preferences.edit()
.putInt(Settings.PREF_BLACK_BACKGROUNDS, defaultValue)
.apply()
IntSetting.THEME_MODE.setInt(defaultValue)
settingsViewModel.setShouldRecreate(true)
}
}
@@ -247,25 +235,24 @@ class SettingsFragmentPresenter(
val blackBackgrounds: AbstractBooleanSetting = object : AbstractBooleanSetting {
override fun getBoolean(needsGlobal: Boolean): Boolean =
preferences.getBoolean(Settings.PREF_BLACK_BACKGROUNDS, false)
BooleanSetting.BLACK_BACKGROUNDS.getBoolean()
override fun setBoolean(value: Boolean) {
preferences.edit()
.putBoolean(Settings.PREF_BLACK_BACKGROUNDS, value)
.apply()
BooleanSetting.BLACK_BACKGROUNDS.setBoolean(value)
settingsViewModel.setShouldRecreate(true)
}
override val key: String = Settings.PREF_BLACK_BACKGROUNDS
override val isRuntimeModifiable: Boolean = false
override fun getValueAsString(needsGlobal: Boolean): String =
getBoolean().toString()
override val key: String = BooleanSetting.BLACK_BACKGROUNDS.key
override val isRuntimeModifiable: Boolean =
BooleanSetting.BLACK_BACKGROUNDS.isRuntimeModifiable
override val defaultValue: Boolean = false
override fun getValueAsString(needsGlobal: Boolean): String =
BooleanSetting.BLACK_BACKGROUNDS.getValueAsString()
override val defaultValue: Boolean = BooleanSetting.BLACK_BACKGROUNDS.defaultValue
override fun reset() {
preferences.edit()
.putBoolean(Settings.PREF_BLACK_BACKGROUNDS, defaultValue)
.apply()
BooleanSetting.BLACK_BACKGROUNDS
.setBoolean(BooleanSetting.BLACK_BACKGROUNDS.defaultValue)
settingsViewModel.setShouldRecreate(true)
}
}
@@ -149,7 +149,7 @@ class AddonsFragment : Fragment() {
}
val isValid = externalAddonDirectory.listFiles()
.any { AddonUtil.validAddonDirectories.contains(it.name) }
.any { AddonUtil.validAddonDirectories.contains(it.name?.lowercase()) }
val errorMessage = MessageDialogFragment.newInstance(
requireActivity(),
titleId = R.string.invalid_directory,
@@ -7,7 +7,6 @@ import android.annotation.SuppressLint
import android.app.AlertDialog
import android.content.Context
import android.content.DialogInterface
import android.content.SharedPreferences
import android.content.pm.ActivityInfo
import android.content.res.Configuration
import android.net.Uri
@@ -33,7 +32,6 @@ import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import androidx.navigation.findNavController
import androidx.navigation.fragment.navArgs
import androidx.preference.PreferenceManager
import androidx.window.layout.FoldingFeature
import androidx.window.layout.WindowInfoTracker
import androidx.window.layout.WindowLayoutInfo
@@ -46,22 +44,23 @@ import kotlinx.coroutines.launch
import org.yuzu.yuzu_emu.HomeNavigationDirections
import org.yuzu.yuzu_emu.NativeLibrary
import org.yuzu.yuzu_emu.R
import org.yuzu.yuzu_emu.YuzuApplication
import org.yuzu.yuzu_emu.activities.EmulationActivity
import org.yuzu.yuzu_emu.databinding.DialogOverlayAdjustBinding
import org.yuzu.yuzu_emu.databinding.FragmentEmulationBinding
import org.yuzu.yuzu_emu.features.settings.model.BooleanSetting
import org.yuzu.yuzu_emu.features.settings.model.IntSetting
import org.yuzu.yuzu_emu.features.settings.model.Settings
import org.yuzu.yuzu_emu.features.settings.model.Settings.EmulationOrientation
import org.yuzu.yuzu_emu.features.settings.utils.SettingsFile
import org.yuzu.yuzu_emu.model.DriverViewModel
import org.yuzu.yuzu_emu.model.Game
import org.yuzu.yuzu_emu.model.EmulationViewModel
import org.yuzu.yuzu_emu.overlay.InputOverlay
import org.yuzu.yuzu_emu.overlay.model.OverlayControl
import org.yuzu.yuzu_emu.overlay.model.OverlayLayout
import org.yuzu.yuzu_emu.utils.*
import java.lang.NullPointerException
class EmulationFragment : Fragment(), SurfaceHolder.Callback {
private lateinit var preferences: SharedPreferences
private lateinit var emulationState: EmulationState
private var emulationActivity: EmulationActivity? = null
private var perfStatsUpdater: (() -> Unit)? = null
@@ -101,6 +100,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
*/
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
updateOrientation()
val intentUri: Uri? = requireActivity().intent.data
var intentGame: Game? = null
@@ -141,7 +141,6 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
// So this fragment doesn't restart on configuration changes; i.e. rotation.
retainInstance = true
preferences = PreferenceManager.getDefaultSharedPreferences(YuzuApplication.appContext)
emulationState = EmulationState(game.path)
}
@@ -382,24 +381,25 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
}
updateScreenLayout()
val showInputOverlay = BooleanSetting.SHOW_INPUT_OVERLAY.getBoolean()
if (emulationActivity?.isInPictureInPictureMode == true) {
if (binding.drawerLayout.isOpen) {
binding.drawerLayout.close()
}
if (EmulationMenuSettings.showOverlay) {
if (showInputOverlay) {
binding.surfaceInputOverlay.visibility = View.INVISIBLE
}
} else {
if (EmulationMenuSettings.showOverlay && emulationViewModel.emulationStarted.value) {
if (showInputOverlay && emulationViewModel.emulationStarted.value) {
binding.surfaceInputOverlay.visibility = View.VISIBLE
} else {
binding.surfaceInputOverlay.visibility = View.INVISIBLE
}
if (!isInFoldableLayout) {
if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT) {
binding.surfaceInputOverlay.layout = InputOverlay.PORTRAIT
binding.surfaceInputOverlay.layout = OverlayLayout.Portrait
} else {
binding.surfaceInputOverlay.layout = InputOverlay.LANDSCAPE
binding.surfaceInputOverlay.layout = OverlayLayout.Landscape
}
}
}
@@ -423,17 +423,15 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
}
private fun resetInputOverlay() {
preferences.edit()
.remove(Settings.PREF_CONTROL_SCALE)
.remove(Settings.PREF_CONTROL_OPACITY)
.apply()
IntSetting.OVERLAY_SCALE.reset()
IntSetting.OVERLAY_OPACITY.reset()
binding.surfaceInputOverlay.post {
binding.surfaceInputOverlay.resetLayoutVisibilityAndPlacement()
}
}
private fun updateShowFpsOverlay() {
if (EmulationMenuSettings.showFps) {
if (BooleanSetting.SHOW_PERFORMANCE_OVERLAY.getBoolean()) {
val SYSTEM_FPS = 0
val FPS = 1
val FRAMETIME = 2
@@ -462,13 +460,23 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
@SuppressLint("SourceLockedOrientationActivity")
private fun updateOrientation() {
emulationActivity?.let {
it.requestedOrientation = when (IntSetting.RENDERER_SCREEN_LAYOUT.getInt()) {
Settings.LayoutOption_MobileLandscape ->
val orientationSetting =
EmulationOrientation.from(IntSetting.RENDERER_SCREEN_LAYOUT.getInt())
it.requestedOrientation = when (orientationSetting) {
EmulationOrientation.Unspecified -> ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED
EmulationOrientation.SensorLandscape ->
ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE
Settings.LayoutOption_MobilePortrait ->
ActivityInfo.SCREEN_ORIENTATION_USER_PORTRAIT
Settings.LayoutOption_Unspecified -> ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED
else -> ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE
EmulationOrientation.Landscape -> ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE
EmulationOrientation.ReverseLandscape ->
ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE
EmulationOrientation.SensorPortrait ->
ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT
EmulationOrientation.Portrait -> ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
EmulationOrientation.ReversePortrait ->
ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT
}
}
}
@@ -496,7 +504,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
binding.inGameMenu.layoutParams.height = it.bounds.bottom
isInFoldableLayout = true
binding.surfaceInputOverlay.layout = InputOverlay.FOLDABLE
binding.surfaceInputOverlay.layout = OverlayLayout.Foldable
}
}
it.isSeparating
@@ -535,18 +543,22 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
popup.menuInflater.inflate(R.menu.menu_overlay_options, popup.menu)
popup.menu.apply {
findItem(R.id.menu_toggle_fps).isChecked = EmulationMenuSettings.showFps
findItem(R.id.menu_rel_stick_center).isChecked = EmulationMenuSettings.joystickRelCenter
findItem(R.id.menu_dpad_slide).isChecked = EmulationMenuSettings.dpadSlide
findItem(R.id.menu_show_overlay).isChecked = EmulationMenuSettings.showOverlay
findItem(R.id.menu_haptics).isChecked = EmulationMenuSettings.hapticFeedback
findItem(R.id.menu_toggle_fps).isChecked =
BooleanSetting.SHOW_PERFORMANCE_OVERLAY.getBoolean()
findItem(R.id.menu_rel_stick_center).isChecked =
BooleanSetting.JOYSTICK_REL_CENTER.getBoolean()
findItem(R.id.menu_dpad_slide).isChecked = BooleanSetting.DPAD_SLIDE.getBoolean()
findItem(R.id.menu_show_overlay).isChecked =
BooleanSetting.SHOW_INPUT_OVERLAY.getBoolean()
findItem(R.id.menu_haptics).isChecked = BooleanSetting.HAPTIC_FEEDBACK.getBoolean()
findItem(R.id.menu_touchscreen).isChecked = BooleanSetting.TOUCHSCREEN.getBoolean()
}
popup.setOnMenuItemClickListener {
when (it.itemId) {
R.id.menu_toggle_fps -> {
it.isChecked = !it.isChecked
EmulationMenuSettings.showFps = it.isChecked
BooleanSetting.SHOW_PERFORMANCE_OVERLAY.setBoolean(it.isChecked)
updateShowFpsOverlay()
true
}
@@ -564,11 +576,12 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
}
R.id.menu_toggle_controls -> {
val preferences =
PreferenceManager.getDefaultSharedPreferences(YuzuApplication.appContext)
val optionsArray = BooleanArray(Settings.overlayPreferences.size)
Settings.overlayPreferences.forEachIndexed { i, _ ->
optionsArray[i] = preferences.getBoolean("buttonToggle$i", i < 15)
val overlayControlData = NativeConfig.getOverlayControlData()
val optionsArray = BooleanArray(overlayControlData.size)
overlayControlData.forEachIndexed { i, _ ->
optionsArray[i] = overlayControlData.firstOrNull { data ->
OverlayControl.entries[i].id == data.id
}?.enabled == true
}
val dialog = MaterialAlertDialogBuilder(requireContext())
@@ -577,11 +590,13 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
R.array.gamepadButtons,
optionsArray
) { _, indexSelected, isChecked ->
preferences.edit()
.putBoolean("buttonToggle$indexSelected", isChecked)
.apply()
overlayControlData.firstOrNull { data ->
OverlayControl.entries[indexSelected].id == data.id
}?.enabled = isChecked
}
.setPositiveButton(android.R.string.ok) { _, _ ->
NativeConfig.setOverlayControlData(overlayControlData)
NativeConfig.saveGlobalConfig()
binding.surfaceInputOverlay.refreshControls()
}
.setNegativeButton(android.R.string.cancel, null)
@@ -592,12 +607,10 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
dialog.getButton(AlertDialog.BUTTON_NEUTRAL)
.setOnClickListener {
val isChecked = !optionsArray[0]
Settings.overlayPreferences.forEachIndexed { i, _ ->
overlayControlData.forEachIndexed { i, _ ->
optionsArray[i] = isChecked
dialog.listView.setItemChecked(i, isChecked)
preferences.edit()
.putBoolean("buttonToggle$i", isChecked)
.apply()
overlayControlData[i].enabled = isChecked
}
}
true
@@ -605,26 +618,32 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
R.id.menu_show_overlay -> {
it.isChecked = !it.isChecked
EmulationMenuSettings.showOverlay = it.isChecked
BooleanSetting.SHOW_INPUT_OVERLAY.setBoolean(it.isChecked)
binding.surfaceInputOverlay.refreshControls()
true
}
R.id.menu_rel_stick_center -> {
it.isChecked = !it.isChecked
EmulationMenuSettings.joystickRelCenter = it.isChecked
BooleanSetting.JOYSTICK_REL_CENTER.setBoolean(it.isChecked)
true
}
R.id.menu_dpad_slide -> {
it.isChecked = !it.isChecked
EmulationMenuSettings.dpadSlide = it.isChecked
BooleanSetting.DPAD_SLIDE.setBoolean(it.isChecked)
true
}
R.id.menu_haptics -> {
it.isChecked = !it.isChecked
EmulationMenuSettings.hapticFeedback = it.isChecked
BooleanSetting.HAPTIC_FEEDBACK.setBoolean(it.isChecked)
true
}
R.id.menu_touchscreen -> {
it.isChecked = !it.isChecked
BooleanSetting.TOUCHSCREEN.setBoolean(it.isChecked)
true
}
@@ -644,7 +663,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
@SuppressLint("SourceLockedOrientationActivity")
private fun startConfiguringControls() {
// Lock the current orientation to prevent editing inconsistencies
if (IntSetting.RENDERER_SCREEN_LAYOUT.getInt() == Settings.LayoutOption_Unspecified) {
if (IntSetting.RENDERER_SCREEN_LAYOUT.getInt() == EmulationOrientation.Unspecified.int) {
emulationActivity?.let {
it.requestedOrientation =
if (resources.configuration.orientation == Configuration.ORIENTATION_PORTRAIT) {
@@ -662,11 +681,12 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
binding.doneControlConfig.visibility = View.GONE
binding.surfaceInputOverlay.setIsInEditMode(false)
// Unlock the orientation if it was locked for editing
if (IntSetting.RENDERER_SCREEN_LAYOUT.getInt() == Settings.LayoutOption_Unspecified) {
if (IntSetting.RENDERER_SCREEN_LAYOUT.getInt() == EmulationOrientation.Unspecified.int) {
emulationActivity?.let {
it.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED
}
}
NativeConfig.saveGlobalConfig()
}
@SuppressLint("SetTextI18n")
@@ -675,7 +695,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
adjustBinding.apply {
inputScaleSlider.apply {
valueTo = 150F
value = preferences.getInt(Settings.PREF_CONTROL_SCALE, 50).toFloat()
value = IntSetting.OVERLAY_SCALE.getInt().toFloat()
addOnChangeListener(
Slider.OnChangeListener { _, value, _ ->
inputScaleValue.text = "${value.toInt()}%"
@@ -685,7 +705,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
}
inputOpacitySlider.apply {
valueTo = 100F
value = preferences.getInt(Settings.PREF_CONTROL_OPACITY, 100).toFloat()
value = IntSetting.OVERLAY_OPACITY.getInt().toFloat()
addOnChangeListener(
Slider.OnChangeListener { _, value, _ ->
inputOpacityValue.text = "${value.toInt()}%"
@@ -709,16 +729,12 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
}
private fun setControlScale(scale: Int) {
preferences.edit()
.putInt(Settings.PREF_CONTROL_SCALE, scale)
.apply()
IntSetting.OVERLAY_SCALE.setInt(scale)
binding.surfaceInputOverlay.refreshControls()
}
private fun setControlOpacity(opacity: Int) {
preferences.edit()
.putInt(Settings.PREF_CONTROL_OPACITY, opacity)
.apply()
IntSetting.OVERLAY_OPACITY.setInt(opacity)
binding.surfaceInputOverlay.refreshControls()
}
@@ -445,7 +445,8 @@ class GamePropertiesFragment : Fragment() {
val zipResult = FileUtil.zipFromInternalStorage(
File(saveLocation),
saveLocation.replaceAfterLast("/", ""),
BufferedOutputStream(requireContext().contentResolver.openOutputStream(result))
BufferedOutputStream(requireContext().contentResolver.openOutputStream(result)),
compression = false
)
return@newInstance when (zipResult) {
TaskState.Completed -> getString(R.string.export_success)
@@ -167,13 +167,14 @@ class GamesViewModel : ViewModel() {
}
}
fun onCloseGameFoldersFragment() =
fun onCloseGameFoldersFragment() {
NativeConfig.saveGlobalConfig()
viewModelScope.launch {
withContext(Dispatchers.IO) {
NativeConfig.saveGlobalConfig()
getGameDirs(true)
}
}
}
private fun getGameDirs(reloadList: Boolean = false) {
val gameDirs = NativeConfig.getGameDirs()
File diff suppressed because it is too large Load Diff
@@ -10,6 +10,7 @@ import android.graphics.Rect
import android.graphics.drawable.BitmapDrawable
import android.view.MotionEvent
import org.yuzu.yuzu_emu.NativeLibrary.ButtonState
import org.yuzu.yuzu_emu.overlay.model.OverlayControlData
/**
* Custom [BitmapDrawable] that is capable
@@ -25,7 +26,7 @@ class InputOverlayDrawableButton(
defaultStateBitmap: Bitmap,
pressedStateBitmap: Bitmap,
val buttonId: Int,
val prefId: String
val overlayControlData: OverlayControlData
) {
// The ID value what motion event is tracking
var trackId: Int
@@ -14,7 +14,7 @@ import kotlin.math.cos
import kotlin.math.sin
import kotlin.math.sqrt
import org.yuzu.yuzu_emu.NativeLibrary
import org.yuzu.yuzu_emu.utils.EmulationMenuSettings
import org.yuzu.yuzu_emu.features.settings.model.BooleanSetting
/**
* Custom [BitmapDrawable] that is capable
@@ -125,7 +125,7 @@ class InputOverlayDrawableJoystick(
pressedState = true
outerBitmap.alpha = 0
boundsBoxBitmap.alpha = opacity
if (EmulationMenuSettings.joystickRelCenter) {
if (BooleanSetting.JOYSTICK_REL_CENTER.getBoolean()) {
virtBounds.offset(
xPosition - virtBounds.centerX(),
yPosition - virtBounds.centerY()
@@ -0,0 +1,188 @@
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
package org.yuzu.yuzu_emu.overlay.model
import androidx.annotation.IntegerRes
import org.yuzu.yuzu_emu.R
import org.yuzu.yuzu_emu.YuzuApplication
enum class OverlayControl(
val id: String,
val defaultVisibility: Boolean,
@IntegerRes val defaultLandscapePositionResources: Pair<Int, Int>,
@IntegerRes val defaultPortraitPositionResources: Pair<Int, Int>,
@IntegerRes val defaultFoldablePositionResources: Pair<Int, Int>
) {
BUTTON_A(
"button_a",
true,
Pair(R.integer.BUTTON_A_X, R.integer.BUTTON_A_Y),
Pair(R.integer.BUTTON_A_X_PORTRAIT, R.integer.BUTTON_A_Y_PORTRAIT),
Pair(R.integer.BUTTON_A_X_FOLDABLE, R.integer.BUTTON_A_Y_FOLDABLE)
),
BUTTON_B(
"button_b",
true,
Pair(R.integer.BUTTON_B_X, R.integer.BUTTON_B_Y),
Pair(R.integer.BUTTON_B_X_PORTRAIT, R.integer.BUTTON_B_Y_PORTRAIT),
Pair(R.integer.BUTTON_B_X_FOLDABLE, R.integer.BUTTON_B_Y_FOLDABLE)
),
BUTTON_X(
"button_x",
true,
Pair(R.integer.BUTTON_X_X, R.integer.BUTTON_X_Y),
Pair(R.integer.BUTTON_X_X_PORTRAIT, R.integer.BUTTON_X_Y_PORTRAIT),
Pair(R.integer.BUTTON_X_X_FOLDABLE, R.integer.BUTTON_X_Y_FOLDABLE)
),
BUTTON_Y(
"button_y",
true,
Pair(R.integer.BUTTON_Y_X, R.integer.BUTTON_Y_Y),
Pair(R.integer.BUTTON_Y_X_PORTRAIT, R.integer.BUTTON_Y_Y_PORTRAIT),
Pair(R.integer.BUTTON_Y_X_FOLDABLE, R.integer.BUTTON_Y_Y_FOLDABLE)
),
BUTTON_PLUS(
"button_plus",
true,
Pair(R.integer.BUTTON_PLUS_X, R.integer.BUTTON_PLUS_Y),
Pair(R.integer.BUTTON_PLUS_X_PORTRAIT, R.integer.BUTTON_PLUS_Y_PORTRAIT),
Pair(R.integer.BUTTON_PLUS_X_FOLDABLE, R.integer.BUTTON_PLUS_Y_FOLDABLE)
),
BUTTON_MINUS(
"button_minus",
true,
Pair(R.integer.BUTTON_MINUS_X, R.integer.BUTTON_MINUS_Y),
Pair(R.integer.BUTTON_MINUS_X_PORTRAIT, R.integer.BUTTON_MINUS_Y_PORTRAIT),
Pair(R.integer.BUTTON_MINUS_X_FOLDABLE, R.integer.BUTTON_MINUS_Y_FOLDABLE)
),
BUTTON_HOME(
"button_home",
false,
Pair(R.integer.BUTTON_HOME_X, R.integer.BUTTON_HOME_Y),
Pair(R.integer.BUTTON_HOME_X_PORTRAIT, R.integer.BUTTON_HOME_Y_PORTRAIT),
Pair(R.integer.BUTTON_HOME_X_FOLDABLE, R.integer.BUTTON_HOME_Y_FOLDABLE)
),
BUTTON_CAPTURE(
"button_capture",
false,
Pair(R.integer.BUTTON_CAPTURE_X, R.integer.BUTTON_CAPTURE_Y),
Pair(R.integer.BUTTON_CAPTURE_X_PORTRAIT, R.integer.BUTTON_CAPTURE_Y_PORTRAIT),
Pair(R.integer.BUTTON_CAPTURE_X_FOLDABLE, R.integer.BUTTON_CAPTURE_Y_FOLDABLE)
),
BUTTON_L(
"button_l",
true,
Pair(R.integer.BUTTON_L_X, R.integer.BUTTON_L_Y),
Pair(R.integer.BUTTON_L_X_PORTRAIT, R.integer.BUTTON_L_Y_PORTRAIT),
Pair(R.integer.BUTTON_L_X_FOLDABLE, R.integer.BUTTON_L_Y_FOLDABLE)
),
BUTTON_R(
"button_r",
true,
Pair(R.integer.BUTTON_R_X, R.integer.BUTTON_R_Y),
Pair(R.integer.BUTTON_R_X_PORTRAIT, R.integer.BUTTON_R_Y_PORTRAIT),
Pair(R.integer.BUTTON_R_X_FOLDABLE, R.integer.BUTTON_R_Y_FOLDABLE)
),
BUTTON_ZL(
"button_zl",
true,
Pair(R.integer.BUTTON_ZL_X, R.integer.BUTTON_ZL_Y),
Pair(R.integer.BUTTON_ZL_X_PORTRAIT, R.integer.BUTTON_ZL_Y_PORTRAIT),
Pair(R.integer.BUTTON_ZL_X_FOLDABLE, R.integer.BUTTON_ZL_Y_FOLDABLE)
),
BUTTON_ZR(
"button_zr",
true,
Pair(R.integer.BUTTON_ZR_X, R.integer.BUTTON_ZR_Y),
Pair(R.integer.BUTTON_ZR_X_PORTRAIT, R.integer.BUTTON_ZR_Y_PORTRAIT),
Pair(R.integer.BUTTON_ZR_X_FOLDABLE, R.integer.BUTTON_ZR_Y_FOLDABLE)
),
BUTTON_STICK_L(
"button_stick_l",
true,
Pair(R.integer.BUTTON_STICK_L_X, R.integer.BUTTON_STICK_L_Y),
Pair(R.integer.BUTTON_STICK_L_X_PORTRAIT, R.integer.BUTTON_STICK_L_Y_PORTRAIT),
Pair(R.integer.BUTTON_STICK_L_X_FOLDABLE, R.integer.BUTTON_STICK_L_Y_FOLDABLE)
),
BUTTON_STICK_R(
"button_stick_r",
true,
Pair(R.integer.BUTTON_STICK_R_X, R.integer.BUTTON_STICK_R_Y),
Pair(R.integer.BUTTON_STICK_R_X_PORTRAIT, R.integer.BUTTON_STICK_R_Y_PORTRAIT),
Pair(R.integer.BUTTON_STICK_R_X_FOLDABLE, R.integer.BUTTON_STICK_R_Y_FOLDABLE)
),
STICK_L(
"stick_l",
true,
Pair(R.integer.STICK_L_X, R.integer.STICK_L_Y),
Pair(R.integer.STICK_L_X_PORTRAIT, R.integer.STICK_L_Y_PORTRAIT),
Pair(R.integer.STICK_L_X_FOLDABLE, R.integer.STICK_L_Y_FOLDABLE)
),
STICK_R(
"stick_r",
true,
Pair(R.integer.STICK_R_X, R.integer.STICK_R_Y),
Pair(R.integer.STICK_R_X_PORTRAIT, R.integer.STICK_R_Y_PORTRAIT),
Pair(R.integer.STICK_R_X_FOLDABLE, R.integer.STICK_R_Y_FOLDABLE)
),
COMBINED_DPAD(
"combined_dpad",
true,
Pair(R.integer.COMBINED_DPAD_X, R.integer.COMBINED_DPAD_Y),
Pair(R.integer.COMBINED_DPAD_X_PORTRAIT, R.integer.COMBINED_DPAD_Y_PORTRAIT),
Pair(R.integer.COMBINED_DPAD_X_FOLDABLE, R.integer.COMBINED_DPAD_Y_FOLDABLE)
);
fun getDefaultPositionForLayout(layout: OverlayLayout): Pair<Double, Double> {
val rawResourcePair: Pair<Int, Int>
YuzuApplication.appContext.resources.apply {
rawResourcePair = when (layout) {
OverlayLayout.Landscape -> {
Pair(
getInteger(this@OverlayControl.defaultLandscapePositionResources.first),
getInteger(this@OverlayControl.defaultLandscapePositionResources.second)
)
}
OverlayLayout.Portrait -> {
Pair(
getInteger(this@OverlayControl.defaultPortraitPositionResources.first),
getInteger(this@OverlayControl.defaultPortraitPositionResources.second)
)
}
OverlayLayout.Foldable -> {
Pair(
getInteger(this@OverlayControl.defaultFoldablePositionResources.first),
getInteger(this@OverlayControl.defaultFoldablePositionResources.second)
)
}
}
}
return Pair(
rawResourcePair.first.toDouble() / 1000,
rawResourcePair.second.toDouble() / 1000
)
}
fun toOverlayControlData(): OverlayControlData =
OverlayControlData(
id,
defaultVisibility,
getDefaultPositionForLayout(OverlayLayout.Landscape),
getDefaultPositionForLayout(OverlayLayout.Portrait),
getDefaultPositionForLayout(OverlayLayout.Foldable)
)
companion object {
val map: HashMap<String, OverlayControl> by lazy {
val hashMap = hashMapOf<String, OverlayControl>()
entries.forEach { hashMap[it.id] = it }
hashMap
}
fun from(id: String): OverlayControl? = map[id]
}
}
@@ -0,0 +1,19 @@
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
package org.yuzu.yuzu_emu.overlay.model
data class OverlayControlData(
val id: String,
var enabled: Boolean,
var landscapePosition: Pair<Double, Double>,
var portraitPosition: Pair<Double, Double>,
var foldablePosition: Pair<Double, Double>
) {
fun positionFromLayout(layout: OverlayLayout): Pair<Double, Double> =
when (layout) {
OverlayLayout.Landscape -> landscapePosition
OverlayLayout.Portrait -> portraitPosition
OverlayLayout.Foldable -> foldablePosition
}
}
@@ -0,0 +1,13 @@
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
package org.yuzu.yuzu_emu.overlay.model
import androidx.annotation.IntegerRes
data class OverlayControlDefault(
val buttonId: String,
@IntegerRes val landscapePositionResource: Pair<Int, Int>,
@IntegerRes val portraitPositionResource: Pair<Int, Int>,
@IntegerRes val foldablePositionResource: Pair<Int, Int>
)
@@ -0,0 +1,10 @@
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
package org.yuzu.yuzu_emu.overlay.model
enum class OverlayLayout(val id: String) {
Landscape("Landscape"),
Portrait("Portrait"),
Foldable("Foldable")
}
@@ -625,7 +625,8 @@ class MainActivity : AppCompatActivity(), ThemeProvider {
File(DirectoryInitialization.userDirectory!!),
DirectoryInitialization.userDirectory!!,
BufferedOutputStream(contentResolver.openOutputStream(result)),
taskViewModel.cancelled
taskViewModel.cancelled,
compression = false
)
return@newInstance when (zipResult) {
TaskState.Completed -> getString(R.string.user_data_export_success)
@@ -3,9 +3,17 @@
package org.yuzu.yuzu_emu.utils
import androidx.preference.PreferenceManager
import java.io.IOException
import org.yuzu.yuzu_emu.NativeLibrary
import org.yuzu.yuzu_emu.YuzuApplication
import org.yuzu.yuzu_emu.features.settings.model.BooleanSetting
import org.yuzu.yuzu_emu.features.settings.model.IntSetting
import org.yuzu.yuzu_emu.features.settings.model.Settings
import org.yuzu.yuzu_emu.overlay.model.OverlayControlData
import org.yuzu.yuzu_emu.overlay.model.OverlayControl
import org.yuzu.yuzu_emu.overlay.model.OverlayLayout
import org.yuzu.yuzu_emu.utils.PreferenceUtil.migratePreference
object DirectoryInitialization {
private var userPath: String? = null
@@ -17,6 +25,7 @@ object DirectoryInitialization {
initializeInternalStorage()
NativeLibrary.initializeSystem(false)
NativeConfig.initializeGlobalConfig()
migrateSettings()
areDirectoriesReady = true
}
}
@@ -35,4 +44,170 @@ object DirectoryInitialization {
e.printStackTrace()
}
}
private fun migrateSettings() {
val preferences = PreferenceManager.getDefaultSharedPreferences(YuzuApplication.appContext)
var saveConfig = false
val theme = preferences.migratePreference<Int>(Settings.PREF_THEME)
if (theme != null) {
IntSetting.THEME.setInt(theme)
saveConfig = true
}
val themeMode = preferences.migratePreference<Int>(Settings.PREF_THEME_MODE)
if (themeMode != null) {
IntSetting.THEME_MODE.setInt(themeMode)
saveConfig = true
}
val blackBackgrounds =
preferences.migratePreference<Boolean>(Settings.PREF_BLACK_BACKGROUNDS)
if (blackBackgrounds != null) {
BooleanSetting.BLACK_BACKGROUNDS.setBoolean(blackBackgrounds)
saveConfig = true
}
val joystickRelCenter =
preferences.migratePreference<Boolean>(Settings.PREF_MENU_SETTINGS_JOYSTICK_REL_CENTER)
if (joystickRelCenter != null) {
BooleanSetting.JOYSTICK_REL_CENTER.setBoolean(joystickRelCenter)
saveConfig = true
}
val dpadSlide =
preferences.migratePreference<Boolean>(Settings.PREF_MENU_SETTINGS_DPAD_SLIDE)
if (dpadSlide != null) {
BooleanSetting.DPAD_SLIDE.setBoolean(dpadSlide)
saveConfig = true
}
val hapticFeedback =
preferences.migratePreference<Boolean>(Settings.PREF_MENU_SETTINGS_HAPTICS)
if (hapticFeedback != null) {
BooleanSetting.HAPTIC_FEEDBACK.setBoolean(hapticFeedback)
saveConfig = true
}
val showPerformanceOverlay =
preferences.migratePreference<Boolean>(Settings.PREF_MENU_SETTINGS_SHOW_FPS)
if (showPerformanceOverlay != null) {
BooleanSetting.SHOW_PERFORMANCE_OVERLAY.setBoolean(showPerformanceOverlay)
saveConfig = true
}
val showInputOverlay =
preferences.migratePreference<Boolean>(Settings.PREF_MENU_SETTINGS_SHOW_OVERLAY)
if (showInputOverlay != null) {
BooleanSetting.SHOW_INPUT_OVERLAY.setBoolean(showInputOverlay)
saveConfig = true
}
val overlayOpacity = preferences.migratePreference<Int>(Settings.PREF_CONTROL_OPACITY)
if (overlayOpacity != null) {
IntSetting.OVERLAY_OPACITY.setInt(overlayOpacity)
saveConfig = true
}
val overlayScale = preferences.migratePreference<Int>(Settings.PREF_CONTROL_SCALE)
if (overlayScale != null) {
IntSetting.OVERLAY_SCALE.setInt(overlayScale)
saveConfig = true
}
var setOverlayData = false
val overlayControlData = NativeConfig.getOverlayControlData()
if (overlayControlData.isEmpty()) {
val overlayControlDataMap =
NativeConfig.getOverlayControlData().associateBy { it.id }.toMutableMap()
for (button in Settings.overlayPreferences) {
val buttonId = convertButtonId(button)
var buttonEnabled = preferences.migratePreference<Boolean>(button)
if (buttonEnabled == null) {
buttonEnabled = OverlayControl.map[buttonId]?.defaultVisibility == true
}
var landscapeXPosition = preferences.migratePreference<Float>(
"$button-X${Settings.PREF_LANDSCAPE_SUFFIX}"
)?.toDouble()
var landscapeYPosition = preferences.migratePreference<Float>(
"$button-Y${Settings.PREF_LANDSCAPE_SUFFIX}"
)?.toDouble()
if (landscapeXPosition == null || landscapeYPosition == null) {
val landscapePosition = OverlayControl.map[buttonId]
?.getDefaultPositionForLayout(OverlayLayout.Landscape) ?: Pair(0.0, 0.0)
landscapeXPosition = landscapePosition.first
landscapeYPosition = landscapePosition.second
}
var portraitXPosition = preferences.migratePreference<Float>(
"$button-X${Settings.PREF_PORTRAIT_SUFFIX}"
)?.toDouble()
var portraitYPosition = preferences.migratePreference<Float>(
"$button-Y${Settings.PREF_PORTRAIT_SUFFIX}"
)?.toDouble()
if (portraitXPosition == null || portraitYPosition == null) {
val portraitPosition = OverlayControl.map[buttonId]
?.getDefaultPositionForLayout(OverlayLayout.Portrait) ?: Pair(0.0, 0.0)
portraitXPosition = portraitPosition.first
portraitYPosition = portraitPosition.second
}
var foldableXPosition = preferences.migratePreference<Float>(
"$button-X${Settings.PREF_FOLDABLE_SUFFIX}"
)?.toDouble()
var foldableYPosition = preferences.migratePreference<Float>(
"$button-Y${Settings.PREF_FOLDABLE_SUFFIX}"
)?.toDouble()
if (foldableXPosition == null || foldableYPosition == null) {
val foldablePosition = OverlayControl.map[buttonId]
?.getDefaultPositionForLayout(OverlayLayout.Foldable) ?: Pair(0.0, 0.0)
foldableXPosition = foldablePosition.first
foldableYPosition = foldablePosition.second
}
val controlData = OverlayControlData(
buttonId,
buttonEnabled,
Pair(landscapeXPosition, landscapeYPosition),
Pair(portraitXPosition, portraitYPosition),
Pair(foldableXPosition, foldableYPosition)
)
overlayControlDataMap[buttonId] = controlData
setOverlayData = true
}
if (setOverlayData) {
NativeConfig.setOverlayControlData(
overlayControlDataMap.map { it.value }.toTypedArray()
)
saveConfig = true
}
}
if (saveConfig) {
NativeConfig.saveGlobalConfig()
}
}
private fun convertButtonId(buttonId: String): String =
when (buttonId) {
Settings.PREF_BUTTON_A -> OverlayControl.BUTTON_A.id
Settings.PREF_BUTTON_B -> OverlayControl.BUTTON_B.id
Settings.PREF_BUTTON_X -> OverlayControl.BUTTON_X.id
Settings.PREF_BUTTON_Y -> OverlayControl.BUTTON_Y.id
Settings.PREF_BUTTON_L -> OverlayControl.BUTTON_L.id
Settings.PREF_BUTTON_R -> OverlayControl.BUTTON_R.id
Settings.PREF_BUTTON_ZL -> OverlayControl.BUTTON_ZL.id
Settings.PREF_BUTTON_ZR -> OverlayControl.BUTTON_ZR.id
Settings.PREF_BUTTON_PLUS -> OverlayControl.BUTTON_PLUS.id
Settings.PREF_BUTTON_MINUS -> OverlayControl.BUTTON_MINUS.id
Settings.PREF_BUTTON_DPAD -> OverlayControl.COMBINED_DPAD.id
Settings.PREF_STICK_L -> OverlayControl.STICK_L.id
Settings.PREF_STICK_R -> OverlayControl.STICK_R.id
Settings.PREF_BUTTON_HOME -> OverlayControl.BUTTON_HOME.id
Settings.PREF_BUTTON_SCREENSHOT -> OverlayControl.BUTTON_CAPTURE.id
Settings.PREF_BUTTON_STICK_L -> OverlayControl.BUTTON_STICK_L.id
Settings.PREF_BUTTON_STICK_R -> OverlayControl.BUTTON_STICK_R.id
else -> ""
}
}
@@ -1,50 +0,0 @@
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
package org.yuzu.yuzu_emu.utils
import androidx.preference.PreferenceManager
import org.yuzu.yuzu_emu.YuzuApplication
import org.yuzu.yuzu_emu.features.settings.model.Settings
object EmulationMenuSettings {
private val preferences =
PreferenceManager.getDefaultSharedPreferences(YuzuApplication.appContext)
var joystickRelCenter: Boolean
get() = preferences.getBoolean(Settings.PREF_MENU_SETTINGS_JOYSTICK_REL_CENTER, true)
set(value) {
preferences.edit()
.putBoolean(Settings.PREF_MENU_SETTINGS_JOYSTICK_REL_CENTER, value)
.apply()
}
var dpadSlide: Boolean
get() = preferences.getBoolean(Settings.PREF_MENU_SETTINGS_DPAD_SLIDE, true)
set(value) {
preferences.edit()
.putBoolean(Settings.PREF_MENU_SETTINGS_DPAD_SLIDE, value)
.apply()
}
var hapticFeedback: Boolean
get() = preferences.getBoolean(Settings.PREF_MENU_SETTINGS_HAPTICS, false)
set(value) {
preferences.edit()
.putBoolean(Settings.PREF_MENU_SETTINGS_HAPTICS, value)
.apply()
}
var showFps: Boolean
get() = preferences.getBoolean(Settings.PREF_MENU_SETTINGS_SHOW_FPS, false)
set(value) {
preferences.edit()
.putBoolean(Settings.PREF_MENU_SETTINGS_SHOW_FPS, value)
.apply()
}
var showOverlay: Boolean
get() = preferences.getBoolean(Settings.PREF_MENU_SETTINGS_SHOW_OVERLAY, true)
set(value) {
preferences.edit()
.putBoolean(Settings.PREF_MENU_SETTINGS_SHOW_OVERLAY, value)
.apply()
}
}
@@ -21,6 +21,7 @@ import org.yuzu.yuzu_emu.model.TaskState
import java.io.BufferedOutputStream
import java.lang.NullPointerException
import java.nio.charset.StandardCharsets
import java.util.zip.Deflater
import java.util.zip.ZipOutputStream
import kotlin.IllegalStateException
@@ -312,15 +313,23 @@ object FileUtil {
* @param inputFile File representation of the item that will be zipped
* @param rootDir Directory containing the inputFile
* @param outputStream Stream where the zip file will be output
* @param cancelled [StateFlow] that reports whether this process has been cancelled
* @param compression Disables compression if true
*/
fun zipFromInternalStorage(
inputFile: File,
rootDir: String,
outputStream: BufferedOutputStream,
cancelled: StateFlow<Boolean>? = null
cancelled: StateFlow<Boolean>? = null,
compression: Boolean = true
): TaskState {
try {
ZipOutputStream(outputStream).use { zos ->
if (!compression) {
zos.setMethod(ZipOutputStream.DEFLATED)
zos.setLevel(Deflater.NO_COMPRESSION)
}
inputFile.walkTopDown().forEach { file ->
if (cancelled?.value == true) {
return TaskState.Cancelled
@@ -338,6 +347,7 @@ object FileUtil {
}
}
} catch (e: Exception) {
Log.error("[FileUtil] Failed creating zip file - ${e.message}")
return TaskState.Failed
}
return TaskState.Completed
@@ -4,6 +4,7 @@
package org.yuzu.yuzu_emu.utils
import org.yuzu.yuzu_emu.model.GameDir
import org.yuzu.yuzu_emu.overlay.model.OverlayControlData
object NativeConfig {
/**
@@ -150,4 +151,21 @@ object NativeConfig {
*/
@Synchronized
external fun setDisabledAddons(programId: String, disabledAddons: Array<String>)
/**
* Gets an array of [OverlayControlData] from settings
*
* @return An array of [OverlayControlData]
*/
@Synchronized
external fun getOverlayControlData(): Array<OverlayControlData>
/**
* Clears the AndroidSettings::values.overlay_control_data array and replaces its values
* with [overlayControlData]
*
* @param overlayControlData Replacement array of [OverlayControlData]
*/
@Synchronized
external fun setOverlayControlData(overlayControlData: Array<OverlayControlData>)
}
@@ -0,0 +1,37 @@
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
package org.yuzu.yuzu_emu.utils
import android.content.SharedPreferences
object PreferenceUtil {
/**
* Retrieves a shared preference value and then deletes the value in storage.
* @param key Associated key for the value in this preferences instance
* @return Typed value associated with [key]. Null if no such key exists.
*/
inline fun <reified T> SharedPreferences.migratePreference(key: String): T? {
if (!this.contains(key)) {
return null
}
val value: Any = when (T::class) {
String::class -> this.getString(key, "")!!
Boolean::class -> this.getBoolean(key, false)
Int::class -> this.getInt(key, 0)
Float::class -> this.getFloat(key, 0f)
Long::class -> this.getLong(key, 0)
else -> throw IllegalStateException("Tried to migrate preference with invalid type!")
}
deletePreference(key)
return value as T
}
fun SharedPreferences.deletePreference(key: String) = this.edit().remove(key).apply()
}
@@ -5,38 +5,38 @@ package org.yuzu.yuzu_emu.utils
import android.content.res.Configuration
import android.graphics.Color
import android.os.Build
import androidx.annotation.ColorInt
import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.app.AppCompatDelegate
import androidx.core.view.WindowCompat
import androidx.core.view.WindowInsetsControllerCompat
import androidx.preference.PreferenceManager
import kotlin.math.roundToInt
import org.yuzu.yuzu_emu.R
import org.yuzu.yuzu_emu.YuzuApplication
import org.yuzu.yuzu_emu.features.settings.model.Settings
import org.yuzu.yuzu_emu.features.settings.model.BooleanSetting
import org.yuzu.yuzu_emu.features.settings.model.IntSetting
import org.yuzu.yuzu_emu.ui.main.ThemeProvider
object ThemeHelper {
const val SYSTEM_BAR_ALPHA = 0.9f
private const val DEFAULT = 0
private const val MATERIAL_YOU = 1
fun setTheme(activity: AppCompatActivity) {
val preferences = PreferenceManager.getDefaultSharedPreferences(YuzuApplication.appContext)
setThemeMode(activity)
when (preferences.getInt(Settings.PREF_THEME, 0)) {
DEFAULT -> activity.setTheme(R.style.Theme_Yuzu_Main)
MATERIAL_YOU -> activity.setTheme(R.style.Theme_Yuzu_Main_MaterialYou)
when (Theme.from(IntSetting.THEME.getInt())) {
Theme.Default -> activity.setTheme(R.style.Theme_Yuzu_Main)
Theme.MaterialYou -> {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
activity.setTheme(R.style.Theme_Yuzu_Main_MaterialYou)
} else {
activity.setTheme(R.style.Theme_Yuzu_Main)
}
}
}
// Using a specific night mode check because this could apply incorrectly when using the
// light app mode, dark system mode, and black backgrounds. Launching the settings activity
// will then show light mode colors/navigation bars but with black backgrounds.
if (preferences.getBoolean(Settings.PREF_BLACK_BACKGROUNDS, false) &&
isNightMode(activity)
) {
if (BooleanSetting.BLACK_BACKGROUNDS.getBoolean() && isNightMode(activity)) {
activity.setTheme(R.style.ThemeOverlay_Yuzu_Dark)
}
}
@@ -60,8 +60,7 @@ object ThemeHelper {
}
fun setThemeMode(activity: AppCompatActivity) {
val themeMode = PreferenceManager.getDefaultSharedPreferences(activity.applicationContext)
.getInt(Settings.PREF_THEME_MODE, AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM)
val themeMode = IntSetting.THEME_MODE.getInt()
activity.delegate.localNightMode = themeMode
val windowController = WindowCompat.getInsetsController(
activity.window,
@@ -95,3 +94,12 @@ object ThemeHelper {
windowController.isAppearanceLightNavigationBars = false
}
}
enum class Theme(val int: Int) {
Default(0),
MaterialYou(1);
companion object {
fun from(int: Int): Theme = entries.firstOrNull { it.int == int } ?: Default
}
}
@@ -9,6 +9,7 @@
#include <jni.h>
#include "common/string_util.h"
#include "jni/id_cache.h"
std::string GetJString(JNIEnv* env, jstring jstr) {
if (!jstr) {
@@ -33,3 +34,11 @@ jstring ToJString(JNIEnv* env, std::string_view str) {
jstring ToJString(JNIEnv* env, std::u16string_view str) {
return ToJString(env, Common::UTF16ToUTF8(str));
}
double GetJDouble(JNIEnv* env, jobject jdouble) {
return env->GetDoubleField(jdouble, IDCache::GetDoubleValueField());
}
jobject ToJDouble(JNIEnv* env, double value) {
return env->NewObject(IDCache::GetDoubleClass(), IDCache::GetDoubleConstructor(), value);
}
@@ -10,3 +10,6 @@
std::string GetJString(JNIEnv* env, jstring jstr);
jstring ToJString(JNIEnv* env, std::string_view str);
jstring ToJString(JNIEnv* env, std::u16string_view str);
double GetJDouble(JNIEnv* env, jobject jdouble);
jobject ToJDouble(JNIEnv* env, double value);
@@ -14,12 +14,6 @@ AndroidConfig::AndroidConfig(const std::string& config_name, ConfigType config_t
}
}
AndroidConfig::~AndroidConfig() {
if (global) {
AndroidConfig::SaveAllValues();
}
}
void AndroidConfig::ReloadAllValues() {
Reload();
ReadAndroidValues();
@@ -35,6 +29,7 @@ void AndroidConfig::ReadAndroidValues() {
if (global) {
ReadAndroidUIValues();
ReadUIValues();
ReadOverlayValues();
}
ReadDriverValues();
}
@@ -81,10 +76,42 @@ void AndroidConfig::ReadDriverValues() {
EndGroup();
}
void AndroidConfig::ReadOverlayValues() {
BeginGroup(Settings::TranslateCategory(Settings::Category::Overlay));
ReadCategory(Settings::Category::Overlay);
AndroidSettings::values.overlay_control_data.clear();
const int control_data_size = BeginArray("control_data");
for (int i = 0; i < control_data_size; ++i) {
SetArrayIndex(i);
AndroidSettings::OverlayControlData control_data;
control_data.id = ReadStringSetting(std::string("id"));
control_data.enabled = ReadBooleanSetting(std::string("enabled"));
control_data.landscape_position.first =
ReadDoubleSetting(std::string("landscape\\x_position"));
control_data.landscape_position.second =
ReadDoubleSetting(std::string("landscape\\y_position"));
control_data.portrait_position.first =
ReadDoubleSetting(std::string("portrait\\x_position"));
control_data.portrait_position.second =
ReadDoubleSetting(std::string("portrait\\y_position"));
control_data.foldable_position.first =
ReadDoubleSetting(std::string("foldable\\x_position"));
control_data.foldable_position.second =
ReadDoubleSetting(std::string("foldable\\y_position"));
AndroidSettings::values.overlay_control_data.push_back(control_data);
}
EndArray();
EndGroup();
}
void AndroidConfig::SaveAndroidValues() {
if (global) {
SaveAndroidUIValues();
SaveUIValues();
SaveOverlayValues();
}
SaveDriverValues();
@@ -114,8 +141,9 @@ void AndroidConfig::SavePathValues() {
for (size_t i = 0; i < AndroidSettings::values.game_dirs.size(); ++i) {
SetArrayIndex(i);
const auto& game_dir = AndroidSettings::values.game_dirs[i];
WriteSetting(std::string("path"), game_dir.path);
WriteSetting(std::string("deep_scan"), game_dir.deep_scan, std::make_optional(false));
WriteStringSetting(std::string("path"), game_dir.path);
WriteBooleanSetting(std::string("deep_scan"), game_dir.deep_scan,
std::make_optional(false));
}
EndArray();
@@ -130,6 +158,35 @@ void AndroidConfig::SaveDriverValues() {
EndGroup();
}
void AndroidConfig::SaveOverlayValues() {
BeginGroup(Settings::TranslateCategory(Settings::Category::Overlay));
WriteCategory(Settings::Category::Overlay);
BeginArray("control_data");
for (size_t i = 0; i < AndroidSettings::values.overlay_control_data.size(); ++i) {
SetArrayIndex(i);
const auto& control_data = AndroidSettings::values.overlay_control_data[i];
WriteStringSetting(std::string("id"), control_data.id);
WriteBooleanSetting(std::string("enabled"), control_data.enabled);
WriteDoubleSetting(std::string("landscape\\x_position"),
control_data.landscape_position.first);
WriteDoubleSetting(std::string("landscape\\y_position"),
control_data.landscape_position.second);
WriteDoubleSetting(std::string("portrait\\x_position"),
control_data.portrait_position.first);
WriteDoubleSetting(std::string("portrait\\y_position"),
control_data.portrait_position.second);
WriteDoubleSetting(std::string("foldable\\x_position"),
control_data.foldable_position.first);
WriteDoubleSetting(std::string("foldable\\y_position"),
control_data.foldable_position.second);
}
EndArray();
EndGroup();
}
std::vector<Settings::BasicSetting*>& AndroidConfig::FindRelevantList(Settings::Category category) {
auto& map = Settings::values.linkage.by_category;
if (map.contains(category)) {
@@ -9,7 +9,6 @@ class AndroidConfig final : public Config {
public:
explicit AndroidConfig(const std::string& config_name = "config",
ConfigType config_type = ConfigType::GlobalConfig);
~AndroidConfig() override;
void ReloadAllValues() override;
void SaveAllValues() override;
@@ -18,6 +17,7 @@ protected:
void ReadAndroidValues();
void ReadAndroidUIValues();
void ReadDriverValues();
void ReadOverlayValues();
void ReadHidbusValues() override {}
void ReadDebugControlValues() override {}
void ReadPathValues() override;
@@ -30,6 +30,7 @@ protected:
void SaveAndroidValues();
void SaveAndroidUIValues();
void SaveDriverValues();
void SaveOverlayValues();
void SaveHidbusValues() override {}
void SaveDebugControlValues() override {}
void SavePathValues() override;
@@ -14,6 +14,14 @@ struct GameDir {
bool deep_scan = false;
};
struct OverlayControlData {
std::string id;
bool enabled;
std::pair<double, double> landscape_position;
std::pair<double, double> portrait_position;
std::pair<double, double> foldable_position;
};
struct Values {
Settings::Linkage linkage;
@@ -33,6 +41,28 @@ struct Values {
Settings::SwitchableSetting<std::string, false> driver_path{linkage, "", "driver_path",
Settings::Category::GpuDriver};
Settings::Setting<s32> theme{linkage, 0, "theme", Settings::Category::Android};
Settings::Setting<s32> theme_mode{linkage, -1, "theme_mode", Settings::Category::Android};
Settings::Setting<bool> black_backgrounds{linkage, false, "black_backgrounds",
Settings::Category::Android};
// Input/performance overlay settings
std::vector<OverlayControlData> overlay_control_data;
Settings::Setting<s32> overlay_scale{linkage, 50, "control_scale", Settings::Category::Overlay};
Settings::Setting<s32> overlay_opacity{linkage, 100, "control_opacity",
Settings::Category::Overlay};
Settings::Setting<bool> joystick_rel_center{linkage, true, "joystick_rel_center",
Settings::Category::Overlay};
Settings::Setting<bool> dpad_slide{linkage, true, "dpad_slide", Settings::Category::Overlay};
Settings::Setting<bool> haptic_feedback{linkage, true, "haptic_feedback",
Settings::Category::Overlay};
Settings::Setting<bool> show_performance_overlay{linkage, true, "show_performance_overlay",
Settings::Category::Overlay};
Settings::Setting<bool> show_input_overlay{linkage, true, "show_input_overlay",
Settings::Category::Overlay};
Settings::Setting<bool> touchscreen{linkage, true, "touchscreen", Settings::Category::Overlay};
};
extern Values values;
+79
View File
@@ -35,6 +35,18 @@ static jmethodID s_pair_constructor;
static jfieldID s_pair_first_field;
static jfieldID s_pair_second_field;
static jclass s_overlay_control_data_class;
static jmethodID s_overlay_control_data_constructor;
static jfieldID s_overlay_control_data_id_field;
static jfieldID s_overlay_control_data_enabled_field;
static jfieldID s_overlay_control_data_landscape_position_field;
static jfieldID s_overlay_control_data_portrait_position_field;
static jfieldID s_overlay_control_data_foldable_position_field;
static jclass s_double_class;
static jmethodID s_double_constructor;
static jfieldID s_double_value_field;
static constexpr jint JNI_VERSION = JNI_VERSION_1_6;
namespace IDCache {
@@ -146,6 +158,46 @@ jfieldID GetPairSecondField() {
return s_pair_second_field;
}
jclass GetOverlayControlDataClass() {
return s_overlay_control_data_class;
}
jmethodID GetOverlayControlDataConstructor() {
return s_overlay_control_data_constructor;
}
jfieldID GetOverlayControlDataIdField() {
return s_overlay_control_data_id_field;
}
jfieldID GetOverlayControlDataEnabledField() {
return s_overlay_control_data_enabled_field;
}
jfieldID GetOverlayControlDataLandscapePositionField() {
return s_overlay_control_data_landscape_position_field;
}
jfieldID GetOverlayControlDataPortraitPositionField() {
return s_overlay_control_data_portrait_position_field;
}
jfieldID GetOverlayControlDataFoldablePositionField() {
return s_overlay_control_data_foldable_position_field;
}
jclass GetDoubleClass() {
return s_double_class;
}
jmethodID GetDoubleConstructor() {
return s_double_constructor;
}
jfieldID GetDoubleValueField() {
return s_double_value_field;
}
} // namespace IDCache
#ifdef __cplusplus
@@ -207,6 +259,31 @@ jint JNI_OnLoad(JavaVM* vm, void* reserved) {
s_pair_second_field = env->GetFieldID(pair_class, "second", "Ljava/lang/Object;");
env->DeleteLocalRef(pair_class);
const jclass overlay_control_data_class =
env->FindClass("org/yuzu/yuzu_emu/overlay/model/OverlayControlData");
s_overlay_control_data_class =
reinterpret_cast<jclass>(env->NewGlobalRef(overlay_control_data_class));
s_overlay_control_data_constructor =
env->GetMethodID(overlay_control_data_class, "<init>",
"(Ljava/lang/String;ZLkotlin/Pair;Lkotlin/Pair;Lkotlin/Pair;)V");
s_overlay_control_data_id_field =
env->GetFieldID(overlay_control_data_class, "id", "Ljava/lang/String;");
s_overlay_control_data_enabled_field =
env->GetFieldID(overlay_control_data_class, "enabled", "Z");
s_overlay_control_data_landscape_position_field =
env->GetFieldID(overlay_control_data_class, "landscapePosition", "Lkotlin/Pair;");
s_overlay_control_data_portrait_position_field =
env->GetFieldID(overlay_control_data_class, "portraitPosition", "Lkotlin/Pair;");
s_overlay_control_data_foldable_position_field =
env->GetFieldID(overlay_control_data_class, "foldablePosition", "Lkotlin/Pair;");
env->DeleteLocalRef(overlay_control_data_class);
const jclass double_class = env->FindClass("java/lang/Double");
s_double_class = reinterpret_cast<jclass>(env->NewGlobalRef(double_class));
s_double_constructor = env->GetMethodID(double_class, "<init>", "(D)V");
s_double_value_field = env->GetFieldID(double_class, "value", "D");
env->DeleteLocalRef(double_class);
// Initialize Android Storage
Common::FS::Android::RegisterCallbacks(env, s_native_library_class);
@@ -231,6 +308,8 @@ void JNI_OnUnload(JavaVM* vm, void* reserved) {
env->DeleteGlobalRef(s_game_class);
env->DeleteGlobalRef(s_string_class);
env->DeleteGlobalRef(s_pair_class);
env->DeleteGlobalRef(s_overlay_control_data_class);
env->DeleteGlobalRef(s_double_class);
// UnInitialize applets
SoftwareKeyboard::CleanupJNI(env);
+12
View File
@@ -35,4 +35,16 @@ jmethodID GetPairConstructor();
jfieldID GetPairFirstField();
jfieldID GetPairSecondField();
jclass GetOverlayControlDataClass();
jmethodID GetOverlayControlDataConstructor();
jfieldID GetOverlayControlDataIdField();
jfieldID GetOverlayControlDataEnabledField();
jfieldID GetOverlayControlDataLandscapePositionField();
jfieldID GetOverlayControlDataPortraitPositionField();
jfieldID GetOverlayControlDataFoldablePositionField();
jclass GetDoubleClass();
jmethodID GetDoubleConstructor();
jfieldID GetDoubleValueField();
} // namespace IDCache
+3 -3
View File
@@ -45,15 +45,15 @@
#include "core/frontend/applets/profile_select.h"
#include "core/frontend/applets/software_keyboard.h"
#include "core/frontend/applets/web_browser.h"
#include "core/hid/emulated_controller.h"
#include "core/hid/hid_core.h"
#include "core/hid/hid_types.h"
#include "core/hle/service/am/applet_ae.h"
#include "core/hle/service/am/applet_oe.h"
#include "core/hle/service/am/applets/applets.h"
#include "core/hle/service/filesystem/filesystem.h"
#include "core/loader/loader.h"
#include "frontend_common/config.h"
#include "hid_core/frontend/emulated_controller.h"
#include "hid_core/hid_core.h"
#include "hid_core/hid_types.h"
#include "jni/android_common/android_common.h"
#include "jni/id_cache.h"
#include "jni/native.h"
@@ -344,4 +344,74 @@ void Java_org_yuzu_yuzu_1emu_utils_NativeConfig_setDisabledAddons(JNIEnv* env, j
Settings::values.disabled_addons[program_id] = disabled_addons;
}
jobjectArray Java_org_yuzu_yuzu_1emu_utils_NativeConfig_getOverlayControlData(JNIEnv* env,
jobject obj) {
jobjectArray joverlayControlDataArray =
env->NewObjectArray(AndroidSettings::values.overlay_control_data.size(),
IDCache::GetOverlayControlDataClass(), nullptr);
for (size_t i = 0; i < AndroidSettings::values.overlay_control_data.size(); ++i) {
const auto& control_data = AndroidSettings::values.overlay_control_data[i];
jobject jlandscapePosition =
env->NewObject(IDCache::GetPairClass(), IDCache::GetPairConstructor(),
ToJDouble(env, control_data.landscape_position.first),
ToJDouble(env, control_data.landscape_position.second));
jobject jportraitPosition =
env->NewObject(IDCache::GetPairClass(), IDCache::GetPairConstructor(),
ToJDouble(env, control_data.portrait_position.first),
ToJDouble(env, control_data.portrait_position.second));
jobject jfoldablePosition =
env->NewObject(IDCache::GetPairClass(), IDCache::GetPairConstructor(),
ToJDouble(env, control_data.foldable_position.first),
ToJDouble(env, control_data.foldable_position.second));
jobject jcontrolData = env->NewObject(
IDCache::GetOverlayControlDataClass(), IDCache::GetOverlayControlDataConstructor(),
ToJString(env, control_data.id), control_data.enabled, jlandscapePosition,
jportraitPosition, jfoldablePosition);
env->SetObjectArrayElement(joverlayControlDataArray, i, jcontrolData);
}
return joverlayControlDataArray;
}
void Java_org_yuzu_yuzu_1emu_utils_NativeConfig_setOverlayControlData(
JNIEnv* env, jobject obj, jobjectArray joverlayControlDataArray) {
AndroidSettings::values.overlay_control_data.clear();
int size = env->GetArrayLength(joverlayControlDataArray);
if (size == 0) {
return;
}
for (int i = 0; i < size; ++i) {
jobject joverlayControlData = env->GetObjectArrayElement(joverlayControlDataArray, i);
jstring jidString = static_cast<jstring>(
env->GetObjectField(joverlayControlData, IDCache::GetOverlayControlDataIdField()));
bool enabled = static_cast<bool>(env->GetBooleanField(
joverlayControlData, IDCache::GetOverlayControlDataEnabledField()));
jobject jlandscapePosition = env->GetObjectField(
joverlayControlData, IDCache::GetOverlayControlDataLandscapePositionField());
std::pair<double, double> landscape_position = std::make_pair(
GetJDouble(env, env->GetObjectField(jlandscapePosition, IDCache::GetPairFirstField())),
GetJDouble(env,
env->GetObjectField(jlandscapePosition, IDCache::GetPairSecondField())));
jobject jportraitPosition = env->GetObjectField(
joverlayControlData, IDCache::GetOverlayControlDataPortraitPositionField());
std::pair<double, double> portrait_position = std::make_pair(
GetJDouble(env, env->GetObjectField(jportraitPosition, IDCache::GetPairFirstField())),
GetJDouble(env, env->GetObjectField(jportraitPosition, IDCache::GetPairSecondField())));
jobject jfoldablePosition = env->GetObjectField(
joverlayControlData, IDCache::GetOverlayControlDataFoldablePositionField());
std::pair<double, double> foldable_position = std::make_pair(
GetJDouble(env, env->GetObjectField(jfoldablePosition, IDCache::GetPairFirstField())),
GetJDouble(env, env->GetObjectField(jfoldablePosition, IDCache::GetPairSecondField())));
AndroidSettings::values.overlay_control_data.push_back(AndroidSettings::OverlayControlData{
GetJString(env, jidString), enabled, landscape_position, portrait_position,
foldable_position});
}
}
} // extern "C"
@@ -24,7 +24,7 @@
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginEnd="24dp"
android:gravity="center_vertical"
android:layout_gravity="center_vertical"
android:orientation="vertical"
android:layout_weight="1">
@@ -38,6 +38,11 @@
android:title="@string/emulation_haptics"
android:checkable="true" />
<item
android:id="@+id/menu_touchscreen"
android:title="@string/touchscreen"
android:checkable="true" />
<item
android:id="@+id/menu_reset_overlay"
android:title="@string/emulation_touch_overlay_reset" />
+34 -9
View File
@@ -118,15 +118,23 @@
</integer-array>
<string-array name="rendererScreenLayoutNames">
<item>@string/screen_layout_landscape</item>
<item>@string/screen_layout_portrait</item>
<item>@string/screen_layout_auto</item>
<item>@string/screen_layout_sensor_landscape</item>
<item>@string/screen_layout_landscape</item>
<item>@string/screen_layout_reverse_landscape</item>
<item>@string/screen_layout_sensor_portrait</item>
<item>@string/screen_layout_portrait</item>
<item>@string/screen_layout_reverse_portrait</item>
</string-array>
<integer-array name="rendererScreenLayoutValues">
<item>5</item>
<item>4</item>
<item>0</item>
<item>5</item>
<item>1</item>
<item>2</item>
<item>6</item>
<item>4</item>
<item>3</item>
</integer-array>
<string-array name="rendererAspectRatioNames">
@@ -212,19 +220,19 @@
<item>B</item>
<item>X</item>
<item>Y</item>
<item>+</item>
<item>-</item>
<item>@string/gamepad_home</item>
<item>@string/gamepad_screenshot</item>
<item>L</item>
<item>R</item>
<item>ZL</item>
<item>ZR</item>
<item>+</item>
<item>-</item>
<item>@string/gamepad_d_pad</item>
<item>@string/gamepad_left_stick</item>
<item>@string/gamepad_right_stick</item>
<item>L3</item>
<item>R3</item>
<item>@string/gamepad_home</item>
<item>@string/gamepad_screenshot</item>
<item>@string/gamepad_d_pad</item>
</string-array>
<string-array name="themeEntries">
@@ -267,4 +275,21 @@
<item>3</item>
</integer-array>
<string-array name="anisoEntries">
<item>@string/auto</item>
<item>@string/slider_default</item>
<item>@string/multiplier_two</item>
<item>@string/multiplier_four</item>
<item>@string/multiplier_eight</item>
<item>@string/multiplier_sixteen</item>
</string-array>
<integer-array name="anisoValues">
<item>0</item>
<item>1</item>
<item>2</item>
<item>3</item>
<item>4</item>
<item>5</item>
</integer-array>
</resources>
+102 -102
View File
@@ -3,111 +3,111 @@
<integer name="grid_columns">1</integer>
<!-- Default SWITCH landscape layout -->
<integer name="SWITCH_BUTTON_A_X">760</integer>
<integer name="SWITCH_BUTTON_A_Y">790</integer>
<integer name="SWITCH_BUTTON_B_X">710</integer>
<integer name="SWITCH_BUTTON_B_Y">900</integer>
<integer name="SWITCH_BUTTON_X_X">710</integer>
<integer name="SWITCH_BUTTON_X_Y">680</integer>
<integer name="SWITCH_BUTTON_Y_X">660</integer>
<integer name="SWITCH_BUTTON_Y_Y">790</integer>
<integer name="SWITCH_STICK_L_X">100</integer>
<integer name="SWITCH_STICK_L_Y">670</integer>
<integer name="SWITCH_STICK_R_X">900</integer>
<integer name="SWITCH_STICK_R_Y">670</integer>
<integer name="SWITCH_TRIGGER_L_X">70</integer>
<integer name="SWITCH_TRIGGER_L_Y">220</integer>
<integer name="SWITCH_TRIGGER_R_X">930</integer>
<integer name="SWITCH_TRIGGER_R_Y">220</integer>
<integer name="SWITCH_TRIGGER_ZL_X">70</integer>
<integer name="SWITCH_TRIGGER_ZL_Y">90</integer>
<integer name="SWITCH_TRIGGER_ZR_X">930</integer>
<integer name="SWITCH_TRIGGER_ZR_Y">90</integer>
<integer name="SWITCH_BUTTON_MINUS_X">460</integer>
<integer name="SWITCH_BUTTON_MINUS_Y">950</integer>
<integer name="SWITCH_BUTTON_PLUS_X">540</integer>
<integer name="SWITCH_BUTTON_PLUS_Y">950</integer>
<integer name="SWITCH_BUTTON_HOME_X">600</integer>
<integer name="SWITCH_BUTTON_HOME_Y">950</integer>
<integer name="SWITCH_BUTTON_CAPTURE_X">400</integer>
<integer name="SWITCH_BUTTON_CAPTURE_Y">950</integer>
<integer name="SWITCH_BUTTON_DPAD_X">260</integer>
<integer name="SWITCH_BUTTON_DPAD_Y">790</integer>
<integer name="SWITCH_BUTTON_STICK_L_X">870</integer>
<integer name="SWITCH_BUTTON_STICK_L_Y">400</integer>
<integer name="SWITCH_BUTTON_STICK_R_X">960</integer>
<integer name="SWITCH_BUTTON_STICK_R_Y">430</integer>
<integer name="BUTTON_A_X">760</integer>
<integer name="BUTTON_A_Y">790</integer>
<integer name="BUTTON_B_X">710</integer>
<integer name="BUTTON_B_Y">900</integer>
<integer name="BUTTON_X_X">710</integer>
<integer name="BUTTON_X_Y">680</integer>
<integer name="BUTTON_Y_X">660</integer>
<integer name="BUTTON_Y_Y">790</integer>
<integer name="BUTTON_PLUS_X">540</integer>
<integer name="BUTTON_PLUS_Y">950</integer>
<integer name="BUTTON_MINUS_X">460</integer>
<integer name="BUTTON_MINUS_Y">950</integer>
<integer name="BUTTON_HOME_X">600</integer>
<integer name="BUTTON_HOME_Y">950</integer>
<integer name="BUTTON_CAPTURE_X">400</integer>
<integer name="BUTTON_CAPTURE_Y">950</integer>
<integer name="BUTTON_L_X">70</integer>
<integer name="BUTTON_L_Y">220</integer>
<integer name="BUTTON_R_X">930</integer>
<integer name="BUTTON_R_Y">220</integer>
<integer name="BUTTON_ZL_X">70</integer>
<integer name="BUTTON_ZL_Y">90</integer>
<integer name="BUTTON_ZR_X">930</integer>
<integer name="BUTTON_ZR_Y">90</integer>
<integer name="BUTTON_STICK_L_X">870</integer>
<integer name="BUTTON_STICK_L_Y">400</integer>
<integer name="BUTTON_STICK_R_X">960</integer>
<integer name="BUTTON_STICK_R_Y">430</integer>
<integer name="STICK_L_X">100</integer>
<integer name="STICK_L_Y">670</integer>
<integer name="STICK_R_X">900</integer>
<integer name="STICK_R_Y">670</integer>
<integer name="COMBINED_DPAD_X">260</integer>
<integer name="COMBINED_DPAD_Y">790</integer>
<!-- Default SWITCH portrait layout -->
<integer name="SWITCH_BUTTON_A_X_PORTRAIT">840</integer>
<integer name="SWITCH_BUTTON_A_Y_PORTRAIT">840</integer>
<integer name="SWITCH_BUTTON_B_X_PORTRAIT">740</integer>
<integer name="SWITCH_BUTTON_B_Y_PORTRAIT">880</integer>
<integer name="SWITCH_BUTTON_X_X_PORTRAIT">740</integer>
<integer name="SWITCH_BUTTON_X_Y_PORTRAIT">800</integer>
<integer name="SWITCH_BUTTON_Y_X_PORTRAIT">640</integer>
<integer name="SWITCH_BUTTON_Y_Y_PORTRAIT">840</integer>
<integer name="SWITCH_STICK_L_X_PORTRAIT">180</integer>
<integer name="SWITCH_STICK_L_Y_PORTRAIT">660</integer>
<integer name="SWITCH_STICK_R_X_PORTRAIT">820</integer>
<integer name="SWITCH_STICK_R_Y_PORTRAIT">660</integer>
<integer name="SWITCH_TRIGGER_L_X_PORTRAIT">140</integer>
<integer name="SWITCH_TRIGGER_L_Y_PORTRAIT">260</integer>
<integer name="SWITCH_TRIGGER_R_X_PORTRAIT">860</integer>
<integer name="SWITCH_TRIGGER_R_Y_PORTRAIT">260</integer>
<integer name="SWITCH_TRIGGER_ZL_X_PORTRAIT">140</integer>
<integer name="SWITCH_TRIGGER_ZL_Y_PORTRAIT">200</integer>
<integer name="SWITCH_TRIGGER_ZR_X_PORTRAIT">860</integer>
<integer name="SWITCH_TRIGGER_ZR_Y_PORTRAIT">200</integer>
<integer name="SWITCH_BUTTON_MINUS_X_PORTRAIT">440</integer>
<integer name="SWITCH_BUTTON_MINUS_Y_PORTRAIT">950</integer>
<integer name="SWITCH_BUTTON_PLUS_X_PORTRAIT">560</integer>
<integer name="SWITCH_BUTTON_PLUS_Y_PORTRAIT">950</integer>
<integer name="SWITCH_BUTTON_HOME_X_PORTRAIT">680</integer>
<integer name="SWITCH_BUTTON_HOME_Y_PORTRAIT">950</integer>
<integer name="SWITCH_BUTTON_CAPTURE_X_PORTRAIT">320</integer>
<integer name="SWITCH_BUTTON_CAPTURE_Y_PORTRAIT">950</integer>
<integer name="SWITCH_BUTTON_DPAD_X_PORTRAIT">240</integer>
<integer name="SWITCH_BUTTON_DPAD_Y_PORTRAIT">840</integer>
<integer name="SWITCH_BUTTON_STICK_L_X_PORTRAIT">730</integer>
<integer name="SWITCH_BUTTON_STICK_L_Y_PORTRAIT">510</integer>
<integer name="SWITCH_BUTTON_STICK_R_X_PORTRAIT">900</integer>
<integer name="SWITCH_BUTTON_STICK_R_Y_PORTRAIT">540</integer>
<integer name="BUTTON_A_X_PORTRAIT">840</integer>
<integer name="BUTTON_A_Y_PORTRAIT">840</integer>
<integer name="BUTTON_B_X_PORTRAIT">740</integer>
<integer name="BUTTON_B_Y_PORTRAIT">880</integer>
<integer name="BUTTON_X_X_PORTRAIT">740</integer>
<integer name="BUTTON_X_Y_PORTRAIT">800</integer>
<integer name="BUTTON_Y_X_PORTRAIT">640</integer>
<integer name="BUTTON_Y_Y_PORTRAIT">840</integer>
<integer name="BUTTON_PLUS_Y_PORTRAIT">950</integer>
<integer name="BUTTON_MINUS_X_PORTRAIT">440</integer>
<integer name="BUTTON_MINUS_Y_PORTRAIT">950</integer>
<integer name="BUTTON_HOME_X_PORTRAIT">680</integer>
<integer name="BUTTON_HOME_Y_PORTRAIT">950</integer>
<integer name="BUTTON_CAPTURE_X_PORTRAIT">320</integer>
<integer name="BUTTON_CAPTURE_Y_PORTRAIT">950</integer>
<integer name="BUTTON_L_X_PORTRAIT">140</integer>
<integer name="BUTTON_L_Y_PORTRAIT">260</integer>
<integer name="BUTTON_R_X_PORTRAIT">860</integer>
<integer name="BUTTON_R_Y_PORTRAIT">260</integer>
<integer name="BUTTON_ZL_X_PORTRAIT">140</integer>
<integer name="BUTTON_ZL_Y_PORTRAIT">200</integer>
<integer name="BUTTON_ZR_X_PORTRAIT">860</integer>
<integer name="BUTTON_ZR_Y_PORTRAIT">200</integer>
<integer name="BUTTON_PLUS_X_PORTRAIT">560</integer>
<integer name="BUTTON_STICK_L_X_PORTRAIT">730</integer>
<integer name="BUTTON_STICK_L_Y_PORTRAIT">510</integer>
<integer name="BUTTON_STICK_R_X_PORTRAIT">900</integer>
<integer name="BUTTON_STICK_R_Y_PORTRAIT">540</integer>
<integer name="STICK_L_X_PORTRAIT">180</integer>
<integer name="STICK_L_Y_PORTRAIT">660</integer>
<integer name="STICK_R_X_PORTRAIT">820</integer>
<integer name="STICK_R_Y_PORTRAIT">660</integer>
<integer name="COMBINED_DPAD_X_PORTRAIT">240</integer>
<integer name="COMBINED_DPAD_Y_PORTRAIT">840</integer>
<!-- Default SWITCH foldable layout -->
<integer name="SWITCH_BUTTON_A_X_FOLDABLE">840</integer>
<integer name="SWITCH_BUTTON_A_Y_FOLDABLE">390</integer>
<integer name="SWITCH_BUTTON_B_X_FOLDABLE">740</integer>
<integer name="SWITCH_BUTTON_B_Y_FOLDABLE">430</integer>
<integer name="SWITCH_BUTTON_X_X_FOLDABLE">740</integer>
<integer name="SWITCH_BUTTON_X_Y_FOLDABLE">350</integer>
<integer name="SWITCH_BUTTON_Y_X_FOLDABLE">640</integer>
<integer name="SWITCH_BUTTON_Y_Y_FOLDABLE">390</integer>
<integer name="SWITCH_STICK_L_X_FOLDABLE">180</integer>
<integer name="SWITCH_STICK_L_Y_FOLDABLE">250</integer>
<integer name="SWITCH_STICK_R_X_FOLDABLE">820</integer>
<integer name="SWITCH_STICK_R_Y_FOLDABLE">250</integer>
<integer name="SWITCH_TRIGGER_L_X_FOLDABLE">140</integer>
<integer name="SWITCH_TRIGGER_L_Y_FOLDABLE">130</integer>
<integer name="SWITCH_TRIGGER_R_X_FOLDABLE">860</integer>
<integer name="SWITCH_TRIGGER_R_Y_FOLDABLE">130</integer>
<integer name="SWITCH_TRIGGER_ZL_X_FOLDABLE">140</integer>
<integer name="SWITCH_TRIGGER_ZL_Y_FOLDABLE">70</integer>
<integer name="SWITCH_TRIGGER_ZR_X_FOLDABLE">860</integer>
<integer name="SWITCH_TRIGGER_ZR_Y_FOLDABLE">70</integer>
<integer name="SWITCH_BUTTON_MINUS_X_FOLDABLE">440</integer>
<integer name="SWITCH_BUTTON_MINUS_Y_FOLDABLE">470</integer>
<integer name="SWITCH_BUTTON_PLUS_X_FOLDABLE">560</integer>
<integer name="SWITCH_BUTTON_PLUS_Y_FOLDABLE">470</integer>
<integer name="SWITCH_BUTTON_HOME_X_FOLDABLE">680</integer>
<integer name="SWITCH_BUTTON_HOME_Y_FOLDABLE">470</integer>
<integer name="SWITCH_BUTTON_CAPTURE_X_FOLDABLE">320</integer>
<integer name="SWITCH_BUTTON_CAPTURE_Y_FOLDABLE">470</integer>
<integer name="SWITCH_BUTTON_DPAD_X_FOLDABLE">240</integer>
<integer name="SWITCH_BUTTON_DPAD_Y_FOLDABLE">390</integer>
<integer name="SWITCH_BUTTON_STICK_L_X_FOLDABLE">550</integer>
<integer name="SWITCH_BUTTON_STICK_L_Y_FOLDABLE">210</integer>
<integer name="SWITCH_BUTTON_STICK_R_X_FOLDABLE">550</integer>
<integer name="SWITCH_BUTTON_STICK_R_Y_FOLDABLE">280</integer>
<integer name="BUTTON_A_X_FOLDABLE">840</integer>
<integer name="BUTTON_A_Y_FOLDABLE">390</integer>
<integer name="BUTTON_B_X_FOLDABLE">740</integer>
<integer name="BUTTON_B_Y_FOLDABLE">430</integer>
<integer name="BUTTON_X_X_FOLDABLE">740</integer>
<integer name="BUTTON_X_Y_FOLDABLE">350</integer>
<integer name="BUTTON_Y_X_FOLDABLE">640</integer>
<integer name="BUTTON_Y_Y_FOLDABLE">390</integer>
<integer name="BUTTON_PLUS_X_FOLDABLE">560</integer>
<integer name="BUTTON_PLUS_Y_FOLDABLE">470</integer>
<integer name="BUTTON_MINUS_X_FOLDABLE">440</integer>
<integer name="BUTTON_MINUS_Y_FOLDABLE">470</integer>
<integer name="BUTTON_HOME_X_FOLDABLE">680</integer>
<integer name="BUTTON_HOME_Y_FOLDABLE">470</integer>
<integer name="BUTTON_CAPTURE_X_FOLDABLE">320</integer>
<integer name="BUTTON_CAPTURE_Y_FOLDABLE">470</integer>
<integer name="BUTTON_L_X_FOLDABLE">140</integer>
<integer name="BUTTON_L_Y_FOLDABLE">130</integer>
<integer name="BUTTON_R_X_FOLDABLE">860</integer>
<integer name="BUTTON_R_Y_FOLDABLE">130</integer>
<integer name="BUTTON_ZL_X_FOLDABLE">140</integer>
<integer name="BUTTON_ZL_Y_FOLDABLE">70</integer>
<integer name="BUTTON_ZR_X_FOLDABLE">860</integer>
<integer name="BUTTON_ZR_Y_FOLDABLE">70</integer>
<integer name="BUTTON_STICK_L_X_FOLDABLE">550</integer>
<integer name="BUTTON_STICK_L_Y_FOLDABLE">210</integer>
<integer name="BUTTON_STICK_R_X_FOLDABLE">550</integer>
<integer name="BUTTON_STICK_R_Y_FOLDABLE">280</integer>
<integer name="STICK_L_X_FOLDABLE">180</integer>
<integer name="STICK_L_Y_FOLDABLE">250</integer>
<integer name="STICK_R_X_FOLDABLE">820</integer>
<integer name="STICK_R_Y_FOLDABLE">250</integer>
<integer name="COMBINED_DPAD_X_FOLDABLE">240</integer>
<integer name="COMBINED_DPAD_Y_FOLDABLE">390</integer>
</resources>
@@ -225,6 +225,8 @@
<string name="renderer_reactive_flushing_description">Improves rendering accuracy in some games at the cost of performance.</string>
<string name="use_disk_shader_cache">Disk shader cache</string>
<string name="use_disk_shader_cache_description">Reduces stuttering by locally storing and loading generated shaders.</string>
<string name="anisotropic_filtering">Anisotropic filtering</string>
<string name="anisotropic_filtering_description">Improves the quality of textures when viewed at oblique angles</string>
<!-- Debug settings strings -->
<string name="cpu">CPU</string>
@@ -364,6 +366,7 @@
<string name="emulation_pause">Pause emulation</string>
<string name="emulation_unpause">Unpause emulation</string>
<string name="emulation_input_overlay">Overlay options</string>
<string name="touchscreen">Touchscreen</string>
<string name="load_settings">Loading settings…</string>
@@ -460,9 +463,13 @@
<string name="anti_aliasing_smaa">SMAA</string>
<!-- Screen Layouts -->
<string name="screen_layout_landscape">Landscape</string>
<string name="screen_layout_portrait">Portrait</string>
<string name="screen_layout_auto">Auto</string>
<string name="screen_layout_sensor_landscape">Sensor landscape</string>
<string name="screen_layout_landscape">Landscape</string>
<string name="screen_layout_reverse_landscape">Reverse landscape</string>
<string name="screen_layout_sensor_portrait">Sensor portrait</string>
<string name="screen_layout_portrait">Portrait</string>
<string name="screen_layout_reverse_portrait">Reverse portrait</string>
<!-- Aspect Ratios -->
<string name="ratio_default">Default (16:9)</string>
@@ -506,6 +513,12 @@
<string name="oboe">oboe</string>
<string name="cubeb">cubeb</string>
<!-- Anisotropic filtering options -->
<string name="multiplier_two">2x</string>
<string name="multiplier_four">4x</string>
<string name="multiplier_eight">8x</string>
<string name="multiplier_sixteen">16x</string>
<!-- Black backgrounds theme -->
<string name="use_black_backgrounds">Black backgrounds</string>
<string name="use_black_backgrounds_description">When using the dark theme, apply black backgrounds.</string>
+1 -1
View File
@@ -5,7 +5,7 @@
plugins {
id("com.android.application") version "8.1.2" apply false
id("com.android.library") version "8.1.2" apply false
id("org.jetbrains.kotlin.android") version "1.8.21" apply false
id("org.jetbrains.kotlin.android") version "1.9.20" apply false
}
tasks.register("clean").configure {
+1 -3
View File
@@ -18,9 +18,7 @@ constexpr auto INCREMENT_TIME{5ms};
DeviceSession::DeviceSession(Core::System& system_)
: system{system_}, thread_event{Core::Timing::CreateEvent(
"AudioOutSampleTick",
[this](std::uintptr_t, s64 time, std::chrono::nanoseconds) {
return ThreadFunc();
})} {}
[this](s64 time, std::chrono::nanoseconds) { return ThreadFunc(); })} {}
DeviceSession::~DeviceSession() {
Finalize();
+2
View File
@@ -64,6 +64,8 @@ add_library(common STATIC
fs/path_util.cpp
fs/path_util.h
hash.h
heap_tracker.cpp
heap_tracker.h
hex_util.cpp
hex_util.h
host_memory.cpp
+3
View File
@@ -3,16 +3,19 @@
#include "common/assert.h"
#include "common/common_funcs.h"
#include "common/logging/backend.h"
#include "common/settings.h"
void assert_fail_impl() {
if (Settings::values.use_debug_asserts) {
Common::Log::Stop();
Crash();
}
}
[[noreturn]] void unreachable_impl() {
Common::Log::Stop();
Crash();
throw std::runtime_error("Unreachable code");
}
+281
View File
@@ -0,0 +1,281 @@
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include <fstream>
#include <vector>
#include "common/heap_tracker.h"
#include "common/logging/log.h"
namespace Common {
namespace {
s64 GetMaxPermissibleResidentMapCount() {
// Default value.
s64 value = 65530;
// Try to read how many mappings we can make.
std::ifstream s("/proc/sys/vm/max_map_count");
s >> value;
// Print, for debug.
LOG_INFO(HW_Memory, "Current maximum map count: {}", value);
// Allow 20000 maps for other code and to account for split inaccuracy.
return std::max<s64>(value - 20000, 0);
}
} // namespace
HeapTracker::HeapTracker(Common::HostMemory& buffer)
: m_buffer(buffer), m_max_resident_map_count(GetMaxPermissibleResidentMapCount()) {}
HeapTracker::~HeapTracker() = default;
void HeapTracker::Map(size_t virtual_offset, size_t host_offset, size_t length,
MemoryPermission perm, bool is_separate_heap) {
// When mapping other memory, map pages immediately.
if (!is_separate_heap) {
m_buffer.Map(virtual_offset, host_offset, length, perm, false);
return;
}
{
// We are mapping part of a separate heap.
std::scoped_lock lk{m_lock};
auto* const map = new SeparateHeapMap{
.vaddr = virtual_offset,
.paddr = host_offset,
.size = length,
.tick = m_tick++,
.perm = perm,
.is_resident = false,
};
// Insert into mappings.
m_map_count++;
m_mappings.insert(*map);
}
// Finally, map.
this->DeferredMapSeparateHeap(virtual_offset);
}
void HeapTracker::Unmap(size_t virtual_offset, size_t size, bool is_separate_heap) {
// If this is a separate heap...
if (is_separate_heap) {
std::scoped_lock lk{m_lock};
const SeparateHeapMap key{
.vaddr = virtual_offset,
};
// Split at the boundaries of the region we are removing.
this->SplitHeapMapLocked(virtual_offset);
this->SplitHeapMapLocked(virtual_offset + size);
// Erase all mappings in range.
auto it = m_mappings.find(key);
while (it != m_mappings.end() && it->vaddr < virtual_offset + size) {
// Get underlying item.
auto* const item = std::addressof(*it);
// If resident, erase from resident map.
if (item->is_resident) {
ASSERT(--m_resident_map_count >= 0);
m_resident_mappings.erase(m_resident_mappings.iterator_to(*item));
}
// Erase from map.
ASSERT(--m_map_count >= 0);
it = m_mappings.erase(it);
// Free the item.
delete item;
}
}
// Unmap pages.
m_buffer.Unmap(virtual_offset, size, false);
}
void HeapTracker::Protect(size_t virtual_offset, size_t size, MemoryPermission perm) {
// Ensure no rebuild occurs while reprotecting.
std::shared_lock lk{m_rebuild_lock};
// Split at the boundaries of the region we are reprotecting.
this->SplitHeapMap(virtual_offset, size);
// Declare tracking variables.
const VAddr end = virtual_offset + size;
VAddr cur = virtual_offset;
while (cur < end) {
VAddr next = cur;
bool should_protect = false;
{
std::scoped_lock lk2{m_lock};
const SeparateHeapMap key{
.vaddr = next,
};
// Try to get the next mapping corresponding to this address.
const auto it = m_mappings.nfind(key);
if (it == m_mappings.end()) {
// There are no separate heap mappings remaining.
next = end;
should_protect = true;
} else if (it->vaddr == cur) {
// We are in range.
// Update permission bits.
it->perm = perm;
// Determine next address and whether we should protect.
next = cur + it->size;
should_protect = it->is_resident;
} else /* if (it->vaddr > cur) */ {
// We weren't in range, but there is a block coming up that will be.
next = it->vaddr;
should_protect = true;
}
}
// Clamp to end.
next = std::min(next, end);
// Reprotect, if we need to.
if (should_protect) {
m_buffer.Protect(cur, next - cur, perm);
}
// Advance.
cur = next;
}
}
bool HeapTracker::DeferredMapSeparateHeap(u8* fault_address) {
if (m_buffer.IsInVirtualRange(fault_address)) {
return this->DeferredMapSeparateHeap(fault_address - m_buffer.VirtualBasePointer());
}
return false;
}
bool HeapTracker::DeferredMapSeparateHeap(size_t virtual_offset) {
bool rebuild_required = false;
{
std::scoped_lock lk{m_lock};
// Check to ensure this was a non-resident separate heap mapping.
const auto it = this->GetNearestHeapMapLocked(virtual_offset);
if (it == m_mappings.end() || it->is_resident) {
return false;
}
// Update tick before possible rebuild.
it->tick = m_tick++;
// Check if we need to rebuild.
if (m_resident_map_count > m_max_resident_map_count) {
rebuild_required = true;
}
// Map the area.
m_buffer.Map(it->vaddr, it->paddr, it->size, it->perm, false);
// This map is now resident.
it->is_resident = true;
m_resident_map_count++;
m_resident_mappings.insert(*it);
}
if (rebuild_required) {
// A rebuild was required, so perform it now.
this->RebuildSeparateHeapAddressSpace();
}
return true;
}
void HeapTracker::RebuildSeparateHeapAddressSpace() {
std::scoped_lock lk{m_rebuild_lock, m_lock};
ASSERT(!m_resident_mappings.empty());
// Dump half of the mappings.
//
// Despite being worse in theory, this has proven to be better in practice than more
// regularly dumping a smaller amount, because it significantly reduces average case
// lock contention.
const size_t desired_count = std::min(m_resident_map_count, m_max_resident_map_count) / 2;
const size_t evict_count = m_resident_map_count - desired_count;
auto it = m_resident_mappings.begin();
for (size_t i = 0; i < evict_count && it != m_resident_mappings.end(); i++) {
// Unmark and unmap.
it->is_resident = false;
m_buffer.Unmap(it->vaddr, it->size, false);
// Advance.
ASSERT(--m_resident_map_count >= 0);
it = m_resident_mappings.erase(it);
}
}
void HeapTracker::SplitHeapMap(VAddr offset, size_t size) {
std::scoped_lock lk{m_lock};
this->SplitHeapMapLocked(offset);
this->SplitHeapMapLocked(offset + size);
}
void HeapTracker::SplitHeapMapLocked(VAddr offset) {
const auto it = this->GetNearestHeapMapLocked(offset);
if (it == m_mappings.end() || it->vaddr == offset) {
// Not contained or no split required.
return;
}
// Cache the original values.
auto* const left = std::addressof(*it);
const size_t orig_size = left->size;
// Adjust the left map.
const size_t left_size = offset - left->vaddr;
left->size = left_size;
// Create the new right map.
auto* const right = new SeparateHeapMap{
.vaddr = left->vaddr + left_size,
.paddr = left->paddr + left_size,
.size = orig_size - left_size,
.tick = left->tick,
.perm = left->perm,
.is_resident = left->is_resident,
};
// Insert the new right map.
m_map_count++;
m_mappings.insert(*right);
// If resident, also insert into resident map.
if (right->is_resident) {
m_resident_map_count++;
m_resident_mappings.insert(*right);
}
}
HeapTracker::AddrTree::iterator HeapTracker::GetNearestHeapMapLocked(VAddr offset) {
const SeparateHeapMap key{
.vaddr = offset,
};
return m_mappings.find(key);
}
} // namespace Common
+98
View File
@@ -0,0 +1,98 @@
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <atomic>
#include <mutex>
#include <set>
#include <shared_mutex>
#include "common/host_memory.h"
#include "common/intrusive_red_black_tree.h"
namespace Common {
struct SeparateHeapMap {
Common::IntrusiveRedBlackTreeNode addr_node{};
Common::IntrusiveRedBlackTreeNode tick_node{};
VAddr vaddr{};
PAddr paddr{};
size_t size{};
size_t tick{};
MemoryPermission perm{};
bool is_resident{};
};
struct SeparateHeapMapAddrComparator {
static constexpr int Compare(const SeparateHeapMap& lhs, const SeparateHeapMap& rhs) {
if (lhs.vaddr < rhs.vaddr) {
return -1;
} else if (lhs.vaddr <= (rhs.vaddr + rhs.size - 1)) {
return 0;
} else {
return 1;
}
}
};
struct SeparateHeapMapTickComparator {
static constexpr int Compare(const SeparateHeapMap& lhs, const SeparateHeapMap& rhs) {
if (lhs.tick < rhs.tick) {
return -1;
} else if (lhs.tick > rhs.tick) {
return 1;
} else {
return SeparateHeapMapAddrComparator::Compare(lhs, rhs);
}
}
};
class HeapTracker {
public:
explicit HeapTracker(Common::HostMemory& buffer);
~HeapTracker();
void Map(size_t virtual_offset, size_t host_offset, size_t length, MemoryPermission perm,
bool is_separate_heap);
void Unmap(size_t virtual_offset, size_t size, bool is_separate_heap);
void Protect(size_t virtual_offset, size_t length, MemoryPermission perm);
u8* VirtualBasePointer() {
return m_buffer.VirtualBasePointer();
}
bool DeferredMapSeparateHeap(u8* fault_address);
bool DeferredMapSeparateHeap(size_t virtual_offset);
private:
using AddrTreeTraits =
Common::IntrusiveRedBlackTreeMemberTraitsDeferredAssert<&SeparateHeapMap::addr_node>;
using AddrTree = AddrTreeTraits::TreeType<SeparateHeapMapAddrComparator>;
using TickTreeTraits =
Common::IntrusiveRedBlackTreeMemberTraitsDeferredAssert<&SeparateHeapMap::tick_node>;
using TickTree = TickTreeTraits::TreeType<SeparateHeapMapTickComparator>;
AddrTree m_mappings{};
TickTree m_resident_mappings{};
private:
void SplitHeapMap(VAddr offset, size_t size);
void SplitHeapMapLocked(VAddr offset);
AddrTree::iterator GetNearestHeapMapLocked(VAddr offset);
void RebuildSeparateHeapAddressSpace();
private:
Common::HostMemory& m_buffer;
const s64 m_max_resident_map_count;
std::shared_mutex m_rebuild_lock{};
std::mutex m_lock{};
s64 m_map_count{};
s64 m_resident_map_count{};
size_t m_tick{};
};
} // namespace Common
+6 -4
View File
@@ -679,7 +679,7 @@ HostMemory::HostMemory(HostMemory&&) noexcept = default;
HostMemory& HostMemory::operator=(HostMemory&&) noexcept = default;
void HostMemory::Map(size_t virtual_offset, size_t host_offset, size_t length,
MemoryPermission perms) {
MemoryPermission perms, bool separate_heap) {
ASSERT(virtual_offset % PageAlignment == 0);
ASSERT(host_offset % PageAlignment == 0);
ASSERT(length % PageAlignment == 0);
@@ -691,7 +691,7 @@ void HostMemory::Map(size_t virtual_offset, size_t host_offset, size_t length,
impl->Map(virtual_offset + virtual_base_offset, host_offset, length, perms);
}
void HostMemory::Unmap(size_t virtual_offset, size_t length) {
void HostMemory::Unmap(size_t virtual_offset, size_t length, bool separate_heap) {
ASSERT(virtual_offset % PageAlignment == 0);
ASSERT(length % PageAlignment == 0);
ASSERT(virtual_offset + length <= virtual_size);
@@ -701,14 +701,16 @@ void HostMemory::Unmap(size_t virtual_offset, size_t length) {
impl->Unmap(virtual_offset + virtual_base_offset, length);
}
void HostMemory::Protect(size_t virtual_offset, size_t length, bool read, bool write,
bool execute) {
void HostMemory::Protect(size_t virtual_offset, size_t length, MemoryPermission perm) {
ASSERT(virtual_offset % PageAlignment == 0);
ASSERT(length % PageAlignment == 0);
ASSERT(virtual_offset + length <= virtual_size);
if (length == 0 || !virtual_base || !impl) {
return;
}
const bool read = True(perm & MemoryPermission::Read);
const bool write = True(perm & MemoryPermission::Write);
const bool execute = True(perm & MemoryPermission::Execute);
impl->Protect(virtual_offset + virtual_base_offset, length, read, write, execute);
}
+8 -3
View File
@@ -40,11 +40,12 @@ public:
HostMemory(HostMemory&& other) noexcept;
HostMemory& operator=(HostMemory&& other) noexcept;
void Map(size_t virtual_offset, size_t host_offset, size_t length, MemoryPermission perms);
void Map(size_t virtual_offset, size_t host_offset, size_t length, MemoryPermission perms,
bool separate_heap);
void Unmap(size_t virtual_offset, size_t length);
void Unmap(size_t virtual_offset, size_t length, bool separate_heap);
void Protect(size_t virtual_offset, size_t length, bool read, bool write, bool execute = false);
void Protect(size_t virtual_offset, size_t length, MemoryPermission perms);
void EnableDirectMappedAddress();
@@ -64,6 +65,10 @@ public:
return virtual_base;
}
bool IsInVirtualRange(void* address) const noexcept {
return address >= virtual_base && address < virtual_base + virtual_size;
}
private:
size_t backing_size{};
size_t virtual_size{};
+17
View File
@@ -208,6 +208,10 @@ public:
instance->StartBackendThread();
}
static void Stop() {
instance->StopBackendThread();
}
Impl(const Impl&) = delete;
Impl& operator=(const Impl&) = delete;
@@ -259,6 +263,15 @@ private:
});
}
void StopBackendThread() {
backend_thread.request_stop();
if (backend_thread.joinable()) {
backend_thread.join();
}
ForEachBackend([](Backend& backend) { backend.Flush(); });
}
Entry CreateEntry(Class log_class, Level log_level, const char* filename, unsigned int line_nr,
const char* function, std::string&& message) const {
using std::chrono::duration_cast;
@@ -313,6 +326,10 @@ void Start() {
Impl::Start();
}
void Stop() {
Impl::Stop();
}
void DisableLoggingInTests() {
initialization_in_progress_suppress_logging = true;
}
+3
View File
@@ -14,6 +14,9 @@ void Initialize();
void Start();
/// Explicitly stops the logger thread and flushes the buffers
void Stop();
void DisableLoggingInTests();
/**
+1 -1
View File
@@ -103,7 +103,7 @@ private:
// Having them on the same cache-line would result in false-sharing between them.
// TODO: Remove this ifdef whenever clang and GCC support
// std::hardware_destructive_interference_size.
#if defined(_MSC_VER) && _MSC_VER >= 1911
#ifdef __cpp_lib_hardware_interference_size
alignas(std::hardware_destructive_interference_size) std::atomic_size_t m_read_index{0};
alignas(std::hardware_destructive_interference_size) std::atomic_size_t m_write_index{0};
#else
+2
View File
@@ -199,6 +199,8 @@ const char* TranslateCategory(Category category) {
case Category::CpuDebug:
case Category::CpuUnsafe:
return "Cpu";
case Category::Overlay:
return "Overlay";
case Category::Renderer:
case Category::RendererAdvanced:
case Category::RendererDebug:
+1
View File
@@ -18,6 +18,7 @@ enum class Category : u32 {
Cpu,
CpuDebug,
CpuUnsafe,
Overlay,
Renderer,
RendererAdvanced,
RendererDebug,
+4 -81
View File
@@ -183,22 +183,6 @@ add_library(core STATIC
frontend/framebuffer_layout.cpp
frontend/framebuffer_layout.h
frontend/graphics_context.h
hid/emulated_console.cpp
hid/emulated_console.h
hid/emulated_controller.cpp
hid/emulated_controller.h
hid/emulated_devices.cpp
hid/emulated_devices.h
hid/hid_core.cpp
hid/hid_core.h
hid/hid_types.h
hid/input_converter.cpp
hid/input_converter.h
hid/input_interpreter.cpp
hid/input_interpreter.h
hid/irs_types.h
hid/motion_input.cpp
hid/motion_input.h
hle/api_version.h
hle/ipc.h
hle/kernel/board/nintendo/nx/k_memory_layout.cpp
@@ -531,80 +515,16 @@ add_library(core STATIC
hle/service/hid/hid.h
hle/service/hid/hid_debug_server.cpp
hle/service/hid/hid_debug_server.h
hle/service/hid/hid_firmware_settings.cpp
hle/service/hid/hid_firmware_settings.h
hle/service/hid/hid_server.cpp
hle/service/hid/hid_server.h
hle/service/hid/hid_system_server.cpp
hle/service/hid/hid_system_server.h
hle/service/hid/hid_util.h
hle/service/hid/hidbus.cpp
hle/service/hid/hidbus.h
hle/service/hid/irs.cpp
hle/service/hid/irs.h
hle/service/hid/irs_ring_lifo.h
hle/service/hid/resource_manager.cpp
hle/service/hid/resource_manager.h
hle/service/hid/ring_lifo.h
hle/service/hid/xcd.cpp
hle/service/hid/xcd.h
hle/service/hid/errors.h
hle/service/hid/controllers/types/debug_pad_types.h
hle/service/hid/controllers/types/keyboard_types.h
hle/service/hid/controllers/types/mouse_types.h
hle/service/hid/controllers/types/npad_types.h
hle/service/hid/controllers/types/touch_types.h
hle/service/hid/controllers/applet_resource.cpp
hle/service/hid/controllers/applet_resource.h
hle/service/hid/controllers/console_six_axis.cpp
hle/service/hid/controllers/console_six_axis.h
hle/service/hid/controllers/controller_base.cpp
hle/service/hid/controllers/controller_base.h
hle/service/hid/controllers/debug_pad.cpp
hle/service/hid/controllers/debug_pad.h
hle/service/hid/controllers/gesture.cpp
hle/service/hid/controllers/gesture.h
hle/service/hid/controllers/keyboard.cpp
hle/service/hid/controllers/keyboard.h
hle/service/hid/controllers/mouse.cpp
hle/service/hid/controllers/mouse.h
hle/service/hid/controllers/npad.cpp
hle/service/hid/controllers/npad.h
hle/service/hid/controllers/palma.cpp
hle/service/hid/controllers/palma.h
hle/service/hid/controllers/seven_six_axis.cpp
hle/service/hid/controllers/seven_six_axis.h
hle/service/hid/controllers/shared_memory_format.h
hle/service/hid/controllers/shared_memory_holder.cpp
hle/service/hid/controllers/shared_memory_holder.h
hle/service/hid/controllers/six_axis.cpp
hle/service/hid/controllers/six_axis.h
hle/service/hid/controllers/stubbed.cpp
hle/service/hid/controllers/stubbed.h
hle/service/hid/controllers/touchscreen.cpp
hle/service/hid/controllers/touchscreen.h
hle/service/hid/hidbus/hidbus_base.cpp
hle/service/hid/hidbus/hidbus_base.h
hle/service/hid/hidbus/ringcon.cpp
hle/service/hid/hidbus/ringcon.h
hle/service/hid/hidbus/starlink.cpp
hle/service/hid/hidbus/starlink.h
hle/service/hid/hidbus/stubbed.cpp
hle/service/hid/hidbus/stubbed.h
hle/service/hid/irsensor/clustering_processor.cpp
hle/service/hid/irsensor/clustering_processor.h
hle/service/hid/irsensor/image_transfer_processor.cpp
hle/service/hid/irsensor/image_transfer_processor.h
hle/service/hid/irsensor/ir_led_processor.cpp
hle/service/hid/irsensor/ir_led_processor.h
hle/service/hid/irsensor/moment_processor.cpp
hle/service/hid/irsensor/moment_processor.h
hle/service/hid/irsensor/pointing_processor.cpp
hle/service/hid/irsensor/pointing_processor.h
hle/service/hid/irsensor/processor_base.cpp
hle/service/hid/irsensor/processor_base.h
hle/service/hid/irsensor/tera_plugin_processor.cpp
hle/service/hid/irsensor/tera_plugin_processor.h
hle/service/lbl/lbl.cpp
hle/service/lbl/lbl.h
hle/service/ldn/lan_discovery.cpp
@@ -945,7 +865,7 @@ endif()
create_target_directory_groups(core)
target_link_libraries(core PUBLIC common PRIVATE audio_core network video_core nx_tzdb)
target_link_libraries(core PUBLIC common PRIVATE audio_core hid_core network video_core nx_tzdb)
target_link_libraries(core PUBLIC Boost::headers PRIVATE fmt::fmt nlohmann_json::nlohmann_json mbedtls RenderDoc::API)
if (MINGW)
target_link_libraries(core PRIVATE ${MSWSOCK_LIBRARY})
@@ -978,6 +898,7 @@ endif()
if (ARCHITECTURE_x86_64 OR ARCHITECTURE_arm64)
target_sources(core PRIVATE
arm/dynarmic/arm_dynarmic.cpp
arm/dynarmic/arm_dynarmic.h
arm/dynarmic/arm_dynarmic_64.cpp
arm/dynarmic/arm_dynarmic_64.h
@@ -987,6 +908,8 @@ if (ARCHITECTURE_x86_64 OR ARCHITECTURE_arm64)
arm/dynarmic/dynarmic_cp15.h
arm/dynarmic/dynarmic_exclusive_monitor.cpp
arm/dynarmic/dynarmic_exclusive_monitor.h
hle/service/jit/jit_code_memory.cpp
hle/service/jit/jit_code_memory.h
hle/service/jit/jit_context.cpp
hle/service/jit/jit_context.h
hle/service/jit/jit.cpp
+1 -1
View File
@@ -9,7 +9,7 @@
namespace Core {
void ArmInterface::LogBacktrace(const Kernel::KProcess* process) const {
void ArmInterface::LogBacktrace(Kernel::KProcess* process) const {
Kernel::Svc::ThreadContext ctx;
this->GetContext(ctx);
+1 -1
View File
@@ -95,7 +95,7 @@ public:
virtual void SignalInterrupt(Kernel::KThread* thread) = 0;
// Stack trace generation.
void LogBacktrace(const Kernel::KProcess* process) const;
void LogBacktrace(Kernel::KProcess* process) const;
// Debug functionality.
virtual const Kernel::DebugWatchpoint* HaltedWatchpoint() const = 0;
+7 -7
View File
@@ -79,7 +79,7 @@ constexpr std::array<u64, 2> SegmentBases{
0x7100000000ULL,
};
void SymbolicateBacktrace(const Kernel::KProcess* process, std::vector<BacktraceEntry>& out) {
void SymbolicateBacktrace(Kernel::KProcess* process, std::vector<BacktraceEntry>& out) {
auto modules = FindModules(process);
const bool is_64 = process->Is64Bit();
@@ -118,7 +118,7 @@ void SymbolicateBacktrace(const Kernel::KProcess* process, std::vector<Backtrace
}
}
std::vector<BacktraceEntry> GetAArch64Backtrace(const Kernel::KProcess* process,
std::vector<BacktraceEntry> GetAArch64Backtrace(Kernel::KProcess* process,
const Kernel::Svc::ThreadContext& ctx) {
std::vector<BacktraceEntry> out;
auto& memory = process->GetMemory();
@@ -144,7 +144,7 @@ std::vector<BacktraceEntry> GetAArch64Backtrace(const Kernel::KProcess* process,
return out;
}
std::vector<BacktraceEntry> GetAArch32Backtrace(const Kernel::KProcess* process,
std::vector<BacktraceEntry> GetAArch32Backtrace(Kernel::KProcess* process,
const Kernel::Svc::ThreadContext& ctx) {
std::vector<BacktraceEntry> out;
auto& memory = process->GetMemory();
@@ -173,7 +173,7 @@ std::vector<BacktraceEntry> GetAArch32Backtrace(const Kernel::KProcess* process,
} // namespace
std::optional<std::string> GetThreadName(const Kernel::KThread* thread) {
const auto* process = thread->GetOwnerProcess();
auto* process = thread->GetOwnerProcess();
if (process->Is64Bit()) {
return GetNameFromThreadType64(process->GetMemory(), *thread);
} else {
@@ -248,7 +248,7 @@ Kernel::KProcessAddress GetModuleEnd(const Kernel::KProcess* process,
return cur_addr - 1;
}
Loader::AppLoader::Modules FindModules(const Kernel::KProcess* process) {
Loader::AppLoader::Modules FindModules(Kernel::KProcess* process) {
Loader::AppLoader::Modules modules;
auto& page_table = process->GetPageTable();
@@ -312,7 +312,7 @@ Loader::AppLoader::Modules FindModules(const Kernel::KProcess* process) {
return modules;
}
Kernel::KProcessAddress FindMainModuleEntrypoint(const Kernel::KProcess* process) {
Kernel::KProcessAddress FindMainModuleEntrypoint(Kernel::KProcess* process) {
// Do we have any loaded executable sections?
auto modules = FindModules(process);
@@ -337,7 +337,7 @@ void InvalidateInstructionCacheRange(const Kernel::KProcess* process, u64 addres
}
}
std::vector<BacktraceEntry> GetBacktraceFromContext(const Kernel::KProcess* process,
std::vector<BacktraceEntry> GetBacktraceFromContext(Kernel::KProcess* process,
const Kernel::Svc::ThreadContext& ctx) {
if (process->Is64Bit()) {
return GetAArch64Backtrace(process, ctx);
+3 -3
View File
@@ -14,9 +14,9 @@ std::optional<std::string> GetThreadName(const Kernel::KThread* thread);
std::string_view GetThreadWaitReason(const Kernel::KThread* thread);
std::string GetThreadState(const Kernel::KThread* thread);
Loader::AppLoader::Modules FindModules(const Kernel::KProcess* process);
Loader::AppLoader::Modules FindModules(Kernel::KProcess* process);
Kernel::KProcessAddress GetModuleEnd(const Kernel::KProcess* process, Kernel::KProcessAddress base);
Kernel::KProcessAddress FindMainModuleEntrypoint(const Kernel::KProcess* process);
Kernel::KProcessAddress FindMainModuleEntrypoint(Kernel::KProcess* process);
void InvalidateInstructionCacheRange(const Kernel::KProcess* process, u64 address, u64 size);
@@ -28,7 +28,7 @@ struct BacktraceEntry {
std::string name;
};
std::vector<BacktraceEntry> GetBacktraceFromContext(const Kernel::KProcess* process,
std::vector<BacktraceEntry> GetBacktraceFromContext(Kernel::KProcess* process,
const Kernel::Svc::ThreadContext& ctx);
std::vector<BacktraceEntry> GetBacktrace(const Kernel::KThread* thread);
+49
View File
@@ -0,0 +1,49 @@
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#ifdef __linux__
#include "common/signal_chain.h"
#include "core/arm/dynarmic/arm_dynarmic.h"
#include "core/hle/kernel/k_process.h"
#include "core/memory.h"
namespace Core {
namespace {
thread_local Core::Memory::Memory* g_current_memory{};
std::once_flag g_registered{};
struct sigaction g_old_segv {};
void HandleSigSegv(int sig, siginfo_t* info, void* ctx) {
if (g_current_memory && g_current_memory->InvalidateSeparateHeap(info->si_addr)) {
return;
}
return g_old_segv.sa_sigaction(sig, info, ctx);
}
} // namespace
ScopedJitExecution::ScopedJitExecution(Kernel::KProcess* process) {
g_current_memory = std::addressof(process->GetMemory());
}
ScopedJitExecution::~ScopedJitExecution() {
g_current_memory = nullptr;
}
void ScopedJitExecution::RegisterHandler() {
std::call_once(g_registered, [] {
struct sigaction sa {};
sa.sa_sigaction = &HandleSigSegv;
sa.sa_flags = SA_SIGINFO | SA_ONSTACK;
Common::SigAction(SIGSEGV, std::addressof(sa), std::addressof(g_old_segv));
});
}
} // namespace Core
#endif
+20
View File
@@ -26,4 +26,24 @@ constexpr HaltReason TranslateHaltReason(Dynarmic::HaltReason hr) {
return static_cast<HaltReason>(hr);
}
#ifdef __linux__
class ScopedJitExecution {
public:
explicit ScopedJitExecution(Kernel::KProcess* process);
~ScopedJitExecution();
static void RegisterHandler();
};
#else
class ScopedJitExecution {
public:
explicit ScopedJitExecution(Kernel::KProcess* process) {}
~ScopedJitExecution() {}
static void RegisterHandler() {}
};
#endif
} // namespace Core
+8 -3
View File
@@ -15,7 +15,7 @@ using namespace Common::Literals;
class DynarmicCallbacks32 : public Dynarmic::A32::UserCallbacks {
public:
explicit DynarmicCallbacks32(ArmDynarmic32& parent, const Kernel::KProcess* process)
explicit DynarmicCallbacks32(ArmDynarmic32& parent, Kernel::KProcess* process)
: m_parent{parent}, m_memory(process->GetMemory()),
m_process(process), m_debugger_enabled{parent.m_system.DebuggerEnabled()},
m_check_memory_access{m_debugger_enabled ||
@@ -169,7 +169,7 @@ public:
ArmDynarmic32& m_parent;
Core::Memory::Memory& m_memory;
const Kernel::KProcess* m_process{};
Kernel::KProcess* m_process{};
const bool m_debugger_enabled{};
const bool m_check_memory_access{};
static constexpr u64 MinimumRunCycles = 10000U;
@@ -331,11 +331,15 @@ bool ArmDynarmic32::IsInThumbMode() const {
}
HaltReason ArmDynarmic32::RunThread(Kernel::KThread* thread) {
ScopedJitExecution sj(thread->GetOwnerProcess());
m_jit->ClearExclusiveState();
return TranslateHaltReason(m_jit->Run());
}
HaltReason ArmDynarmic32::StepThread(Kernel::KThread* thread) {
ScopedJitExecution sj(thread->GetOwnerProcess());
m_jit->ClearExclusiveState();
return TranslateHaltReason(m_jit->Step());
}
@@ -370,13 +374,14 @@ void ArmDynarmic32::RewindBreakpointInstruction() {
this->SetContext(m_breakpoint_context);
}
ArmDynarmic32::ArmDynarmic32(System& system, bool uses_wall_clock, const Kernel::KProcess* process,
ArmDynarmic32::ArmDynarmic32(System& system, bool uses_wall_clock, Kernel::KProcess* process,
DynarmicExclusiveMonitor& exclusive_monitor, std::size_t core_index)
: ArmInterface{uses_wall_clock}, m_system{system}, m_exclusive_monitor{exclusive_monitor},
m_cb(std::make_unique<DynarmicCallbacks32>(*this, process)),
m_cp15(std::make_shared<DynarmicCP15>(*this)), m_core_index{core_index} {
auto& page_table_impl = process->GetPageTable().GetBasePageTable().GetImpl();
m_jit = MakeJit(&page_table_impl);
ScopedJitExecution::RegisterHandler();
}
ArmDynarmic32::~ArmDynarmic32() = default;
+1 -1
View File
@@ -20,7 +20,7 @@ class System;
class ArmDynarmic32 final : public ArmInterface {
public:
ArmDynarmic32(System& system, bool uses_wall_clock, const Kernel::KProcess* process,
ArmDynarmic32(System& system, bool uses_wall_clock, Kernel::KProcess* process,
DynarmicExclusiveMonitor& exclusive_monitor, std::size_t core_index);
~ArmDynarmic32() override;
+8 -3
View File
@@ -15,7 +15,7 @@ using namespace Common::Literals;
class DynarmicCallbacks64 : public Dynarmic::A64::UserCallbacks {
public:
explicit DynarmicCallbacks64(ArmDynarmic64& parent, const Kernel::KProcess* process)
explicit DynarmicCallbacks64(ArmDynarmic64& parent, Kernel::KProcess* process)
: m_parent{parent}, m_memory(process->GetMemory()),
m_process(process), m_debugger_enabled{parent.m_system.DebuggerEnabled()},
m_check_memory_access{m_debugger_enabled ||
@@ -216,7 +216,7 @@ public:
Core::Memory::Memory& m_memory;
u64 m_tpidrro_el0{};
u64 m_tpidr_el0{};
const Kernel::KProcess* m_process{};
Kernel::KProcess* m_process{};
const bool m_debugger_enabled{};
const bool m_check_memory_access{};
static constexpr u64 MinimumRunCycles = 10000U;
@@ -362,11 +362,15 @@ std::shared_ptr<Dynarmic::A64::Jit> ArmDynarmic64::MakeJit(Common::PageTable* pa
}
HaltReason ArmDynarmic64::RunThread(Kernel::KThread* thread) {
ScopedJitExecution sj(thread->GetOwnerProcess());
m_jit->ClearExclusiveState();
return TranslateHaltReason(m_jit->Run());
}
HaltReason ArmDynarmic64::StepThread(Kernel::KThread* thread) {
ScopedJitExecution sj(thread->GetOwnerProcess());
m_jit->ClearExclusiveState();
return TranslateHaltReason(m_jit->Step());
}
@@ -399,13 +403,14 @@ void ArmDynarmic64::RewindBreakpointInstruction() {
this->SetContext(m_breakpoint_context);
}
ArmDynarmic64::ArmDynarmic64(System& system, bool uses_wall_clock, const Kernel::KProcess* process,
ArmDynarmic64::ArmDynarmic64(System& system, bool uses_wall_clock, Kernel::KProcess* process,
DynarmicExclusiveMonitor& exclusive_monitor, std::size_t core_index)
: ArmInterface{uses_wall_clock}, m_system{system}, m_exclusive_monitor{exclusive_monitor},
m_cb(std::make_unique<DynarmicCallbacks64>(*this, process)), m_core_index{core_index} {
auto& page_table = process->GetPageTable().GetBasePageTable();
auto& page_table_impl = page_table.GetImpl();
m_jit = MakeJit(&page_table_impl, page_table.GetAddressSpaceWidth());
ScopedJitExecution::RegisterHandler();
}
ArmDynarmic64::~ArmDynarmic64() = default;
+1 -1
View File
@@ -25,7 +25,7 @@ class System;
class ArmDynarmic64 final : public ArmInterface {
public:
ArmDynarmic64(System& system, bool uses_wall_clock, const Kernel::KProcess* process,
ArmDynarmic64(System& system, bool uses_wall_clock, Kernel::KProcess* process,
DynarmicExclusiveMonitor& exclusive_monitor, std::size_t core_index);
~ArmDynarmic64() override;
+22 -53
View File
@@ -28,8 +28,6 @@
#include "core/file_sys/savedata_factory.h"
#include "core/file_sys/vfs_concat.h"
#include "core/file_sys/vfs_real.h"
#include "core/gpu_dirty_memory_manager.h"
#include "core/hid/hid_core.h"
#include "core/hle/kernel/k_memory_manager.h"
#include "core/hle/kernel/k_process.h"
#include "core/hle/kernel/k_resource_limit.h"
@@ -53,6 +51,7 @@
#include "core/telemetry_session.h"
#include "core/tools/freezer.h"
#include "core/tools/renderdoc.h"
#include "hid_core/hid_core.h"
#include "network/network.h"
#include "video_core/host1x/host1x.h"
#include "video_core/renderer_base.h"
@@ -130,11 +129,8 @@ FileSys::VirtualFile GetGameFileFromPath(const FileSys::VirtualFilesystem& vfs,
struct System::Impl {
explicit Impl(System& system)
: kernel{system}, fs_controller{system}, memory{system}, hid_core{}, room_network{},
cpu_manager{system}, reporter{system}, applet_manager{system}, profile_manager{},
time_manager{system}, gpu_dirty_memory_write_manager{} {
memory.SetGPUDirtyManagers(gpu_dirty_memory_write_manager);
}
: kernel{system}, fs_controller{system}, hid_core{}, room_network{}, cpu_manager{system},
reporter{system}, applet_manager{system}, profile_manager{}, time_manager{system} {}
void Initialize(System& system) {
device_memory = std::make_unique<Core::DeviceMemory>();
@@ -241,17 +237,17 @@ struct System::Impl {
debugger = std::make_unique<Debugger>(system, port);
}
SystemResultStatus SetupForApplicationProcess(System& system, Frontend::EmuWindow& emu_window) {
void InitializeKernel(System& system) {
LOG_DEBUG(Core, "initialized OK");
// Setting changes may require a full system reinitialization (e.g., disabling multicore).
ReinitializeIfNecessary(system);
memory.SetGPUDirtyManagers(gpu_dirty_memory_write_manager);
kernel.Initialize();
cpu_manager.Initialize();
}
SystemResultStatus SetupForApplicationProcess(System& system, Frontend::EmuWindow& emu_window) {
/// Reset all glue registrations
arp_manager.ResetAll();
@@ -300,17 +296,9 @@ struct System::Impl {
return SystemResultStatus::ErrorGetLoader;
}
SystemResultStatus init_result{SetupForApplicationProcess(system, emu_window)};
if (init_result != SystemResultStatus::Success) {
LOG_CRITICAL(Core, "Failed to initialize system (Error {})!",
static_cast<int>(init_result));
ShutdownMainProcess();
return init_result;
}
InitializeKernel(system);
telemetry_session->AddInitialInfo(*app_loader, fs_controller, *content_provider);
// Create the process.
// Create the application process.
auto main_process = Kernel::KProcess::Create(system.Kernel());
Kernel::KProcess::Register(system.Kernel(), main_process);
kernel.AppendNewProcess(main_process);
@@ -323,7 +311,18 @@ struct System::Impl {
return static_cast<SystemResultStatus>(
static_cast<u32>(SystemResultStatus::ErrorLoader) + static_cast<u32>(load_result));
}
// Set up the rest of the system.
SystemResultStatus init_result{SetupForApplicationProcess(system, emu_window)};
if (init_result != SystemResultStatus::Success) {
LOG_CRITICAL(Core, "Failed to initialize system (Error {})!",
static_cast<int>(init_result));
ShutdownMainProcess();
return init_result;
}
AddGlueRegistrationForProcess(*app_loader, *main_process);
telemetry_session->AddInitialInfo(*app_loader, fs_controller, *content_provider);
// Initialize cheat engine
if (cheat_engine) {
@@ -426,7 +425,6 @@ struct System::Impl {
cpu_manager.Shutdown();
debugger.reset();
kernel.Shutdown();
memory.Reset();
Network::RestartSocketOperations();
if (auto room_member = room_network.GetRoomMember().lock()) {
@@ -507,7 +505,6 @@ struct System::Impl {
std::unique_ptr<Tegra::Host1x::Host1x> host1x_core;
std::unique_ptr<Core::DeviceMemory> device_memory;
std::unique_ptr<AudioCore::AudioCore> audio_core;
Core::Memory::Memory memory;
Core::HID::HIDCore hid_core;
Network::RoomNetwork room_network;
@@ -567,9 +564,6 @@ struct System::Impl {
std::array<u64, Core::Hardware::NUM_CPU_CORES> dynarmic_ticks{};
std::array<MicroProfileToken, Core::Hardware::NUM_CPU_CORES> microprofile_cpu{};
std::array<Core::GPUDirtyMemoryManager, Core::Hardware::NUM_CPU_CORES>
gpu_dirty_memory_write_manager{};
std::deque<std::vector<u8>> user_channel;
};
@@ -652,29 +646,12 @@ void System::PrepareReschedule(const u32 core_index) {
impl->kernel.PrepareReschedule(core_index);
}
Core::GPUDirtyMemoryManager& System::CurrentGPUDirtyMemoryManager() {
const std::size_t core = impl->kernel.GetCurrentHostThreadID();
return impl->gpu_dirty_memory_write_manager[core < Core::Hardware::NUM_CPU_CORES
? core
: Core::Hardware::NUM_CPU_CORES - 1];
}
/// Provides a constant reference to the current gou dirty memory manager.
const Core::GPUDirtyMemoryManager& System::CurrentGPUDirtyMemoryManager() const {
const std::size_t core = impl->kernel.GetCurrentHostThreadID();
return impl->gpu_dirty_memory_write_manager[core < Core::Hardware::NUM_CPU_CORES
? core
: Core::Hardware::NUM_CPU_CORES - 1];
}
size_t System::GetCurrentHostThreadID() const {
return impl->kernel.GetCurrentHostThreadID();
}
void System::GatherGPUDirtyMemory(std::function<void(VAddr, size_t)>& callback) {
for (auto& manager : impl->gpu_dirty_memory_write_manager) {
manager.Gather(callback);
}
return this->ApplicationProcess()->GatherGPUDirtyMemory(callback);
}
PerfStatsResults System::GetAndResetPerfStats() {
@@ -723,20 +700,12 @@ const Kernel::KProcess* System::ApplicationProcess() const {
return impl->kernel.ApplicationProcess();
}
ExclusiveMonitor& System::Monitor() {
return impl->kernel.GetExclusiveMonitor();
}
const ExclusiveMonitor& System::Monitor() const {
return impl->kernel.GetExclusiveMonitor();
}
Memory::Memory& System::ApplicationMemory() {
return impl->memory;
return impl->kernel.ApplicationProcess()->GetMemory();
}
const Core::Memory::Memory& System::ApplicationMemory() const {
return impl->memory;
return impl->kernel.ApplicationProcess()->GetMemory();
}
Tegra::GPU& System::GPU() {
-13
View File
@@ -116,7 +116,6 @@ class CpuManager;
class Debugger;
class DeviceMemory;
class ExclusiveMonitor;
class GPUDirtyMemoryManager;
class PerfStats;
class Reporter;
class SpeedLimiter;
@@ -225,12 +224,6 @@ public:
/// Prepare the core emulation for a reschedule
void PrepareReschedule(u32 core_index);
/// Provides a reference to the gou dirty memory manager.
[[nodiscard]] Core::GPUDirtyMemoryManager& CurrentGPUDirtyMemoryManager();
/// Provides a constant reference to the current gou dirty memory manager.
[[nodiscard]] const Core::GPUDirtyMemoryManager& CurrentGPUDirtyMemoryManager() const;
void GatherGPUDirtyMemory(std::function<void(VAddr, size_t)>& callback);
[[nodiscard]] size_t GetCurrentHostThreadID() const;
@@ -250,12 +243,6 @@ public:
/// Gets a const reference to the underlying CPU manager
[[nodiscard]] const CpuManager& GetCpuManager() const;
/// Gets a reference to the exclusive monitor
[[nodiscard]] ExclusiveMonitor& Monitor();
/// Gets a constant reference to the exclusive monitor
[[nodiscard]] const ExclusiveMonitor& Monitor() const;
/// Gets a mutable reference to the system memory instance.
[[nodiscard]] Core::Memory::Memory& ApplicationMemory();
+24 -24
View File
@@ -29,7 +29,6 @@ std::shared_ptr<EventType> CreateEvent(std::string name, TimedCallback&& callbac
struct CoreTiming::Event {
s64 time;
u64 fifo_order;
std::uintptr_t user_data;
std::weak_ptr<EventType> type;
s64 reschedule_time;
heap_t::handle_type handle{};
@@ -67,17 +66,15 @@ void CoreTiming::Initialize(std::function<void()>&& on_thread_init_) {
event_fifo_id = 0;
shutting_down = false;
cpu_ticks = 0;
const auto empty_timed_callback = [](std::uintptr_t, u64, std::chrono::nanoseconds)
-> std::optional<std::chrono::nanoseconds> { return std::nullopt; };
ev_lost = CreateEvent("_lost_event", empty_timed_callback);
if (is_multicore) {
timer_thread = std::make_unique<std::jthread>(ThreadEntry, std::ref(*this));
}
}
void CoreTiming::ClearPendingEvents() {
std::scoped_lock lock{basic_lock};
std::scoped_lock lock{advance_lock, basic_lock};
event_queue.clear();
event.Set();
}
void CoreTiming::Pause(bool is_paused) {
@@ -119,14 +116,12 @@ bool CoreTiming::HasPendingEvents() const {
}
void CoreTiming::ScheduleEvent(std::chrono::nanoseconds ns_into_future,
const std::shared_ptr<EventType>& event_type,
std::uintptr_t user_data, bool absolute_time) {
const std::shared_ptr<EventType>& event_type, bool absolute_time) {
{
std::scoped_lock scope{basic_lock};
const auto next_time{absolute_time ? ns_into_future : GetGlobalTimeNs() + ns_into_future};
auto h{event_queue.emplace(
Event{next_time.count(), event_fifo_id++, user_data, event_type, 0})};
auto h{event_queue.emplace(Event{next_time.count(), event_fifo_id++, event_type, 0})};
(*h).handle = h;
}
@@ -136,13 +131,13 @@ void CoreTiming::ScheduleEvent(std::chrono::nanoseconds ns_into_future,
void CoreTiming::ScheduleLoopingEvent(std::chrono::nanoseconds start_time,
std::chrono::nanoseconds resched_time,
const std::shared_ptr<EventType>& event_type,
std::uintptr_t user_data, bool absolute_time) {
bool absolute_time) {
{
std::scoped_lock scope{basic_lock};
const auto next_time{absolute_time ? start_time : GetGlobalTimeNs() + start_time};
auto h{event_queue.emplace(Event{next_time.count(), event_fifo_id++, user_data, event_type,
resched_time.count()})};
auto h{event_queue.emplace(
Event{next_time.count(), event_fifo_id++, event_type, resched_time.count()})};
(*h).handle = h;
}
@@ -150,14 +145,14 @@ void CoreTiming::ScheduleLoopingEvent(std::chrono::nanoseconds start_time,
}
void CoreTiming::UnscheduleEvent(const std::shared_ptr<EventType>& event_type,
std::uintptr_t user_data, bool wait) {
UnscheduleEventType type) {
{
std::scoped_lock lk{basic_lock};
std::vector<heap_t::handle_type> to_remove;
for (auto itr = event_queue.begin(); itr != event_queue.end(); itr++) {
const Event& e = *itr;
if (e.type.lock().get() == event_type.get() && e.user_data == user_data) {
if (e.type.lock().get() == event_type.get()) {
to_remove.push_back(itr->handle);
}
}
@@ -165,10 +160,12 @@ void CoreTiming::UnscheduleEvent(const std::shared_ptr<EventType>& event_type,
for (auto h : to_remove) {
event_queue.erase(h);
}
event_type->sequence_number++;
}
// Force any in-progress events to finish
if (wait) {
if (type == UnscheduleEventType::Wait) {
std::scoped_lock lk{advance_lock};
}
}
@@ -208,28 +205,31 @@ std::optional<s64> CoreTiming::Advance() {
const Event& evt = event_queue.top();
if (const auto event_type{evt.type.lock()}) {
if (evt.reschedule_time == 0) {
const auto evt_user_data = evt.user_data;
const auto evt_time = evt.time;
const auto evt_time = evt.time;
const auto evt_sequence_num = event_type->sequence_number;
if (evt.reschedule_time == 0) {
event_queue.pop();
basic_lock.unlock();
event_type->callback(
evt_user_data, evt_time,
std::chrono::nanoseconds{GetGlobalTimeNs().count() - evt_time});
evt_time, std::chrono::nanoseconds{GetGlobalTimeNs().count() - evt_time});
basic_lock.lock();
} else {
basic_lock.unlock();
const auto new_schedule_time{event_type->callback(
evt.user_data, evt.time,
std::chrono::nanoseconds{GetGlobalTimeNs().count() - evt.time})};
evt_time, std::chrono::nanoseconds{GetGlobalTimeNs().count() - evt_time})};
basic_lock.lock();
if (evt_sequence_num != event_type->sequence_number) {
// Heap handle is invalidated after external modification.
continue;
}
const auto next_schedule_time{new_schedule_time.has_value()
? new_schedule_time.value().count()
: evt.reschedule_time};
@@ -241,8 +241,8 @@ std::optional<s64> CoreTiming::Advance() {
next_time = pause_end_time + next_schedule_time;
}
event_queue.update(evt.handle, Event{next_time, event_fifo_id++, evt.user_data,
evt.type, next_schedule_time, evt.handle});
event_queue.update(evt.handle, Event{next_time, event_fifo_id++, evt.type,
next_schedule_time, evt.handle});
}
}
+14 -13
View File
@@ -22,17 +22,25 @@ namespace Core::Timing {
/// A callback that may be scheduled for a particular core timing event.
using TimedCallback = std::function<std::optional<std::chrono::nanoseconds>(
std::uintptr_t user_data, s64 time, std::chrono::nanoseconds ns_late)>;
s64 time, std::chrono::nanoseconds ns_late)>;
/// Contains the characteristics of a particular event.
struct EventType {
explicit EventType(TimedCallback&& callback_, std::string&& name_)
: callback{std::move(callback_)}, name{std::move(name_)} {}
: callback{std::move(callback_)}, name{std::move(name_)}, sequence_number{0} {}
/// The event's callback function.
TimedCallback callback;
/// A pointer to the name of the event.
const std::string name;
/// A monotonic sequence number, incremented when this event is
/// changed externally.
size_t sequence_number;
};
enum class UnscheduleEventType {
Wait,
NoWait,
};
/**
@@ -89,23 +97,17 @@ public:
/// Schedules an event in core timing
void ScheduleEvent(std::chrono::nanoseconds ns_into_future,
const std::shared_ptr<EventType>& event_type, std::uintptr_t user_data = 0,
bool absolute_time = false);
const std::shared_ptr<EventType>& event_type, bool absolute_time = false);
/// Schedules an event which will automatically re-schedule itself with the given time, until
/// unscheduled
void ScheduleLoopingEvent(std::chrono::nanoseconds start_time,
std::chrono::nanoseconds resched_time,
const std::shared_ptr<EventType>& event_type,
std::uintptr_t user_data = 0, bool absolute_time = false);
bool absolute_time = false);
void UnscheduleEvent(const std::shared_ptr<EventType>& event_type, std::uintptr_t user_data,
bool wait = true);
void UnscheduleEventWithoutWait(const std::shared_ptr<EventType>& event_type,
std::uintptr_t user_data) {
UnscheduleEvent(event_type, user_data, false);
}
void UnscheduleEvent(const std::shared_ptr<EventType>& event_type,
UnscheduleEventType type = UnscheduleEventType::Wait);
void AddTicks(u64 ticks_to_add);
@@ -158,7 +160,6 @@ private:
heap_t event_queue;
u64 event_fifo_id = 0;
std::shared_ptr<EventType> ev_lost;
Common::Event event{};
Common::Event pause_event{};
mutable std::mutex basic_lock;
+7
View File
@@ -73,6 +73,9 @@ VirtualFile PatchIPS(const VirtualFile& in, const VirtualFile& ips) {
return nullptr;
auto in_data = in->ReadAllBytes();
if (in_data.size() == 0) {
return nullptr;
}
std::vector<u8> temp(type == IPSFileType::IPS ? 3 : 4);
u64 offset = 5; // After header
@@ -88,6 +91,10 @@ VirtualFile PatchIPS(const VirtualFile& in, const VirtualFile& ips) {
else
real_offset = (temp[0] << 16) | (temp[1] << 8) | temp[2];
if (real_offset > in_data.size()) {
return nullptr;
}
u16 data_size{};
if (ips->ReadObject(&data_size, offset) != sizeof(u16))
return nullptr;
+5 -1
View File
@@ -166,6 +166,10 @@ u32 ProgramMetadata::GetSystemResourceSize() const {
return npdm_header.system_resource_size;
}
PoolPartition ProgramMetadata::GetPoolPartition() const {
return acid_header.pool_partition;
}
const ProgramMetadata::KernelCapabilityDescriptors& ProgramMetadata::GetKernelCapabilities() const {
return aci_kernel_capabilities;
}
@@ -201,7 +205,7 @@ void ProgramMetadata::Print() const {
// Begin ACID printing (potential perms, signed)
LOG_DEBUG(Service_FS, "Magic: {:.4}", acid_header.magic.data());
LOG_DEBUG(Service_FS, "Flags: 0x{:02X}", acid_header.flags);
LOG_DEBUG(Service_FS, " > Is Retail: {}", acid_header.is_retail ? "YES" : "NO");
LOG_DEBUG(Service_FS, " > Is Retail: {}", acid_header.production_flag ? "YES" : "NO");
LOG_DEBUG(Service_FS, "Title ID Min: 0x{:016X}", acid_header.title_id_min);
LOG_DEBUG(Service_FS, "Title ID Max: 0x{:016X}", acid_header.title_id_max);
LOG_DEBUG(Service_FS, "Filesystem Access: 0x{:016X}\n", acid_file_access.permissions);

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