Compare commits
49 Commits
__refs_pul
...
__refs_pul
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
63a0a1f826 | ||
|
|
9e0d6f7d54 | ||
|
|
13755c0903 | ||
|
|
833306bf5e | ||
|
|
90d76333da | ||
|
|
e32ce6cc69 | ||
|
|
190748546d | ||
|
|
79e289404b | ||
|
|
a6e467cd55 | ||
|
|
8a87a41f2d | ||
|
|
f02226283e | ||
|
|
82568412f6 | ||
|
|
1255196731 | ||
|
|
9ce5d39829 | ||
|
|
f80edad109 | ||
|
|
738b37e508 | ||
|
|
82a105e2f8 | ||
|
|
d6a9ed32e6 | ||
|
|
e3937fe8ad | ||
|
|
c652e42492 | ||
|
|
eacec2ae12 | ||
|
|
45ea712d39 | ||
|
|
f463ef7dae | ||
|
|
95c5b715b1 | ||
|
|
8bf46f48f8 | ||
|
|
9d7671ec3b | ||
|
|
5d0a051abb | ||
|
|
4c84bce171 | ||
|
|
302a735135 | ||
|
|
d8eb37fbec | ||
|
|
ef7d44e243 | ||
|
|
f71140fbd9 | ||
|
|
0792139a5f | ||
|
|
4467fd9993 | ||
|
|
1462db4694 | ||
|
|
44af2e32a4 | ||
|
|
3c88547c74 | ||
|
|
1fe003113e | ||
|
|
cef7aaa8ec | ||
|
|
005f0eb083 | ||
|
|
b41006004b | ||
|
|
408a9cd50d | ||
|
|
9cd698e8ad | ||
|
|
68f6f2671b | ||
|
|
ad1946b893 | ||
|
|
14ea16e499 | ||
|
|
22263787e3 | ||
|
|
ddcd89afd4 | ||
|
|
dfa040502a |
@@ -56,7 +56,6 @@ for i in package/*.exe; do
|
||||
x86_64-w64-mingw32-strip "${i}"
|
||||
done
|
||||
|
||||
pip3 install pefile
|
||||
python3 .ci/scripts/windows/scan_dll.py package/*.exe package/imageformats/*.dll "package/"
|
||||
|
||||
# copy FFmpeg libraries
|
||||
|
||||
33
.ci/scripts/windows/install-vulkan-sdk.ps1
Normal file
33
.ci/scripts/windows/install-vulkan-sdk.ps1
Normal file
@@ -0,0 +1,33 @@
|
||||
# SPDX-FileCopyrightText: 2023 yuzu Emulator Project
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
$ErrorActionPreference = "Stop"
|
||||
|
||||
$VulkanSDKVer = "1.3.250.1"
|
||||
$ExeFile = "VulkanSDK-$VulkanSDKVer-Installer.exe"
|
||||
$Uri = "https://sdk.lunarg.com/sdk/download/$VulkanSDKVer/windows/$ExeFile"
|
||||
$Destination = "./$ExeFile"
|
||||
|
||||
echo "Downloading Vulkan SDK $VulkanSDKVer from $Uri"
|
||||
$WebClient = New-Object System.Net.WebClient
|
||||
$WebClient.DownloadFile($Uri, $Destination)
|
||||
echo "Finished downloading $ExeFile"
|
||||
|
||||
$VULKAN_SDK = "C:/VulkanSDK/$VulkanSDKVer"
|
||||
$Arguments = "--root `"$VULKAN_SDK`" --accept-licenses --default-answer --confirm-command install"
|
||||
|
||||
echo "Installing Vulkan SDK $VulkanSDKVer"
|
||||
$InstallProcess = Start-Process -FilePath $Destination -NoNewWindow -PassThru -Wait -ArgumentList $Arguments
|
||||
$ExitCode = $InstallProcess.ExitCode
|
||||
|
||||
if ($ExitCode -ne 0) {
|
||||
echo "Error installing Vulkan SDK $VulkanSDKVer (Error: $ExitCode)"
|
||||
Exit $ExitCode
|
||||
}
|
||||
|
||||
echo "Finished installing Vulkan SDK $VulkanSDKVer"
|
||||
|
||||
if ("$env:GITHUB_ACTIONS" -eq "true") {
|
||||
echo "VULKAN_SDK=$VULKAN_SDK" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append
|
||||
echo "$VULKAN_SDK/Bin" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append
|
||||
}
|
||||
@@ -7,9 +7,12 @@ parameters:
|
||||
version: ''
|
||||
|
||||
steps:
|
||||
- script: choco install vulkan-sdk
|
||||
displayName: 'Install vulkan-sdk'
|
||||
- script: refreshenv && mkdir build && cd build && cmake -E env CXXFLAGS="/Gw /GA /Gr /Ob2" cmake -G "Visual Studio 17 2022" -A x64 -DCMAKE_POLICY_DEFAULT_CMP0069=NEW -DYUZU_ENABLE_LTO=ON -DYUZU_USE_BUNDLED_QT=1 -DYUZU_USE_BUNDLED_SDL2=1 -DYUZU_USE_QT_WEB_ENGINE=ON -DENABLE_COMPATIBILITY_LIST_DOWNLOAD=ON -DYUZU_ENABLE_COMPATIBILITY_REPORTING=${COMPAT} -DYUZU_TESTS=OFF -DUSE_DISCORD_PRESENCE=ON -DENABLE_QT_TRANSLATION=ON -DDISPLAY_VERSION=${{ parameters['version'] }} -DCMAKE_BUILD_TYPE=Release -DYUZU_CRASH_DUMPS=ON .. && cd ..
|
||||
- task: Powershell@2
|
||||
displayName: 'Install Vulkan SDK'
|
||||
inputs:
|
||||
targetType: 'filePath'
|
||||
filePath: './.ci/scripts/windows/install-vulkan-sdk.ps1'
|
||||
- script: refreshenv && glslangValidator --version && mkdir build && cd build && cmake -E env CXXFLAGS="/Gw /GA /Gr /Ob2" cmake -G "Visual Studio 17 2022" -A x64 -DCMAKE_POLICY_DEFAULT_CMP0069=NEW -DYUZU_ENABLE_LTO=ON -DYUZU_USE_BUNDLED_QT=1 -DYUZU_USE_BUNDLED_SDL2=1 -DYUZU_USE_QT_WEB_ENGINE=ON -DENABLE_COMPATIBILITY_LIST_DOWNLOAD=ON -DYUZU_ENABLE_COMPATIBILITY_REPORTING=${COMPAT} -DYUZU_TESTS=OFF -DUSE_DISCORD_PRESENCE=ON -DENABLE_QT_TRANSLATION=ON -DDISPLAY_VERSION=${{ parameters['version'] }} -DCMAKE_BUILD_TYPE=Release -DYUZU_CRASH_DUMPS=ON .. && cd ..
|
||||
displayName: 'Configure CMake'
|
||||
- task: MSBuild@1
|
||||
displayName: 'Build'
|
||||
|
||||
80
.github/workflows/android-build.yml
vendored
Normal file
80
.github/workflows/android-build.yml
vendored
Normal file
@@ -0,0 +1,80 @@
|
||||
# SPDX-FileCopyrightText: 2022 yuzu Emulator Project
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
name: 'yuzu-android-build'
|
||||
|
||||
on:
|
||||
push:
|
||||
tags: [ "*" ]
|
||||
|
||||
jobs:
|
||||
android:
|
||||
runs-on: ubuntu-latest
|
||||
if: ${{ github.repository == 'yuzu-emu/yuzu-android' }}
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
submodules: recursive
|
||||
fetch-depth: 0
|
||||
- name: Set up JDK 17
|
||||
uses: actions/setup-java@v3
|
||||
with:
|
||||
java-version: '17'
|
||||
distribution: 'temurin'
|
||||
- name: Set up cache
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: |
|
||||
~/.gradle/caches
|
||||
~/.gradle/wrapper
|
||||
~/.ccache
|
||||
key: ${{ runner.os }}-android-${{ github.sha }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-android-
|
||||
- name: Query tag name
|
||||
uses: olegtarasov/get-tag@v2.1.2
|
||||
id: tagName
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y ccache apksigner glslang-dev glslang-tools
|
||||
- name: Build
|
||||
run: ./.ci/scripts/android/build.sh
|
||||
- name: Copy and sign artifacts
|
||||
env:
|
||||
ANDROID_KEYSTORE_B64: ${{ secrets.ANDROID_KEYSTORE_B64 }}
|
||||
ANDROID_KEY_ALIAS: ${{ secrets.ANDROID_KEY_ALIAS }}
|
||||
ANDROID_KEYSTORE_PASS: ${{ secrets.ANDROID_KEYSTORE_PASS }}
|
||||
run: ./.ci/scripts/android/upload.sh
|
||||
- name: Upload
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: android
|
||||
path: artifacts/
|
||||
# release steps
|
||||
release-android:
|
||||
runs-on: ubuntu-latest
|
||||
needs: [android]
|
||||
if: ${{ startsWith(github.ref, 'refs/tags/') }}
|
||||
permissions:
|
||||
contents: write
|
||||
steps:
|
||||
- uses: actions/download-artifact@v3
|
||||
- name: Query tag name
|
||||
uses: olegtarasov/get-tag@v2.1.2
|
||||
id: tagName
|
||||
- name: Create release
|
||||
uses: actions/create-release@v1
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
tag_name: ${{ steps.tagName.outputs.tag }}
|
||||
release_name: ${{ steps.tagName.outputs.tag }}
|
||||
draft: false
|
||||
prerelease: false
|
||||
- name: Upload artifacts
|
||||
uses: alexellis/upload-assets@0.2.3
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
asset_paths: '["./**/*.apk","./**/*.aab"]'
|
||||
218
.github/workflows/android-merge.js
vendored
Normal file
218
.github/workflows/android-merge.js
vendored
Normal file
@@ -0,0 +1,218 @@
|
||||
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
// Note: This is a GitHub Actions script
|
||||
// It is not meant to be executed directly on your machine without modifications
|
||||
|
||||
const fs = require("fs");
|
||||
// which label to check for changes
|
||||
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) {
|
||||
// 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) {
|
||||
ref(qualifiedName:$ref) {
|
||||
target {
|
||||
... on Commit { id pushedDate oid }
|
||||
}
|
||||
}
|
||||
}
|
||||
}`;
|
||||
const variables = {
|
||||
owner: context.repo.owner,
|
||||
name: context.repo.repo,
|
||||
ref: 'refs/heads/master',
|
||||
};
|
||||
const result = await github.graphql(query, variables);
|
||||
const pushedAt = result.repository.ref.target.pushedDate;
|
||||
console.log(`Last commit pushed at ${pushedAt}.`);
|
||||
const delta = new Date() - new Date(pushedAt);
|
||||
if (delta <= DETECTION_TIME_FRAME) {
|
||||
console.info('New changes detected, triggering a new build.');
|
||||
return true;
|
||||
}
|
||||
console.info('No new changes detected.');
|
||||
return false;
|
||||
}
|
||||
|
||||
async function checkAndroidChanges(github, context) {
|
||||
if (checkBaseChanges(github, context)) return true;
|
||||
const query = `query($owner:String!, $name:String!, $label:String!) {
|
||||
repository(name:$name, owner:$owner) {
|
||||
pullRequests(labels: [$label], states: OPEN, first: 100) {
|
||||
nodes { number headRepository { pushedAt } }
|
||||
}
|
||||
}
|
||||
}`;
|
||||
const variables = {
|
||||
owner: context.repo.owner,
|
||||
name: context.repo.repo,
|
||||
label: CHANGE_LABEL,
|
||||
};
|
||||
const result = await github.graphql(query, variables);
|
||||
const pulls = result.repository.pullRequests.nodes;
|
||||
for (let i = 0; i < pulls.length; i++) {
|
||||
let pull = pulls[i];
|
||||
if (new Date() - new Date(pull.headRepository.pushedAt) <= DETECTION_TIME_FRAME) {
|
||||
console.info(`${pull.number} updated at ${pull.headRepository.pushedAt}`);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
console.info("No changes detected in any tagged pull requests.");
|
||||
return false;
|
||||
}
|
||||
|
||||
async function tagAndPush(github, owner, repo, execa, commit=false) {
|
||||
let altToken = process.env.ALT_GITHUB_TOKEN;
|
||||
if (!altToken) {
|
||||
throw `Please set ALT_GITHUB_TOKEN environment variable. This token should have write access to ${owner}/${repo}.`;
|
||||
}
|
||||
const query = `query ($owner:String!, $name:String!) {
|
||||
repository(name:$name, owner:$owner) {
|
||||
refs(refPrefix: "refs/tags/", orderBy: {field: TAG_COMMIT_DATE, direction: DESC}, first: 10) {
|
||||
nodes { name }
|
||||
}
|
||||
}
|
||||
}`;
|
||||
const variables = {
|
||||
owner: owner,
|
||||
name: repo,
|
||||
};
|
||||
const tags = await github.graphql(query, variables);
|
||||
const tagList = tags.repository.refs.nodes;
|
||||
const lastTag = tagList[0] ? tagList[0].name : 'dummy-0';
|
||||
const tagNumber = /\w+-(\d+)/.exec(lastTag)[1] | 0;
|
||||
const channel = repo.split('-')[1];
|
||||
const newTag = `${channel}-${tagNumber + 1}`;
|
||||
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('Pushing tags to GitHub ...');
|
||||
await execa("git", ['tag', newTag]);
|
||||
await execa("git", ['remote', 'add', 'target', `https://${altToken}@github.com/${owner}/${repo}.git`]);
|
||||
await execa("git", ['push', 'target', 'master', '-f']);
|
||||
await execa("git", ['push', 'target', 'master', '--tags']);
|
||||
console.info('Successfully pushed new changes.');
|
||||
}
|
||||
|
||||
async function generateReadme(pulls, context, mergeResults, execa) {
|
||||
let baseUrl = `https://github.com/${context.repo.owner}/${context.repo.repo}/`;
|
||||
let output =
|
||||
"| Pull Request | Commit | Title | Author | Merged? |\n|----|----|----|----|----|\n";
|
||||
for (let pull of pulls) {
|
||||
let pr = pull.number;
|
||||
let result = mergeResults[pr];
|
||||
output += `| [${pr}](${baseUrl}/pull/${pr}) | [\`${result.rev || "N/A"}\`](${baseUrl}/pull/${pr}/files) | ${pull.title} | [${pull.author.login}](https://github.com/${pull.author.login}/) | ${result.success ? "Yes" : "No"} |\n`;
|
||||
}
|
||||
output +=
|
||||
"\n\nEnd of merge log. You can find the original README.md below the break.\n\n-----\n\n";
|
||||
output += fs.readFileSync("./README.md");
|
||||
fs.writeFileSync("./README.md", output);
|
||||
await execa("git", ["add", "README.md"]);
|
||||
}
|
||||
|
||||
async function fetchPullRequests(pulls, repoUrl, execa) {
|
||||
console.log("::group::Fetch pull requests");
|
||||
for (let pull of pulls) {
|
||||
let pr = pull.number;
|
||||
console.info(`Fetching PR ${pr} ...`);
|
||||
await execa("git", [
|
||||
"fetch",
|
||||
"-f",
|
||||
"--no-recurse-submodules",
|
||||
repoUrl,
|
||||
`pull/${pr}/head:pr-${pr}`,
|
||||
]);
|
||||
}
|
||||
console.log("::endgroup::");
|
||||
}
|
||||
|
||||
async function mergePullRequests(pulls, execa) {
|
||||
let mergeResults = {};
|
||||
console.log("::group::Merge pull requests");
|
||||
await execa("git", ["config", "--global", "user.name", "yuzubot"]);
|
||||
await execa("git", [
|
||||
"config",
|
||||
"--global",
|
||||
"user.email",
|
||||
"yuzu\x40yuzu-emu\x2eorg", // prevent email harvesters from scraping the address
|
||||
]);
|
||||
let hasFailed = false;
|
||||
for (let pull of pulls) {
|
||||
let pr = pull.number;
|
||||
console.info(`Merging PR ${pr} ...`);
|
||||
try {
|
||||
const process1 = execa("git", [
|
||||
"merge",
|
||||
"--squash",
|
||||
"--no-edit",
|
||||
`pr-${pr}`,
|
||||
]);
|
||||
process1.stdout.pipe(process.stdout);
|
||||
await process1;
|
||||
|
||||
const process2 = execa("git", ["commit", "-m", `Merge PR ${pr}`]);
|
||||
process2.stdout.pipe(process.stdout);
|
||||
await process2;
|
||||
|
||||
const process3 = await execa("git", ["rev-parse", "--short", `pr-${pr}`]);
|
||||
mergeResults[pr] = {
|
||||
success: true,
|
||||
rev: process3.stdout,
|
||||
};
|
||||
} catch (err) {
|
||||
console.log(
|
||||
`::error title=#${pr} not merged::Failed to merge pull request: ${pr}: ${err}`
|
||||
);
|
||||
mergeResults[pr] = { success: false };
|
||||
hasFailed = true;
|
||||
await execa("git", ["reset", "--hard"]);
|
||||
}
|
||||
}
|
||||
console.log("::endgroup::");
|
||||
if (hasFailed) {
|
||||
throw 'There are merge failures. Aborting!';
|
||||
}
|
||||
return mergeResults;
|
||||
}
|
||||
|
||||
async function mergebot(github, context, execa) {
|
||||
const query = `query ($owner:String!, $name:String!, $label:String!) {
|
||||
repository(name:$name, owner:$owner) {
|
||||
pullRequests(labels: [$label], states: OPEN, first: 100) {
|
||||
nodes {
|
||||
number title author { login }
|
||||
}
|
||||
}
|
||||
}
|
||||
}`;
|
||||
const variables = {
|
||||
owner: context.repo.owner,
|
||||
name: context.repo.repo,
|
||||
label: CHANGE_LABEL,
|
||||
};
|
||||
const result = await github.graphql(query, variables);
|
||||
const pulls = result.repository.pullRequests.nodes;
|
||||
let displayList = [];
|
||||
for (let i = 0; i < pulls.length; i++) {
|
||||
let pull = pulls[i];
|
||||
displayList.push({ PR: pull.number, Title: pull.title });
|
||||
}
|
||||
console.info("The following pull requests will be merged:");
|
||||
console.table(displayList);
|
||||
await fetchPullRequests(pulls, "https://github.com/yuzu-emu/yuzu", execa);
|
||||
const mergeResults = await mergePullRequests(pulls, execa);
|
||||
await generateReadme(pulls, context, mergeResults, execa);
|
||||
await tagAndPush(github, context.repo.owner, `${context.repo.repo}-android`, execa, true);
|
||||
}
|
||||
|
||||
module.exports.mergebot = mergebot;
|
||||
module.exports.checkAndroidChanges = checkAndroidChanges;
|
||||
module.exports.tagAndPush = tagAndPush;
|
||||
module.exports.checkBaseChanges = checkBaseChanges;
|
||||
57
.github/workflows/android-publish.yml
vendored
Normal file
57
.github/workflows/android-publish.yml
vendored
Normal file
@@ -0,0 +1,57 @@
|
||||
# SPDX-FileCopyrightText: 2023 yuzu Emulator Project
|
||||
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
name: yuzu-android-publish
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: '37 0 * * *'
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
android:
|
||||
description: 'Whether to trigger an Android build (true/false/auto)'
|
||||
required: false
|
||||
default: 'true'
|
||||
|
||||
jobs:
|
||||
android:
|
||||
runs-on: ubuntu-latest
|
||||
if: ${{ github.event.inputs.android != 'false' && github.repository == 'yuzu-emu/yuzu' }}
|
||||
steps:
|
||||
# this checkout is required to make sure the GitHub Actions scripts are available
|
||||
- uses: actions/checkout@v3
|
||||
name: Pre-checkout
|
||||
with:
|
||||
submodules: false
|
||||
- uses: actions/github-script@v6
|
||||
id: check-changes
|
||||
name: 'Check for new changes'
|
||||
env:
|
||||
# 24 hours
|
||||
DETECTION_TIME_FRAME: 86400000
|
||||
with:
|
||||
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);
|
||||
- run: npm install execa@5
|
||||
if: ${{ steps.check-changes.outputs.result == 'true' }}
|
||||
- uses: actions/checkout@v3
|
||||
name: Checkout
|
||||
if: ${{ steps.check-changes.outputs.result == 'true' }}
|
||||
with:
|
||||
path: 'yuzu-merge'
|
||||
fetch-depth: 0
|
||||
submodules: true
|
||||
token: ${{ secrets.ALT_GITHUB_TOKEN }}
|
||||
- uses: actions/github-script@v5
|
||||
name: 'Check and merge Android changes'
|
||||
if: ${{ steps.check-changes.outputs.result == 'true' }}
|
||||
env:
|
||||
ALT_GITHUB_TOKEN: ${{ secrets.ALT_GITHUB_TOKEN }}
|
||||
with:
|
||||
script: |
|
||||
const execa = require("execa");
|
||||
const mergebot = require('./.github/workflows/android-merge.js').mergebot;
|
||||
process.chdir('${{ github.workspace }}/yuzu-merge');
|
||||
mergebot(github, context, execa);
|
||||
34
.github/workflows/verify.yml
vendored
34
.github/workflows/verify.yml
vendored
@@ -73,6 +73,10 @@ jobs:
|
||||
needs: format
|
||||
runs-on: windows-2022
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
submodules: recursive
|
||||
fetch-depth: 0
|
||||
- name: Set up cache
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
@@ -81,22 +85,22 @@ jobs:
|
||||
restore-keys: |
|
||||
${{ runner.os }}-msvc-
|
||||
- name: Install dependencies
|
||||
# due to how chocolatey works, only cmd.exe is supported here
|
||||
shell: cmd
|
||||
shell: pwsh
|
||||
run: |
|
||||
choco install vulkan-sdk wget
|
||||
call refreshenv
|
||||
wget https://github.com/mbitsnbites/buildcache/releases/download/v0.27.6/buildcache-windows.zip
|
||||
7z x buildcache-windows.zip
|
||||
copy buildcache\bin\buildcache.exe C:\ProgramData\chocolatey\bin
|
||||
rmdir buildcache
|
||||
echo %PATH% >> %GITHUB_PATH%
|
||||
$ErrorActionPreference = "Stop"
|
||||
$BuildCacheVer = "v0.28.4"
|
||||
$File = "buildcache-windows.zip"
|
||||
$Uri = "https://github.com/mbitsnbites/buildcache/releases/download/$BuildCacheVer/$File"
|
||||
$WebClient = New-Object System.Net.WebClient
|
||||
$WebClient.DownloadFile($Uri, $File)
|
||||
7z x $File
|
||||
$CurrentDir = Convert-Path .
|
||||
echo "$CurrentDir/buildcache/bin" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append
|
||||
- name: Install Vulkan SDK
|
||||
shell: pwsh
|
||||
run: .\.ci\scripts\windows\install-vulkan-sdk.ps1
|
||||
- name: Set up MSVC
|
||||
uses: ilammy/msvc-dev-cmd@v1
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
submodules: recursive
|
||||
fetch-depth: 0
|
||||
- name: Configure
|
||||
env:
|
||||
CC: cl.exe
|
||||
@@ -129,11 +133,12 @@ jobs:
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
submodules: recursive
|
||||
fetch-depth: 0
|
||||
- name: set up JDK 17
|
||||
uses: actions/setup-java@v3
|
||||
with:
|
||||
java-version: '17'
|
||||
distribution: 'adopt'
|
||||
distribution: 'temurin'
|
||||
- name: Set up cache
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
@@ -151,7 +156,6 @@ jobs:
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y ccache apksigner glslang-dev glslang-tools
|
||||
git -C ./externals/vcpkg/ fetch --all --unshallow
|
||||
- name: Build
|
||||
run: ./.ci/scripts/android/build.sh
|
||||
- name: Copy and sign artifacts
|
||||
|
||||
@@ -285,7 +285,7 @@ find_package(ZLIB 1.2 REQUIRED)
|
||||
find_package(zstd 1.5 REQUIRED)
|
||||
|
||||
if (NOT YUZU_USE_EXTERNAL_VULKAN_HEADERS)
|
||||
find_package(Vulkan 1.3.246 REQUIRED)
|
||||
find_package(Vulkan 1.3.256 REQUIRED)
|
||||
endif()
|
||||
|
||||
if (ENABLE_LIBUSB)
|
||||
@@ -489,7 +489,7 @@ if (ENABLE_SDL2)
|
||||
if (YUZU_USE_BUNDLED_SDL2)
|
||||
# Detect toolchain and platform
|
||||
if ((MSVC_VERSION GREATER_EQUAL 1920 AND MSVC_VERSION LESS 1940) AND ARCHITECTURE_x86_64)
|
||||
set(SDL2_VER "SDL2-2.28.0")
|
||||
set(SDL2_VER "SDL2-2.28.1")
|
||||
else()
|
||||
message(FATAL_ERROR "No bundled SDL2 binaries for your toolchain. Disable YUZU_USE_BUNDLED_SDL2 and provide your own.")
|
||||
endif()
|
||||
|
||||
2
externals/SDL
vendored
2
externals/SDL
vendored
Submodule externals/SDL updated: 491fba1d06...116a5344ff
2
externals/Vulkan-Headers
vendored
2
externals/Vulkan-Headers
vendored
Submodule externals/Vulkan-Headers updated: 63af1cf1ee...ed857118e2
@@ -22,7 +22,7 @@ SPDX-License-Identifier: GPL-3.0-or-later
|
||||
android:label="@string/app_name_suffixed"
|
||||
android:icon="@drawable/ic_launcher"
|
||||
android:allowBackup="true"
|
||||
android:hasFragileUserData="true"
|
||||
android:hasFragileUserData="false"
|
||||
android:supportsRtl="true"
|
||||
android:isGame="true"
|
||||
android:localeConfig="@xml/locales_config"
|
||||
@@ -54,6 +54,7 @@ SPDX-License-Identifier: GPL-3.0-or-later
|
||||
<activity
|
||||
android:name="org.yuzu.yuzu_emu.activities.EmulationActivity"
|
||||
android:theme="@style/Theme.Yuzu.Main"
|
||||
android:launchMode="singleTop"
|
||||
android:screenOrientation="userLandscape"
|
||||
android:supportsPictureInPicture="true"
|
||||
android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout|uiMode"
|
||||
|
||||
@@ -112,25 +112,36 @@ class Settings {
|
||||
|
||||
const val PREF_MEMORY_WARNING_SHOWN = "MemoryWarningShown"
|
||||
|
||||
const val PREF_OVERLAY_INIT = "OverlayInit"
|
||||
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
|
||||
)
|
||||
|
||||
const val PREF_CONTROL_SCALE = "controlScale"
|
||||
const val PREF_CONTROL_OPACITY = "controlOpacity"
|
||||
const val PREF_TOUCH_ENABLED = "isTouchEnabled"
|
||||
const val PREF_BUTTON_TOGGLE_0 = "buttonToggle0"
|
||||
const val PREF_BUTTON_TOGGLE_1 = "buttonToggle1"
|
||||
const val PREF_BUTTON_TOGGLE_2 = "buttonToggle2"
|
||||
const val PREF_BUTTON_TOGGLE_3 = "buttonToggle3"
|
||||
const val PREF_BUTTON_TOGGLE_4 = "buttonToggle4"
|
||||
const val PREF_BUTTON_TOGGLE_5 = "buttonToggle5"
|
||||
const val PREF_BUTTON_TOGGLE_6 = "buttonToggle6"
|
||||
const val PREF_BUTTON_TOGGLE_7 = "buttonToggle7"
|
||||
const val PREF_BUTTON_TOGGLE_8 = "buttonToggle8"
|
||||
const val PREF_BUTTON_TOGGLE_9 = "buttonToggle9"
|
||||
const val PREF_BUTTON_TOGGLE_10 = "buttonToggle10"
|
||||
const val PREF_BUTTON_TOGGLE_11 = "buttonToggle11"
|
||||
const val PREF_BUTTON_TOGGLE_12 = "buttonToggle12"
|
||||
const val PREF_BUTTON_TOGGLE_13 = "buttonToggle13"
|
||||
const val PREF_BUTTON_TOGGLE_14 = "buttonToggle14"
|
||||
const val PREF_BUTTON_A = "buttonToggle0"
|
||||
const val PREF_BUTTON_B = "buttonToggle1"
|
||||
const val PREF_BUTTON_X = "buttonToggle2"
|
||||
const val PREF_BUTTON_Y = "buttonToggle3"
|
||||
const val PREF_BUTTON_L = "buttonToggle4"
|
||||
const val PREF_BUTTON_R = "buttonToggle5"
|
||||
const val PREF_BUTTON_ZL = "buttonToggle6"
|
||||
const val PREF_BUTTON_ZR = "buttonToggle7"
|
||||
const val PREF_BUTTON_PLUS = "buttonToggle8"
|
||||
const val PREF_BUTTON_MINUS = "buttonToggle9"
|
||||
const val PREF_BUTTON_DPAD = "buttonToggle10"
|
||||
const val PREF_STICK_L = "buttonToggle11"
|
||||
const val PREF_STICK_R = "buttonToggle12"
|
||||
const val PREF_BUTTON_STICK_L = "buttonToggle13"
|
||||
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"
|
||||
@@ -145,6 +156,30 @@ class Settings {
|
||||
|
||||
private val configFileSectionsMap: MutableMap<String, List<String>> = HashMap()
|
||||
|
||||
val overlayPreferences = listOf(
|
||||
PREF_OVERLAY_VERSION,
|
||||
PREF_CONTROL_SCALE,
|
||||
PREF_CONTROL_OPACITY,
|
||||
PREF_TOUCH_ENABLED,
|
||||
PREF_BUTTON_A,
|
||||
PREF_BUTTON_B,
|
||||
PREF_BUTTON_X,
|
||||
PREF_BUTTON_Y,
|
||||
PREF_BUTTON_L,
|
||||
PREF_BUTTON_R,
|
||||
PREF_BUTTON_ZL,
|
||||
PREF_BUTTON_ZR,
|
||||
PREF_BUTTON_PLUS,
|
||||
PREF_BUTTON_MINUS,
|
||||
PREF_BUTTON_DPAD,
|
||||
PREF_STICK_L,
|
||||
PREF_STICK_R,
|
||||
PREF_BUTTON_HOME,
|
||||
PREF_BUTTON_SCREENSHOT,
|
||||
PREF_BUTTON_STICK_L,
|
||||
PREF_BUTTON_STICK_R
|
||||
)
|
||||
|
||||
const val LayoutOption_Unspecified = 0
|
||||
const val LayoutOption_MobilePortrait = 4
|
||||
const val LayoutOption_MobileLandscape = 5
|
||||
|
||||
@@ -212,9 +212,9 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
||||
}
|
||||
if (!isInFoldableLayout) {
|
||||
if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT) {
|
||||
binding.surfaceInputOverlay.orientation = InputOverlay.PORTRAIT
|
||||
binding.surfaceInputOverlay.layout = InputOverlay.PORTRAIT
|
||||
} else {
|
||||
binding.surfaceInputOverlay.orientation = InputOverlay.LANDSCAPE
|
||||
binding.surfaceInputOverlay.layout = InputOverlay.LANDSCAPE
|
||||
}
|
||||
}
|
||||
if (!binding.surfaceInputOverlay.isInEditMode) {
|
||||
@@ -260,7 +260,9 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
||||
.remove(Settings.PREF_CONTROL_SCALE)
|
||||
.remove(Settings.PREF_CONTROL_OPACITY)
|
||||
.apply()
|
||||
binding.surfaceInputOverlay.post { binding.surfaceInputOverlay.resetButtonPlacement() }
|
||||
binding.surfaceInputOverlay.post {
|
||||
binding.surfaceInputOverlay.resetLayoutVisibilityAndPlacement()
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateShowFpsOverlay() {
|
||||
@@ -337,7 +339,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
||||
binding.inGameMenu.layoutParams.height = it.bounds.bottom
|
||||
|
||||
isInFoldableLayout = true
|
||||
binding.surfaceInputOverlay.orientation = InputOverlay.FOLDABLE
|
||||
binding.surfaceInputOverlay.layout = InputOverlay.FOLDABLE
|
||||
refreshInputOverlay()
|
||||
}
|
||||
}
|
||||
@@ -410,9 +412,9 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
||||
R.id.menu_toggle_controls -> {
|
||||
val preferences =
|
||||
PreferenceManager.getDefaultSharedPreferences(YuzuApplication.appContext)
|
||||
val optionsArray = BooleanArray(15)
|
||||
for (i in 0..14) {
|
||||
optionsArray[i] = preferences.getBoolean("buttonToggle$i", i < 13)
|
||||
val optionsArray = BooleanArray(Settings.overlayPreferences.size)
|
||||
Settings.overlayPreferences.forEachIndexed { i, _ ->
|
||||
optionsArray[i] = preferences.getBoolean("buttonToggle$i", i < 15)
|
||||
}
|
||||
|
||||
val dialog = MaterialAlertDialogBuilder(requireContext())
|
||||
@@ -436,7 +438,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
||||
dialog.getButton(AlertDialog.BUTTON_NEUTRAL)
|
||||
.setOnClickListener {
|
||||
val isChecked = !optionsArray[0]
|
||||
for (i in 0..14) {
|
||||
Settings.overlayPreferences.forEachIndexed { i, _ ->
|
||||
optionsArray[i] = isChecked
|
||||
dialog.listView.setItemChecked(i, isChecked)
|
||||
preferences.edit()
|
||||
|
||||
@@ -51,15 +51,23 @@ class InputOverlay(context: Context, attrs: AttributeSet?) :
|
||||
|
||||
private lateinit var windowInsets: WindowInsets
|
||||
|
||||
var orientation = LANDSCAPE
|
||||
var layout = LANDSCAPE
|
||||
|
||||
override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) {
|
||||
super.onLayout(changed, left, top, right, bottom)
|
||||
|
||||
windowInsets = rootWindowInsets
|
||||
|
||||
if (!preferences.getBoolean("${Settings.PREF_OVERLAY_INIT}$orientation", false)) {
|
||||
defaultOverlay()
|
||||
val overlayVersion = preferences.getInt(Settings.PREF_OVERLAY_VERSION, 0)
|
||||
if (overlayVersion != OVERLAY_VERSION) {
|
||||
resetAllLayouts()
|
||||
} else {
|
||||
val layoutIndex = overlayLayouts.indexOf(layout)
|
||||
val currentLayoutVersion =
|
||||
preferences.getInt(Settings.overlayLayoutPrefs[layoutIndex], 0)
|
||||
if (currentLayoutVersion != overlayLayoutVersions[layoutIndex]) {
|
||||
resetCurrentLayout()
|
||||
}
|
||||
}
|
||||
|
||||
// Load the controls.
|
||||
@@ -266,10 +274,10 @@ class InputOverlay(context: Context, attrs: AttributeSet?) :
|
||||
MotionEvent.ACTION_POINTER_UP -> if (buttonBeingConfigured === button) {
|
||||
// Persist button position by saving new place.
|
||||
saveControlPosition(
|
||||
buttonBeingConfigured!!.buttonId,
|
||||
buttonBeingConfigured!!.prefId,
|
||||
buttonBeingConfigured!!.bounds.centerX(),
|
||||
buttonBeingConfigured!!.bounds.centerY(),
|
||||
orientation
|
||||
layout
|
||||
)
|
||||
buttonBeingConfigured = null
|
||||
}
|
||||
@@ -299,10 +307,10 @@ class InputOverlay(context: Context, attrs: AttributeSet?) :
|
||||
MotionEvent.ACTION_POINTER_UP -> if (dpadBeingConfigured === dpad) {
|
||||
// Persist button position by saving new place.
|
||||
saveControlPosition(
|
||||
dpadBeingConfigured!!.upId,
|
||||
Settings.PREF_BUTTON_DPAD,
|
||||
dpadBeingConfigured!!.bounds.centerX(),
|
||||
dpadBeingConfigured!!.bounds.centerY(),
|
||||
orientation
|
||||
layout
|
||||
)
|
||||
dpadBeingConfigured = null
|
||||
}
|
||||
@@ -330,10 +338,10 @@ class InputOverlay(context: Context, attrs: AttributeSet?) :
|
||||
MotionEvent.ACTION_UP,
|
||||
MotionEvent.ACTION_POINTER_UP -> if (joystickBeingConfigured != null) {
|
||||
saveControlPosition(
|
||||
joystickBeingConfigured!!.buttonId,
|
||||
joystickBeingConfigured!!.prefId,
|
||||
joystickBeingConfigured!!.bounds.centerX(),
|
||||
joystickBeingConfigured!!.bounds.centerY(),
|
||||
orientation
|
||||
layout
|
||||
)
|
||||
joystickBeingConfigured = null
|
||||
}
|
||||
@@ -343,9 +351,9 @@ class InputOverlay(context: Context, attrs: AttributeSet?) :
|
||||
return true
|
||||
}
|
||||
|
||||
private fun addOverlayControls(orientation: String) {
|
||||
private fun addOverlayControls(layout: String) {
|
||||
val windowSize = getSafeScreenSize(context)
|
||||
if (preferences.getBoolean(Settings.PREF_BUTTON_TOGGLE_0, true)) {
|
||||
if (preferences.getBoolean(Settings.PREF_BUTTON_A, true)) {
|
||||
overlayButtons.add(
|
||||
initializeOverlayButton(
|
||||
context,
|
||||
@@ -353,11 +361,12 @@ class InputOverlay(context: Context, attrs: AttributeSet?) :
|
||||
R.drawable.facebutton_a,
|
||||
R.drawable.facebutton_a_depressed,
|
||||
ButtonType.BUTTON_A,
|
||||
orientation
|
||||
Settings.PREF_BUTTON_A,
|
||||
layout
|
||||
)
|
||||
)
|
||||
}
|
||||
if (preferences.getBoolean(Settings.PREF_BUTTON_TOGGLE_1, true)) {
|
||||
if (preferences.getBoolean(Settings.PREF_BUTTON_B, true)) {
|
||||
overlayButtons.add(
|
||||
initializeOverlayButton(
|
||||
context,
|
||||
@@ -365,11 +374,12 @@ class InputOverlay(context: Context, attrs: AttributeSet?) :
|
||||
R.drawable.facebutton_b,
|
||||
R.drawable.facebutton_b_depressed,
|
||||
ButtonType.BUTTON_B,
|
||||
orientation
|
||||
Settings.PREF_BUTTON_B,
|
||||
layout
|
||||
)
|
||||
)
|
||||
}
|
||||
if (preferences.getBoolean(Settings.PREF_BUTTON_TOGGLE_2, true)) {
|
||||
if (preferences.getBoolean(Settings.PREF_BUTTON_X, true)) {
|
||||
overlayButtons.add(
|
||||
initializeOverlayButton(
|
||||
context,
|
||||
@@ -377,11 +387,12 @@ class InputOverlay(context: Context, attrs: AttributeSet?) :
|
||||
R.drawable.facebutton_x,
|
||||
R.drawable.facebutton_x_depressed,
|
||||
ButtonType.BUTTON_X,
|
||||
orientation
|
||||
Settings.PREF_BUTTON_X,
|
||||
layout
|
||||
)
|
||||
)
|
||||
}
|
||||
if (preferences.getBoolean(Settings.PREF_BUTTON_TOGGLE_3, true)) {
|
||||
if (preferences.getBoolean(Settings.PREF_BUTTON_Y, true)) {
|
||||
overlayButtons.add(
|
||||
initializeOverlayButton(
|
||||
context,
|
||||
@@ -389,11 +400,12 @@ class InputOverlay(context: Context, attrs: AttributeSet?) :
|
||||
R.drawable.facebutton_y,
|
||||
R.drawable.facebutton_y_depressed,
|
||||
ButtonType.BUTTON_Y,
|
||||
orientation
|
||||
Settings.PREF_BUTTON_Y,
|
||||
layout
|
||||
)
|
||||
)
|
||||
}
|
||||
if (preferences.getBoolean(Settings.PREF_BUTTON_TOGGLE_4, true)) {
|
||||
if (preferences.getBoolean(Settings.PREF_BUTTON_L, true)) {
|
||||
overlayButtons.add(
|
||||
initializeOverlayButton(
|
||||
context,
|
||||
@@ -401,11 +413,12 @@ class InputOverlay(context: Context, attrs: AttributeSet?) :
|
||||
R.drawable.l_shoulder,
|
||||
R.drawable.l_shoulder_depressed,
|
||||
ButtonType.TRIGGER_L,
|
||||
orientation
|
||||
Settings.PREF_BUTTON_L,
|
||||
layout
|
||||
)
|
||||
)
|
||||
}
|
||||
if (preferences.getBoolean(Settings.PREF_BUTTON_TOGGLE_5, true)) {
|
||||
if (preferences.getBoolean(Settings.PREF_BUTTON_R, true)) {
|
||||
overlayButtons.add(
|
||||
initializeOverlayButton(
|
||||
context,
|
||||
@@ -413,11 +426,12 @@ class InputOverlay(context: Context, attrs: AttributeSet?) :
|
||||
R.drawable.r_shoulder,
|
||||
R.drawable.r_shoulder_depressed,
|
||||
ButtonType.TRIGGER_R,
|
||||
orientation
|
||||
Settings.PREF_BUTTON_R,
|
||||
layout
|
||||
)
|
||||
)
|
||||
}
|
||||
if (preferences.getBoolean(Settings.PREF_BUTTON_TOGGLE_6, true)) {
|
||||
if (preferences.getBoolean(Settings.PREF_BUTTON_ZL, true)) {
|
||||
overlayButtons.add(
|
||||
initializeOverlayButton(
|
||||
context,
|
||||
@@ -425,11 +439,12 @@ class InputOverlay(context: Context, attrs: AttributeSet?) :
|
||||
R.drawable.zl_trigger,
|
||||
R.drawable.zl_trigger_depressed,
|
||||
ButtonType.TRIGGER_ZL,
|
||||
orientation
|
||||
Settings.PREF_BUTTON_ZL,
|
||||
layout
|
||||
)
|
||||
)
|
||||
}
|
||||
if (preferences.getBoolean(Settings.PREF_BUTTON_TOGGLE_7, true)) {
|
||||
if (preferences.getBoolean(Settings.PREF_BUTTON_ZR, true)) {
|
||||
overlayButtons.add(
|
||||
initializeOverlayButton(
|
||||
context,
|
||||
@@ -437,11 +452,12 @@ class InputOverlay(context: Context, attrs: AttributeSet?) :
|
||||
R.drawable.zr_trigger,
|
||||
R.drawable.zr_trigger_depressed,
|
||||
ButtonType.TRIGGER_ZR,
|
||||
orientation
|
||||
Settings.PREF_BUTTON_ZR,
|
||||
layout
|
||||
)
|
||||
)
|
||||
}
|
||||
if (preferences.getBoolean(Settings.PREF_BUTTON_TOGGLE_8, true)) {
|
||||
if (preferences.getBoolean(Settings.PREF_BUTTON_PLUS, true)) {
|
||||
overlayButtons.add(
|
||||
initializeOverlayButton(
|
||||
context,
|
||||
@@ -449,11 +465,12 @@ class InputOverlay(context: Context, attrs: AttributeSet?) :
|
||||
R.drawable.facebutton_plus,
|
||||
R.drawable.facebutton_plus_depressed,
|
||||
ButtonType.BUTTON_PLUS,
|
||||
orientation
|
||||
Settings.PREF_BUTTON_PLUS,
|
||||
layout
|
||||
)
|
||||
)
|
||||
}
|
||||
if (preferences.getBoolean(Settings.PREF_BUTTON_TOGGLE_9, true)) {
|
||||
if (preferences.getBoolean(Settings.PREF_BUTTON_MINUS, true)) {
|
||||
overlayButtons.add(
|
||||
initializeOverlayButton(
|
||||
context,
|
||||
@@ -461,11 +478,12 @@ class InputOverlay(context: Context, attrs: AttributeSet?) :
|
||||
R.drawable.facebutton_minus,
|
||||
R.drawable.facebutton_minus_depressed,
|
||||
ButtonType.BUTTON_MINUS,
|
||||
orientation
|
||||
Settings.PREF_BUTTON_MINUS,
|
||||
layout
|
||||
)
|
||||
)
|
||||
}
|
||||
if (preferences.getBoolean(Settings.PREF_BUTTON_TOGGLE_10, true)) {
|
||||
if (preferences.getBoolean(Settings.PREF_BUTTON_DPAD, true)) {
|
||||
overlayDpads.add(
|
||||
initializeOverlayDpad(
|
||||
context,
|
||||
@@ -473,11 +491,11 @@ class InputOverlay(context: Context, attrs: AttributeSet?) :
|
||||
R.drawable.dpad_standard,
|
||||
R.drawable.dpad_standard_cardinal_depressed,
|
||||
R.drawable.dpad_standard_diagonal_depressed,
|
||||
orientation
|
||||
layout
|
||||
)
|
||||
)
|
||||
}
|
||||
if (preferences.getBoolean(Settings.PREF_BUTTON_TOGGLE_11, true)) {
|
||||
if (preferences.getBoolean(Settings.PREF_STICK_L, true)) {
|
||||
overlayJoysticks.add(
|
||||
initializeOverlayJoystick(
|
||||
context,
|
||||
@@ -487,11 +505,12 @@ class InputOverlay(context: Context, attrs: AttributeSet?) :
|
||||
R.drawable.joystick_depressed,
|
||||
StickType.STICK_L,
|
||||
ButtonType.STICK_L,
|
||||
orientation
|
||||
Settings.PREF_STICK_L,
|
||||
layout
|
||||
)
|
||||
)
|
||||
}
|
||||
if (preferences.getBoolean(Settings.PREF_BUTTON_TOGGLE_12, true)) {
|
||||
if (preferences.getBoolean(Settings.PREF_STICK_R, true)) {
|
||||
overlayJoysticks.add(
|
||||
initializeOverlayJoystick(
|
||||
context,
|
||||
@@ -501,11 +520,12 @@ class InputOverlay(context: Context, attrs: AttributeSet?) :
|
||||
R.drawable.joystick_depressed,
|
||||
StickType.STICK_R,
|
||||
ButtonType.STICK_R,
|
||||
orientation
|
||||
Settings.PREF_STICK_R,
|
||||
layout
|
||||
)
|
||||
)
|
||||
}
|
||||
if (preferences.getBoolean(Settings.PREF_BUTTON_TOGGLE_13, false)) {
|
||||
if (preferences.getBoolean(Settings.PREF_BUTTON_HOME, false)) {
|
||||
overlayButtons.add(
|
||||
initializeOverlayButton(
|
||||
context,
|
||||
@@ -513,11 +533,12 @@ class InputOverlay(context: Context, attrs: AttributeSet?) :
|
||||
R.drawable.facebutton_home,
|
||||
R.drawable.facebutton_home_depressed,
|
||||
ButtonType.BUTTON_HOME,
|
||||
orientation
|
||||
Settings.PREF_BUTTON_HOME,
|
||||
layout
|
||||
)
|
||||
)
|
||||
}
|
||||
if (preferences.getBoolean(Settings.PREF_BUTTON_TOGGLE_14, false)) {
|
||||
if (preferences.getBoolean(Settings.PREF_BUTTON_SCREENSHOT, false)) {
|
||||
overlayButtons.add(
|
||||
initializeOverlayButton(
|
||||
context,
|
||||
@@ -525,7 +546,34 @@ class InputOverlay(context: Context, attrs: AttributeSet?) :
|
||||
R.drawable.facebutton_screenshot,
|
||||
R.drawable.facebutton_screenshot_depressed,
|
||||
ButtonType.BUTTON_CAPTURE,
|
||||
orientation
|
||||
Settings.PREF_BUTTON_SCREENSHOT,
|
||||
layout
|
||||
)
|
||||
)
|
||||
}
|
||||
if (preferences.getBoolean(Settings.PREF_BUTTON_STICK_L, true)) {
|
||||
overlayButtons.add(
|
||||
initializeOverlayButton(
|
||||
context,
|
||||
windowSize,
|
||||
R.drawable.button_l3,
|
||||
R.drawable.button_l3_depressed,
|
||||
ButtonType.STICK_L,
|
||||
Settings.PREF_BUTTON_STICK_L,
|
||||
layout
|
||||
)
|
||||
)
|
||||
}
|
||||
if (preferences.getBoolean(Settings.PREF_BUTTON_STICK_R, true)) {
|
||||
overlayButtons.add(
|
||||
initializeOverlayButton(
|
||||
context,
|
||||
windowSize,
|
||||
R.drawable.button_r3,
|
||||
R.drawable.button_r3_depressed,
|
||||
ButtonType.STICK_R,
|
||||
Settings.PREF_BUTTON_STICK_R,
|
||||
layout
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -539,18 +587,18 @@ class InputOverlay(context: Context, attrs: AttributeSet?) :
|
||||
|
||||
// Add all the enabled overlay items back to the HashSet.
|
||||
if (EmulationMenuSettings.showOverlay) {
|
||||
addOverlayControls(orientation)
|
||||
addOverlayControls(layout)
|
||||
}
|
||||
invalidate()
|
||||
}
|
||||
|
||||
private fun saveControlPosition(sharedPrefsId: Int, x: Int, y: Int, orientation: String) {
|
||||
private fun saveControlPosition(prefId: String, x: Int, y: Int, layout: String) {
|
||||
val windowSize = getSafeScreenSize(context)
|
||||
val min = windowSize.first
|
||||
val max = windowSize.second
|
||||
PreferenceManager.getDefaultSharedPreferences(YuzuApplication.appContext).edit()
|
||||
.putFloat("$sharedPrefsId-X$orientation", (x - min.x).toFloat() / max.x)
|
||||
.putFloat("$sharedPrefsId-Y$orientation", (y - min.y).toFloat() / max.y)
|
||||
.putFloat("$prefId-X$layout", (x - min.x).toFloat() / max.x)
|
||||
.putFloat("$prefId-Y$layout", (y - min.y).toFloat() / max.y)
|
||||
.apply()
|
||||
}
|
||||
|
||||
@@ -558,19 +606,31 @@ class InputOverlay(context: Context, attrs: AttributeSet?) :
|
||||
inEditMode = editMode
|
||||
}
|
||||
|
||||
private fun defaultOverlay() {
|
||||
if (!preferences.getBoolean("${Settings.PREF_OVERLAY_INIT}$orientation", false)) {
|
||||
defaultOverlayByLayout(orientation)
|
||||
}
|
||||
|
||||
resetButtonPlacement()
|
||||
private fun resetCurrentLayout() {
|
||||
defaultOverlayByLayout(layout)
|
||||
val layoutIndex = overlayLayouts.indexOf(layout)
|
||||
preferences.edit()
|
||||
.putBoolean("${Settings.PREF_OVERLAY_INIT}$orientation", true)
|
||||
.putInt(Settings.overlayLayoutPrefs[layoutIndex], overlayLayoutVersions[layoutIndex])
|
||||
.apply()
|
||||
}
|
||||
|
||||
fun resetButtonPlacement() {
|
||||
defaultOverlayByLayout(orientation)
|
||||
private fun resetAllLayouts() {
|
||||
val editor = preferences.edit()
|
||||
overlayLayouts.forEachIndexed { i, layout ->
|
||||
defaultOverlayByLayout(layout)
|
||||
editor.putInt(Settings.overlayLayoutPrefs[i], overlayLayoutVersions[i])
|
||||
}
|
||||
editor.putInt(Settings.PREF_OVERLAY_VERSION, OVERLAY_VERSION)
|
||||
editor.apply()
|
||||
}
|
||||
|
||||
fun resetLayoutVisibilityAndPlacement() {
|
||||
defaultOverlayByLayout(layout)
|
||||
val editor = preferences.edit()
|
||||
Settings.overlayPreferences.forEachIndexed { _, pref ->
|
||||
editor.remove(pref)
|
||||
}
|
||||
editor.apply()
|
||||
refreshControls()
|
||||
}
|
||||
|
||||
@@ -604,7 +664,11 @@ class InputOverlay(context: Context, attrs: AttributeSet?) :
|
||||
R.integer.SWITCH_STICK_R_X,
|
||||
R.integer.SWITCH_STICK_R_Y,
|
||||
R.integer.SWITCH_STICK_L_X,
|
||||
R.integer.SWITCH_STICK_L_Y
|
||||
R.integer.SWITCH_STICK_L_Y,
|
||||
R.integer.SWITCH_BUTTON_STICK_L_X,
|
||||
R.integer.SWITCH_BUTTON_STICK_L_Y,
|
||||
R.integer.SWITCH_BUTTON_STICK_R_X,
|
||||
R.integer.SWITCH_BUTTON_STICK_R_Y
|
||||
)
|
||||
|
||||
private val portraitResources = arrayOf(
|
||||
@@ -637,7 +701,11 @@ class InputOverlay(context: Context, attrs: AttributeSet?) :
|
||||
R.integer.SWITCH_STICK_R_X_PORTRAIT,
|
||||
R.integer.SWITCH_STICK_R_Y_PORTRAIT,
|
||||
R.integer.SWITCH_STICK_L_X_PORTRAIT,
|
||||
R.integer.SWITCH_STICK_L_Y_PORTRAIT
|
||||
R.integer.SWITCH_STICK_L_Y_PORTRAIT,
|
||||
R.integer.SWITCH_BUTTON_STICK_L_X_PORTRAIT,
|
||||
R.integer.SWITCH_BUTTON_STICK_L_Y_PORTRAIT,
|
||||
R.integer.SWITCH_BUTTON_STICK_R_X_PORTRAIT,
|
||||
R.integer.SWITCH_BUTTON_STICK_R_Y_PORTRAIT
|
||||
)
|
||||
|
||||
private val foldableResources = arrayOf(
|
||||
@@ -670,139 +738,159 @@ class InputOverlay(context: Context, attrs: AttributeSet?) :
|
||||
R.integer.SWITCH_STICK_R_X_FOLDABLE,
|
||||
R.integer.SWITCH_STICK_R_Y_FOLDABLE,
|
||||
R.integer.SWITCH_STICK_L_X_FOLDABLE,
|
||||
R.integer.SWITCH_STICK_L_Y_FOLDABLE
|
||||
R.integer.SWITCH_STICK_L_Y_FOLDABLE,
|
||||
R.integer.SWITCH_BUTTON_STICK_L_X_FOLDABLE,
|
||||
R.integer.SWITCH_BUTTON_STICK_L_Y_FOLDABLE,
|
||||
R.integer.SWITCH_BUTTON_STICK_R_X_FOLDABLE,
|
||||
R.integer.SWITCH_BUTTON_STICK_R_Y_FOLDABLE
|
||||
)
|
||||
|
||||
private fun getResourceValue(orientation: String, position: Int): Float {
|
||||
return when (orientation) {
|
||||
private fun getResourceValue(layout: String, position: Int): Float {
|
||||
return when (layout) {
|
||||
PORTRAIT -> resources.getInteger(portraitResources[position]).toFloat() / 1000
|
||||
FOLDABLE -> resources.getInteger(foldableResources[position]).toFloat() / 1000
|
||||
else -> resources.getInteger(landscapeResources[position]).toFloat() / 1000
|
||||
}
|
||||
}
|
||||
|
||||
private fun defaultOverlayByLayout(orientation: String) {
|
||||
private fun defaultOverlayByLayout(layout: String) {
|
||||
// Each value represents the position of the button in relation to the screen size without insets.
|
||||
preferences.edit()
|
||||
.putFloat(
|
||||
ButtonType.BUTTON_A.toString() + "-X$orientation",
|
||||
getResourceValue(orientation, 0)
|
||||
"${Settings.PREF_BUTTON_A}-X$layout",
|
||||
getResourceValue(layout, 0)
|
||||
)
|
||||
.putFloat(
|
||||
ButtonType.BUTTON_A.toString() + "-Y$orientation",
|
||||
getResourceValue(orientation, 1)
|
||||
"${Settings.PREF_BUTTON_A}-Y$layout",
|
||||
getResourceValue(layout, 1)
|
||||
)
|
||||
.putFloat(
|
||||
ButtonType.BUTTON_B.toString() + "-X$orientation",
|
||||
getResourceValue(orientation, 2)
|
||||
"${Settings.PREF_BUTTON_B}-X$layout",
|
||||
getResourceValue(layout, 2)
|
||||
)
|
||||
.putFloat(
|
||||
ButtonType.BUTTON_B.toString() + "-Y$orientation",
|
||||
getResourceValue(orientation, 3)
|
||||
"${Settings.PREF_BUTTON_B}-Y$layout",
|
||||
getResourceValue(layout, 3)
|
||||
)
|
||||
.putFloat(
|
||||
ButtonType.BUTTON_X.toString() + "-X$orientation",
|
||||
getResourceValue(orientation, 4)
|
||||
"${Settings.PREF_BUTTON_X}-X$layout",
|
||||
getResourceValue(layout, 4)
|
||||
)
|
||||
.putFloat(
|
||||
ButtonType.BUTTON_X.toString() + "-Y$orientation",
|
||||
getResourceValue(orientation, 5)
|
||||
"${Settings.PREF_BUTTON_X}-Y$layout",
|
||||
getResourceValue(layout, 5)
|
||||
)
|
||||
.putFloat(
|
||||
ButtonType.BUTTON_Y.toString() + "-X$orientation",
|
||||
getResourceValue(orientation, 6)
|
||||
"${Settings.PREF_BUTTON_Y}-X$layout",
|
||||
getResourceValue(layout, 6)
|
||||
)
|
||||
.putFloat(
|
||||
ButtonType.BUTTON_Y.toString() + "-Y$orientation",
|
||||
getResourceValue(orientation, 7)
|
||||
"${Settings.PREF_BUTTON_Y}-Y$layout",
|
||||
getResourceValue(layout, 7)
|
||||
)
|
||||
.putFloat(
|
||||
ButtonType.TRIGGER_ZL.toString() + "-X$orientation",
|
||||
getResourceValue(orientation, 8)
|
||||
"${Settings.PREF_BUTTON_ZL}-X$layout",
|
||||
getResourceValue(layout, 8)
|
||||
)
|
||||
.putFloat(
|
||||
ButtonType.TRIGGER_ZL.toString() + "-Y$orientation",
|
||||
getResourceValue(orientation, 9)
|
||||
"${Settings.PREF_BUTTON_ZL}-Y$layout",
|
||||
getResourceValue(layout, 9)
|
||||
)
|
||||
.putFloat(
|
||||
ButtonType.TRIGGER_ZR.toString() + "-X$orientation",
|
||||
getResourceValue(orientation, 10)
|
||||
"${Settings.PREF_BUTTON_ZR}-X$layout",
|
||||
getResourceValue(layout, 10)
|
||||
)
|
||||
.putFloat(
|
||||
ButtonType.TRIGGER_ZR.toString() + "-Y$orientation",
|
||||
getResourceValue(orientation, 11)
|
||||
"${Settings.PREF_BUTTON_ZR}-Y$layout",
|
||||
getResourceValue(layout, 11)
|
||||
)
|
||||
.putFloat(
|
||||
ButtonType.DPAD_UP.toString() + "-X$orientation",
|
||||
getResourceValue(orientation, 12)
|
||||
"${Settings.PREF_BUTTON_DPAD}-X$layout",
|
||||
getResourceValue(layout, 12)
|
||||
)
|
||||
.putFloat(
|
||||
ButtonType.DPAD_UP.toString() + "-Y$orientation",
|
||||
getResourceValue(orientation, 13)
|
||||
"${Settings.PREF_BUTTON_DPAD}-Y$layout",
|
||||
getResourceValue(layout, 13)
|
||||
)
|
||||
.putFloat(
|
||||
ButtonType.TRIGGER_L.toString() + "-X$orientation",
|
||||
getResourceValue(orientation, 14)
|
||||
"${Settings.PREF_BUTTON_L}-X$layout",
|
||||
getResourceValue(layout, 14)
|
||||
)
|
||||
.putFloat(
|
||||
ButtonType.TRIGGER_L.toString() + "-Y$orientation",
|
||||
getResourceValue(orientation, 15)
|
||||
"${Settings.PREF_BUTTON_L}-Y$layout",
|
||||
getResourceValue(layout, 15)
|
||||
)
|
||||
.putFloat(
|
||||
ButtonType.TRIGGER_R.toString() + "-X$orientation",
|
||||
getResourceValue(orientation, 16)
|
||||
"${Settings.PREF_BUTTON_R}-X$layout",
|
||||
getResourceValue(layout, 16)
|
||||
)
|
||||
.putFloat(
|
||||
ButtonType.TRIGGER_R.toString() + "-Y$orientation",
|
||||
getResourceValue(orientation, 17)
|
||||
"${Settings.PREF_BUTTON_R}-Y$layout",
|
||||
getResourceValue(layout, 17)
|
||||
)
|
||||
.putFloat(
|
||||
ButtonType.BUTTON_PLUS.toString() + "-X$orientation",
|
||||
getResourceValue(orientation, 18)
|
||||
"${Settings.PREF_BUTTON_PLUS}-X$layout",
|
||||
getResourceValue(layout, 18)
|
||||
)
|
||||
.putFloat(
|
||||
ButtonType.BUTTON_PLUS.toString() + "-Y$orientation",
|
||||
getResourceValue(orientation, 19)
|
||||
"${Settings.PREF_BUTTON_PLUS}-Y$layout",
|
||||
getResourceValue(layout, 19)
|
||||
)
|
||||
.putFloat(
|
||||
ButtonType.BUTTON_MINUS.toString() + "-X$orientation",
|
||||
getResourceValue(orientation, 20)
|
||||
"${Settings.PREF_BUTTON_MINUS}-X$layout",
|
||||
getResourceValue(layout, 20)
|
||||
)
|
||||
.putFloat(
|
||||
ButtonType.BUTTON_MINUS.toString() + "-Y$orientation",
|
||||
getResourceValue(orientation, 21)
|
||||
"${Settings.PREF_BUTTON_MINUS}-Y$layout",
|
||||
getResourceValue(layout, 21)
|
||||
)
|
||||
.putFloat(
|
||||
ButtonType.BUTTON_HOME.toString() + "-X$orientation",
|
||||
getResourceValue(orientation, 22)
|
||||
"${Settings.PREF_BUTTON_HOME}-X$layout",
|
||||
getResourceValue(layout, 22)
|
||||
)
|
||||
.putFloat(
|
||||
ButtonType.BUTTON_HOME.toString() + "-Y$orientation",
|
||||
getResourceValue(orientation, 23)
|
||||
"${Settings.PREF_BUTTON_HOME}-Y$layout",
|
||||
getResourceValue(layout, 23)
|
||||
)
|
||||
.putFloat(
|
||||
ButtonType.BUTTON_CAPTURE.toString() + "-X$orientation",
|
||||
getResourceValue(orientation, 24)
|
||||
"${Settings.PREF_BUTTON_SCREENSHOT}-X$layout",
|
||||
getResourceValue(layout, 24)
|
||||
)
|
||||
.putFloat(
|
||||
ButtonType.BUTTON_CAPTURE.toString() + "-Y$orientation",
|
||||
getResourceValue(orientation, 25)
|
||||
"${Settings.PREF_BUTTON_SCREENSHOT}-Y$layout",
|
||||
getResourceValue(layout, 25)
|
||||
)
|
||||
.putFloat(
|
||||
ButtonType.STICK_R.toString() + "-X$orientation",
|
||||
getResourceValue(orientation, 26)
|
||||
"${Settings.PREF_STICK_R}-X$layout",
|
||||
getResourceValue(layout, 26)
|
||||
)
|
||||
.putFloat(
|
||||
ButtonType.STICK_R.toString() + "-Y$orientation",
|
||||
getResourceValue(orientation, 27)
|
||||
"${Settings.PREF_STICK_R}-Y$layout",
|
||||
getResourceValue(layout, 27)
|
||||
)
|
||||
.putFloat(
|
||||
ButtonType.STICK_L.toString() + "-X$orientation",
|
||||
getResourceValue(orientation, 28)
|
||||
"${Settings.PREF_STICK_L}-X$layout",
|
||||
getResourceValue(layout, 28)
|
||||
)
|
||||
.putFloat(
|
||||
ButtonType.STICK_L.toString() + "-Y$orientation",
|
||||
getResourceValue(orientation, 29)
|
||||
"${Settings.PREF_STICK_L}-Y$layout",
|
||||
getResourceValue(layout, 29)
|
||||
)
|
||||
.putFloat(
|
||||
"${Settings.PREF_BUTTON_STICK_L}-X$layout",
|
||||
getResourceValue(layout, 30)
|
||||
)
|
||||
.putFloat(
|
||||
"${Settings.PREF_BUTTON_STICK_L}-Y$layout",
|
||||
getResourceValue(layout, 31)
|
||||
)
|
||||
.putFloat(
|
||||
"${Settings.PREF_BUTTON_STICK_R}-X$layout",
|
||||
getResourceValue(layout, 32)
|
||||
)
|
||||
.putFloat(
|
||||
"${Settings.PREF_BUTTON_STICK_R}-Y$layout",
|
||||
getResourceValue(layout, 33)
|
||||
)
|
||||
.apply()
|
||||
}
|
||||
@@ -812,12 +900,30 @@ class InputOverlay(context: Context, attrs: AttributeSet?) :
|
||||
}
|
||||
|
||||
companion object {
|
||||
// Increase this number every time there is a breaking change to every overlay layout
|
||||
const val OVERLAY_VERSION = 1
|
||||
|
||||
// Increase the corresponding layout version number whenever that layout has a breaking change
|
||||
private const val LANDSCAPE_OVERLAY_VERSION = 1
|
||||
private const val PORTRAIT_OVERLAY_VERSION = 1
|
||||
private const val FOLDABLE_OVERLAY_VERSION = 1
|
||||
val overlayLayoutVersions = listOf(
|
||||
LANDSCAPE_OVERLAY_VERSION,
|
||||
PORTRAIT_OVERLAY_VERSION,
|
||||
FOLDABLE_OVERLAY_VERSION
|
||||
)
|
||||
|
||||
private val preferences: SharedPreferences =
|
||||
PreferenceManager.getDefaultSharedPreferences(YuzuApplication.appContext)
|
||||
|
||||
const val LANDSCAPE = ""
|
||||
const val LANDSCAPE = "_Landscape"
|
||||
const val PORTRAIT = "_Portrait"
|
||||
const val FOLDABLE = "_Foldable"
|
||||
val overlayLayouts = listOf(
|
||||
LANDSCAPE,
|
||||
PORTRAIT,
|
||||
FOLDABLE
|
||||
)
|
||||
|
||||
/**
|
||||
* Resizes a [Bitmap] by a given scale factor
|
||||
@@ -948,6 +1054,8 @@ class InputOverlay(context: Context, attrs: AttributeSet?) :
|
||||
* @param defaultResId The resource ID of the [Drawable] to get the [Bitmap] of (Default State).
|
||||
* @param pressedResId The resource ID of the [Drawable] to get the [Bitmap] of (Pressed State).
|
||||
* @param buttonId Identifier for determining what type of button the initialized InputOverlayDrawableButton represents.
|
||||
* @param prefId Identifier for determining where a button appears on screen.
|
||||
* @param layout The current screen layout as determined by [LANDSCAPE], [PORTRAIT], or [FOLDABLE].
|
||||
* @return An [InputOverlayDrawableButton] with the correct drawing bounds set.
|
||||
*/
|
||||
private fun initializeOverlayButton(
|
||||
@@ -956,7 +1064,8 @@ class InputOverlay(context: Context, attrs: AttributeSet?) :
|
||||
defaultResId: Int,
|
||||
pressedResId: Int,
|
||||
buttonId: Int,
|
||||
orientation: String
|
||||
prefId: String,
|
||||
layout: String
|
||||
): InputOverlayDrawableButton {
|
||||
// Resources handle for fetching the initial Drawable resource.
|
||||
val res = context.resources
|
||||
@@ -964,17 +1073,20 @@ class InputOverlay(context: Context, attrs: AttributeSet?) :
|
||||
// SharedPreference to retrieve the X and Y coordinates for the InputOverlayDrawableButton.
|
||||
val sPrefs = PreferenceManager.getDefaultSharedPreferences(YuzuApplication.appContext)
|
||||
|
||||
// Decide scale based on button ID and user preference
|
||||
var scale: Float = when (buttonId) {
|
||||
ButtonType.BUTTON_HOME,
|
||||
ButtonType.BUTTON_CAPTURE,
|
||||
ButtonType.BUTTON_PLUS,
|
||||
ButtonType.BUTTON_MINUS -> 0.07f
|
||||
// Decide scale based on button preference ID and user preference
|
||||
var scale: Float = when (prefId) {
|
||||
Settings.PREF_BUTTON_HOME,
|
||||
Settings.PREF_BUTTON_SCREENSHOT,
|
||||
Settings.PREF_BUTTON_PLUS,
|
||||
Settings.PREF_BUTTON_MINUS -> 0.07f
|
||||
|
||||
ButtonType.TRIGGER_L,
|
||||
ButtonType.TRIGGER_R,
|
||||
ButtonType.TRIGGER_ZL,
|
||||
ButtonType.TRIGGER_ZR -> 0.26f
|
||||
Settings.PREF_BUTTON_L,
|
||||
Settings.PREF_BUTTON_R,
|
||||
Settings.PREF_BUTTON_ZL,
|
||||
Settings.PREF_BUTTON_ZR -> 0.26f
|
||||
|
||||
Settings.PREF_BUTTON_STICK_L,
|
||||
Settings.PREF_BUTTON_STICK_R -> 0.155f
|
||||
|
||||
else -> 0.11f
|
||||
}
|
||||
@@ -984,8 +1096,13 @@ class InputOverlay(context: Context, attrs: AttributeSet?) :
|
||||
// Initialize the InputOverlayDrawableButton.
|
||||
val defaultStateBitmap = getBitmap(context, defaultResId, scale)
|
||||
val pressedStateBitmap = getBitmap(context, pressedResId, scale)
|
||||
val overlayDrawable =
|
||||
InputOverlayDrawableButton(res, defaultStateBitmap, pressedStateBitmap, buttonId)
|
||||
val overlayDrawable = InputOverlayDrawableButton(
|
||||
res,
|
||||
defaultStateBitmap,
|
||||
pressedStateBitmap,
|
||||
buttonId,
|
||||
prefId
|
||||
)
|
||||
|
||||
// Get the minimum and maximum coordinates of the screen where the button can be placed.
|
||||
val min = windowSize.first
|
||||
@@ -993,8 +1110,8 @@ class InputOverlay(context: Context, attrs: AttributeSet?) :
|
||||
|
||||
// The X and Y coordinates of the InputOverlayDrawableButton on the InputOverlay.
|
||||
// These were set in the input overlay configuration menu.
|
||||
val xKey = "$buttonId-X$orientation"
|
||||
val yKey = "$buttonId-Y$orientation"
|
||||
val xKey = "$prefId-X$layout"
|
||||
val yKey = "$prefId-Y$layout"
|
||||
val drawableXPercent = sPrefs.getFloat(xKey, 0f)
|
||||
val drawableYPercent = sPrefs.getFloat(yKey, 0f)
|
||||
val drawableX = (drawableXPercent * max.x + min.x).toInt()
|
||||
@@ -1029,7 +1146,8 @@ class InputOverlay(context: Context, attrs: AttributeSet?) :
|
||||
* @param defaultResId The [Bitmap] resource ID of the default state.
|
||||
* @param pressedOneDirectionResId The [Bitmap] resource ID of the pressed state in one direction.
|
||||
* @param pressedTwoDirectionsResId The [Bitmap] resource ID of the pressed state in two directions.
|
||||
* @return the initialized [InputOverlayDrawableDpad]
|
||||
* @param layout The current screen layout as determined by [LANDSCAPE], [PORTRAIT], or [FOLDABLE].
|
||||
* @return The initialized [InputOverlayDrawableDpad]
|
||||
*/
|
||||
private fun initializeOverlayDpad(
|
||||
context: Context,
|
||||
@@ -1037,7 +1155,7 @@ class InputOverlay(context: Context, attrs: AttributeSet?) :
|
||||
defaultResId: Int,
|
||||
pressedOneDirectionResId: Int,
|
||||
pressedTwoDirectionsResId: Int,
|
||||
orientation: String
|
||||
layout: String
|
||||
): InputOverlayDrawableDpad {
|
||||
// Resources handle for fetching the initial Drawable resource.
|
||||
val res = context.resources
|
||||
@@ -1074,8 +1192,8 @@ class InputOverlay(context: Context, attrs: AttributeSet?) :
|
||||
|
||||
// The X and Y coordinates of the InputOverlayDrawableDpad on the InputOverlay.
|
||||
// These were set in the input overlay configuration menu.
|
||||
val drawableXPercent = sPrefs.getFloat("${ButtonType.DPAD_UP}-X$orientation", 0f)
|
||||
val drawableYPercent = sPrefs.getFloat("${ButtonType.DPAD_UP}-Y$orientation", 0f)
|
||||
val drawableXPercent = sPrefs.getFloat("${Settings.PREF_BUTTON_DPAD}-X$layout", 0f)
|
||||
val drawableYPercent = sPrefs.getFloat("${Settings.PREF_BUTTON_DPAD}-Y$layout", 0f)
|
||||
val drawableX = (drawableXPercent * max.x + min.x).toInt()
|
||||
val drawableY = (drawableYPercent * max.y + min.y).toInt()
|
||||
val width = overlayDrawable.width
|
||||
@@ -1107,7 +1225,9 @@ class InputOverlay(context: Context, attrs: AttributeSet?) :
|
||||
* @param pressedResInner Resource ID for the pressed inner image of the joystick.
|
||||
* @param joystick Identifier for which joystick this is.
|
||||
* @param button Identifier for which joystick button this is.
|
||||
* @return the initialized [InputOverlayDrawableJoystick].
|
||||
* @param prefId Identifier for determining where a button appears on screen.
|
||||
* @param layout The current screen layout as determined by [LANDSCAPE], [PORTRAIT], or [FOLDABLE].
|
||||
* @return The initialized [InputOverlayDrawableJoystick].
|
||||
*/
|
||||
private fun initializeOverlayJoystick(
|
||||
context: Context,
|
||||
@@ -1117,7 +1237,8 @@ class InputOverlay(context: Context, attrs: AttributeSet?) :
|
||||
pressedResInner: Int,
|
||||
joystick: Int,
|
||||
button: Int,
|
||||
orientation: String
|
||||
prefId: String,
|
||||
layout: String
|
||||
): InputOverlayDrawableJoystick {
|
||||
// Resources handle for fetching the initial Drawable resource.
|
||||
val res = context.resources
|
||||
@@ -1141,8 +1262,8 @@ class InputOverlay(context: Context, attrs: AttributeSet?) :
|
||||
|
||||
// The X and Y coordinates of the InputOverlayDrawableButton on the InputOverlay.
|
||||
// These were set in the input overlay configuration menu.
|
||||
val drawableXPercent = sPrefs.getFloat("$button-X$orientation", 0f)
|
||||
val drawableYPercent = sPrefs.getFloat("$button-Y$orientation", 0f)
|
||||
val drawableXPercent = sPrefs.getFloat("$prefId-X$layout", 0f)
|
||||
val drawableYPercent = sPrefs.getFloat("$prefId-Y$layout", 0f)
|
||||
val drawableX = (drawableXPercent * max.x + min.x).toInt()
|
||||
val drawableY = (drawableYPercent * max.y + min.y).toInt()
|
||||
val outerScale = 1.66f
|
||||
@@ -1168,7 +1289,8 @@ class InputOverlay(context: Context, attrs: AttributeSet?) :
|
||||
outerRect,
|
||||
innerRect,
|
||||
joystick,
|
||||
button
|
||||
button,
|
||||
prefId
|
||||
)
|
||||
|
||||
// Need to set the image's position
|
||||
|
||||
@@ -24,7 +24,8 @@ class InputOverlayDrawableButton(
|
||||
res: Resources,
|
||||
defaultStateBitmap: Bitmap,
|
||||
pressedStateBitmap: Bitmap,
|
||||
val buttonId: Int
|
||||
val buttonId: Int,
|
||||
val prefId: String
|
||||
) {
|
||||
// The ID value what motion event is tracking
|
||||
var trackId: Int
|
||||
|
||||
@@ -37,7 +37,8 @@ class InputOverlayDrawableJoystick(
|
||||
rectOuter: Rect,
|
||||
rectInner: Rect,
|
||||
val joystickId: Int,
|
||||
val buttonId: Int
|
||||
val buttonId: Int,
|
||||
val prefId: String
|
||||
) {
|
||||
// The ID value what motion event is tracking
|
||||
var trackId = -1
|
||||
|
||||
128
src/android/app/src/main/res/drawable/button_l3.xml
Normal file
128
src/android/app/src/main/res/drawable/button_l3.xml
Normal file
@@ -0,0 +1,128 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:aapt="http://schemas.android.com/aapt"
|
||||
android:width="34.963dp"
|
||||
android:height="37.265dp"
|
||||
android:viewportWidth="34.963"
|
||||
android:viewportHeight="37.265">
|
||||
<path
|
||||
android:fillAlpha="0.5"
|
||||
android:pathData="M19.451,19.024A3.498,3.498 0,0 0,21.165 19.508c1.336,0 1.749,-0.852 1.738,-1.49 0,-1.077 -0.982,-1.537 -1.987,-1.537L20.327,16.481L20.327,15.7L20.901,15.7c0.757,0 1.714,-0.392 1.714,-1.302C22.621,13.785 22.224,13.229 21.271,13.229a2.834,2.834 0,0 0,-1.537 0.529l-0.265,-0.757a3.662,3.662 0,0 1,2.008 -0.59c1.513,0 2.201,0.897 2.201,1.834 0,0.794 -0.474,1.466 -1.421,1.807l0,0.024c0.947,0.19 1.714,0.9 1.714,1.976C23.967,19.27 23.017,20.346 21.165,20.346a3.929,3.929 135,0 1,-1.998 -0.529z"
|
||||
android:strokeAlpha="0.6">
|
||||
<aapt:attr name="android:fillColor">
|
||||
<gradient
|
||||
android:endX="21.568"
|
||||
android:endY="33.938"
|
||||
android:startX="21.568"
|
||||
android:startY="16.14"
|
||||
android:type="linear">
|
||||
<item
|
||||
android:color="#FFC3C4C5"
|
||||
android:offset="0" />
|
||||
<item
|
||||
android:color="#FFC5C6C6"
|
||||
android:offset="0.03" />
|
||||
<item
|
||||
android:color="#FFC7C7C7"
|
||||
android:offset="0.19" />
|
||||
<item
|
||||
android:color="#DBB5B5B5"
|
||||
android:offset="0.44" />
|
||||
<item
|
||||
android:color="#7F878787"
|
||||
android:offset="1" />
|
||||
</gradient>
|
||||
</aapt:attr>
|
||||
</path>
|
||||
<path
|
||||
android:fillAlpha="0.5"
|
||||
android:pathData="M16.062,9.353 L9.624,3.405A1.963,1.963 0,0 1,10.955 0l12.88,0a1.963,1.963 135,0 1,1.323 3.405L18.726,9.353a1.961,1.961 135,0 1,-2.664 0z"
|
||||
android:strokeAlpha="0.6">
|
||||
<aapt:attr name="android:fillColor">
|
||||
<gradient
|
||||
android:endX="17.395"
|
||||
android:endY="18.74"
|
||||
android:startX="17.395"
|
||||
android:startY="-1.296"
|
||||
android:type="linear">
|
||||
<item
|
||||
android:color="#FFC3C4C5"
|
||||
android:offset="0" />
|
||||
<item
|
||||
android:color="#FFC5C6C6"
|
||||
android:offset="0.03" />
|
||||
<item
|
||||
android:color="#FFC7C7C7"
|
||||
android:offset="0.19" />
|
||||
<item
|
||||
android:color="#DBB5B5B5"
|
||||
android:offset="0.44" />
|
||||
<item
|
||||
android:color="#7F878787"
|
||||
android:offset="1" />
|
||||
</gradient>
|
||||
</aapt:attr>
|
||||
</path>
|
||||
<path
|
||||
android:fillAlpha="0.5"
|
||||
android:pathData="m25.79,5.657l0,0a2.09,2.09 45,0 0,0.23 3.262c3.522,2.402 4.762,5.927 4.741,10.52A13.279,13.279 135,0 1,4.206 19.365c0,-4.516 0.931,-7.71 4.374,-10.107a2.098,2.098 0,0 0,0.233 -3.265l0,0a2.101,2.101 135,0 0,-2.646 -0.169C1.433,9.133 -0.266,13.941 0.033,20.233a17.468,17.468 0,0 0,34.925 -0.868c0,-6.006 -1.971,-10.771 -6.585,-13.917a2.088,2.088 45,0 0,-2.582 0.209z"
|
||||
android:strokeAlpha="0.6">
|
||||
<aapt:attr name="android:fillColor">
|
||||
<gradient
|
||||
android:centerX="17.477"
|
||||
android:centerY="19.92"
|
||||
android:gradientRadius="17.201"
|
||||
android:type="radial">
|
||||
<item
|
||||
android:color="#FFC3C4C5"
|
||||
android:offset="0.58" />
|
||||
<item
|
||||
android:color="#FFC6C6C6"
|
||||
android:offset="0.84" />
|
||||
<item
|
||||
android:color="#FFC7C7C7"
|
||||
android:offset="0.88" />
|
||||
<item
|
||||
android:color="#FFC2C2C2"
|
||||
android:offset="0.91" />
|
||||
<item
|
||||
android:color="#FFB5B5B5"
|
||||
android:offset="0.94" />
|
||||
<item
|
||||
android:color="#FF9E9E9E"
|
||||
android:offset="0.98" />
|
||||
<item
|
||||
android:color="#FF8F8F8F"
|
||||
android:offset="1" />
|
||||
</gradient>
|
||||
</aapt:attr>
|
||||
</path>
|
||||
<path
|
||||
android:fillAlpha="0.5"
|
||||
android:pathData="m12.516,12.729l2,0l0,13.822l6.615,0l0,1.68L12.516,28.231Z"
|
||||
android:strokeAlpha="0.6">
|
||||
<aapt:attr name="android:fillColor">
|
||||
<gradient
|
||||
android:endX="16.829"
|
||||
android:endY="46.882"
|
||||
android:startX="16.829"
|
||||
android:startY="20.479"
|
||||
android:type="linear">
|
||||
<item
|
||||
android:color="#FFC3C4C5"
|
||||
android:offset="0" />
|
||||
<item
|
||||
android:color="#FFC5C6C6"
|
||||
android:offset="0.03" />
|
||||
<item
|
||||
android:color="#FFC7C7C7"
|
||||
android:offset="0.19" />
|
||||
<item
|
||||
android:color="#DBB5B5B5"
|
||||
android:offset="0.44" />
|
||||
<item
|
||||
android:color="#7F878787"
|
||||
android:offset="1" />
|
||||
</gradient>
|
||||
</aapt:attr>
|
||||
</path>
|
||||
</vector>
|
||||
@@ -0,0 +1,75 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:aapt="http://schemas.android.com/aapt"
|
||||
android:width="34.963dp"
|
||||
android:height="37.265dp"
|
||||
android:viewportWidth="34.963"
|
||||
android:viewportHeight="37.265">
|
||||
<path
|
||||
android:fillAlpha="0.3"
|
||||
android:fillColor="#151515"
|
||||
android:pathData="M16.062,9.353 L9.624,3.405A1.963,1.963 0,0 1,10.955 0l12.88,0a1.963,1.963 135,0 1,1.323 3.405L18.726,9.353a1.961,1.961 135,0 1,-2.664 0z"
|
||||
android:strokeAlpha="0.3" />
|
||||
<path
|
||||
android:fillAlpha="0.6"
|
||||
android:fillColor="#151515"
|
||||
android:pathData="m25.79,5.657l0,0a2.09,2.09 45,0 0,0.23 3.262c3.522,2.402 4.762,5.927 4.741,10.52A13.279,13.279 135,0 1,4.206 19.365c0,-4.516 0.931,-7.71 4.374,-10.107a2.098,2.098 0,0 0,0.233 -3.265l0,0a2.101,2.101 135,0 0,-2.646 -0.169C1.433,9.133 -0.266,13.941 0.033,20.233a17.468,17.468 0,0 0,34.925 -0.868c0,-6.006 -1.971,-10.771 -6.585,-13.917a2.088,2.088 45,0 0,-2.582 0.209z"
|
||||
android:strokeAlpha="0.6" />
|
||||
<path
|
||||
android:fillAlpha="0.6"
|
||||
android:pathData="M19.451,19.024A3.498,3.498 0,0 0,21.165 19.508c1.336,0 1.749,-0.852 1.738,-1.49 0,-1.077 -0.982,-1.537 -1.987,-1.537L20.327,16.481L20.327,15.7L20.901,15.7c0.757,0 1.714,-0.392 1.714,-1.302C22.621,13.785 22.224,13.229 21.271,13.229a2.834,2.834 0,0 0,-1.537 0.529l-0.265,-0.757a3.662,3.662 0,0 1,2.008 -0.59c1.513,0 2.201,0.897 2.201,1.834 0,0.794 -0.474,1.466 -1.421,1.807l0,0.024c0.947,0.19 1.714,0.9 1.714,1.976C23.967,19.27 23.017,20.346 21.165,20.346a3.929,3.929 135,0 1,-1.998 -0.529z"
|
||||
android:strokeAlpha="0.6">
|
||||
<aapt:attr name="android:fillColor">
|
||||
<gradient
|
||||
android:endX="21.568"
|
||||
android:endY="33.938"
|
||||
android:startX="21.568"
|
||||
android:startY="16.14"
|
||||
android:type="linear">
|
||||
<item
|
||||
android:color="#FFC3C4C5"
|
||||
android:offset="0" />
|
||||
<item
|
||||
android:color="#FFC5C6C6"
|
||||
android:offset="0.03" />
|
||||
<item
|
||||
android:color="#FFC7C7C7"
|
||||
android:offset="0.19" />
|
||||
<item
|
||||
android:color="#DBB5B5B5"
|
||||
android:offset="0.44" />
|
||||
<item
|
||||
android:color="#7F878787"
|
||||
android:offset="1" />
|
||||
</gradient>
|
||||
</aapt:attr>
|
||||
</path>
|
||||
<path
|
||||
android:fillAlpha="0.6"
|
||||
android:pathData="m12.516,12.729l2,0l0,13.822l6.615,0l0,1.68L12.516,28.231Z"
|
||||
android:strokeAlpha="0.6">
|
||||
<aapt:attr name="android:fillColor">
|
||||
<gradient
|
||||
android:endX="16.829"
|
||||
android:endY="46.882"
|
||||
android:startX="16.829"
|
||||
android:startY="20.479"
|
||||
android:type="linear">
|
||||
<item
|
||||
android:color="#FFC3C4C5"
|
||||
android:offset="0" />
|
||||
<item
|
||||
android:color="#FFC5C6C6"
|
||||
android:offset="0.03" />
|
||||
<item
|
||||
android:color="#FFC7C7C7"
|
||||
android:offset="0.19" />
|
||||
<item
|
||||
android:color="#DBB5B5B5"
|
||||
android:offset="0.44" />
|
||||
<item
|
||||
android:color="#7F878787"
|
||||
android:offset="1" />
|
||||
</gradient>
|
||||
</aapt:attr>
|
||||
</path>
|
||||
</vector>
|
||||
128
src/android/app/src/main/res/drawable/button_r3.xml
Normal file
128
src/android/app/src/main/res/drawable/button_r3.xml
Normal file
@@ -0,0 +1,128 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:aapt="http://schemas.android.com/aapt"
|
||||
android:width="34.963dp"
|
||||
android:height="37.265dp"
|
||||
android:viewportWidth="34.963"
|
||||
android:viewportHeight="37.265">
|
||||
<path
|
||||
android:fillAlpha="0.5"
|
||||
android:pathData="m10.781,12.65a19.579,19.579 0,0 1,3.596 -0.302c2.003,0 3.294,0.368 4.199,1.185a3.622,3.622 0,0 1,1.14 2.757c0,1.916 -1.206,3.175 -2.733,3.704l0,0.063c1.119,0.386 1.786,1.421 2.117,2.929 0.474,2.024 0.818,3.424 1.119,3.982l-1.924,0c-0.238,-0.407 -0.561,-1.656 -0.968,-3.466 -0.431,-2.003 -1.206,-2.757 -2.91,-2.82l-1.762,0l0,6.286l-1.873,0zM12.654,19.264l1.916,0c2.003,0 3.273,-1.098 3.273,-2.757 0,-1.873 -1.357,-2.691 -3.336,-2.712a7.649,7.649 0,0 0,-1.852 0.172z"
|
||||
android:strokeAlpha="0.6">
|
||||
<aapt:attr name="android:fillColor">
|
||||
<gradient
|
||||
android:endX="15.506"
|
||||
android:endY="48.977"
|
||||
android:startX="15.506"
|
||||
android:startY="19.659"
|
||||
android:type="linear">
|
||||
<item
|
||||
android:color="#FFC3C4C5"
|
||||
android:offset="0" />
|
||||
<item
|
||||
android:color="#FFC5C6C6"
|
||||
android:offset="0.03" />
|
||||
<item
|
||||
android:color="#FFC7C7C7"
|
||||
android:offset="0.19" />
|
||||
<item
|
||||
android:color="#DBB5B5B5"
|
||||
android:offset="0.44" />
|
||||
<item
|
||||
android:color="#7F878787"
|
||||
android:offset="1" />
|
||||
</gradient>
|
||||
</aapt:attr>
|
||||
</path>
|
||||
<path
|
||||
android:fillAlpha="0.5"
|
||||
android:pathData="M16.062,9.353 L9.624,3.405A1.963,1.963 0,0 1,10.955 0l12.88,0a1.963,1.963 135,0 1,1.323 3.405L18.726,9.353a1.961,1.961 135,0 1,-2.664 0z"
|
||||
android:strokeAlpha="0.6">
|
||||
<aapt:attr name="android:fillColor">
|
||||
<gradient
|
||||
android:endX="17.395"
|
||||
android:endY="18.74"
|
||||
android:startX="17.395"
|
||||
android:startY="-1.296"
|
||||
android:type="linear">
|
||||
<item
|
||||
android:color="#FFC3C4C5"
|
||||
android:offset="0" />
|
||||
<item
|
||||
android:color="#FFC5C6C6"
|
||||
android:offset="0.03" />
|
||||
<item
|
||||
android:color="#FFC7C7C7"
|
||||
android:offset="0.19" />
|
||||
<item
|
||||
android:color="#DBB5B5B5"
|
||||
android:offset="0.44" />
|
||||
<item
|
||||
android:color="#7F878787"
|
||||
android:offset="1" />
|
||||
</gradient>
|
||||
</aapt:attr>
|
||||
</path>
|
||||
<path
|
||||
android:fillAlpha="0.5"
|
||||
android:pathData="m25.79,5.657l0,0a2.09,2.09 45,0 0,0.23 3.262c3.522,2.402 4.762,5.927 4.741,10.52A13.279,13.279 135,0 1,4.206 19.365c0,-4.516 0.931,-7.71 4.374,-10.107a2.098,2.098 0,0 0,0.233 -3.265l0,0a2.101,2.101 135,0 0,-2.646 -0.169C1.433,9.133 -0.266,13.941 0.033,20.233a17.468,17.468 0,0 0,34.925 -0.868c0,-6.006 -1.971,-10.771 -6.585,-13.917a2.088,2.088 45,0 0,-2.582 0.209z"
|
||||
android:strokeAlpha="0.6">
|
||||
<aapt:attr name="android:fillColor">
|
||||
<gradient
|
||||
android:centerX="17.477"
|
||||
android:centerY="19.92"
|
||||
android:gradientRadius="17.201"
|
||||
android:type="radial">
|
||||
<item
|
||||
android:color="#FFC3C4C5"
|
||||
android:offset="0.58" />
|
||||
<item
|
||||
android:color="#FFC6C6C6"
|
||||
android:offset="0.84" />
|
||||
<item
|
||||
android:color="#FFC7C7C7"
|
||||
android:offset="0.88" />
|
||||
<item
|
||||
android:color="#FFC2C2C2"
|
||||
android:offset="0.91" />
|
||||
<item
|
||||
android:color="#FFB5B5B5"
|
||||
android:offset="0.94" />
|
||||
<item
|
||||
android:color="#FF9E9E9E"
|
||||
android:offset="0.98" />
|
||||
<item
|
||||
android:color="#FF8F8F8F"
|
||||
android:offset="1" />
|
||||
</gradient>
|
||||
</aapt:attr>
|
||||
</path>
|
||||
<path
|
||||
android:fillAlpha="0.5"
|
||||
android:pathData="M21.832,19.024A3.498,3.498 0,0 0,23.547 19.508c1.336,0 1.749,-0.852 1.738,-1.49 0,-1.077 -0.982,-1.537 -1.987,-1.537L22.708,16.481L22.708,15.7L23.282,15.7c0.757,0 1.714,-0.392 1.714,-1.302C25.002,13.785 24.605,13.229 23.652,13.229a2.834,2.834 0,0 0,-1.537 0.529l-0.265,-0.757a3.662,3.662 0,0 1,2.008 -0.59c1.513,0 2.201,0.897 2.201,1.834 0,0.794 -0.474,1.466 -1.421,1.807l0,0.024c0.947,0.19 1.714,0.9 1.714,1.976C26.349,19.27 25.399,20.346 23.547,20.346a3.929,3.929 135,0 1,-1.998 -0.529z"
|
||||
android:strokeAlpha="0.6">
|
||||
<aapt:attr name="android:fillColor">
|
||||
<gradient
|
||||
android:endX="23.949"
|
||||
android:endY="33.938"
|
||||
android:startX="23.949"
|
||||
android:startY="16.14"
|
||||
android:type="linear">
|
||||
<item
|
||||
android:color="#FFC3C4C5"
|
||||
android:offset="0" />
|
||||
<item
|
||||
android:color="#FFC5C6C6"
|
||||
android:offset="0.03" />
|
||||
<item
|
||||
android:color="#FFC7C7C7"
|
||||
android:offset="0.19" />
|
||||
<item
|
||||
android:color="#DBB5B5B5"
|
||||
android:offset="0.44" />
|
||||
<item
|
||||
android:color="#7F878787"
|
||||
android:offset="1" />
|
||||
</gradient>
|
||||
</aapt:attr>
|
||||
</path>
|
||||
</vector>
|
||||
@@ -0,0 +1,75 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:aapt="http://schemas.android.com/aapt"
|
||||
android:width="34.963dp"
|
||||
android:height="37.265dp"
|
||||
android:viewportWidth="34.963"
|
||||
android:viewportHeight="37.265">
|
||||
<path
|
||||
android:fillAlpha="0.3"
|
||||
android:fillColor="#151515"
|
||||
android:pathData="M16.062,9.353 L9.624,3.405A1.963,1.963 0,0 1,10.955 0l12.88,0a1.963,1.963 135,0 1,1.323 3.405L18.726,9.353a1.961,1.961 135,0 1,-2.664 0z"
|
||||
android:strokeAlpha="0.3" />
|
||||
<path
|
||||
android:fillAlpha="0.6"
|
||||
android:fillColor="#151515"
|
||||
android:pathData="m25.79,5.657l0,0a2.09,2.09 45,0 0,0.23 3.262c3.522,2.402 4.762,5.927 4.741,10.52A13.279,13.279 135,0 1,4.206 19.365c0,-4.516 0.931,-7.71 4.374,-10.107a2.098,2.098 0,0 0,0.233 -3.265l0,0a2.101,2.101 135,0 0,-2.646 -0.169C1.433,9.133 -0.266,13.941 0.033,20.233a17.468,17.468 0,0 0,34.925 -0.868c0,-6.006 -1.971,-10.771 -6.585,-13.917a2.088,2.088 45,0 0,-2.582 0.209z"
|
||||
android:strokeAlpha="0.6" />
|
||||
<path
|
||||
android:fillAlpha="0.6"
|
||||
android:pathData="m10.781,12.65a19.579,19.579 0,0 1,3.596 -0.302c2.003,0 3.294,0.368 4.199,1.185a3.622,3.622 0,0 1,1.14 2.757c0,1.916 -1.206,3.175 -2.733,3.704l0,0.063c1.119,0.386 1.786,1.421 2.117,2.929 0.474,2.024 0.818,3.424 1.119,3.982l-1.924,0c-0.238,-0.407 -0.561,-1.656 -0.968,-3.466 -0.431,-2.003 -1.206,-2.757 -2.91,-2.82l-1.762,0l0,6.286l-1.873,0zM12.654,19.264l1.916,0c2.003,0 3.273,-1.098 3.273,-2.757 0,-1.873 -1.357,-2.691 -3.336,-2.712a7.649,7.649 0,0 0,-1.852 0.172z"
|
||||
android:strokeAlpha="0.6">
|
||||
<aapt:attr name="android:fillColor">
|
||||
<gradient
|
||||
android:endX="15.506"
|
||||
android:endY="48.977"
|
||||
android:startX="15.506"
|
||||
android:startY="19.659"
|
||||
android:type="linear">
|
||||
<item
|
||||
android:color="#FFC3C4C5"
|
||||
android:offset="0" />
|
||||
<item
|
||||
android:color="#FFC5C6C6"
|
||||
android:offset="0.03" />
|
||||
<item
|
||||
android:color="#FFC7C7C7"
|
||||
android:offset="0.19" />
|
||||
<item
|
||||
android:color="#DBB5B5B5"
|
||||
android:offset="0.44" />
|
||||
<item
|
||||
android:color="#7F878787"
|
||||
android:offset="1" />
|
||||
</gradient>
|
||||
</aapt:attr>
|
||||
</path>
|
||||
<path
|
||||
android:fillAlpha="0.6"
|
||||
android:pathData="M21.832,19.024A3.498,3.498 0,0 0,23.547 19.508c1.336,0 1.749,-0.852 1.738,-1.49 0,-1.077 -0.982,-1.537 -1.987,-1.537L22.708,16.481L22.708,15.7L23.282,15.7c0.757,0 1.714,-0.392 1.714,-1.302C25.002,13.785 24.605,13.229 23.652,13.229a2.834,2.834 0,0 0,-1.537 0.529l-0.265,-0.757a3.662,3.662 0,0 1,2.008 -0.59c1.513,0 2.201,0.897 2.201,1.834 0,0.794 -0.474,1.466 -1.421,1.807l0,0.024c0.947,0.19 1.714,0.9 1.714,1.976C26.349,19.27 25.399,20.346 23.547,20.346a3.929,3.929 135,0 1,-1.998 -0.529z"
|
||||
android:strokeAlpha="0.6">
|
||||
<aapt:attr name="android:fillColor">
|
||||
<gradient
|
||||
android:endX="23.949"
|
||||
android:endY="33.938"
|
||||
android:startX="23.949"
|
||||
android:startY="16.14"
|
||||
android:type="linear">
|
||||
<item
|
||||
android:color="#FFC3C4C5"
|
||||
android:offset="0" />
|
||||
<item
|
||||
android:color="#FFC5C6C6"
|
||||
android:offset="0.03" />
|
||||
<item
|
||||
android:color="#FFC7C7C7"
|
||||
android:offset="0.19" />
|
||||
<item
|
||||
android:color="#DBB5B5B5"
|
||||
android:offset="0.44" />
|
||||
<item
|
||||
android:color="#7F878787"
|
||||
android:offset="1" />
|
||||
</gradient>
|
||||
</aapt:attr>
|
||||
</path>
|
||||
</vector>
|
||||
@@ -205,6 +205,8 @@
|
||||
<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>
|
||||
</string-array>
|
||||
|
||||
@@ -33,6 +33,10 @@
|
||||
<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>
|
||||
|
||||
<!-- Default SWITCH portrait layout -->
|
||||
<integer name="SWITCH_BUTTON_A_X_PORTRAIT">840</integer>
|
||||
@@ -65,6 +69,10 @@
|
||||
<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>
|
||||
|
||||
<!-- Default SWITCH foldable layout -->
|
||||
<integer name="SWITCH_BUTTON_A_X_FOLDABLE">840</integer>
|
||||
@@ -97,5 +105,9 @@
|
||||
<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>
|
||||
|
||||
</resources>
|
||||
|
||||
@@ -26,9 +26,10 @@ std::string GetTimeZoneString() {
|
||||
|
||||
std::string location_name;
|
||||
if (time_zone_index == 0) { // Auto
|
||||
#if __cpp_lib_chrono >= 201907L
|
||||
const struct std::chrono::tzdb& time_zone_data = std::chrono::get_tzdb();
|
||||
#if __cpp_lib_chrono >= 201907L && !defined(MINGW)
|
||||
// Disabled for MinGW -- tzdb always returns Etc/UTC
|
||||
try {
|
||||
const struct std::chrono::tzdb& time_zone_data = std::chrono::get_tzdb();
|
||||
const std::chrono::time_zone* current_zone = time_zone_data.current_zone();
|
||||
std::string_view current_zone_name = current_zone->name();
|
||||
location_name = current_zone_name;
|
||||
|
||||
@@ -4,13 +4,13 @@
|
||||
#include <chrono>
|
||||
#include <exception>
|
||||
#include <iomanip>
|
||||
#include <map>
|
||||
#include <sstream>
|
||||
#include <stdexcept>
|
||||
#include <fmt/chrono.h>
|
||||
#include <fmt/core.h>
|
||||
|
||||
#include "common/logging/log.h"
|
||||
#include "common/settings.h"
|
||||
#include "common/time_zone.h"
|
||||
|
||||
namespace Common::TimeZone {
|
||||
@@ -33,32 +33,29 @@ std::string GetDefaultTimeZone() {
|
||||
return "GMT";
|
||||
}
|
||||
|
||||
static std::string GetOsTimeZoneOffset() {
|
||||
const std::time_t t{std::time(nullptr)};
|
||||
const std::tm tm{*std::localtime(&t)};
|
||||
|
||||
return fmt::format("{:%z}", tm);
|
||||
}
|
||||
|
||||
static int ConvertOsTimeZoneOffsetToInt(const std::string& timezone) {
|
||||
try {
|
||||
return std::stoi(timezone);
|
||||
} catch (const std::invalid_argument&) {
|
||||
LOG_CRITICAL(Common, "invalid_argument with {}!", timezone);
|
||||
return 0;
|
||||
} catch (const std::out_of_range&) {
|
||||
LOG_CRITICAL(Common, "out_of_range with {}!", timezone);
|
||||
return 0;
|
||||
}
|
||||
// Results are not comparable to seconds since Epoch
|
||||
static std::time_t TmSpecToSeconds(const struct std::tm& spec) {
|
||||
const int year = spec.tm_year - 1; // Years up to now
|
||||
const int leap_years = year / 4 - year / 100;
|
||||
std::time_t cumulative = spec.tm_year;
|
||||
cumulative = cumulative * 365 + leap_years + spec.tm_yday; // Years to days
|
||||
cumulative = cumulative * 24 + spec.tm_hour; // Days to hours
|
||||
cumulative = cumulative * 60 + spec.tm_min; // Hours to minutes
|
||||
cumulative = cumulative * 60 + spec.tm_sec; // Minutes to seconds
|
||||
return cumulative;
|
||||
}
|
||||
|
||||
std::chrono::seconds GetCurrentOffsetSeconds() {
|
||||
const int offset{ConvertOsTimeZoneOffsetToInt(GetOsTimeZoneOffset())};
|
||||
const std::time_t t{std::time(nullptr)};
|
||||
const std::tm local{*std::localtime(&t)};
|
||||
const std::tm gmt{*std::gmtime(&t)};
|
||||
|
||||
int seconds{(offset / 100) * 60 * 60}; // Convert hour component to seconds
|
||||
seconds += (offset % 100) * 60; // Convert minute component to seconds
|
||||
// gmt_seconds is a different offset than time(nullptr)
|
||||
const auto gmt_seconds = TmSpecToSeconds(gmt);
|
||||
const auto local_seconds = TmSpecToSeconds(local);
|
||||
const auto seconds_offset = local_seconds - gmt_seconds;
|
||||
|
||||
return std::chrono::seconds{seconds};
|
||||
return std::chrono::seconds{seconds_offset};
|
||||
}
|
||||
|
||||
// Key is [Hours * 100 + Minutes], multiplied by 100 if DST
|
||||
@@ -71,11 +68,6 @@ const static std::map<s64, const char*> off_timezones = {
|
||||
};
|
||||
|
||||
std::string FindSystemTimeZone() {
|
||||
#if defined(MINGW)
|
||||
// MinGW has broken strftime -- https://sourceforge.net/p/mingw-w64/bugs/793/
|
||||
// e.g. fmt::format("{:%z}") -- returns "Eastern Daylight Time" when it should be "-0400"
|
||||
return timezones[0];
|
||||
#else
|
||||
const s64 seconds = static_cast<s64>(GetCurrentOffsetSeconds().count());
|
||||
|
||||
const s64 minutes = seconds / 60;
|
||||
@@ -97,7 +89,6 @@ std::string FindSystemTimeZone() {
|
||||
}
|
||||
}
|
||||
return fmt::format("Etc/GMT{:s}{:d}", hours > 0 ? "-" : "+", std::abs(hours));
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace Common::TimeZone
|
||||
|
||||
@@ -185,7 +185,7 @@ void ARM_Interface::Run() {
|
||||
// Notify the debugger and go to sleep if a breakpoint was hit,
|
||||
// or if the thread is unable to continue for any reason.
|
||||
if (True(hr & HaltReason::InstructionBreakpoint) || True(hr & HaltReason::PrefetchAbort)) {
|
||||
if (!True(hr & HaltReason::InstructionBreakpoint)) {
|
||||
if (!True(hr & HaltReason::PrefetchAbort)) {
|
||||
RewindBreakpointInstruction();
|
||||
}
|
||||
if (system.DebuggerEnabled()) {
|
||||
|
||||
@@ -283,7 +283,8 @@ std::size_t RealVfsFile::GetSize() const {
|
||||
if (size) {
|
||||
return *size;
|
||||
}
|
||||
return FS::GetSize(path);
|
||||
auto lk = base.RefreshReference(path, perms, *reference);
|
||||
return reference->file ? reference->file->GetSize() : 0;
|
||||
}
|
||||
|
||||
bool RealVfsFile::Resize(std::size_t new_size) {
|
||||
|
||||
@@ -1243,10 +1243,12 @@ Common::Input::DriverResult EmulatedController::SetPollingMode(
|
||||
auto& nfc_output_device = output_devices[3];
|
||||
|
||||
if (device_index == EmulatedDeviceIndex::LeftIndex) {
|
||||
controller.left_polling_mode = polling_mode;
|
||||
return left_output_device->SetPollingMode(polling_mode);
|
||||
}
|
||||
|
||||
if (device_index == EmulatedDeviceIndex::RightIndex) {
|
||||
controller.right_polling_mode = polling_mode;
|
||||
const auto virtual_nfc_result = nfc_output_device->SetPollingMode(polling_mode);
|
||||
const auto mapped_nfc_result = right_output_device->SetPollingMode(polling_mode);
|
||||
|
||||
@@ -1261,12 +1263,22 @@ Common::Input::DriverResult EmulatedController::SetPollingMode(
|
||||
return mapped_nfc_result;
|
||||
}
|
||||
|
||||
controller.left_polling_mode = polling_mode;
|
||||
controller.right_polling_mode = polling_mode;
|
||||
left_output_device->SetPollingMode(polling_mode);
|
||||
right_output_device->SetPollingMode(polling_mode);
|
||||
nfc_output_device->SetPollingMode(polling_mode);
|
||||
return Common::Input::DriverResult::Success;
|
||||
}
|
||||
|
||||
Common::Input::PollingMode EmulatedController::GetPollingMode(
|
||||
EmulatedDeviceIndex device_index) const {
|
||||
if (device_index == EmulatedDeviceIndex::LeftIndex) {
|
||||
return controller.left_polling_mode;
|
||||
}
|
||||
return controller.right_polling_mode;
|
||||
}
|
||||
|
||||
bool EmulatedController::SetCameraFormat(
|
||||
Core::IrSensor::ImageTransferProcessorFormat camera_format) {
|
||||
LOG_INFO(Service_HID, "Set camera format {}", camera_format);
|
||||
|
||||
@@ -143,6 +143,8 @@ struct ControllerStatus {
|
||||
CameraState camera_state{};
|
||||
RingSensorForce ring_analog_state{};
|
||||
NfcState nfc_state{};
|
||||
Common::Input::PollingMode left_polling_mode{};
|
||||
Common::Input::PollingMode right_polling_mode{};
|
||||
};
|
||||
|
||||
enum class ControllerTriggerType {
|
||||
@@ -370,6 +372,12 @@ public:
|
||||
*/
|
||||
Common::Input::DriverResult SetPollingMode(EmulatedDeviceIndex device_index,
|
||||
Common::Input::PollingMode polling_mode);
|
||||
/**
|
||||
* Get the current polling mode from a controller
|
||||
* @param device_index index of the controller to set the polling mode
|
||||
* @return current polling mode
|
||||
*/
|
||||
Common::Input::PollingMode GetPollingMode(EmulatedDeviceIndex device_index) const;
|
||||
|
||||
/**
|
||||
* Sets the desired camera format to be polled from a controller
|
||||
|
||||
@@ -66,10 +66,6 @@ NfcDevice::~NfcDevice() {
|
||||
};
|
||||
|
||||
void NfcDevice::NpadUpdate(Core::HID::ControllerTriggerType type) {
|
||||
if (!is_initalized) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (type == Core::HID::ControllerTriggerType::Connected) {
|
||||
Initialize();
|
||||
availability_change_event->Signal();
|
||||
@@ -77,12 +73,12 @@ void NfcDevice::NpadUpdate(Core::HID::ControllerTriggerType type) {
|
||||
}
|
||||
|
||||
if (type == Core::HID::ControllerTriggerType::Disconnected) {
|
||||
device_state = DeviceState::Unavailable;
|
||||
Finalize();
|
||||
availability_change_event->Signal();
|
||||
return;
|
||||
}
|
||||
|
||||
if (type != Core::HID::ControllerTriggerType::Nfc) {
|
||||
if (!is_initalized) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -90,6 +86,17 @@ void NfcDevice::NpadUpdate(Core::HID::ControllerTriggerType type) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Ensure nfc mode is always active
|
||||
if (npad_device->GetPollingMode(Core::HID::EmulatedDeviceIndex::RightIndex) ==
|
||||
Common::Input::PollingMode::Active) {
|
||||
npad_device->SetPollingMode(Core::HID::EmulatedDeviceIndex::RightIndex,
|
||||
Common::Input::PollingMode::NFC);
|
||||
}
|
||||
|
||||
if (type != Core::HID::ControllerTriggerType::Nfc) {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto nfc_status = npad_device->GetNfc();
|
||||
switch (nfc_status.state) {
|
||||
case Common::Input::NfcState::NewAmiibo:
|
||||
@@ -207,11 +214,14 @@ void NfcDevice::Initialize() {
|
||||
}
|
||||
|
||||
void NfcDevice::Finalize() {
|
||||
if (device_state == DeviceState::TagMounted) {
|
||||
Unmount();
|
||||
}
|
||||
if (device_state == DeviceState::SearchingForTag || device_state == DeviceState::TagRemoved) {
|
||||
StopDetection();
|
||||
if (npad_device->IsConnected()) {
|
||||
if (device_state == DeviceState::TagMounted) {
|
||||
Unmount();
|
||||
}
|
||||
if (device_state == DeviceState::SearchingForTag ||
|
||||
device_state == DeviceState::TagRemoved) {
|
||||
StopDetection();
|
||||
}
|
||||
}
|
||||
|
||||
if (device_state != DeviceState::Unavailable) {
|
||||
|
||||
@@ -160,8 +160,9 @@ void Mouse::Move(int x, int y, int center_x, int center_y) {
|
||||
last_mouse_change.y += mouse_change.y * y_sensitivity;
|
||||
|
||||
// Bind the mouse change to [0 <= deadzone_counterweight <= 1.0]
|
||||
if (last_mouse_change.Length() < deadzone_counterweight) {
|
||||
last_mouse_change /= last_mouse_change.Length();
|
||||
const float length = last_mouse_change.Length();
|
||||
if (length < deadzone_counterweight && length != 0.0f) {
|
||||
last_mouse_change /= length;
|
||||
last_mouse_change *= deadzone_counterweight;
|
||||
}
|
||||
|
||||
|
||||
@@ -598,6 +598,10 @@ void TextureCache<P>::UnmapGPUMemory(size_t as_id, GPUVAddr gpu_addr, size_t siz
|
||||
[&](ImageId id, Image&) { deleted_images.push_back(id); });
|
||||
for (const ImageId id : deleted_images) {
|
||||
Image& image = slot_images[id];
|
||||
if (True(image.flags & ImageFlagBits::CpuModified)) {
|
||||
continue;
|
||||
}
|
||||
image.flags |= ImageFlagBits::CpuModified;
|
||||
if (True(image.flags & ImageFlagBits::Remapped)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -485,7 +485,7 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR
|
||||
loaded_extensions.erase(VK_EXT_EXTENDED_DYNAMIC_STATE_EXTENSION_NAME);
|
||||
}
|
||||
}
|
||||
if (extensions.extended_dynamic_state2 && (is_radv || is_qualcomm)) {
|
||||
if (extensions.extended_dynamic_state2 && is_radv) {
|
||||
const u32 version = (properties.properties.driverVersion << 3) >> 3;
|
||||
if (version < VK_MAKE_API_VERSION(0, 22, 3, 1)) {
|
||||
LOG_WARNING(
|
||||
@@ -498,6 +498,20 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR
|
||||
loaded_extensions.erase(VK_EXT_EXTENDED_DYNAMIC_STATE_2_EXTENSION_NAME);
|
||||
}
|
||||
}
|
||||
if (extensions.extended_dynamic_state2 && is_qualcomm) {
|
||||
const u32 version = (properties.properties.driverVersion << 3) >> 3;
|
||||
if (version >= VK_MAKE_API_VERSION(0, 0, 676, 0) &&
|
||||
version < VK_MAKE_API_VERSION(0, 0, 680, 0)) {
|
||||
// Qualcomm Adreno 7xx drivers do not properly support extended_dynamic_state2.
|
||||
LOG_WARNING(Render_Vulkan,
|
||||
"Qualcomm Adreno 7xx drivers have broken VK_EXT_extended_dynamic_state2");
|
||||
features.extended_dynamic_state2.extendedDynamicState2 = false;
|
||||
features.extended_dynamic_state2.extendedDynamicState2LogicOp = false;
|
||||
features.extended_dynamic_state2.extendedDynamicState2PatchControlPoints = false;
|
||||
extensions.extended_dynamic_state2 = false;
|
||||
loaded_extensions.erase(VK_EXT_EXTENDED_DYNAMIC_STATE_2_EXTENSION_NAME);
|
||||
}
|
||||
}
|
||||
if (extensions.extended_dynamic_state3 && is_radv) {
|
||||
LOG_WARNING(Render_Vulkan, "RADV has broken extendedDynamicState3ColorBlendEquation");
|
||||
features.extended_dynamic_state3.extendedDynamicState3ColorBlendEnable = false;
|
||||
@@ -512,8 +526,7 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR
|
||||
dynamic_state3_enables = false;
|
||||
}
|
||||
}
|
||||
if (extensions.vertex_input_dynamic_state && (is_radv || is_qualcomm)) {
|
||||
// Qualcomm S8gen2 drivers do not properly support vertex_input_dynamic_state.
|
||||
if (extensions.vertex_input_dynamic_state && is_radv) {
|
||||
// TODO(ameerj): Blacklist only offending driver versions
|
||||
// TODO(ameerj): Confirm if RDNA1 is affected
|
||||
const bool is_rdna2 =
|
||||
@@ -526,6 +539,19 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR
|
||||
loaded_extensions.erase(VK_EXT_VERTEX_INPUT_DYNAMIC_STATE_EXTENSION_NAME);
|
||||
}
|
||||
}
|
||||
if (extensions.vertex_input_dynamic_state && is_qualcomm) {
|
||||
const u32 version = (properties.properties.driverVersion << 3) >> 3;
|
||||
if (version >= VK_MAKE_API_VERSION(0, 0, 676, 0) &&
|
||||
version < VK_MAKE_API_VERSION(0, 0, 680, 0)) {
|
||||
// Qualcomm Adreno 7xx drivers do not properly support vertex_input_dynamic_state.
|
||||
LOG_WARNING(
|
||||
Render_Vulkan,
|
||||
"Qualcomm Adreno 7xx drivers have broken VK_EXT_vertex_input_dynamic_state");
|
||||
features.vertex_input_dynamic_state.vertexInputDynamicState = false;
|
||||
extensions.vertex_input_dynamic_state = false;
|
||||
loaded_extensions.erase(VK_EXT_VERTEX_INPUT_DYNAMIC_STATE_EXTENSION_NAME);
|
||||
}
|
||||
}
|
||||
|
||||
sets_per_pool = 64;
|
||||
if (extensions.extended_dynamic_state3 && is_amd_driver &&
|
||||
@@ -774,6 +800,17 @@ bool Device::ShouldBoostClocks() const {
|
||||
return validated_driver && !is_steam_deck && !is_debugging;
|
||||
}
|
||||
|
||||
bool Device::HasTimelineSemaphore() const {
|
||||
if (GetDriverID() == VK_DRIVER_ID_QUALCOMM_PROPRIETARY ||
|
||||
GetDriverID() == VK_DRIVER_ID_MESA_TURNIP) {
|
||||
// Timeline semaphores do not work properly on all Qualcomm drivers.
|
||||
// They generally work properly with Turnip drivers, but are problematic on some devices
|
||||
// (e.g. ZTE handsets with Snapdragon 870).
|
||||
return false;
|
||||
}
|
||||
return features.timeline_semaphore.timelineSemaphore;
|
||||
}
|
||||
|
||||
bool Device::GetSuitability(bool requires_swapchain) {
|
||||
// Assume we will be suitable.
|
||||
bool suitable = true;
|
||||
|
||||
@@ -528,13 +528,7 @@ public:
|
||||
return extensions.shader_atomic_int64;
|
||||
}
|
||||
|
||||
bool HasTimelineSemaphore() const {
|
||||
if (GetDriverID() == VK_DRIVER_ID_QUALCOMM_PROPRIETARY) {
|
||||
// Timeline semaphores do not work properly on all Qualcomm drivers.
|
||||
return false;
|
||||
}
|
||||
return features.timeline_semaphore.timelineSemaphore;
|
||||
}
|
||||
bool HasTimelineSemaphore() const;
|
||||
|
||||
/// Returns the minimum supported version of SPIR-V.
|
||||
u32 SupportedSpirvVersion() const {
|
||||
|
||||
@@ -221,8 +221,8 @@ vk::Image MemoryAllocator::CreateImage(const VkImageCreateInfo& ci) const {
|
||||
const VmaAllocationCreateInfo alloc_ci = {
|
||||
.flags = VMA_ALLOCATION_CREATE_WITHIN_BUDGET_BIT,
|
||||
.usage = VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE,
|
||||
.requiredFlags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
|
||||
.preferredFlags = 0,
|
||||
.requiredFlags = 0,
|
||||
.preferredFlags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
|
||||
.memoryTypeBits = 0,
|
||||
.pool = VK_NULL_HANDLE,
|
||||
.pUserData = nullptr,
|
||||
|
||||
@@ -178,6 +178,8 @@ constexpr int default_mouse_hide_timeout = 2500;
|
||||
constexpr int default_mouse_center_timeout = 10;
|
||||
constexpr int default_input_update_timeout = 1;
|
||||
|
||||
constexpr size_t CopyBufferSize = 1_MiB;
|
||||
|
||||
/**
|
||||
* "Callouts" are one-time instructional messages shown to the user. In the config settings, there
|
||||
* is a bitfield "callout_flags" options, used to track if a message has already been shown to the
|
||||
@@ -2929,10 +2931,10 @@ void GMainWindow::OnMenuInstallToNAND() {
|
||||
|
||||
int remaining = filenames.size();
|
||||
|
||||
// This would only overflow above 2^43 bytes (8.796 TB)
|
||||
// This would only overflow above 2^51 bytes (2.252 PB)
|
||||
int total_size = 0;
|
||||
for (const QString& file : files) {
|
||||
total_size += static_cast<int>(QFile(file).size() / 0x1000);
|
||||
total_size += static_cast<int>(QFile(file).size() / CopyBufferSize);
|
||||
}
|
||||
if (total_size < 0) {
|
||||
LOG_CRITICAL(Frontend, "Attempting to install too many files, aborting.");
|
||||
@@ -3032,7 +3034,7 @@ InstallResult GMainWindow::InstallNSPXCI(const QString& filename) {
|
||||
return false;
|
||||
}
|
||||
|
||||
std::vector<u8> buffer(1_MiB);
|
||||
std::vector<u8> buffer(CopyBufferSize);
|
||||
|
||||
for (std::size_t i = 0; i < src->GetSize(); i += buffer.size()) {
|
||||
if (install_progress->wasCanceled()) {
|
||||
@@ -3088,7 +3090,7 @@ InstallResult GMainWindow::InstallNCA(const QString& filename) {
|
||||
return false;
|
||||
}
|
||||
|
||||
std::array<u8, 0x1000> buffer{};
|
||||
std::vector<u8> buffer(CopyBufferSize);
|
||||
|
||||
for (std::size_t i = 0; i < src->GetSize(); i += buffer.size()) {
|
||||
if (install_progress->wasCanceled()) {
|
||||
|
||||
Reference in New Issue
Block a user