Compare commits
12 commits
Author | SHA1 | Date | |
---|---|---|---|
|
036416fde7 | ||
|
662470c415 | ||
|
5da5b518c5 | ||
|
acc5668274 | ||
|
1c5281eb0e | ||
|
b0e53d4aad | ||
|
c452cd2bf2 | ||
|
711d4f8824 | ||
|
5149b333d7 | ||
|
4e51d76fa6 | ||
|
a1d90f053a | ||
|
c7de7890b6 |
801 changed files with 12391 additions and 64106 deletions
3
.github/FUNDING.yml
vendored
3
.github/FUNDING.yml
vendored
|
@ -1,3 +0,0 @@
|
|||
# These is the list of funding model platforms used by Skyline
|
||||
|
||||
patreon: skyline_emu
|
136
.github/workflows/ci.yml
vendored
136
.github/workflows/ci.yml
vendored
|
@ -1,107 +1,69 @@
|
|||
name: CI
|
||||
|
||||
on:
|
||||
push:
|
||||
pull_request:
|
||||
types: [opened, synchronize, reopened, labeled]
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
# Skip 'labeled' events that didn't add the 'ci' label
|
||||
if: |
|
||||
github.event_name != 'pull_request' ||
|
||||
github.event.action != 'labeled' ||
|
||||
github.event.label.name == 'ci'
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
JVM_OPTS: -Xmx6G
|
||||
IS_SKYLINE_SIGNED: ${{ secrets.KEYSTORE != '' }}
|
||||
UPLOAD_ARTIFACTS: ${{ github.event_name != 'pull_request' || contains(github.event.pull_request.labels.*.name, 'ci') }}
|
||||
CMAKE_VERSION: "3.22.1"
|
||||
NDK_VERSION: "25.0.8775105"
|
||||
|
||||
steps:
|
||||
- name: Git Checkout
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
submodules: recursive
|
||||
- name: Git Checkout
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
submodules: true
|
||||
|
||||
- name: Restore CCache
|
||||
uses: hendrikmuhs/ccache-action@v1.2
|
||||
with:
|
||||
max-size: 3Gi
|
||||
- name: Restore Gradle Cache
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: /root/.gradle/
|
||||
key: ${{ runner.os }}-gradle-${{ hashFiles('**/build.gradle') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-gradle-
|
||||
|
||||
- name: Restore Gradle Cache
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: ~/.gradle/
|
||||
key: ${{ runner.os }}-gradle-${{ hashFiles('**/build.gradle') }}-${{ hashFiles('app/**/*.xml') }}-${{ hashFiles('app/**.kt', 'app/**.java') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-gradle-${{ hashFiles('**/build.gradle') }}-${{ hashFiles('app/**/*.xml') }}-
|
||||
${{ runner.os }}-gradle-${{ hashFiles('**/build.gradle') }}-
|
||||
${{ runner.os }}-gradle-
|
||||
- name: Restore CXX Cache
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: app/.cxx/
|
||||
key: ${{ runner.os }}-cxx-${{ hashFiles('**/CMakeLists.txt') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-cxx-
|
||||
|
||||
- name: Install Ninja Build
|
||||
run: |
|
||||
sudo apt-get install -y ninja-build
|
||||
ln -s /usr/bin/ninja .
|
||||
- name: Setup Environment for Gradle & Ninja Build
|
||||
run: |
|
||||
chmod +x gradlew
|
||||
sudo apt-get install -y ninja-build
|
||||
|
||||
- name: Install CMake & Android NDK
|
||||
run: echo "yes" | $ANDROID_HOME/tools/bin/sdkmanager "cmake;${{ env.CMAKE_VERSION }}" "ndk;${{ env.NDK_VERSION }}" --channel=3 | grep -v = || true
|
||||
- name: Android Lint
|
||||
run: ./gradlew --stacktrace lint
|
||||
|
||||
- name: Decode Keystore
|
||||
if: env.IS_SKYLINE_SIGNED == 'true'
|
||||
env:
|
||||
KEYSTORE_ENCODED: ${{ secrets.KEYSTORE }}
|
||||
run: echo $KEYSTORE_ENCODED | base64 --decode > "/home/runner/keystore.jks"
|
||||
- name: Upload Lint Report
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: lint-result.html
|
||||
path: app/build/reports/lint-results.html
|
||||
|
||||
- name: Android Assemble
|
||||
env:
|
||||
SIGNING_STORE_PATH: "/home/runner/keystore.jks"
|
||||
SIGNING_STORE_PASSWORD: ${{ secrets.SIGNING_STORE_PASSWORD }}
|
||||
SIGNING_KEY_ALIAS: ${{ secrets.SIGNING_KEY_ALIAS }}
|
||||
SIGNING_KEY_PASSWORD: ${{ secrets.SIGNING_KEY_PASSWORD }}
|
||||
CMAKE_C_COMPILER_LAUNCHER: "ccache"
|
||||
CMAKE_CXX_COMPILER_LAUNCHER: "ccache"
|
||||
CCACHE_COMPILERCHECK: "string:${{ env.NDK_VERSION }}"
|
||||
run: ./gradlew --stacktrace --configuration-cache --build-cache --parallel --configure-on-demand assembleFullRelease assembleFullReldebug
|
||||
- name: Android Assemble
|
||||
run: ./gradlew assemble
|
||||
|
||||
- name: Rename APKs (Signed)
|
||||
if: env.IS_SKYLINE_SIGNED == 'true' && env.UPLOAD_ARTIFACTS == 'true'
|
||||
run: |
|
||||
mv app/build/outputs/apk/full/reldebug/app-full-reldebug.apk skyline-$GITHUB_RUN_NUMBER-reldebug.apk
|
||||
mv app/build/outputs/apk/full/release/app-full-release.apk skyline-$GITHUB_RUN_NUMBER-release.apk
|
||||
- name: Upload Debug APK
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: app-debug.apk
|
||||
path: app/build/outputs/apk/debug/
|
||||
|
||||
- name: Upload Signed Debug APK
|
||||
if: env.IS_SKYLINE_SIGNED == 'true' && env.UPLOAD_ARTIFACTS == 'true'
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: skyline-${{ github.run_number }}-reldebug.apk
|
||||
path: skyline-${{ github.run_number }}-reldebug.apk
|
||||
- name: Upload Release APK
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: app-release.apk
|
||||
path: app/build/outputs/apk/release/
|
||||
|
||||
- name: Upload Signed Release APK
|
||||
if: env.IS_SKYLINE_SIGNED == 'true' && env.UPLOAD_ARTIFACTS == 'true'
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: skyline-${{ github.run_number }}-release.apk
|
||||
path: skyline-${{ github.run_number }}-release.apk
|
||||
- name: Upload R8 Mapping
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: mapping.txt
|
||||
path: app/build/outputs/mapping/release/
|
||||
|
||||
- name: Rename APKs (Unsigned)
|
||||
if: env.IS_SKYLINE_SIGNED == 'false' && env.UPLOAD_ARTIFACTS == 'true'
|
||||
run: |
|
||||
mv app/build/outputs/apk/full/reldebug/app-full-reldebug.apk skyline-$GITHUB_RUN_NUMBER-unsigned-reldebug.apk
|
||||
mv app/build/outputs/apk/full/release/app-full-release.apk skyline-$GITHUB_RUN_NUMBER-unsigned-release.apk
|
||||
|
||||
- name: Upload Unsigned Debug APK
|
||||
if: env.IS_SKYLINE_SIGNED == 'false' && env.UPLOAD_ARTIFACTS == 'true'
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: skyline-${{ github.run_number }}-unsigned-reldebug.apk
|
||||
path: skyline-${{ github.run_number }}-unsigned-reldebug.apk
|
||||
|
||||
- name: Upload Unsigned Release APK
|
||||
if: env.IS_SKYLINE_SIGNED == 'false' && env.UPLOAD_ARTIFACTS == 'true'
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: skyline-${{ github.run_number }}-unsigned-release.apk
|
||||
path: skyline-${{ github.run_number }}-unsigned-release.apk
|
||||
- name: Delete Build Folder
|
||||
run: rm -rf app/build/
|
||||
|
|
20
.github/workflows/edge-ci.yml
vendored
20
.github/workflows/edge-ci.yml
vendored
|
@ -1,20 +0,0 @@
|
|||
name: Edge CI
|
||||
|
||||
on:
|
||||
pull_request_target:
|
||||
types: [synchronize, reopened, closed, labeled, unlabeled]
|
||||
|
||||
jobs:
|
||||
update-patches:
|
||||
# Run if the 'edge' label was added/removed, or if an edge PR was synchronized/reopened/closed
|
||||
if: |
|
||||
github.event.label.name == 'edge' ||
|
||||
!contains(github.event.action, 'labeled') && contains(github.event.pull_request.labels.*.name, 'edge')
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Update Edge patches
|
||||
uses: peter-evans/repository-dispatch@v2
|
||||
with:
|
||||
token: ${{ secrets.EDGE_PATCH_PAT }}
|
||||
repository: skyline-emu/edge-patch
|
||||
event-type: update-patches
|
158
.gitignore
vendored
158
.gitignore
vendored
|
@ -1,111 +1,99 @@
|
|||
# Source: https://github.com/github/gitignore/blob/master/Android.gitignore
|
||||
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm
|
||||
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
|
||||
|
||||
# Built application files
|
||||
*.apk
|
||||
*.aar
|
||||
*.ap_
|
||||
*.aab
|
||||
# User-specific stuff
|
||||
.idea/**/workspace.xml
|
||||
.idea/**/tasks.xml
|
||||
.idea/**/usage.statistics.xml
|
||||
.idea/**/dictionaries
|
||||
.idea/**/shelf
|
||||
|
||||
# Files for the ART/Dalvik VM
|
||||
# Files for the ART/Dalvik VM
|
||||
*.dex
|
||||
|
||||
# Java class files
|
||||
*.class
|
||||
|
||||
# Generated files
|
||||
bin/
|
||||
gen/
|
||||
out/
|
||||
.idea/**/contentModel.xml
|
||||
|
||||
# Sensitive or high-churn files
|
||||
.idea/**/dataSources/
|
||||
.idea/**/dataSources.ids
|
||||
.idea/**/dataSources.local.xml
|
||||
.idea/**/sqlDataSources.xml
|
||||
.idea/**/dynamic.xml
|
||||
.idea/**/uiDesigner.xml
|
||||
.idea/**/dbnavigator.xml
|
||||
|
||||
# Gradle
|
||||
.idea/**/gradle.xml
|
||||
.idea/**/libraries
|
||||
|
||||
# Gradle and Maven with auto-import
|
||||
# When using Gradle or Maven with auto-import, you should exclude module files,
|
||||
# since they will be recreated, and may cause churn. Uncomment if using
|
||||
# auto-import.
|
||||
.idea/modules.xml
|
||||
.idea/*.iml
|
||||
.idea/modules
|
||||
*.iml
|
||||
*.ipr
|
||||
|
||||
# CMake
|
||||
cmake-build-*/
|
||||
|
||||
# Gradle files
|
||||
.gradle/
|
||||
build/
|
||||
|
||||
# Local configuration file (sdk path, etc)
|
||||
# Android Studio
|
||||
.idea/caches
|
||||
.idea/assetWizardSettings.xml
|
||||
.idea/runConfigurations.xml
|
||||
|
||||
# Mongo Explorer plugin
|
||||
.idea/**/mongoSettings.xml
|
||||
|
||||
# File-based project format
|
||||
*.iws
|
||||
|
||||
# Local configuration file (SDK path, etc)
|
||||
local.properties
|
||||
|
||||
# Proguard folder generated by Eclipse
|
||||
proguard/
|
||||
# External native build folder generated in Android Studio 2.2 and later
|
||||
.externalNativeBuild/
|
||||
.cxx/
|
||||
|
||||
# Log Files
|
||||
*.log
|
||||
# IntelliJ
|
||||
out/
|
||||
|
||||
# Android Studio Navigation editor temp files
|
||||
.navigation/
|
||||
# mpeltonen/sbt-idea plugin
|
||||
.idea_modules/
|
||||
|
||||
# JIRA plugin
|
||||
atlassian-ide-plugin.xml
|
||||
|
||||
# Cursive Clojure plugin
|
||||
.idea/replstate.xml
|
||||
|
||||
# Crashlytics plugin (for Android Studio and IntelliJ)
|
||||
com_crashlytics_export_strings.xml
|
||||
crashlytics.properties
|
||||
crashlytics-build.properties
|
||||
fabric.properties
|
||||
|
||||
# Editor-based Rest Client
|
||||
.idea/httpRequests
|
||||
|
||||
# Android studio 3.1+ serialized cache file
|
||||
.idea/caches/build_file_checksums.ser
|
||||
|
||||
# Android Studio captures folder
|
||||
captures/
|
||||
|
||||
# IntelliJ
|
||||
*.iml
|
||||
.idea/workspace.xml
|
||||
.idea/tasks.xml
|
||||
.idea/gradle.xml
|
||||
.idea/assetWizardSettings.xml
|
||||
.idea/dictionaries
|
||||
.idea/libraries
|
||||
.idea/jarRepositories.xml
|
||||
.idea/misc.xml
|
||||
.idea/compiler.xml
|
||||
deploymentTargetDropDown.xml
|
||||
render.experimental.xml
|
||||
# Android Studio 3 in .gitignore file.
|
||||
.idea/caches
|
||||
.idea/modules
|
||||
.idea/modules.xml
|
||||
.idea/navEditor.xml
|
||||
.idea/runConfigurations.xml
|
||||
|
||||
# Keystore files
|
||||
*.jks
|
||||
*.keystore
|
||||
|
||||
# External native build folder generated in Android Studio 2.2 and later
|
||||
.externalNativeBuild
|
||||
.cxx/
|
||||
|
||||
# Google Services (e.g. APIs or Firebase)
|
||||
google-services.json
|
||||
|
||||
# Freeline
|
||||
freeline.py
|
||||
freeline/
|
||||
freeline_project_description.json
|
||||
|
||||
# fastlane
|
||||
fastlane/report.xml
|
||||
fastlane/Preview.html
|
||||
fastlane/screenshots
|
||||
fastlane/test_output
|
||||
fastlane/readme.md
|
||||
|
||||
# Version control
|
||||
vcs.xml
|
||||
|
||||
# lint
|
||||
lint/intermediates/
|
||||
lint/generated/
|
||||
lint/outputs/
|
||||
lint/tmp/
|
||||
lint/reports/
|
||||
|
||||
# Android Profiling
|
||||
*.hprof
|
||||
|
||||
# VSCode
|
||||
.vscode/
|
||||
|
||||
# Discord plugin for IntelliJ IDEA
|
||||
.idea/discord.xml
|
||||
|
||||
# Adreno Validation Layer
|
||||
libVkLayer_adreno.so
|
||||
|
||||
# Skyline logs
|
||||
*.sklog
|
||||
|
||||
# Android Studio Profiler Traces
|
||||
*.trace
|
||||
|
||||
# Output Metadata
|
||||
output-metadata.json
|
||||
|
|
62
.gitmodules
vendored
62
.gitmodules
vendored
|
@ -1,65 +1,27 @@
|
|||
[submodule "{fmt}"]
|
||||
[submodule "app/libraries/fmt"]
|
||||
path = app/libraries/fmt
|
||||
url = https://github.com/fmtlib/fmt
|
||||
[submodule "Oboe"]
|
||||
[submodule "app/libraries/oboe"]
|
||||
path = app/libraries/oboe
|
||||
url = https://github.com/google/oboe
|
||||
branch = 1.3-stable
|
||||
[submodule "LZ4"]
|
||||
[submodule "app/libraries/vkhpp"]
|
||||
path = app/libraries/vkhpp
|
||||
url = https://github.com/skyline-emu/vkhpp
|
||||
[submodule "app/libraries/lz4"]
|
||||
path = app/libraries/lz4
|
||||
url = https://github.com/lz4/lz4.git
|
||||
[submodule "Frozen"]
|
||||
[submodule "app/libraries/frozen"]
|
||||
path = app/libraries/frozen
|
||||
url = https://github.com/serge-sans-paille/frozen
|
||||
[submodule "tzcode"]
|
||||
[submodule "app/libraries/pugixml"]
|
||||
path = app/libraries/pugixml
|
||||
url = https://github.com/zeux/pugixml.git
|
||||
[submodule "app/libraries/tzcode"]
|
||||
path = app/libraries/tzcode
|
||||
url = https://github.com/skyline-emu/tz
|
||||
branch = master
|
||||
[submodule "Perfetto"]
|
||||
[submodule "app/libraries/perfetto"]
|
||||
path = app/libraries/perfetto
|
||||
url = https://android.googlesource.com/platform/external/perfetto
|
||||
branch = releases/v12.x
|
||||
[submodule "Vulkan-Hpp"]
|
||||
path = app/libraries/vkhpp
|
||||
url = https://github.com/KhronosGroup/Vulkan-Hpp
|
||||
[submodule "Vulkan Memory Allocator"]
|
||||
path = app/libraries/vkma
|
||||
url = https://github.com/GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator
|
||||
[submodule "Mbed TLS"]
|
||||
path = app/libraries/mbedtls
|
||||
url = https://github.com/ARMmbed/mbedtls
|
||||
[submodule "Opus"]
|
||||
path = app/libraries/opus
|
||||
url = https://github.com/xiph/opus
|
||||
[submodule "Boost"]
|
||||
path = app/libraries/boost
|
||||
url = https://github.com/skyline-emu/boost.git
|
||||
ignore = all
|
||||
[submodule "LLVM"]
|
||||
path = app/libraries/llvm
|
||||
url = https://github.com/llvm/llvm-project.git
|
||||
shallow = true
|
||||
[submodule "C++ Range v3"]
|
||||
path = app/libraries/range
|
||||
url = https://github.com/ericniebler/range-v3
|
||||
[submodule "Sirit"]
|
||||
path = app/libraries/sirit
|
||||
url = https://github.com/yuzu-emu/sirit
|
||||
[submodule "Shader Compiler"]
|
||||
path = app/libraries/shader-compiler
|
||||
url = https://github.com/skyline-emu/shader-compiler.git
|
||||
[submodule "libadrenotools"]
|
||||
path = app/libraries/adrenotools
|
||||
url = https://github.com/bylaws/libadrenotools/
|
||||
[submodule "app/libraries/robin-map"]
|
||||
path = app/libraries/robin-map
|
||||
url = https://github.com/Tessil/robin-map
|
||||
[submodule "app/libraries/thread-pool"]
|
||||
path = app/libraries/thread-pool
|
||||
url = https://github.com/bshoshany/thread-pool.git
|
||||
[submodule "app/libraries/cubeb"]
|
||||
path = app/libraries/cubeb
|
||||
url = https://github.com/skyline-emu/cubeb
|
||||
[submodule "app/libraries/audio-core"]
|
||||
path = app/libraries/audio-core
|
||||
url = https://github.com/skyline-emu/audio-core
|
||||
|
|
44
.idea/codeStyles/Project.xml
generated
44
.idea/codeStyles/Project.xml
generated
|
@ -7,6 +7,22 @@
|
|||
<option name="FORMATTER_OFF_TAG" value="@fmt:off" />
|
||||
<option name="SOFT_MARGINS" value="80,140" />
|
||||
<JetCodeStyleSettings>
|
||||
<option name="PACKAGES_TO_USE_STAR_IMPORTS">
|
||||
<value>
|
||||
<package name="java.util" alias="false" withSubpackages="false" />
|
||||
<package name="kotlinx.android.synthetic" alias="false" withSubpackages="true" />
|
||||
<package name="io.ktor" alias="false" withSubpackages="true" />
|
||||
</value>
|
||||
</option>
|
||||
<option name="PACKAGES_IMPORT_LAYOUT">
|
||||
<value>
|
||||
<package name="" alias="false" withSubpackages="true" />
|
||||
<package name="java" alias="false" withSubpackages="true" />
|
||||
<package name="javax" alias="false" withSubpackages="true" />
|
||||
<package name="kotlin" alias="false" withSubpackages="true" />
|
||||
<package name="" alias="true" withSubpackages="true" />
|
||||
</value>
|
||||
</option>
|
||||
<option name="SPACE_BEFORE_TYPE_COLON" value="true" />
|
||||
<option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" />
|
||||
</JetCodeStyleSettings>
|
||||
|
@ -25,7 +41,6 @@
|
|||
<option name="CLASS_CONSTRUCTOR_INIT_LIST_WRAP" value="0" />
|
||||
<option name="SUPERCLASS_LIST_WRAP" value="0" />
|
||||
<option name="ALIGN_INIT_LIST_IN_COLUMNS" value="false" />
|
||||
<option name="SPACE_BEFORE_COLON_IN_FOREACH" value="true" />
|
||||
<option name="SPACE_BEFORE_DICTIONARY_LITERAL_COLON" value="true" />
|
||||
<option name="ADD_BRIEF_TAG" value="true" />
|
||||
<option name="HEADER_GUARD_STYLE_PATTERN" value="${PROJECT_NAME}_${PROJECT_REL_PATH}_${FILE_NAME}_${EXT}" />
|
||||
|
@ -55,23 +70,12 @@
|
|||
</option>
|
||||
</Objective-C>
|
||||
<Objective-C-extensions>
|
||||
<rules>
|
||||
<rule entity="NAMESPACE" visibility="ANY" specifier="ANY" prefix="" style="CAMEL_CASE" suffix="" />
|
||||
<rule entity="MACRO" visibility="ANY" specifier="ANY" prefix="" style="SCREAMING_SNAKE_CASE" suffix="" />
|
||||
<rule entity="CLASS" visibility="ANY" specifier="ANY" prefix="" style="PASCAL_CASE" suffix="" />
|
||||
<rule entity="ENUM" visibility="ANY" specifier="ANY" prefix="" style="PASCAL_CASE" suffix="" />
|
||||
<rule entity="ENUMERATOR" visibility="ANY" specifier="ANY" prefix="" style="PASCAL_CASE" suffix="" />
|
||||
<rule entity="TYPEDEF" visibility="ANY" specifier="ANY" prefix="" style="PASCAL_CASE" suffix="" />
|
||||
<rule entity="UNION" visibility="ANY" specifier="ANY" prefix="" style="PASCAL_CASE" suffix="" />
|
||||
<rule entity="CLASS_MEMBER_FUNCTION,STRUCT_MEMBER_FUNCTION" visibility="ANY" specifier="ANY" prefix="" style="PASCAL_CASE" suffix="" />
|
||||
<rule entity="CLASS_MEMBER_FIELD,STRUCT_MEMBER_FIELD" visibility="ANY" specifier="ANY" prefix="" style="CAMEL_CASE" suffix="" />
|
||||
<rule entity="GLOBAL_FUNCTION" visibility="ANY" specifier="ANY" prefix="" style="PASCAL_CASE" suffix="" />
|
||||
<rule entity="GLOBAL_VARIABLE" visibility="ANY" specifier="ANY" prefix="" style="PASCAL_CASE" suffix="" />
|
||||
<rule entity="PARAMETER" visibility="ANY" specifier="ANY" prefix="" style="CAMEL_CASE" suffix="" />
|
||||
<rule entity="LOCAL_VARIABLE" visibility="ANY" specifier="ANY" prefix="" style="CAMEL_CASE" suffix="" />
|
||||
</rules>
|
||||
</Objective-C-extensions>
|
||||
<Objective-C-extensions>
|
||||
<extensions>
|
||||
<pair source="cpp" header="h" fileNamingConvention="SNAKE_CASE" />
|
||||
<pair source="c" header="h" fileNamingConvention="SNAKE_CASE" />
|
||||
<pair source="cpp" header="h" fileNamingConvention="PASCAL_CASE" />
|
||||
<pair source="cpp" header="h" fileNamingConvention="NONE" />
|
||||
</extensions>
|
||||
<rules>
|
||||
<rule entity="NAMESPACE" visibility="ANY" specifier="ANY" prefix="" style="CAMEL_CASE" suffix="" />
|
||||
<rule entity="MACRO" visibility="ANY" specifier="ANY" prefix="" style="SCREAMING_SNAKE_CASE" suffix="" />
|
||||
|
@ -122,10 +126,6 @@
|
|||
</indentOptions>
|
||||
</codeStyleSettings>
|
||||
<codeStyleSettings language="XML">
|
||||
<option name="FORCE_REARRANGE_MODE" value="1" />
|
||||
<indentOptions>
|
||||
<option name="CONTINUATION_INDENT_SIZE" value="4" />
|
||||
</indentOptions>
|
||||
<arrangement>
|
||||
<rules>
|
||||
<section>
|
||||
|
|
6
.idea/compiler.xml
generated
Normal file
6
.idea/compiler.xml
generated
Normal file
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="CompilerConfiguration">
|
||||
<bytecodeTargetLevel target="11" />
|
||||
</component>
|
||||
</project>
|
40
.idea/inspectionProfiles/Project_Default.xml
generated
40
.idea/inspectionProfiles/Project_Default.xml
generated
|
@ -81,6 +81,7 @@
|
|||
<inspection_tool class="AssertsWithoutMessages" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="AssertsWithoutMessagesTestNG" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="AssignmentOrReturnOfFieldWithMutableType" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="AssignmentToCatchBlockParameter" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="AssignmentToForLoopParameter" enabled="true" level="WARNING" enabled_by_default="true">
|
||||
<option name="m_checkForeachParameters" value="false" />
|
||||
</inspection_tool>
|
||||
|
@ -91,6 +92,7 @@
|
|||
<inspection_tool class="AssignmentToNull" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="AssignmentToStaticFieldFromInstanceMethod" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="AssignmentToSuperclassField" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="AssignmentUsedAsCondition" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="AutoBoxing" enabled="true" level="WARNING" enabled_by_default="true">
|
||||
<option name="ignoreAddedToCollection" value="false" />
|
||||
</inspection_tool>
|
||||
|
@ -120,6 +122,7 @@
|
|||
</inspection_tool>
|
||||
<inspection_tool class="BadOddness" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="BigDecimalEquals" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="BigDecimalLegacyMethod" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="BlockMarkerComments" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="BooleanExpressionMayBeConditional" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="BooleanMethodNameMustStartWithQuestion" enabled="true" level="WARNING" enabled_by_default="true">
|
||||
|
@ -168,7 +171,7 @@
|
|||
</inspection_tool>
|
||||
<inspection_tool class="CheckedExceptionClass" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="ClangTidy" enabled="true" level="WARNING" enabled_by_default="true">
|
||||
<option name="clangTidyChecks" value="-*,bugprone-argument-comment,bugprone-assert-side-effect,bugprone-bad-signal-to-kill-thread,bugprone-branch-clone,bugprone-copy-constructor-init,bugprone-dangling-handle,bugprone-dynamic-static-initializers,bugprone-fold-init-type,bugprone-forward-declaration-namespace,bugprone-forwarding-reference-overload,bugprone-inaccurate-erase,bugprone-incorrect-roundings,bugprone-integer-division,bugprone-lambda-function-name,bugprone-macro-repeated-side-effects,bugprone-misplaced-operator-in-strlen-in-alloc,bugprone-misplaced-pointer-arithmetic-in-alloc,bugprone-misplaced-widening-cast,bugprone-move-forwarding-reference,bugprone-multiple-statement-macro,bugprone-no-escape,bugprone-not-null-terminated-result,bugprone-parent-virtual-call,bugprone-posix-return,bugprone-reserved-identifier,bugprone-sizeof-container,bugprone-sizeof-expression,bugprone-spuriously-wake-up-functions,bugprone-string-constructor,bugprone-string-integer-assignment,bugprone-string-literal-with-embedded-nul,bugprone-suspicious-enum-usage,bugprone-suspicious-include,bugprone-suspicious-memset-usage,bugprone-suspicious-missing-comma,bugprone-suspicious-semicolon,bugprone-suspicious-string-compare,bugprone-swapped-arguments,bugprone-terminating-continue,bugprone-throw-keyword-missing,bugprone-too-small-loop-variable,bugprone-undefined-memory-manipulation,bugprone-undelegated-constructor,bugprone-unhandled-self-assignment,bugprone-unused-raii,bugprone-unused-return-value,bugprone-use-after-move,bugprone-virtual-near-miss,cert-dcl21-cpp,cert-dcl58-cpp,cert-err34-c,cert-err52-cpp,cert-err58-cpp,cert-err60-cpp,cert-flp30-c,cert-msc50-cpp,cert-msc51-cpp,cert-str34-c,cppcoreguidelines-interfaces-global-init,cppcoreguidelines-narrowing-conversions,cppcoreguidelines-pro-type-member-init,cppcoreguidelines-pro-type-static-cast-downcast,cppcoreguidelines-slicing,google-default-arguments,google-explicit-constructor,google-runtime-operator,hicpp-exception-baseclass,hicpp-multiway-paths-covered,misc-misplaced-const,misc-new-delete-overloads,misc-no-recursion,misc-non-copyable-objects,misc-throw-by-value-catch-by-reference,misc-unconventional-assign-operator,misc-uniqueptr-reset-release,modernize-avoid-bind,modernize-concat-nested-namespaces,modernize-deprecated-ios-base-aliases,modernize-loop-convert,modernize-make-shared,modernize-make-unique,modernize-pass-by-value,modernize-raw-string-literal,modernize-redundant-void-arg,modernize-replace-auto-ptr,modernize-replace-disallow-copy-and-assign-macro,modernize-replace-random-shuffle,modernize-return-braced-init-list,modernize-shrink-to-fit,modernize-unary-static-assert,modernize-use-auto,modernize-use-bool-literals,modernize-use-emplace,modernize-use-equals-default,modernize-use-equals-delete,modernize-use-nodiscard,modernize-use-noexcept,modernize-use-nullptr,modernize-use-override,modernize-use-transparent-functors,modernize-use-uncaught-exceptions,mpi-buffer-deref,mpi-type-mismatch,openmp-use-default-none,performance-faster-string-find,performance-for-range-copy,performance-implicit-conversion-in-loop,performance-inefficient-algorithm,performance-inefficient-string-concatenation,performance-inefficient-vector-operation,performance-move-const-arg,performance-move-constructor-init,performance-no-automatic-move,performance-noexcept-move-constructor,performance-trivially-destructible,performance-type-promotion-in-math-fn,performance-unnecessary-copy-initialization,performance-unnecessary-value-param,portability-simd-intrinsics,readability-avoid-const-params-in-decls,readability-const-return-type,readability-container-size-empty,readability-convert-member-functions-to-static,readability-delete-null-pointer,readability-deleted-default,readability-inconsistent-declaration-parameter-name,readability-misleading-indentation,readability-misplaced-array-index,readability-redundant-control-flow,readability-redundant-declaration,readability-redundant-function-ptr-dereference,readability-redundant-smartptr-get,readability-redundant-string-cstr,readability-redundant-string-init,readability-simplify-subscript-expr,readability-static-accessed-through-instance,readability-static-definition-in-anonymous-namespace,readability-string-compare,readability-uniqueptr-delete-release,readability-use-anyofallof" />
|
||||
<option name="clangTidyChecks" value="-*,bugprone-argument-comment,bugprone-assert-side-effect,bugprone-bad-signal-to-kill-thread,bugprone-branch-clone,bugprone-copy-constructor-init,bugprone-dangling-handle,bugprone-dynamic-static-initializers,bugprone-fold-init-type,bugprone-forward-declaration-namespace,bugprone-forwarding-reference-overload,bugprone-inaccurate-erase,bugprone-incorrect-roundings,bugprone-integer-division,bugprone-lambda-function-name,bugprone-macro-parentheses,bugprone-macro-repeated-side-effects,bugprone-misplaced-operator-in-strlen-in-alloc,bugprone-misplaced-pointer-arithmetic-in-alloc,bugprone-misplaced-widening-cast,bugprone-move-forwarding-reference,bugprone-multiple-statement-macro,bugprone-no-escape,bugprone-not-null-terminated-result,bugprone-parent-virtual-call,bugprone-posix-return,bugprone-reserved-identifier,bugprone-sizeof-container,bugprone-sizeof-expression,bugprone-spuriously-wake-up-functions,bugprone-string-constructor,bugprone-string-integer-assignment,bugprone-string-literal-with-embedded-nul,bugprone-suspicious-enum-usage,bugprone-suspicious-include,bugprone-suspicious-memset-usage,bugprone-suspicious-missing-comma,bugprone-suspicious-semicolon,bugprone-suspicious-string-compare,bugprone-swapped-arguments,bugprone-terminating-continue,bugprone-throw-keyword-missing,bugprone-too-small-loop-variable,bugprone-undefined-memory-manipulation,bugprone-undelegated-constructor,bugprone-unhandled-self-assignment,bugprone-unused-raii,bugprone-unused-return-value,bugprone-use-after-move,bugprone-virtual-near-miss,cert-dcl21-cpp,cert-dcl58-cpp,cert-err34-c,cert-err52-cpp,cert-err60-cpp,cert-flp30-c,cert-msc50-cpp,cert-msc51-cpp,cert-str34-c,cppcoreguidelines-interfaces-global-init,cppcoreguidelines-narrowing-conversions,cppcoreguidelines-pro-type-static-cast-downcast,cppcoreguidelines-slicing,google-default-arguments,google-explicit-constructor,google-runtime-operator,hicpp-exception-baseclass,hicpp-multiway-paths-covered,misc-misplaced-const,misc-new-delete-overloads,misc-no-recursion,misc-non-copyable-objects,misc-throw-by-value-catch-by-reference,misc-unconventional-assign-operator,misc-uniqueptr-reset-release,modernize-avoid-bind,modernize-concat-nested-namespaces,modernize-deprecated-headers,modernize-deprecated-ios-base-aliases,modernize-loop-convert,modernize-make-shared,modernize-make-unique,modernize-pass-by-value,modernize-raw-string-literal,modernize-redundant-void-arg,modernize-replace-auto-ptr,modernize-replace-disallow-copy-and-assign-macro,modernize-replace-random-shuffle,modernize-return-braced-init-list,modernize-shrink-to-fit,modernize-unary-static-assert,modernize-use-auto,modernize-use-bool-literals,modernize-use-emplace,modernize-use-equals-default,modernize-use-equals-delete,modernize-use-nodiscard,modernize-use-noexcept,modernize-use-nullptr,modernize-use-override,modernize-use-transparent-functors,modernize-use-uncaught-exceptions,mpi-buffer-deref,mpi-type-mismatch,openmp-use-default-none,performance-faster-string-find,performance-for-range-copy,performance-implicit-conversion-in-loop,performance-inefficient-algorithm,performance-inefficient-string-concatenation,performance-inefficient-vector-operation,performance-move-const-arg,performance-move-constructor-init,performance-no-automatic-move,performance-noexcept-move-constructor,performance-trivially-destructible,performance-type-promotion-in-math-fn,performance-unnecessary-copy-initialization,performance-unnecessary-value-param,portability-simd-intrinsics,readability-avoid-const-params-in-decls,readability-const-return-type,readability-container-size-empty,readability-convert-member-functions-to-static,readability-delete-null-pointer,readability-deleted-default,readability-inconsistent-declaration-parameter-name,readability-make-member-function-const,readability-misleading-indentation,readability-misplaced-array-index,readability-non-const-parameter,readability-redundant-control-flow,readability-redundant-declaration,readability-redundant-function-ptr-dereference,readability-redundant-smartptr-get,readability-redundant-string-cstr,readability-redundant-string-init,readability-simplify-subscript-expr,readability-static-accessed-through-instance,readability-static-definition-in-anonymous-namespace,readability-string-compare,readability-uniqueptr-delete-release,readability-use-anyofallof" />
|
||||
</inspection_tool>
|
||||
<inspection_tool class="ClassComplexity" enabled="true" level="WARNING" enabled_by_default="true">
|
||||
<option name="m_limit" value="80" />
|
||||
|
@ -244,6 +247,7 @@
|
|||
<inspection_tool class="CompareToUsesNonFinalVariable" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="ComparisonOfShortAndChar" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="ConditionSignal" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="ConditionalExpressionWithIdenticalBranches" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="ConfusingFloatingPointLiteral" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="ConfusingMainMethod" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="ConfusingOctalEscape" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
|
@ -257,13 +261,11 @@
|
|||
<inspection_tool class="ConstantConditionsOC" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="ConstantDeclaredInAbstractClass" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="ConstantDeclaredInInterface" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="ConstantFunctionResult" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="ConstantJUnitAssertArgument" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="ConstantMathCall" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="ConstantOnLHSOfComparison" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="ConstantOnRHSOfComparison" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="ConstantOnWrongSideOfComparison" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="ConstantParameter" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="ConstantTestNGAssertArgument" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="ConstantValueVariableUse" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="ConstructionIsNotAllowed" enabled="true" level="ERROR" enabled_by_default="true" />
|
||||
|
@ -283,7 +285,6 @@
|
|||
<inspection_tool class="CyclomaticComplexity" enabled="true" level="WARNING" enabled_by_default="true">
|
||||
<option name="m_limit" value="10" />
|
||||
</inspection_tool>
|
||||
<inspection_tool class="DanglingPointer" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="DanglingPointers" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="DateToString" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="DeclareCollectionAsInterface" enabled="true" level="WARNING" enabled_by_default="true">
|
||||
|
@ -295,6 +296,9 @@
|
|||
<inspection_tool class="DesignForExtension" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="DisjointPackage" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="DollarSignInName" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="DoubleCheckedLocking" enabled="true" level="WARNING" enabled_by_default="true">
|
||||
<option name="ignoreOnVolatileVariables" value="false" />
|
||||
</inspection_tool>
|
||||
<inspection_tool class="DoubleLiteralMayBeFloatLiteral" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="DriverManagerGetConnection" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="DuplicateBooleanBranch" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
|
@ -313,7 +317,7 @@
|
|||
<option name="commentsAreContent" value="true" />
|
||||
</inspection_tool>
|
||||
<inspection_tool class="EmptyDirectory" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="EndlessLoop" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="EmptySynchronizedStatement" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="EnumAsName" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="EnumClass" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="EnumerationCanBeIteration" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
|
@ -359,9 +363,11 @@
|
|||
<inspection_tool class="FieldNotUsedInToString" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="FinalClass" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="FinalMethod" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="FinalMethodInFinalClass" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="Finalize" enabled="true" level="WARNING" enabled_by_default="true">
|
||||
<option name="ignoreTrivialFinalizers" value="true" />
|
||||
</inspection_tool>
|
||||
<inspection_tool class="FinalizeNotProtected" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="FloatingPointEquality" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="ForLoopReplaceableByWhile" enabled="true" level="INFORMATION" enabled_by_default="true">
|
||||
<option name="m_ignoreLoopsWithoutConditions" value="false" />
|
||||
|
@ -400,7 +406,6 @@
|
|||
<inspection_tool class="IncompatibleTypes" enabled="true" level="ERROR" enabled_by_default="true" />
|
||||
<inspection_tool class="InconsistentLanguageLevel" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="IncrementDecrementUsedAsExpression" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="InfiniteRecursion" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="InitializationIssue" enabled="true" level="ERROR" enabled_by_default="true" />
|
||||
<inspection_tool class="InitializerIssues" enabled="true" level="ERROR" enabled_by_default="true" />
|
||||
<inspection_tool class="InnerClassOnInterface" enabled="true" level="WARNING" enabled_by_default="true">
|
||||
|
@ -473,7 +478,6 @@
|
|||
<option name="REPORT_VARIABLES" value="true" />
|
||||
<option name="REPORT_PARAMETERS" value="true" />
|
||||
</inspection_tool>
|
||||
<inspection_tool class="LocalValueEscapesScope" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="LocalVariableHidingMemberVariable" enabled="true" level="WARNING" enabled_by_default="true">
|
||||
<option name="m_ignoreInvisibleFields" value="true" />
|
||||
<option name="m_ignoreStaticMethods" value="true" />
|
||||
|
@ -587,6 +591,7 @@
|
|||
<inspection_tool class="NestingDepth" enabled="true" level="WARNING" enabled_by_default="true">
|
||||
<option name="m_limit" value="5" />
|
||||
</inspection_tool>
|
||||
<inspection_tool class="NewClassNamingConvention" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="NewExceptionWithoutArguments" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="NewMethodNamingConvention" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="NoDefaultBaseConstructor" enabled="true" level="ERROR" enabled_by_default="true" />
|
||||
|
@ -600,6 +605,7 @@
|
|||
</inspection_tool>
|
||||
<inspection_tool class="NonExceptionNameEndsWithException" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="NonFinalClone" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="NonFinalFieldInEnum" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="NonFinalFieldInImmutable" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="NonFinalFieldOfException" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="NonFinalGuard" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
|
@ -634,7 +640,6 @@
|
|||
<inspection_tool class="NotSuperclass" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="NotifyCalledOnCondition" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="NotifyWithoutCorrespondingWait" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="NullDereference" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="NullDereferences" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="NullThrown" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="NumericToString" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
|
@ -735,6 +740,7 @@
|
|||
<inspection_tool class="PreviewMultipleParameterProviders" enabled="false" level="ERROR" enabled_by_default="false" />
|
||||
<inspection_tool class="PreviewMustBeTopLevelFunction" enabled="false" level="ERROR" enabled_by_default="false" />
|
||||
<inspection_tool class="PreviewNeedsComposableAnnotation" enabled="false" level="ERROR" enabled_by_default="false" />
|
||||
<inspection_tool class="PrivateMemberAccessBetweenOuterAndInnerClass" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="ProblematicVarargsMethodOverride" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="ProjectFingerprint" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="PropKeysLabel" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
|
@ -744,6 +750,7 @@
|
|||
<option name="ignoreEnums" value="false" />
|
||||
<option name="ignoreInterfaces" value="false" />
|
||||
</inspection_tool>
|
||||
<inspection_tool class="ProtectedMemberInFinalClass" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="PublicConstructor" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="PublicConstructorInNonPublicClass" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="PublicFieldAccessedInSynchronizedContext" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
|
@ -911,7 +918,10 @@
|
|||
<inspection_tool class="SerialPersistentFieldsWithWrongSignature" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="SerialVersionUIDNotStaticFinal" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="SerializableDeserializableClassInSecureContext" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="SerializableHasSerialVersionUIDField" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="SerializableHasSerialVersionUIDField" enabled="true" level="WARNING" enabled_by_default="true">
|
||||
<option name="ignoreAnonymousInnerClasses" value="false" />
|
||||
<option name="superClassString" value="java.awt.Component" />
|
||||
</inspection_tool>
|
||||
<inspection_tool class="SerializableHasSerializationMethods" enabled="true" level="WARNING" enabled_by_default="true">
|
||||
<option name="ignoreAnonymousInnerClasses" value="false" />
|
||||
<option name="superClassString" value="java.awt.Component" />
|
||||
|
@ -1015,6 +1025,7 @@
|
|||
<inspection_tool class="SystemGetenv" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="SystemOutErr" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="SystemProperties" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="SystemRunFinalizersOnExit" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="SystemSetSecurityManager" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="TemplateArgumentsIssues" enabled="true" level="ERROR" enabled_by_default="true" />
|
||||
<inspection_tool class="TestCaseInProductCode" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
|
@ -1061,6 +1072,7 @@
|
|||
<option name="onlyWeakentoInterface" value="true" />
|
||||
</inspection_tool>
|
||||
<inspection_tool class="TypeParameterExtendsFinalClass" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="UnaryPlus" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="UncheckedExceptionClass" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="UnconditionalWait" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="UndeclaredTests" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
|
@ -1085,6 +1097,8 @@
|
|||
<inspection_tool class="UnnecessarySuperConstructor" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="UnnecessarySuperQualifier" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="UnnecessaryThis" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="UnnecessaryToStringCall" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="UnnecessaryUnaryMinus" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="UnnecessaryUnicodeEscape" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="UnqualifiedInnerClassAccess" enabled="true" level="WARNING" enabled_by_default="true">
|
||||
<option name="ignoreReferencesToLocalInnerClasses" value="false" />
|
||||
|
@ -1094,7 +1108,6 @@
|
|||
<option name="m_ignoreStaticMethodCalls" value="false" />
|
||||
<option name="m_ignoreStaticAccessFromStaticContext" value="false" />
|
||||
</inspection_tool>
|
||||
<inspection_tool class="UnreachableCallsOfFunction" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="UnreachableCode" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="UnsecureRandomNumberGeneration" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="UnusedClass" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
|
@ -1104,12 +1117,12 @@
|
|||
<inspection_tool class="UnusedIncludeDirective" enabled="true" level="WEAK WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="UnusedInstanceVariable" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="UnusedLibrary" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="UnusedLocalVariable" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="UnusedLocalVariable" enabled="true" level="WEAK WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="UnusedLocalization" enabled="true" level="WEAK WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="UnusedMacro" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="UnusedMainParameter" enabled="true" level="WEAK WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="UnusedMethod" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="UnusedParameter" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="UnusedParameter" enabled="true" level="WEAK WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="UnusedProperty" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="UnusedStruct" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="UnusedTemplateParameter" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
|
@ -1147,6 +1160,7 @@
|
|||
<inspection_tool class="WaitNotInLoop" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="WaitNotifyNotInSynchronizedContext" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="WaitOrAwaitWithoutTimeout" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="WaitWhileHoldingTwoLocks" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="WaitWithoutCorrespondingNotify" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="WeakerAccess" enabled="true" level="WARNING" enabled_by_default="true">
|
||||
<option name="SUGGEST_PACKAGE_LOCAL_FOR_MEMBERS" value="true" />
|
||||
|
@ -1154,7 +1168,7 @@
|
|||
<option name="SUGGEST_PRIVATE_FOR_INNERS" value="false" />
|
||||
</inspection_tool>
|
||||
<inspection_tool class="ZeroLengthArrayInitialization" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="unused" enabled="false" level="WARNING" enabled_by_default="false" checkParameterExcludingHierarchy="false">
|
||||
<inspection_tool class="unused" enabled="false" level="WARNING" enabled_by_default="false">
|
||||
<option name="LOCAL_VARIABLE" value="true" />
|
||||
<option name="FIELD" value="true" />
|
||||
<option name="METHOD" value="true" />
|
||||
|
|
40
.idea/jarRepositories.xml
generated
Normal file
40
.idea/jarRepositories.xml
generated
Normal file
|
@ -0,0 +1,40 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="RemoteRepositoriesConfiguration">
|
||||
<remote-repository>
|
||||
<option name="id" value="central" />
|
||||
<option name="name" value="Maven Central repository" />
|
||||
<option name="url" value="https://repo1.maven.org/maven2" />
|
||||
</remote-repository>
|
||||
<remote-repository>
|
||||
<option name="id" value="jboss.community" />
|
||||
<option name="name" value="JBoss Community repository" />
|
||||
<option name="url" value="https://repository.jboss.org/nexus/content/repositories/public/" />
|
||||
</remote-repository>
|
||||
<remote-repository>
|
||||
<option name="id" value="BintrayJCenter" />
|
||||
<option name="name" value="BintrayJCenter" />
|
||||
<option name="url" value="https://jcenter.bintray.com/" />
|
||||
</remote-repository>
|
||||
<remote-repository>
|
||||
<option name="id" value="Google" />
|
||||
<option name="name" value="Google" />
|
||||
<option name="url" value="https://dl.google.com/dl/android/maven2/" />
|
||||
</remote-repository>
|
||||
<remote-repository>
|
||||
<option name="id" value="MavenRepo" />
|
||||
<option name="name" value="MavenRepo" />
|
||||
<option name="url" value="https://repo.maven.apache.org/maven2/" />
|
||||
</remote-repository>
|
||||
<remote-repository>
|
||||
<option name="id" value="maven" />
|
||||
<option name="name" value="maven" />
|
||||
<option name="url" value="file:/$PROJECT_DIR$/app/libraries/" />
|
||||
</remote-repository>
|
||||
<remote-repository>
|
||||
<option name="id" value="MavenLocal" />
|
||||
<option name="name" value="MavenLocal" />
|
||||
<option name="url" value="file:/$USER_HOME$/.m2/repository/" />
|
||||
</remote-repository>
|
||||
</component>
|
||||
</project>
|
5
.idea/kotlinc.xml
generated
5
.idea/kotlinc.xml
generated
|
@ -1,9 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="Kotlin2JvmCompilerArguments">
|
||||
<option name="jvmTarget" value="1.8" />
|
||||
</component>
|
||||
<component name="KotlinJpsPluginSettings">
|
||||
<option name="version" value="1.7.21" />
|
||||
<option name="jvmTarget" value="15" />
|
||||
</component>
|
||||
</project>
|
59
.idea/misc.xml
generated
Normal file
59
.idea/misc.xml
generated
Normal file
|
@ -0,0 +1,59 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ExternalStorageConfigurationManager" enabled="true" />
|
||||
<component name="JavadocGenerationManager">
|
||||
<option name="OUTPUT_DIRECTORY" value="$PROJECT_DIR$/../LightSwitchEXTRA/JDoc" />
|
||||
<option name="OPTION_SCOPE" value="private" />
|
||||
</component>
|
||||
<component name="NullableNotNullManager">
|
||||
<option name="myDefaultNullable" value="org.jetbrains.annotations.Nullable" />
|
||||
<option name="myDefaultNotNull" value="androidx.annotation.NonNull" />
|
||||
<option name="myNullables">
|
||||
<value>
|
||||
<list size="15">
|
||||
<item index="0" class="java.lang.String" itemvalue="org.jetbrains.annotations.Nullable" />
|
||||
<item index="1" class="java.lang.String" itemvalue="javax.annotation.Nullable" />
|
||||
<item index="2" class="java.lang.String" itemvalue="javax.annotation.CheckForNull" />
|
||||
<item index="3" class="java.lang.String" itemvalue="edu.umd.cs.findbugs.annotations.Nullable" />
|
||||
<item index="4" class="java.lang.String" itemvalue="android.support.annotation.Nullable" />
|
||||
<item index="5" class="java.lang.String" itemvalue="androidx.annotation.Nullable" />
|
||||
<item index="6" class="java.lang.String" itemvalue="androidx.annotation.RecentlyNullable" />
|
||||
<item index="7" class="java.lang.String" itemvalue="org.checkerframework.checker.nullness.qual.Nullable" />
|
||||
<item index="8" class="java.lang.String" itemvalue="org.checkerframework.checker.nullness.compatqual.NullableDecl" />
|
||||
<item index="9" class="java.lang.String" itemvalue="org.checkerframework.checker.nullness.compatqual.NullableType" />
|
||||
<item index="10" class="java.lang.String" itemvalue="android.annotation.Nullable" />
|
||||
<item index="11" class="java.lang.String" itemvalue="com.android.annotations.Nullable" />
|
||||
<item index="12" class="java.lang.String" itemvalue="org.eclipse.jdt.annotation.Nullable" />
|
||||
<item index="13" class="java.lang.String" itemvalue="io.reactivex.annotations.Nullable" />
|
||||
<item index="14" class="java.lang.String" itemvalue="io.reactivex.rxjava3.annotations.Nullable" />
|
||||
</list>
|
||||
</value>
|
||||
</option>
|
||||
<option name="myNotNulls">
|
||||
<value>
|
||||
<list size="14">
|
||||
<item index="0" class="java.lang.String" itemvalue="org.jetbrains.annotations.NotNull" />
|
||||
<item index="1" class="java.lang.String" itemvalue="javax.annotation.Nonnull" />
|
||||
<item index="2" class="java.lang.String" itemvalue="edu.umd.cs.findbugs.annotations.NonNull" />
|
||||
<item index="3" class="java.lang.String" itemvalue="android.support.annotation.NonNull" />
|
||||
<item index="4" class="java.lang.String" itemvalue="androidx.annotation.NonNull" />
|
||||
<item index="5" class="java.lang.String" itemvalue="androidx.annotation.RecentlyNonNull" />
|
||||
<item index="6" class="java.lang.String" itemvalue="org.checkerframework.checker.nullness.qual.NonNull" />
|
||||
<item index="7" class="java.lang.String" itemvalue="org.checkerframework.checker.nullness.compatqual.NonNullDecl" />
|
||||
<item index="8" class="java.lang.String" itemvalue="org.checkerframework.checker.nullness.compatqual.NonNullType" />
|
||||
<item index="9" class="java.lang.String" itemvalue="android.annotation.NonNull" />
|
||||
<item index="10" class="java.lang.String" itemvalue="com.android.annotations.NonNull" />
|
||||
<item index="11" class="java.lang.String" itemvalue="org.eclipse.jdt.annotation.NonNull" />
|
||||
<item index="12" class="java.lang.String" itemvalue="io.reactivex.annotations.NonNull" />
|
||||
<item index="13" class="java.lang.String" itemvalue="io.reactivex.rxjava3.annotations.NonNull" />
|
||||
</list>
|
||||
</value>
|
||||
</option>
|
||||
</component>
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_11" default="false" project-jdk-name="JDK" project-jdk-type="JavaSDK">
|
||||
<output url="file://$PROJECT_DIR$/build/classes" />
|
||||
</component>
|
||||
<component name="ProjectType">
|
||||
<option name="id" value="Android" />
|
||||
</component>
|
||||
</project>
|
|
@ -1,6 +1,6 @@
|
|||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="Controller Configuration" type="AndroidRunConfigurationType" factoryName="Android App" activateToolWindowBeforeRun="false">
|
||||
<module name="skyline.app.main" />
|
||||
<module name="skyline.app" />
|
||||
<option name="DEPLOY" value="true" />
|
||||
<option name="DEPLOY_APK_FROM_BUNDLE" value="false" />
|
||||
<option name="DEPLOY_AS_INSTANT" value="false" />
|
||||
|
@ -8,13 +8,13 @@
|
|||
<option name="PM_INSTALL_OPTIONS" value="" />
|
||||
<option name="ALL_USERS" value="false" />
|
||||
<option name="ALWAYS_INSTALL_WITH_PM" value="false" />
|
||||
<option name="CLEAR_APP_STORAGE" value="false" />
|
||||
<option name="DYNAMIC_FEATURES_DISABLED_LIST" value="" />
|
||||
<option name="ACTIVITY_EXTRA_FLAGS" value="" />
|
||||
<option name="MODE" value="specific_activity" />
|
||||
<option name="CLEAR_LOGCAT" value="false" />
|
||||
<option name="SHOW_LOGCAT_AUTOMATICALLY" value="false" />
|
||||
<option name="INSPECTION_WITHOUT_ACTIVITY_RESTART" value="false" />
|
||||
<option name="SKIP_NOOP_APK_INSTALLATIONS" value="true" />
|
||||
<option name="FORCE_STOP_RUNNING_APP" value="true" />
|
||||
<option name="TARGET_SELECTION_MODE" value="DEVICE_AND_SNAPSHOT_COMBO_BOX" />
|
||||
<option name="SELECTED_CLOUD_MATRIX_CONFIGURATION_ID" value="-1" />
|
||||
<option name="SELECTED_CLOUD_MATRIX_PROJECT_ID" value="" />
|
||||
|
@ -45,7 +45,7 @@
|
|||
<option name="ADVANCED_PROFILING_ENABLED" value="false" />
|
||||
<option name="STARTUP_PROFILING_ENABLED" value="false" />
|
||||
<option name="STARTUP_CPU_PROFILING_ENABLED" value="false" />
|
||||
<option name="STARTUP_CPU_PROFILING_CONFIGURATION_NAME" value="Callstack Sample" />
|
||||
<option name="STARTUP_CPU_PROFILING_CONFIGURATION_NAME" value="Sample Java Methods" />
|
||||
<option name="STARTUP_NATIVE_MEMORY_PROFILING_ENABLED" value="false" />
|
||||
<option name="NATIVE_MEMORY_SAMPLE_RATE_BYTES" value="2048" />
|
||||
</Profilers>
|
||||
|
|
8
.idea/runConfigurations/Main.xml
generated
8
.idea/runConfigurations/Main.xml
generated
|
@ -1,6 +1,6 @@
|
|||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="Main" type="AndroidRunConfigurationType" factoryName="Android App" activateToolWindowBeforeRun="false">
|
||||
<module name="skyline.app.main" />
|
||||
<module name="skyline.app" />
|
||||
<option name="DEPLOY" value="true" />
|
||||
<option name="DEPLOY_APK_FROM_BUNDLE" value="false" />
|
||||
<option name="DEPLOY_AS_INSTANT" value="false" />
|
||||
|
@ -8,13 +8,13 @@
|
|||
<option name="PM_INSTALL_OPTIONS" value="" />
|
||||
<option name="ALL_USERS" value="false" />
|
||||
<option name="ALWAYS_INSTALL_WITH_PM" value="false" />
|
||||
<option name="CLEAR_APP_STORAGE" value="false" />
|
||||
<option name="DYNAMIC_FEATURES_DISABLED_LIST" value="" />
|
||||
<option name="ACTIVITY_EXTRA_FLAGS" value="" />
|
||||
<option name="MODE" value="default_activity" />
|
||||
<option name="CLEAR_LOGCAT" value="false" />
|
||||
<option name="SHOW_LOGCAT_AUTOMATICALLY" value="false" />
|
||||
<option name="INSPECTION_WITHOUT_ACTIVITY_RESTART" value="false" />
|
||||
<option name="SKIP_NOOP_APK_INSTALLATIONS" value="true" />
|
||||
<option name="FORCE_STOP_RUNNING_APP" value="true" />
|
||||
<option name="TARGET_SELECTION_MODE" value="DEVICE_AND_SNAPSHOT_COMBO_BOX" />
|
||||
<option name="SELECTED_CLOUD_MATRIX_CONFIGURATION_ID" value="-1" />
|
||||
<option name="SELECTED_CLOUD_MATRIX_PROJECT_ID" value="" />
|
||||
|
@ -45,7 +45,7 @@
|
|||
<option name="ADVANCED_PROFILING_ENABLED" value="false" />
|
||||
<option name="STARTUP_PROFILING_ENABLED" value="false" />
|
||||
<option name="STARTUP_CPU_PROFILING_ENABLED" value="false" />
|
||||
<option name="STARTUP_CPU_PROFILING_CONFIGURATION_NAME" value="Callstack Sample" />
|
||||
<option name="STARTUP_CPU_PROFILING_CONFIGURATION_NAME" value="Sample Java Methods" />
|
||||
<option name="STARTUP_NATIVE_MEMORY_PROFILING_ENABLED" value="false" />
|
||||
<option name="NATIVE_MEMORY_SAMPLE_RATE_BYTES" value="2048" />
|
||||
</Profilers>
|
||||
|
|
10
.idea/runConfigurations/Settings.xml
generated
10
.idea/runConfigurations/Settings.xml
generated
|
@ -1,6 +1,6 @@
|
|||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="Settings" type="AndroidRunConfigurationType" factoryName="Android App" activateToolWindowBeforeRun="false">
|
||||
<module name="skyline.app.main" />
|
||||
<module name="skyline.app" />
|
||||
<option name="DEPLOY" value="true" />
|
||||
<option name="DEPLOY_APK_FROM_BUNDLE" value="false" />
|
||||
<option name="DEPLOY_AS_INSTANT" value="false" />
|
||||
|
@ -8,13 +8,13 @@
|
|||
<option name="PM_INSTALL_OPTIONS" value="" />
|
||||
<option name="ALL_USERS" value="false" />
|
||||
<option name="ALWAYS_INSTALL_WITH_PM" value="false" />
|
||||
<option name="CLEAR_APP_STORAGE" value="false" />
|
||||
<option name="DYNAMIC_FEATURES_DISABLED_LIST" value="" />
|
||||
<option name="ACTIVITY_EXTRA_FLAGS" value="" />
|
||||
<option name="MODE" value="specific_activity" />
|
||||
<option name="CLEAR_LOGCAT" value="false" />
|
||||
<option name="SHOW_LOGCAT_AUTOMATICALLY" value="false" />
|
||||
<option name="INSPECTION_WITHOUT_ACTIVITY_RESTART" value="false" />
|
||||
<option name="SKIP_NOOP_APK_INSTALLATIONS" value="true" />
|
||||
<option name="FORCE_STOP_RUNNING_APP" value="true" />
|
||||
<option name="TARGET_SELECTION_MODE" value="DEVICE_AND_SNAPSHOT_COMBO_BOX" />
|
||||
<option name="SELECTED_CLOUD_MATRIX_CONFIGURATION_ID" value="-1" />
|
||||
<option name="SELECTED_CLOUD_MATRIX_PROJECT_ID" value="" />
|
||||
|
@ -45,12 +45,12 @@
|
|||
<option name="ADVANCED_PROFILING_ENABLED" value="false" />
|
||||
<option name="STARTUP_PROFILING_ENABLED" value="false" />
|
||||
<option name="STARTUP_CPU_PROFILING_ENABLED" value="false" />
|
||||
<option name="STARTUP_CPU_PROFILING_CONFIGURATION_NAME" value="Callstack Sample" />
|
||||
<option name="STARTUP_CPU_PROFILING_CONFIGURATION_NAME" value="Sample Java Methods" />
|
||||
<option name="STARTUP_NATIVE_MEMORY_PROFILING_ENABLED" value="false" />
|
||||
<option name="NATIVE_MEMORY_SAMPLE_RATE_BYTES" value="2048" />
|
||||
</Profilers>
|
||||
<option name="DEEP_LINK" value="" />
|
||||
<option name="ACTIVITY_CLASS" value="emu.skyline.settings.SettingsActivity" />
|
||||
<option name="ACTIVITY_CLASS" value="emu.skyline.SettingsActivity" />
|
||||
<option name="SEARCH_ACTIVITY_IN_GLOBAL_SCOPE" value="false" />
|
||||
<option name="SKIP_ACTIVITY_VALIDATION" value="false" />
|
||||
<method v="2">
|
||||
|
|
3
.idea/scopes/ShaderCompiler.xml
generated
3
.idea/scopes/ShaderCompiler.xml
generated
|
@ -1,3 +0,0 @@
|
|||
<component name="DependencyValidationManager">
|
||||
<scope name="ShaderCompiler" pattern="file[skyline.app.main]:shader-compiler//*" />
|
||||
</component>
|
4
.idea/scopes/SkylineKotlin.xml
generated
4
.idea/scopes/SkylineKotlin.xml
generated
|
@ -1,3 +1,3 @@
|
|||
<component name="DependencyValidationManager">
|
||||
<scope name="SkylineKotlin" pattern="file[skyline.app.main]:java//*.kt" />
|
||||
</component>
|
||||
<scope name="SkylineKotlin" pattern="file[skyline.app]:src/main/java//*.kt" />
|
||||
</component>
|
||||
|
|
4
.idea/scopes/SkylineLibraries.xml
generated
4
.idea/scopes/SkylineLibraries.xml
generated
|
@ -1,3 +1,3 @@
|
|||
<component name="DependencyValidationManager">
|
||||
<scope name="SkylineLibraries" pattern="(file[skyline.app]:libraries/fmt/include//*||file[skyline.app]:libraries/frozen/include//*||file[skyline.app]:libraries/lz4/lib//*||file[skyline.app]:libraries/oboe/include//*||file[skyline.app]:libraries/perfetto/include//*||file:libraries/pugixml/src/pugixml.hpp||file[skyline.app]:libraries/tzcode/include/*||file[skyline.app]:libraries/vkhpp/vulkan//*||file[skyline.app]:libraries/vkhpp/Vulkan-Headers/include//*)&&!file:libraries/vkhpp/Vulkan-Headers/include/vulkan/vulkan.hpp||file:libraries/vkma/include/vk_mem_alloc.h" />
|
||||
</component>
|
||||
<scope name="SkylineLibraries" pattern="file[skyline.app]:libraries//*" />
|
||||
</component>
|
||||
|
|
4
.idea/scopes/SkylineNative.xml
generated
4
.idea/scopes/SkylineNative.xml
generated
|
@ -1,3 +1,3 @@
|
|||
<component name="DependencyValidationManager">
|
||||
<scope name="SkylineNative" pattern="file[skyline.app.main]:cpp//*.cpp||file[skyline.app.main]:cpp//*.h||file[skyline.app.main]:cpp//*.S||file[skyline.app.main]:cpp//*.natvis" />
|
||||
</component>
|
||||
<scope name="SkylineNative" pattern="file[skyline.app]:src/main/cpp//*.cpp||file[skyline.app]:src/main/cpp//*.h||file[skyline.app]:src/main/cpp//*.S" />
|
||||
</component>
|
||||
|
|
4
.idea/scopes/SkylineXml.xml
generated
4
.idea/scopes/SkylineXml.xml
generated
|
@ -1,3 +1,3 @@
|
|||
<component name="DependencyValidationManager">
|
||||
<scope name="SkylineXml" pattern="file[skyline.app.main]:res/layout/*||file[app.main]:res/menu/*||file[skyline.app.main]:res/values/*||file[skyline.app.main]:res/values-night/*||file[skyline.app.main]:res/xml/*" />
|
||||
</component>
|
||||
<scope name="SkylineXml" pattern="file[skyline.app]:src/main/res/layout/*||file[app]:src/main/res/menu/*||file[skyline.app]:src/main/res/values/*||file[skyline.app]:src/main/res/values-night/*||file[skyline.app]:src/main/res/xml/*" />
|
||||
</component>
|
||||
|
|
14
.idea/vcs.xml
generated
Normal file
14
.idea/vcs.xml
generated
Normal file
|
@ -0,0 +1,14 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="" vcs="Git" />
|
||||
<mapping directory="$PROJECT_DIR$/app/libraries/fmt" vcs="Git" />
|
||||
<mapping directory="$PROJECT_DIR$/app/libraries/frozen" vcs="Git" />
|
||||
<mapping directory="$PROJECT_DIR$/app/libraries/lz4" vcs="Git" />
|
||||
<mapping directory="$PROJECT_DIR$/app/libraries/oboe" vcs="Git" />
|
||||
<mapping directory="$PROJECT_DIR$/app/libraries/perfetto" vcs="Git" />
|
||||
<mapping directory="$PROJECT_DIR$/app/libraries/pugixml" vcs="Git" />
|
||||
<mapping directory="$PROJECT_DIR$/app/libraries/tzcode" vcs="Git" />
|
||||
<mapping directory="$PROJECT_DIR$/app/libraries/vkhpp" vcs="Git" />
|
||||
</component>
|
||||
</project>
|
118
BUILDING.md
118
BUILDING.md
|
@ -1,118 +0,0 @@
|
|||
# Building Guide
|
||||
|
||||
### Software needed
|
||||
* [Git](https://git-scm.com/download)
|
||||
* [Android Studio](https://developer.android.com/studio) – We recommend to get the latest stable version
|
||||
|
||||
### Steps
|
||||
<details><summary><i>Windows only</i></summary>
|
||||
<p>
|
||||
|
||||
> In a terminal prompt with **administrator** privileges, enable git symlinks globally:
|
||||
>
|
||||
> ```cmd
|
||||
> git config --global core.symlinks true
|
||||
> ```
|
||||
>
|
||||
> Use this elevated prompt for the next steps.
|
||||
|
||||
</p>
|
||||
</details>
|
||||
|
||||
Clone the repo **recursively**, either with your preferred Git GUI or with the command below:
|
||||
```cmd
|
||||
git clone https://github.com/skyline-emu/skyline.git --recursive
|
||||
```
|
||||
|
||||
Open Android Studio
|
||||
<details><summary><i>First time users only</i></summary>
|
||||
<p>
|
||||
|
||||
> If you opened Android Studio for the first time, choose the `Standard` install type and complete the setup wizard leaving all settings to their default value.
|
||||
> <p><img height="400" src="https://user-images.githubusercontent.com/37104290/162196602-4c142ed0-0c26-4628-8062-7ac9785201cc.png"></p>
|
||||
> If you get any errors on "Intel® HAXM" or "Android Emulator Hypervisor Driver for AMD Processors", you can safely ignore them as they won't be used for Skyline.
|
||||
|
||||
</p>
|
||||
</details>
|
||||
|
||||
Import the project by clicking on the `Open` icon, then in the file picker choose the `skyline` folder you just cloned in the steps above:
|
||||
<p>
|
||||
<img height="400" src="https://user-images.githubusercontent.com/37104290/162200497-dddfa9f0-00c6-4a32-84c2-1f0ff743a7e2.png">
|
||||
<img height="400" src="https://user-images.githubusercontent.com/37104290/162196879-08d9684b-c6a2-4636-9c23-c026cb7d7494.png">
|
||||
</p>
|
||||
|
||||
Exclude the following folders from indexing:
|
||||
- `app/libraries/llvm`
|
||||
- `app/libraries/boost`
|
||||
|
||||
To exclude a folder, switch to the project view:
|
||||
<p>
|
||||
<img height="400" src="https://user-images.githubusercontent.com/37104290/163343887-56a0b170-2249-45c4-a758-2b33cbfbc4ab.png">
|
||||
<img height="400" src="https://user-images.githubusercontent.com/37104290/163343932-bed0c59c-7aaa-44f6-bdc4-0a10f966fb56.png">
|
||||
</p>
|
||||
|
||||
In the project view navigate to the `app/libraries` folder, right-click on the folder you want to exclude and navigate the menus to the `Exclude` option:
|
||||
<p>
|
||||
<img height="400" src="https://user-images.githubusercontent.com/37104290/162200274-f739e960-82ca-4b12-95eb-caa88a063d61.png">
|
||||
<img height="400" src="https://user-images.githubusercontent.com/37104290/162196999-a0376e13-0399-4352-a30d-85d6785151a9.png">
|
||||
</p>
|
||||
|
||||
If an `Invalid Gradle JDK configuration found` error comes up, select `Use Embedded JDK`:
|
||||
<p><img height="250" src="https://user-images.githubusercontent.com/37104290/162197215-b28ea3ec-ed5c-4d83-ac9a-19e892caa129.png"></p>
|
||||
|
||||
An error about NDK not being configured will be shown:
|
||||
<p><img height="250" src="https://user-images.githubusercontent.com/37104290/162197226-3d9bf980-19af-4cad-86a3-c43cad05e185.png"></p>
|
||||
|
||||
Ignore the suggested version reported by Android Studio. Instead, find the NDK version to download inside the `app/build.gradle` file:
|
||||
```gradle
|
||||
ndkVersion 'X.Y.Z'
|
||||
```
|
||||
From that same file also note down the CMake version required:
|
||||
```gradle
|
||||
externalNativeBuild {
|
||||
cmake {
|
||||
version 'A.B.C+'
|
||||
path "CMakeLists.txt"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Open the SDK manager from the top-right toolbar:
|
||||
<p><img height="75" src="https://user-images.githubusercontent.com/37104290/162198029-4f29c50c-75eb-49ce-b05f-bb6413bf844c.png"></p>
|
||||
|
||||
Navigate to the `SDK Tools` tab and enable the `Show Package Details` checkbox in the bottom-right corner:
|
||||
<p><img height="400" src="https://user-images.githubusercontent.com/37104290/162198766-37045d58-352c-48d6-b8de-67c1ddb7c757.png"></p>
|
||||
|
||||
Expand the `NDK (Side by side)` and `CMake` entries, select the appropriate version from the previous step, then click `OK`.
|
||||
|
||||
Finally, sync the project:
|
||||
<p><img height="75" src="https://user-images.githubusercontent.com/37104290/162199780-b5406b5d-480d-4371-9dc4-5cfc6d655746.png"></p>
|
||||
|
||||
|
||||
## Common issues (and how to fix them)
|
||||
|
||||
* `Cmake Error: CMake was unable to find a build program corresponding to "Ninja"`
|
||||
|
||||
Check that you installed the correct CMake version in the Android Studio SDK Manager. If you're sure you have the correct one, you may try adding the path to CMake binaries installed by Android Studio to the `local.properties` file:
|
||||
```properties
|
||||
cmake.dir=<path-to-cmake-folder>
|
||||
```
|
||||
E.g. on Windows:
|
||||
```properties
|
||||
cmake.dir=C\:\\Users\\skyline\\AppData\\Local\\Android\\Sdk\\cmake\\3.18.1
|
||||
```
|
||||
|
||||
* `'shader_compiler/*.h' file not found`
|
||||
|
||||
You didn't clone the repository with symlinks enabled. Windows requires administrator privileges to create symlinks so it's likely it didn't create them.
|
||||
In an **administrator** terminal prompt navigate to the Skyline root project folder and run:
|
||||
```cmd
|
||||
git submodule deinit app/libraries/shader-compiler
|
||||
git config core.symlinks true
|
||||
git submodule foreach git config core.symlinks true
|
||||
git submodule update --init --recursive app/libraries/shader-compiler
|
||||
```
|
||||
If you'd like to, you can enable symlinks globally by running: (this will only affect new repositories)
|
||||
```cmd
|
||||
git config --global core.symlinks true
|
||||
```
|
|
@ -14,9 +14,6 @@ Android Studio comes with a code formatter in-built, this can fix minor mistakes
|
|||
|
||||
This can also be done by using `Ctrl + Alt + L` on Windows, `Ctrl + Shift + Alt + L` on Linux and `Option + Command + L` on macOS.
|
||||
|
||||
### Skyline Edge
|
||||
Any code that's been PR'd to the Skyline repository will only be in Edge builds for two weeks, after which it will be merged into the mainline branch. This is to ensure that any bugs that may have been introduced by the PR are caught and fixed before it's merged into the mainline branch. If you have any issues with this, you can request that we add the `CI` tag to your PRs so that CI builds are provided pre-merge.
|
||||
|
||||
## C++
|
||||
### Include Order
|
||||
* STD includes
|
||||
|
@ -60,45 +57,45 @@ We generally follow the rule of **"Functional Spacing"**, that being spacing bet
|
|||
Here are a few examples of this to help with intution:
|
||||
* Spacing should generally follow multiple related variable declarations, this applies even more if error checking code needs to follow it
|
||||
```cpp
|
||||
auto a{GetSomethingA()};
|
||||
auto b{GetSomethingB()};
|
||||
auto c{GetSomethingC()};
|
||||
auto a = GetSomethingA();
|
||||
auto b = GetSomethingB();
|
||||
auto c = GetSomethingC();
|
||||
|
||||
auto result{DoSomething(a, b, c)};
|
||||
auto result = DoSomething(a, b, c);
|
||||
if (!result)
|
||||
throw exception("DoSomething has failed: {}", result);
|
||||
```
|
||||
* If a function doesn't require multiple variable declarations, the function call should be right after the variable declaration
|
||||
```cpp
|
||||
auto a{GetClassA()};
|
||||
auto a = GetClassA();
|
||||
a.DoSomething();
|
||||
|
||||
auto b{GetClassB()};
|
||||
auto b = GetClassB();
|
||||
b.DoSomething();
|
||||
```
|
||||
* If a single variable is used by a single-line control flow statement, there can be no spaces after it's declaration
|
||||
```cpp
|
||||
auto a{GetClass()};
|
||||
auto a = GetClass();
|
||||
if (a.fail)
|
||||
throw exception();
|
||||
```
|
||||
* **Be consistent** (The above examples assume that `a`/`b`/`c` are correlated)
|
||||
* Inconsistent
|
||||
```cpp
|
||||
auto a{GetClassA()};
|
||||
auto a = GetClassA();
|
||||
a.DoSomething();
|
||||
|
||||
auto b{GetClassB()};
|
||||
auto c{GetClassC()};
|
||||
auto b = GetClassB();
|
||||
auto c = GetClassC();
|
||||
|
||||
b.DoSomething();
|
||||
c.DoSomething();
|
||||
```
|
||||
* Consistent #1
|
||||
```cpp
|
||||
auto a{GetClassA()};
|
||||
auto b{GetClassB()};
|
||||
auto c{GetClassC()};
|
||||
auto a = GetClassA();
|
||||
auto b = GetClassB();
|
||||
auto c = GetClassC();
|
||||
|
||||
a.DoSomething();
|
||||
b.DoSomething();
|
||||
|
@ -106,13 +103,13 @@ Here are a few examples of this to help with intution:
|
|||
```
|
||||
* Consistent #2
|
||||
```cpp
|
||||
auto a{GetClassA()};
|
||||
auto a = GetClassA();
|
||||
a.DoSomething();
|
||||
|
||||
auto b{GetClassB()};
|
||||
auto b = GetClassB();
|
||||
b.DoSomething();
|
||||
|
||||
auto c{GetClassC()};
|
||||
auto c = GetClassC();
|
||||
c.DoSomething();
|
||||
```
|
||||
|
||||
|
@ -165,8 +162,8 @@ Here are a few examples of this to help with intution:
|
|||
We generally support the usage of functional programming and lambda, usage of it for assigning conditional variables is recommended especially if it would otherwise be a nested ternary statement:
|
||||
* With Lambda (Inlined function)
|
||||
```cpp
|
||||
auto a{random()};
|
||||
auto b{[a] {
|
||||
auto a = random();
|
||||
auto b = [a] {
|
||||
if (a > 1000)
|
||||
return 0;
|
||||
else if (a > 500)
|
||||
|
@ -175,12 +172,12 @@ We generally support the usage of functional programming and lambda, usage of it
|
|||
return 2;
|
||||
else
|
||||
return 3;
|
||||
}()};
|
||||
}();
|
||||
```
|
||||
* With Ternary Operator
|
||||
```cpp
|
||||
auto a{random()};
|
||||
auto b{(a > 1000) ? 0 : ((a > 500) ? 1 : (a > 250 ? 2 : 3))};
|
||||
auto a = random();
|
||||
auto b = (a > 1000) ? 0 : ((a > 500) ? 1 : (a > 250 ? 2 : 3));
|
||||
```
|
||||
|
||||
### References
|
||||
|
@ -213,8 +210,8 @@ Use C++ range-based iterators for any C++ container iteration unless it can be p
|
|||
### Usage of auto
|
||||
Use `auto` to assign a variable the type of the value it's being assigned to, but not where a different type is desired. So, as a rule of thumb always specify the type when setting something from a number rather than depending on `auto`. In addition, prefer not to use `auto` in cases where it's hard to determine the return type due to assigned value being complex.
|
||||
```cpp
|
||||
u8 a{20}; // `20` won't be stored in a `u8` but rather in a `int` (i32, generally) if `auto` is used
|
||||
auto b{std::make_shared<Something>()}; // In this case `auto` is used to avoid typing out `std::shared_ptr<Something>`
|
||||
u8 a = 20; // `20` won't be stored in a `u8` but rather in a `int` (i32, generally) if `auto` is used
|
||||
auto b = std::make_shared<Something>(); // In this case `auto` is used to avoid typing out `std::shared_ptr<Something>`
|
||||
```
|
||||
|
||||
### Primitive Types
|
||||
|
@ -228,55 +225,6 @@ In addition, try to `constexpr` as much as possible including constructors and f
|
|||
We should also mention that this isn't promoting the usage of `const`, it's use is actually discouraged out of references, in which case it is extremely encouraged. In addition, pointers are a general exception to this, using `const` with them isn't encouraged nor discouraged. Another exception are class functions, they can be made `const` if used from a `const` reference/pointer and don't
|
||||
modify any members but do not do this preemptively.
|
||||
|
||||
### Initialization
|
||||
We use bracketed initialization as opposed to traditional initalization due to the better type checking it offers and the consistency with designated initalizers.
|
||||
|
||||
* Correct
|
||||
```c++
|
||||
int a{FindA()};
|
||||
static constexpr size_t AConstant{1ULL << 63}
|
||||
|
||||
for (int i{}; i < a; i++);
|
||||
```
|
||||
|
||||
* Incorrect
|
||||
```c++
|
||||
int a = FindA();
|
||||
static constexpr size_t AConstant = 1ULL << 63;
|
||||
|
||||
for (int i = 0; i < a; i++);
|
||||
```
|
||||
|
||||
### Wrapping
|
||||
We do not enforce a particular limit on line lengths however excessively long lines that may be difficult to read when soft-wrapped should be wrapped semantically. See the below examples:
|
||||
|
||||
* Correct:
|
||||
```c++
|
||||
PresentationEngine::PresentationEngine(const DeviceState &state, GPU &gpu)
|
||||
: state(state),
|
||||
gpu(gpu),
|
||||
acquireFence(gpu.vkDevice, vk::FenceCreateInfo{}),
|
||||
presentationTrack(static_cast<u64>(trace::TrackIds::Presentation), perfetto::ProcessTrack::Current()),
|
||||
choreographerThread(&PresentationEngine::ChoreographerThread, this),
|
||||
vsyncEvent(std::make_shared<kernel::type::KEvent>(state, true)) {
|
||||
```
|
||||
|
||||
* Incorrect:
|
||||
```c++
|
||||
PresentationEngine::PresentationEngine(const DeviceState &state, GPU &gpu) : state(state), gpu(gpu), acquireFence(gpu.vkDevice, vk::FenceCreateInfo{}), presentationTrack(static_cast<u64>(trace::TrackIds::Presentation), perfetto::ProcessTrack::Current()), choreographerThread(&PresentationEngine::ChoreographerThread, this), vsyncEvent(std::make_shared<kernel::type::KEvent>(state, true)) {
|
||||
```
|
||||
|
||||
* Incorrect
|
||||
```c++
|
||||
PresentationEngine::PresentationEngine(const DeviceState &state, GPU &gpu)
|
||||
: state(state), gpu(gpu), acquireFence(gpu.vkDevice, vk::FenceCreateInfo{}), presentationTrack(static_cast<u64>(trace::TrackIds::Presentation), perfetto::ProcessTrack::Current()),
|
||||
choreographerThread(&PresentationEngine::ChoreographerThread, this),
|
||||
vsyncEvent(std::make_shared<kernel::type::KEvent>(state, true)) {
|
||||
```
|
||||
|
||||
### Vulkan.hpp Header Size
|
||||
The size of the header imported for [Vulkan-Hpp](https://github.com/KhronosGroup/Vulkan-Hpp) is extremely large and exceeds the CLion default analysis limit, it is required to run for properly annotating any code which uses components from it. To override this limit, refer to this [article from JetBrains](https://www.jetbrains.com/help/objc/configuring-file-size-limit.html#file-size-limit) or navigate to Help -> Edit Custom Properties and add `idea.max.intellisense.filesize=20000` to set the maximum limit to 20MB which should be adequate for it.
|
||||
|
||||
## Kotlin
|
||||
### Naming rules
|
||||
* Enumerator: `PascalCase` **(1)**
|
||||
|
|
25
README.md
25
README.md
|
@ -1,26 +1,17 @@
|
|||
<p>
|
||||
<h3 align="center">Development on Skyline has been ceased</h3>
|
||||
<p align="center">All Skyline code is within this repository or <a href="https://github.com/skyline-emu/skyline-dev"><code>skyline-dev</code></a>. Anyone is free to fork the code to continue the work as long as they follow our <a href="LICENSE.md">MPL-2.0 license</a>, it should be noted that Skyline branding isn't licensed.</p>
|
||||
</p>
|
||||
|
||||
<h1 align="center">
|
||||
<a href="https://github.com/skyline-emu/skyline" target="_blank">
|
||||
<img height="60%" width="60%" src="https://raw.github.com/skyline-emu/branding/master/banner/skyline-banner-rounded.png"><br>
|
||||
<img height="60%" width="60%" src="https://i.imgur.com/6PJ7Ml2.png"><br>
|
||||
</a>
|
||||
<a href="https://discord.gg/XnbXNQM" target="_blank">
|
||||
<img src="https://img.shields.io/discord/545842171459272705.svg?label=&logo=discord&logoColor=ffffff&color=5865F2&labelColor=404EED">
|
||||
<img src="https://img.shields.io/discord/545842171459272705?label=Discord&logo=Discord&color=yellow">
|
||||
</a>
|
||||
<a href="https://github.com/skyline-emu/skyline/actions/workflows/ci.yml" target="_blank">
|
||||
<img src="https://github.com/skyline-emu/skyline/actions/workflows/ci.yml/badge.svg"><br>
|
||||
<img src="https://github.com/skyline-emu/skyline/actions/workflows/ci.yml/badge.svg"/><br>
|
||||
</a>
|
||||
<img src="https://forthebadge.com/images/badges/built-for-android.svg"/>
|
||||
</h1>
|
||||
|
||||
<p align="center">
|
||||
<b><a href="CONTRIBUTING.md">Contributing Guide</a> • <a href="BUILDING.md">Building Guide</a></b>
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
<b>Skyline</b> was an experimental emulator that runs on <b>ARMv8 Android™</b> devices and emulates the functionality of a <b>Nintendo Switch™</b> system, licensed under <a href="https://github.com/skyline-emu/skyline/blob/master/LICENSE.md"><b>Mozilla Public License 2.0</b></a>
|
||||
<b>Skyline</b> is an experimental emulator that runs on <b>ARMv8 Android™</b> devices and emulates the functionality of a <b>Nintendo Switch™</b> system, licensed under <a href="https://github.com/skyline-emu/skyline/blob/master/LICENSE.md"><b>Mozilla Public License 2.0</b></a>
|
||||
</p>
|
||||
|
||||
---
|
||||
|
@ -32,11 +23,11 @@ You can contact the core developers of Skyline at our **[Discord](https://discor
|
|||
|
||||
### Special Thanks
|
||||
A few noteworthy teams/projects who've helped us along the way are:
|
||||
* **[Ryujinx](https://ryujinx.org/):** We've used Ryujinx for reference throughout the project, the accuracy of their HLE implementations of Switch subsystems make it an amazing reference. The team behind the project has been extremely helpful with any queries we've had and have constantly helped us with any issues we've come across. **It should be noted that Skyline is not based on Ryujinx**.
|
||||
* **[Ryujinx](https://ryujinx.org/):** We've used Ryujinx for reference throughout the project, the amount of accuracy of their HLE kernel implementation is what makes them such an amazing reference. The team behind the project has been really helpful with any queries we've had. **It should be noted that Skyline is not based on Ryujinx**.
|
||||
|
||||
* **[yuzu](https://yuzu-emu.org/):** Skyline's shader compiler is a **fork** of *yuzu*'s shader compiler with Skyline-specific changes, using it allowed us to focus on the parts of GPU emulation that we could specifically optimize for mobile while having a high-quality shader compiler implementation as a base. The team behind *yuzu* has also often helped us and have graciously provided us with a license exemption.
|
||||
* **[Switchbrew](https://github.com/switchbrew/):** We've extensively used Switchbrew whether that be their **[wiki](https://switchbrew.org/)** with it's colossal amount of information on the Switch that has saved us countless hours of time or **[libnx](https://github.com/switchbrew/libnx)** which was crucial to initial development of the emulator to ensure that our HLE kernel and sysmodule implementations were accurate.
|
||||
|
||||
* **[Switchbrew](https://github.com/switchbrew/):** We've extensively used Switchbrew whether that be their **[wiki](https://switchbrew.org/)** with its colossal amount of information on the Switch that has saved us countless hours of time or **[libnx](https://github.com/switchbrew/libnx)** which was crucial to initial development of the emulator to ensure that our HLE kernel and sysmodule implementations were accurate.
|
||||
* **[Atmosphère](https://github.com/Atmosphere-NX/Atmosphere):** We've used [libmesosphere](https://github.com/Atmosphere-NX/Atmosphere/tree/master/libraries/libmesosphere) as another reference for our HLE kernel, it's faithfulness to the HOS kernel helps us a lot. This makes it invaluably important for us as a tool for writing code that can accurately emulate HOS behavior without missing any crucial parts.
|
||||
|
||||
---
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
cmake_minimum_required(VERSION 3.16)
|
||||
project(Skyline LANGUAGES C CXX ASM VERSION 0.3)
|
||||
project(Skyline LANGUAGES CXX ASM VERSION 0.3)
|
||||
|
||||
set(BUILD_TESTS OFF CACHE BOOL "Build Tests" FORCE)
|
||||
set(BUILD_TESTING OFF CACHE BOOL "Build Testing" FORCE)
|
||||
|
@ -9,159 +9,44 @@ set(CMAKE_CXX_STANDARD 20)
|
|||
set(CMAKE_CXX_STANDARD_REQUIRED TRUE)
|
||||
|
||||
set(source_DIR ${CMAKE_SOURCE_DIR}/src/main/cpp)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-strict-aliasing -Wno-unused-command-line-argument -fwrapv")
|
||||
set(CMAKE_CXX_FLAGS_RELEASE "-Ofast -flto=full -fno-stack-protector -DNDEBUG")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-strict-aliasing")
|
||||
set(CMAKE_CXX_FLAGS_RELEASE "-Ofast -flto=full -fno-stack-protector -Wno-unused-command-line-argument")
|
||||
if (uppercase_CMAKE_BUILD_TYPE STREQUAL "RELEASE")
|
||||
add_compile_definitions(NDEBUG)
|
||||
set(CMAKE_INTERPROCEDURAL_OPTIMIZATION TRUE)
|
||||
endif ()
|
||||
|
||||
# Build all libraries with -Ofast but with default debug data (-g) for debug and reldebug builds
|
||||
set(CMAKE_CXX_FLAGS_DEBUG "-Ofast")
|
||||
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-Ofast")
|
||||
|
||||
# libcxx
|
||||
set(ANDROID_STL "none")
|
||||
set(LIBCXX_INCLUDE_TESTS OFF)
|
||||
set(LIBCXX_INCLUDE_BENCHMARKS OFF)
|
||||
set(LIBCXX_INCLUDE_DOCS OFF)
|
||||
set(LIBCXX_ENABLE_SHARED FALSE)
|
||||
set(LIBCXX_ENABLE_ASSERTIONS FALSE)
|
||||
set(LIBCXX_STANDALONE_BUILD FALSE)
|
||||
add_subdirectory("libraries/llvm/libcxx")
|
||||
link_libraries(cxx_static)
|
||||
get_target_property(LIBCXX_INCLUDE_COMPILE_OPTION cxx-headers INTERFACE_COMPILE_OPTIONS)
|
||||
string(REGEX REPLACE "-I" "" LIBCXX_INCLUDE_DIRECTORY_LIST "${LIBCXX_INCLUDE_COMPILE_OPTION}")
|
||||
list(GET LIBCXX_INCLUDE_DIRECTORY_LIST 1 LIBCXX_TARGET_INCLUDE_DIRECTORY) # We just want the target include directory
|
||||
set_target_properties(cxx-headers PROPERTIES INTERFACE_COMPILE_OPTIONS -isystem${LIBCXX_TARGET_INCLUDE_DIRECTORY})
|
||||
|
||||
# libcxxabi
|
||||
set(LIBCXXABI_INCLUDE_TESTS OFF)
|
||||
set(LIBCXXABI_ENABLE_SHARED FALSE)
|
||||
set(LIBCXXABI_STANDALONE_BUILD FALSE)
|
||||
set(LIBCXXABI_LIBCXX_INCLUDES "${LIBCXX_TARGET_INCLUDE_DIRECTORY}" CACHE STRING "" FORCE)
|
||||
add_subdirectory("libraries/llvm/libcxxabi")
|
||||
link_libraries(cxxabi_static)
|
||||
|
||||
# Skyline's Boost fork
|
||||
set(Boost_USE_STATIC_LIBS ON)
|
||||
set(Boost_USE_MULTITHREADED ON)
|
||||
add_subdirectory("libraries/boost")
|
||||
|
||||
# {fmt}
|
||||
add_subdirectory("libraries/fmt")
|
||||
|
||||
# TzCode
|
||||
add_subdirectory("libraries/tzcode")
|
||||
target_compile_options(tzcode PRIVATE -Wno-everything)
|
||||
|
||||
# LZ4
|
||||
add_subdirectory("libraries/oboe")
|
||||
include_directories("libraries/oboe/include")
|
||||
|
||||
set(LZ4_BUILD_CLI OFF CACHE BOOL "Build LZ4 CLI" FORCE)
|
||||
set(LZ4_BUILD_LEGACY_LZ4C OFF CACHE BOOL "Build lz4c progam with legacy argument support" FORCE)
|
||||
add_subdirectory("libraries/lz4/build/cmake")
|
||||
include_directories(SYSTEM "libraries/lz4/lib")
|
||||
include_directories("libraries/lz4/lib")
|
||||
|
||||
# Vulkan + Vulkan-Hpp
|
||||
add_compile_definitions(VK_USE_PLATFORM_ANDROID_KHR) # We want all the Android-specific structures to be defined
|
||||
add_compile_definitions(VULKAN_HPP_NO_SPACESHIP_OPERATOR) # libcxx doesn't implement operator<=> for std::array which breaks this
|
||||
add_compile_definitions(VULKAN_HPP_NO_STRUCT_CONSTRUCTORS) # We want to use designated initializers in Vulkan-Hpp
|
||||
add_compile_definitions(VULKAN_HPP_NO_SETTERS)
|
||||
add_compile_definitions(VULKAN_HPP_NO_SMART_HANDLE)
|
||||
include_directories("libraries/vkhpp/include")
|
||||
include_directories("libraries/pugixml/src") # We use PugiXML in header-only mode
|
||||
include_directories("libraries/frozen/include")
|
||||
|
||||
add_compile_definitions(VULKAN_HPP_DISPATCH_LOADER_DYNAMIC=1) # We use the dynamic loader rather than the static one to avoid an additional level of indirection
|
||||
add_compile_definitions(VULKAN_HPP_ENABLE_DYNAMIC_LOADER_TOOL=0) # We disable the dynamic loader tool so we can supply our own getInstanceProcAddress function from a custom driver
|
||||
include_directories(SYSTEM "libraries/vkhpp")
|
||||
include_directories(SYSTEM "libraries/vkhpp/Vulkan-Headers/include") # We use base Vulkan headers from this to ensure version parity with Vulkan-Hpp
|
||||
|
||||
# Vulkan Memory Allocator
|
||||
include_directories("libraries/vkma/include")
|
||||
add_library(vkma STATIC libraries/vkma.cpp)
|
||||
target_compile_options(vkma PRIVATE -Wno-everything)
|
||||
|
||||
# Frozen
|
||||
include_directories(SYSTEM "libraries/frozen/include")
|
||||
|
||||
# MbedTLS
|
||||
set(ENABLE_TESTING OFF CACHE BOOL "Build mbed TLS tests." FORCE)
|
||||
set(ENABLE_PROGRAMS OFF CACHE BOOL "Build mbed TLS programs." FORCE)
|
||||
set(UNSAFE_BUILD ON CACHE BOOL "Allow unsafe builds. These builds ARE NOT SECURE." FORCE)
|
||||
add_subdirectory("libraries/mbedtls")
|
||||
include_directories(SYSTEM "libraries/mbedtls/include")
|
||||
target_compile_options(mbedcrypto PRIVATE -Wno-everything)
|
||||
|
||||
# Opus
|
||||
set(OPUS_INSTALL_CMAKE_CONFIG_MODULE OFF CACHE BOOL "Install Opus CMake package config module" FORCE)
|
||||
include_directories(SYSTEM "libraries/opus/include")
|
||||
add_subdirectory("libraries/opus")
|
||||
target_compile_definitions(opus PRIVATE OPUS_WILL_BE_SLOW=1) # libopus will warn when built without optimizations
|
||||
|
||||
# Cubeb
|
||||
set(USE_OPENSL ON)
|
||||
set(USE_SANITIZERS OFF)
|
||||
set(USE_LAZY_LOAD_LIBS OFF)
|
||||
set(USE_AAUDIO OFF)
|
||||
set(BUNDLE_SPEEX ON)
|
||||
add_subdirectory("libraries/cubeb")
|
||||
include_directories(SYSTEM "libraries/cubeb/include")
|
||||
find_package(mbedtls REQUIRED CONFIG)
|
||||
|
||||
# Perfetto SDK
|
||||
include_directories(SYSTEM "libraries/perfetto/sdk")
|
||||
include_directories(libraries/perfetto/sdk)
|
||||
add_library(perfetto STATIC libraries/perfetto/sdk/perfetto.cc)
|
||||
target_compile_options(perfetto PRIVATE -Wno-everything)
|
||||
|
||||
# C++ Range v3
|
||||
add_subdirectory("libraries/range")
|
||||
include_directories(${source_DIR}/skyline)
|
||||
|
||||
# Sirit
|
||||
add_subdirectory("libraries/sirit")
|
||||
|
||||
# libadrenotools
|
||||
add_subdirectory("libraries/adrenotools")
|
||||
|
||||
# Tessil Robin Map
|
||||
add_subdirectory("libraries/robin-map")
|
||||
|
||||
# Renderdoc in-app API
|
||||
include_directories("libraries/renderdoc")
|
||||
|
||||
# Thread Pool
|
||||
include_directories("libraries/thread-pool")
|
||||
|
||||
# Build Skyline with full debugging data and -Og for debug builds
|
||||
set(CMAKE_CXX_FLAGS_DEBUG "-O0 -g3 -glldb -gdwarf-5 -fno-omit-frame-pointer")
|
||||
# Build Skyline with full debugging data and some optimizations for reldebug builds, build speed is pioritised
|
||||
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-O1 -g3 -glldb -gdwarf-5 -fno-omit-frame-pointer -fno-stack-protector")
|
||||
|
||||
# Include headers from libraries as system headers to silence warnings from them
|
||||
function(target_link_libraries_system target)
|
||||
set(libraries ${ARGN})
|
||||
foreach (library ${libraries})
|
||||
if (TARGET ${library})
|
||||
get_target_property(library_include_directories ${library} INTERFACE_INCLUDE_DIRECTORIES)
|
||||
if (NOT "${library_include_directories}" STREQUAL "library_include_directories-NOTFOUND")
|
||||
target_include_directories(${target} SYSTEM PRIVATE ${library_include_directories})
|
||||
endif ()
|
||||
endif ()
|
||||
target_link_libraries(${target} PRIVATE ${library})
|
||||
endforeach (library)
|
||||
endfunction(target_link_libraries_system)
|
||||
|
||||
# yuzu Shader Compiler
|
||||
add_subdirectory("libraries/shader-compiler")
|
||||
target_include_directories(shader_recompiler PUBLIC "libraries/shader-compiler/include")
|
||||
target_link_libraries_system(shader_recompiler Boost::intrusive Boost::container range-v3)
|
||||
|
||||
# yuzu Audio Core
|
||||
add_subdirectory("libraries/audio-core")
|
||||
include_directories(SYSTEM "libraries/audio-core/include")
|
||||
target_link_libraries_system(audio_core Boost::intrusive Boost::container range-v3)
|
||||
|
||||
# Skyline
|
||||
add_library(skyline SHARED
|
||||
${source_DIR}/driver_jni.cpp
|
||||
${source_DIR}/emu_jni.cpp
|
||||
${source_DIR}/loader_jni.cpp
|
||||
${source_DIR}/skyline/common.cpp
|
||||
${source_DIR}/skyline/common/exception.cpp
|
||||
${source_DIR}/skyline/common/logger.cpp
|
||||
${source_DIR}/skyline/common/settings.cpp
|
||||
${source_DIR}/skyline/common/signal.cpp
|
||||
${source_DIR}/skyline/common/spin_lock.cpp
|
||||
${source_DIR}/skyline/common/uuid.cpp
|
||||
${source_DIR}/skyline/common/trace.cpp
|
||||
${source_DIR}/skyline/nce/guest.S
|
||||
|
@ -178,69 +63,16 @@ add_library(skyline SHARED
|
|||
${source_DIR}/skyline/kernel/types/KPrivateMemory.cpp
|
||||
${source_DIR}/skyline/kernel/types/KSyncObject.cpp
|
||||
${source_DIR}/skyline/audio.cpp
|
||||
${source_DIR}/skyline/gpu.cpp
|
||||
${source_DIR}/skyline/gpu/trait_manager.cpp
|
||||
${source_DIR}/skyline/gpu/memory_manager.cpp
|
||||
${source_DIR}/skyline/gpu/texture_manager.cpp
|
||||
${source_DIR}/skyline/gpu/buffer_manager.cpp
|
||||
${source_DIR}/skyline/gpu/command_scheduler.cpp
|
||||
${source_DIR}/skyline/gpu/descriptor_allocator.cpp
|
||||
${source_DIR}/skyline/gpu/texture/bc_decoder.cpp
|
||||
${source_DIR}/skyline/gpu/texture/texture.cpp
|
||||
${source_DIR}/skyline/gpu/texture/layout.cpp
|
||||
${source_DIR}/skyline/gpu/buffer.cpp
|
||||
${source_DIR}/skyline/gpu/megabuffer.cpp
|
||||
${source_DIR}/skyline/audio/track.cpp
|
||||
${source_DIR}/skyline/audio/resampler.cpp
|
||||
${source_DIR}/skyline/audio/adpcm_decoder.cpp
|
||||
${source_DIR}/skyline/gpu/presentation_engine.cpp
|
||||
${source_DIR}/skyline/gpu/shader_manager.cpp
|
||||
${source_DIR}/skyline/gpu/pipeline_cache_manager.cpp
|
||||
${source_DIR}/skyline/gpu/graphics_pipeline_assembler.cpp
|
||||
${source_DIR}/skyline/gpu/cache/renderpass_cache.cpp
|
||||
${source_DIR}/skyline/gpu/cache/framebuffer_cache.cpp
|
||||
${source_DIR}/skyline/gpu/interconnect/fermi_2d.cpp
|
||||
${source_DIR}/skyline/gpu/interconnect/maxwell_dma.cpp
|
||||
${source_DIR}/skyline/gpu/interconnect/inline2memory.cpp
|
||||
${source_DIR}/skyline/gpu/interconnect/maxwell_3d/active_state.cpp
|
||||
${source_DIR}/skyline/gpu/interconnect/maxwell_3d/pipeline_state.cpp
|
||||
${source_DIR}/skyline/gpu/interconnect/maxwell_3d/graphics_pipeline_state_accessor.cpp
|
||||
${source_DIR}/skyline/gpu/interconnect/maxwell_3d/packed_pipeline_state.cpp
|
||||
${source_DIR}/skyline/gpu/interconnect/maxwell_3d/pipeline_manager.cpp
|
||||
${source_DIR}/skyline/gpu/interconnect/maxwell_3d/constant_buffers.cpp
|
||||
${source_DIR}/skyline/gpu/interconnect/maxwell_3d/queries.cpp
|
||||
${source_DIR}/skyline/gpu/interconnect/maxwell_3d/maxwell_3d.cpp
|
||||
${source_DIR}/skyline/gpu/interconnect/kepler_compute/pipeline_manager.cpp
|
||||
${source_DIR}/skyline/gpu/interconnect/kepler_compute/pipeline_state.cpp
|
||||
${source_DIR}/skyline/gpu/interconnect/kepler_compute/kepler_compute.cpp
|
||||
${source_DIR}/skyline/gpu/interconnect/kepler_compute/constant_buffers.cpp
|
||||
${source_DIR}/skyline/gpu/interconnect/command_executor.cpp
|
||||
${source_DIR}/skyline/gpu/interconnect/command_nodes.cpp
|
||||
${source_DIR}/skyline/gpu/interconnect/conversion/quads.cpp
|
||||
${source_DIR}/skyline/gpu/interconnect/common/common.cpp
|
||||
${source_DIR}/skyline/gpu/interconnect/common/samplers.cpp
|
||||
${source_DIR}/skyline/gpu/interconnect/common/textures.cpp
|
||||
${source_DIR}/skyline/gpu/interconnect/common/shader_cache.cpp
|
||||
${source_DIR}/skyline/gpu/interconnect/common/pipeline_state_bundle.cpp
|
||||
${source_DIR}/skyline/gpu/interconnect/common/file_pipeline_state_accessor.cpp
|
||||
${source_DIR}/skyline/gpu/shaders/helper_shaders.cpp
|
||||
${source_DIR}/skyline/soc/smmu.cpp
|
||||
${source_DIR}/skyline/soc/host1x/syncpoint.cpp
|
||||
${source_DIR}/skyline/soc/host1x/command_fifo.cpp
|
||||
${source_DIR}/skyline/soc/host1x/classes/host1x.cpp
|
||||
${source_DIR}/skyline/soc/host1x/classes/vic.cpp
|
||||
${source_DIR}/skyline/soc/host1x/classes/nvdec.cpp
|
||||
${source_DIR}/skyline/soc/gm20b/channel.cpp
|
||||
${source_DIR}/skyline/soc/gm20b/gpfifo.cpp
|
||||
${source_DIR}/skyline/soc/gm20b/gmmu.cpp
|
||||
${source_DIR}/skyline/soc/gm20b/macro/macro_state.cpp
|
||||
${source_DIR}/skyline/soc/gm20b/macro/macro_interpreter.cpp
|
||||
${source_DIR}/skyline/soc/gm20b/engines/engine.cpp
|
||||
${source_DIR}/skyline/soc/gm20b/engines/gpfifo.cpp
|
||||
${source_DIR}/skyline/soc/gm20b/engines/maxwell_3d.cpp
|
||||
${source_DIR}/skyline/soc/gm20b/engines/inline2memory.cpp
|
||||
${source_DIR}/skyline/soc/gm20b/engines/kepler_compute.cpp
|
||||
${source_DIR}/skyline/soc/gm20b/engines/maxwell_dma.cpp
|
||||
${source_DIR}/skyline/soc/gm20b/engines/maxwell/initialization.cpp
|
||||
${source_DIR}/skyline/soc/gm20b/engines/fermi_2d.cpp
|
||||
${source_DIR}/skyline/input.cpp
|
||||
${source_DIR}/skyline/gpu/macro_interpreter.cpp
|
||||
${source_DIR}/skyline/gpu/memory_manager.cpp
|
||||
${source_DIR}/skyline/gpu/gpfifo.cpp
|
||||
${source_DIR}/skyline/gpu/syncpoint.cpp
|
||||
${source_DIR}/skyline/gpu/texture.cpp
|
||||
${source_DIR}/skyline/gpu/engines/maxwell_3d.cpp
|
||||
${source_DIR}/skyline/input/npad.cpp
|
||||
${source_DIR}/skyline/input/npad_device.cpp
|
||||
${source_DIR}/skyline/input/touch.cpp
|
||||
|
@ -252,7 +84,6 @@ add_library(skyline SHARED
|
|||
${source_DIR}/skyline/loader/nca.cpp
|
||||
${source_DIR}/skyline/loader/xci.cpp
|
||||
${source_DIR}/skyline/loader/nsp.cpp
|
||||
${source_DIR}/skyline/hle/symbol_hooks.cpp
|
||||
${source_DIR}/skyline/vfs/partition_filesystem.cpp
|
||||
${source_DIR}/skyline/vfs/ctr_encrypted_backing.cpp
|
||||
${source_DIR}/skyline/vfs/rom_filesystem.cpp
|
||||
|
@ -266,14 +97,16 @@ add_library(skyline SHARED
|
|||
${source_DIR}/skyline/vfs/ticket.cpp
|
||||
${source_DIR}/skyline/services/serviceman.cpp
|
||||
${source_DIR}/skyline/services/base_service.cpp
|
||||
${source_DIR}/skyline/services/common/parcel.cpp
|
||||
${source_DIR}/skyline/services/sm/IUserInterface.cpp
|
||||
${source_DIR}/skyline/services/fatalsrv/IService.cpp
|
||||
${source_DIR}/skyline/services/audio/IAudioInManager.cpp
|
||||
${source_DIR}/skyline/services/audio/IAudioOutManager.cpp
|
||||
${source_DIR}/skyline/services/audio/IAudioOut.cpp
|
||||
${source_DIR}/skyline/services/audio/IAudioDevice.cpp
|
||||
${source_DIR}/skyline/services/audio/IAudioRendererManager.cpp
|
||||
${source_DIR}/skyline/services/audio/IAudioRenderer.cpp
|
||||
${source_DIR}/skyline/services/audio/IAudioRenderer/IAudioRenderer.cpp
|
||||
${source_DIR}/skyline/services/audio/IAudioRenderer/voice.cpp
|
||||
${source_DIR}/skyline/services/audio/IAudioRenderer/memory_pool.cpp
|
||||
${source_DIR}/skyline/services/settings/ISettingsServer.cpp
|
||||
${source_DIR}/skyline/services/settings/ISystemSettingsServer.cpp
|
||||
${source_DIR}/skyline/services/apm/IManager.cpp
|
||||
|
@ -295,37 +128,11 @@ add_library(skyline SHARED
|
|||
${source_DIR}/skyline/services/am/controller/ISelfController.cpp
|
||||
${source_DIR}/skyline/services/am/controller/IWindowController.cpp
|
||||
${source_DIR}/skyline/services/am/storage/IStorage.cpp
|
||||
${source_DIR}/skyline/services/am/storage/VectorIStorage.cpp
|
||||
${source_DIR}/skyline/services/am/storage/TransferMemoryIStorage.cpp
|
||||
${source_DIR}/skyline/services/am/storage/IStorageAccessor.cpp
|
||||
${source_DIR}/skyline/services/am/applet/ILibraryAppletAccessor.cpp
|
||||
${source_DIR}/skyline/services/am/applet/IApplet.cpp
|
||||
${source_DIR}/skyline/services/bcat/IBcatService.cpp
|
||||
${source_DIR}/skyline/services/bcat/IDeliveryCacheStorageService.cpp
|
||||
${source_DIR}/skyline/services/bcat/IDeliveryCacheFileService.cpp
|
||||
${source_DIR}/skyline/services/bcat/IDeliveryCacheDirectoryService.cpp
|
||||
${source_DIR}/skyline/services/bcat/IServiceCreator.cpp
|
||||
${source_DIR}/skyline/services/bt/IBluetoothUser.cpp
|
||||
${source_DIR}/skyline/services/btm/IBtmUser.cpp
|
||||
${source_DIR}/skyline/services/btm/IBtmUserCore.cpp
|
||||
${source_DIR}/skyline/services/capsrv/IAlbumAccessorService.cpp
|
||||
${source_DIR}/skyline/services/capsrv/ICaptureControllerService.cpp
|
||||
${source_DIR}/skyline/services/capsrv/IAlbumApplicationService.cpp
|
||||
${source_DIR}/skyline/services/capsrv/IScreenShotApplicationService.cpp
|
||||
${source_DIR}/skyline/services/ro/IRoInterface.cpp
|
||||
${source_DIR}/skyline/applet/applet_creator.cpp
|
||||
${source_DIR}/skyline/applet/controller_applet.cpp
|
||||
${source_DIR}/skyline/applet/error_applet.cpp
|
||||
${source_DIR}/skyline/applet/player_select_applet.cpp
|
||||
${source_DIR}/skyline/applet/web_applet.cpp
|
||||
${source_DIR}/skyline/applet/swkbd/software_keyboard_applet.cpp
|
||||
${source_DIR}/skyline/applet/swkbd/software_keyboard_config.cpp
|
||||
${source_DIR}/skyline/services/codec/IHardwareOpusDecoder.cpp
|
||||
${source_DIR}/skyline/services/codec/IHardwareOpusDecoderManager.cpp
|
||||
${source_DIR}/skyline/services/hid/IHidServer.cpp
|
||||
${source_DIR}/skyline/services/hid/IAppletResource.cpp
|
||||
${source_DIR}/skyline/services/hid/IActiveVibrationDeviceList.cpp
|
||||
${source_DIR}/skyline/services/irs/IIrSensorServer.cpp
|
||||
${source_DIR}/skyline/services/timesrv/common.cpp
|
||||
${source_DIR}/skyline/services/timesrv/core.cpp
|
||||
${source_DIR}/skyline/services/timesrv/time_shared_memory.cpp
|
||||
|
@ -337,42 +144,33 @@ add_library(skyline SHARED
|
|||
${source_DIR}/skyline/services/timesrv/ITimeZoneService.cpp
|
||||
${source_DIR}/skyline/services/glue/IStaticService.cpp
|
||||
${source_DIR}/skyline/services/glue/ITimeZoneService.cpp
|
||||
${source_DIR}/skyline/services/glue/IWriterForSystem.cpp
|
||||
${source_DIR}/skyline/services/glue/INotificationServicesForApplication.cpp
|
||||
${source_DIR}/skyline/services/fssrv/IFileSystemProxy.cpp
|
||||
${source_DIR}/skyline/services/fssrv/IFileSystem.cpp
|
||||
${source_DIR}/skyline/services/fssrv/IFile.cpp
|
||||
${source_DIR}/skyline/services/fssrv/IStorage.cpp
|
||||
${source_DIR}/skyline/services/fssrv/IDirectory.cpp
|
||||
${source_DIR}/skyline/services/fssrv/IMultiCommitManager.cpp
|
||||
${source_DIR}/skyline/services/nvdrv/INvDrvServices.cpp
|
||||
${source_DIR}/skyline/services/nvdrv/driver.cpp
|
||||
${source_DIR}/skyline/services/nvdrv/core/nvmap.cpp
|
||||
${source_DIR}/skyline/services/nvdrv/core/syncpoint_manager.cpp
|
||||
${source_DIR}/skyline/services/nvdrv/devices/nvdevice.cpp
|
||||
${source_DIR}/skyline/services/nvdrv/devices/nvmap.cpp
|
||||
${source_DIR}/skyline/services/nvdrv/devices/nvhost/as_gpu.cpp
|
||||
${source_DIR}/skyline/services/nvdrv/devices/nvhost/ctrl.cpp
|
||||
${source_DIR}/skyline/services/nvdrv/devices/nvhost/ctrl_gpu.cpp
|
||||
${source_DIR}/skyline/services/nvdrv/devices/nvhost/gpu_channel.cpp
|
||||
${source_DIR}/skyline/services/nvdrv/devices/nvhost/host1x_channel.cpp
|
||||
${source_DIR}/skyline/services/hosbinder/parcel.cpp
|
||||
${source_DIR}/skyline/services/nvdrv/devices/nvhost_ctrl_gpu.cpp
|
||||
${source_DIR}/skyline/services/nvdrv/devices/nvhost_ctrl.cpp
|
||||
${source_DIR}/skyline/services/nvdrv/devices/nvhost_channel.cpp
|
||||
${source_DIR}/skyline/services/nvdrv/devices/nvhost_as_gpu.cpp
|
||||
${source_DIR}/skyline/services/nvdrv/devices/nvhost_syncpoint.cpp
|
||||
${source_DIR}/skyline/services/hosbinder/IHOSBinderDriver.cpp
|
||||
${source_DIR}/skyline/services/hosbinder/GraphicBufferProducer.cpp
|
||||
${source_DIR}/skyline/services/visrv/IDisplayService.cpp
|
||||
${source_DIR}/skyline/services/visrv/IApplicationDisplayService.cpp
|
||||
${source_DIR}/skyline/services/visrv/IManagerDisplayService.cpp
|
||||
${source_DIR}/skyline/services/visrv/IRootService.cpp
|
||||
${source_DIR}/skyline/services/visrv/IManagerRootService.cpp
|
||||
${source_DIR}/skyline/services/visrv/ISystemDisplayService.cpp
|
||||
${source_DIR}/skyline/services/pl/IPlatformServiceManager.cpp
|
||||
${source_DIR}/skyline/services/aocsrv/IAddOnContentManager.cpp
|
||||
${source_DIR}/skyline/services/aocsrv/IPurchaseEventManager.cpp
|
||||
${source_DIR}/skyline/services/pctl/IParentalControlServiceFactory.cpp
|
||||
${source_DIR}/skyline/services/pctl/IParentalControlService.cpp
|
||||
${source_DIR}/skyline/services/lm/ILogService.cpp
|
||||
${source_DIR}/skyline/services/lm/ILogger.cpp
|
||||
${source_DIR}/skyline/services/ldn/IUserServiceCreator.cpp
|
||||
${source_DIR}/skyline/services/ldn/IUserLocalCommunicationService.cpp
|
||||
${source_DIR}/skyline/services/account/IAccountServiceForApplication.cpp
|
||||
${source_DIR}/skyline/services/account/IManagerForApplication.cpp
|
||||
${source_DIR}/skyline/services/account/IProfile.cpp
|
||||
|
@ -383,27 +181,12 @@ add_library(skyline SHARED
|
|||
${source_DIR}/skyline/services/nfp/IUser.cpp
|
||||
${source_DIR}/skyline/services/nifm/IStaticService.cpp
|
||||
${source_DIR}/skyline/services/nifm/IGeneralService.cpp
|
||||
${source_DIR}/skyline/services/nifm/IScanRequest.cpp
|
||||
${source_DIR}/skyline/services/nifm/IRequest.cpp
|
||||
${source_DIR}/skyline/services/nim/IShopServiceAccessor.cpp
|
||||
${source_DIR}/skyline/services/nim/IShopServiceAccessServer.cpp
|
||||
${source_DIR}/skyline/services/nim/IShopServiceAccessServerInterface.cpp
|
||||
${source_DIR}/skyline/services/nim/IShopServiceAsync.cpp
|
||||
${source_DIR}/skyline/services/socket/bsd/IClient.cpp
|
||||
${source_DIR}/skyline/services/socket/nsd/IManager.cpp
|
||||
${source_DIR}/skyline/services/socket/sfdnsres/IResolver.cpp
|
||||
${source_DIR}/skyline/services/spl/IRandomInterface.cpp
|
||||
${source_DIR}/skyline/services/ssl/ISslService.cpp
|
||||
${source_DIR}/skyline/services/ssl/ISslContext.cpp
|
||||
${source_DIR}/skyline/services/prepo/IPrepoService.cpp
|
||||
${source_DIR}/skyline/services/mmnv/IRequest.cpp
|
||||
${source_DIR}/skyline/services/mii/IStaticService.cpp
|
||||
${source_DIR}/skyline/services/mii/IDatabaseService.cpp
|
||||
${source_DIR}/skyline/services/olsc/IOlscServiceForApplication.cpp
|
||||
)
|
||||
target_include_directories(skyline PRIVATE ${source_DIR}/skyline)
|
||||
# target_precompile_headers(skyline PRIVATE ${source_DIR}/skyline/common.h) # PCH will currently break Intellisense
|
||||
target_compile_options(skyline PRIVATE -Wall -Wno-unknown-attributes -Wno-c++20-extensions -Wno-c++17-extensions -Wno-c99-designator -Wno-reorder -Wno-missing-braces -Wno-unused-variable -Wno-unused-private-field -Wno-dangling-else -Wconversion -fsigned-bitfields)
|
||||
|
||||
target_link_libraries(skyline PRIVATE shader_recompiler audio_core)
|
||||
target_link_libraries_system(skyline android perfetto fmt lz4_static tzcode vkma mbedcrypto opus Boost::intrusive Boost::container range-v3 adrenotools tsl::robin_map)
|
||||
target_link_libraries(skyline vulkan android perfetto fmt lz4_static tzcode oboe mbedtls::mbedcrypto)
|
||||
target_compile_options(skyline PRIVATE -Wall -Wno-unknown-attributes -Wno-c++20-extensions -Wno-c++17-extensions -Wno-c99-designator -Wno-reorder -Wno-missing-braces -Wno-unused-variable -Wno-unused-private-field)
|
||||
|
|
171
app/build.gradle
171
app/build.gradle
|
@ -1,78 +1,35 @@
|
|||
plugins {
|
||||
id 'com.android.application'
|
||||
id 'kotlin-android'
|
||||
id 'kotlin-kapt'
|
||||
id 'com.google.dagger.hilt.android'
|
||||
id 'idea'
|
||||
id 'org.jetbrains.kotlin.plugin.serialization' version "$kotlin_version"
|
||||
}
|
||||
|
||||
idea.module {
|
||||
// These are not viable to index on most systems so exclude them to prevent IDE crashes
|
||||
excludeDirs.add(file("libraries/boost"))
|
||||
excludeDirs.add(file("libraries/llvm"))
|
||||
}
|
||||
apply plugin: 'com.android.application'
|
||||
apply plugin: 'kotlin-android'
|
||||
apply plugin: 'kotlin-android-extensions'
|
||||
|
||||
android {
|
||||
namespace 'emu.skyline'
|
||||
compileSdk 33
|
||||
|
||||
var isBuildSigned = (System.getenv("CI") == "true") && (System.getenv("IS_SKYLINE_SIGNED") == "true")
|
||||
|
||||
compileSdkVersion 30
|
||||
buildToolsVersion '30.0.3'
|
||||
defaultConfig {
|
||||
applicationId "skyline.emu"
|
||||
|
||||
minSdk 29
|
||||
targetSdk 33
|
||||
minSdkVersion 26
|
||||
targetSdkVersion 30
|
||||
|
||||
versionCode 3
|
||||
versionName "0.0.3"
|
||||
versionName "0.3"
|
||||
|
||||
ndk {
|
||||
//noinspection ChromeOsAbiSupport
|
||||
abiFilters "arm64-v8a"
|
||||
}
|
||||
|
||||
if (isBuildSigned)
|
||||
manifestPlaceholders += [shouldSaveUserData: "true"]
|
||||
else
|
||||
manifestPlaceholders += [shouldSaveUserData: "false"]
|
||||
|
||||
// Only enable separate process for release builds
|
||||
manifestPlaceholders += [emulationProcess: ""]
|
||||
|
||||
def locales = ["en", "de", "el", "es", "es-419", "fr", "hu", "id", "it", "ja", "ko", "pl", "ru", "ta", "zh-Hans", "zh-Hant"]
|
||||
|
||||
// Add available locales to the build config so that they can be accessed from the app
|
||||
buildConfigField "String[]", "AVAILABLE_APP_LANGUAGES", "new String[]{\"" + locales.join("\",\"") + "\"}"
|
||||
// Uncomment the following line whenever AAPT2 will properly support BCP47 language tags
|
||||
//resourceConfigurations += locales
|
||||
}
|
||||
|
||||
/* JVM Bytecode Options */
|
||||
def javaVersion = JavaVersion.VERSION_1_8
|
||||
compileOptions {
|
||||
sourceCompatibility = javaVersion
|
||||
targetCompatibility = javaVersion
|
||||
}
|
||||
kotlinOptions {
|
||||
jvmTarget = javaVersion.toString()
|
||||
freeCompilerArgs += "-opt-in=kotlin.RequiresOptIn"
|
||||
}
|
||||
compileOptions {
|
||||
sourceCompatibility javaVersion
|
||||
targetCompatibility javaVersion
|
||||
}
|
||||
|
||||
packagingOptions {
|
||||
jniLibs.useLegacyPackaging = true
|
||||
}
|
||||
|
||||
signingConfigs {
|
||||
ci {
|
||||
storeFile file(System.getenv("SIGNING_STORE_PATH") ?: "${System.getenv("user.home")}/keystore.jks")
|
||||
storePassword System.getenv("SIGNING_STORE_PASSWORD")
|
||||
keyAlias System.getenv("SIGNING_KEY_ALIAS")
|
||||
keyPassword System.getenv("SIGNING_KEY_PASSWORD")
|
||||
}
|
||||
}
|
||||
|
||||
/* Build Options */
|
||||
buildTypes {
|
||||
release {
|
||||
debuggable true
|
||||
|
@ -84,113 +41,63 @@ android {
|
|||
minifyEnabled true
|
||||
shrinkResources true
|
||||
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
|
||||
signingConfig = isBuildSigned ? signingConfigs.ci : signingConfigs.debug
|
||||
manifestPlaceholders += [emulationProcess: ":emulationProcess"]
|
||||
}
|
||||
|
||||
reldebug {
|
||||
debuggable true
|
||||
externalNativeBuild {
|
||||
cmake {
|
||||
arguments "-DCMAKE_BUILD_TYPE=RELWITHDEBINFO"
|
||||
}
|
||||
}
|
||||
minifyEnabled false
|
||||
shrinkResources false
|
||||
signingConfig = isBuildSigned ? signingConfigs.ci : signingConfigs.debug
|
||||
signingConfig signingConfigs.debug
|
||||
}
|
||||
|
||||
debug {
|
||||
debuggable true
|
||||
minifyEnabled false
|
||||
shrinkResources false
|
||||
signingConfig = isBuildSigned ? signingConfigs.ci : signingConfigs.debug
|
||||
}
|
||||
}
|
||||
|
||||
flavorDimensions += "version"
|
||||
productFlavors {
|
||||
full {
|
||||
dimension = "version"
|
||||
manifestPlaceholders += [appLabel: "Skyline"]
|
||||
}
|
||||
|
||||
dev {
|
||||
dimension = "version"
|
||||
applicationIdSuffix = ".dev"
|
||||
versionNameSuffix = "-dev"
|
||||
manifestPlaceholders += [appLabel: "Skyline Dev"]
|
||||
}
|
||||
}
|
||||
|
||||
buildFeatures {
|
||||
viewBinding true
|
||||
prefab true
|
||||
viewBinding false
|
||||
}
|
||||
|
||||
/* Android Extensions */
|
||||
androidExtensions {
|
||||
/* TODO: Remove this after migrating to View Bindings */
|
||||
experimental = true
|
||||
}
|
||||
|
||||
/* Linting */
|
||||
lint {
|
||||
lintOptions {
|
||||
disable 'IconLocation'
|
||||
}
|
||||
|
||||
/* NDK and CMake */
|
||||
ndkVersion '25.0.8775105'
|
||||
/* NDK */
|
||||
ndkVersion '22.0.7026061'
|
||||
externalNativeBuild {
|
||||
cmake {
|
||||
version '3.22.1+'
|
||||
version '3.18.1+'
|
||||
path "CMakeLists.txt"
|
||||
}
|
||||
}
|
||||
|
||||
/* Android Assets */
|
||||
androidResources {
|
||||
ignoreAssetsPattern '*.md'
|
||||
}
|
||||
|
||||
/* Vulkan Validation Layers */
|
||||
sourceSets {
|
||||
reldebug {
|
||||
jniLibs {
|
||||
srcDir "libraries/vklayers"
|
||||
}
|
||||
}
|
||||
|
||||
debug {
|
||||
jniLibs {
|
||||
srcDir "libraries/vklayers"
|
||||
}
|
||||
}
|
||||
aaptOptions {
|
||||
ignoreAssetsPattern "*.md"
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
/* Filetrees */
|
||||
implementation fileTree(dir: 'libs', include: ['*.jar', '*.aar'])
|
||||
|
||||
/* Google */
|
||||
implementation 'androidx.core:core-ktx:1.9.0'
|
||||
implementation 'androidx.appcompat:appcompat:1.6.0'
|
||||
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
|
||||
implementation 'androidx.preference:preference-ktx:1.2.0'
|
||||
implementation 'androidx.activity:activity-ktx:1.6.1'
|
||||
implementation 'com.google.android.material:material:1.8.0'
|
||||
implementation 'androidx.appcompat:appcompat:1.2.0'
|
||||
implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
|
||||
implementation 'androidx.preference:preference-ktx:1.1.1'
|
||||
implementation 'com.google.android.material:material:1.3.0'
|
||||
implementation 'androidx.documentfile:documentfile:1.0.1'
|
||||
implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.1.0'
|
||||
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.5.1"
|
||||
implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.5.1"
|
||||
implementation 'androidx.fragment:fragment-ktx:1.5.5'
|
||||
implementation "com.google.dagger:hilt-android:$hilt_version"
|
||||
kapt "com.google.dagger:hilt-compiler:$hilt_version"
|
||||
implementation 'com.google.android.flexbox:flexbox:3.0.0'
|
||||
|
||||
/* Kotlin */
|
||||
implementation "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version"
|
||||
implementation "org.jetbrains.kotlinx:kotlinx-serialization-json:1.4.1"
|
||||
|
||||
/* JetBrains */
|
||||
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
|
||||
implementation "androidx.core:core-ktx:1.3.2"
|
||||
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
|
||||
|
||||
/* Other Java */
|
||||
implementation 'info.debatty:java-string-similarity:2.0.0'
|
||||
implementation 'com.github.KikiManjaro:colorpicker:v1.1.12'
|
||||
}
|
||||
|
||||
kapt {
|
||||
correctErrorTypes true
|
||||
/* NDK */
|
||||
implementation files("libraries/mbedtls.aar")
|
||||
}
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
Subproject commit 19d1998c5a39dc18f90086e068ce7b3331110d74
|
|
@ -1 +0,0 @@
|
|||
Subproject commit 76440e0a3554433398c0ef03233f862a6e86f5ee
|
|
@ -1 +0,0 @@
|
|||
Subproject commit 06d52af216340ed46b865d01c4f7c0d7a8cc5918
|
|
@ -1 +0,0 @@
|
|||
Subproject commit 2d93d734ecff78deb060abd727712bae8ab0489a
|
|
@ -1 +1 @@
|
|||
Subproject commit dcd282bb268a0766f6d273b6e41a3a96719bbbfb
|
||||
Subproject commit 9c418bc468baf434a848010bff74663e1f820e79
|
|
@ -1 +1 @@
|
|||
Subproject commit 7264ab0eae2a072afa55d617d5e9e11bcb464aae
|
||||
Subproject commit e6ddc432d0ba4e42542b5867bdc932b5f6d1e08d
|
|
@ -1 +0,0 @@
|
|||
Subproject commit abffdd88767791ef6da4d2df7ec7ab158eb8b775
|
|
@ -1 +0,0 @@
|
|||
Subproject commit d895668359eb8ba7536a04f5e2be1e5268c86b33
|
BIN
app/libraries/mbedtls.aar
Normal file
BIN
app/libraries/mbedtls.aar
Normal file
Binary file not shown.
|
@ -1 +1 @@
|
|||
Subproject commit 9053f015ce1317d3c8bac0111c516b377c2e287e
|
||||
Subproject commit 5eb2ea6899367f9cdc5a262f340c06e1a7c284b2
|
|
@ -1 +0,0 @@
|
|||
Subproject commit 6b6035ae4a29abbd237463d84a45fbeb0d92bc18
|
|
@ -1 +1 @@
|
|||
Subproject commit e5293f1cf1800d5776f4bfe96d1ec0aeec30cd46
|
||||
Subproject commit 3f02be823cef0f54e720c0382ffc4507f48e6e4b
|
1
app/libraries/pugixml
Submodule
1
app/libraries/pugixml
Submodule
|
@ -0,0 +1 @@
|
|||
Subproject commit 08b3433180727ea2f78fe02e860a08471db1e03c
|
|
@ -1 +0,0 @@
|
|||
Subproject commit 83783f578e0e6666d68a3bf17b0038a80e62530e
|
|
@ -1,707 +0,0 @@
|
|||
/******************************************************************************
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2019-2022 Baldur Karlsson
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Documentation for the API is available at https://renderdoc.org/docs/in_application_api.html
|
||||
//
|
||||
|
||||
#if !defined(RENDERDOC_NO_STDINT)
|
||||
#include <stdint.h>
|
||||
#endif
|
||||
|
||||
#if defined(WIN32) || defined(__WIN32__) || defined(_WIN32) || defined(_MSC_VER)
|
||||
#define RENDERDOC_CC __cdecl
|
||||
#elif defined(__linux__)
|
||||
#define RENDERDOC_CC
|
||||
#elif defined(__APPLE__)
|
||||
#define RENDERDOC_CC
|
||||
#else
|
||||
#error "Unknown platform"
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Constants not used directly in below API
|
||||
|
||||
// This is a GUID/magic value used for when applications pass a path where shader debug
|
||||
// information can be found to match up with a stripped shader.
|
||||
// the define can be used like so: const GUID RENDERDOC_ShaderDebugMagicValue =
|
||||
// RENDERDOC_ShaderDebugMagicValue_value
|
||||
#define RENDERDOC_ShaderDebugMagicValue_struct \
|
||||
{ \
|
||||
0xeab25520, 0x6670, 0x4865, 0x84, 0x29, 0x6c, 0x8, 0x51, 0x54, 0x00, 0xff \
|
||||
}
|
||||
|
||||
// as an alternative when you want a byte array (assuming x86 endianness):
|
||||
#define RENDERDOC_ShaderDebugMagicValue_bytearray \
|
||||
{ \
|
||||
0x20, 0x55, 0xb2, 0xea, 0x70, 0x66, 0x65, 0x48, 0x84, 0x29, 0x6c, 0x8, 0x51, 0x54, 0x00, 0xff \
|
||||
}
|
||||
|
||||
// truncated version when only a uint64_t is available (e.g. Vulkan tags):
|
||||
#define RENDERDOC_ShaderDebugMagicValue_truncated 0x48656670eab25520ULL
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// RenderDoc capture options
|
||||
//
|
||||
|
||||
typedef enum RENDERDOC_CaptureOption {
|
||||
// Allow the application to enable vsync
|
||||
//
|
||||
// Default - enabled
|
||||
//
|
||||
// 1 - The application can enable or disable vsync at will
|
||||
// 0 - vsync is force disabled
|
||||
eRENDERDOC_Option_AllowVSync = 0,
|
||||
|
||||
// Allow the application to enable fullscreen
|
||||
//
|
||||
// Default - enabled
|
||||
//
|
||||
// 1 - The application can enable or disable fullscreen at will
|
||||
// 0 - fullscreen is force disabled
|
||||
eRENDERDOC_Option_AllowFullscreen = 1,
|
||||
|
||||
// Record API debugging events and messages
|
||||
//
|
||||
// Default - disabled
|
||||
//
|
||||
// 1 - Enable built-in API debugging features and records the results into
|
||||
// the capture, which is matched up with events on replay
|
||||
// 0 - no API debugging is forcibly enabled
|
||||
eRENDERDOC_Option_APIValidation = 2,
|
||||
eRENDERDOC_Option_DebugDeviceMode = 2, // deprecated name of this enum
|
||||
|
||||
// Capture CPU callstacks for API events
|
||||
//
|
||||
// Default - disabled
|
||||
//
|
||||
// 1 - Enables capturing of callstacks
|
||||
// 0 - no callstacks are captured
|
||||
eRENDERDOC_Option_CaptureCallstacks = 3,
|
||||
|
||||
// When capturing CPU callstacks, only capture them from actions.
|
||||
// This option does nothing without the above option being enabled
|
||||
//
|
||||
// Default - disabled
|
||||
//
|
||||
// 1 - Only captures callstacks for actions.
|
||||
// Ignored if CaptureCallstacks is disabled
|
||||
// 0 - Callstacks, if enabled, are captured for every event.
|
||||
eRENDERDOC_Option_CaptureCallstacksOnlyDraws = 4,
|
||||
eRENDERDOC_Option_CaptureCallstacksOnlyActions = 4,
|
||||
|
||||
// Specify a delay in seconds to wait for a debugger to attach, after
|
||||
// creating or injecting into a process, before continuing to allow it to run.
|
||||
//
|
||||
// 0 indicates no delay, and the process will run immediately after injection
|
||||
//
|
||||
// Default - 0 seconds
|
||||
//
|
||||
eRENDERDOC_Option_DelayForDebugger = 5,
|
||||
|
||||
// Verify buffer access. This includes checking the memory returned by a Map() call to
|
||||
// detect any out-of-bounds modification, as well as initialising buffers with undefined contents
|
||||
// to a marker value to catch use of uninitialised memory.
|
||||
//
|
||||
// NOTE: This option is only valid for OpenGL and D3D11. Explicit APIs such as D3D12 and Vulkan do
|
||||
// not do the same kind of interception & checking and undefined contents are really undefined.
|
||||
//
|
||||
// Default - disabled
|
||||
//
|
||||
// 1 - Verify buffer access
|
||||
// 0 - No verification is performed, and overwriting bounds may cause crashes or corruption in
|
||||
// RenderDoc.
|
||||
eRENDERDOC_Option_VerifyBufferAccess = 6,
|
||||
|
||||
// The old name for eRENDERDOC_Option_VerifyBufferAccess was eRENDERDOC_Option_VerifyMapWrites.
|
||||
// This option now controls the filling of uninitialised buffers with 0xdddddddd which was
|
||||
// previously always enabled
|
||||
eRENDERDOC_Option_VerifyMapWrites = eRENDERDOC_Option_VerifyBufferAccess,
|
||||
|
||||
// Hooks any system API calls that create child processes, and injects
|
||||
// RenderDoc into them recursively with the same options.
|
||||
//
|
||||
// Default - disabled
|
||||
//
|
||||
// 1 - Hooks into spawned child processes
|
||||
// 0 - Child processes are not hooked by RenderDoc
|
||||
eRENDERDOC_Option_HookIntoChildren = 7,
|
||||
|
||||
// By default RenderDoc only includes resources in the final capture necessary
|
||||
// for that frame, this allows you to override that behaviour.
|
||||
//
|
||||
// Default - disabled
|
||||
//
|
||||
// 1 - all live resources at the time of capture are included in the capture
|
||||
// and available for inspection
|
||||
// 0 - only the resources referenced by the captured frame are included
|
||||
eRENDERDOC_Option_RefAllResources = 8,
|
||||
|
||||
// **NOTE**: As of RenderDoc v1.1 this option has been deprecated. Setting or
|
||||
// getting it will be ignored, to allow compatibility with older versions.
|
||||
// In v1.1 the option acts as if it's always enabled.
|
||||
//
|
||||
// By default RenderDoc skips saving initial states for resources where the
|
||||
// previous contents don't appear to be used, assuming that writes before
|
||||
// reads indicate previous contents aren't used.
|
||||
//
|
||||
// Default - disabled
|
||||
//
|
||||
// 1 - initial contents at the start of each captured frame are saved, even if
|
||||
// they are later overwritten or cleared before being used.
|
||||
// 0 - unless a read is detected, initial contents will not be saved and will
|
||||
// appear as black or empty data.
|
||||
eRENDERDOC_Option_SaveAllInitials = 9,
|
||||
|
||||
// In APIs that allow for the recording of command lists to be replayed later,
|
||||
// RenderDoc may choose to not capture command lists before a frame capture is
|
||||
// triggered, to reduce overheads. This means any command lists recorded once
|
||||
// and replayed many times will not be available and may cause a failure to
|
||||
// capture.
|
||||
//
|
||||
// NOTE: This is only true for APIs where multithreading is difficult or
|
||||
// discouraged. Newer APIs like Vulkan and D3D12 will ignore this option
|
||||
// and always capture all command lists since the API is heavily oriented
|
||||
// around it and the overheads have been reduced by API design.
|
||||
//
|
||||
// 1 - All command lists are captured from the start of the application
|
||||
// 0 - Command lists are only captured if their recording begins during
|
||||
// the period when a frame capture is in progress.
|
||||
eRENDERDOC_Option_CaptureAllCmdLists = 10,
|
||||
|
||||
// Mute API debugging output when the API validation mode option is enabled
|
||||
//
|
||||
// Default - enabled
|
||||
//
|
||||
// 1 - Mute any API debug messages from being displayed or passed through
|
||||
// 0 - API debugging is displayed as normal
|
||||
eRENDERDOC_Option_DebugOutputMute = 11,
|
||||
|
||||
// Option to allow vendor extensions to be used even when they may be
|
||||
// incompatible with RenderDoc and cause corrupted replays or crashes.
|
||||
//
|
||||
// Default - inactive
|
||||
//
|
||||
// No values are documented, this option should only be used when absolutely
|
||||
// necessary as directed by a RenderDoc developer.
|
||||
eRENDERDOC_Option_AllowUnsupportedVendorExtensions = 12,
|
||||
|
||||
} RENDERDOC_CaptureOption;
|
||||
|
||||
// Sets an option that controls how RenderDoc behaves on capture.
|
||||
//
|
||||
// Returns 1 if the option and value are valid
|
||||
// Returns 0 if either is invalid and the option is unchanged
|
||||
typedef int(RENDERDOC_CC *pRENDERDOC_SetCaptureOptionU32)(RENDERDOC_CaptureOption opt, uint32_t val);
|
||||
typedef int(RENDERDOC_CC *pRENDERDOC_SetCaptureOptionF32)(RENDERDOC_CaptureOption opt, float val);
|
||||
|
||||
// Gets the current value of an option as a uint32_t
|
||||
//
|
||||
// If the option is invalid, 0xffffffff is returned
|
||||
typedef uint32_t(RENDERDOC_CC *pRENDERDOC_GetCaptureOptionU32)(RENDERDOC_CaptureOption opt);
|
||||
|
||||
// Gets the current value of an option as a float
|
||||
//
|
||||
// If the option is invalid, -FLT_MAX is returned
|
||||
typedef float(RENDERDOC_CC *pRENDERDOC_GetCaptureOptionF32)(RENDERDOC_CaptureOption opt);
|
||||
|
||||
typedef enum RENDERDOC_InputButton {
|
||||
// '0' - '9' matches ASCII values
|
||||
eRENDERDOC_Key_0 = 0x30,
|
||||
eRENDERDOC_Key_1 = 0x31,
|
||||
eRENDERDOC_Key_2 = 0x32,
|
||||
eRENDERDOC_Key_3 = 0x33,
|
||||
eRENDERDOC_Key_4 = 0x34,
|
||||
eRENDERDOC_Key_5 = 0x35,
|
||||
eRENDERDOC_Key_6 = 0x36,
|
||||
eRENDERDOC_Key_7 = 0x37,
|
||||
eRENDERDOC_Key_8 = 0x38,
|
||||
eRENDERDOC_Key_9 = 0x39,
|
||||
|
||||
// 'A' - 'Z' matches ASCII values
|
||||
eRENDERDOC_Key_A = 0x41,
|
||||
eRENDERDOC_Key_B = 0x42,
|
||||
eRENDERDOC_Key_C = 0x43,
|
||||
eRENDERDOC_Key_D = 0x44,
|
||||
eRENDERDOC_Key_E = 0x45,
|
||||
eRENDERDOC_Key_F = 0x46,
|
||||
eRENDERDOC_Key_G = 0x47,
|
||||
eRENDERDOC_Key_H = 0x48,
|
||||
eRENDERDOC_Key_I = 0x49,
|
||||
eRENDERDOC_Key_J = 0x4A,
|
||||
eRENDERDOC_Key_K = 0x4B,
|
||||
eRENDERDOC_Key_L = 0x4C,
|
||||
eRENDERDOC_Key_M = 0x4D,
|
||||
eRENDERDOC_Key_N = 0x4E,
|
||||
eRENDERDOC_Key_O = 0x4F,
|
||||
eRENDERDOC_Key_P = 0x50,
|
||||
eRENDERDOC_Key_Q = 0x51,
|
||||
eRENDERDOC_Key_R = 0x52,
|
||||
eRENDERDOC_Key_S = 0x53,
|
||||
eRENDERDOC_Key_T = 0x54,
|
||||
eRENDERDOC_Key_U = 0x55,
|
||||
eRENDERDOC_Key_V = 0x56,
|
||||
eRENDERDOC_Key_W = 0x57,
|
||||
eRENDERDOC_Key_X = 0x58,
|
||||
eRENDERDOC_Key_Y = 0x59,
|
||||
eRENDERDOC_Key_Z = 0x5A,
|
||||
|
||||
// leave the rest of the ASCII range free
|
||||
// in case we want to use it later
|
||||
eRENDERDOC_Key_NonPrintable = 0x100,
|
||||
|
||||
eRENDERDOC_Key_Divide,
|
||||
eRENDERDOC_Key_Multiply,
|
||||
eRENDERDOC_Key_Subtract,
|
||||
eRENDERDOC_Key_Plus,
|
||||
|
||||
eRENDERDOC_Key_F1,
|
||||
eRENDERDOC_Key_F2,
|
||||
eRENDERDOC_Key_F3,
|
||||
eRENDERDOC_Key_F4,
|
||||
eRENDERDOC_Key_F5,
|
||||
eRENDERDOC_Key_F6,
|
||||
eRENDERDOC_Key_F7,
|
||||
eRENDERDOC_Key_F8,
|
||||
eRENDERDOC_Key_F9,
|
||||
eRENDERDOC_Key_F10,
|
||||
eRENDERDOC_Key_F11,
|
||||
eRENDERDOC_Key_F12,
|
||||
|
||||
eRENDERDOC_Key_Home,
|
||||
eRENDERDOC_Key_End,
|
||||
eRENDERDOC_Key_Insert,
|
||||
eRENDERDOC_Key_Delete,
|
||||
eRENDERDOC_Key_PageUp,
|
||||
eRENDERDOC_Key_PageDn,
|
||||
|
||||
eRENDERDOC_Key_Backspace,
|
||||
eRENDERDOC_Key_Tab,
|
||||
eRENDERDOC_Key_PrtScrn,
|
||||
eRENDERDOC_Key_Pause,
|
||||
|
||||
eRENDERDOC_Key_Max,
|
||||
} RENDERDOC_InputButton;
|
||||
|
||||
// Sets which key or keys can be used to toggle focus between multiple windows
|
||||
//
|
||||
// If keys is NULL or num is 0, toggle keys will be disabled
|
||||
typedef void(RENDERDOC_CC *pRENDERDOC_SetFocusToggleKeys)(RENDERDOC_InputButton *keys, int num);
|
||||
|
||||
// Sets which key or keys can be used to capture the next frame
|
||||
//
|
||||
// If keys is NULL or num is 0, captures keys will be disabled
|
||||
typedef void(RENDERDOC_CC *pRENDERDOC_SetCaptureKeys)(RENDERDOC_InputButton *keys, int num);
|
||||
|
||||
typedef enum RENDERDOC_OverlayBits {
|
||||
// This single bit controls whether the overlay is enabled or disabled globally
|
||||
eRENDERDOC_Overlay_Enabled = 0x1,
|
||||
|
||||
// Show the average framerate over several seconds as well as min/max
|
||||
eRENDERDOC_Overlay_FrameRate = 0x2,
|
||||
|
||||
// Show the current frame number
|
||||
eRENDERDOC_Overlay_FrameNumber = 0x4,
|
||||
|
||||
// Show a list of recent captures, and how many captures have been made
|
||||
eRENDERDOC_Overlay_CaptureList = 0x8,
|
||||
|
||||
// Default values for the overlay mask
|
||||
eRENDERDOC_Overlay_Default = (eRENDERDOC_Overlay_Enabled | eRENDERDOC_Overlay_FrameRate |
|
||||
eRENDERDOC_Overlay_FrameNumber | eRENDERDOC_Overlay_CaptureList),
|
||||
|
||||
// Enable all bits
|
||||
eRENDERDOC_Overlay_All = ~0U,
|
||||
|
||||
// Disable all bits
|
||||
eRENDERDOC_Overlay_None = 0,
|
||||
} RENDERDOC_OverlayBits;
|
||||
|
||||
// returns the overlay bits that have been set
|
||||
typedef uint32_t(RENDERDOC_CC *pRENDERDOC_GetOverlayBits)();
|
||||
// sets the overlay bits with an and & or mask
|
||||
typedef void(RENDERDOC_CC *pRENDERDOC_MaskOverlayBits)(uint32_t And, uint32_t Or);
|
||||
|
||||
// this function will attempt to remove RenderDoc's hooks in the application.
|
||||
//
|
||||
// Note: that this can only work correctly if done immediately after
|
||||
// the module is loaded, before any API work happens. RenderDoc will remove its
|
||||
// injected hooks and shut down. Behaviour is undefined if this is called
|
||||
// after any API functions have been called, and there is still no guarantee of
|
||||
// success.
|
||||
typedef void(RENDERDOC_CC *pRENDERDOC_RemoveHooks)();
|
||||
|
||||
// DEPRECATED: compatibility for code compiled against pre-1.4.1 headers.
|
||||
typedef pRENDERDOC_RemoveHooks pRENDERDOC_Shutdown;
|
||||
|
||||
// This function will unload RenderDoc's crash handler.
|
||||
//
|
||||
// If you use your own crash handler and don't want RenderDoc's handler to
|
||||
// intercede, you can call this function to unload it and any unhandled
|
||||
// exceptions will pass to the next handler.
|
||||
typedef void(RENDERDOC_CC *pRENDERDOC_UnloadCrashHandler)();
|
||||
|
||||
// Sets the capture file path template
|
||||
//
|
||||
// pathtemplate is a UTF-8 string that gives a template for how captures will be named
|
||||
// and where they will be saved.
|
||||
//
|
||||
// Any extension is stripped off the path, and captures are saved in the directory
|
||||
// specified, and named with the filename and the frame number appended. If the
|
||||
// directory does not exist it will be created, including any parent directories.
|
||||
//
|
||||
// If pathtemplate is NULL, the template will remain unchanged
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// SetCaptureFilePathTemplate("my_captures/example");
|
||||
//
|
||||
// Capture #1 -> my_captures/example_frame123.rdc
|
||||
// Capture #2 -> my_captures/example_frame456.rdc
|
||||
typedef void(RENDERDOC_CC *pRENDERDOC_SetCaptureFilePathTemplate)(const char *pathtemplate);
|
||||
|
||||
// returns the current capture path template, see SetCaptureFileTemplate above, as a UTF-8 string
|
||||
typedef const char *(RENDERDOC_CC *pRENDERDOC_GetCaptureFilePathTemplate)();
|
||||
|
||||
// DEPRECATED: compatibility for code compiled against pre-1.1.2 headers.
|
||||
typedef pRENDERDOC_SetCaptureFilePathTemplate pRENDERDOC_SetLogFilePathTemplate;
|
||||
typedef pRENDERDOC_GetCaptureFilePathTemplate pRENDERDOC_GetLogFilePathTemplate;
|
||||
|
||||
// returns the number of captures that have been made
|
||||
typedef uint32_t(RENDERDOC_CC *pRENDERDOC_GetNumCaptures)();
|
||||
|
||||
// This function returns the details of a capture, by index. New captures are added
|
||||
// to the end of the list.
|
||||
//
|
||||
// filename will be filled with the absolute path to the capture file, as a UTF-8 string
|
||||
// pathlength will be written with the length in bytes of the filename string
|
||||
// timestamp will be written with the time of the capture, in seconds since the Unix epoch
|
||||
//
|
||||
// Any of the parameters can be NULL and they'll be skipped.
|
||||
//
|
||||
// The function will return 1 if the capture index is valid, or 0 if the index is invalid
|
||||
// If the index is invalid, the values will be unchanged
|
||||
//
|
||||
// Note: when captures are deleted in the UI they will remain in this list, so the
|
||||
// capture path may not exist anymore.
|
||||
typedef uint32_t(RENDERDOC_CC *pRENDERDOC_GetCapture)(uint32_t idx, char *filename,
|
||||
uint32_t *pathlength, uint64_t *timestamp);
|
||||
|
||||
// Sets the comments associated with a capture file. These comments are displayed in the
|
||||
// UI program when opening.
|
||||
//
|
||||
// filePath should be a path to the capture file to add comments to. If set to NULL or ""
|
||||
// the most recent capture file created made will be used instead.
|
||||
// comments should be a NULL-terminated UTF-8 string to add as comments.
|
||||
//
|
||||
// Any existing comments will be overwritten.
|
||||
typedef void(RENDERDOC_CC *pRENDERDOC_SetCaptureFileComments)(const char *filePath,
|
||||
const char *comments);
|
||||
|
||||
// returns 1 if the RenderDoc UI is connected to this application, 0 otherwise
|
||||
typedef uint32_t(RENDERDOC_CC *pRENDERDOC_IsTargetControlConnected)();
|
||||
|
||||
// DEPRECATED: compatibility for code compiled against pre-1.1.1 headers.
|
||||
// This was renamed to IsTargetControlConnected in API 1.1.1, the old typedef is kept here for
|
||||
// backwards compatibility with old code, it is castable either way since it's ABI compatible
|
||||
// as the same function pointer type.
|
||||
typedef pRENDERDOC_IsTargetControlConnected pRENDERDOC_IsRemoteAccessConnected;
|
||||
|
||||
// This function will launch the Replay UI associated with the RenderDoc library injected
|
||||
// into the running application.
|
||||
//
|
||||
// if connectTargetControl is 1, the Replay UI will be launched with a command line parameter
|
||||
// to connect to this application
|
||||
// cmdline is the rest of the command line, as a UTF-8 string. E.g. a captures to open
|
||||
// if cmdline is NULL, the command line will be empty.
|
||||
//
|
||||
// returns the PID of the replay UI if successful, 0 if not successful.
|
||||
typedef uint32_t(RENDERDOC_CC *pRENDERDOC_LaunchReplayUI)(uint32_t connectTargetControl,
|
||||
const char *cmdline);
|
||||
|
||||
// RenderDoc can return a higher version than requested if it's backwards compatible,
|
||||
// this function returns the actual version returned. If a parameter is NULL, it will be
|
||||
// ignored and the others will be filled out.
|
||||
typedef void(RENDERDOC_CC *pRENDERDOC_GetAPIVersion)(int *major, int *minor, int *patch);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Capturing functions
|
||||
//
|
||||
|
||||
// A device pointer is a pointer to the API's root handle.
|
||||
//
|
||||
// This would be an ID3D11Device, HGLRC/GLXContext, ID3D12Device, etc
|
||||
typedef void *RENDERDOC_DevicePointer;
|
||||
|
||||
// A window handle is the OS's native window handle
|
||||
//
|
||||
// This would be an HWND, GLXDrawable, etc
|
||||
typedef void *RENDERDOC_WindowHandle;
|
||||
|
||||
// A helper macro for Vulkan, where the device handle cannot be used directly.
|
||||
//
|
||||
// Passing the VkInstance to this macro will return the RENDERDOC_DevicePointer to use.
|
||||
//
|
||||
// Specifically, the value needed is the dispatch table pointer, which sits as the first
|
||||
// pointer-sized object in the memory pointed to by the VkInstance. Thus we cast to a void** and
|
||||
// indirect once.
|
||||
#define RENDERDOC_DEVICEPOINTER_FROM_VKINSTANCE(inst) (*((void **)(inst)))
|
||||
|
||||
// This sets the RenderDoc in-app overlay in the API/window pair as 'active' and it will
|
||||
// respond to keypresses. Neither parameter can be NULL
|
||||
typedef void(RENDERDOC_CC *pRENDERDOC_SetActiveWindow)(RENDERDOC_DevicePointer device,
|
||||
RENDERDOC_WindowHandle wndHandle);
|
||||
|
||||
// capture the next frame on whichever window and API is currently considered active
|
||||
typedef void(RENDERDOC_CC *pRENDERDOC_TriggerCapture)();
|
||||
|
||||
// capture the next N frames on whichever window and API is currently considered active
|
||||
typedef void(RENDERDOC_CC *pRENDERDOC_TriggerMultiFrameCapture)(uint32_t numFrames);
|
||||
|
||||
// When choosing either a device pointer or a window handle to capture, you can pass NULL.
|
||||
// Passing NULL specifies a 'wildcard' match against anything. This allows you to specify
|
||||
// any API rendering to a specific window, or a specific API instance rendering to any window,
|
||||
// or in the simplest case of one window and one API, you can just pass NULL for both.
|
||||
//
|
||||
// In either case, if there are two or more possible matching (device,window) pairs it
|
||||
// is undefined which one will be captured.
|
||||
//
|
||||
// Note: for headless rendering you can pass NULL for the window handle and either specify
|
||||
// a device pointer or leave it NULL as above.
|
||||
|
||||
// Immediately starts capturing API calls on the specified device pointer and window handle.
|
||||
//
|
||||
// If there is no matching thing to capture (e.g. no supported API has been initialised),
|
||||
// this will do nothing.
|
||||
//
|
||||
// The results are undefined (including crashes) if two captures are started overlapping,
|
||||
// even on separate devices and/oror windows.
|
||||
typedef void(RENDERDOC_CC *pRENDERDOC_StartFrameCapture)(RENDERDOC_DevicePointer device,
|
||||
RENDERDOC_WindowHandle wndHandle);
|
||||
|
||||
// Returns whether or not a frame capture is currently ongoing anywhere.
|
||||
//
|
||||
// This will return 1 if a capture is ongoing, and 0 if there is no capture running
|
||||
typedef uint32_t(RENDERDOC_CC *pRENDERDOC_IsFrameCapturing)();
|
||||
|
||||
// Ends capturing immediately.
|
||||
//
|
||||
// This will return 1 if the capture succeeded, and 0 if there was an error capturing.
|
||||
typedef uint32_t(RENDERDOC_CC *pRENDERDOC_EndFrameCapture)(RENDERDOC_DevicePointer device,
|
||||
RENDERDOC_WindowHandle wndHandle);
|
||||
|
||||
// Ends capturing immediately and discard any data stored without saving to disk.
|
||||
//
|
||||
// This will return 1 if the capture was discarded, and 0 if there was an error or no capture
|
||||
// was in progress
|
||||
typedef uint32_t(RENDERDOC_CC *pRENDERDOC_DiscardFrameCapture)(RENDERDOC_DevicePointer device,
|
||||
RENDERDOC_WindowHandle wndHandle);
|
||||
|
||||
// Requests that the replay UI show itself (if hidden or not the current top window). This can be
|
||||
// used in conjunction with IsTargetControlConnected and LaunchReplayUI to intelligently handle
|
||||
// showing the UI after making a capture.
|
||||
//
|
||||
// This will return 1 if the request was successfully passed on, though it's not guaranteed that
|
||||
// the UI will be on top in all cases depending on OS rules. It will return 0 if there is no current
|
||||
// target control connection to make such a request, or if there was another error
|
||||
typedef uint32_t(RENDERDOC_CC *pRENDERDOC_ShowReplayUI)();
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// RenderDoc API versions
|
||||
//
|
||||
|
||||
// RenderDoc uses semantic versioning (http://semver.org/).
|
||||
//
|
||||
// MAJOR version is incremented when incompatible API changes happen.
|
||||
// MINOR version is incremented when functionality is added in a backwards-compatible manner.
|
||||
// PATCH version is incremented when backwards-compatible bug fixes happen.
|
||||
//
|
||||
// Note that this means the API returned can be higher than the one you might have requested.
|
||||
// e.g. if you are running against a newer RenderDoc that supports 1.0.1, it will be returned
|
||||
// instead of 1.0.0. You can check this with the GetAPIVersion entry point
|
||||
typedef enum RENDERDOC_Version {
|
||||
eRENDERDOC_API_Version_1_0_0 = 10000, // RENDERDOC_API_1_0_0 = 1 00 00
|
||||
eRENDERDOC_API_Version_1_0_1 = 10001, // RENDERDOC_API_1_0_1 = 1 00 01
|
||||
eRENDERDOC_API_Version_1_0_2 = 10002, // RENDERDOC_API_1_0_2 = 1 00 02
|
||||
eRENDERDOC_API_Version_1_1_0 = 10100, // RENDERDOC_API_1_1_0 = 1 01 00
|
||||
eRENDERDOC_API_Version_1_1_1 = 10101, // RENDERDOC_API_1_1_1 = 1 01 01
|
||||
eRENDERDOC_API_Version_1_1_2 = 10102, // RENDERDOC_API_1_1_2 = 1 01 02
|
||||
eRENDERDOC_API_Version_1_2_0 = 10200, // RENDERDOC_API_1_2_0 = 1 02 00
|
||||
eRENDERDOC_API_Version_1_3_0 = 10300, // RENDERDOC_API_1_3_0 = 1 03 00
|
||||
eRENDERDOC_API_Version_1_4_0 = 10400, // RENDERDOC_API_1_4_0 = 1 04 00
|
||||
eRENDERDOC_API_Version_1_4_1 = 10401, // RENDERDOC_API_1_4_1 = 1 04 01
|
||||
eRENDERDOC_API_Version_1_4_2 = 10402, // RENDERDOC_API_1_4_2 = 1 04 02
|
||||
eRENDERDOC_API_Version_1_5_0 = 10500, // RENDERDOC_API_1_5_0 = 1 05 00
|
||||
} RENDERDOC_Version;
|
||||
|
||||
// API version changelog:
|
||||
//
|
||||
// 1.0.0 - initial release
|
||||
// 1.0.1 - Bugfix: IsFrameCapturing() was returning false for captures that were triggered
|
||||
// by keypress or TriggerCapture, instead of Start/EndFrameCapture.
|
||||
// 1.0.2 - Refactor: Renamed eRENDERDOC_Option_DebugDeviceMode to eRENDERDOC_Option_APIValidation
|
||||
// 1.1.0 - Add feature: TriggerMultiFrameCapture(). Backwards compatible with 1.0.x since the new
|
||||
// function pointer is added to the end of the struct, the original layout is identical
|
||||
// 1.1.1 - Refactor: Renamed remote access to target control (to better disambiguate from remote
|
||||
// replay/remote server concept in replay UI)
|
||||
// 1.1.2 - Refactor: Renamed "log file" in function names to just capture, to clarify that these
|
||||
// are captures and not debug logging files. This is the first API version in the v1.0
|
||||
// branch.
|
||||
// 1.2.0 - Added feature: SetCaptureFileComments() to add comments to a capture file that will be
|
||||
// displayed in the UI program on load.
|
||||
// 1.3.0 - Added feature: New capture option eRENDERDOC_Option_AllowUnsupportedVendorExtensions
|
||||
// which allows users to opt-in to allowing unsupported vendor extensions to function.
|
||||
// Should be used at the user's own risk.
|
||||
// Refactor: Renamed eRENDERDOC_Option_VerifyMapWrites to
|
||||
// eRENDERDOC_Option_VerifyBufferAccess, which now also controls initialisation to
|
||||
// 0xdddddddd of uninitialised buffer contents.
|
||||
// 1.4.0 - Added feature: DiscardFrameCapture() to discard a frame capture in progress and stop
|
||||
// capturing without saving anything to disk.
|
||||
// 1.4.1 - Refactor: Renamed Shutdown to RemoveHooks to better clarify what is happening
|
||||
// 1.4.2 - Refactor: Renamed 'draws' to 'actions' in callstack capture option.
|
||||
// 1.5.0 - Added feature: ShowReplayUI() to request that the replay UI show itself if connected
|
||||
|
||||
typedef struct RENDERDOC_API_1_5_0
|
||||
{
|
||||
pRENDERDOC_GetAPIVersion GetAPIVersion;
|
||||
|
||||
pRENDERDOC_SetCaptureOptionU32 SetCaptureOptionU32;
|
||||
pRENDERDOC_SetCaptureOptionF32 SetCaptureOptionF32;
|
||||
|
||||
pRENDERDOC_GetCaptureOptionU32 GetCaptureOptionU32;
|
||||
pRENDERDOC_GetCaptureOptionF32 GetCaptureOptionF32;
|
||||
|
||||
pRENDERDOC_SetFocusToggleKeys SetFocusToggleKeys;
|
||||
pRENDERDOC_SetCaptureKeys SetCaptureKeys;
|
||||
|
||||
pRENDERDOC_GetOverlayBits GetOverlayBits;
|
||||
pRENDERDOC_MaskOverlayBits MaskOverlayBits;
|
||||
|
||||
// Shutdown was renamed to RemoveHooks in 1.4.1.
|
||||
// These unions allow old code to continue compiling without changes
|
||||
union
|
||||
{
|
||||
pRENDERDOC_Shutdown Shutdown;
|
||||
pRENDERDOC_RemoveHooks RemoveHooks;
|
||||
};
|
||||
pRENDERDOC_UnloadCrashHandler UnloadCrashHandler;
|
||||
|
||||
// Get/SetLogFilePathTemplate was renamed to Get/SetCaptureFilePathTemplate in 1.1.2.
|
||||
// These unions allow old code to continue compiling without changes
|
||||
union
|
||||
{
|
||||
// deprecated name
|
||||
pRENDERDOC_SetLogFilePathTemplate SetLogFilePathTemplate;
|
||||
// current name
|
||||
pRENDERDOC_SetCaptureFilePathTemplate SetCaptureFilePathTemplate;
|
||||
};
|
||||
union
|
||||
{
|
||||
// deprecated name
|
||||
pRENDERDOC_GetLogFilePathTemplate GetLogFilePathTemplate;
|
||||
// current name
|
||||
pRENDERDOC_GetCaptureFilePathTemplate GetCaptureFilePathTemplate;
|
||||
};
|
||||
|
||||
pRENDERDOC_GetNumCaptures GetNumCaptures;
|
||||
pRENDERDOC_GetCapture GetCapture;
|
||||
|
||||
pRENDERDOC_TriggerCapture TriggerCapture;
|
||||
|
||||
// IsRemoteAccessConnected was renamed to IsTargetControlConnected in 1.1.1.
|
||||
// This union allows old code to continue compiling without changes
|
||||
union
|
||||
{
|
||||
// deprecated name
|
||||
pRENDERDOC_IsRemoteAccessConnected IsRemoteAccessConnected;
|
||||
// current name
|
||||
pRENDERDOC_IsTargetControlConnected IsTargetControlConnected;
|
||||
};
|
||||
pRENDERDOC_LaunchReplayUI LaunchReplayUI;
|
||||
|
||||
pRENDERDOC_SetActiveWindow SetActiveWindow;
|
||||
|
||||
pRENDERDOC_StartFrameCapture StartFrameCapture;
|
||||
pRENDERDOC_IsFrameCapturing IsFrameCapturing;
|
||||
pRENDERDOC_EndFrameCapture EndFrameCapture;
|
||||
|
||||
// new function in 1.1.0
|
||||
pRENDERDOC_TriggerMultiFrameCapture TriggerMultiFrameCapture;
|
||||
|
||||
// new function in 1.2.0
|
||||
pRENDERDOC_SetCaptureFileComments SetCaptureFileComments;
|
||||
|
||||
// new function in 1.4.0
|
||||
pRENDERDOC_DiscardFrameCapture DiscardFrameCapture;
|
||||
|
||||
// new function in 1.5.0
|
||||
pRENDERDOC_ShowReplayUI ShowReplayUI;
|
||||
} RENDERDOC_API_1_5_0;
|
||||
|
||||
typedef RENDERDOC_API_1_5_0 RENDERDOC_API_1_0_0;
|
||||
typedef RENDERDOC_API_1_5_0 RENDERDOC_API_1_0_1;
|
||||
typedef RENDERDOC_API_1_5_0 RENDERDOC_API_1_0_2;
|
||||
typedef RENDERDOC_API_1_5_0 RENDERDOC_API_1_1_0;
|
||||
typedef RENDERDOC_API_1_5_0 RENDERDOC_API_1_1_1;
|
||||
typedef RENDERDOC_API_1_5_0 RENDERDOC_API_1_1_2;
|
||||
typedef RENDERDOC_API_1_5_0 RENDERDOC_API_1_2_0;
|
||||
typedef RENDERDOC_API_1_5_0 RENDERDOC_API_1_3_0;
|
||||
typedef RENDERDOC_API_1_5_0 RENDERDOC_API_1_4_0;
|
||||
typedef RENDERDOC_API_1_5_0 RENDERDOC_API_1_4_1;
|
||||
typedef RENDERDOC_API_1_5_0 RENDERDOC_API_1_4_2;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// RenderDoc API entry point
|
||||
//
|
||||
// This entry point can be obtained via GetProcAddress/dlsym if RenderDoc is available.
|
||||
//
|
||||
// The name is the same as the typedef - "RENDERDOC_GetAPI"
|
||||
//
|
||||
// This function is not thread safe, and should not be called on multiple threads at once.
|
||||
// Ideally, call this once as early as possible in your application's startup, before doing
|
||||
// any API work, since some configuration functionality etc has to be done also before
|
||||
// initialising any APIs.
|
||||
//
|
||||
// Parameters:
|
||||
// version is a single value from the RENDERDOC_Version above.
|
||||
//
|
||||
// outAPIPointers will be filled out with a pointer to the corresponding struct of function
|
||||
// pointers.
|
||||
//
|
||||
// Returns:
|
||||
// 1 - if the outAPIPointers has been filled with a pointer to the API struct requested
|
||||
// 0 - if the requested version is not supported or the arguments are invalid.
|
||||
//
|
||||
typedef int(RENDERDOC_CC *pRENDERDOC_GetAPI)(RENDERDOC_Version version, void **outAPIPointers);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
|
@ -1 +0,0 @@
|
|||
Subproject commit f8e0f679d2fad8b47f6300f25ab844fd49a1f7e5
|
|
@ -1 +0,0 @@
|
|||
Subproject commit 0e22c80ff7b1bb4c4c5c7c3dd2e91b4a58ad519d
|
|
@ -1 +0,0 @@
|
|||
Subproject commit d7ad93a88864bda94e282e95028f90b5784e4d20
|
|
@ -1 +0,0 @@
|
|||
Subproject commit 67fad04348b91cf93bdfad7495d298f54825602c
|
|
@ -1 +1 @@
|
|||
Subproject commit de5ced3d4b76dd24bc43628127e26a9c7eb098d3
|
||||
Subproject commit f638311337d6b0eaf63e84c6e9afe1227539e0d3
|
|
@ -1 +1 @@
|
|||
Subproject commit 80dada6a7b455cf18c39788d70aa7711323ea977
|
||||
Subproject commit a4b8f74942a932ea191dc95cc4a210fea524508f
|
|
@ -1,208 +0,0 @@
|
|||
The majority of files in this project use the Apache 2.0 License.
|
||||
There are a few exceptions and their license can be found in the source.
|
||||
Any license deviations from Apache 2.0 are "more permissive" licenses.
|
||||
Any file without a license in it's source defaults to the repository Apache 2.0 License.
|
||||
|
||||
===========================================================================================
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
Binary file not shown.
|
@ -1 +0,0 @@
|
|||
Subproject commit 936bc4b57e7ffa5906a786735537c5493224e7d6
|
|
@ -1,7 +0,0 @@
|
|||
// SPDX-License-Identifier: MPL-2.0
|
||||
// Copyright © 2021 Skyline Team and Contributors (https://github.com/skyline-emu/)
|
||||
|
||||
#define VMA_IMPLEMENTATION
|
||||
#define VMA_STATIC_VULKAN_FUNCTIONS 0
|
||||
#define VMA_DYNAMIC_VULKAN_FUNCTIONS 0
|
||||
#include <vk_mem_alloc.h>
|
30
app/proguard-rules.pro
vendored
30
app/proguard-rules.pro
vendored
|
@ -4,33 +4,3 @@
|
|||
|
||||
# Retain all classes within Skyline for traces + JNI access + Serializable classes
|
||||
-keep class emu.skyline.** { *; }
|
||||
# Keep kotlin classes so that kotlin reflection works
|
||||
-keep class kotlin.** {*;}
|
||||
|
||||
# https://github.com/Kotlin/kotlinx.serialization#android
|
||||
# Keep `Companion` object fields of serializable classes.
|
||||
# This avoids serializer lookup through `getDeclaredClasses` as done for named companion objects.
|
||||
-if @kotlinx.serialization.Serializable class **
|
||||
-keepclassmembers class <1> {
|
||||
static <1>$Companion Companion;
|
||||
}
|
||||
|
||||
# Keep `serializer()` on companion objects (both default and named) of serializable classes.
|
||||
-if @kotlinx.serialization.Serializable class ** {
|
||||
static **$* *;
|
||||
}
|
||||
-keepclassmembers class <2>$<3> {
|
||||
kotlinx.serialization.KSerializer serializer(...);
|
||||
}
|
||||
|
||||
# Keep `INSTANCE.serializer()` of serializable objects.
|
||||
-if @kotlinx.serialization.Serializable class ** {
|
||||
public static ** INSTANCE;
|
||||
}
|
||||
-keepclassmembers class <1> {
|
||||
public static <1> INSTANCE;
|
||||
kotlinx.serialization.KSerializer serializer(...);
|
||||
}
|
||||
|
||||
# @Serializable and @Polymorphic are used at runtime for polymorphic serialization.
|
||||
-keepattributes RuntimeVisibleAnnotations,AnnotationDefault
|
||||
|
|
|
@ -1,78 +1,83 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools">
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
package="emu.skyline">
|
||||
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
<uses-permission android:name="android.permission.VIBRATE" />
|
||||
|
||||
<uses-feature
|
||||
android:name="android.hardware.vulkan.version"
|
||||
android:required="true"
|
||||
android:version="0x401000" />
|
||||
|
||||
android:glEsVersion="0x00030001"
|
||||
android:required="true" />
|
||||
<uses-permission android:name="android.permission.VIBRATE" />
|
||||
<application
|
||||
android:name=".SkylineApplication"
|
||||
android:enableOnBackInvokedCallback="true"
|
||||
android:allowBackup="true"
|
||||
android:extractNativeLibs="true"
|
||||
android:fullBackupContent="@xml/backup_descriptor"
|
||||
android:hasFragileUserData="${shouldSaveUserData}"
|
||||
android:icon="@drawable/logo_skyline"
|
||||
android:isGame="true"
|
||||
android:label="${appLabel}"
|
||||
android:localeConfig="@xml/locales_config"
|
||||
android:supportsRtl="true"
|
||||
android:theme="@style/AppTheme"
|
||||
tools:ignore="GoogleAppIndexingWarning,UnusedAttribute">
|
||||
|
||||
<profileable android:shell="true" />
|
||||
|
||||
<activity
|
||||
android:name=".MainActivity"
|
||||
android:exported="true"
|
||||
android:launchMode="singleTop">
|
||||
android:name=".SkylineApplication"
|
||||
android:allowBackup="true"
|
||||
android:extractNativeLibs="true"
|
||||
android:fullBackupContent="@xml/backup_descriptor"
|
||||
android:icon="@drawable/logo_skyline"
|
||||
android:isGame="true"
|
||||
android:label="@string/app_name"
|
||||
android:supportsRtl="true"
|
||||
android:theme="@style/AppTheme"
|
||||
tools:ignore="GoogleAppIndexingWarning,UnusedAttribute">
|
||||
<activity android:name="emu.skyline.MainActivity">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<activity
|
||||
android:name=".settings.SettingsActivity"
|
||||
android:exported="true"
|
||||
android:label="@string/settings"
|
||||
android:launchMode="singleTop"
|
||||
android:parentActivityName=".MainActivity">
|
||||
android:name="emu.skyline.LogActivity"
|
||||
android:label="@string/log"
|
||||
android:parentActivityName="emu.skyline.MainActivity">
|
||||
<meta-data
|
||||
android:name="android.support.PARENT_ACTIVITY"
|
||||
android:value="emu.skyline.MainActivity" />
|
||||
</activity>
|
||||
|
||||
<activity
|
||||
android:name=".input.ControllerActivity"
|
||||
android:exported="true"
|
||||
android:parentActivityName=".settings.SettingsActivity">
|
||||
android:name="emu.skyline.SettingsActivity"
|
||||
android:exported="true"
|
||||
android:label="@string/settings"
|
||||
android:parentActivityName="emu.skyline.MainActivity">
|
||||
<meta-data
|
||||
android:name="android.support.PARENT_ACTIVITY"
|
||||
android:value="emu.skyline.MainActivity" />
|
||||
</activity>
|
||||
|
||||
<activity
|
||||
android:name=".preference.GpuDriverActivity"
|
||||
android:exported="true"
|
||||
android:parentActivityName=".settings.SettingsActivity">
|
||||
<activity android:name="emu.skyline.preference.FolderActivity">
|
||||
<meta-data
|
||||
android:name="android.support.PARENT_ACTIVITY"
|
||||
android:value="emu.skyline.SettingsActivity" />
|
||||
</activity>
|
||||
|
||||
<activity
|
||||
android:name=".input.onscreen.OnScreenEditActivity"
|
||||
android:exported="true"
|
||||
android:screenOrientation="sensorLandscape"
|
||||
tools:ignore="LockedOrientationActivity"
|
||||
android:parentActivityName=".input.ControllerActivity">
|
||||
<activity android:name="emu.skyline.preference.FileActivity">
|
||||
<meta-data
|
||||
android:name="android.support.PARENT_ACTIVITY"
|
||||
android:value="emu.skyline.SettingsActivity" />
|
||||
</activity>
|
||||
|
||||
<activity
|
||||
android:name=".EmulationActivity"
|
||||
android:supportsPictureInPicture="true"
|
||||
android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout|uiMode"
|
||||
android:exported="true"
|
||||
android:launchMode="singleTask"
|
||||
android:process="${emulationProcess}"
|
||||
android:parentActivityName=".MainActivity">
|
||||
android:name="emu.skyline.input.ControllerActivity"
|
||||
android:exported="true">
|
||||
<meta-data
|
||||
android:name="android.support.PARENT_ACTIVITY"
|
||||
android:value="emu.skyline.SettingsActivity" />
|
||||
</activity>
|
||||
<activity
|
||||
android:name="emu.skyline.input.onscreen.OnScreenEditActivity"
|
||||
android:exported="true"
|
||||
android:screenOrientation="landscape"
|
||||
tools:ignore="LockedOrientationActivity">
|
||||
<meta-data
|
||||
android:name="android.support.PARENT_ACTIVITY"
|
||||
android:value="emu.skyline.input.ControllerActivity" />
|
||||
</activity>
|
||||
<activity
|
||||
android:name="emu.skyline.EmulationActivity"
|
||||
android:configChanges="orientation|screenSize"
|
||||
android:launchMode="singleInstance"
|
||||
android:screenOrientation="landscape"
|
||||
tools:ignore="LockedOrientationActivity">
|
||||
<meta-data
|
||||
android:name="android.support.PARENT_ACTIVITY"
|
||||
android:value="emu.skyline.MainActivity" />
|
||||
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
|
@ -81,54 +86,30 @@
|
|||
<category android:name="android.intent.category.DEFAULT" />
|
||||
|
||||
<data
|
||||
android:mimeType="application/nro"
|
||||
android:pathPattern=".*\\.nro"
|
||||
android:scheme="content"
|
||||
tools:ignore="AppLinkUrlError" />
|
||||
android:mimeType="application/nro"
|
||||
android:pathPattern=".*\\.nro"
|
||||
android:scheme="content"
|
||||
tools:ignore="AppLinkUrlError" />
|
||||
</intent-filter>
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
|
||||
<data
|
||||
android:mimeType="text/plain"
|
||||
android:pathPattern=".*\\.nro"
|
||||
android:scheme="content"
|
||||
tools:ignore="IntentFilterUniqueDataAttributes" />
|
||||
android:mimeType="text/plain"
|
||||
android:pathPattern=".*\\.nro"
|
||||
android:scheme="content"
|
||||
tools:ignore="AppLinkUrlError" />
|
||||
<data
|
||||
android:mimeType="application/octet-stream"
|
||||
android:pathPattern=".*\\.nro"
|
||||
android:scheme="content"
|
||||
tools:ignore="IntentFilterUniqueDataAttributes" />
|
||||
android:mimeType="application/octet-stream"
|
||||
android:pathPattern=".*\\.nro"
|
||||
android:scheme="content"
|
||||
tools:ignore="AppLinkUrlError" />
|
||||
<data
|
||||
android:mimeType="application/nro"
|
||||
android:scheme="content"
|
||||
tools:ignore="IntentFilterUniqueDataAttributes" />
|
||||
android:mimeType="application/nro"
|
||||
android:scheme="content"
|
||||
tools:ignore="AppLinkUrlError" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<provider
|
||||
android:name=".provider.DocumentsProvider"
|
||||
android:authorities="${applicationId}.provider"
|
||||
android:exported="true"
|
||||
android:grantUriPermissions="true"
|
||||
android:permission="android.permission.MANAGE_DOCUMENTS">
|
||||
<intent-filter>
|
||||
<action android:name="android.content.action.DOCUMENTS_PROVIDER" />
|
||||
</intent-filter>
|
||||
</provider>
|
||||
|
||||
<service
|
||||
android:name="androidx.appcompat.app.AppLocalesMetadataHolderService"
|
||||
android:enabled="false"
|
||||
android:exported="false">
|
||||
<meta-data
|
||||
android:name="autoStoreLocales"
|
||||
android:value="true" />
|
||||
</service>
|
||||
|
||||
<meta-data
|
||||
android:name="com.android.graphics.injectLayers.enable"
|
||||
android:value="true" />
|
||||
</application>
|
||||
</manifest>
|
||||
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -1,3 +0,0 @@
|
|||
#### Skyline FOSS Shared Fonts:
|
||||
* [FontStandard](FontStandard.ttf), [FontKorean](FontKorean.ttf), [FontChineseSimplified](FontChineseSimplified.ttf), [FontChineseTraditional](FontChineseTraditional.ttf) and [FontExtendedChineseSimplified](FontExtendedChineseSimplified.ttf) are using [Noto Sans CJK](https://github.com/googlefonts/noto-cjk), which is licensed under [Open Font License](https://scripts.sil.org/cms/scripts/page.php?site_id=nrsi&id=OFL)
|
||||
* [FontNintendoExtended](FontNintendoExtended.ttf) is using [Roboto](https://fonts.google.com/specimen/Roboto), which is licensed under [Apache 2.0](https://www.apache.org/licenses/LICENSE-2.0)
|
Binary file not shown.
Before Width: | Height: | Size: 19 KiB |
Binary file not shown.
Binary file not shown.
|
@ -1,50 +0,0 @@
|
|||
// SPDX-License-Identifier: MPL-2.0
|
||||
// Copyright © 2022 Skyline Team and Contributors (https://github.com/skyline-emu/)
|
||||
|
||||
#include <jni.h>
|
||||
#include <dlfcn.h>
|
||||
#include <fcntl.h>
|
||||
#include <vulkan/vulkan_raii.hpp>
|
||||
#include <adrenotools/driver.h>
|
||||
#include "skyline/common/signal.h"
|
||||
#include "skyline/common/utils.h"
|
||||
|
||||
extern "C" JNIEXPORT jobjectArray JNICALL Java_emu_skyline_utils_GpuDriverHelper_00024Companion_getSystemDriverInfo(JNIEnv *env, jobject) {
|
||||
auto libvulkanHandle{dlopen("libvulkan.so", RTLD_NOW)};
|
||||
|
||||
vk::raii::Context vkContext{reinterpret_cast<PFN_vkGetInstanceProcAddr>(dlsym(libvulkanHandle, "vkGetInstanceProcAddr"))};
|
||||
vk::raii::Instance vkInstance{vkContext, vk::InstanceCreateInfo{}};
|
||||
vk::raii::PhysicalDevice physicalDevice{std::move(vk::raii::PhysicalDevices(vkInstance).front())}; // Get the first device as we aren't expecting multiple GPUs
|
||||
|
||||
auto deviceProperties2{physicalDevice.getProperties2<vk::PhysicalDeviceProperties2, vk::PhysicalDeviceDriverProperties>()};
|
||||
auto properties{deviceProperties2.get<vk::PhysicalDeviceProperties2>().properties};
|
||||
|
||||
auto driverId{vk::to_string(deviceProperties2.get<vk::PhysicalDeviceDriverProperties>().driverID)};
|
||||
auto driverVersion{skyline::util::Format("{}.{}.{}", VK_API_VERSION_MAJOR(properties.driverVersion), VK_API_VERSION_MINOR(properties.driverVersion), VK_API_VERSION_PATCH(properties.driverVersion))};
|
||||
|
||||
auto array = env->NewObjectArray(2, env->FindClass("java/lang/String"), nullptr);
|
||||
env->SetObjectArrayElement(array, 0, env->NewStringUTF(driverId.c_str()));
|
||||
env->SetObjectArrayElement(array, 1, env->NewStringUTF(driverVersion.c_str()));
|
||||
|
||||
return array;
|
||||
}
|
||||
|
||||
static bool CheckKgslPresent() {
|
||||
constexpr auto KgslPath{"/dev/kgsl-3d0"};
|
||||
|
||||
return access(KgslPath, F_OK) == 0;
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT jboolean JNICALL Java_emu_skyline_utils_GpuDriverHelper_00024Companion_supportsCustomDriverLoading(JNIEnv *env, jobject instance) {
|
||||
// If the KGSL device exists custom drivers can be loaded using adrenotools
|
||||
return CheckKgslPresent();
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT jboolean JNICALL Java_emu_skyline_utils_GpuDriverHelper_00024Companion_supportsForceMaxGpuClocks(JNIEnv *env, jobject instance) {
|
||||
// If the KGSL device exists adrenotools can be used to set GPU turbo mode
|
||||
return CheckKgslPresent();
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT void JNICALL Java_emu_skyline_utils_GpuDriverHelper_00024Companion_forceMaxGpuClocks(JNIEnv *env, jobject instance, jboolean enable) {
|
||||
adrenotools_set_turbo(enable);
|
||||
}
|
|
@ -3,35 +3,31 @@
|
|||
|
||||
#include <csignal>
|
||||
#include <pthread.h>
|
||||
#include <unistd.h>
|
||||
#include <android/log.h>
|
||||
#include <android/asset_manager_jni.h>
|
||||
#include <sys/system_properties.h>
|
||||
#include "skyline/common.h"
|
||||
#include "skyline/common/language.h"
|
||||
#include "skyline/common/signal.h"
|
||||
#include "skyline/common/android_settings.h"
|
||||
#include "skyline/common/settings.h"
|
||||
#include "skyline/common/trace.h"
|
||||
#include "skyline/loader/loader.h"
|
||||
#include "skyline/vfs/android_asset_filesystem.h"
|
||||
#include "skyline/os.h"
|
||||
#include "skyline/jvm.h"
|
||||
#include "skyline/gpu.h"
|
||||
#include "skyline/audio.h"
|
||||
#include "skyline/input.h"
|
||||
#include "skyline/kernel/types/KProcess.h"
|
||||
|
||||
jint Fps; //!< An approximation of the amount of frames being submitted every second
|
||||
jfloat AverageFrametimeMs; //!< The average time it takes for a frame to be rendered and presented in milliseconds
|
||||
jfloat AverageFrametimeDeviationMs; //!< The average deviation of the average frametimes in milliseconds
|
||||
|
||||
skyline::u16 Fps;
|
||||
skyline::u32 FrameTime;
|
||||
std::weak_ptr<skyline::kernel::OS> OsWeak;
|
||||
std::weak_ptr<skyline::gpu::GPU> GpuWeak;
|
||||
std::weak_ptr<skyline::audio::Audio> AudioWeak;
|
||||
std::weak_ptr<skyline::input::Input> InputWeak;
|
||||
std::weak_ptr<skyline::Settings> SettingsWeak;
|
||||
|
||||
// https://cs.android.com/android/platform/superproject/+/master:bionic/libc/tzcode/bionic.cpp;l=43;drc=master;bpv=1;bpt=1
|
||||
static std::string GetTimeZoneName() {
|
||||
const char *nameEnv = getenv("TZ");
|
||||
const char* nameEnv = getenv("TZ");
|
||||
if (nameEnv)
|
||||
return std::string(nameEnv);
|
||||
|
||||
|
@ -54,101 +50,68 @@ static std::string GetTimeZoneName() {
|
|||
return "GMT";
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT void Java_emu_skyline_SkylineApplication_initializeLog(
|
||||
JNIEnv *env,
|
||||
jobject,
|
||||
jstring publicAppFilesPathJstring,
|
||||
jint logLevel
|
||||
) {
|
||||
skyline::JniString publicAppFilesPath(env, publicAppFilesPathJstring);
|
||||
skyline::Logger::configLevel = static_cast<skyline::Logger::LogLevel>(logLevel);
|
||||
skyline::Logger::LoaderContext.Initialize(publicAppFilesPath + "logs/loader.sklog");
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT void Java_emu_skyline_EmulationActivity_executeApplication(
|
||||
JNIEnv *env,
|
||||
jobject instance,
|
||||
jstring romUriJstring,
|
||||
jint romType,
|
||||
jint romFd,
|
||||
jobject settingsInstance,
|
||||
jstring publicAppFilesPathJstring,
|
||||
jstring privateAppFilesPathJstring,
|
||||
jstring nativeLibraryPathJstring,
|
||||
jobject assetManager
|
||||
) {
|
||||
extern "C" JNIEXPORT void Java_emu_skyline_EmulationActivity_executeApplication(JNIEnv *env, jobject instance, jstring romUriJstring, jint romType, jint romFd, jint preferenceFd, jstring appFilesPathJstring, jobject assetManager) {
|
||||
skyline::signal::ScopedStackBlocker stackBlocker; // We do not want anything to unwind past JNI code as there are invalid stack frames which can lead to a segmentation fault
|
||||
Fps = 0;
|
||||
AverageFrametimeMs = AverageFrametimeDeviationMs = 0.0f;
|
||||
Fps = FrameTime = 0;
|
||||
|
||||
pthread_setname_np(pthread_self(), "EmuMain");
|
||||
|
||||
auto jvmManager{std::make_shared<skyline::JvmManager>(env, instance)};
|
||||
auto settings{std::make_shared<skyline::Settings>(preferenceFd)};
|
||||
close(preferenceFd);
|
||||
|
||||
std::shared_ptr<skyline::Settings> settings{std::make_shared<skyline::AndroidSettings>(env, settingsInstance)};
|
||||
|
||||
skyline::JniString publicAppFilesPath(env, publicAppFilesPathJstring);
|
||||
skyline::Logger::EmulationContext.Initialize(publicAppFilesPath + "logs/emulation.sklog");
|
||||
auto appFilesPath{env->GetStringUTFChars(appFilesPathJstring, nullptr)};
|
||||
auto logger{std::make_shared<skyline::Logger>(std::string(appFilesPath) + "skyline.log", settings->logLevel)};
|
||||
|
||||
auto start{std::chrono::steady_clock::now()};
|
||||
|
||||
// Initialize tracing
|
||||
perfetto::TracingInitArgs args;
|
||||
args.backends |= perfetto::kSystemBackend;
|
||||
args.shmem_size_hint_kb = 0x200000;
|
||||
perfetto::Tracing::Initialize(args);
|
||||
perfetto::TrackEvent::Register();
|
||||
|
||||
try {
|
||||
skyline::JniString nativeLibraryPath(env, nativeLibraryPathJstring);
|
||||
skyline::JniString privateAppFilesPath{env, privateAppFilesPathJstring};
|
||||
|
||||
auto os{std::make_shared<skyline::kernel::OS>(
|
||||
jvmManager,
|
||||
settings,
|
||||
publicAppFilesPath,
|
||||
privateAppFilesPath,
|
||||
nativeLibraryPath,
|
||||
GetTimeZoneName(),
|
||||
std::make_shared<skyline::vfs::AndroidAssetFileSystem>(AAssetManager_fromJava(env, assetManager))
|
||||
)};
|
||||
auto os{std::make_shared<skyline::kernel::OS>(jvmManager, logger, settings, std::string(appFilesPath), GetTimeZoneName(), std::make_shared<skyline::vfs::AndroidAssetFileSystem>(AAssetManager_fromJava(env, assetManager)))};
|
||||
OsWeak = os;
|
||||
GpuWeak = os->state.gpu;
|
||||
AudioWeak = os->state.audio;
|
||||
InputWeak = os->state.input;
|
||||
SettingsWeak = settings;
|
||||
jvmManager->InitializeControllers();
|
||||
env->ReleaseStringUTFChars(appFilesPathJstring, appFilesPath);
|
||||
|
||||
skyline::Logger::DebugNoPrefix("Launching ROM {}", skyline::JniString(env, romUriJstring));
|
||||
auto romUri{env->GetStringUTFChars(romUriJstring, nullptr)};
|
||||
logger->InfoNoPrefix("Launching ROM {}", romUri);
|
||||
env->ReleaseStringUTFChars(romUriJstring, romUri);
|
||||
|
||||
os->Execute(romFd, static_cast<skyline::loader::RomFormat>(romType));
|
||||
} catch (std::exception &e) {
|
||||
skyline::Logger::ErrorNoPrefix("An uncaught exception has occurred: {}", e.what());
|
||||
logger->Error("An exception has occurred: {}", e.what());
|
||||
} catch (const skyline::signal::SignalException &e) {
|
||||
skyline::Logger::ErrorNoPrefix("An uncaught exception has occurred: {}", e.what());
|
||||
logger->Error("An exception has occurred: {}", e.what());
|
||||
} catch (...) {
|
||||
skyline::Logger::ErrorNoPrefix("An unknown uncaught exception has occurred");
|
||||
logger->Error("An unknown exception has occurred");
|
||||
}
|
||||
|
||||
perfetto::TrackEvent::Flush();
|
||||
|
||||
InputWeak.reset();
|
||||
|
||||
auto end{std::chrono::steady_clock::now()};
|
||||
skyline::Logger::Write(skyline::Logger::LogLevel::Info, fmt::format("Emulation has ended in {}ms", std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count()));
|
||||
logger->InfoNoPrefix("Emulation has ended");
|
||||
|
||||
auto end{std::chrono::steady_clock::now()};
|
||||
logger->InfoNoPrefix("Done in: {} ms", (std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count()));
|
||||
|
||||
skyline::Logger::EmulationContext.Finalize();
|
||||
close(romFd);
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT jboolean Java_emu_skyline_EmulationActivity_stopEmulation(JNIEnv *, jobject, jboolean join) {
|
||||
extern "C" JNIEXPORT jboolean Java_emu_skyline_EmulationActivity_stopEmulation(JNIEnv *, jobject) {
|
||||
auto os{OsWeak.lock()};
|
||||
if (!os)
|
||||
return false;
|
||||
auto process{os->state.process};
|
||||
if (!process)
|
||||
return false;
|
||||
process->Kill(join, false, true);
|
||||
process->Kill(true, false, true);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -160,15 +123,6 @@ extern "C" JNIEXPORT jboolean Java_emu_skyline_EmulationActivity_setSurface(JNIE
|
|||
return true;
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT void Java_emu_skyline_EmulationActivity_changeAudioStatus(JNIEnv *, jobject, jboolean play) {
|
||||
auto audio{AudioWeak.lock()};
|
||||
if (audio)
|
||||
if (play)
|
||||
audio->Resume();
|
||||
else
|
||||
audio->Pause();
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT void Java_emu_skyline_EmulationActivity_updatePerformanceStatistics(JNIEnv *env, jobject thiz) {
|
||||
static jclass clazz{};
|
||||
if (!clazz)
|
||||
|
@ -179,58 +133,41 @@ extern "C" JNIEXPORT void Java_emu_skyline_EmulationActivity_updatePerformanceSt
|
|||
fpsField = env->GetFieldID(clazz, "fps", "I");
|
||||
env->SetIntField(thiz, fpsField, Fps);
|
||||
|
||||
static jfieldID averageFrametimeField{};
|
||||
if (!averageFrametimeField)
|
||||
averageFrametimeField = env->GetFieldID(clazz, "averageFrametime", "F");
|
||||
env->SetFloatField(thiz, averageFrametimeField, AverageFrametimeMs);
|
||||
|
||||
static jfieldID averageFrametimeDeviationField{};
|
||||
if (!averageFrametimeDeviationField)
|
||||
averageFrametimeDeviationField = env->GetFieldID(clazz, "averageFrametimeDeviation", "F");
|
||||
env->SetFloatField(thiz, averageFrametimeDeviationField, AverageFrametimeDeviationMs);
|
||||
static jfieldID frametimeField{};
|
||||
if (!frametimeField)
|
||||
frametimeField = env->GetFieldID(clazz, "frametime", "F");
|
||||
env->SetFloatField(thiz, frametimeField, static_cast<float>(FrameTime) / 100);
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT void JNICALL Java_emu_skyline_input_InputHandler_00024Companion_setController(JNIEnv *, jobject, jint index, jint type, jint partnerIndex) {
|
||||
extern "C" JNIEXPORT void JNICALL Java_emu_skyline_EmulationActivity_setController(JNIEnv *, jobject, jint index, jint type, jint partnerIndex) {
|
||||
auto input{InputWeak.lock()};
|
||||
std::lock_guard guard(input->npad.mutex);
|
||||
input->npad.controllers[static_cast<size_t>(index)] = skyline::input::GuestController{static_cast<skyline::input::NpadControllerType>(type), static_cast<skyline::i8>(partnerIndex)};
|
||||
input->npad.controllers[index] = skyline::input::GuestController{static_cast<skyline::input::NpadControllerType>(type), static_cast<skyline::i8>(partnerIndex)};
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT void JNICALL Java_emu_skyline_input_InputHandler_00024Companion_updateControllers(JNIEnv *, jobject) {
|
||||
extern "C" JNIEXPORT void JNICALL Java_emu_skyline_EmulationActivity_updateControllers(JNIEnv *, jobject) {
|
||||
InputWeak.lock()->npad.Update();
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT void JNICALL Java_emu_skyline_input_InputHandler_00024Companion_setButtonState(JNIEnv *, jobject, jint index, jlong mask, jboolean pressed) {
|
||||
extern "C" JNIEXPORT void JNICALL Java_emu_skyline_EmulationActivity_setButtonState(JNIEnv *, jobject, jint index, jlong mask, jboolean pressed) {
|
||||
auto input{InputWeak.lock()};
|
||||
if (!input)
|
||||
return; // We don't mind if we miss button updates while input hasn't been initialized
|
||||
auto device{input->npad.controllers[static_cast<size_t>(index)].device};
|
||||
auto device{input->npad.controllers[index].device};
|
||||
if (device)
|
||||
device->SetButtonState(skyline::input::NpadButton{.raw = static_cast<skyline::u64>(mask)}, pressed);
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT void JNICALL Java_emu_skyline_input_InputHandler_00024Companion_setAxisValue(JNIEnv *, jobject, jint index, jint axis, jint value) {
|
||||
extern "C" JNIEXPORT void JNICALL Java_emu_skyline_EmulationActivity_setAxisValue(JNIEnv *, jobject, jint index, jint axis, jint value) {
|
||||
auto input{InputWeak.lock()};
|
||||
if (!input)
|
||||
return; // We don't mind if we miss axis updates while input hasn't been initialized
|
||||
auto device{input->npad.controllers[static_cast<size_t>(index)].device};
|
||||
auto device{input->npad.controllers[index].device};
|
||||
if (device)
|
||||
device->SetAxisValue(static_cast<skyline::input::NpadAxisId>(axis), value);
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT void JNICALL Java_emu_skyline_input_InputHandler_00024Companion_setMotionState(JNIEnv *env, jobject, jint index, jint motionId, jobject value) {
|
||||
auto input{InputWeak.lock()};
|
||||
if (!input)
|
||||
return; // We don't mind if we miss motion updates while input hasn't been initialized
|
||||
|
||||
const auto motionValue = reinterpret_cast<skyline::input::MotionSensorState*>(env->GetDirectBufferAddress(value));
|
||||
|
||||
auto device{input->npad.controllers[static_cast<size_t>(index)].device};
|
||||
if (device)
|
||||
device->SetMotionValue(static_cast<skyline::input::MotionId>(motionId), motionValue);
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT void JNICALL Java_emu_skyline_input_InputHandler_00024Companion_setTouchState(JNIEnv *env, jobject, jintArray pointsJni) {
|
||||
extern "C" JNIEXPORT void JNICALL Java_emu_skyline_EmulationActivity_setTouchState(JNIEnv *env, jobject, jintArray pointsJni) {
|
||||
using Point = skyline::input::TouchScreenPoint;
|
||||
|
||||
auto input{InputWeak.lock()};
|
||||
|
@ -238,19 +175,7 @@ extern "C" JNIEXPORT void JNICALL Java_emu_skyline_input_InputHandler_00024Compa
|
|||
return; // We don't mind if we miss touch updates while input hasn't been initialized
|
||||
jboolean isCopy{false};
|
||||
|
||||
skyline::span<Point> points(reinterpret_cast<Point *>(env->GetIntArrayElements(pointsJni, &isCopy)),
|
||||
static_cast<size_t>(env->GetArrayLength(pointsJni)) / (sizeof(Point) / sizeof(jint)));
|
||||
skyline::span<Point> points(reinterpret_cast<Point *>(env->GetIntArrayElements(pointsJni, &isCopy)), env->GetArrayLength(pointsJni) / (sizeof(Point) / sizeof(jint)));
|
||||
input->touch.SetState(points);
|
||||
env->ReleaseIntArrayElements(pointsJni, reinterpret_cast<jint *>(points.data()), JNI_ABORT);
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT void JNICALL Java_emu_skyline_settings_NativeSettings_updateNative(JNIEnv *env, jobject) {
|
||||
auto settings{SettingsWeak.lock()};
|
||||
if (!settings)
|
||||
return; // We don't mind if we miss settings updates while settings haven't been initialized
|
||||
settings->Update();
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT void JNICALL Java_emu_skyline_settings_NativeSettings_00024Companion_setLogLevel(JNIEnv *, jobject, jint logLevel) {
|
||||
skyline::Logger::configLevel = static_cast<skyline::Logger::LogLevel>(logLevel);
|
||||
}
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
// SPDX-License-Identifier: MPL-2.0
|
||||
// Copyright © 2020 Skyline Team and Contributors (https://github.com/skyline-emu/)
|
||||
|
||||
#include "skyline/common/logger.h"
|
||||
#include "skyline/crypto/key_store.h"
|
||||
#include "skyline/vfs/nca.h"
|
||||
#include "skyline/vfs/os_backing.h"
|
||||
|
@ -12,14 +11,13 @@
|
|||
#include "skyline/loader/nsp.h"
|
||||
#include "skyline/jvm.h"
|
||||
|
||||
extern "C" JNIEXPORT jint JNICALL Java_emu_skyline_loader_RomFile_populate(JNIEnv *env, jobject thiz, jint jformat, jint fd, jstring appFilesPathJstring, jint systemLanguage) {
|
||||
skyline::signal::ScopedStackBlocker stackBlocker;
|
||||
|
||||
extern "C" JNIEXPORT jint JNICALL Java_emu_skyline_loader_RomFile_populate(JNIEnv *env, jobject thiz, jint jformat, jint fd, jstring appFilesPathJstring) {
|
||||
skyline::loader::RomFormat format{static_cast<skyline::loader::RomFormat>(jformat)};
|
||||
|
||||
skyline::Logger::SetContext(&skyline::Logger::LoaderContext);
|
||||
auto appFilesPath{env->GetStringUTFChars(appFilesPathJstring, nullptr)};
|
||||
auto keyStore{std::make_shared<skyline::crypto::KeyStore>(appFilesPath)};
|
||||
env->ReleaseStringUTFChars(appFilesPathJstring, appFilesPath);
|
||||
|
||||
auto keyStore{std::make_shared<skyline::crypto::KeyStore>(skyline::JniString(env, appFilesPathJstring))};
|
||||
std::unique_ptr<skyline::loader::Loader> loader;
|
||||
try {
|
||||
auto backing{std::make_shared<skyline::vfs::OsBacking>(fd)};
|
||||
|
@ -51,24 +49,16 @@ extern "C" JNIEXPORT jint JNICALL Java_emu_skyline_loader_RomFile_populate(JNIEn
|
|||
|
||||
jclass clazz{env->GetObjectClass(thiz)};
|
||||
jfieldID applicationNameField{env->GetFieldID(clazz, "applicationName", "Ljava/lang/String;")};
|
||||
jfieldID applicationTitleIdField{env->GetFieldID(clazz, "applicationTitleId", "Ljava/lang/String;")};
|
||||
jfieldID applicationAuthorField{env->GetFieldID(clazz, "applicationAuthor", "Ljava/lang/String;")};
|
||||
jfieldID rawIconField{env->GetFieldID(clazz, "rawIcon", "[B")};
|
||||
jfieldID applicationVersionField{env->GetFieldID(clazz, "applicationVersion", "Ljava/lang/String;")};
|
||||
|
||||
if (loader->nacp) {
|
||||
auto language{skyline::language::GetApplicationLanguage(static_cast<skyline::language::SystemLanguage>(systemLanguage))};
|
||||
if (((1 << static_cast<skyline::u32>(language)) & loader->nacp->supportedTitleLanguages) == 0)
|
||||
language = loader->nacp->GetFirstSupportedTitleLanguage();
|
||||
env->SetObjectField(thiz, applicationNameField, env->NewStringUTF(loader->nacp->applicationName.c_str()));
|
||||
env->SetObjectField(thiz, applicationAuthorField, env->NewStringUTF(loader->nacp->applicationPublisher.c_str()));
|
||||
|
||||
env->SetObjectField(thiz, applicationNameField, env->NewStringUTF(loader->nacp->GetApplicationName(language).c_str()));
|
||||
env->SetObjectField(thiz, applicationVersionField, env->NewStringUTF(loader->nacp->GetApplicationVersion().c_str()));
|
||||
env->SetObjectField(thiz, applicationTitleIdField, env->NewStringUTF(loader->nacp->GetSaveDataOwnerId().c_str()));
|
||||
env->SetObjectField(thiz, applicationAuthorField, env->NewStringUTF(loader->nacp->GetApplicationPublisher(language).c_str()));
|
||||
|
||||
auto icon{loader->GetIcon(language)};
|
||||
jbyteArray iconByteArray{env->NewByteArray(static_cast<jsize>(icon.size()))};
|
||||
env->SetByteArrayRegion(iconByteArray, 0, static_cast<jsize>(icon.size()), reinterpret_cast<const jbyte *>(icon.data()));
|
||||
auto icon{loader->GetIcon()};
|
||||
jbyteArray iconByteArray{env->NewByteArray(icon.size())};
|
||||
env->SetByteArrayRegion(iconByteArray, 0, icon.size(), reinterpret_cast<const jbyte *>(icon.data()));
|
||||
env->SetObjectField(thiz, rawIconField, iconByteArray);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,34 +0,0 @@
|
|||
// SPDX-License-Identifier: MPL-2.0
|
||||
// Copyright © 2022 Skyline Team and Contributors (https://github.com/skyline-emu/)
|
||||
|
||||
#include "applet_creator.h"
|
||||
#include "controller_applet.h"
|
||||
#include "error_applet.h"
|
||||
#include "player_select_applet.h"
|
||||
#include "web_applet.h"
|
||||
#include "swkbd/software_keyboard_applet.h"
|
||||
|
||||
namespace skyline::applet {
|
||||
std::shared_ptr<service::am::IApplet> CreateApplet(
|
||||
const DeviceState &state, service::ServiceManager &manager,
|
||||
applet::AppletId appletId, std::shared_ptr<kernel::type::KEvent> onAppletStateChanged,
|
||||
std::shared_ptr<kernel::type::KEvent> onNormalDataPushFromApplet,
|
||||
std::shared_ptr<kernel::type::KEvent> onInteractiveDataPushFromApplet,
|
||||
service::applet::LibraryAppletMode appletMode) {
|
||||
switch (appletId) {
|
||||
case AppletId::LibraryAppletController:
|
||||
return std::make_shared<ControllerApplet>(state, manager, std::move(onAppletStateChanged), std::move(onNormalDataPushFromApplet), std::move(onInteractiveDataPushFromApplet), appletMode);
|
||||
case AppletId::LibraryAppletPlayerSelect:
|
||||
return std::make_shared<PlayerSelectApplet>(state, manager, std::move(onAppletStateChanged), std::move(onNormalDataPushFromApplet), std::move(onInteractiveDataPushFromApplet), appletMode);
|
||||
case AppletId::LibraryAppletSwkbd:
|
||||
return std::make_shared<swkbd::SoftwareKeyboardApplet>(state, manager, std::move(onAppletStateChanged), std::move(onNormalDataPushFromApplet), std::move(onInteractiveDataPushFromApplet), appletMode);
|
||||
case AppletId::LibraryAppletError:
|
||||
return std::make_shared<ErrorApplet>(state, manager, std::move(onAppletStateChanged), std::move(onNormalDataPushFromApplet), std::move(onInteractiveDataPushFromApplet), appletMode);
|
||||
case AppletId::LibraryAppletOfflineWeb:
|
||||
case AppletId::LibraryAppletShop:
|
||||
return std::make_shared<WebApplet>(state, manager, std::move(onAppletStateChanged), std::move(onNormalDataPushFromApplet), std::move(onInteractiveDataPushFromApplet), appletMode);
|
||||
default:
|
||||
throw exception{"Unimplemented Applet: 0x{:X} ({})", static_cast<u32>(appletId), ToString(appletId)};
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,81 +0,0 @@
|
|||
// SPDX-License-Identifier: MPL-2.0
|
||||
// Copyright © 2022 Skyline Team and Contributors (https://github.com/skyline-emu/)
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <common/macros.h>
|
||||
#include <services/am/applet/IApplet.h>
|
||||
#include <services/applet/common_arguments.h>
|
||||
|
||||
namespace skyline::applet {
|
||||
#define APPLETS \
|
||||
APPLET_ENTRY(None, 0x000) \
|
||||
APPLET_ENTRY(Application, 0x001) \
|
||||
APPLET_ENTRY(OverlayApplet, 0x002) \
|
||||
APPLET_ENTRY(SystemAppletMenu, 0x003) \
|
||||
APPLET_ENTRY(SystemApplication, 0x004) \
|
||||
APPLET_ENTRY(LibraryAppletAuth, 0x00A) \
|
||||
APPLET_ENTRY(LibraryAppletCabinet, 0x00B) \
|
||||
APPLET_ENTRY(LibraryAppletController, 0x00C) \
|
||||
APPLET_ENTRY(LibraryAppletDataErase, 0x00D) \
|
||||
APPLET_ENTRY(LibraryAppletError, 0x00E) \
|
||||
APPLET_ENTRY(LibraryAppletNetConnect, 0x00F) \
|
||||
APPLET_ENTRY(LibraryAppletPlayerSelect, 0x010) \
|
||||
APPLET_ENTRY(LibraryAppletSwkbd, 0x011) \
|
||||
APPLET_ENTRY(LibraryAppletMiiEdit, 0x012) \
|
||||
APPLET_ENTRY(LibraryAppletWeb, 0x013) \
|
||||
APPLET_ENTRY(LibraryAppletShop, 0x014) \
|
||||
APPLET_ENTRY(LibraryAppletPhotoViewer, 0x015) \
|
||||
APPLET_ENTRY(LibraryAppletSet, 0x016) \
|
||||
APPLET_ENTRY(LibraryAppletOfflineWeb, 0x017) \
|
||||
APPLET_ENTRY(LibraryAppletLoginShare, 0x018) \
|
||||
APPLET_ENTRY(LibraryAppletWifiWebAuth, 0x019) \
|
||||
APPLET_ENTRY(LibraryAppletMyPage, 0x01A) \
|
||||
APPLET_ENTRY(LibraryAppletGift, 0x01B) \
|
||||
APPLET_ENTRY(LibraryAppletUserMigration, 0x01C) \
|
||||
APPLET_ENTRY(LibraryAppletPreomiaSys, 0x01D) \
|
||||
APPLET_ENTRY(LibraryAppletStory, 0x01E) \
|
||||
APPLET_ENTRY(LibraryAppletPreomiaUsr, 0x01F) \
|
||||
APPLET_ENTRY(LibraryAppletPreomiaUsrDummy, 0x020) \
|
||||
APPLET_ENTRY(LibraryAppletSample, 0x021) \
|
||||
APPLET_ENTRY(DevlopmentTool, 0x3E8) \
|
||||
APPLET_ENTRY(CombinationLA, 0x3F1) \
|
||||
APPLET_ENTRY(AeSystemApplet, 0x3F2) \
|
||||
APPLET_ENTRY(AeOverlayApplet, 0x3F3) \
|
||||
APPLET_ENTRY(AeStarter, 0x3F4) \
|
||||
APPLET_ENTRY(AeLibraryAppletAlone, 0x3F5) \
|
||||
APPLET_ENTRY(AeLibraryApplet1, 0x3F6) \
|
||||
APPLET_ENTRY(AeLibraryApplet2, 0x3F7) \
|
||||
APPLET_ENTRY(AeLibraryApplet3, 0x3F8) \
|
||||
APPLET_ENTRY(AeLibraryApplet4, 0x3F9) \
|
||||
APPLET_ENTRY(AppletISA, 0x3FA) \
|
||||
APPLET_ENTRY(AppletIOA, 0x3FB) \
|
||||
APPLET_ENTRY(AppletISTA, 0x3FC) \
|
||||
APPLET_ENTRY(AppletILA1, 0x3FD) \
|
||||
APPLET_ENTRY(AppletILA2, 0x3FE)
|
||||
|
||||
/**
|
||||
* @url https://switchbrew.org/wiki/Applet_Manager_services#AppletId
|
||||
*/
|
||||
enum class AppletId : u32 {
|
||||
#define APPLET_ENTRY(name, id) name = id,
|
||||
APPLETS
|
||||
#undef APPLET_ENTRY
|
||||
};
|
||||
|
||||
#define APPLET_ENTRY(name, id) ENUM_CASE(name);
|
||||
|
||||
ENUM_STRING(AppletId, APPLETS)
|
||||
|
||||
#undef APPLET_ENTRY
|
||||
|
||||
/**
|
||||
* @brief Creates an Applet of the appropiate class depending on the AppletId
|
||||
*/
|
||||
std::shared_ptr<service::am::IApplet> CreateApplet(
|
||||
const DeviceState &state, service::ServiceManager &manager,
|
||||
applet::AppletId appletId, std::shared_ptr<kernel::type::KEvent> onAppletStateChanged,
|
||||
std::shared_ptr<kernel::type::KEvent> onNormalDataPushFromApplet,
|
||||
std::shared_ptr<kernel::type::KEvent> onInteractiveDataPushFromApplet,
|
||||
service::applet::LibraryAppletMode appletMode);
|
||||
}
|
|
@ -1,114 +0,0 @@
|
|||
// SPDX-License-Identifier: MPL-2.0
|
||||
// Copyright © 2022 Skyline Team and Contributors (https://github.com/skyline-emu/)
|
||||
// Copyright © 2020 yuzu Emulator Project (https://github.com/yuzu-emu/)
|
||||
|
||||
#include <input.h>
|
||||
#include <input/npad.h>
|
||||
#include <services/applet/common_arguments.h>
|
||||
#include <services/am/storage/ObjIStorage.h>
|
||||
#include "controller_applet.h"
|
||||
|
||||
namespace skyline::applet {
|
||||
ControllerApplet::ControllerApplet(const DeviceState &state,
|
||||
service::ServiceManager &manager,
|
||||
std::shared_ptr<kernel::type::KEvent> onAppletStateChanged,
|
||||
std::shared_ptr<kernel::type::KEvent> onNormalDataPushFromApplet,
|
||||
std::shared_ptr<kernel::type::KEvent> onInteractiveDataPushFromApplet,
|
||||
service::applet::LibraryAppletMode appletMode)
|
||||
: IApplet{state, manager, std::move(onAppletStateChanged), std::move(onNormalDataPushFromApplet), std::move(onInteractiveDataPushFromApplet), appletMode} {}
|
||||
|
||||
void ControllerApplet::HandleShowControllerSupport(input::NpadStyleSet styleSet, ControllerAppletVersion version, span<u8> arg) {
|
||||
// Generic macro due to both versions of arguments sharing the same fields but having different layouts
|
||||
auto handle{[&](auto controllerSupportModeArg) {
|
||||
Logger::InfoNoPrefix("Controller Support: "
|
||||
"Player Count: {} - {}, "
|
||||
"Take Over Connection: {}, Left Justify: {}, Dual Joy-Con Allowed: {}, Single Mode Enabled: {}, "
|
||||
"Identification Color Enabled: {}, Explain Text Enabled: {}",
|
||||
controllerSupportModeArg.playerCountMin, controllerSupportModeArg.playerCountMax,
|
||||
controllerSupportModeArg.enableTakeOverConnection, controllerSupportModeArg.enableLeftJustify, controllerSupportModeArg.enablePermitJoyDual, controllerSupportModeArg.enableSingleMode,
|
||||
controllerSupportModeArg.enableIdentificationColor, controllerSupportModeArg.enableExplainText);
|
||||
|
||||
// Here is where we would trigger the applet UI
|
||||
|
||||
auto &npad{state.input->npad};
|
||||
std::scoped_lock lock{npad.mutex};
|
||||
|
||||
PushNormalDataAndSignal(std::make_shared<service::am::ObjIStorage<ControllerSupportResultInfo>>(state, manager, ControllerSupportResultInfo{
|
||||
.playerCount = static_cast<i8>(controllerSupportModeArg.enableSingleMode ? 1 : npad.GetConnectedControllerCount()),
|
||||
.selectedId = [&npad]() {
|
||||
if (npad.controllers[0].device) {
|
||||
return npad.controllers[0].device->id;
|
||||
} else {
|
||||
Logger::Warn("Controller requested but none connected!");
|
||||
return input::NpadId::Player1; // Fallback to player 1
|
||||
}
|
||||
}(),
|
||||
.result = {}
|
||||
}));
|
||||
}};
|
||||
|
||||
switch (version) {
|
||||
case ControllerAppletVersion::Version3:
|
||||
case ControllerAppletVersion::Version4:
|
||||
case ControllerAppletVersion::Version5:
|
||||
handle(arg.as<ControllerSupportArgOld>());
|
||||
break;
|
||||
case ControllerAppletVersion::Version7:
|
||||
case ControllerAppletVersion::Version8:
|
||||
handle(arg.as<ControllerSupportArgNew>());
|
||||
break;
|
||||
default:
|
||||
Logger::Warn("Unsupported controller applet version {}", static_cast<u32>(version));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Result ControllerApplet::Start() {
|
||||
auto commonArg{PopNormalInput<service::applet::CommonArguments>()};
|
||||
ControllerAppletVersion appletVersion{commonArg.apiVersion};
|
||||
|
||||
auto argPrivate{PopNormalInput<ControllerSupportArgPrivate>()};
|
||||
|
||||
// Some games such as Cave Story+ set invalid values for the ControllerSupportMode so use argSize to derive it if necessary (from yuzu)
|
||||
if (argPrivate.mode >= ControllerSupportMode::MaxControllerSupportMode) {
|
||||
switch (argPrivate.argSize) {
|
||||
case sizeof(ControllerSupportArgOld):
|
||||
case sizeof(ControllerSupportArgNew):
|
||||
argPrivate.mode = ControllerSupportMode::ShowControllerSupport;
|
||||
break;
|
||||
default:
|
||||
// TODO: when we support other modes make sure to add them here too
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
std::scoped_lock lock{normalInputDataMutex};
|
||||
switch (argPrivate.mode) {
|
||||
case ControllerSupportMode::ShowControllerSupport:
|
||||
HandleShowControllerSupport(argPrivate.styleSet, appletVersion, normalInputData.front()->GetSpan());
|
||||
normalInputData.pop();
|
||||
break;
|
||||
default:
|
||||
Logger::Warn("Controller applet mode {} is unimplemented", static_cast<u32>(argPrivate.mode));
|
||||
normalInputData.pop();
|
||||
|
||||
// Return empty result
|
||||
PushNormalDataAndSignal(std::make_shared<service::am::ObjIStorage<Result>>(state, manager, Result{}));
|
||||
break;
|
||||
}
|
||||
|
||||
// Notify the guest that we've finished running
|
||||
onAppletStateChanged->Signal();
|
||||
return {};
|
||||
}
|
||||
|
||||
Result ControllerApplet::GetResult() {
|
||||
return {};
|
||||
}
|
||||
|
||||
void ControllerApplet::PushNormalDataToApplet(std::shared_ptr<service::am::IStorage> data) {
|
||||
PushNormalInput(data);
|
||||
}
|
||||
|
||||
void ControllerApplet::PushInteractiveDataToApplet(std::shared_ptr<service::am::IStorage> data) {}
|
||||
}
|
|
@ -1,118 +0,0 @@
|
|||
// SPDX-License-Identifier: MPL-2.0
|
||||
// Copyright © 2022 Skyline Team and Contributors (https://github.com/skyline-emu/)
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <services/am/applet/IApplet.h>
|
||||
#include <services/applet/common_arguments.h>
|
||||
#include <input/npad_device.h>
|
||||
|
||||
namespace skyline::applet {
|
||||
/**
|
||||
* @brief The Controller applet is responsible for notifiying the user of a games controller requirements and for allowing user management og controllers
|
||||
*/
|
||||
class ControllerApplet : public service::am::IApplet, service::am::EnableNormalQueue {
|
||||
private:
|
||||
/**
|
||||
* @brief The version of the controller applet interface that an application supports
|
||||
*/
|
||||
enum class ControllerAppletVersion : u32 {
|
||||
Version3 = 0x3, // 1.0.0 - 2.3.0
|
||||
Version4 = 0x4, // 3.0.0 - 5.1.0
|
||||
Version5 = 0x5, // 6.0.0 - 7.0.1
|
||||
// No version 6
|
||||
Version7 = 0x7, // 8.0.0 - 10.2.0
|
||||
Version8 = 0x8, // 11.0.0+
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief The requested mode of the controller applet, determines the specific UI that should be shown to the user
|
||||
*/
|
||||
enum class ControllerSupportMode : u8 {
|
||||
ShowControllerSupport = 0,
|
||||
ShowControllerStrapGuide = 1,
|
||||
ShowControllerFirmwareUpdate = 2,
|
||||
ShowControllerKeyRemappingForSystem = 3,
|
||||
|
||||
MaxControllerSupportMode
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief The caller that is requesting the controller applet
|
||||
*/
|
||||
enum class ControllerSupportCaller : u8 {
|
||||
Application = 1,
|
||||
System = 2
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Common set of arguments supplied for all controller applet invocations
|
||||
*/
|
||||
struct ControllerSupportArgPrivate {
|
||||
u32 argPrivateSize;
|
||||
u32 argSize;
|
||||
bool flag0;
|
||||
bool flag1;
|
||||
ControllerSupportMode mode;
|
||||
ControllerSupportCaller caller;
|
||||
input::NpadStyleSet styleSet;
|
||||
u32 joyHoldType;
|
||||
};
|
||||
static_assert(sizeof(ControllerSupportArgPrivate) == 0x14);
|
||||
|
||||
/**
|
||||
* @brief Set of arguments required for the ShowControllerSupport mode, templated since the number of controller supported varies based on applet version
|
||||
*/
|
||||
template<u8 NumControllersSupported>
|
||||
struct ControllerSupportArg {
|
||||
using IdentificationColor = std::array<u8, 4>; // RGBA colour code
|
||||
using ExplainText = std::array<char, 128 + 1>; // 128 chars + null terminator
|
||||
|
||||
i8 playerCountMin{};
|
||||
i8 playerCountMax{};
|
||||
bool enableTakeOverConnection{};
|
||||
bool enableLeftJustify{};
|
||||
bool enablePermitJoyDual{};
|
||||
bool enableSingleMode{};
|
||||
bool enableIdentificationColor{};
|
||||
std::array<IdentificationColor, NumControllersSupported> identification_colors{};
|
||||
bool enableExplainText{};
|
||||
std::array<ExplainText, NumControllersSupported> explain_text{};
|
||||
};
|
||||
|
||||
// Applet versions 3-5 inclusive allow 4 controllers maximum
|
||||
using ControllerSupportArgOld = ControllerSupportArg<4>;
|
||||
static_assert(sizeof(ControllerSupportArgOld) == 0x21C);
|
||||
|
||||
// Applet versions 6-8 allow 8 controllers maximum
|
||||
using ControllerSupportArgNew = ControllerSupportArg<8>;
|
||||
static_assert(sizeof(ControllerSupportArgNew) == 0x430);
|
||||
|
||||
/**
|
||||
* @brief The result type of the controller applet controller support mode
|
||||
*/
|
||||
struct ControllerSupportResultInfo {
|
||||
i8 playerCount;
|
||||
u8 _pad_[3];
|
||||
input::NpadId selectedId;
|
||||
Result result;
|
||||
};
|
||||
static_assert(sizeof(ControllerSupportResultInfo) == 0xC);
|
||||
|
||||
/**
|
||||
* @brief Handles the 'ShowControllerSupport' mode of the controller applet
|
||||
*/
|
||||
void HandleShowControllerSupport(input::NpadStyleSet styleSet, ControllerAppletVersion version, span<u8> arg);
|
||||
|
||||
public:
|
||||
ControllerApplet(const DeviceState &state, service::ServiceManager &manager, std::shared_ptr<kernel::type::KEvent> onAppletStateChanged, std::shared_ptr<kernel::type::KEvent> onNormalDataPushFromApplet, std::shared_ptr<kernel::type::KEvent> onInteractiveDataPushFromApplet, service::applet::LibraryAppletMode appletMode);
|
||||
|
||||
Result Start() override;
|
||||
|
||||
Result GetResult() override;
|
||||
|
||||
void PushNormalDataToApplet(std::shared_ptr<service::am::IStorage> data) override;
|
||||
|
||||
void PushInteractiveDataToApplet(std::shared_ptr<service::am::IStorage> data) override;
|
||||
};
|
||||
}
|
|
@ -1,63 +0,0 @@
|
|||
// SPDX-License-Identifier: MPL-2.0
|
||||
// Copyright © 2022 Skyline Team and Contributors (https://github.com/skyline-emu/)
|
||||
|
||||
#include "error_applet.h"
|
||||
#include "services/am/storage/ObjIStorage.h"
|
||||
|
||||
namespace skyline::applet {
|
||||
ErrorApplet::ErrorApplet(const DeviceState &state,
|
||||
service::ServiceManager &manager,
|
||||
std::shared_ptr<kernel::type::KEvent> onAppletStateChanged,
|
||||
std::shared_ptr<kernel::type::KEvent> onNormalDataPushFromApplet,
|
||||
std::shared_ptr<kernel::type::KEvent> onInteractiveDataPushFromApplet,
|
||||
service::applet::LibraryAppletMode appletMode)
|
||||
: IApplet{state, manager, std::move(onAppletStateChanged), std::move(onNormalDataPushFromApplet), std::move(onInteractiveDataPushFromApplet), appletMode} {}
|
||||
|
||||
Result ErrorApplet::Start() {
|
||||
auto commonArg{PopNormalInput<service::applet::CommonArguments>()};
|
||||
|
||||
errorStorage = PopNormalInput();
|
||||
auto errorCommonHeader{errorStorage->GetSpan().as<ErrorCommonHeader>()};
|
||||
Logger::Debug("ErrorApplet: version: 0x{:X}, type: 0x{:X}", commonArg.apiVersion, errorCommonHeader.type);
|
||||
|
||||
switch (errorCommonHeader.type) {
|
||||
case ErrorType::ErrorCommonArg:
|
||||
HandleErrorCommonArg();
|
||||
break;
|
||||
case ErrorType::ApplicationErrorArg:
|
||||
HandleApplicationErrorArg();
|
||||
break;
|
||||
default:
|
||||
throw exception("ErrorApplet type 0x{:X} is not implemented", errorCommonHeader.type);
|
||||
}
|
||||
|
||||
// Notify the guest that we've finished running
|
||||
onAppletStateChanged->Signal();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
void ErrorApplet::HandleErrorCommonArg() {
|
||||
auto errorCommonArg{errorStorage->GetSpan().as<ErrorCommonArg>()};
|
||||
Logger::Error("ErrorApplet: error code: 0x{:X}, result: 0x{:X}", errorCommonArg.errorCode, errorCommonArg.result);
|
||||
}
|
||||
|
||||
void ErrorApplet::HandleApplicationErrorArg() {
|
||||
auto applicationErrorStorage{errorStorage->GetSpan().as<ApplicationErrorArg>()};
|
||||
|
||||
if (applicationErrorStorage.fullscreenMessage[0] == '\0')
|
||||
Logger::ErrorNoPrefix("Application Error: {}", applicationErrorStorage.dialogMessage.data());
|
||||
else
|
||||
Logger::ErrorNoPrefix("Application Error: {}\nFull message: {}", applicationErrorStorage.dialogMessage.data(), applicationErrorStorage.fullscreenMessage.data());
|
||||
}
|
||||
|
||||
Result ErrorApplet::GetResult() {
|
||||
return {};
|
||||
}
|
||||
|
||||
void ErrorApplet::PushNormalDataToApplet(std::shared_ptr<service::am::IStorage> data) {
|
||||
PushNormalInput(data);
|
||||
}
|
||||
|
||||
void ErrorApplet::PushInteractiveDataToApplet(std::shared_ptr<service::am::IStorage> data) {}
|
||||
}
|
|
@ -1,81 +0,0 @@
|
|||
// SPDX-License-Identifier: MPL-2.0
|
||||
// Copyright © 2022 Skyline Team and Contributors (https://github.com/skyline-emu/)
|
||||
// Copyright © 2020 Ryujinx Team and Contributors (https://github.com/ryujinx/)
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <services/am/applet/IApplet.h>
|
||||
#include "common/language.h"
|
||||
|
||||
namespace skyline::applet {
|
||||
/**
|
||||
* @brief The Error Applet is utilized by the guest to display an error to the user, this class prints the supplied error to the logger
|
||||
* @url https://switchbrew.org/wiki/Error_Applet
|
||||
* @url https://switchbrew.org/wiki/Error_applet
|
||||
*/
|
||||
class ErrorApplet : public service::am::IApplet, service::am::EnableNormalQueue {
|
||||
private:
|
||||
|
||||
#pragma pack(push, 1)
|
||||
|
||||
enum class ErrorType : u8 {
|
||||
ErrorCommonArg = 0,
|
||||
SystemErrorArg = 1,
|
||||
ApplicationErrorArg = 2,
|
||||
ErrorEulaArg = 3,
|
||||
ErrorPctlArg = 4,
|
||||
ErrorRecordArg = 5,
|
||||
SystemUpdateEulaArg = 8
|
||||
};
|
||||
|
||||
/**
|
||||
* @url https://switchbrew.org/wiki/Error_Applet#ErrorCommonHeader
|
||||
*/
|
||||
struct ErrorCommonHeader {
|
||||
ErrorType type;
|
||||
u8 jump;
|
||||
u8 _pad_[0x3];
|
||||
u8 contextFlag;
|
||||
u8 resultFlag;
|
||||
u8 contextFlag2;
|
||||
};
|
||||
static_assert(sizeof(ErrorCommonHeader) == 0x8);
|
||||
|
||||
/**
|
||||
* @url https://switchbrew.org/wiki/Error_Applet#ErrorCommonArg
|
||||
*/
|
||||
struct ErrorCommonArg {
|
||||
ErrorCommonHeader header;
|
||||
u64 errorCode;
|
||||
Result result;
|
||||
};
|
||||
|
||||
struct ApplicationErrorArg {
|
||||
ErrorCommonHeader commonHeader;
|
||||
u32 errorNumber;
|
||||
LanguageCode languageCode;
|
||||
std::array<char, 0x800> dialogMessage;
|
||||
std::array<char, 0x800> fullscreenMessage; //!< The message displayed when the user clicks on "Details", when not set this disables displaying Details
|
||||
};
|
||||
static_assert(sizeof(ApplicationErrorArg) == 0x1014);
|
||||
|
||||
#pragma pack(pop)
|
||||
|
||||
std::shared_ptr<service::am::IStorage> errorStorage;
|
||||
|
||||
void HandleErrorCommonArg();
|
||||
|
||||
void HandleApplicationErrorArg();
|
||||
|
||||
public:
|
||||
ErrorApplet(const DeviceState &state, service::ServiceManager &manager, std::shared_ptr<kernel::type::KEvent> onAppletStateChanged, std::shared_ptr<kernel::type::KEvent> onNormalDataPushFromApplet, std::shared_ptr<kernel::type::KEvent> onInteractiveDataPushFromApplet, service::applet::LibraryAppletMode appletMode);
|
||||
|
||||
Result Start() override;
|
||||
|
||||
Result GetResult() override;
|
||||
|
||||
void PushNormalDataToApplet(std::shared_ptr<service::am::IStorage> data) override;
|
||||
|
||||
void PushInteractiveDataToApplet(std::shared_ptr<service::am::IStorage> data) override;
|
||||
};
|
||||
}
|
|
@ -1,32 +0,0 @@
|
|||
// SPDX-License-Identifier: MPL-2.0
|
||||
// Copyright © 2022 Skyline Team and Contributors (https://github.com/skyline-emu/)
|
||||
|
||||
#include <services/am/storage/ObjIStorage.h>
|
||||
#include "player_select_applet.h"
|
||||
|
||||
namespace skyline::applet {
|
||||
PlayerSelectApplet::PlayerSelectApplet(const DeviceState &state,
|
||||
service::ServiceManager &manager,
|
||||
std::shared_ptr<kernel::type::KEvent> onAppletStateChanged,
|
||||
std::shared_ptr<kernel::type::KEvent> onNormalDataPushFromApplet,
|
||||
std::shared_ptr<kernel::type::KEvent> onInteractiveDataPushFromApplet,
|
||||
service::applet::LibraryAppletMode appletMode)
|
||||
: IApplet{state, manager, std::move(onAppletStateChanged), std::move(onNormalDataPushFromApplet), std::move(onInteractiveDataPushFromApplet), appletMode} {}
|
||||
|
||||
Result PlayerSelectApplet::Start() {
|
||||
// Return default user
|
||||
PushNormalDataAndSignal(std::make_shared<service::am::ObjIStorage<AccountResult>>(state, manager, AccountResult{}));
|
||||
|
||||
// Notify the guest that we've finished running
|
||||
onAppletStateChanged->Signal();
|
||||
return {};
|
||||
};
|
||||
|
||||
Result PlayerSelectApplet::GetResult() {
|
||||
return {};
|
||||
}
|
||||
|
||||
void PlayerSelectApplet::PushNormalDataToApplet(std::shared_ptr<service::am::IStorage> data) {}
|
||||
|
||||
void PlayerSelectApplet::PushInteractiveDataToApplet(std::shared_ptr<service::am::IStorage> data) {}
|
||||
}
|
|
@ -1,37 +0,0 @@
|
|||
// SPDX-License-Identifier: MPL-2.0
|
||||
// Copyright © 2022 Skyline Team and Contributors (https://github.com/skyline-emu/)
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <common/uuid.h>
|
||||
#include <services/account/IAccountServiceForApplication.h>
|
||||
#include <services/am/applet/IApplet.h>
|
||||
|
||||
namespace skyline::applet {
|
||||
/**
|
||||
* @brief The player select applet is responsible for allowing the user to select a player to use with the application
|
||||
*/
|
||||
class PlayerSelectApplet : public service::am::IApplet {
|
||||
private:
|
||||
/**
|
||||
* @brief Result structure for the player select applet
|
||||
*/
|
||||
struct AccountResult {
|
||||
Result result{};
|
||||
u32 _pad_;
|
||||
service::account::UserId accountId{constant::DefaultUserId};
|
||||
};
|
||||
static_assert(sizeof(AccountResult) == 0x18);
|
||||
|
||||
public:
|
||||
PlayerSelectApplet(const DeviceState &state, service::ServiceManager &manager, std::shared_ptr<kernel::type::KEvent> onAppletStateChanged, std::shared_ptr<kernel::type::KEvent> onNormalDataPushFromApplet, std::shared_ptr<kernel::type::KEvent> onInteractiveDataPushFromApplet, service::applet::LibraryAppletMode appletMode);
|
||||
|
||||
Result Start() override;
|
||||
|
||||
Result GetResult() override;
|
||||
|
||||
void PushNormalDataToApplet(std::shared_ptr<service::am::IStorage> data) override;
|
||||
|
||||
void PushInteractiveDataToApplet(std::shared_ptr<service::am::IStorage> data) override;
|
||||
};
|
||||
}
|
|
@ -1,182 +0,0 @@
|
|||
// SPDX-License-Identifier: MPL-2.0
|
||||
// Copyright © 2022 Skyline Team and Contributors (https://github.com/skyline-emu/)
|
||||
// Copyright © 2019-2022 Ryujinx Team and Contributors
|
||||
|
||||
#include <codecvt>
|
||||
#include <services/am/storage/ObjIStorage.h>
|
||||
#include <common/settings.h>
|
||||
#include "software_keyboard_applet.h"
|
||||
#include <jvm.h>
|
||||
|
||||
class Utf8Utf16Converter : public std::codecvt<char16_t, char8_t, std::mbstate_t> {
|
||||
public:
|
||||
~Utf8Utf16Converter() override = default;
|
||||
};
|
||||
|
||||
namespace skyline::applet::swkbd {
|
||||
static void WriteStringToSpan(span<u8> chars, std::u16string_view text, bool useUtf8Storage) {
|
||||
if (useUtf8Storage) {
|
||||
auto u8chars{chars.cast<char8_t>()};
|
||||
Utf8Utf16Converter::state_type convert_state;
|
||||
const char16_t *from_next;
|
||||
char8_t *to_next;
|
||||
Utf8Utf16Converter().out(convert_state, text.data(), text.end(), from_next, u8chars.data(), u8chars.end().base(), to_next);
|
||||
// Null terminate the string, if it isn't out of bounds
|
||||
if (to_next < reinterpret_cast<const char8_t *>(text.end()))
|
||||
*to_next = u8'\0';
|
||||
} else {
|
||||
std::memcpy(chars.data(), text.data(), std::min(text.size() * sizeof(char16_t), chars.size()));
|
||||
// Null terminate the string, if it isn't out of bounds
|
||||
if (text.size() * sizeof(char16_t) < chars.size())
|
||||
*(reinterpret_cast<char16_t *>(chars.data()) + text.size()) = u'\0';
|
||||
}
|
||||
}
|
||||
|
||||
SoftwareKeyboardApplet::ValidationRequest::ValidationRequest(std::u16string_view text, bool useUtf8Storage) : size{sizeof(ValidationRequest)} {
|
||||
WriteStringToSpan(chars, text, useUtf8Storage);
|
||||
}
|
||||
|
||||
SoftwareKeyboardApplet::OutputResult::OutputResult(CloseResult closeResult, std::u16string_view text, bool useUtf8Storage) : closeResult{closeResult} {
|
||||
WriteStringToSpan(chars, text, useUtf8Storage);
|
||||
}
|
||||
|
||||
static std::u16string FillDefaultText(u32 minLength, u32 maxLength) {
|
||||
std::u16string text{u"Skyline"};
|
||||
while (text.size() < minLength)
|
||||
text += u"Emulator" + text;
|
||||
if (text.size() > maxLength)
|
||||
text.resize(maxLength);
|
||||
return text;
|
||||
}
|
||||
|
||||
void SoftwareKeyboardApplet::SendResult() {
|
||||
if (dialog)
|
||||
state.jvm->CloseKeyboard(dialog);
|
||||
PushNormalDataAndSignal(std::make_shared<service::am::ObjIStorage<OutputResult>>(state, manager, OutputResult{currentResult, currentText, config.commonConfig.isUseUtf8}));
|
||||
onAppletStateChanged->Signal();
|
||||
}
|
||||
|
||||
SoftwareKeyboardApplet::SoftwareKeyboardApplet(
|
||||
const DeviceState &state,
|
||||
service::ServiceManager &manager,
|
||||
std::shared_ptr<kernel::type::KEvent> onAppletStateChanged,
|
||||
std::shared_ptr<kernel::type::KEvent> onNormalDataPushFromApplet,
|
||||
std::shared_ptr<kernel::type::KEvent> onInteractiveDataPushFromApplet,
|
||||
service::applet::LibraryAppletMode appletMode)
|
||||
: IApplet{state,
|
||||
manager,
|
||||
std::move(onAppletStateChanged),
|
||||
std::move(onNormalDataPushFromApplet),
|
||||
std::move(onInteractiveDataPushFromApplet),
|
||||
appletMode}, mode{appletMode} {
|
||||
}
|
||||
|
||||
Result SoftwareKeyboardApplet::Start() {
|
||||
if (mode != service::applet::LibraryAppletMode::AllForeground) {
|
||||
Logger::Warn("Stubbing out InlineKeyboard!");
|
||||
SendResult();
|
||||
return {};
|
||||
}
|
||||
|
||||
std::scoped_lock lock{normalInputDataMutex};
|
||||
auto commonArgs{normalInputData.front()->GetSpan().as<service::applet::CommonArguments>()};
|
||||
normalInputData.pop();
|
||||
|
||||
auto configSpan{normalInputData.front()->GetSpan()};
|
||||
normalInputData.pop();
|
||||
config = [&] {
|
||||
if (commonArgs.apiVersion < 0x30007)
|
||||
return KeyboardConfigVB{configSpan.as<KeyboardConfigV0>()};
|
||||
else if (commonArgs.apiVersion < 0x6000B)
|
||||
return KeyboardConfigVB{configSpan.as<KeyboardConfigV7>()};
|
||||
else
|
||||
return configSpan.as<KeyboardConfigVB>();
|
||||
}();
|
||||
Logger::Debug("Swkbd Config:\n* KeyboardMode: {}\n* InvalidCharFlags: {:#09b}\n* TextMaxLength: {}\n* TextMinLength: {}\n* PasswordMode: {}\n* InputFormMode: {}\n* IsUseNewLine: {}\n* IsUseTextCheck: {}",
|
||||
static_cast<u32>(config.commonConfig.keyboardMode),
|
||||
config.commonConfig.invalidCharFlags.raw,
|
||||
config.commonConfig.textMaxLength,
|
||||
config.commonConfig.textMinLength,
|
||||
static_cast<u32>(config.commonConfig.passwordMode),
|
||||
static_cast<u32>(config.commonConfig.inputFormMode),
|
||||
config.commonConfig.isUseNewLine,
|
||||
config.commonConfig.isUseTextCheck
|
||||
);
|
||||
|
||||
auto maxChars{static_cast<u32>(SwkbdTextBytes / (config.commonConfig.isUseUtf8 ? sizeof(char8_t) : sizeof(char16_t)))};
|
||||
config.commonConfig.textMaxLength = std::min(config.commonConfig.textMaxLength, maxChars);
|
||||
if (config.commonConfig.textMaxLength == 0)
|
||||
config.commonConfig.textMaxLength = maxChars;
|
||||
config.commonConfig.textMinLength = std::min(config.commonConfig.textMinLength, config.commonConfig.textMaxLength);
|
||||
|
||||
if (config.commonConfig.textMaxLength > MaxOneLineChars)
|
||||
config.commonConfig.inputFormMode = InputFormMode::MultiLine;
|
||||
|
||||
if (!normalInputData.empty() && config.commonConfig.initialStringLength > 0)
|
||||
currentText = std::u16string(normalInputData.front()->GetSpan().subspan(config.commonConfig.initialStringOffset).cast<char16_t>().data(), config.commonConfig.initialStringLength);
|
||||
|
||||
dialog = state.jvm->ShowKeyboard(*reinterpret_cast<JvmManager::KeyboardConfig *>(&config), currentText);
|
||||
if (!dialog) {
|
||||
Logger::Warn("Couldn't show keyboard dialog, using default text");
|
||||
currentResult = CloseResult::Enter;
|
||||
currentText = FillDefaultText(config.commonConfig.textMinLength, config.commonConfig.textMaxLength);
|
||||
} else {
|
||||
auto result{state.jvm->WaitForSubmitOrCancel(dialog)};
|
||||
currentResult = static_cast<CloseResult>(result.first);
|
||||
currentText = result.second;
|
||||
}
|
||||
if (config.commonConfig.isUseTextCheck && currentResult == CloseResult::Enter) {
|
||||
PushInteractiveDataAndSignal(std::make_shared<service::am::ObjIStorage<ValidationRequest>>(state, manager, ValidationRequest{currentText, config.commonConfig.isUseUtf8}));
|
||||
validationPending = true;
|
||||
} else {
|
||||
SendResult();
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
Result SoftwareKeyboardApplet::GetResult() {
|
||||
return {};
|
||||
}
|
||||
|
||||
void SoftwareKeyboardApplet::PushNormalDataToApplet(std::shared_ptr<service::am::IStorage> data) {
|
||||
PushNormalInput(data);
|
||||
}
|
||||
|
||||
void SoftwareKeyboardApplet::PushInteractiveDataToApplet(std::shared_ptr<service::am::IStorage> data) {
|
||||
if (validationPending) {
|
||||
auto dataSpan{data->GetSpan()};
|
||||
auto validationResult{dataSpan.as<ValidationResult>()};
|
||||
if (validationResult.result == TextCheckResult::Success) {
|
||||
validationPending = false;
|
||||
SendResult();
|
||||
} else {
|
||||
if (dialog) {
|
||||
if (static_cast<CloseResult>(state.jvm->ShowValidationResult(dialog, static_cast<JvmManager::KeyboardTextCheckResult>(validationResult.result), std::u16string(validationResult.chars.data()))) == CloseResult::Enter) {
|
||||
// Accepted on confirmation dialog
|
||||
validationPending = false;
|
||||
SendResult();
|
||||
} else {
|
||||
// Cancelled or failed validation, go back to waiting for text
|
||||
auto result{state.jvm->WaitForSubmitOrCancel(dialog)};
|
||||
currentResult = static_cast<CloseResult>(result.first);
|
||||
currentText = result.second;
|
||||
if (currentResult == CloseResult::Enter) {
|
||||
PushInteractiveDataAndSignal(std::make_shared<service::am::ObjIStorage<ValidationRequest>>(state, manager, ValidationRequest{currentText, config.commonConfig.isUseUtf8}));
|
||||
} else {
|
||||
SendResult();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
std::array<u8, SwkbdTextBytes> chars{};
|
||||
WriteStringToSpan(chars, std::u16string(validationResult.chars.data()), true);
|
||||
std::string message{reinterpret_cast<char *>(chars.data())};
|
||||
if (validationResult.result == TextCheckResult::ShowFailureDialog)
|
||||
Logger::Warn("Sending default text despite being rejected by the guest with message: \"{}\"", message);
|
||||
else
|
||||
Logger::Debug("Guest asked to confirm default text with message: \"{}\"", message);
|
||||
PushNormalDataAndSignal(std::make_shared<service::am::ObjIStorage<OutputResult>>(state, manager, OutputResult{CloseResult::Enter, currentText, config.commonConfig.isUseUtf8}));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,97 +0,0 @@
|
|||
// SPDX-License-Identifier: MPL-2.0
|
||||
// Copyright © 2022 Skyline Team and Contributors (https://github.com/skyline-emu/)
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <services/am/applet/IApplet.h>
|
||||
#include <services/applet/common_arguments.h>
|
||||
#include <jvm.h>
|
||||
#include "software_keyboard_config.h"
|
||||
|
||||
namespace skyline::applet::swkbd {
|
||||
static_assert(sizeof(KeyboardConfigVB) == sizeof(JvmManager::KeyboardConfig));
|
||||
|
||||
/**
|
||||
* @url https://switchbrew.org/wiki/Software_Keyboard
|
||||
* @brief An implementation for the Software Keyboard (swkbd) Applet which handles translating guest applet transactions to the appropriate host behavior
|
||||
*/
|
||||
class SoftwareKeyboardApplet : public service::am::IApplet, service::am::EnableNormalQueue {
|
||||
private:
|
||||
/**
|
||||
* @url https://switchbrew.org/wiki/Software_Keyboard#CloseResult
|
||||
*/
|
||||
enum class CloseResult : u32 {
|
||||
Enter = 0x0,
|
||||
Cancel = 0x1,
|
||||
};
|
||||
|
||||
/**
|
||||
* @url https://switchbrew.org/wiki/Software_Keyboard#TextCheckResult
|
||||
*/
|
||||
enum class TextCheckResult : u32 {
|
||||
Success = 0x0,
|
||||
ShowFailureDialog = 0x1,
|
||||
ShowConfirmDialog = 0x2,
|
||||
};
|
||||
|
||||
static constexpr u32 SwkbdTextBytes{0x7D4}; //!< Size of the returned IStorage buffer that's used to return the input text
|
||||
|
||||
static constexpr u32 MaxOneLineChars{32}; //!< The maximum number of characters for which anything other than InputFormMode::MultiLine is used
|
||||
|
||||
#pragma pack(push, 1)
|
||||
|
||||
/**
|
||||
* @brief The final result after the swkbd has closed
|
||||
*/
|
||||
struct OutputResult {
|
||||
CloseResult closeResult;
|
||||
std::array<u8, SwkbdTextBytes> chars{};
|
||||
|
||||
OutputResult(CloseResult closeResult, std::u16string_view text, bool useUtf8Storage);
|
||||
};
|
||||
static_assert(sizeof(OutputResult) == 0x7D8);
|
||||
|
||||
/**
|
||||
* @brief A request for validating a string inside guest code, this is pushed via the interactive queue
|
||||
*/
|
||||
struct ValidationRequest {
|
||||
u64 size;
|
||||
std::array<u8, SwkbdTextBytes> chars{};
|
||||
|
||||
ValidationRequest(std::u16string_view text, bool useUtf8Storage);
|
||||
};
|
||||
static_assert(sizeof(ValidationRequest) == 0x7DC);
|
||||
|
||||
/**
|
||||
* @brief The result of validating text submitted to the guest
|
||||
*/
|
||||
struct ValidationResult {
|
||||
TextCheckResult result;
|
||||
std::array<char16_t, SwkbdTextBytes / sizeof(char16_t)> chars;
|
||||
};
|
||||
static_assert(sizeof(ValidationResult) == 0x7D8);
|
||||
|
||||
#pragma pack(pop)
|
||||
|
||||
KeyboardConfigVB config{};
|
||||
service::applet::LibraryAppletMode mode{};
|
||||
bool validationPending{};
|
||||
std::u16string currentText{};
|
||||
CloseResult currentResult{};
|
||||
|
||||
jobject dialog{};
|
||||
|
||||
void SendResult();
|
||||
|
||||
public:
|
||||
SoftwareKeyboardApplet(const DeviceState &state, service::ServiceManager &manager, std::shared_ptr<kernel::type::KEvent> onAppletStateChanged, std::shared_ptr<kernel::type::KEvent> onNormalDataPushFromApplet, std::shared_ptr<kernel::type::KEvent> onInteractiveDataPushFromApplet, service::applet::LibraryAppletMode appletMode);
|
||||
|
||||
Result Start() override;
|
||||
|
||||
Result GetResult() override;
|
||||
|
||||
void PushNormalDataToApplet(std::shared_ptr<service::am::IStorage> data) override;
|
||||
|
||||
void PushInteractiveDataToApplet(std::shared_ptr<service::am::IStorage> data) override;
|
||||
};
|
||||
}
|
|
@ -1,13 +0,0 @@
|
|||
// SPDX-License-Identifier: MPL-2.0
|
||||
// Copyright © 2022 Skyline Team and Contributors (https://github.com/skyline-emu/)
|
||||
// Copyright © 2019-2022 Ryujinx Team and Contributors
|
||||
|
||||
#include "software_keyboard_config.h"
|
||||
|
||||
namespace skyline::applet::swkbd {
|
||||
KeyboardConfigVB::KeyboardConfigVB() = default;
|
||||
|
||||
KeyboardConfigVB::KeyboardConfigVB(const KeyboardConfigV7 &v7config) : commonConfig{v7config.commonConfig}, separateTextPos{v7config.separateTextPos} {}
|
||||
|
||||
KeyboardConfigVB::KeyboardConfigVB(const KeyboardConfigV0 &v0config) : commonConfig{v0config.commonConfig} {}
|
||||
}
|
|
@ -1,187 +0,0 @@
|
|||
// SPDX-License-Identifier: MPL-2.0
|
||||
// Copyright © 2022 Skyline Team and Contributors (https://github.com/skyline-emu/)
|
||||
// Copyright © 2019-2022 Ryujinx Team and Contributors
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <services/account/IAccountServiceForApplication.h>
|
||||
|
||||
namespace skyline::applet::swkbd {
|
||||
/**
|
||||
* @brief Specifies the characters the keyboard should allow you to input
|
||||
* @url https://switchbrew.org/wiki/Software_Keyboard#KeyboardMode
|
||||
*/
|
||||
enum class KeyboardMode : u32 {
|
||||
Full = 0x0,
|
||||
Numeric = 0x1,
|
||||
ASCII = 0x2,
|
||||
FullLatin = 0x3,
|
||||
Alphabet = 0x4,
|
||||
SimplifiedChinese = 0x5,
|
||||
TraditionalChinese = 0x6,
|
||||
Korean = 0x7,
|
||||
LanguageSet2 = 0x8,
|
||||
LanguageSet2Latin = 0x9,
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Specifies the characters that you shouldn't be allowed to input
|
||||
* @url https://switchbrew.org/wiki/Software_Keyboard#InvalidCharFlags
|
||||
*/
|
||||
union InvalidCharFlags {
|
||||
u32 raw;
|
||||
struct {
|
||||
u32 _pad_ : 1;
|
||||
u32 space : 1;
|
||||
u32 atMark : 1;
|
||||
u32 percent : 1;
|
||||
u32 slash : 1;
|
||||
u32 backslash : 1;
|
||||
u32 numeric : 1;
|
||||
u32 outsideOfDownloadCode : 1;
|
||||
u32 outsideOfMiiNickName : 1;
|
||||
} flags;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Specifies where the cursor should initially be on the initial string
|
||||
* @url https://switchbrew.org/wiki/Software_Keyboard#InitialCursorPos
|
||||
*/
|
||||
enum class InitialCursorPos : u32 {
|
||||
First = 0x0,
|
||||
Last = 0x1,
|
||||
};
|
||||
|
||||
/**
|
||||
* @url https://switchbrew.org/wiki/Software_Keyboard#PasswordMode
|
||||
*/
|
||||
enum class PasswordMode : u32 {
|
||||
Show = 0x0,
|
||||
Hide = 0x1, //!< Hides any inputted text to prevent a password from being leaked
|
||||
};
|
||||
|
||||
/**
|
||||
* @url https://switchbrew.org/wiki/Software_Keyboard#InputFormMode
|
||||
* @note Only applies when 1 <= textMaxLength <= 32, otherwise Multiline is used
|
||||
*/
|
||||
enum class InputFormMode : u32 {
|
||||
OneLine = 0x0,
|
||||
MultiLine = 0x1,
|
||||
Separate = 0x2, //!< Used with separateTextPos
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Specifies the language of custom dictionary entries
|
||||
* @url https://switchbrew.org/wiki/Software_Keyboard#DictionaryLanguage
|
||||
*/
|
||||
enum class DictionaryLanguage : u16 {
|
||||
Japanese = 0x00,
|
||||
AmericanEnglish = 0x01,
|
||||
CanadianFrench = 0x02,
|
||||
LatinAmericanSpanish = 0x03,
|
||||
Reserved1 = 0x04,
|
||||
BritishEnglish = 0x05,
|
||||
French = 0x06,
|
||||
German = 0x07,
|
||||
Spanish = 0x08,
|
||||
Italian = 0x09,
|
||||
Dutch = 0x0A,
|
||||
Portuguese = 0x0B,
|
||||
Russian = 0x0C,
|
||||
Reserved2 = 0x0D,
|
||||
SimplifiedChinesePinyin = 0x0E,
|
||||
TraditionalChineseCangjie = 0x0F,
|
||||
TraditionalChineseSimplifiedCangjie = 0x10,
|
||||
TraditionalChineseZhuyin = 0x11,
|
||||
Korean = 0x12,
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief A descriptor of a custom dictionary entry
|
||||
* @url https://switchbrew.org/wiki/Software_Keyboard#DictionaryInfo
|
||||
*/
|
||||
struct DictionaryInfo {
|
||||
u32 offset;
|
||||
u16 size;
|
||||
DictionaryLanguage language;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief The keyboard config that's common across all versions
|
||||
* @url https://switchbrew.org/wiki/Software_Keyboard#KeyboardConfig
|
||||
*/
|
||||
struct CommonKeyboardConfig {
|
||||
KeyboardMode keyboardMode;
|
||||
std::array<char16_t, 0x9> okText;
|
||||
char16_t leftOptionalSymbolKey;
|
||||
char16_t rightOptionalSymbolKey;
|
||||
bool isPredictionEnabled;
|
||||
u8 _pad0_;
|
||||
InvalidCharFlags invalidCharFlags;
|
||||
InitialCursorPos initialCursorPos;
|
||||
std::array<char16_t, 0x41> headerText;
|
||||
std::array<char16_t, 0x81> subText;
|
||||
std::array<char16_t, 0x101> guideText;
|
||||
u8 _pad2_[0x2];
|
||||
u32 textMaxLength;
|
||||
u32 textMinLength;
|
||||
PasswordMode passwordMode;
|
||||
InputFormMode inputFormMode;
|
||||
bool isUseNewLine;
|
||||
bool isUseUtf8;
|
||||
bool isUseBlurBackground;
|
||||
u8 _pad3_;
|
||||
u32 initialStringOffset;
|
||||
u32 initialStringLength;
|
||||
u32 userDictionaryOffset;
|
||||
u32 userDictionaryNum;
|
||||
bool isUseTextCheck;
|
||||
u8 reserved[0x3];
|
||||
};
|
||||
static_assert(sizeof(CommonKeyboardConfig) == 0x3D4);
|
||||
|
||||
/**
|
||||
* @brief The keyboard config for the first api version
|
||||
* @url https://switchbrew.org/wiki/Software_Keyboard#KeyboardConfig
|
||||
*/
|
||||
struct KeyboardConfigV0 {
|
||||
CommonKeyboardConfig commonConfig;
|
||||
u8 _pad0_[0x4];
|
||||
u64 textCheckCallback{};
|
||||
};
|
||||
static_assert(sizeof(KeyboardConfigV0) == 0x3E0);
|
||||
|
||||
/**
|
||||
* @brief The keyboard config as of api version 0x30007
|
||||
* @url https://switchbrew.org/wiki/Software_Keyboard#KeyboardConfig
|
||||
*/
|
||||
struct KeyboardConfigV7 {
|
||||
CommonKeyboardConfig commonConfig;
|
||||
u8 _pad0_[0x4];
|
||||
u64 textCheckCallback;
|
||||
std::array<u32, 0x8> separateTextPos;
|
||||
};
|
||||
static_assert(sizeof(KeyboardConfigV7) == 0x400);
|
||||
|
||||
/**
|
||||
* @brief The keyboard config as of api version 0x6000B
|
||||
* @url https://switchbrew.org/wiki/Software_Keyboard#KeyboardConfig
|
||||
*/
|
||||
struct KeyboardConfigVB {
|
||||
CommonKeyboardConfig commonConfig{};
|
||||
std::array<u32, 0x8> separateTextPos{0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF};
|
||||
std::array<DictionaryInfo, 0x18> customisedDictionaryInfoList{};
|
||||
u8 customisedDictionaryCount{};
|
||||
bool isCancelButtonDisabled{};
|
||||
u8 reserved0[0xD];
|
||||
u8 trigger{};
|
||||
u8 reserved1[0x4];
|
||||
|
||||
KeyboardConfigVB();
|
||||
|
||||
KeyboardConfigVB(const KeyboardConfigV7 &v7config);
|
||||
|
||||
KeyboardConfigVB(const KeyboardConfigV0 &v0config);
|
||||
};
|
||||
static_assert(sizeof(KeyboardConfigVB) == 0x4C8);
|
||||
}
|
|
@ -1,47 +0,0 @@
|
|||
// SPDX-License-Identifier: MPL-2.0
|
||||
// Copyright © 2022 Skyline Team and Contributors (https://github.com/skyline-emu/)
|
||||
// Copyright © 2020 yuzu Emulator Project (https://github.com/yuzu-emu/)
|
||||
|
||||
#include <input.h>
|
||||
#include <input/npad.h>
|
||||
#include <services/applet/common_arguments.h>
|
||||
#include <services/am/storage/ObjIStorage.h>
|
||||
#include "web_applet.h"
|
||||
|
||||
namespace skyline::applet {
|
||||
WebApplet::WebApplet(const DeviceState &state,
|
||||
service::ServiceManager &manager,
|
||||
std::shared_ptr<kernel::type::KEvent> onAppletStateChanged,
|
||||
std::shared_ptr<kernel::type::KEvent> onNormalDataPushFromApplet,
|
||||
std::shared_ptr<kernel::type::KEvent> onInteractiveDataPushFromApplet,
|
||||
service::applet::LibraryAppletMode appletMode)
|
||||
: IApplet{state, manager, std::move(onAppletStateChanged), std::move(onNormalDataPushFromApplet), std::move(onInteractiveDataPushFromApplet), appletMode} {}
|
||||
|
||||
Result WebApplet::Start() {
|
||||
auto commonArg{PopNormalInput<service::applet::CommonArguments>()};
|
||||
auto argHeader{PopNormalInput<WebArgHeader>()};
|
||||
|
||||
if ((commonArg.apiVersion >= 0x80000 && argHeader.shimKind == ShimKind::Web) || (commonArg.apiVersion >= 0x30000 && argHeader.shimKind == ShimKind::Share))
|
||||
Logger::Error("OfflineWeb TLV output is unsupported!");
|
||||
|
||||
PushNormalDataAndSignal(std::make_shared<service::am::ObjIStorage<WebCommonReturnValue>>(state, manager, WebCommonReturnValue{
|
||||
.exitReason = WebExitReason::WindowClosed,
|
||||
.lastUrl = {'h', 't', 't', 'p', ':', '/', '/', 'l', 'o', 'c', 'a', 'l', 'h', 'o', 's', 't', '/'},
|
||||
.lastUrlSize = 17
|
||||
}));
|
||||
|
||||
// Notify the guest that we've finished running
|
||||
onAppletStateChanged->Signal();
|
||||
return {};
|
||||
}
|
||||
|
||||
Result WebApplet::GetResult() {
|
||||
return {};
|
||||
}
|
||||
|
||||
void WebApplet::PushNormalDataToApplet(std::shared_ptr<service::am::IStorage> data) {
|
||||
PushNormalInput(data);
|
||||
}
|
||||
|
||||
void WebApplet::PushInteractiveDataToApplet(std::shared_ptr<service::am::IStorage> data) {}
|
||||
}
|
|
@ -1,75 +0,0 @@
|
|||
// SPDX-License-Identifier: MPL-2.0
|
||||
// Copyright © 2022 Skyline Team and Contributors (https://github.com/skyline-emu/)
|
||||
// Copyright © 2020 Ryujinx Team and Contributors (https://github.com/ryujinx/)
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <services/am/applet/IApplet.h>
|
||||
|
||||
namespace skyline::applet {
|
||||
/**
|
||||
* @brief The Web applet is utilized by the guest to display web pages using the built-in web browser
|
||||
*/
|
||||
class WebApplet : public service::am::IApplet, service::am::EnableNormalQueue {
|
||||
private:
|
||||
#pragma pack(push, 1)
|
||||
|
||||
/**
|
||||
* @brief Type of web-applet to launch
|
||||
* @url https://switchbrew.org/wiki/Internet_Browser#ShimKind
|
||||
*/
|
||||
enum class ShimKind : u32 {
|
||||
Shop = 1,
|
||||
Login = 2,
|
||||
Offline = 3,
|
||||
Share = 4,
|
||||
Web = 5,
|
||||
Wifi = 6,
|
||||
Lobby = 7,
|
||||
Lhub = 8,
|
||||
};
|
||||
|
||||
enum class WebExitReason : u32 {
|
||||
EndButtonPressed = 0,
|
||||
BackButtonPressed = 1,
|
||||
ExitRequested = 2,
|
||||
CallbackURL = 3,
|
||||
WindowClosed = 4,
|
||||
ErrorDialog = 7,
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Common return value struct for all web-applet commands
|
||||
*/
|
||||
struct WebCommonReturnValue {
|
||||
WebExitReason exitReason;
|
||||
u32 _pad_;
|
||||
std::array<char, 0x1000> lastUrl;
|
||||
u64 lastUrlSize;
|
||||
};
|
||||
static_assert(sizeof(WebCommonReturnValue) == 0x1010);
|
||||
|
||||
/**
|
||||
* @brief The input data for the web-applet
|
||||
*/
|
||||
struct WebArgHeader {
|
||||
u16 count;
|
||||
u16 _pad_;
|
||||
ShimKind shimKind;
|
||||
};
|
||||
|
||||
#pragma pack(pop)
|
||||
|
||||
|
||||
public:
|
||||
WebApplet(const DeviceState &state, service::ServiceManager &manager, std::shared_ptr<kernel::type::KEvent> onAppletStateChanged, std::shared_ptr<kernel::type::KEvent> onNormalDataPushFromApplet, std::shared_ptr<kernel::type::KEvent> onInteractiveDataPushFromApplet, service::applet::LibraryAppletMode appletMode);
|
||||
|
||||
Result Start() override;
|
||||
|
||||
Result GetResult() override;
|
||||
|
||||
void PushNormalDataToApplet(std::shared_ptr<service::am::IStorage> data) override;
|
||||
|
||||
void PushInteractiveDataToApplet(std::shared_ptr<service::am::IStorage> data) override;
|
||||
};
|
||||
}
|
|
@ -1,55 +1,78 @@
|
|||
// SPDX-License-Identifier: MPL-2.0
|
||||
// Copyright © 2020 Skyline Team and Contributors (https://github.com/skyline-emu/)
|
||||
|
||||
#include <audio_core/audio_core.h>
|
||||
#include <audio_core/audio_out_manager.h>
|
||||
#include <audio_core/common/settings.h>
|
||||
#include <common/settings.h>
|
||||
#include <common/utils.h>
|
||||
#include "audio.h"
|
||||
|
||||
namespace AudioCore::Log {
|
||||
void Debug(const std::string &message) {
|
||||
skyline::Logger::Write(skyline::Logger::LogLevel::Debug, message);
|
||||
}
|
||||
|
||||
void Info(const std::string &message) {
|
||||
skyline::Logger::Write(skyline::Logger::LogLevel::Info, message);
|
||||
}
|
||||
|
||||
void Warn(const std::string &message) {
|
||||
skyline::Logger::Write(skyline::Logger::LogLevel::Warn, message);
|
||||
}
|
||||
|
||||
void Error(const std::string &message) {
|
||||
skyline::Logger::Write(skyline::Logger::LogLevel::Error, message);
|
||||
}
|
||||
}
|
||||
|
||||
namespace Core::Timing {
|
||||
skyline::u64 GetClockTicks() {
|
||||
return skyline::util::GetTimeTicks();
|
||||
}
|
||||
|
||||
std::chrono::nanoseconds GetClockNs() {
|
||||
return std::chrono::nanoseconds{skyline::util::GetTimeNs()};
|
||||
}
|
||||
}
|
||||
|
||||
namespace skyline::audio {
|
||||
Audio::Audio(const DeviceState &state)
|
||||
: audioOutManager{std::make_unique<AudioCore::AudioOut::Manager>(audioSystem)},
|
||||
audioRendererManager{std::make_unique<AudioCore::AudioRenderer::Manager>(audioSystem)} {
|
||||
AudioCore::Settings::values.volume = *state.settings->isAudioOutputDisabled ? 0 : 200;
|
||||
Audio::Audio(const DeviceState &state) : oboe::AudioStreamCallback() {
|
||||
builder.setChannelCount(constant::ChannelCount);
|
||||
builder.setSampleRate(constant::SampleRate);
|
||||
builder.setFormat(constant::PcmFormat);
|
||||
builder.setFramesPerCallback(constant::MixBufferSize);
|
||||
builder.setUsage(oboe::Usage::Game);
|
||||
builder.setCallback(this);
|
||||
builder.setSharingMode(oboe::SharingMode::Exclusive);
|
||||
builder.setPerformanceMode(oboe::PerformanceMode::LowLatency);
|
||||
|
||||
builder.openManagedStream(outputStream);
|
||||
outputStream->requestStart();
|
||||
}
|
||||
|
||||
Audio::~Audio() = default;
|
||||
|
||||
void Audio::Pause() {
|
||||
audioSystem.AudioCore().GetOutputSink().SetSystemVolume(0.0f);
|
||||
Audio::~Audio() {
|
||||
outputStream->requestStop();
|
||||
}
|
||||
|
||||
void Audio::Resume() {
|
||||
audioSystem.AudioCore().GetOutputSink().SetSystemVolume(1.0f);
|
||||
std::shared_ptr<AudioTrack> Audio::OpenTrack(u8 channelCount, u32 sampleRate, const std::function<void()> &releaseCallback) {
|
||||
std::lock_guard trackGuard(trackLock);
|
||||
|
||||
auto track{std::make_shared<AudioTrack>(channelCount, sampleRate, releaseCallback)};
|
||||
audioTracks.push_back(track);
|
||||
|
||||
return track;
|
||||
}
|
||||
|
||||
void Audio::CloseTrack(std::shared_ptr<AudioTrack> &track) {
|
||||
std::lock_guard trackGuard(trackLock);
|
||||
|
||||
audioTracks.erase(std::remove(audioTracks.begin(), audioTracks.end(), track), audioTracks.end());
|
||||
track.reset();
|
||||
}
|
||||
|
||||
oboe::DataCallbackResult Audio::onAudioReady(oboe::AudioStream *audioStream, void *audioData, int32_t numFrames) {
|
||||
auto destBuffer{static_cast<i16 *>(audioData)};
|
||||
auto streamSamples{static_cast<size_t>(numFrames) * audioStream->getChannelCount()};
|
||||
size_t writtenSamples{};
|
||||
|
||||
{
|
||||
std::lock_guard trackGuard(trackLock);
|
||||
|
||||
for (auto &track : audioTracks) {
|
||||
if (track->playbackState == AudioOutState::Stopped)
|
||||
continue;
|
||||
|
||||
std::lock_guard bufferGuard(track->bufferLock);
|
||||
|
||||
auto trackSamples{track->samples.Read(span(destBuffer, streamSamples), [](i16 *source, i16 *destination) {
|
||||
*destination = Saturate<i16, i32>(static_cast<u32>(*destination) + static_cast<u32>(*source));
|
||||
}, writtenSamples)};
|
||||
|
||||
writtenSamples = std::max(trackSamples, writtenSamples);
|
||||
|
||||
track->sampleCounter += trackSamples;
|
||||
track->CheckReleasedBuffers();
|
||||
}
|
||||
}
|
||||
|
||||
if (streamSamples > writtenSamples)
|
||||
memset(destBuffer + writtenSamples, 0, (streamSamples - writtenSamples) * sizeof(i16));
|
||||
|
||||
return oboe::DataCallbackResult::Continue;
|
||||
}
|
||||
|
||||
void Audio::onErrorAfterClose(oboe::AudioStream *audioStream, oboe::Result error) {
|
||||
if (error == oboe::Result::ErrorDisconnected) {
|
||||
builder.openManagedStream(outputStream);
|
||||
outputStream->requestStart();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,33 +3,51 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <audio_core/core/core.h>
|
||||
#include <common.h>
|
||||
|
||||
namespace AudioCore::AudioOut {
|
||||
class Manager;
|
||||
}
|
||||
|
||||
namespace AudioCore::AudioRenderer {
|
||||
class Manager;
|
||||
}
|
||||
#include <audio/track.h>
|
||||
|
||||
namespace skyline::audio {
|
||||
/**
|
||||
* @brief The Audio class is used to bridge yuzu's audio core with services
|
||||
* @brief The Audio class is used to mix audio from all tracks
|
||||
*/
|
||||
class Audio {
|
||||
public:
|
||||
Core::System audioSystem{};
|
||||
std::unique_ptr<AudioCore::AudioOut::Manager> audioOutManager;
|
||||
std::unique_ptr<AudioCore::AudioRenderer::Manager> audioRendererManager;
|
||||
class Audio : public oboe::AudioStreamCallback {
|
||||
private:
|
||||
oboe::AudioStreamBuilder builder;
|
||||
oboe::ManagedStream outputStream;
|
||||
std::vector<std::shared_ptr<AudioTrack>> audioTracks;
|
||||
std::mutex trackLock; //!< Synchronizes modifications to the audio tracks
|
||||
|
||||
public:
|
||||
Audio(const DeviceState &state);
|
||||
|
||||
~Audio();
|
||||
|
||||
void Pause();
|
||||
/**
|
||||
* @brief Opens a new track that can be used to play sound
|
||||
* @param channelCount The amount channels that are present in the track
|
||||
* @param sampleRate The sample rate of the track
|
||||
* @param releaseCallback The callback to call when a buffer has been released
|
||||
* @return A shared pointer to a new AudioTrack object
|
||||
*/
|
||||
std::shared_ptr<AudioTrack> OpenTrack(u8 channelCount, u32 sampleRate, const std::function<void()> &releaseCallback);
|
||||
|
||||
void Resume();
|
||||
/**
|
||||
* @brief Closes a track and frees its data
|
||||
*/
|
||||
void CloseTrack(std::shared_ptr<AudioTrack> &track);
|
||||
|
||||
/**
|
||||
* @brief The callback oboe uses to get audio sample data
|
||||
* @param audioStream The audio stream we are being called by
|
||||
* @param audioData The raw audio sample data
|
||||
* @param numFrames The amount of frames the sample data needs to contain
|
||||
*/
|
||||
oboe::DataCallbackResult onAudioReady(oboe::AudioStream *audioStream, void *audioData, int32_t numFrames);
|
||||
|
||||
/**
|
||||
* @brief The callback oboe uses to notify the application about stream closure
|
||||
* @param audioStream The audio stream we are being called by
|
||||
* @param error The error due to which the stream is being closed
|
||||
*/
|
||||
void onErrorAfterClose(oboe::AudioStream *audioStream, oboe::Result error);
|
||||
};
|
||||
}
|
||||
|
|
52
app/src/main/cpp/skyline/audio/adpcm_decoder.cpp
Normal file
52
app/src/main/cpp/skyline/audio/adpcm_decoder.cpp
Normal file
|
@ -0,0 +1,52 @@
|
|||
// SPDX-License-Identifier: MPL-2.0
|
||||
// Copyright © 2020 Skyline Team and Contributors (https://github.com/skyline-emu/)
|
||||
|
||||
#include "common.h"
|
||||
#include "adpcm_decoder.h"
|
||||
|
||||
namespace skyline::audio {
|
||||
AdpcmDecoder::AdpcmDecoder(std::vector<std::array<i16, 2>> coefficients) : coefficients(std::move(coefficients)) {}
|
||||
|
||||
std::vector<i16> AdpcmDecoder::Decode(span<u8> adpcmData) {
|
||||
constexpr size_t BytesPerFrame{0x8};
|
||||
constexpr size_t SamplesPerFrame{0xE};
|
||||
|
||||
size_t remainingSamples{(adpcmData.size() / BytesPerFrame) * SamplesPerFrame};
|
||||
|
||||
std::vector<i16> output;
|
||||
output.reserve(remainingSamples);
|
||||
|
||||
size_t inputOffset{};
|
||||
|
||||
while (inputOffset < adpcmData.size()) {
|
||||
FrameHeader header{adpcmData[inputOffset++]};
|
||||
|
||||
size_t frameSamples{std::min(SamplesPerFrame, remainingSamples)};
|
||||
|
||||
i32 ctx{};
|
||||
|
||||
for (size_t index{}; index < frameSamples; index++) {
|
||||
i32 sample{};
|
||||
|
||||
if (index & 1) {
|
||||
sample = (ctx << 28) >> 28;
|
||||
} else {
|
||||
ctx = adpcmData[inputOffset++];
|
||||
sample = (ctx << 24) >> 28;
|
||||
}
|
||||
|
||||
i32 prediction{history[0] * coefficients[header.coefficientIndex][0] + history[1] * coefficients[header.coefficientIndex][1]};
|
||||
sample = (sample * (0x800 << header.scale) + prediction + 0x400) >> 11;
|
||||
|
||||
auto saturated{audio::Saturate<i16, i32>(sample)};
|
||||
output.push_back(saturated);
|
||||
history[1] = history[0];
|
||||
history[0] = saturated;
|
||||
}
|
||||
|
||||
remainingSamples -= frameSamples;
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
}
|
36
app/src/main/cpp/skyline/audio/adpcm_decoder.h
Normal file
36
app/src/main/cpp/skyline/audio/adpcm_decoder.h
Normal file
|
@ -0,0 +1,36 @@
|
|||
// SPDX-License-Identifier: MPL-2.0
|
||||
// Copyright © 2020 Skyline Team and Contributors (https://github.com/skyline-emu/)
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <common.h>
|
||||
|
||||
namespace skyline::audio {
|
||||
/**
|
||||
* @brief The AdpcmDecoder class handles decoding single channel ADPCM (Adaptive Differential Pulse-Code Modulation) data
|
||||
*/
|
||||
class AdpcmDecoder {
|
||||
private:
|
||||
union FrameHeader {
|
||||
u8 raw;
|
||||
|
||||
struct {
|
||||
u8 scale : 4; //!< The scale factor for this frame
|
||||
u8 coefficientIndex : 3;
|
||||
u8 _pad_ : 1;
|
||||
};
|
||||
};
|
||||
static_assert(sizeof(FrameHeader) == 0x1);
|
||||
|
||||
std::array<i32, 2> history{}; //!< The previous samples for decoding the ADPCM stream
|
||||
std::vector<std::array<i16, 2>> coefficients; //!< The coefficients for decoding the ADPCM stream
|
||||
|
||||
public:
|
||||
AdpcmDecoder(std::vector<std::array<i16, 2>> coefficients);
|
||||
|
||||
/**
|
||||
* @brief Decodes a buffer of ADPCM data into I16 PCM
|
||||
*/
|
||||
std::vector<i16> Decode(span <u8> adpcmData);
|
||||
};
|
||||
}
|
50
app/src/main/cpp/skyline/audio/common.h
Normal file
50
app/src/main/cpp/skyline/audio/common.h
Normal file
|
@ -0,0 +1,50 @@
|
|||
// SPDX-License-Identifier: MPL-2.0
|
||||
// Copyright © 2020 Skyline Team and Contributors (https://github.com/skyline-emu/)
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <oboe/Oboe.h>
|
||||
#include <common.h>
|
||||
|
||||
namespace skyline {
|
||||
namespace constant {
|
||||
constexpr u16 SampleRate{48000}; //!< The common sampling rate to use for audio output
|
||||
constexpr u8 ChannelCount{2}; //!< The common amount of channels to use for audio output
|
||||
constexpr u16 MixBufferSize{960}; //!< The size of the mix buffer by default
|
||||
constexpr auto PcmFormat{oboe::AudioFormat::I16}; //!< The common PCM data format to use for audio output
|
||||
}
|
||||
|
||||
namespace audio {
|
||||
enum class AudioFormat : u8 {
|
||||
Invalid = 0, //!< An invalid PCM format
|
||||
Int8 = 1, //!< 8 bit integer PCM
|
||||
Int16 = 2, //!< 16 bit integer PCM
|
||||
Int24 = 3, //!< 24 bit integer PCM
|
||||
Int32 = 4, //!< 32 bit integer PCM
|
||||
Float = 5, //!< Floating point PCM
|
||||
ADPCM = 6, //!< Adaptive differential PCM
|
||||
};
|
||||
|
||||
enum class AudioOutState : u8 {
|
||||
Started = 0, //!< Stream is started and is playing
|
||||
Stopped = 1, //!< Stream is stopped, there are no samples left to play
|
||||
Paused = 2, //!< Stream is paused, some samples may not have been played yet
|
||||
};
|
||||
|
||||
struct BufferIdentifier {
|
||||
u64 tag;
|
||||
u64 finalSample; //!< The final sample this buffer will be played in, after that the buffer can be safely released
|
||||
bool released; //!< If the buffer has been released (fully played back)
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Saturates the specified value according to the numeric limits of Out
|
||||
* @tparam Out The return value type and the numeric limit clamp
|
||||
* @tparam Intermediate The intermediate type that is converted to from In before clamping
|
||||
*/
|
||||
template<typename Out, typename Intermediate, typename In>
|
||||
inline Out Saturate(In value) {
|
||||
return static_cast<Out>(std::clamp(static_cast<Intermediate>(value), static_cast<Intermediate>(std::numeric_limits<Out>::min()), static_cast<Intermediate>(std::numeric_limits<Out>::max())));
|
||||
}
|
||||
}
|
||||
}
|
155
app/src/main/cpp/skyline/audio/resampler.cpp
Normal file
155
app/src/main/cpp/skyline/audio/resampler.cpp
Normal file
|
@ -0,0 +1,155 @@
|
|||
// SPDX-License-Identifier: MPL-2.0
|
||||
// Copyright © 2020 Skyline Team and Contributors (https://github.com/skyline-emu/)
|
||||
|
||||
#include "common.h"
|
||||
#include "resampler.h"
|
||||
|
||||
namespace skyline::audio {
|
||||
/**
|
||||
* @brief The coefficients for each index of a single output frame
|
||||
*/
|
||||
struct LutEntry {
|
||||
i32 a;
|
||||
i32 b;
|
||||
i32 c;
|
||||
i32 d;
|
||||
};
|
||||
|
||||
// @fmt:off
|
||||
constexpr std::array<LutEntry, 128> CurveLut0{{
|
||||
{6600, 19426, 6722, 3}, {6479, 19424, 6845, 9}, {6359, 19419, 6968, 15}, {6239, 19412, 7093, 22},
|
||||
{6121, 19403, 7219, 28}, {6004, 19391, 7345, 34}, {5888, 19377, 7472, 41}, {5773, 19361, 7600, 48},
|
||||
{5659, 19342, 7728, 55}, {5546, 19321, 7857, 62}, {5434, 19298, 7987, 69}, {5323, 19273, 8118, 77},
|
||||
{5213, 19245, 8249, 84}, {5104, 19215, 8381, 92}, {4997, 19183, 8513, 101}, {4890, 19148, 8646, 109},
|
||||
{4785, 19112, 8780, 118}, {4681, 19073, 8914, 127}, {4579, 19031, 9048, 137}, {4477, 18988, 9183, 147},
|
||||
{4377, 18942, 9318, 157}, {4277, 18895, 9454, 168}, {4179, 18845, 9590, 179}, {4083, 18793, 9726, 190},
|
||||
{3987, 18738, 9863, 202}, {3893, 18682, 10000, 215}, {3800, 18624, 10137, 228}, {3709, 18563, 10274, 241},
|
||||
{3618, 18500, 10411, 255}, {3529, 18436, 10549, 270}, {3441, 18369, 10687, 285}, {3355, 18300, 10824, 300},
|
||||
{3269, 18230, 10962, 317}, {3186, 18157, 11100, 334}, {3103, 18082, 11238, 351}, {3022, 18006, 11375, 369},
|
||||
{2942, 17927, 11513, 388}, {2863, 17847, 11650, 408}, {2785, 17765, 11788, 428}, {2709, 17681, 11925, 449},
|
||||
{2635, 17595, 12062, 471}, {2561, 17507, 12198, 494}, {2489, 17418, 12334, 517}, {2418, 17327, 12470, 541},
|
||||
{2348, 17234, 12606, 566}, {2280, 17140, 12741, 592}, {2213, 17044, 12876, 619}, {2147, 16946, 13010, 647},
|
||||
{2083, 16846, 13144, 675}, {2020, 16745, 13277, 704}, {1958, 16643, 13409, 735}, {1897, 16539, 13541, 766},
|
||||
{1838, 16434, 13673, 798}, {1780, 16327, 13803, 832}, {1723, 16218, 13933, 866}, {1667, 16109, 14062, 901},
|
||||
{1613, 15998, 14191, 937}, {1560, 15885, 14318, 975}, {1508, 15772, 14445, 1013}, {1457, 15657, 14571, 1052},
|
||||
{1407, 15540, 14695, 1093}, {1359, 15423, 14819, 1134}, {1312, 15304, 14942, 1177}, {1266, 15185, 15064, 1221},
|
||||
{1221, 15064, 15185, 1266}, {1177, 14942, 15304, 1312}, {1134, 14819, 15423, 1359}, {1093, 14695, 15540, 1407},
|
||||
{1052, 14571, 15657, 1457}, {1013, 14445, 15772, 1508}, {975, 14318, 15885, 1560}, {937, 14191, 15998, 1613},
|
||||
{901, 14062, 16109, 1667}, {866, 13933, 16218, 1723}, {832, 13803, 16327, 1780}, {798, 13673, 16434, 1838},
|
||||
{766, 13541, 16539, 1897}, {735, 13409, 16643, 1958}, {704, 13277, 16745, 2020}, {675, 13144, 16846, 2083},
|
||||
{647, 13010, 16946, 2147}, {619, 12876, 17044, 2213}, {592, 12741, 17140, 2280}, {566, 12606, 17234, 2348},
|
||||
{541, 12470, 17327, 2418}, {517, 12334, 17418, 2489}, {494, 12198, 17507, 2561}, {471, 12062, 17595, 2635},
|
||||
{449, 11925, 17681, 2709}, {428, 11788, 17765, 2785}, {408, 11650, 17847, 2863}, {388, 11513, 17927, 2942},
|
||||
{369, 11375, 18006, 3022}, {351, 11238, 18082, 3103}, {334, 11100, 18157, 3186}, {317, 10962, 18230, 3269},
|
||||
{300, 10824, 18300, 3355}, {285, 10687, 18369, 3441}, {270, 10549, 18436, 3529}, {255, 10411, 18500, 3618},
|
||||
{241, 10274, 18563, 3709}, {228, 10137, 18624, 3800}, {215, 10000, 18682, 3893}, {202, 9863, 18738, 3987},
|
||||
{190, 9726, 18793, 4083}, {179, 9590, 18845, 4179}, {168, 9454, 18895, 4277}, {157, 9318, 18942, 4377},
|
||||
{147, 9183, 18988, 4477}, {137, 9048, 19031, 4579}, {127, 8914, 19073, 4681}, {118, 8780, 19112, 4785},
|
||||
{109, 8646, 19148, 4890}, {101, 8513, 19183, 4997}, {92, 8381, 19215, 5104}, {84, 8249, 19245, 5213},
|
||||
{77, 8118, 19273, 5323}, {69, 7987, 19298, 5434}, {62, 7857, 19321, 5546}, {55, 7728, 19342, 5659},
|
||||
{48, 7600, 19361, 5773}, {41, 7472, 19377, 5888}, {34, 7345, 19391, 6004}, {28, 7219, 19403, 6121},
|
||||
{22, 7093, 19412, 6239}, {15, 6968, 19419, 6359}, {9, 6845, 19424, 6479}, {3, 6722, 19426, 6600}}};
|
||||
|
||||
constexpr std::array<LutEntry, 128> CurveLut1{{
|
||||
{-68, 32639, 69, -5}, {-200, 32630, 212, -15}, {-328, 32613, 359, -26}, {-450, 32586, 512, -36},
|
||||
{-568, 32551, 669, -47}, {-680, 32507, 832, -58}, {-788, 32454, 1000, -69}, {-891, 32393, 1174, -80},
|
||||
{-990, 32323, 1352, -92}, {-1084, 32244, 1536, -103}, {-1173, 32157, 1724, -115}, {-1258, 32061, 1919, -128},
|
||||
{-1338, 31956, 2118, -140}, {-1414, 31844, 2322, -153}, {-1486, 31723, 2532, -167}, {-1554, 31593, 2747, -180},
|
||||
{-1617, 31456, 2967, -194}, {-1676, 31310, 3192, -209}, {-1732, 31157, 3422, -224}, {-1783, 30995, 3657, -240},
|
||||
{-1830, 30826, 3897, -256}, {-1874, 30649, 4143, -272}, {-1914, 30464, 4393, -289}, {-1951, 30272, 4648, -307},
|
||||
{-1984, 30072, 4908, -325}, {-2014, 29866, 5172, -343}, {-2040, 29652, 5442, -362}, {-2063, 29431, 5716, -382},
|
||||
{-2083, 29203, 5994, -403}, {-2100, 28968, 6277, -424}, {-2114, 28727, 6565, -445}, {-2125, 28480, 6857, -468},
|
||||
{-2133, 28226, 7153, -490}, {-2139, 27966, 7453, -514}, {-2142, 27700, 7758, -538}, {-2142, 27428, 8066, -563},
|
||||
{-2141, 27151, 8378, -588}, {-2136, 26867, 8694, -614}, {-2130, 26579, 9013, -641}, {-2121, 26285, 9336, -668},
|
||||
{-2111, 25987, 9663, -696}, {-2098, 25683, 9993, -724}, {-2084, 25375, 10326, -753}, {-2067, 25063, 10662, -783},
|
||||
{-2049, 24746, 11000, -813}, {-2030, 24425, 11342, -844}, {-2009, 24100, 11686, -875}, {-1986, 23771, 12033, -907},
|
||||
{-1962, 23438, 12382, -939}, {-1937, 23103, 12733, -972}, {-1911, 22764, 13086, -1005}, {-1883, 22422, 13441, -1039},
|
||||
{-1855, 22077, 13798, -1072}, {-1825, 21729, 14156, -1107}, {-1795, 21380, 14516, -1141}, {-1764, 21027, 14877, -1176},
|
||||
{-1732, 20673, 15239, -1211}, {-1700, 20317, 15602, -1246}, {-1667, 19959, 15965, -1282}, {-1633, 19600, 16329, -1317},
|
||||
{-1599, 19239, 16694, -1353}, {-1564, 18878, 17058, -1388}, {-1530, 18515, 17423, -1424}, {-1495, 18151, 17787, -1459},
|
||||
{-1459, 17787, 18151, -1495}, {-1424, 17423, 18515, -1530}, {-1388, 17058, 18878, -1564}, {-1353, 16694, 19239, -1599},
|
||||
{-1317, 16329, 19600, -1633}, {-1282, 15965, 19959, -1667}, {-1246, 15602, 20317, -1700}, {-1211, 15239, 20673, -1732},
|
||||
{-1176, 14877, 21027, -1764}, {-1141, 14516, 21380, -1795}, {-1107, 14156, 21729, -1825}, {-1072, 13798, 22077, -1855},
|
||||
{-1039, 13441, 22422, -1883}, {-1005, 13086, 22764, -1911}, {-972, 12733, 23103, -1937}, {-939, 12382, 23438, -1962},
|
||||
{-907, 12033, 23771, -1986}, {-875, 11686, 24100, -2009}, {-844, 11342, 24425, -2030}, {-813, 11000, 24746, -2049},
|
||||
{-783, 10662, 25063, -2067}, {-753, 10326, 25375, -2084}, {-724, 9993, 25683, -2098}, {-696, 9663, 25987, -2111},
|
||||
{-668, 9336, 26285, -2121}, {-641, 9013, 26579, -2130}, {-614, 8694, 26867, -2136}, {-588, 8378, 27151, -2141},
|
||||
{-563, 8066, 27428, -2142}, {-538, 7758, 27700, -2142}, {-514, 7453, 27966, -2139}, {-490, 7153, 28226, -2133},
|
||||
{-468, 6857, 28480, -2125}, {-445, 6565, 28727, -2114}, {-424, 6277, 28968, -2100}, {-403, 5994, 29203, -2083},
|
||||
{-382, 5716, 29431, -2063}, {-362, 5442, 29652, -2040}, {-343, 5172, 29866, -2014}, {-325, 4908, 30072, -1984},
|
||||
{-307, 4648, 30272, -1951}, {-289, 4393, 30464, -1914}, {-272, 4143, 30649, -1874}, {-256, 3897, 30826, -1830},
|
||||
{-240, 3657, 30995, -1783}, {-224, 3422, 31157, -1732}, {-209, 3192, 31310, -1676}, {-194, 2967, 31456, -1617},
|
||||
{-180, 2747, 31593, -1554}, {-167, 2532, 31723, -1486}, {-153, 2322, 31844, -1414}, {-140, 2118, 31956, -1338},
|
||||
{-128, 1919, 32061, -1258}, {-115, 1724, 32157, -1173}, {-103, 1536, 32244, -1084}, {-92, 1352, 32323, -990},
|
||||
{-80, 1174, 32393, -891}, {-69, 1000, 32454, -788}, {-58, 832, 32507, -680}, {-47, 669, 32551, -568},
|
||||
{-36, 512, 32586, -450}, {-26, 359, 32613, -328}, {-15, 212, 32630, -200}, {-5, 69, 32639, -68}}};
|
||||
|
||||
constexpr std::array<LutEntry, 128> CurveLut2{{
|
||||
{3195, 26287, 3329, -32}, {3064, 26281, 3467, -34}, {2936, 26270, 3608, -38}, {2811, 26253, 3751, -42},
|
||||
{2688, 26230, 3897, -46}, {2568, 26202, 4046, -50}, {2451, 26169, 4199, -54}, {2338, 26130, 4354, -58},
|
||||
{2227, 26085, 4512, -63}, {2120, 26035, 4673, -67}, {2015, 25980, 4837, -72}, {1912, 25919, 5004, -76},
|
||||
{1813, 25852, 5174, -81}, {1716, 25780, 5347, -87}, {1622, 25704, 5522, -92}, {1531, 25621, 5701, -98},
|
||||
{1442, 25533, 5882, -103}, {1357, 25440, 6066, -109}, {1274, 25342, 6253, -115}, {1193, 25239, 6442, -121},
|
||||
{1115, 25131, 6635, -127}, {1040, 25018, 6830, -133}, {967, 24899, 7027, -140}, {897, 24776, 7227, -146},
|
||||
{829, 24648, 7430, -153}, {764, 24516, 7635, -159}, {701, 24379, 7842, -166}, {641, 24237, 8052, -174},
|
||||
{583, 24091, 8264, -181}, {526, 23940, 8478, -187}, {472, 23785, 8695, -194}, {420, 23626, 8914, -202},
|
||||
{371, 23462, 9135, -209}, {324, 23295, 9358, -215}, {279, 23123, 9583, -222}, {236, 22948, 9809, -230},
|
||||
{194, 22769, 10038, -237}, {154, 22586, 10269, -243}, {117, 22399, 10501, -250}, {81, 22208, 10735, -258},
|
||||
{47, 22015, 10970, -265}, {15, 21818, 11206, -271}, {-16, 21618, 11444, -277}, {-44, 21415, 11684, -283},
|
||||
{-71, 21208, 11924, -290}, {-97, 20999, 12166, -296}, {-121, 20786, 12409, -302}, {-143, 20571, 12653, -306},
|
||||
{-163, 20354, 12898, -311}, {-183, 20134, 13143, -316}, {-201, 19911, 13389, -321}, {-218, 19686, 13635, -325},
|
||||
{-234, 19459, 13882, -328}, {-248, 19230, 14130, -332}, {-261, 18998, 14377, -335}, {-273, 18765, 14625, -337},
|
||||
{-284, 18531, 14873, -339}, {-294, 18295, 15121, -341}, {-302, 18057, 15369, -341}, {-310, 17817, 15617, -341},
|
||||
{-317, 17577, 15864, -340}, {-323, 17335, 16111, -340}, {-328, 17092, 16357, -338}, {-332, 16848, 16603, -336},
|
||||
{-336, 16603, 16848, -332}, {-338, 16357, 17092, -328}, {-340, 16111, 17335, -323}, {-340, 15864, 17577, -317},
|
||||
{-341, 15617, 17817, -310}, {-341, 15369, 18057, -302}, {-341, 15121, 18295, -294}, {-339, 14873, 18531, -284},
|
||||
{-337, 14625, 18765, -273}, {-335, 14377, 18998, -261}, {-332, 14130, 19230, -248}, {-328, 13882, 19459, -234},
|
||||
{-325, 13635, 19686, -218}, {-321, 13389, 19911, -201}, {-316, 13143, 20134, -183}, {-311, 12898, 20354, -163},
|
||||
{-306, 12653, 20571, -143}, {-302, 12409, 20786, -121}, {-296, 12166, 20999, -97}, {-290, 11924, 21208, -71},
|
||||
{-283, 11684, 21415, -44}, {-277, 11444, 21618, -16}, {-271, 11206, 21818, 15}, {-265, 10970, 22015, 47},
|
||||
{-258, 10735, 22208, 81}, {-250, 10501, 22399, 117}, {-243, 10269, 22586, 154}, {-237, 10038, 22769, 194},
|
||||
{-230, 9809, 22948, 236}, {-222, 9583, 23123, 279}, {-215, 9358, 23295, 324}, {-209, 9135, 23462, 371},
|
||||
{-202, 8914, 23626, 420}, {-194, 8695, 23785, 472}, {-187, 8478, 23940, 526}, {-181, 8264, 24091, 583},
|
||||
{-174, 8052, 24237, 641}, {-166, 7842, 24379, 701}, {-159, 7635, 24516, 764}, {-153, 7430, 24648, 829},
|
||||
{-146, 7227, 24776, 897}, {-140, 7027, 24899, 967}, {-133, 6830, 25018, 1040}, {-127, 6635, 25131, 1115},
|
||||
{-121, 6442, 25239, 1193}, {-115, 6253, 25342, 1274}, {-109, 6066, 25440, 1357}, {-103, 5882, 25533, 1442},
|
||||
{-98, 5701, 25621, 1531}, {-92, 5522, 25704, 1622}, {-87, 5347, 25780, 1716}, {-81, 5174, 25852, 1813},
|
||||
{-76, 5004, 25919, 1912}, {-72, 4837, 25980, 2015}, {-67, 4673, 26035, 2120}, {-63, 4512, 26085, 2227},
|
||||
{-58, 4354, 26130, 2338}, {-54, 4199, 26169, 2451}, {-50, 4046, 26202, 2568}, {-46, 3897, 26230, 2688},
|
||||
{-42, 3751, 26253, 2811}, {-38, 3608, 26270, 2936}, {-34, 3467, 26281, 3064}, {-32, 3329, 26287, 3195}}};
|
||||
// @fmt:on
|
||||
|
||||
std::vector<i16> Resampler::ResampleBuffer(span<i16> inputBuffer, double ratio, u8 channelCount) {
|
||||
auto step{static_cast<u32>(ratio * 0x8000)};
|
||||
auto outputSize{static_cast<size_t>(inputBuffer.size() / ratio)};
|
||||
std::vector<i16> outputBuffer(outputSize);
|
||||
|
||||
const std::array<LutEntry, 128> &lut = [step] {
|
||||
if (step > 0xAAAA)
|
||||
return CurveLut0;
|
||||
else if (step <= 0x8000)
|
||||
return CurveLut1;
|
||||
else
|
||||
return CurveLut2;
|
||||
}();
|
||||
|
||||
for (size_t outIndex{}, inIndex{}; outIndex < outputSize; outIndex += channelCount) {
|
||||
u32 lutIndex{fraction >> 8};
|
||||
|
||||
for (u8 channel{}; channel < channelCount; channel++) {
|
||||
i32 data{inputBuffer[(inIndex + 0) * channelCount + channel] * lut[lutIndex].a +
|
||||
inputBuffer[(inIndex + 1) * channelCount + channel] * lut[lutIndex].b +
|
||||
inputBuffer[(inIndex + 2) * channelCount + channel] * lut[lutIndex].c +
|
||||
inputBuffer[(inIndex + 3) * channelCount + channel] * lut[lutIndex].d};
|
||||
|
||||
outputBuffer[outIndex + channel] = Saturate<i16, i32>(data >> 15);
|
||||
}
|
||||
|
||||
u32 newOffset{fraction + step};
|
||||
inIndex += newOffset >> 15;
|
||||
fraction = newOffset & 0x7FFF;
|
||||
}
|
||||
|
||||
return outputBuffer;
|
||||
}
|
||||
}
|
25
app/src/main/cpp/skyline/audio/resampler.h
Normal file
25
app/src/main/cpp/skyline/audio/resampler.h
Normal file
|
@ -0,0 +1,25 @@
|
|||
// SPDX-License-Identifier: MPL-2.0
|
||||
// Copyright © 2020 Skyline Team and Contributors (https://github.com/skyline-emu/)
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <common.h>
|
||||
|
||||
namespace skyline::audio {
|
||||
/**
|
||||
* @brief The Resampler class handles resampling audio PCM data
|
||||
*/
|
||||
class Resampler {
|
||||
private:
|
||||
u32 fraction{}; //!< The fractional value used for storing the resamplers last frame
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief Resamples the given sample buffer by the given ratio
|
||||
* @param inputBuffer A buffer containing PCM sample data
|
||||
* @param ratio The conversion ratio needed
|
||||
* @param channelCount The amount of channels the buffer contains
|
||||
*/
|
||||
std::vector<i16> ResampleBuffer(span <i16> inputBuffer, double ratio, u8 channelCount);
|
||||
};
|
||||
}
|
73
app/src/main/cpp/skyline/audio/track.cpp
Normal file
73
app/src/main/cpp/skyline/audio/track.cpp
Normal file
|
@ -0,0 +1,73 @@
|
|||
// SPDX-License-Identifier: MPL-2.0
|
||||
// Copyright © 2020 Skyline Team and Contributors (https://github.com/skyline-emu/)
|
||||
|
||||
#include "track.h"
|
||||
|
||||
namespace skyline::audio {
|
||||
AudioTrack::AudioTrack(u8 channelCount, u32 sampleRate, std::function<void()> releaseCallback) : channelCount(channelCount), sampleRate(sampleRate), releaseCallback(std::move(releaseCallback)) {
|
||||
if (sampleRate != constant::SampleRate)
|
||||
throw exception("Unsupported audio sample rate: {}", sampleRate);
|
||||
|
||||
if (channelCount != constant::ChannelCount)
|
||||
throw exception("Unsupported quantity of audio channels: {}", channelCount);
|
||||
}
|
||||
|
||||
void AudioTrack::Stop() {
|
||||
while (!identifiers.end()->released);
|
||||
playbackState = AudioOutState::Stopped;
|
||||
}
|
||||
|
||||
bool AudioTrack::ContainsBuffer(u64 tag) {
|
||||
// Iterate from front of queue as we don't want released samples
|
||||
for (auto identifier{identifiers.crbegin()}; identifier != identifiers.crend(); identifier++) {
|
||||
if (identifier->released)
|
||||
return false;
|
||||
|
||||
if (identifier->tag == tag)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
std::vector<u64> AudioTrack::GetReleasedBuffers(u32 max) {
|
||||
std::vector<u64> bufferIds;
|
||||
std::lock_guard trackGuard(bufferLock);
|
||||
|
||||
for (u32 index{}; index < max; index++) {
|
||||
if (identifiers.empty() || !identifiers.back().released)
|
||||
break;
|
||||
bufferIds.push_back(identifiers.back().tag);
|
||||
identifiers.pop_back();
|
||||
}
|
||||
|
||||
return bufferIds;
|
||||
}
|
||||
|
||||
void AudioTrack::AppendBuffer(u64 tag, span<i16> buffer) {
|
||||
BufferIdentifier identifier{
|
||||
.released = false,
|
||||
.tag = tag,
|
||||
.finalSample = identifiers.empty() ? (buffer.size()) : (buffer.size() + identifiers.front().finalSample)
|
||||
};
|
||||
|
||||
std::lock_guard guard(bufferLock);
|
||||
|
||||
identifiers.push_front(identifier);
|
||||
samples.Append(buffer);
|
||||
}
|
||||
|
||||
void AudioTrack::CheckReleasedBuffers() {
|
||||
bool anyReleased{};
|
||||
|
||||
for (auto &identifier : identifiers) {
|
||||
if (identifier.finalSample <= sampleCounter && !identifier.released) {
|
||||
anyReleased = true;
|
||||
identifier.released = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (anyReleased)
|
||||
releaseCallback();
|
||||
}
|
||||
}
|
75
app/src/main/cpp/skyline/audio/track.h
Normal file
75
app/src/main/cpp/skyline/audio/track.h
Normal file
|
@ -0,0 +1,75 @@
|
|||
// SPDX-License-Identifier: MPL-2.0
|
||||
// Copyright © 2020 Skyline Team and Contributors (https://github.com/skyline-emu/)
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <kernel/types/KEvent.h>
|
||||
#include <common/circular_buffer.h>
|
||||
#include "common.h"
|
||||
|
||||
namespace skyline::audio {
|
||||
/**
|
||||
* @brief The AudioTrack class manages the buffers for an audio stream
|
||||
*/
|
||||
class AudioTrack {
|
||||
private:
|
||||
std::function<void()> releaseCallback; //!< Callback called when a buffer has been played
|
||||
std::deque<BufferIdentifier> identifiers; //!< Queue of all appended buffer identifiers
|
||||
|
||||
u8 channelCount;
|
||||
u32 sampleRate;
|
||||
|
||||
public:
|
||||
CircularBuffer<i16, constant::SampleRate * constant::ChannelCount * 10> samples; //!< A circular buffer with all appended audio samples
|
||||
std::mutex bufferLock; //!< Synchronizes appending to audio buffers
|
||||
|
||||
AudioOutState playbackState{AudioOutState::Stopped}; //!< The current state of playback
|
||||
u64 sampleCounter{}; //!< A counter used for tracking when buffers have been played and can be released
|
||||
|
||||
/**
|
||||
* @param channelCount The amount channels that will be present in the track
|
||||
* @param sampleRate The sample rate to use for the track
|
||||
* @param releaseCallback A callback to call when a buffer has been played
|
||||
*/
|
||||
AudioTrack(u8 channelCount, u32 sampleRate, std::function<void()> releaseCallback);
|
||||
|
||||
/**
|
||||
* @brief Starts audio playback using data from appended buffers
|
||||
*/
|
||||
void Start() {
|
||||
playbackState = AudioOutState::Started;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Stops audio playback, this waits for audio playback to finish before returning
|
||||
*/
|
||||
void Stop();
|
||||
|
||||
/**
|
||||
* @brief Checks if a buffer has been released
|
||||
* @param tag The tag of the buffer to check
|
||||
* @return True if the given buffer hasn't been released
|
||||
*/
|
||||
bool ContainsBuffer(u64 tag);
|
||||
|
||||
/**
|
||||
* @brief Gets the IDs of all newly released buffers
|
||||
* @param max The maximum amount of buffers to return
|
||||
* @return A vector containing the identifiers of the buffers
|
||||
*/
|
||||
std::vector<u64> GetReleasedBuffers(u32 max);
|
||||
|
||||
/**
|
||||
* @brief Appends audio samples to the output buffer
|
||||
* @param tag The tag of the buffer
|
||||
* @param buffer A span containing the source sample buffer
|
||||
*/
|
||||
void AppendBuffer(u64 tag, span<i16> buffer = {});
|
||||
|
||||
/**
|
||||
* @brief Checks if any buffers have been released and calls the appropriate callback for them
|
||||
* @note bufferLock MUST be locked when calling this
|
||||
*/
|
||||
void CheckReleasedBuffers();
|
||||
};
|
||||
}
|
|
@ -1,28 +1,64 @@
|
|||
// SPDX-License-Identifier: MPL-2.0
|
||||
// Copyright © 2020 Skyline Team and Contributors (https://github.com/skyline-emu/)
|
||||
|
||||
#include <android/log.h>
|
||||
#include "common.h"
|
||||
#include "nce.h"
|
||||
#include "soc.h"
|
||||
#include "gpu.h"
|
||||
#include "audio.h"
|
||||
#include "input.h"
|
||||
#include "kernel/types/KProcess.h"
|
||||
#include "kernel/types/KThread.h"
|
||||
|
||||
namespace skyline {
|
||||
DeviceState::DeviceState(kernel::OS *os, std::shared_ptr<JvmManager> jvmManager, std::shared_ptr<Settings> settings)
|
||||
: os(os), jvm(std::move(jvmManager)), settings(std::move(settings)) {
|
||||
Logger::Logger(const std::string &path, LogLevel configLevel) : configLevel(configLevel) {
|
||||
logFile.open(path, std::ios::trunc);
|
||||
UpdateTag();
|
||||
WriteHeader("Logging started");
|
||||
}
|
||||
|
||||
Logger::~Logger() {
|
||||
WriteHeader("Logging ended");
|
||||
logFile.flush();
|
||||
}
|
||||
|
||||
thread_local static std::string logTag, threadName;
|
||||
|
||||
void Logger::UpdateTag() {
|
||||
std::array<char, 16> name;
|
||||
if (!pthread_getname_np(pthread_self(), name.data(), name.size()))
|
||||
threadName = name.data();
|
||||
else
|
||||
threadName = "unk";
|
||||
logTag = std::string("emu-cpp-") + threadName;
|
||||
}
|
||||
|
||||
void Logger::WriteHeader(const std::string &str) {
|
||||
__android_log_write(ANDROID_LOG_INFO, "emu-cpp", str.c_str());
|
||||
|
||||
std::lock_guard guard(mutex);
|
||||
logFile << "\0360\035" << str << '\n';
|
||||
}
|
||||
|
||||
void Logger::Write(LogLevel level, const std::string &str) {
|
||||
constexpr std::array<char, 5> levelCharacter{'E', 'W', 'I', 'D', 'V'}; // The LogLevel as written out to a file
|
||||
constexpr std::array<int, 5> levelAlog{ANDROID_LOG_ERROR, ANDROID_LOG_WARN, ANDROID_LOG_INFO, ANDROID_LOG_DEBUG, ANDROID_LOG_VERBOSE}; // This corresponds to LogLevel and provides its equivalent for NDK Logging
|
||||
|
||||
if (logTag.empty())
|
||||
UpdateTag();
|
||||
|
||||
__android_log_write(levelAlog[static_cast<u8>(level)], logTag.c_str(), str.c_str());
|
||||
|
||||
std::lock_guard guard(mutex);
|
||||
logFile << "\0361\035" << levelCharacter[static_cast<u8>(level)] << '\035' << threadName << '\035' << str << '\n'; // We use RS (\036) and GS (\035) as our delimiters
|
||||
}
|
||||
|
||||
DeviceState::DeviceState(kernel::OS *os, std::shared_ptr<JvmManager> jvmManager, std::shared_ptr<Settings> settings, std::shared_ptr<Logger> logger)
|
||||
: os(os), jvm(std::move(jvmManager)), settings(std::move(settings)), logger(std::move(logger)) {
|
||||
// We assign these later as they use the state in their constructor and we don't want null pointers
|
||||
gpu = std::make_shared<gpu::GPU>(*this);
|
||||
soc = std::make_shared<soc::SOC>(*this);
|
||||
audio = std::make_shared<audio::Audio>(*this);
|
||||
nce = std::make_shared<nce::NCE>(*this);
|
||||
scheduler = std::make_shared<kernel::Scheduler>(*this);
|
||||
input = std::make_shared<input::Input>(*this);
|
||||
}
|
||||
|
||||
DeviceState::~DeviceState() {
|
||||
if (process)
|
||||
process->ClearHandleTable();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,26 +3,602 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <bit>
|
||||
#include <map>
|
||||
#include <unordered_map>
|
||||
#include <span>
|
||||
#include <list>
|
||||
#include <vector>
|
||||
#include <span>
|
||||
#include <fstream>
|
||||
#include <mutex>
|
||||
#include <shared_mutex>
|
||||
#include <functional>
|
||||
#include <thread>
|
||||
#include <string>
|
||||
#include <cstdint>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
#include <memory>
|
||||
#include <compare>
|
||||
#include <condition_variable>
|
||||
#include <boost/container/small_vector.hpp>
|
||||
#include <common/exception.h>
|
||||
#include <common/span.h>
|
||||
#include <common/result.h>
|
||||
#include <common/logger.h>
|
||||
#include <sys/mman.h>
|
||||
#include <fmt/format.h>
|
||||
#include <frozen/unordered_map.h>
|
||||
#include <frozen/string.h>
|
||||
#include <jni.h>
|
||||
|
||||
#define FORCE_INLINE __attribute__((always_inline)) inline // NOLINT(cppcoreguidelines-macro-usage)
|
||||
|
||||
namespace fmt {
|
||||
/**
|
||||
* @brief A std::bitset formatter for {fmt}
|
||||
*/
|
||||
template<size_t N>
|
||||
struct formatter<std::bitset<N>> : formatter<std::string> {
|
||||
template<typename FormatContext>
|
||||
constexpr auto format(const std::bitset<N> &s, FormatContext &ctx) {
|
||||
return formatter<std::string>::format(s.to_string(), ctx);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
namespace skyline {
|
||||
using u128 = __uint128_t; //!< Unsigned 128-bit integer
|
||||
using u64 = __uint64_t; //!< Unsigned 64-bit integer
|
||||
using u32 = __uint32_t; //!< Unsigned 32-bit integer
|
||||
using u16 = __uint16_t; //!< Unsigned 16-bit integer
|
||||
using u8 = __uint8_t; //!< Unsigned 8-bit integer
|
||||
using i128 = __int128_t; //!< Signed 128-bit integer
|
||||
using i64 = __int64_t; //!< Signed 64-bit integer
|
||||
using i32 = __int32_t; //!< Signed 32-bit integer
|
||||
using i16 = __int16_t; //!< Signed 16-bit integer
|
||||
using i8 = __int8_t; //!< Signed 8-bit integer
|
||||
|
||||
using KHandle = u32; //!< The type of a kernel handle
|
||||
namespace frz = frozen;
|
||||
|
||||
/**
|
||||
* @brief The result of an operation in HOS
|
||||
* @url https://switchbrew.org/wiki/Error_codes
|
||||
*/
|
||||
union Result {
|
||||
u32 raw{};
|
||||
struct __attribute__((packed)) {
|
||||
u16 module : 9;
|
||||
u16 id : 12;
|
||||
};
|
||||
|
||||
/**
|
||||
* @note Success is 0, it's the only result that's not specific to a module
|
||||
*/
|
||||
constexpr Result() = default;
|
||||
|
||||
constexpr explicit Result(u16 module, u16 id) : module(module), id(id) {}
|
||||
|
||||
constexpr operator u32() const {
|
||||
return raw;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief A wrapper around std::optional that also stores a HOS result code
|
||||
* @tparam T The object type to hold
|
||||
*/
|
||||
template<typename T>
|
||||
class ResultValue {
|
||||
static_assert(!std::is_same<T, Result>::value);
|
||||
|
||||
private:
|
||||
std::optional<T> value;
|
||||
|
||||
public:
|
||||
Result result;
|
||||
|
||||
constexpr ResultValue(T value) : value(value) {};
|
||||
|
||||
constexpr ResultValue(Result result) : result(result) {};
|
||||
|
||||
template<typename U>
|
||||
constexpr ResultValue(ResultValue<U> result) : result(result) {};
|
||||
|
||||
constexpr operator Result() const {
|
||||
return result;
|
||||
}
|
||||
|
||||
explicit constexpr operator bool() const {
|
||||
return value.has_value();
|
||||
}
|
||||
|
||||
constexpr T& operator*() {
|
||||
return *value;
|
||||
}
|
||||
|
||||
constexpr T* operator->() {
|
||||
return &*value;
|
||||
}
|
||||
};
|
||||
|
||||
namespace constant {
|
||||
// Display
|
||||
constexpr u16 HandheldResolutionW{1280}; //!< The width component of the handheld resolution
|
||||
constexpr u16 HandheldResolutionH{720}; //!< The height component of the handheld resolution
|
||||
constexpr u16 DockedResolutionW{1920}; //!< The width component of the docked resolution
|
||||
constexpr u16 DockedResolutionH{1080}; //!< The height component of the docked resolution
|
||||
// Time
|
||||
constexpr u64 NsInSecond{1000000000}; //!< The amount of nanoseconds in a second
|
||||
constexpr u64 NsInDay{86400000000000UL}; //!< The amount of nanoseconds in a day
|
||||
}
|
||||
|
||||
namespace util {
|
||||
/**
|
||||
* @brief A way to implicitly cast all pointers to uintptr_t, this is used for {fmt} as we use 0x{:X} to print pointers
|
||||
* @note There's the exception of signed char pointers as they represent C Strings
|
||||
* @note This does not cover std::shared_ptr or std::unique_ptr and those will have to be explicitly casted to uintptr_t or passed through fmt::ptr
|
||||
*/
|
||||
template<typename T>
|
||||
constexpr auto FmtCast(T object) {
|
||||
if constexpr (std::is_pointer<T>::value)
|
||||
if constexpr (std::is_same<char, typename std::remove_cv<typename std::remove_pointer<T>::type>::type>::value)
|
||||
return reinterpret_cast<typename std::common_type<char *, T>::type>(object);
|
||||
else
|
||||
return reinterpret_cast<const uintptr_t>(object);
|
||||
else
|
||||
return object;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief {fmt}::format but with FmtCast built into it
|
||||
*/
|
||||
template<typename S, typename... Args>
|
||||
auto Format(S formatString, Args &&... args) {
|
||||
return fmt::format(formatString, FmtCast(args)...);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief A wrapper over std::runtime_error with {fmt} formatting
|
||||
*/
|
||||
class exception : public std::runtime_error {
|
||||
public:
|
||||
template<typename S, typename... Args>
|
||||
exception(const S &formatStr, Args &&... args) : runtime_error(fmt::format(formatStr, util::FmtCast(args)...)) {}
|
||||
};
|
||||
|
||||
namespace util {
|
||||
/**
|
||||
* @brief Returns the current time in nanoseconds
|
||||
* @return The current time in nanoseconds
|
||||
*/
|
||||
inline u64 GetTimeNs() {
|
||||
u64 frequency;
|
||||
asm("MRS %0, CNTFRQ_EL0" : "=r"(frequency));
|
||||
u64 ticks;
|
||||
asm("MRS %0, CNTVCT_EL0" : "=r"(ticks));
|
||||
return ((ticks / frequency) * constant::NsInSecond) + (((ticks % frequency) * constant::NsInSecond + (frequency / 2)) / frequency);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the current time in arbitrary ticks
|
||||
* @return The current time in ticks
|
||||
*/
|
||||
inline u64 GetTimeTicks() {
|
||||
u64 ticks;
|
||||
asm("MRS %0, CNTVCT_EL0" : "=r"(ticks));
|
||||
return ticks;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief A way to implicitly convert a pointer to uintptr_t and leave it unaffected if it isn't a pointer
|
||||
*/
|
||||
template<typename T>
|
||||
T PointerValue(T item) {
|
||||
return item;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
uintptr_t PointerValue(T *item) {
|
||||
return reinterpret_cast<uintptr_t>(item);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief A way to implicitly convert an integral to a pointer, if the return type is a pointer
|
||||
*/
|
||||
template<typename Return, typename T>
|
||||
Return ValuePointer(T item) {
|
||||
if constexpr (std::is_pointer<Return>::value)
|
||||
return reinterpret_cast<Return>(item);
|
||||
else
|
||||
return item;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The value aligned up to the next multiple
|
||||
* @note The multiple needs to be a power of 2
|
||||
*/
|
||||
template<typename TypeVal, typename TypeMul>
|
||||
constexpr TypeVal AlignUp(TypeVal value, TypeMul multiple) {
|
||||
multiple--;
|
||||
return ValuePointer<TypeVal>((PointerValue(value) + multiple) & ~(multiple));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The value aligned down to the previous multiple
|
||||
* @note The multiple needs to be a power of 2
|
||||
*/
|
||||
template<typename TypeVal, typename TypeMul>
|
||||
constexpr TypeVal AlignDown(TypeVal value, TypeMul multiple) {
|
||||
return ValuePointer<TypeVal>(PointerValue(value) & ~(multiple - 1));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return If the address is aligned with the multiple
|
||||
*/
|
||||
template<typename TypeVal, typename TypeMul>
|
||||
constexpr bool IsAligned(TypeVal value, TypeMul multiple) {
|
||||
if ((multiple & (multiple - 1)) == 0)
|
||||
return !(PointerValue(value) & (multiple - 1U));
|
||||
else
|
||||
return (PointerValue(value) % multiple) == 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return If the value is page aligned
|
||||
*/
|
||||
template<typename TypeVal>
|
||||
constexpr bool PageAligned(TypeVal value) {
|
||||
return IsAligned(value, PAGE_SIZE);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return If the value is word aligned
|
||||
*/
|
||||
template<typename TypeVal>
|
||||
constexpr bool WordAligned(TypeVal value) {
|
||||
return IsAligned(value, WORD_BIT / 8);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string The string to create a magic from
|
||||
* @return The magic of the supplied string
|
||||
*/
|
||||
template<typename Type>
|
||||
constexpr Type MakeMagic(std::string_view string) {
|
||||
Type object{};
|
||||
size_t offset{};
|
||||
|
||||
for (auto &character : string) {
|
||||
object |= static_cast<Type>(character) << offset;
|
||||
offset += sizeof(character) * 8;
|
||||
}
|
||||
|
||||
return object;
|
||||
}
|
||||
|
||||
constexpr u8 HexDigitToNibble(char digit) {
|
||||
if (digit >= '0' && digit <= '9')
|
||||
return digit - '0';
|
||||
else if (digit >= 'a' && digit <= 'f')
|
||||
return digit - 'a' + 10;
|
||||
else if (digit >= 'A' && digit <= 'F')
|
||||
return digit - 'A' + 10;
|
||||
throw exception("Invalid hex character: '{}'", digit);
|
||||
}
|
||||
|
||||
template<size_t Size>
|
||||
constexpr std::array<u8, Size> HexStringToArray(std::string_view string) {
|
||||
if (string.size() != Size * 2)
|
||||
throw exception("String size: {} (Expected {})", string.size(), Size);
|
||||
std::array<u8, Size> result;
|
||||
for (size_t i{}; i < Size; i++) {
|
||||
size_t index{i * 2};
|
||||
result[i] = (HexDigitToNibble(string[index]) << 4) | HexDigitToNibble(string[index + 1]);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
template<typename Type>
|
||||
constexpr Type HexStringToInt(std::string_view string) {
|
||||
if (string.size() > sizeof(Type) * 2)
|
||||
throw exception("String size larger than type: {} (sizeof(Type): {})", string.size(), sizeof(Type));
|
||||
Type result{};
|
||||
size_t offset{(sizeof(Type) * 8) - 4};
|
||||
for (size_t index{}; index < string.size(); index++, offset -= 4) {
|
||||
char digit{string[index]};
|
||||
if (digit >= '0' && digit <= '9')
|
||||
result |= static_cast<Type>(digit - '0') << offset;
|
||||
else if (digit >= 'a' && digit <= 'f')
|
||||
result |= static_cast<Type>(digit - 'a' + 10) << offset;
|
||||
else if (digit >= 'A' && digit <= 'F')
|
||||
result |= static_cast<Type>(digit - 'A' + 10) << offset;
|
||||
else
|
||||
break;
|
||||
}
|
||||
return result >> (offset + 4);
|
||||
}
|
||||
|
||||
template<size_t N>
|
||||
constexpr std::array<u8, N> SwapEndianness(std::array<u8, N> in) {
|
||||
std::reverse(in.begin(), in.end());
|
||||
return in;
|
||||
}
|
||||
|
||||
constexpr u64 SwapEndianness(u64 in) {
|
||||
return __builtin_bswap64(in);
|
||||
}
|
||||
|
||||
constexpr u32 SwapEndianness(u32 in) {
|
||||
return __builtin_bswap32(in);
|
||||
}
|
||||
|
||||
constexpr u16 SwapEndianness(u16 in) {
|
||||
return __builtin_bswap16(in);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief A compile-time hash function as std::hash isn't constexpr
|
||||
*/
|
||||
constexpr std::size_t Hash(std::string_view view) {
|
||||
return frz::elsa<frz::string>{}(frz::string(view.data(), view.size()), 0);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief A custom wrapper over span that adds several useful methods to it
|
||||
* @note This class is completely transparent, it implicitly converts from and to span
|
||||
*/
|
||||
template<typename T, size_t Extent = std::dynamic_extent>
|
||||
class span : public std::span<T, Extent> {
|
||||
public:
|
||||
using std::span<T, Extent>::span;
|
||||
using std::span<T, Extent>::operator=;
|
||||
|
||||
typedef typename std::span<T, Extent>::element_type element_type;
|
||||
typedef typename std::span<T, Extent>::size_type size_type;
|
||||
|
||||
constexpr span(const std::span<T, Extent> &spn) : std::span<T, Extent>(spn) {}
|
||||
|
||||
/**
|
||||
* @brief We want to support implicitly casting from std::string_view -> span as it's just a specialization of a data view which span is a generic form of, the opposite doesn't hold true as not all data held by a span is string data therefore the conversion isn't implicit there
|
||||
*/
|
||||
template<typename Traits>
|
||||
constexpr span(const std::basic_string_view<T, Traits> &string) : std::span<T, Extent>(const_cast<T *>(string.data()), string.size()) {}
|
||||
|
||||
template<typename Out>
|
||||
constexpr Out &as() {
|
||||
if (span::size_bytes() >= sizeof(Out))
|
||||
return *reinterpret_cast<Out *>(span::data());
|
||||
throw exception("Span size is less than Out type size (0x{:X}/0x{:X})", span::size_bytes(), sizeof(Out));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param nullTerminated If true and the string is null-terminated, a view of it will be returned (not including the null terminator itself), otherwise the entire span will be returned as a string view
|
||||
*/
|
||||
constexpr std::string_view as_string(bool nullTerminated = false) {
|
||||
return std::string_view(reinterpret_cast<char *>(span::data()), nullTerminated ? (std::find(span::begin(), span::end(), 0) - span::begin()) : span::size_bytes());
|
||||
}
|
||||
|
||||
template<typename Out, size_t OutExtent = std::dynamic_extent>
|
||||
constexpr span<Out> cast() {
|
||||
if (util::IsAligned(span::size_bytes(), sizeof(Out)))
|
||||
return span<Out, OutExtent>(reinterpret_cast<Out *>(span::data()), span::size_bytes() / sizeof(Out));
|
||||
throw exception("Span size not aligned with Out type size (0x{:X}/0x{:X})", span::size_bytes(), sizeof(Out));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Copies data from the supplied span into this one
|
||||
* @param amount The amount of elements that need to be copied (in terms of the supplied span), 0 will try to copy the entirety of the other span
|
||||
*/
|
||||
template<typename In, size_t InExtent>
|
||||
constexpr void copy_from(const span<In, InExtent> spn, size_type amount = 0) {
|
||||
auto size{amount ? amount * sizeof(In) : spn.size_bytes()};
|
||||
if (span::size_bytes() < size)
|
||||
throw exception("Data being copied is larger than this span");
|
||||
std::memmove(span::data(), spn.data(), size);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Implicit type conversion for copy_from, this allows passing in std::vector/std::array in directly is automatically passed by reference which is important for any containers
|
||||
*/
|
||||
template<typename In>
|
||||
constexpr void copy_from(const In &in, size_type amount = 0) {
|
||||
copy_from(span<typename std::add_const<typename In::value_type>::type>(in), amount);
|
||||
}
|
||||
|
||||
/** Base Class Functions that return an instance of it, we upcast them **/
|
||||
template<size_t Count>
|
||||
constexpr span<T, Count> first() const noexcept {
|
||||
return std::span<T, Extent>::template first<Count>();
|
||||
}
|
||||
|
||||
template<size_t Count>
|
||||
constexpr span<T, Count> last() const noexcept {
|
||||
return std::span<T, Extent>::template last<Count>();
|
||||
}
|
||||
|
||||
constexpr span<element_type, std::dynamic_extent> first(size_type count) const noexcept {
|
||||
return std::span<T, Extent>::first(count);
|
||||
}
|
||||
|
||||
constexpr span<element_type, std::dynamic_extent> last(size_type count) const noexcept {
|
||||
return std::span<T, Extent>::last(count);
|
||||
}
|
||||
|
||||
template<size_t Offset, size_t Count = std::dynamic_extent>
|
||||
constexpr auto subspan() const noexcept -> span<T, Count != std::dynamic_extent ? Count : Extent - Offset> {
|
||||
return std::span<T, Extent>::template subspan<Offset, Count>();
|
||||
}
|
||||
|
||||
constexpr span<T, std::dynamic_extent> subspan(size_type offset, size_type count = std::dynamic_extent) const noexcept {
|
||||
return std::span<T, Extent>::subspan(offset, count);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Deduction guides required for arguments to span, CTAD will fail for iterators, arrays and containers without this
|
||||
*/
|
||||
template<typename It, typename End, size_t Extent = std::dynamic_extent>
|
||||
span(It, End) -> span<typename std::iterator_traits<It>::value_type, Extent>;
|
||||
template<typename T, size_t Size>
|
||||
span(T (&)[Size]) -> span<T, Size>;
|
||||
template<typename T, size_t Size>
|
||||
span(std::array<T, Size> &) -> span<T, Size>;
|
||||
template<typename T, size_t Size>
|
||||
span(const std::array<T, Size> &) -> span<const T, Size>;
|
||||
template<typename Container>
|
||||
span(Container &) -> span<typename Container::value_type>;
|
||||
template<typename Container>
|
||||
span(const Container &) -> span<const typename Container::value_type>;
|
||||
|
||||
/**
|
||||
* @brief A wrapper around writing logs into a log file and logcat using Android Log APIs
|
||||
*/
|
||||
class Logger {
|
||||
private:
|
||||
std::ofstream logFile; //!< An output stream to the log file
|
||||
std::mutex mutex; //!< Synchronizes all output I/O to ensure there are no races
|
||||
|
||||
public:
|
||||
enum class LogLevel {
|
||||
Error,
|
||||
Warn,
|
||||
Info,
|
||||
Debug,
|
||||
Verbose,
|
||||
};
|
||||
|
||||
LogLevel configLevel; //!< The minimum level of logs to write
|
||||
|
||||
/**
|
||||
* @param path The path of the log file
|
||||
* @param configLevel The minimum level of logs to write
|
||||
*/
|
||||
Logger(const std::string &path, LogLevel configLevel);
|
||||
|
||||
/**
|
||||
* @brief Writes the termination message to the log file
|
||||
*/
|
||||
~Logger();
|
||||
|
||||
/**
|
||||
* @brief Update the tag in log messages with a new thread name
|
||||
*/
|
||||
static void UpdateTag();
|
||||
|
||||
/**
|
||||
* @brief Writes a header, should only be used for emulation starting and ending
|
||||
*/
|
||||
void WriteHeader(const std::string &str);
|
||||
|
||||
void Write(LogLevel level, const std::string &str);
|
||||
|
||||
/**
|
||||
* @brief A wrapper around a string which captures the calling function using Clang source location builtins
|
||||
* @note A function needs to be declared for every argument template specialization as CTAD cannot work with implicit casting
|
||||
* @url https://clang.llvm.org/docs/LanguageExtensions.html#source-location-builtins
|
||||
*/
|
||||
template<typename S>
|
||||
struct FunctionString {
|
||||
S string;
|
||||
const char *function;
|
||||
|
||||
FunctionString(S string, const char *function = __builtin_FUNCTION()) : string(std::move(string)), function(function) {}
|
||||
|
||||
std::string operator*() {
|
||||
return std::string(function) + ": " + std::string(string);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename... Args>
|
||||
void Error(FunctionString<const char*> formatString, Args &&... args) {
|
||||
if (LogLevel::Error <= configLevel)
|
||||
Write(LogLevel::Error, fmt::format(*formatString, util::FmtCast(args)...));
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
void Error(FunctionString<std::string> formatString, Args &&... args) {
|
||||
if (LogLevel::Error <= configLevel)
|
||||
Write(LogLevel::Error, fmt::format(*formatString, util::FmtCast(args)...));
|
||||
}
|
||||
|
||||
template<typename S, typename... Args>
|
||||
void ErrorNoPrefix(S formatString, Args &&... args) {
|
||||
if (LogLevel::Error <= configLevel)
|
||||
Write(LogLevel::Error, fmt::format(formatString, util::FmtCast(args)...));
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
void Warn(FunctionString<const char*> formatString, Args &&... args) {
|
||||
if (LogLevel::Warn <= configLevel)
|
||||
Write(LogLevel::Warn, fmt::format(*formatString, util::FmtCast(args)...));
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
void Warn(FunctionString<std::string> formatString, Args &&... args) {
|
||||
if (LogLevel::Warn <= configLevel)
|
||||
Write(LogLevel::Warn, fmt::format(*formatString, util::FmtCast(args)...));
|
||||
}
|
||||
|
||||
template<typename S, typename... Args>
|
||||
void WarnNoPrefix(S formatString, Args &&... args) {
|
||||
if (LogLevel::Warn <= configLevel)
|
||||
Write(LogLevel::Warn, fmt::format(formatString, util::FmtCast(args)...));
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
void Info(FunctionString<const char*> formatString, Args &&... args) {
|
||||
if (LogLevel::Info <= configLevel)
|
||||
Write(LogLevel::Info, fmt::format(*formatString, util::FmtCast(args)...));
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
void Info(FunctionString<std::string> formatString, Args &&... args) {
|
||||
if (LogLevel::Info <= configLevel)
|
||||
Write(LogLevel::Info, fmt::format(*formatString, util::FmtCast(args)...));
|
||||
}
|
||||
|
||||
template<typename S, typename... Args>
|
||||
void InfoNoPrefix(S formatString, Args &&... args) {
|
||||
if (LogLevel::Info <= configLevel)
|
||||
Write(LogLevel::Info, fmt::format(formatString, util::FmtCast(args)...));
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
void Debug(FunctionString<const char*> formatString, Args &&... args) {
|
||||
if (LogLevel::Debug <= configLevel)
|
||||
Write(LogLevel::Debug, fmt::format(*formatString, util::FmtCast(args)...));
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
void Debug(FunctionString<std::string> formatString, Args &&... args) {
|
||||
if (LogLevel::Debug <= configLevel)
|
||||
Write(LogLevel::Debug, fmt::format(*formatString, util::FmtCast(args)...));
|
||||
}
|
||||
|
||||
template<typename S, typename... Args>
|
||||
void DebugNoPrefix(S formatString, Args &&... args) {
|
||||
if (LogLevel::Debug <= configLevel)
|
||||
Write(LogLevel::Debug, fmt::format(formatString, util::FmtCast(args)...));
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
void Verbose(FunctionString<const char*> formatString, Args &&... args) {
|
||||
if (LogLevel::Verbose <= configLevel)
|
||||
Write(LogLevel::Verbose, fmt::format(*formatString, util::FmtCast(args)...));
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
void Verbose(FunctionString<std::string> formatString, Args &&... args) {
|
||||
if (LogLevel::Verbose <= configLevel)
|
||||
Write(LogLevel::Verbose, fmt::format(*formatString, util::FmtCast(args)...));
|
||||
}
|
||||
|
||||
template<typename S, typename... Args>
|
||||
void VerboseNoPrefix(S formatString, Args &&... args) {
|
||||
if (LogLevel::Verbose <= configLevel)
|
||||
Write(LogLevel::Verbose, fmt::format(formatString, util::FmtCast(args)...));
|
||||
}
|
||||
};
|
||||
|
||||
class Settings;
|
||||
namespace nce {
|
||||
class NCE;
|
||||
|
@ -32,9 +608,6 @@ namespace skyline {
|
|||
namespace gpu {
|
||||
class GPU;
|
||||
}
|
||||
namespace soc {
|
||||
class SOC;
|
||||
}
|
||||
namespace kernel {
|
||||
namespace type {
|
||||
class KProcess;
|
||||
|
@ -57,22 +630,20 @@ namespace skyline {
|
|||
* @brief The state of the entire emulator is contained within this class, all objects related to emulation are tied into it
|
||||
*/
|
||||
struct DeviceState {
|
||||
DeviceState(kernel::OS *os, std::shared_ptr<JvmManager> jvmManager, std::shared_ptr<Settings> settings);
|
||||
|
||||
~DeviceState();
|
||||
DeviceState(kernel::OS *os, std::shared_ptr<JvmManager> jvmManager, std::shared_ptr<Settings> settings, std::shared_ptr<Logger> logger);
|
||||
|
||||
kernel::OS *os;
|
||||
std::shared_ptr<JvmManager> jvm;
|
||||
std::shared_ptr<Settings> settings;
|
||||
std::shared_ptr<Logger> logger;
|
||||
std::shared_ptr<loader::Loader> loader;
|
||||
std::shared_ptr<gpu::GPU> gpu;
|
||||
std::shared_ptr<audio::Audio> audio;
|
||||
std::shared_ptr<nce::NCE> nce;
|
||||
std::shared_ptr<kernel::type::KProcess> process{};
|
||||
std::shared_ptr<kernel::Scheduler> scheduler;
|
||||
std::shared_ptr<kernel::type::KProcess> process;
|
||||
static thread_local inline std::shared_ptr<kernel::type::KThread> thread{}; //!< The KThread of the thread which accesses this object
|
||||
static thread_local inline nce::ThreadContext *ctx{}; //!< The context of the guest thread for the corresponding host thread
|
||||
std::shared_ptr<gpu::GPU> gpu;
|
||||
std::shared_ptr<soc::SOC> soc;
|
||||
std::shared_ptr<audio::Audio> audio;
|
||||
std::shared_ptr<kernel::Scheduler> scheduler;
|
||||
std::shared_ptr<input::Input> input;
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1,293 +0,0 @@
|
|||
// SPDX-License-Identifier: MPL-2.0
|
||||
// Copyright © 2021 Skyline Team and Contributors (https://github.com/skyline-emu/)
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <boost/container/small_vector.hpp>
|
||||
#include <concepts>
|
||||
#include <common.h>
|
||||
#include "segment_table.h"
|
||||
#include "spin_lock.h"
|
||||
|
||||
namespace skyline {
|
||||
template<typename VaType, size_t AddressSpaceBits>
|
||||
concept AddressSpaceValid = std::is_unsigned_v<VaType> && sizeof(VaType) * 8 >= AddressSpaceBits;
|
||||
|
||||
using TranslatedAddressRange = boost::container::small_vector<span<u8>, 1>;
|
||||
|
||||
struct EmptyStruct {};
|
||||
|
||||
/**
|
||||
* @brief FlatAddressSpaceMap provides a generic VA->PA mapping implementation using a sorted vector
|
||||
*/
|
||||
template<typename VaType, VaType UnmappedVa, typename PaType, PaType UnmappedPa, bool PaContigSplit, size_t AddressSpaceBits, typename ExtraBlockInfo = EmptyStruct> requires AddressSpaceValid<VaType, AddressSpaceBits>
|
||||
class FlatAddressSpaceMap {
|
||||
private:
|
||||
std::function<void(VaType, VaType)> unmapCallback{}; //!< Callback called when the mappings in an region have changed
|
||||
|
||||
protected:
|
||||
/**
|
||||
* @brief Represents a block of memory in the AS, the physical mapping is contiguous until another block with a different phys address is hit
|
||||
*/
|
||||
struct Block {
|
||||
VaType virt{UnmappedVa}; //!< VA of the block
|
||||
PaType phys{UnmappedPa}; //!< PA of the block, will increase 1-1 with VA until a new block is encountered
|
||||
[[no_unique_address]] ExtraBlockInfo extraInfo;
|
||||
|
||||
Block() = default;
|
||||
|
||||
Block(VaType virt, PaType phys, ExtraBlockInfo extraInfo) : virt(virt), phys(phys), extraInfo(extraInfo) {}
|
||||
|
||||
constexpr bool Valid() {
|
||||
return virt != UnmappedVa;
|
||||
}
|
||||
|
||||
constexpr bool Mapped() {
|
||||
return phys != UnmappedPa;
|
||||
}
|
||||
|
||||
constexpr bool Unmapped() {
|
||||
return phys == UnmappedPa;
|
||||
}
|
||||
|
||||
bool operator<(const VaType &pVirt) const {
|
||||
return virt < pVirt;
|
||||
}
|
||||
};
|
||||
|
||||
SharedSpinLock blockMutex;
|
||||
std::vector<Block> blocks{Block{}};
|
||||
|
||||
/**
|
||||
* @brief Maps a PA range into the given AS region
|
||||
* @note blockMutex MUST be locked when calling this
|
||||
*/
|
||||
void MapLocked(VaType virt, PaType phys, VaType size, ExtraBlockInfo extraInfo);
|
||||
|
||||
/**
|
||||
* @brief Unmaps the given range and merges it with other unmapped regions
|
||||
* @note blockMutex MUST be locked when calling this
|
||||
*/
|
||||
void UnmapLocked(VaType virt, VaType size);
|
||||
|
||||
public:
|
||||
static constexpr VaType VaMaximum{(1ULL << (AddressSpaceBits - 1)) + ((1ULL << (AddressSpaceBits - 1)) - 1)}; //!< The maximum VA that this AS can technically reach
|
||||
|
||||
VaType vaLimit{VaMaximum}; //!< A soft limit on the maximum VA of the AS
|
||||
|
||||
FlatAddressSpaceMap(VaType vaLimit, std::function<void(VaType, VaType)> unmapCallback = {});
|
||||
|
||||
FlatAddressSpaceMap() = default;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Hold memory manager specific block info
|
||||
*/
|
||||
struct MemoryManagerBlockInfo {
|
||||
bool sparseMapped;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief FlatMemoryManager specialises FlatAddressSpaceMap to focus on pointers as PAs, adding read/write functions and sparse mapping support
|
||||
*/
|
||||
template<typename VaType, VaType UnmappedVa, size_t AddressSpaceBits, size_t VaGranularityBits, size_t VaL2GranularityBits> requires AddressSpaceValid<VaType, AddressSpaceBits>
|
||||
class FlatMemoryManager : public FlatAddressSpaceMap<VaType, UnmappedVa, u8 *, nullptr, true, AddressSpaceBits, MemoryManagerBlockInfo> {
|
||||
private:
|
||||
static constexpr u64 SparseMapSize{0x400000000}; //!< 16GiB pool size for sparse mappings returned by TranslateRange, this number is arbritary and should be large enough to fit the largest sparse mapping in the AS
|
||||
u8 *sparseMap; //!< Pointer to a zero filled memory region that is returned by TranslateRange for sparse mappings
|
||||
|
||||
/**
|
||||
* @brief Version of `Block` that is trivial so it can be stored in a segment table for rapid lookups, also holds an additional extent member
|
||||
*/
|
||||
struct SegmentTableEntry {
|
||||
VaType virt;
|
||||
u8 *phys;
|
||||
VaType extent;
|
||||
MemoryManagerBlockInfo extraInfo;
|
||||
};
|
||||
|
||||
static constexpr size_t AddressSpaceSize{1ULL << AddressSpaceBits};
|
||||
SegmentTable<SegmentTableEntry, AddressSpaceSize, VaGranularityBits, VaL2GranularityBits> blockSegmentTable; //!< A page table of all buffer mappings for O(1) lookups on full matches
|
||||
|
||||
TranslatedAddressRange TranslateRangeImpl(VaType virt, VaType size, std::function<void(span<u8>)> cpuAccessCallback = {});
|
||||
|
||||
std::pair<span<u8>, size_t> LookupBlockLocked(VaType virt, std::function<void(span<u8>)> cpuAccessCallback = {}) {
|
||||
const auto &blockEntry{this->blockSegmentTable[virt]};
|
||||
VaType segmentOffset{virt - blockEntry.virt};
|
||||
|
||||
if (blockEntry.extraInfo.sparseMapped || blockEntry.phys == nullptr)
|
||||
return {span<u8>{static_cast<u8*>(nullptr), blockEntry.extent}, segmentOffset};
|
||||
|
||||
span<u8> blockSpan{blockEntry.phys, blockEntry.extent};
|
||||
if (cpuAccessCallback)
|
||||
cpuAccessCallback(blockSpan);
|
||||
|
||||
return {blockSpan, segmentOffset};
|
||||
}
|
||||
|
||||
public:
|
||||
FlatMemoryManager();
|
||||
|
||||
~FlatMemoryManager();
|
||||
|
||||
/**
|
||||
* @return A placeholder address for sparse mapped regions, this means nothing
|
||||
*/
|
||||
static u8 *SparsePlaceholderAddress() {
|
||||
return reinterpret_cast<u8 *>(0xCAFEBABE);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Looks up the mapped region that contains the given VA
|
||||
* @return A span of the mapped region and the offset of the input VA in the region
|
||||
*/
|
||||
__attribute__((always_inline)) std::pair<span<u8>, VaType> LookupBlock(VaType virt, std::function<void(span<u8>)> cpuAccessCallback = {}) {
|
||||
std::shared_lock lock{this->blockMutex};
|
||||
return LookupBlockLocked(virt, cpuAccessCallback);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Translates a region in the VA space to a corresponding set of regions in the PA space
|
||||
*/
|
||||
TranslatedAddressRange TranslateRange(VaType virt, VaType size, std::function<void(span<u8>)> cpuAccessCallback = {}) {
|
||||
std::shared_lock lock{this->blockMutex};
|
||||
|
||||
// Fast path for when the range is mapped in a single block
|
||||
auto [blockSpan, rangeOffset]{LookupBlockLocked(virt, cpuAccessCallback)};
|
||||
if (blockSpan.size() - rangeOffset >= size) {
|
||||
TranslatedAddressRange ranges;
|
||||
ranges.push_back(blockSpan.subspan(blockSpan.valid() ? rangeOffset : 0, size));
|
||||
return ranges;
|
||||
}
|
||||
|
||||
return TranslateRangeImpl(virt, size, cpuAccessCallback);
|
||||
}
|
||||
|
||||
|
||||
void Read(u8 *destination, VaType virt, VaType size, std::function<void(span<u8>)> cpuAccessCallback = {});
|
||||
|
||||
template<typename T>
|
||||
void Read(span <T> destination, VaType virt, std::function<void(span<u8>)> cpuAccessCallback = {}) {
|
||||
Read(reinterpret_cast<u8 *>(destination.data()), virt, destination.size_bytes(), cpuAccessCallback);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T Read(VaType virt, std::function<void(span<u8>)> cpuAccessCallback = {}) {
|
||||
T obj;
|
||||
Read(reinterpret_cast<u8 *>(&obj), virt, sizeof(T), cpuAccessCallback);
|
||||
return obj;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Writes contents starting from the virtual address till the end of the span or an unmapped block has been hit or when `function` returns a non-nullopt value
|
||||
* @param function A function that is called on every block where it should return an end offset into the block when it wants to end reading or std::nullopt when it wants to continue reading
|
||||
* @return A span into the supplied container with the contents of the memory region
|
||||
* @note The function will **NOT** be run on any sparse block
|
||||
* @note The function will provide no feedback on if the end has been reached or if there was an early exit
|
||||
*/
|
||||
template<typename Function, typename Container>
|
||||
span<u8> ReadTill(Container& destination, VaType virt, Function function, std::function<void(span<u8>)> cpuAccessCallback = {}) {
|
||||
//TRACE_EVENT("containers", "FlatMemoryManager::ReadTill");
|
||||
|
||||
std::shared_lock lock(this->blockMutex);
|
||||
|
||||
auto successor{std::upper_bound(this->blocks.begin(), this->blocks.end(), virt, [](auto virt, const auto &block) {
|
||||
return virt < block.virt;
|
||||
})};
|
||||
|
||||
auto predecessor{std::prev(successor)};
|
||||
|
||||
auto pointer{destination.data()};
|
||||
auto remainingSize{destination.size()};
|
||||
|
||||
u8 *blockPhys{predecessor->phys + (virt - predecessor->virt)};
|
||||
VaType blockReadSize{std::min(successor->virt - virt, remainingSize)};
|
||||
|
||||
while (remainingSize) {
|
||||
if (predecessor->phys == nullptr) {
|
||||
return {destination.data(), destination.size() - remainingSize};
|
||||
} else {
|
||||
if (predecessor->extraInfo.sparseMapped) {
|
||||
std::memset(pointer, 0, blockReadSize);
|
||||
} else {
|
||||
span<u8> cpuBlock{blockPhys, blockReadSize};
|
||||
if (cpuAccessCallback)
|
||||
cpuAccessCallback(cpuBlock);
|
||||
|
||||
auto end{function(cpuBlock)};
|
||||
std::memcpy(pointer, blockPhys, end ? *end : blockReadSize);
|
||||
if (end)
|
||||
return {destination.data(), (destination.size() - remainingSize) + *end};
|
||||
}
|
||||
}
|
||||
|
||||
pointer += blockReadSize;
|
||||
remainingSize -= blockReadSize;
|
||||
|
||||
if (remainingSize) {
|
||||
predecessor = successor++;
|
||||
blockPhys = predecessor->phys;
|
||||
blockReadSize = std::min(successor->virt - predecessor->virt, remainingSize);
|
||||
}
|
||||
}
|
||||
|
||||
return {destination.data(), destination.size()};
|
||||
}
|
||||
|
||||
void Write(VaType virt, u8 *source, VaType size, std::function<void(span<u8>)> cpuAccessCallback = {});
|
||||
|
||||
template<typename T>
|
||||
void Write(VaType virt, span<T> source, std::function<void(span<u8>)> cpuAccessCallback = {}) {
|
||||
Write(virt, reinterpret_cast<u8 *>(source.data()), source.size_bytes());
|
||||
}
|
||||
|
||||
void Write(VaType virt, util::TrivialObject auto source, std::function<void(span<u8>)> cpuAccessCallback = {}) {
|
||||
Write(virt, reinterpret_cast<u8 *>(&source), sizeof(source), cpuAccessCallback);
|
||||
}
|
||||
|
||||
void Copy(VaType dst, VaType src, VaType size, std::function<void(span<u8>)> cpuAccessCallback = {});
|
||||
|
||||
void Map(VaType virt, u8 *phys, VaType size, MemoryManagerBlockInfo extraInfo = {}) {
|
||||
std::scoped_lock lock(this->blockMutex);
|
||||
blockSegmentTable.Set(virt, virt + size, {virt, phys, size, extraInfo});
|
||||
this->MapLocked(virt, phys, size, extraInfo);
|
||||
}
|
||||
|
||||
void Unmap(VaType virt, VaType size) {
|
||||
std::scoped_lock lock(this->blockMutex);
|
||||
blockSegmentTable.Set(virt, virt + size, {});
|
||||
this->UnmapLocked(virt, size);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief FlatMemoryManager specialises FlatAddressSpaceMap to work as an allocator, with an initial, fast linear pass and a subsequent slower pass that iterates until it finds a free block
|
||||
*/
|
||||
template<typename VaType, VaType UnmappedVa, size_t AddressSpaceBits> requires AddressSpaceValid<VaType, AddressSpaceBits>
|
||||
class FlatAllocator : public FlatAddressSpaceMap<VaType, UnmappedVa, bool, false, false, AddressSpaceBits> {
|
||||
private:
|
||||
using Base = FlatAddressSpaceMap<VaType, UnmappedVa, bool, false, false, AddressSpaceBits>;
|
||||
|
||||
VaType currentLinearAllocEnd; //!< The end address for the initial linear allocation pass, once this reaches the AS limit the slower allocation path will be used
|
||||
|
||||
public:
|
||||
VaType vaStart; //!< The base VA of the allocator, no allocations will be below this
|
||||
|
||||
FlatAllocator(VaType vaStart, VaType vaLimit = Base::VaMaximum);
|
||||
|
||||
/**
|
||||
* @brief Allocates a region in the AS of the given size and returns its address
|
||||
*/
|
||||
VaType Allocate(VaType size);
|
||||
|
||||
/**
|
||||
* @brief Marks the given region in the AS as allocated
|
||||
*/
|
||||
void AllocateFixed(VaType virt, VaType size);
|
||||
|
||||
/**
|
||||
* @brief Frees an AS region so it can be used again
|
||||
*/
|
||||
void Free(VaType virt, VaType size);
|
||||
};
|
||||
}
|
|
@ -1,501 +0,0 @@
|
|||
// SPDX-License-Identifier: MPL-2.0
|
||||
// Copyright © 2021 Skyline Team and Contributors (https://github.com/skyline-emu/)
|
||||
|
||||
#include <common/trace.h>
|
||||
#include <kernel/types/KProcess.h>
|
||||
#include "address_space.h"
|
||||
|
||||
#define MAP_MEMBER(returnType) template<typename VaType, VaType UnmappedVa, typename PaType, PaType UnmappedPa, bool PaContigSplit, size_t AddressSpaceBits, typename ExtraBlockInfo> requires AddressSpaceValid<VaType, AddressSpaceBits> returnType FlatAddressSpaceMap<VaType, UnmappedVa, PaType, UnmappedPa, PaContigSplit, AddressSpaceBits, ExtraBlockInfo>
|
||||
|
||||
#define MM_MEMBER(returnType) template<typename VaType, VaType UnmappedVa, size_t AddressSpaceBits, size_t VaGranularityBits, size_t VaL2GranularityBits> requires AddressSpaceValid<VaType, AddressSpaceBits> returnType FlatMemoryManager<VaType, UnmappedVa, AddressSpaceBits, VaGranularityBits, VaL2GranularityBits>
|
||||
|
||||
#define ALLOC_MEMBER(returnType) template<typename VaType, VaType UnmappedVa, size_t AddressSpaceBits> requires AddressSpaceValid<VaType, AddressSpaceBits> returnType FlatAllocator<VaType, UnmappedVa, AddressSpaceBits>
|
||||
|
||||
namespace skyline {
|
||||
MAP_MEMBER()::FlatAddressSpaceMap(VaType vaLimit, std::function<void(VaType, VaType)> unmapCallback) :
|
||||
vaLimit(vaLimit),
|
||||
unmapCallback(std::move(unmapCallback)) {
|
||||
if (vaLimit > VaMaximum)
|
||||
throw exception("Invalid VA limit!");
|
||||
}
|
||||
|
||||
MAP_MEMBER(void)::MapLocked(VaType virt, PaType phys, VaType size, ExtraBlockInfo extraInfo) {
|
||||
TRACE_EVENT("containers", "FlatAddressSpaceMap::Map");
|
||||
|
||||
VaType virtEnd{virt + size};
|
||||
|
||||
if (virtEnd > vaLimit)
|
||||
throw exception("Trying to map a block past the VA limit: virtEnd: 0x{:X}, vaLimit: 0x{:X}", virtEnd, vaLimit);
|
||||
|
||||
auto blockEndSuccessor{std::lower_bound(blocks.begin(), blocks.end(), virtEnd)};
|
||||
if (blockEndSuccessor == blocks.begin())
|
||||
throw exception("Trying to map a block before the VA start: virtEnd: 0x{:X}", virtEnd);
|
||||
|
||||
auto blockEndPredecessor{std::prev(blockEndSuccessor)};
|
||||
|
||||
if (blockEndSuccessor != blocks.end()) {
|
||||
// We have blocks in front of us, if one is directly in front then we don't have to add a tail
|
||||
if (blockEndSuccessor->virt != virtEnd) {
|
||||
PaType tailPhys{[&]() -> PaType {
|
||||
if (!PaContigSplit || blockEndPredecessor->Unmapped())
|
||||
return blockEndPredecessor->phys; // Always propagate unmapped regions rather than calculating offset
|
||||
else
|
||||
return blockEndPredecessor->phys + virtEnd - blockEndPredecessor->virt;
|
||||
}()};
|
||||
|
||||
if (blockEndPredecessor->virt >= virt) {
|
||||
// If this block's start would be overlapped by the map then reuse it as a tail block
|
||||
blockEndPredecessor->virt = virtEnd;
|
||||
blockEndPredecessor->phys = tailPhys;
|
||||
blockEndPredecessor->extraInfo = blockEndPredecessor->extraInfo;
|
||||
|
||||
// No longer predecessor anymore
|
||||
blockEndSuccessor = blockEndPredecessor--;
|
||||
} else {
|
||||
// Else insert a new one and we're done
|
||||
blocks.insert(blockEndSuccessor, {Block(virt, phys, extraInfo), Block(virtEnd, tailPhys, blockEndPredecessor->extraInfo)});
|
||||
if (unmapCallback)
|
||||
unmapCallback(virt, size);
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// blockEndPredecessor will always be unmapped as blocks has to be terminated by an unmapped chunk
|
||||
if (blockEndPredecessor != blocks.begin() && blockEndPredecessor->virt >= virt) {
|
||||
// Move the unmapped block start backwards
|
||||
blockEndPredecessor->virt = virtEnd;
|
||||
|
||||
// No longer predecessor anymore
|
||||
blockEndSuccessor = blockEndPredecessor--;
|
||||
} else {
|
||||
// Else insert a new one and we're done
|
||||
blocks.insert(blockEndSuccessor, {Block(virt, phys, extraInfo), Block(virtEnd, UnmappedPa, {})});
|
||||
if (unmapCallback)
|
||||
unmapCallback(virt, size);
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
auto blockStartSuccessor{blockEndSuccessor};
|
||||
|
||||
// Walk the block vector to find the start successor as this is more efficient than another binary search in most scenarios
|
||||
while (std::prev(blockStartSuccessor)->virt >= virt)
|
||||
blockStartSuccessor--;
|
||||
|
||||
// Check that the start successor is either the end block or something in between
|
||||
if (blockStartSuccessor->virt > virtEnd) {
|
||||
throw exception("Unsorted block in AS map: virt: 0x{:X}", blockStartSuccessor->virt);
|
||||
} else if (blockStartSuccessor->virt == virtEnd) {
|
||||
// We need to create a new block as there are none spare that we would overwrite
|
||||
blocks.insert(blockStartSuccessor, Block(virt, phys, extraInfo));
|
||||
} else {
|
||||
// Erase overwritten blocks
|
||||
if (auto eraseStart{std::next(blockStartSuccessor)}; eraseStart != blockEndSuccessor)
|
||||
blocks.erase(eraseStart, blockEndSuccessor);
|
||||
|
||||
// Reuse a block that would otherwise be overwritten as a start block
|
||||
blockStartSuccessor->virt = virt;
|
||||
blockStartSuccessor->phys = phys;
|
||||
blockStartSuccessor->extraInfo = extraInfo;
|
||||
}
|
||||
|
||||
if (unmapCallback)
|
||||
unmapCallback(virt, size);
|
||||
}
|
||||
|
||||
MAP_MEMBER(void)::UnmapLocked(VaType virt, VaType size) {
|
||||
TRACE_EVENT("containers", "FlatAddressSpaceMap::Unmap");
|
||||
|
||||
VaType virtEnd{virt + size};
|
||||
|
||||
if (virtEnd > vaLimit)
|
||||
throw exception("Trying to map a block past the VA limit: virtEnd: 0x{:X}, vaLimit: 0x{:X}", virtEnd, vaLimit);
|
||||
|
||||
auto blockEndSuccessor{std::lower_bound(blocks.begin(), blocks.end(), virtEnd)};
|
||||
if (blockEndSuccessor == blocks.begin())
|
||||
throw exception("Trying to unmap a block before the VA start: virtEnd: 0x{:X}", virtEnd);
|
||||
|
||||
auto blockEndPredecessor{std::prev(blockEndSuccessor)};
|
||||
|
||||
auto walkBackToPredecessor{[&](auto iter) {
|
||||
while (iter->virt >= virt)
|
||||
iter--;
|
||||
|
||||
return iter;
|
||||
}};
|
||||
|
||||
auto eraseBlocksWithEndUnmapped{[&](auto unmappedEnd) {
|
||||
auto blockStartPredecessor{walkBackToPredecessor(unmappedEnd)};
|
||||
auto blockStartSuccessor{std::next(blockStartPredecessor)};
|
||||
|
||||
auto eraseEnd{[&]() {
|
||||
if (blockStartPredecessor->Unmapped()) {
|
||||
// If the start predecessor is unmapped then we can erase everything in our region and be done
|
||||
return std::next(unmappedEnd);
|
||||
} else {
|
||||
// Else reuse the end predecessor as the start of our unmapped region then erase all up to it
|
||||
unmappedEnd->virt = virt;
|
||||
return unmappedEnd;
|
||||
}
|
||||
}()};
|
||||
|
||||
// We can't have two unmapped regions after each other
|
||||
if (eraseEnd != blocks.end() && (eraseEnd == blockStartSuccessor || (blockStartPredecessor->Unmapped() && eraseEnd->Unmapped())))
|
||||
throw exception("Multiple contiguous unmapped regions are unsupported!");
|
||||
|
||||
blocks.erase(blockStartSuccessor, eraseEnd);
|
||||
}};
|
||||
|
||||
// We can avoid any splitting logic if these are the case
|
||||
if (blockEndPredecessor->Unmapped()) {
|
||||
if (blockEndPredecessor->virt > virt)
|
||||
eraseBlocksWithEndUnmapped(blockEndPredecessor);
|
||||
|
||||
if (unmapCallback)
|
||||
unmapCallback(virt, size);
|
||||
|
||||
return; // The region is unmapped, bail out early
|
||||
} else if (blockEndSuccessor->virt == virtEnd && blockEndSuccessor->Unmapped()) {
|
||||
eraseBlocksWithEndUnmapped(blockEndSuccessor);
|
||||
|
||||
if (unmapCallback)
|
||||
unmapCallback(virt, size);
|
||||
|
||||
return; // The region is unmapped here and doesn't need splitting, bail out early
|
||||
} else if (blockEndSuccessor == blocks.end()) {
|
||||
// This should never happen as the end should always follow an unmapped block
|
||||
throw exception("Unexpected Memory Manager state!");
|
||||
} else if (blockEndSuccessor->virt != virtEnd) {
|
||||
// If one block is directly in front then we don't have to add a tail
|
||||
|
||||
// The previous block is mapped so we will need to add a tail with an offset
|
||||
PaType tailPhys{[&]() {
|
||||
if constexpr (PaContigSplit)
|
||||
return blockEndPredecessor->phys + virtEnd - blockEndPredecessor->virt;
|
||||
else
|
||||
return blockEndPredecessor->phys;
|
||||
}()};
|
||||
|
||||
if (blockEndPredecessor->virt >= virt) {
|
||||
// If this block's start would be overlapped by the unmap then reuse it as a tail block
|
||||
blockEndPredecessor->virt = virtEnd;
|
||||
blockEndPredecessor->phys = tailPhys;
|
||||
|
||||
// No longer predecessor anymore
|
||||
blockEndSuccessor = blockEndPredecessor--;
|
||||
} else {
|
||||
blocks.insert(blockEndSuccessor, {Block(virt, UnmappedPa, {}), Block(virtEnd, tailPhys, blockEndPredecessor->extraInfo)});
|
||||
if (unmapCallback)
|
||||
unmapCallback(virt, size);
|
||||
|
||||
return; // The previous block is mapped and ends before
|
||||
}
|
||||
}
|
||||
|
||||
// Walk the block vector to find the start predecessor as this is more efficient than another binary search in most scenarios
|
||||
auto blockStartPredecessor{walkBackToPredecessor(blockEndSuccessor)};
|
||||
auto blockStartSuccessor{std::next(blockStartPredecessor)};
|
||||
|
||||
if (blockStartSuccessor->virt > virtEnd) {
|
||||
throw exception("Unsorted block in AS map: virt: 0x{:X}", blockStartSuccessor->virt);
|
||||
} else if (blockStartSuccessor->virt == virtEnd) {
|
||||
// There are no blocks between the start and the end that would let us skip inserting a new one for head
|
||||
|
||||
// The previous block is may be unmapped, if so we don't need to insert any unmaps after it
|
||||
if (blockStartPredecessor->Mapped())
|
||||
blocks.insert(blockStartSuccessor, Block(virt, UnmappedPa, {}));
|
||||
} else if (blockStartPredecessor->Unmapped()) {
|
||||
// If the previous block is unmapped
|
||||
blocks.erase(blockStartSuccessor, blockEndPredecessor);
|
||||
} else {
|
||||
// Erase overwritten blocks, skipping the first one as we have written the unmapped start block there
|
||||
if (auto eraseStart{std::next(blockStartSuccessor)}; eraseStart != blockEndSuccessor)
|
||||
blocks.erase(eraseStart, blockEndSuccessor);
|
||||
|
||||
// Add in the unmapped block header
|
||||
blockStartSuccessor->virt = virt;
|
||||
blockStartSuccessor->phys = UnmappedPa;
|
||||
}
|
||||
|
||||
if (unmapCallback)
|
||||
unmapCallback(virt, size);
|
||||
}
|
||||
|
||||
|
||||
MM_MEMBER(TranslatedAddressRange)::TranslateRangeImpl(VaType virt, VaType size, std::function<void(span<u8>)> cpuAccessCallback) {
|
||||
TRACE_EVENT("containers", "FlatMemoryManager::TranslateRange");
|
||||
|
||||
TranslatedAddressRange ranges;
|
||||
|
||||
auto successor{std::upper_bound(this->blocks.begin(), this->blocks.end(), virt, [] (auto virt, const auto &block) {
|
||||
return virt < block.virt;
|
||||
})};
|
||||
|
||||
auto predecessor{std::prev(successor)};
|
||||
|
||||
u8 *blockPhys{predecessor->phys + (virt - predecessor->virt)};
|
||||
VaType blockSize{std::min(successor->virt - virt, size)};
|
||||
|
||||
while (size) {
|
||||
if (predecessor->phys) {
|
||||
span cpuBlock{blockPhys, blockSize};
|
||||
if (cpuAccessCallback)
|
||||
cpuAccessCallback(cpuBlock);
|
||||
|
||||
// Batch contiguous ranges into one
|
||||
if (!ranges.empty() && ranges.back().data() + ranges.back().size() == cpuBlock.data())
|
||||
ranges.back() = {ranges.back().data(), ranges.back().size() + cpuBlock.size()};
|
||||
else
|
||||
ranges.push_back(cpuBlock);
|
||||
} else {
|
||||
ranges.push_back(span<u8>{static_cast<u8*>(nullptr), blockSize});
|
||||
}
|
||||
|
||||
size -= blockSize;
|
||||
|
||||
if (size) {
|
||||
predecessor = successor++;
|
||||
blockPhys = predecessor->phys;
|
||||
blockSize = std::min(successor->virt - predecessor->virt, size);
|
||||
}
|
||||
}
|
||||
|
||||
return ranges;
|
||||
}
|
||||
|
||||
MM_MEMBER()::FlatMemoryManager() {
|
||||
sparseMap = static_cast<u8 *>(mmap(0, SparseMapSize, PROT_READ, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0));
|
||||
if (!sparseMap)
|
||||
throw exception("Failed to mmap sparse map!");
|
||||
}
|
||||
|
||||
MM_MEMBER()::~FlatMemoryManager() {
|
||||
munmap(sparseMap, SparseMapSize);
|
||||
}
|
||||
|
||||
MM_MEMBER(void)::Read(u8 *destination, VaType virt, VaType size, std::function<void(span<u8>)> cpuAccessCallback) {
|
||||
TRACE_EVENT("containers", "FlatMemoryManager::Read");
|
||||
|
||||
std::shared_lock lock(this->blockMutex);
|
||||
|
||||
auto successor{std::upper_bound(this->blocks.begin(), this->blocks.end(), virt, [] (auto virt, const auto &block) {
|
||||
return virt < block.virt;
|
||||
})};
|
||||
|
||||
auto predecessor{std::prev(successor)};
|
||||
|
||||
u8 *blockPhys{predecessor->phys + (virt - predecessor->virt)};
|
||||
VaType blockReadSize{std::min(successor->virt - virt, size)};
|
||||
|
||||
// Reads may span across multiple individual blocks
|
||||
while (size) {
|
||||
if (predecessor->phys == nullptr) {
|
||||
throw exception("Page fault at 0x{:X}", predecessor->virt);
|
||||
} else {
|
||||
if (predecessor->extraInfo.sparseMapped) { // Sparse mappings read all zeroes
|
||||
std::memset(destination, 0, blockReadSize);
|
||||
} else {
|
||||
if (cpuAccessCallback)
|
||||
cpuAccessCallback(span{blockPhys, blockReadSize});
|
||||
|
||||
std::memcpy(destination, blockPhys, blockReadSize);
|
||||
}
|
||||
}
|
||||
|
||||
destination += blockReadSize;
|
||||
size -= blockReadSize;
|
||||
|
||||
if (size) {
|
||||
predecessor = successor++;
|
||||
blockPhys = predecessor->phys;
|
||||
blockReadSize = std::min(successor->virt - predecessor->virt, size);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MM_MEMBER(void)::Write(VaType virt, u8 *source, VaType size, std::function<void(span<u8>)> cpuAccessCallback) {
|
||||
TRACE_EVENT("containers", "FlatMemoryManager::Write");
|
||||
|
||||
std::shared_lock lock(this->blockMutex);
|
||||
|
||||
VaType virtEnd{virt + size};
|
||||
|
||||
auto successor{std::upper_bound(this->blocks.begin(), this->blocks.end(), virt, [] (auto virt, const auto &block) {
|
||||
return virt < block.virt;
|
||||
})};
|
||||
|
||||
auto predecessor{std::prev(successor)};
|
||||
|
||||
u8 *blockPhys{predecessor->phys + (virt - predecessor->virt)};
|
||||
VaType blockWriteSize{std::min(successor->virt - virt, size)};
|
||||
|
||||
// Writes may span across multiple individual blocks
|
||||
while (size) {
|
||||
if (predecessor->phys == nullptr) {
|
||||
throw exception("Page fault at 0x{:X}", predecessor->virt);
|
||||
} else {
|
||||
if (!predecessor->extraInfo.sparseMapped) { // Sparse mappings ignore writes
|
||||
if (cpuAccessCallback)
|
||||
cpuAccessCallback(span{blockPhys, blockWriteSize});
|
||||
|
||||
std::memcpy(blockPhys, source, blockWriteSize);
|
||||
}
|
||||
}
|
||||
|
||||
source += blockWriteSize;
|
||||
size -= blockWriteSize;
|
||||
|
||||
if (size) {
|
||||
predecessor = successor++;
|
||||
blockPhys = predecessor->phys;
|
||||
blockWriteSize = std::min(successor->virt - predecessor->virt, size);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MM_MEMBER(void)::Copy(VaType dst, VaType src, VaType size, std::function<void(span<u8>)> cpuAccessCallback) {
|
||||
TRACE_EVENT("containers", "FlatMemoryManager::Copy");
|
||||
|
||||
std::shared_lock lock(this->blockMutex);
|
||||
|
||||
VaType srcEnd{src + size};
|
||||
VaType dstEnd{dst + size};
|
||||
|
||||
auto srcSuccessor{std::upper_bound(this->blocks.begin(), this->blocks.end(), src, [] (auto virt, const auto &block) {
|
||||
return virt < block.virt;
|
||||
})};
|
||||
|
||||
auto dstSuccessor{std::upper_bound(this->blocks.begin(), this->blocks.end(), dst, [] (auto virt, const auto &block) {
|
||||
return virt < block.virt;
|
||||
})};
|
||||
|
||||
auto srcPredecessor{std::prev(srcSuccessor)};
|
||||
auto dstPredecessor{std::prev(dstSuccessor)};
|
||||
|
||||
u8 *srcBlockPhys{srcPredecessor->phys + (src - srcPredecessor->virt)};
|
||||
u8 *dstBlockPhys{dstPredecessor->phys + (dst - dstPredecessor->virt)};
|
||||
|
||||
VaType srcBlockRemainingSize{srcSuccessor->virt - src};
|
||||
VaType dstBlockRemainingSize{dstSuccessor->virt - dst};
|
||||
|
||||
VaType blockCopySize{std::min({srcBlockRemainingSize, dstBlockRemainingSize, size})};
|
||||
|
||||
// Writes may span across multiple individual blocks
|
||||
while (size) {
|
||||
if (srcPredecessor->phys == nullptr) {
|
||||
throw exception("Page fault at 0x{:X}", srcPredecessor->virt);
|
||||
} else if (dstPredecessor->phys == nullptr) {
|
||||
throw exception("Page fault at 0x{:X}", dstPredecessor->virt);
|
||||
} else { [[likely]]
|
||||
if (srcPredecessor->extraInfo.sparseMapped) {
|
||||
std::memset(dstBlockPhys, 0, blockCopySize);
|
||||
} else [[likely]] {
|
||||
if (cpuAccessCallback) {
|
||||
cpuAccessCallback(span{dstBlockPhys, blockCopySize});
|
||||
cpuAccessCallback(span{srcBlockPhys, blockCopySize});
|
||||
}
|
||||
|
||||
std::memcpy(dstBlockPhys, srcBlockPhys, blockCopySize);
|
||||
}
|
||||
}
|
||||
|
||||
dstBlockPhys += blockCopySize;
|
||||
srcBlockPhys += blockCopySize;
|
||||
size -= blockCopySize;
|
||||
srcBlockRemainingSize -= blockCopySize;
|
||||
dstBlockRemainingSize -= blockCopySize;
|
||||
|
||||
if (size) {
|
||||
if (!srcBlockRemainingSize) {
|
||||
srcPredecessor = srcSuccessor++;
|
||||
srcBlockPhys = srcPredecessor->phys;
|
||||
srcBlockRemainingSize = srcSuccessor->virt - srcPredecessor->virt;
|
||||
blockCopySize = std::min({srcBlockRemainingSize, dstBlockRemainingSize, size});
|
||||
}
|
||||
if (!dstBlockRemainingSize) {
|
||||
dstPredecessor = dstSuccessor++;
|
||||
dstBlockPhys = dstPredecessor->phys;
|
||||
dstBlockRemainingSize = dstSuccessor->virt - dstPredecessor->virt;
|
||||
blockCopySize = std::min({srcBlockRemainingSize, dstBlockRemainingSize, size});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ALLOC_MEMBER()::FlatAllocator(VaType vaStart, VaType vaLimit) : Base(vaLimit), vaStart(vaStart), currentLinearAllocEnd(vaStart) {}
|
||||
|
||||
ALLOC_MEMBER(VaType)::Allocate(VaType size) {
|
||||
TRACE_EVENT("containers", "FlatAllocator::Allocate");
|
||||
|
||||
std::scoped_lock lock(this->blockMutex);
|
||||
|
||||
VaType allocStart{UnmappedVa};
|
||||
VaType allocEnd{currentLinearAllocEnd + size};
|
||||
|
||||
// Avoid searching backwards in the address space if possible
|
||||
if (allocEnd >= currentLinearAllocEnd && allocEnd <= this->vaLimit) {
|
||||
auto allocEndSuccessor{std::lower_bound(this->blocks.begin(), this->blocks.end(), allocEnd)};
|
||||
if (allocEndSuccessor == this->blocks.begin())
|
||||
throw exception("First block in AS map is invalid!");
|
||||
|
||||
auto allocEndPredecessor{std::prev(allocEndSuccessor)};
|
||||
if (allocEndPredecessor->virt <= currentLinearAllocEnd) {
|
||||
allocStart = currentLinearAllocEnd;
|
||||
} else {
|
||||
// Skip over fixed any mappings in front of us
|
||||
while (allocEndSuccessor != this->blocks.end()) {
|
||||
if (allocEndSuccessor->virt - allocEndPredecessor->virt < size || allocEndPredecessor->Mapped() ) {
|
||||
allocStart = allocEndPredecessor->virt;
|
||||
break;
|
||||
}
|
||||
|
||||
allocEndPredecessor = allocEndSuccessor++;
|
||||
|
||||
// Use the VA limit to calculate if we can fit in the final block since it has no successor
|
||||
if (allocEndSuccessor == this->blocks.end()) {
|
||||
allocEnd = allocEndPredecessor->virt + size;
|
||||
|
||||
if (allocEnd >= allocEndPredecessor->virt && allocEnd <= this->vaLimit)
|
||||
allocStart = allocEndPredecessor->virt;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (allocStart != UnmappedVa) {
|
||||
currentLinearAllocEnd = allocStart + size;
|
||||
} else { // If linear allocation overflows the AS then find a gap
|
||||
if (this->blocks.size() <= 2)
|
||||
throw exception("Unexpected allocator state!");
|
||||
|
||||
auto searchPredecessor{std::next(this->blocks.begin())};
|
||||
auto searchSuccessor{std::next(searchPredecessor)};
|
||||
|
||||
while (searchSuccessor != this->blocks.end() &&
|
||||
(searchSuccessor->virt - searchPredecessor->virt < size || searchPredecessor->Mapped())) {
|
||||
searchPredecessor = searchSuccessor++;
|
||||
}
|
||||
|
||||
if (searchSuccessor != this->blocks.end())
|
||||
allocStart = searchPredecessor->virt;
|
||||
else
|
||||
return {}; // AS is full
|
||||
}
|
||||
|
||||
|
||||
this->MapLocked(allocStart, true, size, {});
|
||||
return allocStart;
|
||||
}
|
||||
|
||||
ALLOC_MEMBER(void)::AllocateFixed(VaType virt, VaType size) {
|
||||
std::scoped_lock lock(this->blockMutex);
|
||||
this->MapLocked(virt, true, size, {});
|
||||
}
|
||||
|
||||
ALLOC_MEMBER(void)::Free(VaType virt, VaType size) {
|
||||
std::scoped_lock lock(this->blockMutex);
|
||||
this->UnmapLocked(virt, size);
|
||||
}
|
||||
}
|
|
@ -1,56 +0,0 @@
|
|||
// SPDX-License-Identifier: MPL-2.0
|
||||
// Copyright © 2022 Skyline Team and Contributors (https://github.com/skyline-emu/)
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "settings.h"
|
||||
#include "jvm.h"
|
||||
|
||||
namespace skyline {
|
||||
/**
|
||||
* @brief Handles settings on the android platform
|
||||
* @note Lifetime of this class must not exceed the one of the JNIEnv contained inside ktSettings
|
||||
*/
|
||||
class AndroidSettings final : public Settings {
|
||||
private:
|
||||
KtSettings ktSettings;
|
||||
|
||||
public:
|
||||
/**
|
||||
* @note Will construct the underlying KtSettings object in-place
|
||||
*/
|
||||
AndroidSettings(JNIEnv *env, jobject settingsInstance) : ktSettings(env, settingsInstance) {
|
||||
Update();
|
||||
}
|
||||
|
||||
/**
|
||||
* @note Will take ownership of the passed KtSettings object
|
||||
*/
|
||||
AndroidSettings(KtSettings &&ktSettings) : ktSettings(std::move(ktSettings)) {
|
||||
Update();
|
||||
}
|
||||
|
||||
void Update() override {
|
||||
isDocked = ktSettings.GetBool("isDocked");
|
||||
usernameValue = std::move(ktSettings.GetString("usernameValue"));
|
||||
profilePictureValue = ktSettings.GetString("profilePictureValue");
|
||||
systemLanguage = ktSettings.GetInt<skyline::language::SystemLanguage>("systemLanguage");
|
||||
systemRegion = ktSettings.GetInt<skyline::region::RegionCode>("systemRegion");
|
||||
forceTripleBuffering = ktSettings.GetBool("forceTripleBuffering");
|
||||
disableFrameThrottling = ktSettings.GetBool("disableFrameThrottling");
|
||||
gpuDriver = ktSettings.GetString("gpuDriver");
|
||||
gpuDriverLibraryName = ktSettings.GetString("gpuDriverLibraryName");
|
||||
executorSlotCountScale = ktSettings.GetInt<u32>("executorSlotCountScale");
|
||||
executorFlushThreshold = ktSettings.GetInt<u32>("executorFlushThreshold");
|
||||
useDirectMemoryImport = ktSettings.GetBool("useDirectMemoryImport");
|
||||
forceMaxGpuClocks = ktSettings.GetBool("forceMaxGpuClocks");
|
||||
disableShaderCache = ktSettings.GetBool("disableShaderCache");
|
||||
freeGuestTextureMemory = ktSettings.GetBool("freeGuestTextureMemory");
|
||||
enableFastGpuReadbackHack = ktSettings.GetBool("enableFastGpuReadbackHack");
|
||||
enableFastReadbackWrites = ktSettings.GetBool("enableFastReadbackWrites");
|
||||
disableSubgroupShuffle = ktSettings.GetBool("disableSubgroupShuffle");
|
||||
isAudioOutputDisabled = ktSettings.GetBool("isAudioOutputDisabled");
|
||||
validationLayer = ktSettings.GetBool("validationLayer");
|
||||
};
|
||||
};
|
||||
}
|
|
@ -1,110 +0,0 @@
|
|||
// SPDX-License-Identifier: MPL-2.0
|
||||
// Copyright © 2022 Skyline Team and Contributors (https://github.com/skyline-emu/)
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <atomic>
|
||||
|
||||
namespace skyline {
|
||||
/**
|
||||
* @brief A singly-linked list with atomic access to allow for lock-free access semantics
|
||||
*/
|
||||
template<typename Type>
|
||||
class AtomicForwardList {
|
||||
private:
|
||||
struct Node {
|
||||
Node *next;
|
||||
Type value;
|
||||
};
|
||||
|
||||
std::atomic<Node *> head{}; //!< The head of the list
|
||||
|
||||
public:
|
||||
AtomicForwardList() = default;
|
||||
|
||||
AtomicForwardList(const AtomicForwardList &) = delete;
|
||||
|
||||
AtomicForwardList(AtomicForwardList &&other) {
|
||||
head = other.head.load();
|
||||
while (!other.head.compare_exchange_strong(head, nullptr, std::memory_order_release, std::memory_order_consume));
|
||||
}
|
||||
|
||||
~AtomicForwardList() {
|
||||
Clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Clears all the items from the list while deallocating them
|
||||
*/
|
||||
void Clear() {
|
||||
auto current{head.exchange(nullptr, std::memory_order_acquire)};
|
||||
while (current) {
|
||||
auto next{current->next};
|
||||
delete current;
|
||||
current = next;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Appends an item to the start of the list
|
||||
*/
|
||||
void Append(Type item) {
|
||||
auto node{new Node{nullptr, item}};
|
||||
auto next{head.load(std::memory_order_consume)};
|
||||
do {
|
||||
node->next = next;
|
||||
} while (!head.compare_exchange_strong(next, node, std::memory_order_release, std::memory_order_consume));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Appends multiple items to the start of the list
|
||||
*/
|
||||
void Append(std::initializer_list<Type> items) {
|
||||
if (std::empty(items))
|
||||
return;
|
||||
|
||||
Node* firstNode{new Node{nullptr, *items.begin()}};
|
||||
Node* lastNode{firstNode};
|
||||
for (auto item{items.begin() + 1}; item != items.end(); item++)
|
||||
lastNode = new Node{lastNode, *item};
|
||||
|
||||
auto next{head.load(std::memory_order_consume)};
|
||||
do {
|
||||
firstNode->next = next;
|
||||
} while (!head.compare_exchange_strong(next, lastNode, std::memory_order_release, std::memory_order_consume));
|
||||
}
|
||||
|
||||
template<typename... Items>
|
||||
void Append(Items &&... items) {
|
||||
Append(std::initializer_list<Type>{std::forward<Items>(items)...});
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Iterates over every single list item and calls the given function
|
||||
* @note This function is **not** thread-safe when used with Clear() as the item may be deallocated while iterating
|
||||
*/
|
||||
template <typename Function>
|
||||
void Iterate(Function function) {
|
||||
auto current{head.load(std::memory_order_consume)};
|
||||
while (current) {
|
||||
function(current->value);
|
||||
current = current->next;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Iterates over every single list item and calls the given function till the given predicate returns false
|
||||
* @note This function is **not** thread-safe when used with Clear() as the item may be deallocated while iterating
|
||||
*/
|
||||
template <typename Function>
|
||||
bool AllOf(Function function) {
|
||||
auto current{head.load(std::memory_order_consume)};
|
||||
while (current) {
|
||||
if (!function(current->value))
|
||||
return false;
|
||||
current = current->next;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
}
|
|
@ -1,85 +0,0 @@
|
|||
// SPDX-License-Identifier: MPL-2.0
|
||||
// Copyright © 2021 Skyline Team and Contributors (https://github.com/skyline-emu/)
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <stdexcept>
|
||||
#include <variant>
|
||||
#include <bitset>
|
||||
#include <fmt/format.h>
|
||||
|
||||
namespace fmt {
|
||||
/**
|
||||
* @brief A std::bitset formatter for {fmt}
|
||||
*/
|
||||
template<size_t N>
|
||||
struct formatter<std::bitset<N>> : formatter<std::string> {
|
||||
template<typename FormatContext>
|
||||
constexpr auto format(const std::bitset<N> &s, FormatContext &ctx) {
|
||||
return formatter<std::string>::format(s.to_string(), ctx);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
namespace skyline {
|
||||
using u128 = __uint128_t; //!< Unsigned 128-bit integer
|
||||
using u64 = __uint64_t; //!< Unsigned 64-bit integer
|
||||
using u32 = __uint32_t; //!< Unsigned 32-bit integer
|
||||
using u16 = __uint16_t; //!< Unsigned 16-bit integer
|
||||
using u8 = __uint8_t; //!< Unsigned 8-bit integer
|
||||
using i128 = __int128_t; //!< Signed 128-bit integer
|
||||
using i64 = __int64_t; //!< Signed 64-bit integer
|
||||
using i32 = __int32_t; //!< Signed 32-bit integer
|
||||
using i16 = __int16_t; //!< Signed 16-bit integer
|
||||
using i8 = __int8_t; //!< Signed 8-bit integer
|
||||
|
||||
using KHandle = u32; //!< The type of a kernel handle
|
||||
|
||||
namespace constant {
|
||||
// Time
|
||||
constexpr i64 NsInMicrosecond{1000}; //!< The amount of nanoseconds in a microsecond
|
||||
constexpr i64 NsInSecond{1000000000}; //!< The amount of nanoseconds in a second
|
||||
constexpr i64 NsInMillisecond{1000000}; //!< The amount of nanoseconds in a millisecond
|
||||
constexpr i64 NsInDay{86400000000000UL}; //!< The amount of nanoseconds in a day
|
||||
|
||||
constexpr size_t AddressSpaceSize{1ULL << 39}; //!< The size of the host CPU AS in bytes
|
||||
constexpr size_t PageSize{0x1000}; //!< The size of a host page
|
||||
constexpr size_t PageSizeBits{12}; //!< log2(PageSize)
|
||||
|
||||
static_assert(PageSize == PAGE_SIZE);
|
||||
}
|
||||
|
||||
namespace util {
|
||||
/**
|
||||
* @brief A way to implicitly cast all pointers to uintptr_t, this is used for {fmt} as we use 0x{:X} to print pointers
|
||||
* @note There's the exception of signed char pointers as they represent C Strings
|
||||
* @note This does not cover std::shared_ptr or std::unique_ptr and those will have to be explicitly casted to uintptr_t or passed through fmt::ptr
|
||||
*/
|
||||
template<typename T>
|
||||
constexpr auto FmtCast(T object) {
|
||||
if constexpr (std::is_pointer<T>::value)
|
||||
if constexpr (std::is_same<char, typename std::remove_cv<typename std::remove_pointer<T>::type>::type>::value)
|
||||
return reinterpret_cast<typename std::common_type<char *, T>::type>(object);
|
||||
else
|
||||
return reinterpret_cast<const uintptr_t>(object);
|
||||
else
|
||||
return object;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief {fmt}::format but with FmtCast built into it
|
||||
*/
|
||||
template<typename S, typename... Args>
|
||||
constexpr auto Format(S formatString, Args &&... args) {
|
||||
return fmt::format(fmt::runtime(formatString), FmtCast(args)...);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief A deduction guide for overloads required for std::visit with std::variant
|
||||
*/
|
||||
template<class... Ts>
|
||||
struct VariantVisitor : Ts ... { using Ts::operator()...; };
|
||||
template<class... Ts> VariantVisitor(Ts...) -> VariantVisitor<Ts...>;
|
||||
}
|
|
@ -28,9 +28,8 @@ namespace skyline {
|
|||
* @param copyOffset The offset into the buffer after which to use memcpy rather than copyFunction, -1 will use it for the entire buffer
|
||||
* @return The amount of data written into the input buffer in units of Type
|
||||
*/
|
||||
template<typename CopyFunc>
|
||||
size_t Read(span <Type> buffer, CopyFunc copyFunction) {
|
||||
std::scoped_lock guard{mtx};
|
||||
size_t Read(span <Type> buffer, void copyFunction(Type *, Type *) = {}, ssize_t copyOffset = -1) {
|
||||
std::lock_guard guard(mtx);
|
||||
|
||||
if (empty)
|
||||
return 0;
|
||||
|
@ -49,19 +48,38 @@ namespace skyline {
|
|||
size = sizeBegin + sizeEnd;
|
||||
}
|
||||
|
||||
{
|
||||
auto sourceEnd{start + sizeEnd};
|
||||
if (copyFunction && copyOffset) {
|
||||
auto sourceEnd{start + ((copyOffset != -1) ? copyOffset : sizeEnd)};
|
||||
|
||||
for (; start < sourceEnd; start++, pointer++)
|
||||
copyFunction(start, pointer);
|
||||
for (auto source{start}, destination{pointer}; source < sourceEnd; source++, destination++)
|
||||
copyFunction(source, destination);
|
||||
|
||||
if (copyOffset != -1) {
|
||||
std::memcpy(pointer + copyOffset, start + copyOffset, (sizeEnd - copyOffset) * sizeof(Type));
|
||||
copyOffset -= sizeEnd;
|
||||
}
|
||||
} else {
|
||||
std::memcpy(pointer, start, sizeEnd * sizeof(Type));
|
||||
}
|
||||
|
||||
if (sizeBegin) {
|
||||
start = array.begin();
|
||||
auto sourceEnd{array.begin() + sizeBegin};
|
||||
pointer += sizeEnd;
|
||||
|
||||
for (; start < sourceEnd; start++, pointer++)
|
||||
copyFunction(start, pointer);
|
||||
if (sizeBegin) {
|
||||
if (copyFunction && copyOffset) {
|
||||
auto sourceEnd{array.begin() + ((copyOffset != -1) ? copyOffset : sizeBegin)};
|
||||
|
||||
for (auto source{array.begin()}, destination{pointer}; source < sourceEnd; source++, destination++)
|
||||
copyFunction(source, destination);
|
||||
|
||||
if (copyOffset != -1)
|
||||
std::memcpy(array.begin() + copyOffset, pointer + copyOffset, (sizeBegin - copyOffset) * sizeof(Type));
|
||||
} else {
|
||||
std::memcpy(pointer, array.begin(), sizeBegin * sizeof(Type));
|
||||
}
|
||||
|
||||
start = array.begin() + sizeBegin;
|
||||
} else {
|
||||
start += sizeEnd;
|
||||
}
|
||||
|
||||
if (start == end)
|
||||
|
@ -74,27 +92,51 @@ namespace skyline {
|
|||
* @brief Appends data from the specified buffer into this buffer
|
||||
*/
|
||||
void Append(span <Type> buffer) {
|
||||
std::scoped_lock guard{mtx};
|
||||
std::lock_guard guard(mtx);
|
||||
|
||||
Type *pointer{buffer.data()};
|
||||
ssize_t remainingSize{static_cast<ssize_t>(buffer.size())};
|
||||
while (remainingSize) {
|
||||
ssize_t writeSize{std::min([&]() {
|
||||
if (start <= end)
|
||||
return array.end() - end;
|
||||
else
|
||||
return start - end - 1;
|
||||
}(), remainingSize)};
|
||||
ssize_t size{static_cast<ssize_t>(buffer.size())};
|
||||
while (size) {
|
||||
if (start <= end && end != array.end()) {
|
||||
auto sizeEnd{std::min(array.end() - end, size)};
|
||||
std::memcpy(end, pointer, sizeEnd * sizeof(Type));
|
||||
|
||||
if (writeSize) {
|
||||
std::memcpy(end, pointer, static_cast<size_t>(writeSize) * sizeof(Type));
|
||||
remainingSize -= writeSize;
|
||||
end += writeSize;
|
||||
pointer += writeSize;
|
||||
pointer += sizeEnd;
|
||||
size -= sizeEnd;
|
||||
|
||||
end += sizeEnd;
|
||||
} else {
|
||||
auto sizePreStart{(end == array.end()) ? std::min(start - array.begin(), size) : std::min(start - end, size)};
|
||||
auto sizePostStart{std::min(array.end() - start, size - sizePreStart)};
|
||||
|
||||
if (sizePreStart)
|
||||
std::memcpy((end == array.end()) ? array.begin() : end, pointer, sizePreStart * sizeof(Type));
|
||||
|
||||
if (end == array.end())
|
||||
end = array.begin() + sizePreStart;
|
||||
else
|
||||
end += sizePreStart;
|
||||
|
||||
pointer += sizePreStart;
|
||||
size -= sizePreStart;
|
||||
|
||||
if (sizePostStart)
|
||||
std::memcpy(end, pointer, sizePostStart * sizeof(Type));
|
||||
|
||||
if (start == array.end())
|
||||
start = array.begin() + sizePostStart;
|
||||
else
|
||||
start += sizePostStart;
|
||||
|
||||
if (end == array.end())
|
||||
end = array.begin() + sizePostStart;
|
||||
else
|
||||
end += sizePostStart;
|
||||
|
||||
pointer += sizePostStart;
|
||||
size -= sizePostStart;
|
||||
}
|
||||
|
||||
if (end == array.end())
|
||||
end = array.begin();
|
||||
empty = false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,8 +3,6 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <common/trace.h>
|
||||
#include <common/spin_lock.h>
|
||||
#include <common.h>
|
||||
|
||||
namespace skyline {
|
||||
|
@ -15,12 +13,12 @@ namespace skyline {
|
|||
class CircularQueue {
|
||||
private:
|
||||
std::vector<u8> vector; //!< The internal vector holding the circular queue's data, we use a byte vector due to the default item construction/destruction semantics not being appropriate for a circular buffer
|
||||
std::atomic<Type *> start{reinterpret_cast<Type *>(vector.begin().base())}; //!< The start/oldest element of the queue
|
||||
std::atomic<Type *> end{reinterpret_cast<Type *>(vector.begin().base())}; //!< The end/newest element of the queue
|
||||
SpinLock consumptionMutex;
|
||||
std::condition_variable_any consumeCondition;
|
||||
SpinLock productionMutex;
|
||||
std::condition_variable_any produceCondition;
|
||||
Type *start{reinterpret_cast<Type *>(vector.begin().base())}; //!< The start/oldest element of the queue
|
||||
Type *end{reinterpret_cast<Type *>(vector.begin().base())}; //!< The end/newest element of the queue
|
||||
std::mutex consumptionMutex;
|
||||
std::condition_variable consumeCondition;
|
||||
std::mutex productionMutex;
|
||||
std::condition_variable produceCondition;
|
||||
|
||||
public:
|
||||
/**
|
||||
|
@ -50,22 +48,15 @@ namespace skyline {
|
|||
/**
|
||||
* @brief A blocking for-each that runs on every item and waits till new items to run on them as well
|
||||
* @param function A function that is called for each item (with the only parameter as a reference to that item)
|
||||
* @param preWait An optional function that's called prior to waiting on more items to be queued
|
||||
*/
|
||||
template<typename F1, typename F2>
|
||||
[[noreturn]] void Process(F1 function, F2 preWait) {
|
||||
TRACE_EVENT_BEGIN("containers", "CircularQueue::Process");
|
||||
|
||||
template<typename F>
|
||||
[[noreturn]] void Process(F function) {
|
||||
while (true) {
|
||||
if (start == end) {
|
||||
std::unique_lock productionLock{productionMutex};
|
||||
TRACE_EVENT_END("containers");
|
||||
preWait();
|
||||
produceCondition.wait(productionLock, [this]() { return start != end; });
|
||||
TRACE_EVENT_BEGIN("containers", "CircularQueue::Process");
|
||||
std::unique_lock lock(productionMutex);
|
||||
produceCondition.wait(lock, [this]() { return start != end; });
|
||||
}
|
||||
|
||||
std::scoped_lock comsumptionLock{consumptionMutex};
|
||||
while (start != end) {
|
||||
auto next{start + 1};
|
||||
next = (next == reinterpret_cast<Type *>(vector.end().base())) ? reinterpret_cast<Type *>(vector.begin().base()) : next;
|
||||
|
@ -77,58 +68,30 @@ namespace skyline {
|
|||
}
|
||||
}
|
||||
|
||||
Type Pop() {
|
||||
{
|
||||
std::unique_lock productionLock{productionMutex};
|
||||
produceCondition.wait(productionLock, [this]() { return start != end; });
|
||||
void Push(const Type &item) {
|
||||
std::unique_lock lock(productionMutex);
|
||||
end = (end == reinterpret_cast<Type *>(vector.end().base()) - 1) ? reinterpret_cast<Type *>(vector.begin().base()) : end;
|
||||
if (start == end + 1) {
|
||||
std::unique_lock consumeLock(consumptionMutex);
|
||||
consumeCondition.wait(consumeLock, [=]() { return start != end + 1; });
|
||||
}
|
||||
|
||||
std::scoped_lock comsumptionLock{consumptionMutex};
|
||||
auto next{start + 1};
|
||||
next = (next == reinterpret_cast<Type *>(vector.end().base())) ? reinterpret_cast<Type *>(vector.begin().base()) : next;
|
||||
Type item{*next};
|
||||
start = next;
|
||||
|
||||
consumeCondition.notify_one();
|
||||
|
||||
return item;
|
||||
*end = item;
|
||||
produceCondition.notify_one();
|
||||
}
|
||||
|
||||
void Push(const Type &item) {
|
||||
Type *waitNext{};
|
||||
Type *waitEnd{};
|
||||
|
||||
while (true) {
|
||||
if (waitNext) {
|
||||
std::unique_lock consumeLock{consumptionMutex};
|
||||
|
||||
consumeCondition.wait(consumeLock, [=]() { return waitNext != start || waitEnd != end; });
|
||||
waitNext = nullptr;
|
||||
waitEnd = nullptr;
|
||||
}
|
||||
|
||||
std::scoped_lock lock{productionMutex};
|
||||
void Append(span <Type> buffer) {
|
||||
std::unique_lock lock(productionMutex);
|
||||
for (const auto &item : buffer) {
|
||||
auto next{end + 1};
|
||||
next = (next == reinterpret_cast<Type *>(vector.end().base())) ? reinterpret_cast<Type *>(vector.begin().base()) : next;
|
||||
if (next == start) {
|
||||
waitNext = next;
|
||||
waitEnd = end;
|
||||
continue;
|
||||
std::unique_lock consumeLock(consumptionMutex);
|
||||
consumeCondition.wait(consumeLock, [=]() { return next != start; });
|
||||
}
|
||||
*next = item;
|
||||
end = next;
|
||||
produceCondition.notify_one();
|
||||
break;
|
||||
end = next++;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @note The appended elements may not necessarily be directly contiguous as another thread could push elements in between those in the span
|
||||
*/
|
||||
void Append(span<Type> buffer) {
|
||||
for (const auto &item : buffer)
|
||||
Push(item);
|
||||
produceCondition.notify_one();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -136,9 +99,19 @@ namespace skyline {
|
|||
* @param tranformation A function that takes in an item of TransformedType as input and returns an item of Type
|
||||
*/
|
||||
template<typename TransformedType, typename Transformation>
|
||||
void AppendTranform(TransformedType &container, Transformation transformation) {
|
||||
for (const auto &item : container)
|
||||
Push(transformation(item));
|
||||
void AppendTranform(span <TransformedType> buffer, Transformation transformation) {
|
||||
std::unique_lock lock(productionMutex);
|
||||
for (const auto &item : buffer) {
|
||||
auto next{end + 1};
|
||||
next = (next == reinterpret_cast<Type *>(vector.end().base())) ? reinterpret_cast<Type *>(vector.begin().base()) : next;
|
||||
if (next == start) {
|
||||
std::unique_lock consumeLock(consumptionMutex);
|
||||
consumeCondition.wait(consumeLock, [=]() { return next != start; });
|
||||
}
|
||||
*next = transformation(item);
|
||||
end = next;
|
||||
}
|
||||
produceCondition.notify_one();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1,261 +0,0 @@
|
|||
// SPDX-License-Identifier: MPL-2.0
|
||||
// Copyright © 2022 Skyline Team and Contributors (https://github.com/skyline-emu/)
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "base.h"
|
||||
#include "exception.h"
|
||||
#include "logger.h"
|
||||
#include "span.h"
|
||||
|
||||
namespace skyline::dirty {
|
||||
template<size_t, size_t, size_t>
|
||||
class Manager;
|
||||
|
||||
/**
|
||||
* @brief An opaque handle to a dirty subresource
|
||||
*/
|
||||
struct Handle {
|
||||
private:
|
||||
template<size_t, size_t, size_t>
|
||||
friend class Manager;
|
||||
|
||||
bool *dirtyPtr; //!< Underlying target ptr
|
||||
|
||||
public:
|
||||
explicit Handle(bool *dirtyPtr) : dirtyPtr{dirtyPtr} {}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Implements a way to track dirty subresources within a region of memory
|
||||
* @tparam ManagedResourceSize Size of the managed resource in bytes
|
||||
* @tparam Granularity Minimum granularity of a subresource in bytes
|
||||
* @tparam OverlapPoolSize Size of the pool used to store handles when there are multiple bound to the same subresource
|
||||
* @note This class is *NOT* thread-safe
|
||||
*/
|
||||
template<size_t ManagedResourceSize, size_t Granularity, size_t OverlapPoolSize = 0x2000>
|
||||
class Manager {
|
||||
private:
|
||||
struct BindingState {
|
||||
enum class Type : u32 {
|
||||
None, //!< No handles are bound
|
||||
Inline, //!< `inlineDirtyPtr` contains a pointer to the single bound handle for the entry
|
||||
OverlapSpan, //!< `overlapSpanDirtyPtrs` contains an array of pointers to handles bound to the entry
|
||||
} type{Type::None};
|
||||
u32 overlapSpanSize{}; //!< Size of the array that overlapSpanDirtyPtrs points to
|
||||
|
||||
union {
|
||||
bool *inlineDirtyPtr;
|
||||
bool **overlapSpanDirtyPtrs;
|
||||
};
|
||||
|
||||
/**
|
||||
* @return An array of pointers to handles bound to the entry
|
||||
*/
|
||||
span<bool *> GetOverlapSpan() {
|
||||
return {overlapSpanDirtyPtrs, overlapSpanSize};
|
||||
}
|
||||
};
|
||||
|
||||
std::array<bool *, OverlapPoolSize> overlapPool{}; //!< Backing pool for `overlapSpanDirtyPtrs` in entry
|
||||
bool **freeOverlapPtr{}; //!< Pointer to the next free entry in `overlapPool`
|
||||
|
||||
std::array<BindingState, ManagedResourceSize / Granularity> states{}; //!< The dirty binding states for the entire managed resource
|
||||
|
||||
uintptr_t managedResourceBaseAddress; //!< The base address of the managed resource
|
||||
|
||||
public:
|
||||
template<typename ManagedResourceType> requires (std::is_standard_layout_v<ManagedResourceType> && sizeof(ManagedResourceType) == ManagedResourceSize)
|
||||
Manager(ManagedResourceType &managedResource) : managedResourceBaseAddress{reinterpret_cast<uintptr_t>(&managedResource)}, freeOverlapPtr{overlapPool.data()} {}
|
||||
|
||||
/**
|
||||
* @brief Binds a handle to a subresource, automatically handling overlaps
|
||||
*/
|
||||
void Bind(Handle handle, uintptr_t subresourceAddress, size_t subresourceSizeBytes) {
|
||||
if (managedResourceBaseAddress > subresourceAddress)
|
||||
throw exception("Dirty subresource address is below the managed resource base address");
|
||||
|
||||
size_t subresourceAddressOffset{subresourceAddress - managedResourceBaseAddress};
|
||||
|
||||
// Validate
|
||||
if (subresourceAddressOffset < 0 || (subresourceAddressOffset + subresourceSizeBytes) >= ManagedResourceSize)
|
||||
throw exception("Dirty subresource address is not within the managed resource");
|
||||
|
||||
if (subresourceSizeBytes % Granularity)
|
||||
throw exception("Dirty subresource size isn't aligned to the tracking granularity");
|
||||
|
||||
if (subresourceAddressOffset % Granularity)
|
||||
throw exception("Dirty subresource offset isn't aligned to the tracking granularity");
|
||||
|
||||
// Insert
|
||||
size_t subresourceIndex{static_cast<size_t>(subresourceAddressOffset / Granularity)};
|
||||
size_t subresourceSize{subresourceSizeBytes / Granularity};
|
||||
|
||||
for (size_t i{subresourceIndex}; i < subresourceIndex + subresourceSize; i++) {
|
||||
auto &state{states[i]};
|
||||
|
||||
if (state.type == BindingState::Type::None) {
|
||||
state.type = BindingState::Type::Inline;
|
||||
state.inlineDirtyPtr = handle.dirtyPtr;
|
||||
} else if (state.type == BindingState::Type::Inline) {
|
||||
state.type = BindingState::Type::OverlapSpan;
|
||||
|
||||
// Save the old inline dirty pointer since we'll need to insert it into the new overlap span and setting the overlap span ptr will overwrite it
|
||||
bool *origDirtyPtr{state.inlineDirtyPtr};
|
||||
|
||||
// Point to a new pool allocation that can hold the overlap
|
||||
state.overlapSpanDirtyPtrs = freeOverlapPtr;
|
||||
state.overlapSpanSize = 2; // Existing inline handle + our new handle
|
||||
|
||||
// Check if the pool allocation is valid
|
||||
if (freeOverlapPtr + state.overlapSpanSize >= overlapPool.end())
|
||||
throw exception("Dirty overlap pool is full");
|
||||
|
||||
// Write overlap to our new pool allocation
|
||||
*freeOverlapPtr++ = origDirtyPtr;
|
||||
*freeOverlapPtr++ = handle.dirtyPtr;
|
||||
} else if (state.type == BindingState::Type::OverlapSpan) {
|
||||
auto originalOverlapSpan{state.GetOverlapSpan()};
|
||||
|
||||
// Point to a new pool allocation that can hold all the old overlaps + our new overlap
|
||||
state.overlapSpanSize++;
|
||||
state.overlapSpanDirtyPtrs = freeOverlapPtr;
|
||||
|
||||
// Check if the pool allocation is valid
|
||||
if (freeOverlapPtr + state.overlapSpanSize >= overlapPool.end())
|
||||
throw exception("Dirty overlap pool is full");
|
||||
|
||||
// Write all overlaps to our new pool allocation
|
||||
auto newOverlapSpan{state.GetOverlapSpan()};
|
||||
newOverlapSpan.copy_from(originalOverlapSpan); // Copy old overlaps
|
||||
*newOverlapSpan.last(1).data() = handle.dirtyPtr; // Write new overlap
|
||||
freeOverlapPtr += state.overlapSpanSize;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<typename SubresourceType> requires std::is_standard_layout_v<SubresourceType>
|
||||
void Bind(Handle handle, SubresourceType &subresource) {
|
||||
Bind(handle, reinterpret_cast<uintptr_t>(&subresource), sizeof(SubresourceType));
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
void Bind(Handle handle, Args && ...subresources) {
|
||||
(Bind(handle, subresources), ...);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Marks part of the managed resource as dirty
|
||||
* @note This *MUST NOT* be called after any bound handles have been destroyed
|
||||
*/
|
||||
void MarkDirty(size_t index) {
|
||||
auto &state{states[index]};
|
||||
if (state.type == BindingState::Type::None) [[likely]] {
|
||||
return;
|
||||
} else if (state.type == BindingState::Type::Inline) {
|
||||
*state.inlineDirtyPtr = true;
|
||||
} else if (state.type == BindingState::Type::OverlapSpan) [[unlikely]] {
|
||||
for (auto &dirtyPtr : state.GetOverlapSpan())
|
||||
*dirtyPtr = true;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Encapsulates a dirty subresource to allow for automatic binding on construction
|
||||
*/
|
||||
template<typename T>
|
||||
class BoundSubresource {
|
||||
private:
|
||||
const T subresource;
|
||||
|
||||
public:
|
||||
template<typename ManagerT>
|
||||
BoundSubresource(ManagerT &manager, dirty::Handle handle, const T &subresource) : subresource{subresource} {
|
||||
subresource.DirtyBind(manager, handle);
|
||||
}
|
||||
|
||||
const T *operator->() const {
|
||||
return &subresource;
|
||||
}
|
||||
|
||||
const T &operator*() const {
|
||||
return subresource;
|
||||
}
|
||||
};
|
||||
|
||||
class ManualDirty {};
|
||||
|
||||
/**
|
||||
* @brief ManualDirty but with a `Refresh()` method that should be called for every `Update()`, irrespective of dirty state
|
||||
*/
|
||||
class RefreshableManualDirty : ManualDirty {};
|
||||
|
||||
/**
|
||||
* @brief ManualDirty but with a `PurgeCaches()` method to purge caches that would usually be kept even after being marked dirty
|
||||
*/
|
||||
class CachedManualDirty : ManualDirty {};
|
||||
|
||||
/**
|
||||
* @brief Wrapper around an object that holds dirty state and provides convinient functionality for dirty tracking
|
||||
*/
|
||||
template<typename T> requires (std::is_base_of_v<ManualDirty, T>)
|
||||
class ManualDirtyState {
|
||||
private:
|
||||
T value; //!< The underlying object
|
||||
bool dirty{true}; //!< Whether the value is dirty
|
||||
|
||||
/**
|
||||
* @return An opaque handle that can be used to modify dirty state
|
||||
*/
|
||||
Handle GetDirtyHandle() {
|
||||
return Handle{&dirty};
|
||||
}
|
||||
|
||||
public:
|
||||
template<typename... Args>
|
||||
ManualDirtyState(Args &&... args) : value{GetDirtyHandle(), std::forward<Args>(args)...} {}
|
||||
|
||||
/**
|
||||
* @brief Cleans the object of its dirty state and refreshes it if necessary
|
||||
* @note This *MUST* be called before any accesses to the underlying object without *ANY* calls to `MarkDirty()` in between
|
||||
*/
|
||||
template<typename... Args>
|
||||
void Update(Args &&... args) {
|
||||
if (dirty) {
|
||||
dirty = false;
|
||||
value.Flush(std::forward<Args>(args)...);
|
||||
} else if constexpr (std::is_base_of_v<RefreshableManualDirty, T>) {
|
||||
if (value.Refresh(std::forward<Args>(args)...))
|
||||
value.Flush(std::forward<Args>(args)...);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Marks the object as dirty
|
||||
* @param purgeCaches Whether to purge caches of the object that would usually be kept even after being marked dirty
|
||||
*/
|
||||
void MarkDirty(bool purgeCaches) {
|
||||
dirty = true;
|
||||
|
||||
if constexpr (std::is_base_of_v<CachedManualDirty, T>)
|
||||
if (purgeCaches)
|
||||
value.PurgeCaches();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Returns a reference to the underlying object
|
||||
* @note `Update()` *MUST* be called before calling this, without *ANY* calls to `MarkDirty()` in between
|
||||
*/
|
||||
T &Get() {
|
||||
return value;
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
T &UpdateGet(Args &&... args) {
|
||||
Update(std::forward<Args>(args)...);
|
||||
return value;
|
||||
}
|
||||
};
|
||||
}
|
|
@ -1,20 +0,0 @@
|
|||
// SPDX-License-Identifier: MPL-2.0
|
||||
// Copyright © 2022 Skyline Team and Contributors (https://github.com/skyline-emu/)
|
||||
|
||||
#include "signal.h"
|
||||
#include "exception.h"
|
||||
|
||||
namespace skyline {
|
||||
std::vector<void *> exception::GetStackFrames() {
|
||||
std::vector<void*> frames;
|
||||
signal::StackFrame *frame{};
|
||||
asm("MOV %0, FP" : "=r"(frame));
|
||||
if (frame)
|
||||
frame = frame->next; // We want to skip the first frame as it's going to be the caller of this function
|
||||
while (frame && frame->lr) {
|
||||
frames.push_back(frame->lr);
|
||||
frame = frame->next;
|
||||
}
|
||||
return frames;
|
||||
}
|
||||
}
|
|
@ -1,26 +0,0 @@
|
|||
// SPDX-License-Identifier: MPL-2.0
|
||||
// Copyright © 2022 Skyline Team and Contributors (https://github.com/skyline-emu/)
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include "base.h"
|
||||
|
||||
namespace skyline {
|
||||
/**
|
||||
* @brief A wrapper over std::runtime_error with {fmt} formatting and stack tracing support
|
||||
*/
|
||||
class exception : public std::runtime_error {
|
||||
public:
|
||||
std::vector<void *> frames; //!< All frames from the stack trace during the exception
|
||||
|
||||
/**
|
||||
* @return A vector of all frames on the caller's stack
|
||||
* @note This cannot be inlined because it depends on having one stack frame itself consistently
|
||||
*/
|
||||
static std::vector<void*> GetStackFrames() __attribute__((noinline));
|
||||
|
||||
template<typename S, typename... Args>
|
||||
exception(const S &formatStr, Args &&... args) : runtime_error(util::Format(formatStr, args...)), frames(GetStackFrames()) {}
|
||||
};
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue