Compare commits
298 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
69703bd330 | ||
|
|
5956ac4dad | ||
|
|
4b65e86f2a | ||
|
|
5591e8d996 | ||
|
|
30dcf82cf3 | ||
|
|
dc9a1c2f3f | ||
|
|
21f698e99a | ||
|
|
8e200a89fa | ||
|
|
f06b7ff6c3 | ||
|
|
09b4e5ebae | ||
|
|
e04a5b7fe7 | ||
|
|
c18f3f1468 | ||
|
|
dc7fa98d19 | ||
|
|
54fd2eb98d | ||
|
|
bd6502f930 | ||
|
|
266e56c884 | ||
|
|
e429e6ad44 | ||
|
|
9725b1ba8f | ||
|
|
01c78bf8b6 | ||
|
|
8e7d82156c | ||
|
|
e5293e0eb8 | ||
|
|
6ddabbb303 | ||
|
|
3315924356 | ||
|
|
bd36eb26d7 | ||
|
|
0053b1b367 | ||
|
|
0401397e98 | ||
|
|
18e9c47941 | ||
|
|
80a61fb3b7 | ||
|
|
39c51e0fcc | ||
|
|
afc551eb96 | ||
|
|
820335f831 | ||
|
|
955f73635c | ||
|
|
32dbdcabca | ||
|
|
319fa2bf8f | ||
|
|
65eb5f8903 | ||
|
|
464b7d8fff | ||
|
|
da7f7a2f7c | ||
|
|
73fccf339f | ||
|
|
2fdb0ee492 | ||
|
|
4a5e889c40 | ||
|
|
6429556b96 | ||
|
|
8ebf887956 | ||
|
|
7634ff767b | ||
|
|
380f621b39 | ||
|
|
e7c5bd02c2 | ||
|
|
19175e5307 | ||
|
|
4b37217077 | ||
|
|
b561d2f0ca | ||
|
|
a78de5f18a | ||
|
|
90b950a17c | ||
|
|
6be91a1b0e | ||
|
|
88bfa9a4ec | ||
|
|
c6a8884c14 | ||
|
|
06ec789e32 | ||
|
|
82ce031851 | ||
|
|
2908d7520c | ||
|
|
4cfdd28cb0 | ||
|
|
60d6bf3b26 | ||
|
|
6d6b5c93ef | ||
|
|
c7c485cc60 | ||
|
|
ec0155be3e | ||
|
|
3a68a060c6 | ||
|
|
e34ec9d8d1 | ||
|
|
9a4e659b9c | ||
|
|
a9adadd30e | ||
|
|
16ac50e783 | ||
|
|
62b3b71854 | ||
|
|
b460f635bd | ||
|
|
52b3b6b469 | ||
|
|
f763fb70a8 | ||
|
|
6a5c3b786a | ||
|
|
afa4fa924a | ||
|
|
7ebc999e4a | ||
|
|
6fcb2029fe | ||
|
|
d21391fe79 | ||
|
|
db62b6fb42 | ||
|
|
53bf78181c | ||
|
|
8504bd786e | ||
|
|
5540a96af1 | ||
|
|
0d5558f876 | ||
|
|
a95c0fc23c | ||
|
|
1d56ed1504 | ||
|
|
a8b43a650d | ||
|
|
aaa8ec1881 | ||
|
|
bc6dd1a4f6 | ||
|
|
532a85b593 | ||
|
|
a18efcbed7 | ||
|
|
e52d57a961 | ||
|
|
6093cff721 | ||
|
|
de62e8b33d | ||
|
|
0d7608a4d5 | ||
|
|
397d96843b | ||
|
|
fd6ceaaaf1 | ||
|
|
a35a3b241b | ||
|
|
072e9e4076 | ||
|
|
3af3ad4a68 | ||
|
|
d1308e0251 | ||
|
|
e48cab36b7 | ||
|
|
b2ba7354cd | ||
|
|
4f0e890e01 | ||
|
|
86a2800e6e | ||
|
|
13550fbc20 | ||
|
|
187d6d6422 | ||
|
|
060178aea6 | ||
|
|
715577a644 | ||
|
|
45332444ec | ||
|
|
fd3808fd82 | ||
|
|
e13e2b1f41 | ||
|
|
6b26aa5574 | ||
|
|
13f422fa29 | ||
|
|
fa66a09b04 | ||
|
|
5d9c7acc52 | ||
|
|
52076a0191 | ||
|
|
08936d9466 | ||
|
|
45ed9afb04 | ||
|
|
1358b10616 | ||
|
|
e9f5f59ddf | ||
|
|
67be6d9120 | ||
|
|
749fd385ce | ||
|
|
65927cffce | ||
|
|
10bcf4542d | ||
|
|
8bc1aee110 | ||
|
|
ca4b132f25 | ||
|
|
afeee4937c | ||
|
|
66308b152b | ||
|
|
72dfdb53fc | ||
|
|
ee730ca68e | ||
|
|
2d0a2c4f6d | ||
|
|
8411a14b26 | ||
|
|
99e9270314 | ||
|
|
58488f7f48 | ||
|
|
c2238eb070 | ||
|
|
4271efb4a7 | ||
|
|
fd9e5a2e08 | ||
|
|
4587b01152 | ||
|
|
fae0fa5d5f | ||
|
|
059fe40339 | ||
|
|
a617a7398a | ||
|
|
2f092f7955 | ||
|
|
003854d2bb | ||
|
|
f49e1a80a0 | ||
|
|
16ea883fa8 | ||
|
|
f787ed7fd8 | ||
|
|
63c7fb211d | ||
|
|
52e13f5e1e | ||
|
|
797bcf79a2 | ||
|
|
0d227cfb82 | ||
|
|
3010c915a7 | ||
|
|
196933a6b3 | ||
|
|
bfc93c6238 | ||
|
|
6d284d9c2b | ||
|
|
7384404ac1 | ||
|
|
35de44d3fa | ||
|
|
1b07df5f08 | ||
|
|
34e1f39510 | ||
|
|
ef830ce3f6 | ||
|
|
d7e22b3ccc | ||
|
|
d6c2ddf2ea | ||
|
|
b4627ad171 | ||
|
|
381a1eafc4 | ||
|
|
f90ba2ca59 | ||
|
|
f97fdc9528 | ||
|
|
ed63a95488 | ||
|
|
e24512c9d6 | ||
|
|
1efd91d535 | ||
|
|
3337738dcc | ||
|
|
7f1f504c36 | ||
|
|
2f21f23266 | ||
|
|
3c99ad0186 | ||
|
|
e4dd690ac9 | ||
|
|
9122768953 | ||
|
|
3539916cfd | ||
|
|
4bd776c8aa | ||
|
|
78cda43054 | ||
|
|
580db1f167 | ||
|
|
ea9adbfa14 | ||
|
|
accfea86f1 | ||
|
|
badf182529 | ||
|
|
12f12c6b1e | ||
|
|
dde723baee | ||
|
|
27db54644e | ||
|
|
138bcb6dc6 | ||
|
|
05fa5034d3 | ||
|
|
8a98a57b4b | ||
|
|
c12b0136f8 | ||
|
|
c4f7f0e713 | ||
|
|
935dd24129 | ||
|
|
d72e05259a | ||
|
|
847ae19de9 | ||
|
|
8651e418ca | ||
|
|
2e3ef0f3b0 | ||
|
|
c018b10a7f | ||
|
|
336ea0eddb | ||
|
|
d561c0e538 | ||
|
|
a7c1fe0d27 | ||
|
|
33582678c2 | ||
|
|
3ca1f17e4d | ||
|
|
65dfa8f48a | ||
|
|
90ea18c881 | ||
|
|
598136c64b | ||
|
|
848a788c5f | ||
|
|
d443e069fd | ||
|
|
b7e7f0f720 | ||
|
|
916e5c5ddf | ||
|
|
c766ab1569 | ||
|
|
9ee4d79f77 | ||
|
|
d55d1ab319 | ||
|
|
3be1eb6149 | ||
|
|
5e4f58975c | ||
|
|
d0c257dbc0 | ||
|
|
ffb0ded210 | ||
|
|
396304c738 | ||
|
|
8c6baf9e2f | ||
|
|
a24eec7256 | ||
|
|
77a45966da | ||
|
|
04d7e2f8e0 | ||
|
|
f5481d1c00 | ||
|
|
2e39421074 | ||
|
|
9cf901d487 | ||
|
|
0cdc96f7f8 | ||
|
|
73fafa6337 | ||
|
|
cfae441656 | ||
|
|
bf6bfa3e57 | ||
|
|
72f5e11c42 | ||
|
|
93b6974be5 | ||
|
|
1f545a7030 | ||
|
|
73bcb384b5 | ||
|
|
fab0b76a35 | ||
|
|
2f830bac53 | ||
|
|
5bf7fdf60e | ||
|
|
af4f00f682 | ||
|
|
d4b09f147b | ||
|
|
1b33e9982c | ||
|
|
c998aa78ae | ||
|
|
2b5a27f86e | ||
|
|
52b1b8da81 | ||
|
|
f409f5b8c3 | ||
|
|
77a7470149 | ||
|
|
1d9fa4c091 | ||
|
|
a16cf8a2ef | ||
|
|
89418b7cd0 | ||
|
|
00cf05d9c5 | ||
|
|
39e7ba6b75 | ||
|
|
d7f2cee3b1 | ||
|
|
3848bd7c83 | ||
|
|
693954930a | ||
|
|
de89768c74 | ||
|
|
8f243c8369 | ||
|
|
fd91f376c4 | ||
|
|
f0fe114303 | ||
|
|
1c64cf5db8 | ||
|
|
9eea39325d | ||
|
|
9bb6b3383b | ||
|
|
fb3e976f2e | ||
|
|
ec4a1f974b | ||
|
|
fc4b3b8352 | ||
|
|
5123f7b1de | ||
|
|
3251d104c4 | ||
|
|
ea2d604c20 | ||
|
|
ae71cd447d | ||
|
|
4261dd83f0 | ||
|
|
4dc01c024a | ||
|
|
9e26329173 | ||
|
|
36441e6dea | ||
|
|
cdf28607c9 | ||
|
|
b383fa7ec2 | ||
|
|
d7178ddd2c | ||
|
|
9d149f0939 | ||
|
|
170dd79347 | ||
|
|
d97d359ec2 | ||
|
|
9ff9e315a0 | ||
|
|
cde560c4bd | ||
|
|
a15860ba8d | ||
|
|
76e6f1bd27 | ||
|
|
2c1ad1b755 | ||
|
|
2f2e5e9fb8 | ||
|
|
65b77a2d0b | ||
|
|
5d4812bde5 | ||
|
|
addd2de4d9 | ||
|
|
0df8ce745f | ||
|
|
62d055f163 | ||
|
|
fa1510a40d | ||
|
|
e6942f95e7 | ||
|
|
94b63003ab | ||
|
|
8aa20dc0cf | ||
|
|
db92c60cd2 | ||
|
|
c8c7b233f5 | ||
|
|
5a9afcbb74 | ||
|
|
8127a0c3b7 | ||
|
|
7c5e746594 | ||
|
|
7d30c4d384 | ||
|
|
883b4fc3f4 | ||
|
|
530588a818 | ||
|
|
a6402bd5d5 | ||
|
|
cd3d29ce88 | ||
|
|
192b70dae4 | ||
|
|
aaa9f90794 | ||
|
|
d5e38b0eb3 |
@@ -7,28 +7,41 @@ BasedOnStyle: LLVM
|
||||
IndentWidth: 4
|
||||
UseTab: Never
|
||||
|
||||
BreakBeforeBraces: Linux
|
||||
# === Struct/Union/Class member indentation ===
|
||||
# These options control indentation of struct members to ensure consistent
|
||||
# 4-space indentation for all struct/union/class members
|
||||
IndentAccessModifiers: false
|
||||
AccessModifierOffset: 0
|
||||
NamespaceIndentation: All
|
||||
IndentPPDirectives: BeforeHash
|
||||
|
||||
BreakBeforeBraces: Attach
|
||||
BraceWrapping:
|
||||
AfterControlStatement: false
|
||||
AfterFunction: true
|
||||
AfterFunction: false
|
||||
AfterClass: false
|
||||
AfterStruct: false
|
||||
# AfterStruct: false keeps struct opening brace on same line (K&R style)
|
||||
# Struct members will still be indented with IndentWidth: 4
|
||||
AfterUnion: false
|
||||
AfterNamespace: false
|
||||
AfterEnum: false
|
||||
BeforeCatch: false
|
||||
BeforeElse: false
|
||||
IndentBraces: false
|
||||
# IndentBraces: false ensures braces themselves are not indented,
|
||||
# but content inside braces respects IndentWidth setting
|
||||
|
||||
ContinuationIndentWidth: 0
|
||||
AlignAfterOpenBracket: false
|
||||
AllowShortIfStatementsOnASingleLine: false
|
||||
AllowShortLoopsOnASingleLine: false
|
||||
AllowShortBlocksOnASingleLine: Always
|
||||
IndentCaseLabels: false
|
||||
SpaceAfterCStyleCast: true
|
||||
# AllowShortFunctionsOnASingleLine: None enforces function bodies
|
||||
# to always be on separate lines, following K&R convention
|
||||
AllowShortFunctionsOnASingleLine: None
|
||||
ColumnLimit: 80
|
||||
|
||||
IndentCaseLabels: true
|
||||
SpaceAfterCStyleCast: false
|
||||
ColumnLimit: 150
|
||||
MaxEmptyLinesToKeep: 1
|
||||
Cpp11BracedListStyle: false
|
||||
AlignTrailingComments: true
|
||||
@@ -39,7 +52,9 @@ IncludeBlocks: Regroup
|
||||
IncludeCategories:
|
||||
- Regex: '<[[:alnum:].]+>'
|
||||
Priority: 1
|
||||
# System headers (angle brackets) have highest priority
|
||||
- Regex: '.*'
|
||||
Priority: 2
|
||||
# Project headers (quotes) have lower priority
|
||||
SortIncludes: CaseSensitive
|
||||
AlignEscapedNewlines: Left
|
||||
35
.github/workflows/build.yml
vendored
@@ -12,7 +12,7 @@ jobs:
|
||||
|
||||
# Minimal devkitA64 container
|
||||
container:
|
||||
image: devkitpro/devkita64:20251231
|
||||
image: devkitpro/devkita64:20260219
|
||||
|
||||
steps:
|
||||
- name: Checkout repository and submodules # needed for hoc-clk
|
||||
@@ -55,7 +55,7 @@ jobs:
|
||||
echo $GITHUB_SHA >> dist/.commit
|
||||
|
||||
- name: Clone Libnx
|
||||
run: git clone https://github.com/switchbrew/libnx.git
|
||||
run: git clone https://github.com/switchbrew/libnx.git --depth=1 --single-branch -b v4.12.0
|
||||
|
||||
- name: Clone Atmosphere
|
||||
run: git clone --depth=1 --single-branch https://github.com/Atmosphere-NX/Atmosphere.git atmosphere -b $(cat ams_ver.txt)
|
||||
@@ -70,20 +70,27 @@ jobs:
|
||||
cp -rf Source/Atmosphere/stratosphere/loader/source/* build/stratosphere/loader/source/
|
||||
|
||||
- name: Cache ccache
|
||||
uses: actions/cache@v5.0.3
|
||||
uses: actions/cache@v5.0.5
|
||||
with:
|
||||
path: /root/.cache/ccache
|
||||
key: ccache-${{ runner.os }}-devkitpro-ams-${{ hashFiles('ams_ver.txt') }} # last key was utter garbage, stick to ams versions,
|
||||
path: .ccache
|
||||
key: ccache-${{ runner.os }}-devkitpro-ams-${{ hashFiles('ams_ver.txt') }}
|
||||
restore-keys: |
|
||||
ccache-${{ runner.os }}-devkitpro-
|
||||
|
||||
- name: Configure ccache
|
||||
run: |
|
||||
export CCACHE_DIR=/root/.cache/ccache
|
||||
echo "CCACHE_DIR=/root/.cache/ccache" >> $GITHUB_ENV
|
||||
export CCACHE_DIR="$GITHUB_WORKSPACE/.ccache"
|
||||
export CCACHE_COMPILERCHECK=content
|
||||
export CCACHE_NOHASHDIR=true
|
||||
echo "CCACHE_DIR=$GITHUB_WORKSPACE/.ccache" >> $GITHUB_ENV
|
||||
echo "CCACHE_BASEDIR=$GITHUB_WORKSPACE" >> $GITHUB_ENV
|
||||
echo "CCACHE_COMPILERCHECK=content" >> $GITHUB_ENV
|
||||
echo "CCACHE_NOHASHDIR=true" >> $GITHUB_ENV
|
||||
ccache --set-config=max_size=10G
|
||||
ccache --set-config=compiler_check=content
|
||||
ccache --zero-stats
|
||||
ccache --set-config=hash_dir=false
|
||||
ccache -s
|
||||
ls -lah "$GITHUB_WORKSPACE/.ccache"
|
||||
|
||||
- name: Build Libnx
|
||||
shell: bash
|
||||
@@ -102,6 +109,7 @@ jobs:
|
||||
|
||||
ROOT_DIR="$GITHUB_WORKSPACE/Source/hoc-clk"
|
||||
DIST_DIR="$ROOT_DIR/dist"
|
||||
echo "DIST_DIR="$ROOT_DIR/dist"" >> $GITHUB_ENV
|
||||
|
||||
mkdir -p "$DIST_DIR"
|
||||
|
||||
@@ -162,8 +170,11 @@ jobs:
|
||||
hactool -t kip1 out/nintendo_nx_arm64_armv8a/release/loader.kip --uncompress=hoc.kip
|
||||
cp hoc.kip ../../../dist/atmosphere/kips/hoc.kip
|
||||
|
||||
- name: ccache stats
|
||||
run: ccache --show-stats
|
||||
- name: ccache stat
|
||||
run: |
|
||||
ccache --show-stats
|
||||
ccache -s
|
||||
ccache --show-config
|
||||
|
||||
# -------------------------------------------------
|
||||
# Upload ZIP artifact
|
||||
@@ -172,5 +183,5 @@ jobs:
|
||||
uses: actions/upload-artifact@v6
|
||||
with:
|
||||
name: horizon-oc-zeus-dist
|
||||
path: dist/
|
||||
compression-level: 3
|
||||
path: $DIST_DIR
|
||||
compression-level: 6
|
||||
|
||||
2
.gitignore
vendored
@@ -4,3 +4,5 @@
|
||||
build/
|
||||
__pycache__/
|
||||
build
|
||||
*.dksh
|
||||
Source/hekate
|
||||
|
||||
13
COMPILING.md
@@ -1,12 +1,7 @@
|
||||
Horizon OC Zeus Compilation Instructions
|
||||
Horizon OC Compilation Instructions
|
||||
|
||||
1. Install devkitpro (https://devkitpro.org/wiki/Getting_Started) with switch-dev
|
||||
2. Set up a development enviorment for compiling Atmosphere (https://github.com/Atmosphere-NX/Atmosphere/blob/master/docs/building.md)
|
||||
3. Install GNU make and ENSURE THAT YOUR ENVIORMENT HAS A PYTHON3 COMMAND AVAILABLE!
|
||||
4. Git clone atmosphere (git clone https://github.com/Atmosphere-NX/Atmosphere.git)
|
||||
5. Clone the Horizon OC develop branch (git clone -b develop --single-branch https://github.com/Horizon-OC/Horizon-OC.git)
|
||||
6. Create a new folder named "build" in the horizon oc repo
|
||||
7. Copy atmosphere files into that build folder
|
||||
8. Copy Source/Atmosphere/stratosphere/loader/source/ldr_process_creation.cpp to build/stratosphere/loader/source/ldr_process_creation.cpp, replacing any files if prompted
|
||||
9. Grab a copy of libultrahand (https://github.com/ppkantorski/libultrahand) and place it into Source/sys-clk/overlay/lib/libultrahand
|
||||
10. Run ./build.sh in the root directory
|
||||
3. Clone the Horizon OC develop branch (``git clone https://github.com/Horizon-OC/Horizon-OC.git --recurse-submodules``)
|
||||
4. Run ``./build.sh`` in the root directory
|
||||
- If you want to compile with extensions, append ``--ext``
|
||||
|
||||
86
README.md
@@ -11,7 +11,7 @@
|
||||

|
||||

|
||||

|
||||

|
||||

|
||||
|
||||
---
|
||||
|
||||
@@ -56,6 +56,7 @@ It enables advanced CPU, GPU, and RAM tuning with user-friendly configuration to
|
||||
|
||||
```
|
||||
kip1=atmosphere/kips/hoc.kip
|
||||
secmon=atmosphere/exosphere.bin
|
||||
```
|
||||
|
||||
*(No changes needed if using fusee.)*
|
||||
@@ -78,21 +79,64 @@ Refer to COMPILATION.md
|
||||
---
|
||||
## Clock table
|
||||
|
||||
### MEM clocks
|
||||
### MEM clocks (mhz)
|
||||
|
||||
* 3200 → max on mariko, JEDEC.
|
||||
* 3166
|
||||
* 3133
|
||||
* 3100
|
||||
* 3066
|
||||
* 3033
|
||||
* 3000
|
||||
* 2966
|
||||
* 2933 → JEDEC.
|
||||
* 2900
|
||||
* 2866
|
||||
* 2833
|
||||
* 2800
|
||||
* 2766
|
||||
* 2733
|
||||
* 2700
|
||||
* 2666 → JEDEC.
|
||||
* 2633
|
||||
* 2600
|
||||
* 2566
|
||||
* 2533
|
||||
* 2500
|
||||
* 2466
|
||||
* 2433
|
||||
* 2400 → max on erista, JEDEC.
|
||||
* 2133 → mariko safe max (4266 Modules), JEDEC.
|
||||
* 1996 → JEDEC.
|
||||
* 1866 → mariko safe max (3733 Modules), JEDEC.
|
||||
* 1600 → official docked, boost mode, erista safe max, JEDEC.
|
||||
* 2366
|
||||
* 2333
|
||||
* 2300
|
||||
* 2266
|
||||
* 2233
|
||||
* 2200
|
||||
* 2166
|
||||
* 2133 → Mariko JEDEC standard max (4266 Modules)
|
||||
* 2100
|
||||
* 2066
|
||||
* 2033
|
||||
* 2000
|
||||
* 1996 → JEDEC standard
|
||||
* 1966
|
||||
* 1933
|
||||
* 1900
|
||||
* 1866 → Mariko JEDEC standard max (3733 Modules)
|
||||
* 1833
|
||||
* 1800
|
||||
* 1766
|
||||
* 1733
|
||||
* 1700
|
||||
* 1666
|
||||
* 1633
|
||||
* 1600 → official docked, boost mode, Erista JEDEC standard max (3200 Modules), JEDEC.
|
||||
* 1331 → official handheld, JEDEC.
|
||||
* 1065
|
||||
* 800
|
||||
* 665
|
||||
|
||||
### CPU clocks
|
||||
### CPU clocks (mhz)
|
||||
* 2703 → mariko absolute max, dangerous
|
||||
* 2601 → unsafe
|
||||
* 2499
|
||||
@@ -115,17 +159,17 @@ Refer to COMPILATION.md
|
||||
* 714
|
||||
* 612 → sleep mode
|
||||
|
||||
### GPU clocks
|
||||
### GPU clocks (mhz)
|
||||
* 1536 → absolute max clock on mariko. very dangerous
|
||||
* 1459
|
||||
* 1382
|
||||
* 1305
|
||||
* 1267 → NVIDIA T214 rating
|
||||
* 1228 → mariko HiOPT safe clock
|
||||
* 1152 → mariko SLT max clock
|
||||
* 1075 → mariko no UV max clock. absolute max clock on erista. very dangerous
|
||||
* 998 → NVIDIA T210 rating
|
||||
* 960 (erista only) → erista slt/hiopt safe max clock
|
||||
* 1267 → NVIDIA T214(mariko) rating
|
||||
* 1228 → mariko High UV safe clock
|
||||
* 1152 → mariko hiOpt-15mV max clock
|
||||
* 1075 → mariko hiOpt max clock. absolute max clock on erista. very dangerous
|
||||
* 998 → NVIDIA T210 (erista) rating
|
||||
* 960 (erista only) → erista high uv/hiOpt-15mV safe max clock
|
||||
* 921 → erista no UV max clock
|
||||
* 844
|
||||
* 768 → official docked
|
||||
@@ -142,31 +186,31 @@ Refer to COMPILATION.md
|
||||
**Notes:**
|
||||
1. On Erista, CPU in handheld is capped to 1581MHz
|
||||
2. GPU overclock is capped at 460MHz on erista in handheld
|
||||
3. On Mariko, cap with No uv is 614MHz, with SLT it is 691MHz and with HiOPT it's 768MHz
|
||||
3. On Mariko, cap with hiOpt is 614MHz, with hiOpt-15mV it is 691MHz and with High UV it's 768MHz
|
||||
4. Clocks higher than 768MHz on erista need the official charger is plugged in.
|
||||
5. On Mariko, cap with No uv is 844MHz, with SLT it is 921MHz and with HiOPT it's 998MHz
|
||||
|
||||
|
||||
---
|
||||
|
||||
## Credits
|
||||
* **Lightos's Cat** - Cat
|
||||
|
||||
* **Souldbminer** - hoc-clk and loader development
|
||||
* **Lightos** - Loader patches development, hoc-clk development, guides
|
||||
* **TDRR** - HOC Logo Design
|
||||
* **tetetete-ctrl** - Website design
|
||||
* **SciresM** - Atmosphere CFW
|
||||
* **CTCaer** - L4T, Hekate, proper RAM timings
|
||||
* **KazushiMe** - Switch OC Suite
|
||||
* **Hanai3bi (Meha)** - Switch OC Suite, EOS, sys-clk-eos
|
||||
* **NaGaa95** - L4T-OC kernel, Status Monitor fork
|
||||
* **B3711 (halop)** - EOS
|
||||
* **B3711 (halop)** - EOS, contributions
|
||||
* **sys-clk team (m4xw, p-sam, natinusala)** - sys-clk
|
||||
* **Dominatorul** - Soctherm driver, guides, general help
|
||||
* **b0rd2death** - Ultrahand sys-clk & Status Monitor fork
|
||||
* **ppkantorski** - Ultrahand sys-clk & Status Monitor fork
|
||||
* **MasaGratoR and ZachyCatGames** - General help
|
||||
* **MasaGratoR** - Status Monitor & Display Refresh Rate driver
|
||||
* **Dominatorul, Samybigio, Arcdelta, Miki, Happy, Flopsider, Winnerboi77, Blaise, Alvise, TDRR, agjeococh, frost, letum00, and Xenshen** - Testing
|
||||
* **Dominatorul, Samybigio, Arcdelta, Miki, Happy, Winnerboi77, Blaise, Alvise, agjeococh, frost, letum00, and Xenshen** - Testing
|
||||
* **Samybigio2011, Miki** - Italian translations
|
||||
* **angelblaster** - Korean translations
|
||||
* **q1332348216-glitch** - Chinese translations
|
||||
* **th3-ne0undr5c0r** - French translations
|
||||
* **Nvidia** - [Tegra X1 Technical Reference Manual](https://developer.nvidia.com/embedded/dlc/tegra-x1-technical-reference-manual), soctherm driver, L4T
|
||||
|
||||
@@ -4,8 +4,9 @@
|
||||
|
||||
| Version | Supported |
|
||||
| ------- | ------------------ |
|
||||
| 1.x | :white_check_mark: |
|
||||
| 0.x | Not supported |
|
||||
| 2.x.x | :white_check_mark: |
|
||||
| 1.x.x | Not supported |
|
||||
| 0.x.x | Not supported |
|
||||
|
||||
## Reporting a Vulnerability
|
||||
|
||||
|
||||
@@ -14,9 +14,9 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#define __ACCESS_TABLE_NAME__ EmcAccessTable1
|
||||
#define __ACCESS_TABLE_ADDRESS__ MemoryRegionPhysicalDeviceExternalMemoryController1.GetAddress()
|
||||
#define __ACCESS_TABLE_INC__ "secmon_emc_access_table_data.inc"
|
||||
#define __ACCESS_TABLE_NAME__ RtcPmcAccessTable
|
||||
#define __ACCESS_TABLE_ADDRESS__ MemoryRegionPhysicalDeviceRtcPmc.GetAddress()
|
||||
#define __ACCESS_TABLE_INC__ "secmon_rtc_pmc_access_table_data.inc"
|
||||
|
||||
#include "secmon_define_access_table.inc"
|
||||
|
||||
1040
Source/Atmosphere-Patches/secmon_rtc_pmc_access_table_data.inc
Normal file
@@ -99,18 +99,16 @@ namespace ams::secmon::smc {
|
||||
#include "secmon_define_pmc_access_table.inc"
|
||||
#include "secmon_define_mc_access_table.inc"
|
||||
#include "secmon_define_emc_access_table.inc"
|
||||
#include "secmon_define_emc1_access_table.inc"
|
||||
#include "secmon_define_emc2_access_table.inc"
|
||||
#include "secmon_define_rtc_pmc_access_table.inc"
|
||||
#include "secmon_define_mc01_access_table.inc"
|
||||
|
||||
constexpr const AccessTableEntry AccessTables[] = {
|
||||
{ PmcAccessTable::ReducedAccessTable.data(), MemoryRegionVirtualDevicePmc.GetAddress(), PmcAccessTable::Address, PmcAccessTable::Size, },
|
||||
{ McAccessTable::ReducedAccessTable.data(), MemoryRegionVirtualDeviceMemoryController.GetAddress(), McAccessTable::Address, McAccessTable::Size, },
|
||||
{ EmcAccessTable::ReducedAccessTable.data(), MemoryRegionVirtualDeviceExternalMemoryController.GetAddress(), EmcAccessTable::Address, EmcAccessTable::Size, },
|
||||
{ EmcAccessTable1::ReducedAccessTable.data(), MemoryRegionVirtualDeviceExternalMemoryController1.GetAddress(), EmcAccessTable1::Address, EmcAccessTable1::Size, },
|
||||
{ EmcAccessTable2::ReducedAccessTable.data(), MemoryRegionVirtualDeviceExternalMemoryController2.GetAddress(), EmcAccessTable2::Address, EmcAccessTable2::Size, },
|
||||
{ Mc01AccessTable::ReducedAccessTable.data(), Mc01AccessTable::Address + MemoryRegionVirtualDeviceMemoryController0.GetAddress(), Mc01AccessTable::Address + MemoryRegionPhysicalDeviceMemoryController0.GetAddress(), Mc01AccessTable::Size, },
|
||||
{ Mc01AccessTable::ReducedAccessTable.data(), Mc01AccessTable::Address + MemoryRegionVirtualDeviceMemoryController1.GetAddress(), Mc01AccessTable::Address + MemoryRegionPhysicalDeviceMemoryController1.GetAddress(), Mc01AccessTable::Size, },
|
||||
{ PmcAccessTable::ReducedAccessTable.data(), MemoryRegionVirtualDevicePmc.GetAddress(), PmcAccessTable::Address, PmcAccessTable::Size, },
|
||||
{ McAccessTable::ReducedAccessTable.data(), MemoryRegionVirtualDeviceMemoryController.GetAddress(), McAccessTable::Address, McAccessTable::Size, },
|
||||
{ EmcAccessTable::ReducedAccessTable.data(), MemoryRegionVirtualDeviceExternalMemoryController.GetAddress(), EmcAccessTable::Address, EmcAccessTable::Size, },
|
||||
{ RtcPmcAccessTable::ReducedAccessTable.data(), MemoryRegionVirtualDeviceRtcPmc.GetAddress(), RtcPmcAccessTable::Address, RtcPmcAccessTable::Size, },
|
||||
{ Mc01AccessTable::ReducedAccessTable.data(), Mc01AccessTable::Address + MemoryRegionVirtualDeviceMemoryController0.GetAddress(), Mc01AccessTable::Address + MemoryRegionPhysicalDeviceMemoryController0.GetAddress(), Mc01AccessTable::Size, },
|
||||
{ Mc01AccessTable::ReducedAccessTable.data(), Mc01AccessTable::Address + MemoryRegionVirtualDeviceMemoryController1.GetAddress(), Mc01AccessTable::Address + MemoryRegionPhysicalDeviceMemoryController1.GetAddress(), Mc01AccessTable::Size, },
|
||||
};
|
||||
|
||||
constexpr bool IsAccessAllowed(const AccessTableEntry &entry, uintptr_t address) {
|
||||
|
||||
88
Source/Atmosphere/stratosphere/loader/loader.json
Normal file
@@ -0,0 +1,88 @@
|
||||
{
|
||||
"name": "Loader",
|
||||
"title_id": "0x0100000000000001",
|
||||
"main_thread_stack_size": "0x4000",
|
||||
"main_thread_priority": 49,
|
||||
"default_cpu_id": 3,
|
||||
"process_category": 1,
|
||||
"use_secure_memory": true,
|
||||
"immortal": true,
|
||||
"kernel_capabilities": [
|
||||
{
|
||||
"type": "handle_table_size",
|
||||
"value": 128
|
||||
},
|
||||
{
|
||||
"type": "syscalls",
|
||||
"value": {
|
||||
"svcSetHeapSize" : "0x01",
|
||||
"svcSetMemoryPermission" : "0x02",
|
||||
"svcSetMemoryAttribute" : "0x03",
|
||||
"svcMapMemory" : "0x04",
|
||||
"svcUnmapMemory" : "0x05",
|
||||
"svcQueryMemory" : "0x06",
|
||||
"svcExitProcess" : "0x07",
|
||||
"svcCreateThread" : "0x08",
|
||||
"svcStartThread" : "0x09",
|
||||
"svcExitThread" : "0x0A",
|
||||
"svcSleepThread" : "0x0B",
|
||||
"svcGetThreadPriority" : "0x0C",
|
||||
"svcSetThreadPriority" : "0x0D",
|
||||
"svcGetThreadCoreMask" : "0x0E",
|
||||
"svcSetThreadCoreMask" : "0x0F",
|
||||
"svcGetCurrentProcessorNumber" : "0x10",
|
||||
"svcSignalEvent" : "0x11",
|
||||
"svcClearEvent" : "0x12",
|
||||
"svcMapSharedMemory" : "0x13",
|
||||
"svcUnmapSharedMemory" : "0x14",
|
||||
"svcCreateTransferMemory" : "0x15",
|
||||
"svcCloseHandle" : "0x16",
|
||||
"svcResetSignal" : "0x17",
|
||||
"svcWaitSynchronization" : "0x18",
|
||||
"svcCancelSynchronization" : "0x19",
|
||||
"svcArbitrateLock" : "0x1A",
|
||||
"svcArbitrateUnlock" : "0x1B",
|
||||
"svcWaitProcessWideKeyAtomic" : "0x1C",
|
||||
"svcSignalProcessWideKey" : "0x1D",
|
||||
"svcGetSystemTick" : "0x1E",
|
||||
"svcConnectToNamedPort" : "0x1F",
|
||||
"svcSendSyncRequestLight" : "0x20",
|
||||
"svcSendSyncRequest" : "0x21",
|
||||
"svcSendSyncRequestWithUserBuffer" : "0x22",
|
||||
"svcSendAsyncRequestWithUserBuffer" : "0x23",
|
||||
"svcGetProcessId" : "0x24",
|
||||
"svcGetThreadId" : "0x25",
|
||||
"svcBreak" : "0x26",
|
||||
"svcOutputDebugString" : "0x27",
|
||||
"svcReturnFromException" : "0x28",
|
||||
"svcGetInfo" : "0x29",
|
||||
"svcWaitForAddress" : "0x34",
|
||||
"svcSignalToAddress" : "0x35",
|
||||
"svcSynchronizePreemptionState" : "0x36",
|
||||
"svcCreateSession" : "0x40",
|
||||
"svcAcceptSession" : "0x41",
|
||||
"svcReplyAndReceiveLight" : "0x42",
|
||||
"svcReplyAndReceive" : "0x43",
|
||||
"svcReplyAndReceiveWithUserBuffer" : "0x44",
|
||||
"svcCreateEvent" : "0x45",
|
||||
"svcReadWriteRegister" : "0x4E",
|
||||
"svcQueryIoMapping" : "0x55",
|
||||
"svcSetProcessMemoryPermission" : "0x73",
|
||||
"svcMapProcessMemory" : "0x74",
|
||||
"svcUnmapProcessMemory" : "0x75",
|
||||
"svcMapProcessCodeMemory" : "0x77",
|
||||
"svcUnmapProcessCodeMemory" : "0x78",
|
||||
"svcCreateProcess" : "0x79",
|
||||
"svcCallSecureMonitor" : "0x7F"
|
||||
}
|
||||
}, {
|
||||
"type": "map",
|
||||
"value": {
|
||||
"address": "0x7000F000",
|
||||
"is_ro": false,
|
||||
"size": "0x00001000",
|
||||
"is_io": true
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1,51 +0,0 @@
|
||||
TARGET_EXEC := test
|
||||
|
||||
BUILD_DIR := ./build
|
||||
SRC_DIRS := ./
|
||||
|
||||
# CXX := clang++ g++-12
|
||||
|
||||
# Find all the C and C++ files we want to compile
|
||||
# Note the single quotes around the * expressions. Make will incorrectly expand these otherwise.
|
||||
SRCS := $(shell find $(SRC_DIRS) -name '*.cpp' -or -name '*.c' -or -name '*.s')
|
||||
|
||||
# String substitution for every C/C++ file.
|
||||
# As an example, hello.cpp turns into ./build/hello.cpp.o
|
||||
OBJS := $(SRCS:%=$(BUILD_DIR)/%.o)
|
||||
|
||||
# String substitution (suffix version without %).
|
||||
# As an example, ./build/hello.cpp.o turns into ./build/hello.cpp.d
|
||||
DEPS := $(OBJS:.o=.d)
|
||||
|
||||
# Every folder in ./src will need to be passed to GCC so that it can find header files
|
||||
INC_DIRS := $(shell find $(SRC_DIRS) -type d)
|
||||
# Add a prefix to INC_DIRS. So moduleA would become -ImoduleA. GCC understands this -I flag
|
||||
INC_FLAGS := $(addprefix -I,$(INC_DIRS))
|
||||
|
||||
CPPFLAGS := $(INC_FLAGS) -Wall -Werror -Wno-unused-result -std=c++20 -Og -g
|
||||
|
||||
# The final build step.
|
||||
$(TARGET_EXEC): $(OBJS)
|
||||
@echo "Linking $@"
|
||||
@$(CXX) $(OBJS) -o $@ $(LDFLAGS)
|
||||
|
||||
# Build step for C source
|
||||
$(BUILD_DIR)/%.c.o: %.c
|
||||
@mkdir -p $(dir $@)
|
||||
@echo "$<"
|
||||
@$(CC) $(CPPFLAGS) $(CFLAGS) -c $< -o $@
|
||||
|
||||
# Build step for C++ source
|
||||
$(BUILD_DIR)/%.cpp.o: %.cpp
|
||||
@mkdir -p $(dir $@)
|
||||
@echo "$<"
|
||||
@$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $< -o $@
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
@rm -r $(BUILD_DIR) $(TARGET_EXEC)
|
||||
|
||||
# Include the .d makefiles. The - at the front suppresses the errors of missing
|
||||
# Makefiles. Initially, all the .d files will be missing, and we don't want those
|
||||
# errors to show up.
|
||||
-include $(DEPS)
|
||||
@@ -37,27 +37,27 @@ volatile CustomizeTable C = {
|
||||
|
||||
.commonEmcMemVolt = 1175000, /* LPDDR4(X) JEDEC Specification */
|
||||
.eristaEmcMaxClock = 1600000, /* Maximum HB-MGCH ram rating */
|
||||
.eristaEmcMaxClock1 = 1600000,
|
||||
.eristaEmcMaxClock2 = 1600000,
|
||||
|
||||
/* Available: 66MHz step rate, 100MHz step rate and jedec. */
|
||||
/* Available: 66MHz step rate, 100MHz step rate, 133MHz step rate and jedec. */
|
||||
/* Jedec freqs are 1333MHz, 1600MHz, 1866MHz, 2133MHz, 2400MHz, 2666MHz, 2933MHz, 3200MHz. */
|
||||
.stepMode = StepMode_66MHz,
|
||||
|
||||
.marikoEmcMaxClock = 2133000, /* 1866MHz @ 1866tWRL is guaranteed to work on all Mariko units */
|
||||
.marikoEmcVddqVolt = 600000,
|
||||
.emcDvbShift = 0,
|
||||
|
||||
// Primary
|
||||
.t1_tRCD = 0,
|
||||
.t2_tRP = 0,
|
||||
.t3_tRAS = 0,
|
||||
// Secondary
|
||||
.t4_tRRD = 0,
|
||||
.t5_tRFC = 0,
|
||||
.t6_tRTW = 0,
|
||||
.t7_tWTR = 0,
|
||||
.t8_tREFI = 0,
|
||||
.emcDvbShift = 0,
|
||||
.marikoSocVmax = 0, /* 0 = stock limits (1450 - 1597 is 1050mV, 1598-1708 is 1025mV, 1709+ is 1000mV). */
|
||||
|
||||
/* Primary. */
|
||||
.t1_tRCD = 0,
|
||||
.t2_tRP = 0,
|
||||
.t3_tRAS = 0,
|
||||
/* Secondary. */
|
||||
.t4_tRRD = 0,
|
||||
.t5_tRFC = 0,
|
||||
.t6_tRTW = 0,
|
||||
.t7_tWTR = 0,
|
||||
.t8_tREFI = 0,
|
||||
|
||||
/* At 1333WL, for some reason (incorrect ram timing config in mtc table?), tRP causes crashes at high reductions - 2 seems to be the most common limit. */
|
||||
/* This is a lazy workaround until I find the issue... */
|
||||
@@ -65,54 +65,44 @@ volatile CustomizeTable C = {
|
||||
|
||||
/* Frequency where non low timings gets used. */
|
||||
.timingEmcTbreak = DISABLED,
|
||||
.low_t6_tRTW = DISABLED,
|
||||
.low_t7_tWTR = DISABLED,
|
||||
.low_t1_tRCD = 0,
|
||||
.low_t2_tRP = 0,
|
||||
.low_t3_tRAS = 0,
|
||||
.low_t4_tRRD = 0,
|
||||
.low_t5_tRFC = 0,
|
||||
.low_t6_tRTW = 0,
|
||||
.low_t7_tWTR = 0,
|
||||
.low_t8_tREFI = 0,
|
||||
|
||||
.readLatency = {
|
||||
DISABLED,
|
||||
DISABLED,
|
||||
DISABLED,
|
||||
DISABLED,
|
||||
/* 1333 */ 0,
|
||||
/* 1600 */ 0,
|
||||
/* 1866 */ 0,
|
||||
/* 2133 */ 0,
|
||||
},
|
||||
|
||||
.writeLatency = {
|
||||
DISABLED,
|
||||
DISABLED,
|
||||
DISABLED,
|
||||
DISABLED,
|
||||
/* 1333 */ 0,
|
||||
/* 1600 */ 0,
|
||||
/* 1866 */ 0,
|
||||
/* 2133 */ 0,
|
||||
},
|
||||
|
||||
/* You can mix and match different latencies if needed */
|
||||
/*
|
||||
* Read:
|
||||
* 2133RL = 40
|
||||
* 1866RL = 36
|
||||
* 1600RL = 32
|
||||
* 1331RL = 28
|
||||
* Write:
|
||||
* 2133WL = 18
|
||||
* 1866WL = 16
|
||||
* 1600WL = 14
|
||||
* 1331WL = 12
|
||||
*/
|
||||
|
||||
.mem_burst_read_latency = RL_1600,
|
||||
.mem_burst_write_latency = WL_1600,
|
||||
|
||||
.eristaCpuUV = 0,
|
||||
.eristaCpuVmin = 800,
|
||||
.eristaCpuUV = 0,
|
||||
.eristaCpuVmin = 800,
|
||||
.eristaCpuMaxVolt = 1200,
|
||||
/* Unlocks up to 2397 Mhz CPU, usage is not recommended. */
|
||||
.eristaCpuUnlock = DISABLED,
|
||||
.eristaCpuUnlock = DISABLED,
|
||||
|
||||
.marikoCpuUVLow = 0, // No undervolt
|
||||
.marikoCpuUVLow = 0, // No undervolt
|
||||
.marikoCpuUVHigh = 0, // No undervolt
|
||||
|
||||
.tableConf = TBREAK_1683,
|
||||
.marikoCpuLowVmin = 620,
|
||||
.tableConf = TBREAK_1683,
|
||||
.marikoCpuLowVmin = 620,
|
||||
.marikoCpuHighVmin = 750,
|
||||
|
||||
/* 1120mV is NVIDIA rating */
|
||||
.marikoCpuMaxVolt = 1120,
|
||||
.marikoCpuMaxVolt = 1120,
|
||||
|
||||
/* Supported values: 1963500, 2091000, 2193000, 2295000, 2397000, 2499000, 2601000, 2703000. */
|
||||
/* 1963500 is official rating of T214/Mariko, fully safe. */
|
||||
@@ -123,29 +113,23 @@ volatile CustomizeTable C = {
|
||||
/* 2703000 is potentially dangerous and not advised. */
|
||||
.marikoCpuMaxClock = 1963500,
|
||||
|
||||
.eristaCpuBoostClock = 1785000, // Default boost clock
|
||||
.marikoCpuBoostClock = 1963500, // Default boost clock
|
||||
.eristaCpuBoostClock = 1785000, /* Default boost clock */
|
||||
.marikoCpuBoostClock = 1963500, /* Default boost clock */
|
||||
|
||||
.eristaGpuUV = 0,
|
||||
.eristaGpuUV = 0,
|
||||
.eristaGpuVmin = 810,
|
||||
|
||||
.marikoGpuUV = 0,
|
||||
|
||||
.marikoGpuUV = 2,
|
||||
/* Vmin past 795mV won't work due boot voltage being 800mV. */
|
||||
.marikoGpuVmin = 610,
|
||||
|
||||
.marikoGpuVmax = 800,
|
||||
|
||||
.commonGpuVoltOffset = 0,
|
||||
|
||||
/* Speedo is automatically set by hoc-clk on first boot */
|
||||
.gpuSpeedo = 1450,
|
||||
|
||||
/* Setting DEACTIVATED_GPU_FREQ on any freq will disable it and all freqs greater than it. (the latter is a bug :/) */
|
||||
/* AUTO: Voltage is optimally chosen; with commonGpuVoltOffset applied. */
|
||||
/* AUTO only works up to 1305 GPU on Mariko and 998 GPU on Erista (it is reccomended to manually set your 998MHz voltage though) */
|
||||
/* You can overwrite auto with any voltage (in mv) of your choice - offset will not be applied. */
|
||||
|
||||
.eristaGpuVoltArray = {
|
||||
AUTO /* 76 */,
|
||||
AUTO /* 115 */,
|
||||
@@ -177,30 +161,60 @@ volatile CustomizeTable C = {
|
||||
},
|
||||
|
||||
.marikoGpuVoltArray = {
|
||||
AUTO /* 76 */,
|
||||
AUTO /* 153 */,
|
||||
AUTO /* 230 */,
|
||||
AUTO /* 307 */,
|
||||
AUTO /* 384 */,
|
||||
AUTO /* 460 */,
|
||||
AUTO /* 537 */,
|
||||
AUTO /* 614 */,
|
||||
AUTO /* 691 */,
|
||||
AUTO /* 768 */,
|
||||
AUTO /* 844 */,
|
||||
AUTO /* 921 */,
|
||||
AUTO /* 998 */,
|
||||
AUTO /* 1075 */,
|
||||
AUTO /* 1152 (SLT / HiOPT Only!) */,
|
||||
AUTO /* 1228 (HiOPT Only!) */,
|
||||
DEACTIVATED_GPU_FREQ /* 1267 (Disabled by default) */,
|
||||
DEACTIVATED_GPU_FREQ /* 1305 (Disabled by default) */,
|
||||
DEACTIVATED_GPU_FREQ /* 1344 (Disabled by default) */,
|
||||
DEACTIVATED_GPU_FREQ /* 1382 (Disabled by default) */,
|
||||
DEACTIVATED_GPU_FREQ /* 1420 (Disabled by default) */,
|
||||
DEACTIVATED_GPU_FREQ /* 1459 (Disabled by default) */,
|
||||
DEACTIVATED_GPU_FREQ /* 1497 (Disabled by default) */,
|
||||
DEACTIVATED_GPU_FREQ /* 1536 (Disabled by default) */,
|
||||
AUTO /* 76 */,
|
||||
AUTO /* 153 */,
|
||||
AUTO /* 230 */,
|
||||
AUTO /* 307 */,
|
||||
AUTO /* 384 */,
|
||||
AUTO /* 460 */,
|
||||
AUTO /* 537 */,
|
||||
AUTO /* 614 */,
|
||||
AUTO /* 691 */,
|
||||
AUTO /* 768 */,
|
||||
AUTO /* 844 */,
|
||||
AUTO /* 921 */,
|
||||
AUTO /* 998 */,
|
||||
AUTO /* 1075 */,
|
||||
AUTO /* 1152 (HioPT / High UV only!) */,
|
||||
AUTO /* 1228 (High UV Only!) */,
|
||||
DEACTIVATED_GPU_FREQ /* 1267 (Disabled by default) */,
|
||||
DEACTIVATED_GPU_FREQ /* 1305 (Disabled by default) */,
|
||||
DEACTIVATED_GPU_FREQ /* 1344 (Disabled by default) */,
|
||||
DEACTIVATED_GPU_FREQ /* 1382 (Disabled by default) */,
|
||||
DEACTIVATED_GPU_FREQ /* 1420 (Disabled by default) */,
|
||||
DEACTIVATED_GPU_FREQ /* 1459 (Disabled by default) */,
|
||||
DEACTIVATED_GPU_FREQ /* 1497 (Disabled by default) */,
|
||||
DEACTIVATED_GPU_FREQ /* 1536 (Disabled by default) */,
|
||||
},
|
||||
|
||||
/* Override soc voltage brackets. */
|
||||
.marikoSocVoltArray = {
|
||||
0 /* >= 1866 */,
|
||||
0 /* >= 2000 */,
|
||||
0 /* >= 2133 */,
|
||||
0 /* >= 2200 */,
|
||||
0 /* >= 2266 */,
|
||||
0 /* >= 2333 */,
|
||||
0 /* >= 2400 */,
|
||||
0 /* >= 2433 */,
|
||||
0 /* >= 2466 */,
|
||||
0 /* >= 2533 */,
|
||||
0 /* >= 2566 */,
|
||||
0 /* >= 2600 */,
|
||||
0 /* >= 2666 */,
|
||||
0 /* >= 2700 */,
|
||||
0 /* >= 2733 */,
|
||||
0 /* >= 2766 */,
|
||||
0 /* >= 2800 */,
|
||||
0 /* >= 2833 */,
|
||||
0 /* >= 2900 */,
|
||||
0 /* >= 2933 */,
|
||||
0 /* >= 3000 */,
|
||||
0 /* >= 3033 */,
|
||||
0 /* >= 3100 */,
|
||||
0 /* >= 3133 */,
|
||||
0 /* >= 3166 */,
|
||||
0 /* >= 3200 */,
|
||||
},
|
||||
|
||||
/* Advanced. */
|
||||
@@ -478,6 +492,47 @@ volatile CustomizeTable C = {
|
||||
},
|
||||
|
||||
.marikoGpuDvfsTable = {
|
||||
{ 76800, {}, { 610000, } },
|
||||
{ 153600, {}, { 610000, } },
|
||||
{ 230400, {}, { 610000, } },
|
||||
{ 307200, {}, { 610000, } },
|
||||
{ 384000, {}, { 610000, } },
|
||||
{ 460800, {}, { 610000, } },
|
||||
{ 537600, {}, { 801688, -10900, -163, 298, -10599, 162 } },
|
||||
{ 614400, {}, { 824214, -5743, -452, 238, -6325, 81 } },
|
||||
{ 691200, {}, { 848830, -3903, -552, 119, -4030, -2 } },
|
||||
{ 768000, {}, { 891575, -4409, -584, 0, -2849, 39 } },
|
||||
{ 844800, {}, { 940071, -5367, -602, -60, -63, -93 } },
|
||||
{ 921600, {}, { 986765, -6637, -614, -179, 1905, -13 } },
|
||||
{ 998400, {}, { 1098475, -13529, -497, -179, 3626, 9 } },
|
||||
// { 1075200, {}, { 1163644, -12688, -648, 0, 1077, 40 } },
|
||||
// { 1152000, {}, { 1204812, -9908, -830, 0, 1469, 110 } },
|
||||
// { 1228800, {}, { 1277303, -11675, -859, 0, 3722, 313 } },
|
||||
// { 1267200, {}, { 1335531, -12567, -867, 0, 3681, 559 } },
|
||||
// { 1305600, {}, { 1374130, -13725, -859, 0, 4442, 576 } },
|
||||
},
|
||||
|
||||
.marikoGpuDvfsTableSLT = {
|
||||
{ 76800, {}, { 590000, } },
|
||||
{ 153600, {}, { 590000, } },
|
||||
{ 230400, {}, { 590000, } },
|
||||
{ 307200, {}, { 590000, } },
|
||||
{ 384000, {}, { 590000, } },
|
||||
{ 460800, {}, { 795089, -11096, -163, 298, -10421, 162 } },
|
||||
{ 537600, {}, { 795089, -11096, -163, 298, -10421, 162 } },
|
||||
{ 614400, {}, { 820606, -6285, -452, 238, -6182, 81 } },
|
||||
{ 691200, {}, { 846289, -4565, -552, 119, -3958, -2 } },
|
||||
{ 768000, {}, { 888720, -5110, -584, 0, -2849, 39 } },
|
||||
{ 844800, {}, { 936634, -6089, -602, -60, -99, -93 } },
|
||||
{ 921600, {}, { 982562, -7373, -614, -179, 1797, -13 } },
|
||||
{ 998400, {}, { 1090179, -14125, -497, -179, 3518, 9 } },
|
||||
{ 1075200, {}, { 1155798, -13465, -648, 0, 1077, 40 } },
|
||||
// { 1152000, {}, { 1198568, -10904, -830, 0, 1469, 110 } },
|
||||
// { 1228800, {}, { 1269988, -12707, -859, 0, 3722, 313 } },
|
||||
// { 1267200, {}, { 1308155, -13694, -867, 0, 3681, 559 } },
|
||||
},
|
||||
|
||||
.marikoGpuDvfsTableHiOPT = {
|
||||
{ 76800, { }, { GPU_MIN_MIN_VOLT, } },
|
||||
{ 153600, { }, { GPU_MIN_MIN_VOLT, } },
|
||||
{ 230400, { }, { GPU_MIN_MIN_VOLT, } },
|
||||
@@ -492,12 +547,12 @@ volatile CustomizeTable C = {
|
||||
{ 921600, { }, { 970060,-10108, -614,-179, 1508, -13 } },
|
||||
{ 998400, { }, { 1065665,-16075, -497,-179, 3213, 9 } },
|
||||
{ 1075200, { }, { 1132576,-16093, -648, 0, 1077, 40 } },
|
||||
// { 1152000, { }, { 1180029,-14534, -830, 0, 1469, 110 } },
|
||||
{ 1152000, { }, { 1180029,-14534, -830, 0, 1469, 110 } },
|
||||
// { 1228800, { }, { 1248293,-16383, -859, 0, 3722, 313 } },
|
||||
// { 1267200, { }, { 1286399,-17475, -867, 0, 3681, 559 } },
|
||||
},
|
||||
|
||||
.marikoGpuDvfsTableSLT = {
|
||||
.marikoGpuDvfsTableHiOPT15 = {
|
||||
{ 76800, { }, { GPU_MIN_MIN_VOLT, } },
|
||||
{ 153600, { }, { GPU_MIN_MIN_VOLT, } },
|
||||
{ 230400, { }, { GPU_MIN_MIN_VOLT, } },
|
||||
@@ -513,11 +568,11 @@ volatile CustomizeTable C = {
|
||||
{ 998400, { }, { 1065665, -16075, -497, -179, 3213, 9 } },
|
||||
{ 1075200, { }, { 1132576, -16093, -648, 0, 1077, 40 } },
|
||||
{ 1152000, { }, { 1180029, -14534, -830, 0, 1469, 110 } },
|
||||
{ 1228800, { }, { 1238293, -16383, -859, 0, 3722, 313 } },
|
||||
// { 1228800, { }, { 1238293, -16383, -859, 0, 3722, 313 } },
|
||||
// { 1267200, { }, { 1276399, -17475, -867, 0, 3681, 559 } },
|
||||
},
|
||||
|
||||
.marikoGpuDvfsTableHiOPT = {
|
||||
.marikoGpuDvfsTableHighUV = {
|
||||
{ 76800, { }, { GPU_MIN_MIN_VOLT, } },
|
||||
{ 153600, { }, { GPU_MIN_MIN_VOLT, } },
|
||||
{ 230400, { }, { GPU_MIN_MIN_VOLT, } },
|
||||
|
||||
@@ -20,19 +20,18 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#define CUST_REV 2
|
||||
#define CUST_REV 5
|
||||
#define KIP_VERSION 242
|
||||
|
||||
#include "oc_common.hpp"
|
||||
#include "pcv/pcv_common.hpp"
|
||||
|
||||
namespace ams::ldr::hoc {
|
||||
|
||||
#include "mtc_timing_table.hpp"
|
||||
|
||||
enum TableConfig: u32 {
|
||||
DEFAULT_TABLE = 1,
|
||||
TBREAK_1581 = 2,
|
||||
TBREAK_1683 = 3,
|
||||
TBREAK_1581 = 2,
|
||||
TBREAK_1683 = 3,
|
||||
EXTREME_TABLE = 4,
|
||||
};
|
||||
|
||||
@@ -40,21 +39,9 @@ enum StepMode: u32 {
|
||||
StepMode_66MHz = 0,
|
||||
StepMode_100MHz = 1,
|
||||
StepMode_Jedec = 2,
|
||||
StepMode_133MHz = 3,
|
||||
};
|
||||
|
||||
/*
|
||||
* Read:
|
||||
* 2133RL = 40
|
||||
* 1866RL = 36
|
||||
* 1600RL = 32
|
||||
* 1331RL = 28
|
||||
* Write:
|
||||
* 2133WL = 18
|
||||
* 1866WL = 16
|
||||
* 1600WL = 14
|
||||
* 1331WL = 12
|
||||
*/
|
||||
|
||||
enum ReadLatency: u32 {
|
||||
RL_2133 = 40,
|
||||
RL_1866 = 36,
|
||||
@@ -74,25 +61,21 @@ using CustomizeGpuDvfsTable = pcv::cvb_entry_t[pcv::DvfsTableEntryLimit];
|
||||
static_assert(sizeof(CustomizeCpuDvfsTable) == sizeof(CustomizeGpuDvfsTable));
|
||||
static_assert(sizeof(CustomizeCpuDvfsTable) == sizeof(pcv::cvb_entry_t) * pcv::DvfsTableEntryLimit);
|
||||
|
||||
constexpr uint32_t ERISTA_MTC_MAGIC = 0x43544D45; // EMTC
|
||||
constexpr uint32_t MARIKO_MTC_MAGIC = 0x43544D4D; // MMTC
|
||||
struct CustomizeTable {
|
||||
u8 cust[4] = {'C', 'U', 'S', 'T'};
|
||||
u32 custRev = CUST_REV;
|
||||
u32 kipVersion = KIP_VERSION;
|
||||
|
||||
typedef struct CustomizeTable {
|
||||
u8 cust[4] = {'C', 'U', 'S', 'T'};
|
||||
u32 custRev = CUST_REV;
|
||||
|
||||
u32 placeholder;
|
||||
u32 hpMode;
|
||||
|
||||
u32 commonEmcMemVolt;
|
||||
u32 eristaEmcMaxClock;
|
||||
u32 eristaEmcMaxClock1;
|
||||
u32 eristaEmcMaxClock2;
|
||||
|
||||
StepMode stepMode;
|
||||
u32 marikoEmcMaxClock;
|
||||
u32 marikoEmcVddqVolt;
|
||||
u32 emcDvbShift;
|
||||
s32 emcDvbShift;
|
||||
u32 marikoSocVmax;
|
||||
// advanced config
|
||||
u32 t1_tRCD;
|
||||
u32 t2_tRP;
|
||||
@@ -106,15 +89,18 @@ typedef struct CustomizeTable {
|
||||
u32 t2_tRP_cap;
|
||||
|
||||
u32 timingEmcTbreak;
|
||||
u32 low_t1_tRCD;
|
||||
u32 low_t2_tRP;
|
||||
u32 low_t3_tRAS;
|
||||
u32 low_t4_tRRD;
|
||||
u32 low_t5_tRFC;
|
||||
u32 low_t6_tRTW;
|
||||
u32 low_t7_tWTR;
|
||||
u32 low_t8_tREFI;
|
||||
|
||||
u32 readLatency[4];
|
||||
u32 writeLatency[4];
|
||||
|
||||
u32 mem_burst_read_latency;
|
||||
u32 mem_burst_write_latency;
|
||||
|
||||
u32 eristaCpuUV;
|
||||
u32 eristaCpuVmin;
|
||||
u32 eristaCpuMaxVolt;
|
||||
@@ -138,12 +124,11 @@ typedef struct CustomizeTable {
|
||||
u32 marikoGpuVmin;
|
||||
u32 marikoGpuVmax;
|
||||
|
||||
u32 commonGpuVoltOffset;
|
||||
|
||||
u32 gpuSpeedo;
|
||||
s32 commonGpuVoltOffset;
|
||||
|
||||
u32 eristaGpuVoltArray[27];
|
||||
u32 marikoGpuVoltArray[24];
|
||||
s32 marikoSocVoltArray[26];
|
||||
|
||||
u32 fineTune_t6_tRTW;
|
||||
u32 fineTune_t7_tWTR;
|
||||
@@ -166,8 +151,10 @@ typedef struct CustomizeTable {
|
||||
CustomizeGpuDvfsTable marikoGpuDvfsTable;
|
||||
CustomizeGpuDvfsTable marikoGpuDvfsTableSLT;
|
||||
CustomizeGpuDvfsTable marikoGpuDvfsTableHiOPT;
|
||||
CustomizeGpuDvfsTable marikoGpuDvfsTableHiOPT15;
|
||||
CustomizeGpuDvfsTable marikoGpuDvfsTableHighUV;
|
||||
|
||||
} CustomizeTable;
|
||||
};
|
||||
|
||||
extern volatile CustomizeTable C;
|
||||
|
||||
|
||||
@@ -14,16 +14,126 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <stratosphere.hpp>
|
||||
#include "../mtc_timing_value.hpp"
|
||||
|
||||
namespace ams::ldr::hoc::pcv::erista {
|
||||
|
||||
void CalculateTimings(double tCK_avg) {
|
||||
tR2W = FLOOR(FLOOR((5.0 / tCK_avg) + ((FLOOR(48.0 / WL) - 0.478) * 3.0)) / 1.501) + RL - (C.t6_tRTW * 3) + finetRTW;
|
||||
void SwitchLatency(volatile u32 &latency, u32 index, u32 latencyStep) {
|
||||
latency += index * latencyStep;
|
||||
}
|
||||
|
||||
static s32 GetMaxLatencyIndex(volatile u32 *latencyArray, u32 latencySize) {
|
||||
s32 maxIndex = -1;
|
||||
for (u32 i = 0; i < latencySize; ++i) {
|
||||
if (latencyArray[i]) {
|
||||
maxIndex = i;
|
||||
}
|
||||
}
|
||||
|
||||
return maxIndex;
|
||||
}
|
||||
|
||||
void AutoLatency(volatile u32 &latency, u32 freq, u32 latencyStep) {
|
||||
if (freq > 1600'000 && freq <= 1866'000) { /* 1866tRWL */
|
||||
latency += latencyStep * 2;
|
||||
} else { /* 2133tRWL */
|
||||
latency += latencyStep * 3;
|
||||
}
|
||||
}
|
||||
|
||||
void HandleLatency(u32 freq, volatile u32 &latency, volatile u32 *latencyArray, u32 indexMax, u32 latencyStep) {
|
||||
for (u32 i = 0; i <= indexMax; ++i) {
|
||||
if (latencyArray[i] != 0 && freq <= latencyArray[i]) {
|
||||
SwitchLatency(latency, i, latencyStep);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
SwitchLatency(latency, indexMax, latencyStep);
|
||||
}
|
||||
|
||||
void HandleLatency(u32 freq) {
|
||||
static s32 rlIndexMax = GetMaxLatencyIndex(C.readLatency, std::size(C.readLatency));
|
||||
static s32 wlIndexMax = GetMaxLatencyIndex(C.writeLatency, std::size(C.writeLatency));
|
||||
constexpr u32 ReadLatencyStep = 4;
|
||||
constexpr u32 WriteLatencyStep = 2;
|
||||
bool autoLatencyRead = false, autoLatencyWrite = false;
|
||||
|
||||
if (rlIndexMax == -1) {
|
||||
AutoLatency(RL, freq, ReadLatencyStep);
|
||||
autoLatencyRead = true;
|
||||
}
|
||||
|
||||
if (wlIndexMax == -1) {
|
||||
AutoLatency(WL, freq, WriteLatencyStep);
|
||||
autoLatencyWrite = true;
|
||||
}
|
||||
|
||||
if (autoLatencyRead && autoLatencyWrite) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!autoLatencyRead) {
|
||||
HandleLatency(freq, RL, C.readLatency, rlIndexMax, ReadLatencyStep);
|
||||
}
|
||||
|
||||
if (!autoLatencyWrite) {
|
||||
HandleLatency(freq, WL, C.writeLatency, wlIndexMax, WriteLatencyStep);
|
||||
}
|
||||
}
|
||||
|
||||
void CalculateMrw2() {
|
||||
static const u8 rlMapDBI[8] = {
|
||||
6, 12, 16, 22, 28, 32, 36, 40
|
||||
};
|
||||
|
||||
static const u8 wlMapSetA[8] = {
|
||||
4, 6, 8, 10, 12, 14, 16, 18
|
||||
};
|
||||
|
||||
u32 rlIndex = 0;
|
||||
u32 wlIndex = 0;
|
||||
|
||||
for (u32 i = 0; i < std::size(rlMapDBI); ++i) {
|
||||
if (rlMapDBI[i] == 32) {
|
||||
rlIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (u32 i = 0; i < std::size(wlMapSetA); ++i) {
|
||||
if (wlMapSetA[i] == WL) {
|
||||
wlIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* DBI is always enabled. */
|
||||
mrw2 = static_cast<u8>(((rlIndex & 0x7) | ((wlIndex & 0x7) << 3) | ((0 & 0x1) << 6)));
|
||||
}
|
||||
|
||||
void CalculateTimings(double tCK_avg, u32 freq) {
|
||||
RL = RL_1331;
|
||||
WL = WL_1331;
|
||||
|
||||
HandleLatency(freq);
|
||||
CalculateMrw2();
|
||||
|
||||
tR2P = CEIL((RL * 0.426) - 2.0);
|
||||
tR2W = FLOOR(FLOOR((5.0 / tCK_avg) + ((FLOOR(48.0 / WL) - 0.478) * 3.0)) / 1.501) + RL - (C.t6_tRTW * 3) + finetRTW;
|
||||
|
||||
tW2P = (CEIL(WL * 1.7303) * 2) - 5;
|
||||
tWTPDEN = CEIL(((1.803 / tCK_avg) + MAX(RL + (2.694 / tCK_avg), static_cast<double>(tW2P))) + (BL / 2));
|
||||
tW2R = FLOOR(MAX((5.020 / tCK_avg) + 1.130, WL - MAX(-CEIL(0.258 * (WL - RL)), 1.964)) * 1.964) + WL - CEIL(tWTR / tCK_avg) + finetWTR;
|
||||
|
||||
wdv = WL;
|
||||
wsv = WL - 2;
|
||||
wev = 0xA + (WL - 14);
|
||||
|
||||
u32 obdlyHigh = 3 / FLOOR(MIN(static_cast<double>(2), tCK_avg * (WL - 7)));
|
||||
u32 obdlyLow = MAX(WL - FLOOR((126.0 / CEIL(tCK_avg + 8.601))), 0.0);
|
||||
obdly = PACK_U32_NIBBLE_HIGH_BYTE_LOW(obdlyHigh, obdlyLow);
|
||||
|
||||
pdex2rw = CEIL((CEIL(12.335 - tCK_avg) + (7.430 / tCK_avg) - CEIL(tCK_avg * 11.361)));
|
||||
tCLKSTOP = FLOOR(MIN(8.488 / tCK_avg, 23.0)) + 8.0;
|
||||
|
||||
|
||||
@@ -18,6 +18,6 @@
|
||||
|
||||
namespace ams::ldr::hoc::pcv::erista {
|
||||
|
||||
void CalculateTimings(double tCK_avg);
|
||||
void CalculateTimings(double tCK_avg, u32 freq);
|
||||
|
||||
}
|
||||
|
||||
@@ -26,16 +26,16 @@ namespace ams::ldr::hoc::pcv::mariko {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Fallback. */
|
||||
rext = 0x1A;
|
||||
/* > 3200 */
|
||||
rext = 0x1E;
|
||||
}
|
||||
|
||||
void SwitchLatency(volatile u32 &latency, u32 index, u32 latencyStep) {
|
||||
latency += index * latencyStep;
|
||||
}
|
||||
|
||||
static u32 GetMaxLatencyIndex(volatile u32 *latencyArray, u32 latencySize) {
|
||||
u32 maxIndex = 0;
|
||||
static s32 GetMaxLatencyIndex(volatile u32 *latencyArray, u32 latencySize) {
|
||||
s32 maxIndex = -1;
|
||||
for (u32 i = 0; i < latencySize; ++i) {
|
||||
if (latencyArray[i]) {
|
||||
maxIndex = i;
|
||||
@@ -46,7 +46,7 @@ namespace ams::ldr::hoc::pcv::mariko {
|
||||
}
|
||||
|
||||
void AutoLatency(volatile u32 &latency, u32 freq, u32 latencyStep) {
|
||||
if (freq > 1600'000 && freq <= 1866'000) { /* 1866tRWL */
|
||||
if (freq > 1600'000 && freq <= 1862'400) { /* 1866tRWL */
|
||||
latency += latencyStep * 2;
|
||||
} else { /* 2133tRWL */
|
||||
latency += latencyStep * 3;
|
||||
@@ -65,18 +65,18 @@ namespace ams::ldr::hoc::pcv::mariko {
|
||||
}
|
||||
|
||||
void HandleLatency(u32 freq) {
|
||||
static u32 rlIndexMax = GetMaxLatencyIndex(C.readLatency, std::size(C.readLatency));
|
||||
static u32 wlIndexMax = GetMaxLatencyIndex(C.writeLatency, std::size(C.writeLatency));
|
||||
static s32 rlIndexMax = GetMaxLatencyIndex(C.readLatency, std::size(C.readLatency));
|
||||
static s32 wlIndexMax = GetMaxLatencyIndex(C.writeLatency, std::size(C.writeLatency));
|
||||
constexpr u32 ReadLatencyStep = 4;
|
||||
constexpr u32 WriteLatencyStep = 2;
|
||||
bool autoLatencyRead = false, autoLatencyWrite = false;
|
||||
|
||||
if (rlIndexMax == 0) {
|
||||
if (rlIndexMax == -1) {
|
||||
AutoLatency(RL, freq, ReadLatencyStep);
|
||||
autoLatencyRead = true;
|
||||
}
|
||||
|
||||
if (wlIndexMax == 0) {
|
||||
if (wlIndexMax == -1) {
|
||||
AutoLatency(WL, freq, WriteLatencyStep);
|
||||
autoLatencyWrite = true;
|
||||
}
|
||||
@@ -120,6 +120,7 @@ namespace ams::ldr::hoc::pcv::mariko {
|
||||
}
|
||||
}
|
||||
|
||||
/* DBI is always enabled. */
|
||||
mrw2 = static_cast<u8>(((rlIndex & 0x7) | ((wlIndex & 0x7) << 3) | ((0 & 0x1) << 6)));
|
||||
}
|
||||
|
||||
@@ -133,32 +134,37 @@ namespace ams::ldr::hoc::pcv::mariko {
|
||||
|
||||
/* At 1333WL, for some reason (incorrect ram timing config in mtc table?), tRP causes crashes at high reductions - 2 seems to be the most common limit. */
|
||||
/* This is a lazy workaround until I find the issue... */
|
||||
u32 tRPpbIndex = C.t2_tRP;
|
||||
const bool lowFreq = freq < C.timingEmcTbreak;
|
||||
volatile u32 tRPpbIndex = lowFreq ? C.low_t2_tRP : C.t2_tRP;
|
||||
|
||||
if (WL == WL_1331) {
|
||||
tRPpbIndex = MIN(C.t2_tRP_cap, C.t2_tRP);
|
||||
tRPpbIndex = MIN(C.t2_tRP_cap, tRPpbIndex);
|
||||
}
|
||||
|
||||
tRCD = tRCD_values[C.t1_tRCD];
|
||||
tRPpb = tRP_values[tRPpbIndex];
|
||||
tRAS = tRAS_values[C.t3_tRAS];
|
||||
tRRD = tRRD_values[C.t4_tRRD];
|
||||
tRFCpb = tRFC_values[C.t5_tRFC];
|
||||
u32 tRTW = C.t6_tRTW;
|
||||
u32 tWTR = 10 - tWTR_values[C.t7_tWTR];
|
||||
tRCD = tRCD_values[lowFreq ? C.low_t1_tRCD : C.t1_tRCD];
|
||||
tRPpb = tRP_values[tRPpbIndex];
|
||||
tRAS = tRAS_values[lowFreq ? C.low_t3_tRAS : C.t3_tRAS];
|
||||
tRRD = tRRD_values[lowFreq ? C.low_t4_tRRD : C.t4_tRRD];
|
||||
tRFCpb = tRFC_values[lowFreq ? C.low_t5_tRFC : C.t5_tRFC];
|
||||
|
||||
if (freq < C.timingEmcTbreak) {
|
||||
tRTW = C.low_t6_tRTW;
|
||||
tWTR = 10 - tWTR_values[C.low_t7_tWTR];
|
||||
}
|
||||
u32 tRTW = lowFreq ? C.low_t6_tRTW : C.t6_tRTW;
|
||||
u32 tWTR = 10 - tWTR_values[lowFreq ? C.low_t7_tWTR : C.t7_tWTR];
|
||||
|
||||
s32 finetRTW = C.fineTune_t6_tRTW;
|
||||
s32 finetWTR = C.fineTune_t7_tWTR;
|
||||
|
||||
tRC = tRAS + tRPpb;
|
||||
tRFCab = tRFCpb * 2;
|
||||
tXSR = static_cast<double>(tRFCab + 7.5);
|
||||
tFAW = static_cast<u32>(tRRD * 4.0);
|
||||
tRPab = tRPpb + 3;
|
||||
u32 tREFI = lowFreq ? C.low_t8_tREFI : C.t8_tREFI;
|
||||
refresh_raw = 0xFFFF;
|
||||
if (tREFI != 6) {
|
||||
refresh_raw = CEIL(tREFpb_values[tREFI] / tCK_avg) - 0x40;
|
||||
refresh_raw = MIN(refresh_raw, static_cast<u32>(0xFFFF));
|
||||
}
|
||||
|
||||
tRC = tRAS + tRPpb;
|
||||
tRFCab = tRFCpb * 2;
|
||||
tXSR = static_cast<double>(tRFCab + 7.5);
|
||||
tFAW = static_cast<u32>(tRRD * 4.0);
|
||||
tRPab = tRPpb + 3;
|
||||
|
||||
tR2P = CEIL((RL * 0.426) - 2.0);
|
||||
tR2W = FLOOR(FLOOR((5.0 / tCK_avg) + ((FLOOR(48.0 / WL) - 0.478) * 3.0)) / 1.501) + RL - (tRTW * 3) + finetRTW;
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "../mtc_timing_value.hpp"
|
||||
#include "../oc_common.hpp"
|
||||
#include "timing_tables.hpp"
|
||||
|
||||
namespace ams::ldr::hoc::pcv::mariko {
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "../mtc_timing_value.hpp"
|
||||
#include <stratosphere.hpp>
|
||||
|
||||
namespace ams::ldr::hoc::pcv::mariko {
|
||||
|
||||
|
||||
@@ -33,10 +33,6 @@ namespace ams::ldr::hoc {
|
||||
/* Burst latency, not to be confused with base latency (tWRL). */
|
||||
const u32 BL = 16;
|
||||
|
||||
/* Base latency for read and write (tWRL). */
|
||||
const u32 RL = C.mem_burst_read_latency;
|
||||
const u32 WL = C.mem_burst_write_latency;
|
||||
|
||||
/* Precharge to Precharge Delay. (tCK) */
|
||||
const u32 tPPD = 4;
|
||||
|
||||
@@ -87,19 +83,30 @@ namespace ams::ldr::hoc {
|
||||
const u32 tFAW = static_cast<u32>(tRRD * 4.0);
|
||||
const double tRPab = tRPpb + 3;
|
||||
|
||||
const u32 tR2P = CEIL((RL * 0.426) - 2.0);
|
||||
inline u32 RL;
|
||||
inline u32 WL;
|
||||
|
||||
inline u32 tR2P;
|
||||
inline u32 tR2W;
|
||||
inline u32 rext;
|
||||
|
||||
const u32 tW2P = (CEIL(WL * 1.7303) * 2) - 5;
|
||||
inline u32 tW2P;
|
||||
inline u32 tWTPDEN;
|
||||
inline u32 tW2R;
|
||||
|
||||
inline u32 wdv;
|
||||
inline u32 wsv;
|
||||
inline u32 wev;
|
||||
|
||||
inline u32 obdly;
|
||||
|
||||
inline u32 pdex2rw;
|
||||
|
||||
inline u32 tCLKSTOP;
|
||||
|
||||
inline double pdex2mrr;
|
||||
|
||||
inline u8 mrw2;
|
||||
}
|
||||
|
||||
namespace pcv::mariko {
|
||||
@@ -123,6 +130,8 @@ namespace ams::ldr::hoc {
|
||||
inline u32 tFAW;
|
||||
inline double tRPab;
|
||||
|
||||
inline u32 refresh_raw;
|
||||
|
||||
inline u32 RL;
|
||||
inline u32 WL;
|
||||
|
||||
|
||||
@@ -18,17 +18,16 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef ATMOSPHERE_IS_STRATOSPHERE
|
||||
#include <stratosphere.hpp>
|
||||
#include <vapours/results/results_common.hpp>
|
||||
#define LOGGING(fmt, ...) ((void)0)
|
||||
#define CRASH(msg, ...) { ams::diag::AbortImpl(msg, __PRETTY_FUNCTION__, "", 0); __builtin_unreachable(); }
|
||||
#else
|
||||
#include "oc_test.hpp"
|
||||
#endif
|
||||
#include <stratosphere.hpp>
|
||||
#include <vapours/results/results_common.hpp>
|
||||
#define LOGGING(fmt, ...) ((void)0)
|
||||
#define CRASH(msg, ...) { ams::diag::AbortImpl(msg, __PRETTY_FUNCTION__, "", 0); __builtin_unreachable(); }
|
||||
|
||||
#include "customize.hpp"
|
||||
#include "oc_log.hpp"
|
||||
|
||||
#if defined(AMS_BUILD_FOR_AUDITING) || defined(AMS_BUILD_FOR_DEBUGGING)
|
||||
#include "oc_log.hpp"
|
||||
#endif
|
||||
|
||||
#define PATCH_OFFSET(offset, value) \
|
||||
static_assert(sizeof(__typeof__(offset)) <= sizeof(u64)); \
|
||||
@@ -52,51 +51,57 @@ namespace ams::ldr {
|
||||
R_DEFINE_ERROR_RESULT(UnsuccessfulPatcher, 1014);
|
||||
R_DEFINE_ERROR_RESULT(SafetyCheckFailure, 1015);
|
||||
R_DEFINE_ERROR_RESULT(InvalidMtcTablePattern, 1016);
|
||||
R_DEFINE_ERROR_RESULT(InvalidSocVoltPattern, 1017);
|
||||
R_DEFINE_ERROR_RESULT(InvalidSocVoltLimit, 1018);
|
||||
}
|
||||
|
||||
namespace ams::ldr::hoc {
|
||||
template<typename Pointer>
|
||||
struct PatcherEntry {
|
||||
using patternFn = bool(*)(Pointer* ptr);
|
||||
using patcherFn = Result(*)(Pointer* ptr);
|
||||
using patternFn = bool(*)(Pointer *ptr);
|
||||
using patcherFn = Result(*)(Pointer *ptr);
|
||||
|
||||
const char* description;
|
||||
patcherFn patcher_fn = nullptr;
|
||||
size_t maximum_patched_count = 0;
|
||||
patternFn pattern_search_fn = nullptr;
|
||||
Pointer value_search;
|
||||
|
||||
size_t patched_count = 0;
|
||||
|
||||
Result Apply(Pointer* ptr) {
|
||||
Result Apply(Pointer *ptr) {
|
||||
Result res = patcher_fn(ptr);
|
||||
if (R_SUCCEEDED(res))
|
||||
if (R_SUCCEEDED(res)) {
|
||||
patched_count++;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
Result SearchAndApply(Pointer* ptr) {
|
||||
Result SearchAndApply(Pointer *ptr) {
|
||||
bool searchOk = false;
|
||||
if (pattern_search_fn) {
|
||||
if (pattern_search_fn(ptr)) searchOk = true;
|
||||
if (pattern_search_fn(ptr)) {
|
||||
searchOk = true;
|
||||
}
|
||||
} else {
|
||||
if (value_search == *(ptr)) searchOk = true;
|
||||
if (value_search == *(ptr)) {
|
||||
searchOk = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (searchOk)
|
||||
if (searchOk) {
|
||||
return Apply(ptr);
|
||||
}
|
||||
|
||||
R_THROW(ldr::ResultUnsuccessfulPatcher());
|
||||
}
|
||||
|
||||
Result CheckResult() {
|
||||
#ifndef ATMOSPHERE_IS_STRATOSPHERE
|
||||
R_UNLESS(patched_count > 0, ldr::ResultUnsuccessfulPatcher());
|
||||
#endif
|
||||
|
||||
if (maximum_patched_count)
|
||||
if (maximum_patched_count) {
|
||||
R_UNLESS(patched_count <= maximum_patched_count, ldr::ResultUnsuccessfulPatcher());
|
||||
}
|
||||
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
@@ -87,7 +87,7 @@ namespace ams::ldr::hoc {
|
||||
static bool initDone = false;
|
||||
log_ctx_t *log_ctx = (log_ctx_t*)working_buf;
|
||||
|
||||
SmcCopyFromIram(working_buf, IRAM_LOG_CTX_ADDR, sizeof(working_buf));
|
||||
R_DISCARD(SmcCopyFromIram(working_buf, IRAM_LOG_CTX_ADDR, sizeof(working_buf)));
|
||||
|
||||
if (!initDone) {
|
||||
initDone = true;
|
||||
@@ -103,26 +103,30 @@ namespace ams::ldr::hoc {
|
||||
va_end(args);
|
||||
|
||||
if (res < 0 || res >= (static_cast<s32>(max_log_sz - log_ctx->end))) {
|
||||
SmcCopyToIram(IRAM_LOG_CTX_ADDR, working_buf, sizeof(working_buf));
|
||||
R_DISCARD(SmcCopyToIram(IRAM_LOG_CTX_ADDR, working_buf, sizeof(working_buf)));
|
||||
return;
|
||||
}
|
||||
|
||||
log_ctx->end += res;
|
||||
SmcCopyToIram(IRAM_LOG_CTX_ADDR, working_buf, sizeof(working_buf));
|
||||
R_DISCARD(SmcCopyToIram(IRAM_LOG_CTX_ADDR, working_buf, sizeof(working_buf)));
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(AMS_BUILD_FOR_AUDITING) || defined(AMS_BUILD_FOR_DEBUGGING)
|
||||
void ViewLog() {
|
||||
if (spl::GetSocType() == spl::SocType_Mariko) {
|
||||
return;
|
||||
}
|
||||
|
||||
constexpr size_t PageSize = 4096;
|
||||
for (size_t ofs = 0; ofs < fatal_handler_bin_size; ofs += PageSize) {
|
||||
memcpy(&working_buf, fatal_handler_bin + ofs, std::min(fatal_handler_bin_size - ofs, PageSize));
|
||||
SmcCopyToIram(ATMOSPHERE_IRAM_PAYLOAD_BASE + ofs, &working_buf, std::min(fatal_handler_bin_size - ofs, PageSize));
|
||||
R_DISCARD(SmcCopyToIram(ATMOSPHERE_IRAM_PAYLOAD_BASE + ofs, &working_buf, std::min(fatal_handler_bin_size - ofs, PageSize)));
|
||||
}
|
||||
|
||||
SmcRebootToIramPayload();
|
||||
|
||||
while(true){}
|
||||
while(true) { }
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -1,214 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) Switch-OC-Suite
|
||||
*
|
||||
* Copyright (c) Souldbminer, Lightos_ and Horizon OC Contributors
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef ATMOSPHERE_IS_STRATOSPHERE
|
||||
#include "oc_test.hpp"
|
||||
#include "oc_loader.hpp"
|
||||
|
||||
void* loadExec(const char* file_loc, size_t* out_size) {
|
||||
FILE* fp = fopen(file_loc, "rb");
|
||||
if (!fp) {
|
||||
fprintf(stderr, "Cannot open file: \"%s\"\n", file_loc);
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
if (fseek(fp, 0, SEEK_END) < 0) {
|
||||
fprintf(stderr, "fseek error\n");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
long size = ftell(fp);
|
||||
if (size == -1L) {
|
||||
fprintf(stderr, "\"%s\" is a directory", file_loc);
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
fseek(fp, 0, SEEK_SET);
|
||||
void* buf = malloc(size);
|
||||
|
||||
fread(buf, size, 1, fp);
|
||||
fclose(fp);
|
||||
|
||||
if (size < 8192) {
|
||||
fprintf(stderr, "File is too small to process: \"%s\" (%ld B)\n", file_loc, size);
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
*out_size = size;
|
||||
return buf;
|
||||
}
|
||||
|
||||
void saveExec(const char* file_loc, const void* buf, size_t size) {
|
||||
FILE* fp = fopen(file_loc, "wb");
|
||||
if (!fp) {
|
||||
fprintf(stderr, "Cannot write to \"%s\"\n", file_loc);
|
||||
exit(-1);
|
||||
}
|
||||
printf("Saving to \"%s\"...\n", file_loc);
|
||||
fwrite(buf, size, 1, fp);
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
Result Test_PcvDvfsTable() {
|
||||
using namespace ams::ldr::hoc::pcv;
|
||||
|
||||
assert(GetDvfsTableEntryCount((cvb_entry_t *)(&mariko::CpuCvbTableDefault)) == 18);
|
||||
assert(GetDvfsTableEntryCount((cvb_entry_t *)(&erista::CpuCvbTableDefault)) == 16);
|
||||
|
||||
assert(GetDvfsTableEntryCount((cvb_entry_t *)(&mariko::GpuCvbTableDefault)) == 17);
|
||||
assert(GetDvfsTableEntryCount((cvb_entry_t *)(&erista::GpuCvbTableDefault)) == 12);
|
||||
|
||||
cvb_entry_t last_mariko_cpu_cvb_entry_default = { 1963500, { 1675751, -38635, 27 }, { 1120000 } };
|
||||
assert(memcmp(GetDvfsTableLastEntry((cvb_entry_t *)(&mariko::CpuCvbTableDefault)), (void *)&last_mariko_cpu_cvb_entry_default, sizeof(last_mariko_cpu_cvb_entry_default)) == 0);
|
||||
assert(GetDvfsTableLastEntry((cvb_entry_t *)(&erista::GpuCvbTableDefault))->freq == 921600);
|
||||
assert(GetDvfsTableEntryCount((cvb_entry_t *)(&ams::ldr::hoc::C.marikoCpuDvfsTableSLT)) == 25);
|
||||
|
||||
// Customized table default
|
||||
assert(GetDvfsTableEntryCount((cvb_entry_t *)(&ams::ldr::hoc::C.eristaCpuDvfsTable)) == 19);
|
||||
assert(GetDvfsTableEntryCount((cvb_entry_t *)(&ams::ldr::hoc::C.marikoCpuDvfsTable)) == 21);
|
||||
assert(GetDvfsTableEntryCount((cvb_entry_t *)(&ams::ldr::hoc::C.marikoCpuDvfsTableSLT)) == 22);
|
||||
|
||||
assert(GetDvfsTableEntryCount((cvb_entry_t *)(&ams::ldr::hoc::C.eristaGpuDvfsTable)) == 12);
|
||||
assert(GetDvfsTableEntryCount((cvb_entry_t *)(&ams::ldr::hoc::C.marikoGpuDvfsTable)) == 17);
|
||||
assert(GetDvfsTableEntryCount((cvb_entry_t *)(&ams::ldr::hoc::C.marikoGpuDvfsTableSLT)) == 17);
|
||||
assert(GetDvfsTableEntryCount((cvb_entry_t *)(&ams::ldr::hoc::C.marikoGpuDvfsTableHiOPT)) == 17);
|
||||
|
||||
constexpr size_t limit = ams::ldr::hoc::pcv::DvfsTableEntryLimit;
|
||||
cvb_entry_t customized_table[limit] = {};
|
||||
for (size_t i = 0; i < limit; i++) {
|
||||
assert(GetDvfsTableEntryCount(customized_table) == i);
|
||||
auto p = GetDvfsTableLastEntry(customized_table);
|
||||
if (p)
|
||||
assert(p->freq == i);
|
||||
|
||||
customized_table[i].freq = i + 1;
|
||||
}
|
||||
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
void unitTest() {
|
||||
UnitTest test[] = {
|
||||
{ "PCV DVFS Table", &Test_PcvDvfsTable }
|
||||
};
|
||||
|
||||
for (auto &t : test) {
|
||||
t.Test();
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
unitTest();
|
||||
|
||||
const char* pcv_opt = "pcv";
|
||||
const char* ptm_opt = "ptm";
|
||||
const char* save_opt = "-s";
|
||||
const char* mariko_ext = ".mariko";
|
||||
const char* erista_ext = ".erista";
|
||||
enum EXE_OPTION {
|
||||
EXE_PCV,
|
||||
EXE_PTM,
|
||||
UNKNOWN
|
||||
};
|
||||
EXE_OPTION exe_opt = UNKNOWN;
|
||||
if (argc > 2) {
|
||||
if (!strcmp(argv[1], pcv_opt))
|
||||
exe_opt = EXE_PCV;
|
||||
|
||||
if (!strcmp(argv[1], ptm_opt))
|
||||
exe_opt = EXE_PTM;
|
||||
}
|
||||
if ((argc != 3 && argc != 4) || exe_opt == UNKNOWN) {
|
||||
fprintf(stderr, "Usage:\n"\
|
||||
" %s %s | %s [%s] <exec_path>\n\n"\
|
||||
" %s : Save patched executable with extension \"%s\" / \"%s\"\n"
|
||||
, argv[0], pcv_opt, ptm_opt, save_opt
|
||||
, save_opt, mariko_ext, erista_ext);
|
||||
return -1;
|
||||
}
|
||||
|
||||
bool save_patched = false;
|
||||
char* exec_path = argv[2];
|
||||
if (argc == 4 && !strcmp(argv[2], save_opt)) {
|
||||
save_patched = true;
|
||||
exec_path = argv[3];
|
||||
}
|
||||
|
||||
size_t file_size;
|
||||
void* file_buffer = loadExec(exec_path, &file_size);
|
||||
|
||||
size_t exec_path_len = strlen(reinterpret_cast<const char *>(exec_path));
|
||||
size_t exec_path_patched_len = exec_path_len + std::max(strlen(mariko_ext), strlen(erista_ext)) + 1;
|
||||
|
||||
if (exe_opt == EXE_PCV) {
|
||||
ams::ldr::hoc::pcv::SafetyCheck();
|
||||
|
||||
{
|
||||
void* erista_buf = malloc(file_size);
|
||||
std::memcpy(erista_buf, file_buffer, file_size);
|
||||
|
||||
printf("Patching %s for Erista...\n", pcv_opt);
|
||||
ams::ldr::hoc::pcv::erista::Patch(reinterpret_cast<uintptr_t>(erista_buf), file_size);
|
||||
if (save_patched) {
|
||||
char* exec_path_erista = reinterpret_cast<char *>(malloc(exec_path_patched_len));
|
||||
strncpy(exec_path_erista, exec_path, exec_path_patched_len);
|
||||
strncat(exec_path_erista, erista_ext, exec_path_patched_len);
|
||||
saveExec(exec_path_erista, erista_buf, file_size);
|
||||
free(exec_path_erista);
|
||||
}
|
||||
free(erista_buf);
|
||||
}
|
||||
|
||||
{
|
||||
void* mariko_buf = malloc(file_size);
|
||||
std::memcpy(mariko_buf, file_buffer, file_size);
|
||||
|
||||
printf("Patching %s for Mariko...\n", pcv_opt);
|
||||
ams::ldr::hoc::pcv::mariko::Patch(reinterpret_cast<uintptr_t>(mariko_buf), file_size);
|
||||
if (save_patched) {
|
||||
char* exec_path_mariko = reinterpret_cast<char *>(malloc(exec_path_patched_len));
|
||||
strncpy(exec_path_mariko, exec_path, exec_path_patched_len);
|
||||
strncat(exec_path_mariko, mariko_ext, exec_path_patched_len);
|
||||
saveExec(exec_path_mariko, mariko_buf, file_size);
|
||||
free(exec_path_mariko);
|
||||
}
|
||||
free(mariko_buf);
|
||||
}
|
||||
}
|
||||
|
||||
if (exe_opt == EXE_PTM) {
|
||||
void* mariko_buf = malloc(file_size);
|
||||
std::memcpy(mariko_buf, file_buffer, file_size);
|
||||
|
||||
printf("Patching %s (Mariko Only)...\n", ptm_opt);
|
||||
ams::ldr::hoc::ptm::Patch(reinterpret_cast<uintptr_t>(mariko_buf), file_size);
|
||||
if (save_patched) {
|
||||
char* exec_path_mariko = reinterpret_cast<char *>(malloc(exec_path_patched_len));
|
||||
strncpy(exec_path_mariko, exec_path, exec_path_patched_len);
|
||||
strncat(exec_path_mariko, mariko_ext, exec_path_patched_len);
|
||||
saveExec(exec_path_mariko, mariko_buf, file_size);
|
||||
free(exec_path_mariko);
|
||||
}
|
||||
free(mariko_buf);
|
||||
}
|
||||
|
||||
free(file_buffer);
|
||||
printf("Passed!\n\n");
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
@@ -1,81 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) Switch-OC-Suite
|
||||
*
|
||||
* Copyright (c) Souldbminer, Lightos_ and Horizon OC Contributors
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef ATMOSPHERE_IS_STRATOSPHERE
|
||||
#include <cassert>
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <cctype>
|
||||
|
||||
typedef uint8_t u8;
|
||||
typedef uint16_t u16;
|
||||
typedef uint32_t u32;
|
||||
typedef int32_t s32;
|
||||
typedef uint64_t u64;
|
||||
typedef int Result;
|
||||
|
||||
#define R_SUCCEEDED(arg) (arg == 0)
|
||||
#define R_FAILED(arg) (arg != 0)
|
||||
#define LOGGING(fmt, ...) { printf(fmt "\n", ##__VA_ARGS__); }
|
||||
#define CRASH(msg, ...) { fprintf(stderr, "%s\nFailed in %s!\n", msg, __PRETTY_FUNCTION__); exit(-1); }
|
||||
#define R_SUCCEED() { return 0; }
|
||||
#define R_THROW(err) { return err; }
|
||||
#define R_TRY(expr) { Result _rc = (expr); if (R_FAILED(_rc)) { return _rc; } }
|
||||
#define R_UNLESS(expr, rc) { if (!(expr)) { return rc; } }
|
||||
|
||||
#define R_DEFINE_ERROR_RESULT(name, rc) \
|
||||
inline Result Result##name() { return rc; }
|
||||
|
||||
#define HEXDUMP(ptr, len) \
|
||||
{ \
|
||||
const uint8_t* p = reinterpret_cast<const uint8_t *>(ptr); \
|
||||
size_t i, j; \
|
||||
for (i = 0; i < len; i += 16) { \
|
||||
printf("%06zx: ", i); \
|
||||
for (j = 0; j < 16 && i + j < len; j++) \
|
||||
printf("%02x ", p[i + j]); \
|
||||
for (; j < 16; j++) \
|
||||
printf(" "); \
|
||||
for (j = 0; j < 16 && i + j < len; j++) \
|
||||
printf("%c", isprint(p[i + j]) ? p[i + j] : '.'); \
|
||||
printf("\n"); \
|
||||
} \
|
||||
} \
|
||||
|
||||
typedef struct UnitTest {
|
||||
using Func = Result(*)();
|
||||
|
||||
const char* description;
|
||||
Func fun = nullptr;
|
||||
|
||||
void Test() {
|
||||
Result res = fun();
|
||||
if (R_FAILED(res)) {
|
||||
CRASH(description);
|
||||
}
|
||||
}
|
||||
} UnitTest;
|
||||
|
||||
#endif
|
||||
@@ -22,20 +22,20 @@
|
||||
|
||||
namespace ams::ldr::hoc::pcv {
|
||||
|
||||
Result MemFreqPllmLimit(u32* ptr) {
|
||||
clk_pll_param* entry = reinterpret_cast<clk_pll_param *>(ptr);
|
||||
Result MemFreqPllmLimit(u32 *ptr) {
|
||||
clk_pll_param *entry = reinterpret_cast<clk_pll_param *>(ptr);
|
||||
R_UNLESS(entry->freq == entry->vco_max, ldr::ResultInvalidMemPllmEntry());
|
||||
|
||||
// Double the max clk simply
|
||||
u32 max_clk = entry->freq * 2;
|
||||
entry->freq = max_clk;
|
||||
u32 max_clk = entry->freq * 2;
|
||||
entry->freq = max_clk;
|
||||
entry->vco_max = max_clk;
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result MemVoltHandler(u32* ptr) {
|
||||
Result MemVoltHandler(u32 *ptr) {
|
||||
// ptr value might be default_uv or max_uv
|
||||
regulator* entries[2] = {
|
||||
regulator *entries[2] = {
|
||||
reinterpret_cast<regulator *>(reinterpret_cast<u8 *>(ptr) - offsetof(regulator, type_1.default_uv)),
|
||||
reinterpret_cast<regulator *>(reinterpret_cast<u8 *>(ptr) - offsetof(regulator, type_1.max_uv)),
|
||||
};
|
||||
@@ -44,16 +44,16 @@ namespace ams::ldr::hoc::pcv {
|
||||
constexpr u32 uv_min = 600'000;
|
||||
|
||||
auto validator = [](regulator* entry) {
|
||||
R_UNLESS(entry->id == 1, ldr::ResultInvalidRegulatorEntry());
|
||||
R_UNLESS(entry->type == 1, ldr::ResultInvalidRegulatorEntry());
|
||||
R_UNLESS(entry->id == 1, ldr::ResultInvalidRegulatorEntry());
|
||||
R_UNLESS(entry->type == 1, ldr::ResultInvalidRegulatorEntry());
|
||||
R_UNLESS(entry->type_1.volt_reg == 0x17, ldr::ResultInvalidRegulatorEntry());
|
||||
R_UNLESS(entry->type_1.step_uv == uv_step, ldr::ResultInvalidRegulatorEntry());
|
||||
R_UNLESS(entry->type_1.min_uv == uv_min, ldr::ResultInvalidRegulatorEntry());
|
||||
R_UNLESS(entry->type_1.step_uv == uv_step, ldr::ResultInvalidRegulatorEntry());
|
||||
R_UNLESS(entry->type_1.min_uv == uv_min, ldr::ResultInvalidRegulatorEntry());
|
||||
R_SUCCEED();
|
||||
};
|
||||
|
||||
regulator* entry = nullptr;
|
||||
for (auto& i : entries) {
|
||||
regulator *entry = nullptr;
|
||||
for (auto &i : entries) {
|
||||
if (R_SUCCEEDED(validator(i))) {
|
||||
entry = i;
|
||||
}
|
||||
@@ -76,24 +76,25 @@ namespace ams::ldr::hoc::pcv {
|
||||
}
|
||||
|
||||
void SafetyCheck() {
|
||||
// if (C.custRev != CUST_REV)
|
||||
// CRASH("Triggered");
|
||||
|
||||
struct sValidator {
|
||||
volatile u32 value;
|
||||
u32 min;
|
||||
u32 max;
|
||||
bool value_required = false;
|
||||
u32 panic;
|
||||
bool value_required = false;
|
||||
|
||||
Result check() {
|
||||
if (!value_required && !value)
|
||||
if (!value_required && !value) {
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
if (min && value < min)
|
||||
if (min && value < min) {
|
||||
R_THROW(ldr::ResultSafetyCheckFailure());
|
||||
if (max && value > max)
|
||||
}
|
||||
|
||||
if (max && value > max) {
|
||||
R_THROW(ldr::ResultSafetyCheckFailure());
|
||||
}
|
||||
|
||||
R_SUCCEED();
|
||||
}
|
||||
@@ -102,28 +103,24 @@ namespace ams::ldr::hoc::pcv {
|
||||
u32 eristaCpuDvfsMaxFreq = static_cast<u32>(GetDvfsTableLastEntry(C.eristaCpuDvfsTable)->freq);
|
||||
u32 marikoCpuDvfsMaxFreq;
|
||||
if (C.marikoCpuUVHigh) {
|
||||
marikoCpuDvfsMaxFreq = static_cast<u32>(
|
||||
GetDvfsTableLastEntry(C.marikoCpuDvfsTableSLT)->freq
|
||||
);
|
||||
marikoCpuDvfsMaxFreq = static_cast<u32>(GetDvfsTableLastEntry(C.marikoCpuDvfsTableSLT)->freq);
|
||||
} else {
|
||||
marikoCpuDvfsMaxFreq = static_cast<u32>(
|
||||
GetDvfsTableLastEntry(C.marikoCpuDvfsTable)->freq
|
||||
);
|
||||
marikoCpuDvfsMaxFreq = static_cast<u32>(GetDvfsTableLastEntry(C.marikoCpuDvfsTable)->freq);
|
||||
}
|
||||
u32 eristaGpuDvfsMaxFreq;
|
||||
switch (C.eristaGpuUV) {
|
||||
case 0:
|
||||
eristaGpuDvfsMaxFreq = static_cast<u32>(GetDvfsTableLastEntry(C.eristaGpuDvfsTable)->freq);
|
||||
break;
|
||||
case 1:
|
||||
eristaGpuDvfsMaxFreq = static_cast<u32>(GetDvfsTableLastEntry(C.eristaGpuDvfsTableSLT)->freq);
|
||||
break;
|
||||
case 2:
|
||||
eristaGpuDvfsMaxFreq = static_cast<u32>(GetDvfsTableLastEntry(C.eristaGpuDvfsTableHiOPT)->freq);
|
||||
break;
|
||||
default:
|
||||
eristaGpuDvfsMaxFreq = static_cast<u32>(GetDvfsTableLastEntry(C.eristaGpuDvfsTable)->freq);
|
||||
break;
|
||||
case 0:
|
||||
eristaGpuDvfsMaxFreq = static_cast<u32>(GetDvfsTableLastEntry(C.eristaGpuDvfsTable)->freq);
|
||||
break;
|
||||
case 1:
|
||||
eristaGpuDvfsMaxFreq = static_cast<u32>(GetDvfsTableLastEntry(C.eristaGpuDvfsTableSLT)->freq);
|
||||
break;
|
||||
case 2:
|
||||
eristaGpuDvfsMaxFreq = static_cast<u32>(GetDvfsTableLastEntry(C.eristaGpuDvfsTableHiOPT)->freq);
|
||||
break;
|
||||
default:
|
||||
eristaGpuDvfsMaxFreq = static_cast<u32>(GetDvfsTableLastEntry(C.eristaGpuDvfsTable)->freq);
|
||||
break;
|
||||
}
|
||||
|
||||
u32 marikoGpuDvfsMaxFreq;
|
||||
@@ -137,41 +134,43 @@ namespace ams::ldr::hoc::pcv {
|
||||
case 2:
|
||||
marikoGpuDvfsMaxFreq = static_cast<u32>(GetDvfsTableLastEntry(C.marikoGpuDvfsTableHiOPT)->freq);
|
||||
break;
|
||||
case 3:
|
||||
marikoGpuDvfsMaxFreq = static_cast<u32>(GetDvfsTableLastEntry(C.marikoGpuDvfsTableHiOPT15)->freq);
|
||||
break;
|
||||
case 4:
|
||||
marikoGpuDvfsMaxFreq = static_cast<u32>(GetDvfsTableLastEntry(C.marikoGpuDvfsTableHighUV)->freq);
|
||||
break;
|
||||
default:
|
||||
marikoGpuDvfsMaxFreq = static_cast<u32>(GetDvfsTableLastEntry(C.marikoGpuDvfsTable)->freq);
|
||||
marikoGpuDvfsMaxFreq = static_cast<u32>(GetDvfsTableLastEntry(C.marikoGpuDvfsTableHiOPT)->freq);
|
||||
break;
|
||||
}
|
||||
|
||||
using namespace ams::ldr::hoc::pcv;
|
||||
sValidator validators[] = {
|
||||
{ C.eristaCpuBoostClock, 1020'000, 2397'000, true, panic::Cpu },
|
||||
{ C.marikoCpuBoostClock, 1020'000, 2703'000, true, panic::Cpu },
|
||||
{ C.eristaCpuMaxVolt, 1000, 1260, false, panic::Cpu },
|
||||
{ C.marikoCpuMaxVolt, 1000, 1200, false, panic::Cpu },
|
||||
{ eristaCpuDvfsMaxFreq, 1785'000, 2397'000, false, panic::Cpu },
|
||||
{ marikoCpuDvfsMaxFreq, 1785'000, 2703'000, false, panic::Cpu },
|
||||
{ C.commonEmcMemVolt, 912'500, 1350'000, false, panic::Emc }, // Official burst vmax for the RAMs is 1500mV
|
||||
{ GET_MAX_OF_ARR(erista::maxEmcClocks), 1600'000, 2600'000, false, panic::Emc },
|
||||
{ C.marikoEmcMaxClock, 1600'000, 3500'000, false, panic::Emc },
|
||||
{ C.marikoEmcVddqVolt, 250'000, 700'000, false, panic::Emc },
|
||||
{ eristaGpuDvfsMaxFreq, 768'000, 1152'000, false, panic::Gpu },
|
||||
{ marikoGpuDvfsMaxFreq, 768'000, 1536'000, false, panic::Gpu },
|
||||
{ C.marikoGpuVmax, 800, 960, false, panic::Gpu },
|
||||
{ C.eristaCpuBoostClock, 1020'000, 2397'000, panic::Cpu, true },
|
||||
{ C.marikoCpuBoostClock, 1020'000, 2703'000, panic::Cpu, true },
|
||||
{ C.eristaCpuMaxVolt, 1000, 1260, panic::Cpu, },
|
||||
{ C.marikoCpuMaxVolt, 1000, 1200, panic::Cpu, },
|
||||
{ eristaCpuDvfsMaxFreq, 1785'000, 2397'000, panic::Cpu, },
|
||||
{ marikoCpuDvfsMaxFreq, 1785'000, 2703'000, panic::Cpu, },
|
||||
{ C.commonEmcMemVolt, 912'500, 1350'000, panic::Emc, }, /* Official vmax for the RAMs is 1400-1500mV */
|
||||
{ C.eristaEmcMaxClock, 1600'000, 2600'000, panic::Emc, },
|
||||
{ C.marikoEmcMaxClock, 1600'000, 3500'000, panic::Emc, },
|
||||
{ C.marikoEmcVddqVolt, 400'000, 750'000, panic::Emc, },
|
||||
{ C.marikoSocVmax, 1000, 1200, panic::Emc, },
|
||||
{ eristaGpuDvfsMaxFreq, 768'000, 1152'000, panic::Gpu, },
|
||||
{ marikoGpuDvfsMaxFreq, 768'000, 1536'000, panic::Gpu, },
|
||||
{ C.marikoGpuVmax, 800, 960, panic::Gpu, },
|
||||
};
|
||||
|
||||
for (auto &v : validators) {
|
||||
if (R_FAILED(v.check())) {
|
||||
#if defined(AMS_BUILD_FOR_AUDITING) || defined(AMS_BUILD_FOR_DEBUGGING)
|
||||
panic::SmcError(v.panic);
|
||||
#endif
|
||||
|
||||
panic::SmcError(v.panic);
|
||||
CRASH("Validation FAIL");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Patch(uintptr_t mapped_nso, size_t nso_size) {
|
||||
#ifdef ATMOSPHERE_IS_STRATOSPHERE
|
||||
SafetyCheck();
|
||||
|
||||
bool isMariko = (spl::GetSocType() == spl::SocType_Mariko);
|
||||
@@ -180,8 +179,6 @@ namespace ams::ldr::hoc::pcv {
|
||||
} else {
|
||||
erista::Patch(mapped_nso, nso_size);
|
||||
}
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -24,7 +24,6 @@
|
||||
#include "pcv_common.hpp"
|
||||
#include "pcv_erista.hpp"
|
||||
#include "pcv_mariko.hpp"
|
||||
#include "pcv_asm.hpp"
|
||||
|
||||
namespace ams::ldr::hoc::pcv {
|
||||
|
||||
@@ -119,34 +118,40 @@ namespace ams::ldr::hoc::pcv {
|
||||
cvb_entry_t *customize_table;
|
||||
if (isMariko) {
|
||||
switch (C.marikoGpuUV) {
|
||||
case 0:
|
||||
customize_table = const_cast<cvb_entry_t *>(C.marikoGpuDvfsTable);
|
||||
break;
|
||||
case 1:
|
||||
customize_table = const_cast<cvb_entry_t *>(C.marikoGpuDvfsTableSLT);
|
||||
break;
|
||||
case 2:
|
||||
customize_table = const_cast<cvb_entry_t *>(C.marikoGpuDvfsTableHiOPT);
|
||||
break;
|
||||
default:
|
||||
customize_table = const_cast<cvb_entry_t *>(C.marikoGpuDvfsTable);
|
||||
break;
|
||||
}
|
||||
case 0:
|
||||
customize_table = const_cast<cvb_entry_t *>(C.marikoGpuDvfsTable);
|
||||
break;
|
||||
case 1:
|
||||
customize_table = const_cast<cvb_entry_t *>(C.marikoGpuDvfsTableSLT);
|
||||
break;
|
||||
case 2:
|
||||
customize_table = const_cast<cvb_entry_t *>(C.marikoGpuDvfsTableHiOPT);
|
||||
break;
|
||||
case 3:
|
||||
customize_table = const_cast<cvb_entry_t *>(C.marikoGpuDvfsTableHiOPT15);
|
||||
break;
|
||||
case 4:
|
||||
customize_table = const_cast<cvb_entry_t *>(C.marikoGpuDvfsTableHighUV);
|
||||
break;
|
||||
default:
|
||||
customize_table = const_cast<cvb_entry_t *>(C.marikoGpuDvfsTableHiOPT);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
switch (C.eristaGpuUV) {
|
||||
case 0:
|
||||
customize_table = const_cast<cvb_entry_t *>(C.eristaGpuDvfsTable);
|
||||
break;
|
||||
case 1:
|
||||
customize_table = const_cast<cvb_entry_t *>(C.eristaGpuDvfsTableSLT);
|
||||
break;
|
||||
case 2:
|
||||
customize_table = const_cast<cvb_entry_t *>(C.eristaGpuDvfsTableHiOPT);
|
||||
break;
|
||||
default:
|
||||
customize_table = const_cast<cvb_entry_t *>(C.eristaGpuDvfsTable);
|
||||
break;
|
||||
}
|
||||
case 0:
|
||||
customize_table = const_cast<cvb_entry_t *>(C.eristaGpuDvfsTable);
|
||||
break;
|
||||
case 1:
|
||||
customize_table = const_cast<cvb_entry_t *>(C.eristaGpuDvfsTableSLT);
|
||||
break;
|
||||
case 2:
|
||||
customize_table = const_cast<cvb_entry_t *>(C.eristaGpuDvfsTableHiOPT);
|
||||
break;
|
||||
default:
|
||||
customize_table = const_cast<cvb_entry_t *>(C.eristaGpuDvfsTable);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
size_t default_entry_count = GetDvfsTableEntryCount(default_table);
|
||||
@@ -170,14 +175,14 @@ namespace ams::ldr::hoc::pcv {
|
||||
PATCH_OFFSET(&(entry->cvb_pll_param.c0), (C.marikoGpuVoltArray[i] * 1000));
|
||||
ClearCvbPllEntry(entry);
|
||||
} else {
|
||||
PATCH_OFFSET(&(entry->cvb_pll_param.c0), (entry->cvb_pll_param.c0 - C.commonGpuVoltOffset * 1000));
|
||||
PATCH_OFFSET(&(entry->cvb_pll_param.c0), (u32)((s32)entry->cvb_pll_param.c0 + C.commonGpuVoltOffset * 1000));
|
||||
}
|
||||
} else {
|
||||
if (C.eristaGpuVoltArray[i] != 0) {
|
||||
PATCH_OFFSET(&(entry->cvb_pll_param.c0), (C.eristaGpuVoltArray[i] * 1000));
|
||||
ClearCvbPllEntry(entry);
|
||||
} else {
|
||||
PATCH_OFFSET(&(entry->cvb_pll_param.c0), (entry->cvb_pll_param.c0 - C.commonGpuVoltOffset * 1000));
|
||||
PATCH_OFFSET(&(entry->cvb_pll_param.c0), (u32)((s32)entry->cvb_pll_param.c0 + C.commonGpuVoltOffset * 1000));
|
||||
}
|
||||
}
|
||||
++entry;
|
||||
@@ -185,7 +190,7 @@ namespace ams::ldr::hoc::pcv {
|
||||
if (C.commonGpuVoltOffset && !(isMariko ? C.marikoGpuUV : C.eristaGpuUV)) {
|
||||
cvb_entry_t *entry = static_cast<cvb_entry_t *>(gpu_cvb_table_head);
|
||||
for (size_t i = 0; i < customize_entry_count; ++i) {
|
||||
PATCH_OFFSET(&(entry->cvb_pll_param.c0), (entry->cvb_pll_param.c0 - C.commonGpuVoltOffset * 1000));
|
||||
PATCH_OFFSET(&(entry->cvb_pll_param.c0), (u32)((s32)entry->cvb_pll_param.c0 + C.commonGpuVoltOffset * 1000));
|
||||
++entry;
|
||||
}
|
||||
}
|
||||
@@ -196,26 +201,6 @@ namespace ams::ldr::hoc::pcv {
|
||||
Result MemFreqPllmLimit(u32 *ptr);
|
||||
Result MemVoltHandler(u32 *ptr); // Used for Erista MEM Vdd2 + EMC Vddq or Mariko MEM Vdd2
|
||||
|
||||
template <typename T>
|
||||
Result MemMtcCustomizeTable(T *dst, T *src) {
|
||||
constexpr u32 mtc_magic = std::is_same_v<T, MarikoMtcTable> ? MARIKO_MTC_MAGIC : ERISTA_MTC_MAGIC;
|
||||
R_UNLESS(src->rev == mtc_magic, ldr::ResultInvalidMtcMagic());
|
||||
|
||||
constexpr u32 ZERO_VAL = UINT32_MAX;
|
||||
// Skip params from dvfs_ver to clock_src;
|
||||
for (size_t offset = offsetof(T, clk_src_emc); offset < sizeof(T); offset += sizeof(u32)) {
|
||||
u32 *src_ent = reinterpret_cast<u32 *>(reinterpret_cast<size_t>(src) + offset);
|
||||
u32 *dst_ent = reinterpret_cast<u32 *>(reinterpret_cast<size_t>(dst) + offset);
|
||||
u32 src_val = *src_ent;
|
||||
|
||||
if (src_val){
|
||||
PATCH_OFFSET(dst_ent, src_val == ZERO_VAL ? 0 : src_val);
|
||||
}
|
||||
}
|
||||
|
||||
R_SUCCEED();
|
||||
};
|
||||
|
||||
void SafetyCheck();
|
||||
void Patch(uintptr_t mapped_nso, size_t nso_size);
|
||||
|
||||
|
||||
@@ -24,7 +24,17 @@
|
||||
|
||||
namespace ams::ldr::hoc::pcv {
|
||||
|
||||
constexpr u32 NopIns = 0x1f2003d5;
|
||||
constexpr u32 NopIns = 0xD503201F;
|
||||
|
||||
template <typename Compare>
|
||||
u32 *ScanAssembly(u32 *ptr, u32 scanLimit, u32 pattern, Compare comp) {
|
||||
for (u32 i = 0; i < scanLimit; ++i) {
|
||||
if (comp(pattern, ptr[i])) {
|
||||
return ptr + i;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
inline auto asm_compare_no_rd = [](u32 ins1, u32 ins2) {
|
||||
return ((ins1 ^ ins2) >> 5) == 0;
|
||||
@@ -61,4 +71,121 @@ namespace ams::ldr::hoc::pcv {
|
||||
return ((ins1 & ImmMask) ^ (ins2 & ImmMask)) == 0;
|
||||
};
|
||||
|
||||
/* Csel (Conditional Select) */
|
||||
/*
|
||||
SF | Op | S | | RM | Cond | 0 | 0 | Rn | Rd
|
||||
31 | 30 | 29 | 28 27 26 25 24 23 | 20 19 18 17 16 | 15 14 13 12 | 11 | 10 | 9 8 7 6 5 | 4 3 2 1 0
|
||||
*/
|
||||
inline auto AsmCbzCompareOpcodeOnly = [](u32 ins1, u32 ins2) {
|
||||
return ((ins1 ^ ins2) >> 24) == 0;
|
||||
};
|
||||
|
||||
inline auto AsmBlCompareOpcodeOnly = [](u32 ins1, u32 ins2) {
|
||||
return ((ins1 ^ ins2) >> 26) == 0;
|
||||
};
|
||||
|
||||
inline auto AsmIsAdrX0 = [](u32 ins) {
|
||||
return (ins & 0x9F00001Fu) == 0x10000000u;
|
||||
};
|
||||
|
||||
inline auto AsmAdrTarget = [](u32 ins, uintptr_t pc) -> uintptr_t {
|
||||
s64 imm = static_cast<s64>((((ins >> 5) & 0x7FFFFu) << 2) | ((ins >> 29) & 0x3u));
|
||||
imm = (imm << 43) >> 43;
|
||||
return static_cast<uintptr_t>(static_cast<s64>(pc) + imm);
|
||||
};
|
||||
|
||||
inline auto AsmSetAdrTarget = [](u32 ins, uintptr_t pc, uintptr_t target) -> u32 {
|
||||
const s64 delta = static_cast<s64>(target) - static_cast<s64>(pc);
|
||||
const u32 immlo = static_cast<u32>(delta & 0x3);
|
||||
const u32 immhi = static_cast<u32>((delta >> 2) & 0x7FFFF);
|
||||
return (ins & ~((0x3u << 29) | (0x7FFFFu << 5))) | (immlo << 29) | (immhi << 5);
|
||||
};
|
||||
|
||||
inline auto AsmIsLdpX = [](u32 ins) {
|
||||
return (ins & 0xFE400000u) == 0xA8400000u;
|
||||
};
|
||||
|
||||
inline bool AsmComparePrologue(u32 ins1, u32 ins2, u32 ins3, u32 cmp1, u32 cmp2, u32 cmp3) {
|
||||
constexpr u32 StpImmMask = ~((((1u << 7) - 1u) << 15));
|
||||
|
||||
bool firstMatch = (ins1 & StpImmMask) == (cmp1 & StpImmMask);
|
||||
|
||||
constexpr u32 StpRegsImmMask = ~(((1u << 5) - 1u) |(((1u << 5) - 1u) << 10) | (((1u << 7) - 1u) << 15));
|
||||
|
||||
bool secondMatch = (ins2 & StpRegsImmMask) == (cmp2 & StpRegsImmMask);
|
||||
|
||||
|
||||
constexpr u32 MovMask = ~((1u << 5) - 1u);
|
||||
|
||||
bool thirdMatch = (ins3 & MovMask) == (cmp3 & MovMask);
|
||||
|
||||
return firstMatch && secondMatch && thirdMatch;
|
||||
}
|
||||
|
||||
inline auto AsmCompareCselNoReg = [](u32 ins1, u32 ins2) {
|
||||
constexpr u32 ClearReg = ~(((1 << 10) - 1) | (((1 << 5) - 1) << 16));
|
||||
return ((ins1 & ClearReg) ^ (ins2 & ClearReg)) == 0;
|
||||
};
|
||||
|
||||
/* Mul */
|
||||
/*
|
||||
SF | Op54 | Op31 | RM | o0 | RA | RN | RD
|
||||
31 | 30 29 28 27 26 25 24 | 23 22 21 | 20 19 18 17 16 | 15 | 14 13 12 11 10 | 9 8 7 6 5 | 4 3 2 1 0
|
||||
*/
|
||||
inline auto AsmCompareMullNoReg = [](u32 ins1, u32 ins2) {
|
||||
constexpr u32 ClearReg = ~(((1 << 10) - 1) | (((1 << 5) - 1) << 16));
|
||||
return ((ins1 & ClearReg) ^ (ins2 & ClearReg)) == 0;
|
||||
};
|
||||
|
||||
/* Mul */
|
||||
/* MUL W11, W24, W26 */
|
||||
/* multiplies by 1000, mV -> uV */
|
||||
/*
|
||||
SF | Op54 | Op31 | RM | o0 | RA | RN | RD
|
||||
31 | 30 29 28 27 26 25 24 | 23 22 21 | 20 19 18 17 16 | 15 | 14 13 12 11 10 | 9 8 7 6 5 | 4 3 2 1 0
|
||||
*/
|
||||
inline auto AsmGetMullRn = [](u32 ins) {
|
||||
constexpr u32 Mask = ((1 << 5) - 1) << 5;
|
||||
return (ins & Mask) >> 5;
|
||||
};
|
||||
|
||||
inline auto AsmGetMullRm = [](u32 ins) {
|
||||
constexpr u32 Mask = ((1 << 5) - 1) << 16;
|
||||
return (ins & Mask) >> 16;
|
||||
};
|
||||
|
||||
/* Subs (Shifted register) */
|
||||
/*
|
||||
SF | Op | S | | Shift | 0 | RM | Imm6 | Rn | Rd
|
||||
31 | 30 | 29 | 28 27 26 25 24 | 23 22 | 21 | 20 19 18 17 16 | 15 14 13 12 11 10 | 9 8 7 6 5 | 4 3 2 1 0
|
||||
*/
|
||||
inline auto AsmSubsSetRn = [](u32 ins, u8 rn) {
|
||||
constexpr u32 RnMaskClear = ~(((1u << 5) - 1u) << 5);
|
||||
constexpr u32 RnMaskSet = (1u << 5) - 1u;
|
||||
|
||||
return (ins & RnMaskClear) | ((static_cast<u32>(rn) & RnMaskSet) << 5);
|
||||
};
|
||||
|
||||
/* Subs (Immediate) */
|
||||
|
||||
/*
|
||||
SF | Op | S | | Sh | Imm12 | Rn | Rd
|
||||
31 | 30 | 29 | 28 27 26 25 24 23 | 22 | 21 20 19 18 17 16 15 14 13 12 11 10 | 9 8 7 6 5 | 4 3 2 1 0
|
||||
*/
|
||||
inline auto AsmSubsSetImm12 = [](u32 ins, u16 imm12) {
|
||||
constexpr u32 ClearMask = ~(((1u << 12) - 1) << 10);
|
||||
constexpr u32 SetImm12Mask = ( 1u << 12) - 1;
|
||||
|
||||
return (ins & ClearMask) | ((imm12 & SetImm12Mask) << 10);
|
||||
};
|
||||
|
||||
inline auto AsmSubsCompareNoReg = [](u32 ins1, u32 ins2) {
|
||||
return ((ins1 ^ ins2) >> 10) == 0;
|
||||
};
|
||||
|
||||
inline auto AsmCompareBrConNoImm19 = [](u32 ins1, u32 ins2) {
|
||||
constexpr u32 ClearImm19 = ~(((1 << 19) - 1) << 5);
|
||||
return (ins1 & ClearImm19) == (ins2 & ClearImm19);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -18,35 +18,37 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../mtc_timing_table.hpp"
|
||||
|
||||
namespace ams::ldr::hoc::pcv {
|
||||
|
||||
typedef struct cvb_coefficients {
|
||||
struct cvb_coefficients {
|
||||
s32 c0 = 0;
|
||||
s32 c1 = 0;
|
||||
s32 c2 = 0;
|
||||
s32 c3 = 0;
|
||||
s32 c4 = 0;
|
||||
s32 c5 = 0;
|
||||
} cvb_coefficients;
|
||||
};
|
||||
|
||||
typedef struct cvb_entry_t {
|
||||
struct cvb_entry_t {
|
||||
u64 freq;
|
||||
cvb_coefficients cvb_dfll_param;
|
||||
cvb_coefficients cvb_pll_param;
|
||||
} cvb_entry_t;
|
||||
};
|
||||
static_assert(sizeof(cvb_entry_t) == 0x38);
|
||||
|
||||
typedef struct cvb_cpu_dfll_data {
|
||||
struct CvbCpuDfllData {
|
||||
u32 tune0_low;
|
||||
u32 tune0_high;
|
||||
u32 tune1_low;
|
||||
u32 tune1_high;
|
||||
unsigned int tune_high_min_millivolts;
|
||||
unsigned int tune_high_margin_millivolts;
|
||||
unsigned long dvco_calibration_max;
|
||||
} cvb_cpu_dfll_data;
|
||||
u32 tune_high_min_millivolts;
|
||||
u32 tune_high_margin_millivolts;
|
||||
u64 dvco_calibration_max;
|
||||
};
|
||||
|
||||
typedef struct __attribute__((packed)) div_nmp {
|
||||
struct __attribute__((packed)) div_nmp {
|
||||
u8 divn_shift;
|
||||
u8 divn_width;
|
||||
u8 divm_shift;
|
||||
@@ -56,9 +58,9 @@ namespace ams::ldr::hoc::pcv {
|
||||
u8 override_divn_shift;
|
||||
u8 override_divm_shift;
|
||||
u8 override_divp_shift;
|
||||
} div_nmp;
|
||||
};
|
||||
|
||||
typedef struct __attribute__((packed)) clk_pll_param {
|
||||
struct __attribute__((packed)) clk_pll_param {
|
||||
u32 freq;
|
||||
u32 input_min;
|
||||
u32 input_max;
|
||||
@@ -71,10 +73,10 @@ namespace ams::ldr::hoc::pcv {
|
||||
u32 unk_0;
|
||||
struct div_nmp *div_nmp;
|
||||
u32 unk_1[4];
|
||||
void (*unk_fn)(u64* unk_struct); // set_defaults?
|
||||
} clk_pll_param;
|
||||
void (*unk_fn)(u64 *unk_struct); // set_defaults?
|
||||
};
|
||||
|
||||
typedef struct __attribute__((packed)) dvfs_rail {
|
||||
struct __attribute__((packed)) dvfs_rail {
|
||||
u32 id;
|
||||
u32 unk_0[5];
|
||||
u32 freq;
|
||||
@@ -84,11 +86,11 @@ namespace ams::ldr::hoc::pcv {
|
||||
u32 step_mv;
|
||||
u32 max_mv;
|
||||
u32 unk_2[11];
|
||||
} dvfs_rail;
|
||||
};
|
||||
|
||||
typedef struct __attribute__((packed)) regulator {
|
||||
struct __attribute__((packed)) regulator {
|
||||
u64 id;
|
||||
const char* name;
|
||||
const char *name;
|
||||
u32 type;
|
||||
union {
|
||||
struct {
|
||||
@@ -110,9 +112,28 @@ namespace ams::ldr::hoc::pcv {
|
||||
} type_2_3;
|
||||
};
|
||||
u32 unk_x[60];
|
||||
} regulator;
|
||||
};
|
||||
static_assert(sizeof(regulator) == 0x120);
|
||||
|
||||
struct __attribute__((packed)) CvbMeta {
|
||||
u64 socType;
|
||||
CvbCpuDfllData dfllData; /* Maybe? */
|
||||
u32 unkZero2[6];
|
||||
u32 unkMagic;
|
||||
u32 unkZero3;
|
||||
u32 highVmin;
|
||||
u32 unkStepMaybe;
|
||||
u32 vmin;
|
||||
u32 unkZero4[3];
|
||||
u32 pllMinMilliVolts;
|
||||
u32 vmax;
|
||||
u32 unkScale2;
|
||||
u32 speedoScale;
|
||||
u32 voltageScale;
|
||||
u32 unkZero5;
|
||||
};
|
||||
static_assert(sizeof(CvbMeta) == 0x78);
|
||||
|
||||
constexpr u32 CpuClkOSLimit = 1785'000;
|
||||
constexpr u32 GpuClkOsLimit = 921'600;
|
||||
constexpr u32 EmcClkOSLimit = 1600'000;
|
||||
@@ -124,11 +145,11 @@ namespace ams::ldr::hoc::pcv {
|
||||
constexpr size_t DvfsTableEntryLimit = DvfsTableEntryCount - 1;
|
||||
|
||||
template<typename T>
|
||||
size_t GetDvfsTableEntryCount(T* table_head) {
|
||||
size_t GetDvfsTableEntryCount(T *table_head) {
|
||||
using NT = std::remove_const_t<std::remove_volatile_t<T>>;
|
||||
|
||||
auto is_empty = [](NT* entry) {
|
||||
uint8_t* m = reinterpret_cast<uint8_t *>(entry);
|
||||
auto is_empty = [](NT *entry) {
|
||||
u8 *m = reinterpret_cast<u8 *>(entry);
|
||||
for (size_t i = 0; i < sizeof(NT); i++) {
|
||||
if (*(m + i)) {
|
||||
return false;
|
||||
@@ -137,7 +158,7 @@ namespace ams::ldr::hoc::pcv {
|
||||
return true;
|
||||
};
|
||||
|
||||
NT* table = const_cast<NT *>(table_head);
|
||||
NT *table = const_cast<NT *>(table_head);
|
||||
size_t count = 0;
|
||||
while (count < DvfsTableEntryLimit) {
|
||||
if (is_empty(table++)) {
|
||||
@@ -149,10 +170,10 @@ namespace ams::ldr::hoc::pcv {
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T* GetDvfsTableLastEntry(T* table_head) {
|
||||
T *GetDvfsTableLastEntry(T *table_head) {
|
||||
using NT = std::remove_const_t<std::remove_volatile_t<T>>;
|
||||
|
||||
NT* table = const_cast<NT *>(table_head);
|
||||
NT *table = const_cast<NT *>(table_head);
|
||||
size_t count = GetDvfsTableEntryCount(table_head);
|
||||
if (!count) {
|
||||
return nullptr;
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
*
|
||||
* Copyright (c) 2023 hanai3Bi
|
||||
*
|
||||
* Copyright (c) B3711
|
||||
*
|
||||
* Copyright (c) Souldbminer, Lightos_ and Horizon OC Contributors
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
@@ -18,12 +20,17 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <vector>
|
||||
#include "pcv.hpp"
|
||||
#include "../mtc_timing_value.hpp"
|
||||
#include "../erista/calculate_timings_erista.hpp"
|
||||
|
||||
namespace ams::ldr::hoc::pcv::erista {
|
||||
|
||||
std::vector<u32> newEmcList;
|
||||
u32 *nsoStart;
|
||||
u32 *nsoEnd;
|
||||
|
||||
Result CpuVoltDvfs(u32 *ptr) {
|
||||
if (std::memcmp(ptr + 5, cpuVoltDvfsPattern, sizeof(cpuVoltDvfsPattern))) {
|
||||
R_THROW(ldr::ResultInvalidCpuMinVolt());
|
||||
@@ -66,11 +73,12 @@ namespace ams::ldr::hoc::pcv::erista {
|
||||
}
|
||||
|
||||
Result CpuVoltDfll(u32* ptr) {
|
||||
cvb_cpu_dfll_data *entry = reinterpret_cast<cvb_cpu_dfll_data *>(ptr);
|
||||
R_UNLESS(entry->tune0_low == 0xFFEAD0FF, ldr::ResultInvalidCpuVoltDfllEntry());
|
||||
R_UNLESS(entry->tune0_high == 0x0, ldr::ResultInvalidCpuVoltDfllEntry());
|
||||
R_UNLESS(entry->tune1_low == 0x0, ldr::ResultInvalidCpuVoltDfllEntry());
|
||||
R_UNLESS(entry->tune1_high == 0x0, ldr::ResultInvalidCpuVoltDfllEntry());
|
||||
CvbCpuDfllData *entry = reinterpret_cast<CvbCpuDfllData *>(ptr);
|
||||
|
||||
R_UNLESS(entry->tune0_low == 0xFFEAD0FF, ldr::ResultInvalidCpuVoltDfllEntry());
|
||||
R_UNLESS(entry->tune0_high == 0x0, ldr::ResultInvalidCpuVoltDfllEntry());
|
||||
R_UNLESS(entry->tune1_low == 0x0, ldr::ResultInvalidCpuVoltDfllEntry());
|
||||
R_UNLESS(entry->tune1_high == 0x0, ldr::ResultInvalidCpuVoltDfllEntry());
|
||||
|
||||
if (!C.eristaCpuUV) {
|
||||
R_SKIP();
|
||||
@@ -100,6 +108,7 @@ namespace ams::ldr::hoc::pcv::erista {
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
@@ -121,10 +130,10 @@ namespace ams::ldr::hoc::pcv::erista {
|
||||
}
|
||||
|
||||
if (C.eristaGpuVmin) {
|
||||
PATCH_OFFSET(ptr , C.eristaGpuVmin);
|
||||
PATCH_OFFSET(ptr + 3, C.eristaGpuVmin);
|
||||
PATCH_OFFSET(ptr + 6, C.eristaGpuVmin);
|
||||
PATCH_OFFSET(ptr + 9, C.eristaGpuVmin);
|
||||
PATCH_OFFSET(ptr, C.eristaGpuVmin);
|
||||
PATCH_OFFSET(ptr + 3, C.eristaGpuVmin);
|
||||
PATCH_OFFSET(ptr + 6, C.eristaGpuVmin);
|
||||
PATCH_OFFSET(ptr + 9, C.eristaGpuVmin);
|
||||
PATCH_OFFSET(ptr + 12, C.eristaGpuVmin);
|
||||
}
|
||||
|
||||
@@ -134,17 +143,13 @@ namespace ams::ldr::hoc::pcv::erista {
|
||||
Result GpuFreqMaxAsm(u32 *ptr32) {
|
||||
// Check if both two instructions match the pattern
|
||||
u32 ins1 = *ptr32, ins2 = *(ptr32 + 1);
|
||||
if (!(asm_compare_no_rd(ins1, GpuAsmPattern[0]) && asm_compare_no_rd(ins2, GpuAsmPattern[1])))
|
||||
if (!(asm_compare_no_rd(ins1, GpuAsmPattern[0]) && asm_compare_no_rd(ins2, GpuAsmPattern[1]))) {
|
||||
R_THROW(ldr::ResultInvalidGpuFreqMaxPattern());
|
||||
}
|
||||
|
||||
// Both instructions should operate on the same register
|
||||
u8 rd = asm_get_rd(ins1);
|
||||
if (rd != asm_get_rd(ins2))
|
||||
R_THROW(ldr::ResultInvalidGpuFreqMaxPattern());
|
||||
|
||||
/* Verify the limit. */
|
||||
/* TODO: Make this a little bit cleaner at some point. */
|
||||
if (AsmGetImm16(ins1) != (GpuClkOsLimit & 0xFFFF) || AsmGetImm16(ins2) != (GpuClkOsLimit >> 16)) {
|
||||
if (rd != asm_get_rd(ins2)) {
|
||||
R_THROW(ldr::ResultInvalidGpuFreqMaxPattern());
|
||||
}
|
||||
|
||||
@@ -163,10 +168,13 @@ namespace ams::ldr::hoc::pcv::erista {
|
||||
max_clock = GetDvfsTableLastEntry(C.eristaGpuDvfsTable)->freq;
|
||||
break;
|
||||
}
|
||||
|
||||
u32 asm_patch[2] = {
|
||||
asm_set_rd(asm_set_imm16(GpuAsmPattern[0], max_clock), rd),
|
||||
asm_set_rd(asm_set_imm16(GpuAsmPattern[1], max_clock >> 16), rd)};
|
||||
PATCH_OFFSET(ptr32, asm_patch[0]);
|
||||
asm_set_rd(asm_set_imm16(GpuAsmPattern[1], max_clock >> 16), rd)
|
||||
};
|
||||
|
||||
PATCH_OFFSET(ptr32, asm_patch[0]);
|
||||
PATCH_OFFSET(ptr32 + 1, asm_patch[1]);
|
||||
|
||||
R_SUCCEED();
|
||||
@@ -210,13 +218,15 @@ namespace ams::ldr::hoc::pcv::erista {
|
||||
}
|
||||
|
||||
u32 trefbw = refresh_raw + 0x40;
|
||||
trefbw = MIN(trefbw, static_cast<u32>(0x3FFF));
|
||||
trefbw = MIN(trefbw, static_cast<u32>(0x3FFF));
|
||||
|
||||
CalculateTimings(tCK_avg);
|
||||
const u32 dyn_self_ref_control = (static_cast<u32>(7605.0 / tCK_avg) + 260) | (table->burst_regs.emc_dyn_self_ref_control & 0xffff0000);
|
||||
|
||||
CalculateTimings(tCK_avg, table->rate_khz);
|
||||
|
||||
WRITE_PARAM_ALL_REG(table, emc_rd_rcd, GET_CYCLE_CEIL(tRCD));
|
||||
WRITE_PARAM_ALL_REG(table, emc_wr_rcd, GET_CYCLE_CEIL(tRCD));
|
||||
WRITE_PARAM_ALL_REG(table, emc_rc, MIN(GET_CYCLE_CEIL(tRC), static_cast<u32>(0xB8)));
|
||||
WRITE_PARAM_ALL_REG(table, emc_rc, MIN(GET_CYCLE_CEIL(tRC), static_cast<u32>(0xB9)));
|
||||
WRITE_PARAM_ALL_REG(table, emc_ras, MIN(GET_CYCLE_CEIL(tRAS), static_cast<u32>(0x7F)));
|
||||
WRITE_PARAM_ALL_REG(table, emc_rrd, GET_CYCLE_CEIL(tRRD));
|
||||
WRITE_PARAM_ALL_REG(table, emc_rfcpb, GET_CYCLE_CEIL(tRFCpb));
|
||||
@@ -239,7 +249,6 @@ namespace ams::ldr::hoc::pcv::erista {
|
||||
WRITE_PARAM_ALL_REG(table, emc_refresh, refresh_raw);
|
||||
WRITE_PARAM_ALL_REG(table, emc_pre_refresh_req_cnt, refresh_raw / 4);
|
||||
WRITE_PARAM_ALL_REG(table, emc_trefbw, trefbw);
|
||||
const u32 dyn_self_ref_control = (static_cast<u32>(7605.0 / tCK_avg) + 260) | (table->burst_regs.emc_dyn_self_ref_control & 0xffff0000);
|
||||
WRITE_PARAM_ALL_REG(table, emc_dyn_self_ref_control, dyn_self_ref_control);
|
||||
WRITE_PARAM_ALL_REG(table, emc_pdex2wr, pdex2rw);
|
||||
WRITE_PARAM_ALL_REG(table, emc_pdex2rd, pdex2rw);
|
||||
@@ -252,16 +261,17 @@ namespace ams::ldr::hoc::pcv::erista {
|
||||
WRITE_PARAM_ALL_REG(table, emc_rw2pden, tWTPDEN);
|
||||
|
||||
/* Accept imperfection or prepare for suffering. */
|
||||
// #if defined(AMS_BUILD_FOR_AUDITING) || defined(AMS_BUILD_FOR_DEBUGGING)
|
||||
// WRITE_PARAM_ALL_REG(table, emc_einput, einput);
|
||||
// WRITE_PARAM_ALL_REG(table, emc_einput_duration, einput_duration);
|
||||
// WRITE_PARAM_ALL_REG(table, emc_obdly, obdly);
|
||||
WRITE_PARAM_ALL_REG(table, emc_obdly, obdly);
|
||||
// WRITE_PARAM_ALL_REG(table, emc_ibdly, ibdly);
|
||||
// WRITE_PARAM_ALL_REG(table, emc_wdv_mask, wdv);
|
||||
// WRITE_PARAM_ALL_REG(table, emc_quse_width, quse_width);
|
||||
// WRITE_PARAM_ALL_REG(table, emc_quse, quse);
|
||||
// WRITE_PARAM_ALL_REG(table, emc_wdv, wdv);
|
||||
// WRITE_PARAM_ALL_REG(table, emc_wsv, wsv);
|
||||
// WRITE_PARAM_ALL_REG(table, emc_wev, wev);
|
||||
WRITE_PARAM_ALL_REG(table, emc_wdv, wdv);
|
||||
WRITE_PARAM_ALL_REG(table, emc_wsv, wsv);
|
||||
WRITE_PARAM_ALL_REG(table, emc_wev, wev);
|
||||
// WRITE_PARAM_ALL_REG(table, emc_qrst, qrst);
|
||||
// WRITE_PARAM_ALL_REG(table, emc_tr_qrst, qrst);
|
||||
// WRITE_PARAM_ALL_REG(table, emc_qsafe, qsafe);
|
||||
@@ -274,22 +284,21 @@ namespace ams::ldr::hoc::pcv::erista {
|
||||
// WRITE_PARAM_ALL_REG(table, emc_rdv_early_mask, rdv);
|
||||
// WRITE_PARAM_ALL_REG(table, emc_rdv_mask, rdv + 2);
|
||||
// WRITE_PARAM_ALL_REG(table, emc_tr_rdv, rdv);
|
||||
// ams::ldr::hoc::pcv::mariko::CalculateMrw2();
|
||||
// table->emc_mrw2 = (table->emc_mrw2 & ~0xFFu) | static_cast<u32>(mrw2);
|
||||
table->emc_mrw2 = (table->emc_mrw2 & ~0xFFu) | static_cast<u32>(mrw2);
|
||||
// table->dram_timings.rl = RL;
|
||||
// #endif
|
||||
|
||||
/* This needs some clean up. */
|
||||
constexpr double MC_ARB_DIV = 4.0;
|
||||
constexpr u32 MC_ARB_SFA = 2;
|
||||
constexpr u32 MC_ARB_SFA = 2;
|
||||
|
||||
table->burst_mc_regs.mc_emem_arb_cfg = table->rate_khz / (33.3 * 1000) / MC_ARB_DIV;
|
||||
table->burst_mc_regs.mc_emem_arb_timing_rcd = CEIL(GET_CYCLE_CEIL(tRCD) / MC_ARB_DIV) - 2;
|
||||
table->burst_mc_regs.mc_emem_arb_timing_rp = CEIL(GET_CYCLE_CEIL(tRPpb) / MC_ARB_DIV) - 1;
|
||||
table->burst_mc_regs.mc_emem_arb_timing_rc = CEIL(GET_CYCLE_CEIL(tRC) / MC_ARB_DIV) - 1;
|
||||
table->burst_mc_regs.mc_emem_arb_timing_ras = CEIL(GET_CYCLE_CEIL(tRAS) / MC_ARB_DIV) - 2;
|
||||
table->burst_mc_regs.mc_emem_arb_timing_faw = CEIL(GET_CYCLE_CEIL(tFAW) / MC_ARB_DIV) - 1;
|
||||
table->burst_mc_regs.mc_emem_arb_timing_rrd = CEIL(GET_CYCLE_CEIL(tRRD) / MC_ARB_DIV) - 1;
|
||||
table->burst_mc_regs.mc_emem_arb_timing_rfcpb = CEIL(GET_CYCLE_CEIL(tRFCpb) / MC_ARB_DIV) - 1;
|
||||
table->burst_mc_regs.mc_emem_arb_cfg = table->rate_khz / (33.3 * 1000) / MC_ARB_DIV;
|
||||
table->burst_mc_regs.mc_emem_arb_timing_rcd = CEIL(GET_CYCLE_CEIL(tRCD) / MC_ARB_DIV) - 2;
|
||||
table->burst_mc_regs.mc_emem_arb_timing_rp = CEIL(GET_CYCLE_CEIL(tRPpb) / MC_ARB_DIV) - 1;
|
||||
table->burst_mc_regs.mc_emem_arb_timing_rc = CEIL(GET_CYCLE_CEIL(tRC) / MC_ARB_DIV) - 1;
|
||||
table->burst_mc_regs.mc_emem_arb_timing_ras = CEIL(GET_CYCLE_CEIL(tRAS) / MC_ARB_DIV) - 2;
|
||||
table->burst_mc_regs.mc_emem_arb_timing_faw = CEIL(GET_CYCLE_CEIL(tFAW) / MC_ARB_DIV) - 1;
|
||||
table->burst_mc_regs.mc_emem_arb_timing_rrd = CEIL(GET_CYCLE_CEIL(tRRD) / MC_ARB_DIV) - 1;
|
||||
table->burst_mc_regs.mc_emem_arb_timing_rfcpb = CEIL(GET_CYCLE_CEIL(tRFCpb) / MC_ARB_DIV) - 1;
|
||||
table->burst_mc_regs.mc_emem_arb_timing_rap2pre = CEIL(tR2P / MC_ARB_DIV);
|
||||
table->burst_mc_regs.mc_emem_arb_timing_wap2pre = CEIL(tW2P / MC_ARB_DIV) + MC_ARB_SFA;
|
||||
|
||||
@@ -325,8 +334,8 @@ namespace ams::ldr::hoc::pcv::erista {
|
||||
table->la_scale_regs.mc_ptsa_grant_decrement = grant_decrement;
|
||||
|
||||
constexpr u32 MaskHigh = 0xFF00FFFF;
|
||||
constexpr u32 Mask2 = 0xFFFFFF00;
|
||||
constexpr u32 Mask3 = 0xFF00FF00;
|
||||
constexpr u32 Mask2 = 0xFFFFFF00;
|
||||
constexpr u32 Mask3 = 0xFF00FF00;
|
||||
|
||||
const u32 allowance1 = static_cast<u32>(0x32000 / (table->rate_khz / 0x3E8)) & 0xFF;
|
||||
const u32 allowance2 = static_cast<u32>(0x9C40 / (table->rate_khz / 0x3E8)) & 0xFF;
|
||||
@@ -354,71 +363,219 @@ namespace ams::ldr::hoc::pcv::erista {
|
||||
table->la_scale_regs.mc_latency_allowance_hc_1 = (table->la_scale_regs.mc_latency_allowance_hc_1 & Mask2) | allowance1;
|
||||
table->la_scale_regs.mc_latency_allowance_vi2_0 = (table->la_scale_regs.mc_latency_allowance_vi2_0 & Mask2) | allowance1;
|
||||
|
||||
table->dram_timings.t_rp = tRFCpb;
|
||||
table->dram_timings.t_rp = tRFCpb;
|
||||
table->dram_timings.t_rfc = tRFCab;
|
||||
table->emc_cfg_2 = 0x11083D;
|
||||
table->min_volt = std::min(static_cast<u32>(1050), 900 + C.emcDvbShift * 25);
|
||||
table->emc_cfg_2 = 0x11083D;
|
||||
table->min_volt = std::clamp(900 + (C.emcDvbShift * 25), 900, 1050);
|
||||
}
|
||||
|
||||
/* TODO: Template this */
|
||||
Result VerifyMtcTable(EristaMtcTable *tableStart, u32 expectedFreq) {
|
||||
R_UNLESS(tableStart->rate_khz == expectedFreq, ldr::ResultInvalidMtcTable());
|
||||
R_UNLESS(tableStart->rev == MTC_TABLE_REV, ldr::ResultInvalidMtcTable());
|
||||
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
/* Probably more intuitive to point to 40800 rather than 1600000, but oh well. */
|
||||
Result MemFreqMtcTable(u32 *ptr) {
|
||||
if (GET_MAX_OF_ARR(maxEmcClocks) <= EmcClkOSLimit) {
|
||||
R_SKIP();
|
||||
/* TODO: Template this */
|
||||
Result MtcValidateAllTables(EristaMtcTable *tableStart, const u32 *validationList, u32 tableCount) {
|
||||
for (u32 i = 0; i < tableCount; ++i) {
|
||||
R_TRY(VerifyMtcTable(&tableStart[i], validationList[i]));
|
||||
}
|
||||
|
||||
u32 khz_list[] = { 40800, 68000, 102000, 204000, 408000, 665600, 800000, 1065600, 1331200, 1600000 };
|
||||
std::sort(maxEmcClocks, maxEmcClocks + std::size(maxEmcClocks));
|
||||
u32 khz_list_size = std::size(khz_list);
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
// Generate list for mtc table pointers
|
||||
EristaMtcTable *table_list[khz_list_size];
|
||||
for (u32 i = 0; i < khz_list_size; i++) {
|
||||
u32 mtcIndex = khz_list_size - 1 - i;
|
||||
u8 *table = reinterpret_cast<u8 *>(ptr) - offsetof(EristaMtcTable, rate_khz) - i * sizeof(EristaMtcTable);
|
||||
table_list[mtcIndex] = reinterpret_cast<EristaMtcTable *>(table);
|
||||
R_UNLESS(table_list[mtcIndex]->rate_khz == khz_list[mtcIndex], ldr::ResultInvalidMtcTable());
|
||||
R_UNLESS(table_list[mtcIndex]->rev == MTC_TABLE_REV, ldr::ResultInvalidMtcTable());
|
||||
}
|
||||
/* TODO: Put this into common. */
|
||||
DramId GetDramId() {
|
||||
u64 id64;
|
||||
splGetConfig(SplConfigItem_DramId, &id64);
|
||||
return static_cast<DramId>(id64);
|
||||
}
|
||||
|
||||
/* If we oc ram at all, tables are always shifted by at least 1. */
|
||||
u32 tableShifts = 1;
|
||||
for (u32 i = 0; i < std::size(maxEmcClocks) - 1; ++i) {
|
||||
/* Duplicated mtc tables may cause pcv to not select frequencies properly, causing issues. */
|
||||
if (maxEmcClocks[i] != maxEmcClocks[i + 1] && maxEmcClocks[i] > EmcClkOSLimit) {
|
||||
++tableShifts;
|
||||
} else {
|
||||
maxEmcClocks[i] = 0;
|
||||
MtcTableIndex GetMtcDramIndex(DramId dramId) {
|
||||
for (u32 i = 0; i < std::size(mtcIndexTable); ++i) {
|
||||
if (mtcIndexTable[i].dramId == dramId) {
|
||||
return mtcIndexTable[i].index;
|
||||
}
|
||||
}
|
||||
|
||||
/* Erista has extra, useless mtc tables, such as 40.8 Mhz, overwrite them to make room for oc freqs. */
|
||||
/* More than 3 tables can be overwritten, but 3 is plenty. */
|
||||
std::memmove(table_list[0], table_list[tableShifts], sizeof(EristaMtcTable) * (khz_list_size - tableShifts));
|
||||
return MtcTableIndex_Invalid;
|
||||
}
|
||||
|
||||
/* Since we're not scaling r/w latency properly on Erista, we first overwrite the tables with the 1600 MHz table before scaling it. */
|
||||
for (u32 i = 0; i < tableShifts; ++i) {
|
||||
std::memcpy(table_list[khz_list_size - i - 1], table_list[khz_list_size - tableShifts - 1], sizeof(EristaMtcTable));
|
||||
NORETURN void AbortInvalidMtc(const char *crashMsg) {
|
||||
panic::SmcError(panic::Emc);
|
||||
CRASH(crashMsg);
|
||||
}
|
||||
|
||||
u32 GetMtcOffset(MtcTableIndex index) {
|
||||
if (index < T210SdevEmcDvfsTableS6gb01) {
|
||||
return index * erista::MtcFullTableSize;
|
||||
}
|
||||
|
||||
for (u32 i = tableShifts, j = 0; i > 0 && j < std::size(maxEmcClocks); ++j) {
|
||||
if (!maxEmcClocks[j]) {
|
||||
/* Account for the weird in between mariko table. */
|
||||
return index * erista::MtcFullTableSize + mariko::MtcFullTableSize;
|
||||
}
|
||||
|
||||
void PrepareMtcMemoryRegion(u8 *firstTable, EristaMtcTable *usedTable) {
|
||||
/* Move the table, this is nessasary for NLE */
|
||||
memmove(firstTable, usedTable, erista::MtcFullTableSize);
|
||||
|
||||
/* Clear all other tables. */
|
||||
/* The used table is excluded. */
|
||||
constexpr size_t RemainingRegionSize = (mariko::MtcFullTableSize) * (mariko::MtcFullTableCount) + (erista::MtcFullTableSize * (erista::MtcFullTableCount - 1));
|
||||
memset(firstTable + erista::MtcFullTableSize, 0, RemainingRegionSize);
|
||||
}
|
||||
|
||||
void MtcExtendTables(EristaMtcTable *table) {
|
||||
for (u32 i = erista::MtcTableCountDefault; i < newEmcList.size(); ++i) {
|
||||
std::memcpy(&table[i], &table[i - 1], sizeof(EristaMtcTable));
|
||||
table[i].rate_khz = newEmcList[i];
|
||||
}
|
||||
}
|
||||
|
||||
/* Relocate the table */
|
||||
/* Rescanning is simpler than trying to extract a bunch of data from the asm patch, performance impact is negligable */
|
||||
/* Also, this is more stable :P */
|
||||
u32 RepointEristaEmcTablePtr(uintptr_t fromSlot, uintptr_t toTable) {
|
||||
constexpr u32 RetIns = 0xD65F03C0; /* ret */
|
||||
u32 patched = 0;
|
||||
|
||||
for (u32 *p = nsoStart; p + 4 < nsoEnd; ++p) {
|
||||
const u32 ins = *p;
|
||||
if (!AsmIsAdrX0(ins)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
table_list[khz_list_size - i]->rate_khz = maxEmcClocks[j];
|
||||
MemMtcTableAutoAdjust(table_list[khz_list_size - i]);
|
||||
--i;
|
||||
const uintptr_t pc = reinterpret_cast<uintptr_t>(p);
|
||||
if (AsmAdrTarget(ins, pc) != fromSlot) {
|
||||
continue;
|
||||
}
|
||||
if (!(AsmIsLdpX(p[1]) && AsmIsLdpX(p[2]) && p[3] == RetIns)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* adr only reaches +-1MB */
|
||||
const s64 delta = static_cast<s64>(toTable) - static_cast<s64>(pc);
|
||||
if (delta > 0xFFFFF || delta < -0x100000) {
|
||||
continue;
|
||||
}
|
||||
|
||||
PATCH_OFFSET(p, AsmSetAdrTarget(ins, pc, toTable));
|
||||
++patched;
|
||||
}
|
||||
return patched;
|
||||
}
|
||||
|
||||
/* The silicon instructs; the children obey... */
|
||||
void MtcGenerateFreqTables() {
|
||||
newEmcList.clear();
|
||||
newEmcList.reserve(DvfsTableEntryCount);
|
||||
newEmcList.insert(newEmcList.end(), std::begin(EmcListDefault), std::end(EmcListDefault));
|
||||
|
||||
if (C.eristaEmcMaxClock <= EmcClkOSLimit) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* This is scuffed, but Eristas step rate is... weird? */
|
||||
/* 1766MHz seems to cause crashes with other freqs near it... why is anyones guess... */
|
||||
u32 freqsLow[] = { 1633000, 1666000, 1700000, 1733000, 1800000, 1833000, 1862400, };
|
||||
constexpr size_t freqsLowSize = std::size(freqsLow);
|
||||
|
||||
for (size_t i = 0; i < freqsLowSize; ++i) {
|
||||
if (freqsLow[i] <= C.eristaEmcMaxClock) {
|
||||
newEmcList.push_back(freqsLow[i]);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (C.eristaEmcMaxClock <= freqsLow[freqsLowSize - 1]) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* High range. */
|
||||
constexpr u32 StepRate = 38400;
|
||||
while (newEmcList.back() + StepRate < C.eristaEmcMaxClock) {
|
||||
newEmcList.push_back(newEmcList.back() + StepRate);
|
||||
}
|
||||
|
||||
if (newEmcList.back() != C.eristaEmcMaxClock) {
|
||||
newEmcList.push_back(static_cast<u32>(C.eristaEmcMaxClock));
|
||||
}
|
||||
|
||||
constexpr u32 PllmToggleFrequency = 19200;
|
||||
|
||||
/* A step of 19.2khz will cause hangs, crashes and other weirdness. */
|
||||
/* Why? ¯\_(ツ)_/¯ */
|
||||
if (C.eristaEmcMaxClock - newEmcList[newEmcList.size() - 2] <= PllmToggleFrequency) {
|
||||
newEmcList.erase(newEmcList.begin() + newEmcList.size() - 2);
|
||||
}
|
||||
|
||||
newEmcList.resize(std::min(newEmcList.size(), DvfsTableEntryLimit));
|
||||
}
|
||||
|
||||
Result MemFreqMtcTable(u32 *ptr) {
|
||||
static const DramId dramId = [] {
|
||||
DramId id = GetDramId();
|
||||
return id;
|
||||
}();
|
||||
|
||||
static const MtcTableIndex mtcIndex = [] {
|
||||
MtcTableIndex idx = GetMtcDramIndex(dramId);
|
||||
/* If for some reason this happens, there is no chance of recovering this. */
|
||||
if (idx == MtcTableIndex_Invalid) {
|
||||
AbortInvalidMtc("Invalid dramId");
|
||||
}
|
||||
return idx;
|
||||
}();
|
||||
|
||||
static const u32 mtcOffset = GetMtcOffset(mtcIndex);
|
||||
|
||||
constexpr u32 StartAdjustment = offsetof(EristaMtcTable, rate_khz) + sizeof(EristaMtcTable) * (erista::MtcTableCountDefault - 1);
|
||||
u8 *startPtr = reinterpret_cast<u8 *>(ptr) - StartAdjustment;
|
||||
|
||||
const uintptr_t usedSlot = reinterpret_cast<uintptr_t>(startPtr) + mtcOffset;
|
||||
EristaMtcTable *table = reinterpret_cast<EristaMtcTable *>(usedSlot);
|
||||
R_TRY(MtcValidateAllTables(table, EmcListDefault, EmcListSizeDefault));
|
||||
|
||||
PrepareMtcMemoryRegion(startPtr, table);
|
||||
table = reinterpret_cast<EristaMtcTable *>(startPtr);
|
||||
|
||||
/* We must do this as the NLE tables don't have enough space past them for our extended ones */
|
||||
if (usedSlot != reinterpret_cast<uintptr_t>(startPtr)) {
|
||||
if (RepointEristaEmcTablePtr(usedSlot, reinterpret_cast<uintptr_t>(startPtr)) == 0) {
|
||||
AbortInvalidMtc("Failed to repoint emc table");
|
||||
}
|
||||
}
|
||||
|
||||
if (R_FAILED(MtcValidateAllTables(table, EmcListDefault, EmcListSizeDefault))) {
|
||||
AbortInvalidMtc("Failed mtc validation");
|
||||
}
|
||||
|
||||
if (C.eristaEmcMaxClock <= EmcClkOSLimit) {
|
||||
R_SKIP();
|
||||
}
|
||||
|
||||
MtcExtendTables(table);
|
||||
|
||||
if (R_FAILED(MtcValidateAllTables(table, newEmcList.data(), newEmcList.size()))) {
|
||||
AbortInvalidMtc("Failed mtc validation");
|
||||
}
|
||||
|
||||
for (u32 i = erista::MtcTableCountDefault; i < newEmcList.size(); ++i) {
|
||||
MemMtcTableAutoAdjust(&table[i]);
|
||||
}
|
||||
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result MemFreqMax(u32 *ptr) {
|
||||
if (GET_MAX_OF_ARR(maxEmcClocks) <= EmcClkOSLimit) {
|
||||
if (C.eristaEmcMaxClock <= EmcClkOSLimit) {
|
||||
R_SKIP();
|
||||
}
|
||||
|
||||
PATCH_OFFSET(ptr, GET_MAX_OF_ARR(maxEmcClocks));
|
||||
PATCH_OFFSET(ptr, C.eristaEmcMaxClock);
|
||||
|
||||
R_SUCCEED();
|
||||
}
|
||||
@@ -450,22 +607,78 @@ namespace ams::ldr::hoc::pcv::erista {
|
||||
// R_SUCCEED();
|
||||
// }
|
||||
|
||||
|
||||
Result MemMtcTableAsm(u32 *ptr) {
|
||||
/* This is a mess but the compiler made this painful to patch so we must do it this way */
|
||||
constexpr s32 GoodAdrpOffset = -1;
|
||||
constexpr s32 GoodMovOffset = -7;
|
||||
constexpr s32 GoodBlOffset = 1;
|
||||
constexpr u32 MtcGoodBlOpcode = 0x97fe6cfc;
|
||||
|
||||
constexpr u32 MtcBadBlOpcode0 = 0x97ffae64; // bl nn::pcv::GetHardwareType
|
||||
constexpr u32 MtcBadBlOpcode1 = 0x940036d5; // bl strcmp
|
||||
constexpr u32 MtcBadAdrpAsm = 0xd00000a1; // adrp x1, s_ModuleResetStatus_
|
||||
|
||||
constexpr s32 MtcBadBlOffset0 = 2;
|
||||
constexpr s32 MtcBadBlOffset1 = -1;
|
||||
constexpr s32 MtcBadAdrpOffset = 1;
|
||||
|
||||
/* Ensure we don't dereference memory before nso start. */
|
||||
R_UNLESS(ptr + GoodMovOffset >= nsoStart, ldr::ResultInvalidMtcTablePattern());
|
||||
|
||||
/* Check for GetHardwareType asm and skip if it is found */
|
||||
/* The pattern will match on the first time, but the location is bad, so it must be skipped */
|
||||
if(AsmCompareAdrpNoImm(*(ptr + MtcBadAdrpOffset), MtcBadAdrpAsm) && AsmBlCompareOpcodeOnly(*(ptr + MtcBadBlOffset0), MtcBadBlOpcode0) && AsmBlCompareOpcodeOnly(*(ptr + MtcBadBlOffset1), MtcBadBlOpcode1)) {
|
||||
R_SKIP();
|
||||
}
|
||||
|
||||
/* We don't check for matching register because both registers must be x0 in order to pass the previous checks. */
|
||||
/* The correct instructions will always be x0 since the mtcTable pointer is returned. */
|
||||
u32 adrp = *(ptr + GoodAdrpOffset);
|
||||
R_UNLESS(AsmCompareAdrpNoImm(adrp, MtcAdrpAsm), ldr::ResultInvalidMtcTablePattern());
|
||||
|
||||
|
||||
/* Check for the branch instruction above the cbz to ensure we are patching the right location*/
|
||||
u32 bl = *(ptr + GoodBlOffset);
|
||||
R_UNLESS(AsmBlCompareOpcodeOnly(bl, MtcGoodBlOpcode), ldr::ResultInvalidMtcTablePattern());
|
||||
|
||||
|
||||
/* Check for the mov that actually sets the mtc table count. */
|
||||
u32 mov = *(ptr + GoodMovOffset);
|
||||
R_UNLESS(asm_compare_no_rd(mov, MtcMovAsm), ldr::ResultInvalidMtcTablePattern());
|
||||
|
||||
/* Patch out the count of the mov to our custom mtc table amount*/
|
||||
u32 movCountPatch = asm_set_rd(asm_set_imm16(MtcMovAsm, newEmcList.size()), asm_get_rd(mov));
|
||||
|
||||
PATCH_OFFSET(ptr + GoodMovOffset, movCountPatch);
|
||||
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
void Patch(uintptr_t mapped_nso, size_t nso_size) {
|
||||
nsoStart = reinterpret_cast<u32 *>(mapped_nso);
|
||||
nsoEnd = reinterpret_cast<u32 *>(mapped_nso + nso_size);
|
||||
MtcGenerateFreqTables();
|
||||
|
||||
u32 CpuCvbDefaultMaxFreq = static_cast<u32>(GetDvfsTableLastEntry(CpuCvbTableDefault)->freq);
|
||||
u32 GpuCvbDefaultMaxFreq = static_cast<u32>(GetDvfsTableLastEntry(GpuCvbTableDefault)->freq);
|
||||
|
||||
PatcherEntry<u32> patches[] = {
|
||||
{"CPU Freq Table", CpuFreqCvbTable<false>, 1, nullptr, static_cast<u32>(GetDvfsTableLastEntry(CpuCvbTableDefault)->freq)},
|
||||
{"CPU Volt DVFS", &CpuVoltDvfs, 1, nullptr, CpuVminOfficial},
|
||||
{"CPU Volt Thermals", &CpuVoltThermals, 1, nullptr, CpuVminOfficial},
|
||||
{"CPU Volt Dfll", &CpuVoltDfll, 1, nullptr, 0xFFEAD0FF},
|
||||
{"GPU Volt DVFS", &GpuVoltDVFS, 1, nullptr, GpuVminOfficial},
|
||||
{"GPU Volt Thermals", &GpuVoltThermals, 1, nullptr, GpuVminOfficial},
|
||||
{"GPU Freq Table", GpuFreqCvbTable<false>, 1, nullptr, static_cast<u32>(GetDvfsTableLastEntry(GpuCvbTableDefault)->freq)},
|
||||
{"GPU Freq Asm", &GpuFreqMaxAsm, 2, &GpuMaxClockPatternFn},
|
||||
{"GPU PLL Max", &GpuFreqPllMax, 1, nullptr, GpuClkPllMax},
|
||||
// {"GPU PLL Limit", &GpuFreqPllLimit, 4, nullptr, GpuClkPllLimit},
|
||||
{"MEM Freq Mtc", &MemFreqMtcTable, 0, nullptr, EmcClkOSLimit},
|
||||
{"MEM Freq Max", &MemFreqMax, 0, nullptr, EmcClkOSLimit},
|
||||
{"MEM Freq PLLM", &MemFreqPllmLimit, 2, nullptr, EmcClkPllmLimit},
|
||||
{"MEM Volt", &MemVoltHandler, 2, nullptr, MemVoltHOS},
|
||||
{"CPU Freq Table", CpuFreqCvbTable<false>, 1, nullptr, CpuCvbDefaultMaxFreq },
|
||||
{"CPU Volt DVFS", &CpuVoltDvfs, 1, nullptr, CpuVminOfficial },
|
||||
{"CPU Volt Thermals", &CpuVoltThermals, 1, nullptr, CpuVminOfficial },
|
||||
{"CPU Volt Dfll", &CpuVoltDfll, 1, nullptr, CpuTune0Low },
|
||||
{"GPU Volt DVFS", &GpuVoltDVFS, 1, nullptr, GpuVminOfficial },
|
||||
{"GPU Volt Thermals", &GpuVoltThermals, 1, nullptr, GpuVminOfficial },
|
||||
{"GPU Freq Table", GpuFreqCvbTable<false>, 1, nullptr, GpuCvbDefaultMaxFreq },
|
||||
{"GPU Freq Asm", &GpuFreqMaxAsm, 2, &GpuMaxClockPatternFn },
|
||||
{"GPU PLL Max", & GpuFreqPllMax, 1, nullptr, GpuClkPllMax },
|
||||
// {"GPU PLL Limit", &GpuFreqPllLimit, 4, nullptr, GpuClkPllLimit },
|
||||
{"MEM Table Asm", &MemMtcTableAsm, 4, &MemMtcGetGetTablePatternFn },
|
||||
{"MEM Freq Mtc", &MemFreqMtcTable, 1, nullptr, EmcClkOSLimit },
|
||||
{"MEM Freq Max", &MemFreqMax, 0, nullptr, EmcClkOSLimit },
|
||||
{"MEM Freq PLLM", &MemFreqPllmLimit, 2, nullptr, EmcClkPllmLimit },
|
||||
{"MEM Volt", &MemVoltHandler, 2, nullptr, MemVoltHOS },
|
||||
};
|
||||
|
||||
for (uintptr_t ptr = mapped_nso; ptr <= mapped_nso + nso_size - sizeof(EristaMtcTable); ptr += sizeof(u32)) {
|
||||
@@ -477,12 +690,13 @@ namespace ams::ldr::hoc::pcv::erista {
|
||||
}
|
||||
}
|
||||
|
||||
// ViewLog();
|
||||
|
||||
for (auto &entry : patches) {
|
||||
LOGGING("%s Count: %zu", entry.description, entry.patched_count);
|
||||
LOGGING("%s Count: %zu\n", entry.description, entry.patched_count);
|
||||
if (R_FAILED(entry.CheckResult())) {
|
||||
#if defined(AMS_BUILD_FOR_AUDITING) || defined(AMS_BUILD_FOR_DEBUGGING)
|
||||
panic::SmcError(panic::Patch);
|
||||
#endif
|
||||
// ViewLog();
|
||||
panic::SmcError(panic::Patch);
|
||||
|
||||
CRASH(entry.description);
|
||||
}
|
||||
|
||||
@@ -26,9 +26,6 @@
|
||||
|
||||
namespace ams::ldr::hoc::pcv::erista {
|
||||
|
||||
static u32 maxEmcClocks[] = { C.eristaEmcMaxClock2, C.eristaEmcMaxClock1, C.eristaEmcMaxClock, };
|
||||
#define GET_MAX_OF_ARR(ARR) (*std::max_element(ARR, ARR + std::size(ARR)))
|
||||
|
||||
constexpr cvb_entry_t CpuCvbTableDefault[] = {
|
||||
// CPU_PLL_CVB_TABLE_ODN
|
||||
{ 204000, {721094}, { } },
|
||||
@@ -51,16 +48,16 @@ namespace ams::ldr::hoc::pcv::erista {
|
||||
};
|
||||
|
||||
constexpr u32 CpuVoltOfficial = 1227;
|
||||
|
||||
constexpr u32 CpuVminOfficial = 825;
|
||||
constexpr u32 CpuTune0Low = 0xFFEAD0FF;
|
||||
|
||||
constexpr u32 CpuVoltL4T = 1257'000;
|
||||
|
||||
static const u32 cpuVoltDvfsPattern[] = { 1227, 1000, 100, 1000, 0 };
|
||||
static_assert(sizeof(cpuVoltDvfsPattern) == 0x14, "invalid cpuVoltDvfsPattern size");
|
||||
static_assert(sizeof(cpuVoltDvfsPattern) == 0x14, "Invalid cpuVoltDvfsPattern size");
|
||||
|
||||
static const u32 cpuVoltageThermalPattern[] = { 950, 1132, 0, 950, 1227, 0, 825, 1227, 15000, 825, 1170, 60000, 825, 1132, 80000 };
|
||||
static_assert(sizeof(cpuVoltageThermalPattern) == 0x3c, "invalid cpuVoltageThermalPattern size");
|
||||
static_assert(sizeof(cpuVoltageThermalPattern) == 0x3c, "Invalid cpuVoltageThermalPattern size");
|
||||
|
||||
constexpr u32 GpuClkPllLimit = 2'600'000;
|
||||
constexpr u32 GpuClkPllMax = 921'600'000;
|
||||
@@ -72,7 +69,7 @@ namespace ams::ldr::hoc::pcv::erista {
|
||||
static_assert(sizeof(gpuVoltDvfsPattern) == (sizeof(u32) * 6), "Invalid gpuVoltDvfsPattern");
|
||||
|
||||
static const u32 gpuVoltThermalPattern[] = { 950, 1132, 0, 810, 1132, 15000, 810, 1132, 30000, 810, 1132, 50000, 810, 1132, 70000, 810, 1132, 105000 };
|
||||
static_assert(sizeof(gpuVoltThermalPattern) == 0x48, "invalid gpuVoltageThermalPattern size");
|
||||
static_assert(sizeof(gpuVoltThermalPattern) == 0x48, "Invalid gpuVoltageThermalPattern size");
|
||||
|
||||
/* GPU Max Clock asm Pattern:
|
||||
*
|
||||
@@ -109,8 +106,11 @@ namespace ams::ldr::hoc::pcv::erista {
|
||||
{ },
|
||||
};
|
||||
|
||||
constexpr u32 MemVoltHOS = 1125'000;
|
||||
constexpr u32 EmcClkMinFreq = 40800; /* 40.8 MHz table only exists on erista. */
|
||||
constexpr u32 EmcListDefault[] = { 40800, 68000, 102000, 204000, 408000, 665600, 800000, 1065600, 1331200, 1600000, };
|
||||
constexpr u32 EmcListSizeDefault = std::size(EmcListDefault);
|
||||
constexpr u32 EmcListEndDefault = EmcListSizeDefault - 1;
|
||||
|
||||
constexpr u32 MemVoltHOS = 1125'000;
|
||||
constexpr u32 EmcClkPllmLimit = 1866'000'000;
|
||||
|
||||
constexpr u32 MTC_TABLE_REV = 7;
|
||||
@@ -123,13 +123,13 @@ namespace ams::ldr::hoc::pcv::erista {
|
||||
enum DramId {
|
||||
ICOSA_4GB_SAMSUNG_K4F6E304HB_MGCH = 0,
|
||||
ICOSA_4GB_HYNIX_H9HCNNNBPUMLHR_NLE = 1,
|
||||
ICOSA_4GB_MICRON_MT53B512M32D2NP_062_WTC = 2, /* This doesn't have a table in pcv? Wtf? */
|
||||
ICOSA_4GB_MICRON_MT53B512M32D2NP_062_WTC = 2,
|
||||
ICOSA_6GB_SAMSUNG_K4FHE3D4HM_MGCH = 4,
|
||||
ICOSA_8GB_SAMSUNG_K4FBE3D4HM_MGXX = 7, /* No table, but expected */
|
||||
ICOSA_8GB_SAMSUNG_K4FBE3D4HM_MGXX = 7,
|
||||
};
|
||||
|
||||
enum MtcTableIndex {
|
||||
T210SdevEmcDvfsTableS4gb01 = 0, /* HB-MGCH */
|
||||
T210SdevEmcDvfsTableS4gb01 = 0, /* HB-MGCH, WT:C */
|
||||
T210SdevEmcDvfsTableS6gb01 = 1, /* HM-MGCH */
|
||||
T210SdevEmcDvfsTableH4gb01 = 2, /* HR-NLE */
|
||||
MtcTableIndex_Invalid = 3,
|
||||
@@ -140,12 +140,26 @@ namespace ams::ldr::hoc::pcv::erista {
|
||||
MtcTableIndex index;
|
||||
};
|
||||
|
||||
constexpr MtcDramIndex mtcIndexTable[] = {
|
||||
{ ICOSA_4GB_SAMSUNG_K4F6E304HB_MGCH, T210SdevEmcDvfsTableS4gb01, },
|
||||
{ ICOSA_6GB_SAMSUNG_K4FHE3D4HM_MGCH, T210SdevEmcDvfsTableS6gb01, },
|
||||
{ ICOSA_4GB_HYNIX_H9HCNNNBPUMLHR_NLE, T210SdevEmcDvfsTableH4gb01, },
|
||||
/* TODO: Test 6gb and 8gb. */
|
||||
const inline MtcDramIndex mtcIndexTable[] = {
|
||||
{ ICOSA_4GB_SAMSUNG_K4F6E304HB_MGCH, T210SdevEmcDvfsTableS4gb01, },
|
||||
{ ICOSA_4GB_MICRON_MT53B512M32D2NP_062_WTC, T210SdevEmcDvfsTableS4gb01, },
|
||||
{ ICOSA_6GB_SAMSUNG_K4FHE3D4HM_MGCH, T210SdevEmcDvfsTableS6gb01, },
|
||||
{ ICOSA_8GB_SAMSUNG_K4FBE3D4HM_MGXX, T210SdevEmcDvfsTableS6gb01, },
|
||||
{ ICOSA_4GB_HYNIX_H9HCNNNBPUMLHR_NLE, T210SdevEmcDvfsTableH4gb01, },
|
||||
};
|
||||
|
||||
constexpr u32 MtcBrAsm = 0xD61F0140;
|
||||
constexpr u32 MtcMovAsm = 0x52800148;
|
||||
constexpr u32 MtcAdrpAsm = 0xD0000081;
|
||||
constexpr u32 MtcBlIns = 0x97ffae64;
|
||||
constexpr u32 MtcAddAsm = 0x91131821;
|
||||
|
||||
ALWAYS_INLINE bool MemMtcGetGetTablePatternFn(u32 *ptr) {
|
||||
/* This builds an address that gets returned, so the register must be x0 by convention. */
|
||||
return AsmCompareAddNoImm12(*ptr, MtcAddAsm);
|
||||
}
|
||||
|
||||
void Patch(uintptr_t mapped_nso, size_t nso_size);
|
||||
|
||||
}
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
*
|
||||
* Copyright (c) 2023 hanai3Bi
|
||||
*
|
||||
* Copyright (c) B3711
|
||||
*
|
||||
* Copyright (c) Souldbminer and Horizon OC Contributors
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
@@ -50,15 +52,17 @@ namespace ams::ldr::hoc::pcv::mariko {
|
||||
R_THROW(ldr::ResultInvalidGpuDvfs());
|
||||
}
|
||||
|
||||
if (!C.marikoGpuVmin) {
|
||||
R_SKIP();
|
||||
}
|
||||
// if (C.marikoGpuBootVolt) {
|
||||
// PATCH_OFFSET(ptr - 3, C.marikoGpuBootVolt);
|
||||
// }
|
||||
|
||||
PATCH_OFFSET(ptr, C.marikoGpuVmin);
|
||||
PATCH_OFFSET(ptr + 3, C.marikoGpuVmin);
|
||||
PATCH_OFFSET(ptr + 6, C.marikoGpuVmin);
|
||||
PATCH_OFFSET(ptr + 9, C.marikoGpuVmin);
|
||||
PATCH_OFFSET(ptr + 12, C.marikoGpuVmin);
|
||||
if (C.marikoGpuVmin) {
|
||||
PATCH_OFFSET(ptr, C.marikoGpuVmin);
|
||||
PATCH_OFFSET(ptr + 3, C.marikoGpuVmin);
|
||||
PATCH_OFFSET(ptr + 6, C.marikoGpuVmin);
|
||||
PATCH_OFFSET(ptr + 9, C.marikoGpuVmin);
|
||||
PATCH_OFFSET(ptr + 12, C.marikoGpuVmin);
|
||||
}
|
||||
|
||||
R_SUCCEED();
|
||||
}
|
||||
@@ -79,37 +83,44 @@ namespace ams::ldr::hoc::pcv::mariko {
|
||||
Result CpuFreqVdd(u32 *ptr) {
|
||||
dvfs_rail *entry = reinterpret_cast<dvfs_rail *>(reinterpret_cast<u8 *>(ptr) - offsetof(dvfs_rail, freq));
|
||||
|
||||
R_UNLESS(entry->id == 1, ldr::ResultInvalidCpuFreqVddEntry());
|
||||
R_UNLESS(entry->min_mv == 250'000, ldr::ResultInvalidCpuFreqVddEntry());
|
||||
R_UNLESS(entry->step_mv == 5000, ldr::ResultInvalidCpuFreqVddEntry());
|
||||
R_UNLESS(entry->max_mv == 1525'000, ldr::ResultInvalidCpuFreqVddEntry());
|
||||
R_UNLESS(entry->id == 1, ldr::ResultInvalidCpuFreqVddEntry());
|
||||
R_UNLESS(entry->min_mv == 250'000, ldr::ResultInvalidCpuFreqVddEntry());
|
||||
R_UNLESS(entry->step_mv == 5000, ldr::ResultInvalidCpuFreqVddEntry());
|
||||
R_UNLESS(entry->max_mv == 1525'000, ldr::ResultInvalidCpuFreqVddEntry());
|
||||
|
||||
if (C.marikoCpuUVHigh) {
|
||||
PATCH_OFFSET(ptr, CapCpuClock());
|
||||
} else {
|
||||
PATCH_OFFSET(ptr, GetDvfsTableLastEntry(C.marikoCpuDvfsTable)->freq);
|
||||
}
|
||||
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result CpuVoltDVFS(u32 *ptr) {
|
||||
if (MatchesPattern(ptr, cpuVoltagePatchOffsets, cpuVoltagePatchValues)) {
|
||||
if (C.marikoCpuLowVmin) {
|
||||
PATCH_OFFSET(ptr, C.marikoCpuLowVmin);
|
||||
}
|
||||
CvbMeta *cpuCvbMeta = reinterpret_cast<CvbMeta *>(reinterpret_cast<u8 *>(ptr) - offsetof(CvbMeta, vmin));
|
||||
|
||||
if (C.marikoCpuHighVmin) {
|
||||
PATCH_OFFSET(ptr - 2, C.marikoCpuHighVmin);
|
||||
}
|
||||
R_UNLESS(cpuCvbMeta->highVmin == CpuHighVminOfficial, ldr::ResultInvalidCpuMinVolt());
|
||||
R_UNLESS(cpuCvbMeta->unkStepMaybe == 38, ldr::ResultInvalidCpuMinVolt());
|
||||
R_UNLESS(cpuCvbMeta->vmax == CpuVoltOfficial, ldr::ResultInvalidCpuMinVolt());
|
||||
R_UNLESS(cpuCvbMeta->unkScale2 == 1000, ldr::ResultInvalidCpuMinVolt());
|
||||
R_UNLESS(cpuCvbMeta->speedoScale == 100, ldr::ResultInvalidCpuMinVolt());
|
||||
R_UNLESS(cpuCvbMeta->voltageScale == 1000, ldr::ResultInvalidCpuMinVolt());
|
||||
R_UNLESS(cpuCvbMeta->unkZero5 == 0, ldr::ResultInvalidCpuMinVolt());
|
||||
|
||||
if (C.marikoCpuMaxVolt) {
|
||||
PATCH_OFFSET(ptr + 5, C.marikoCpuMaxVolt);
|
||||
}
|
||||
|
||||
R_SUCCEED();
|
||||
if (C.marikoCpuLowVmin) {
|
||||
PATCH_OFFSET(&(cpuCvbMeta->vmin), C.marikoCpuLowVmin);
|
||||
}
|
||||
|
||||
R_THROW(ldr::ResultInvalidCpuMinVolt());
|
||||
if (C.marikoCpuHighVmin) {
|
||||
PATCH_OFFSET(&(cpuCvbMeta->highVmin), C.marikoCpuHighVmin);
|
||||
}
|
||||
|
||||
if (C.marikoCpuMaxVolt) {
|
||||
PATCH_OFFSET(&(cpuCvbMeta->vmax), C.marikoCpuMaxVolt);
|
||||
}
|
||||
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result CpuVoltThermals(u32 *ptr) {
|
||||
@@ -133,80 +144,80 @@ namespace ams::ldr::hoc::pcv::mariko {
|
||||
}
|
||||
|
||||
Result CpuVoltDfll(u32 *ptr) {
|
||||
cvb_cpu_dfll_data *entry = reinterpret_cast<cvb_cpu_dfll_data *>(ptr);
|
||||
CvbCpuDfllData *entry = reinterpret_cast<CvbCpuDfllData *>(ptr);
|
||||
|
||||
R_UNLESS(entry->tune0_low == 0xFFCF, ldr::ResultInvalidCpuVoltDfllEntry());
|
||||
R_UNLESS(entry->tune0_high == 0x0, ldr::ResultInvalidCpuVoltDfllEntry());
|
||||
R_UNLESS(entry->tune1_low == 0x12207FF, ldr::ResultInvalidCpuVoltDfllEntry());
|
||||
R_UNLESS(entry->tune0_low == 0xFFCF, ldr::ResultInvalidCpuVoltDfllEntry());
|
||||
R_UNLESS(entry->tune0_high == 0x0, ldr::ResultInvalidCpuVoltDfllEntry());
|
||||
R_UNLESS(entry->tune1_low == 0x12207FF, ldr::ResultInvalidCpuVoltDfllEntry());
|
||||
R_UNLESS(entry->tune1_high == 0x3FFF7FF, ldr::ResultInvalidCpuVoltDfllEntry());
|
||||
|
||||
switch (C.marikoCpuUVLow) {
|
||||
case 1:
|
||||
PATCH_OFFSET(&(entry->tune0_low), 0xffa0);
|
||||
PATCH_OFFSET(&(entry->tune0_low), 0xffa0);
|
||||
PATCH_OFFSET(&(entry->tune0_high), 0xffff);
|
||||
PATCH_OFFSET(&(entry->tune1_low), 0x21107ff);
|
||||
PATCH_OFFSET(&(entry->tune1_high), 0);
|
||||
PATCH_OFFSET(&(entry->tune1_low), 0x21107ff);
|
||||
PATCH_OFFSET(&(entry->tune1_high), 0x0);
|
||||
break;
|
||||
case 2:
|
||||
PATCH_OFFSET(&(entry->tune0_high), 0xffdf);
|
||||
PATCH_OFFSET(&(entry->tune1_low), 0x21107ff);
|
||||
PATCH_OFFSET(&(entry->tune1_low), 0x21107ff);
|
||||
PATCH_OFFSET(&(entry->tune1_high), 0x27207ff);
|
||||
break;
|
||||
case 3:
|
||||
PATCH_OFFSET(&(entry->tune0_low), 0xffdf);
|
||||
PATCH_OFFSET(&(entry->tune0_low), 0xffdf);
|
||||
PATCH_OFFSET(&(entry->tune0_high), 0xffdf);
|
||||
PATCH_OFFSET(&(entry->tune1_low), 0x21107ff);
|
||||
PATCH_OFFSET(&(entry->tune1_low), 0x21107ff);
|
||||
PATCH_OFFSET(&(entry->tune1_high), 0x27307ff);
|
||||
break;
|
||||
case 4:
|
||||
PATCH_OFFSET(&(entry->tune0_low), 0xffff);
|
||||
PATCH_OFFSET(&(entry->tune0_low), 0xffff);
|
||||
PATCH_OFFSET(&(entry->tune0_high), 0xffdf);
|
||||
PATCH_OFFSET(&(entry->tune1_low), 0x21107ff);
|
||||
PATCH_OFFSET(&(entry->tune1_low), 0x21107ff);
|
||||
PATCH_OFFSET(&(entry->tune1_high), 0x27407ff);
|
||||
break;
|
||||
case 5:
|
||||
PATCH_OFFSET(&(entry->tune0_high), 0xffdf);
|
||||
PATCH_OFFSET(&(entry->tune1_low), 0x21607ff);
|
||||
PATCH_OFFSET(&(entry->tune1_low), 0x21607ff);
|
||||
PATCH_OFFSET(&(entry->tune1_high), 0x27707ff);
|
||||
break;
|
||||
case 6:
|
||||
PATCH_OFFSET(&(entry->tune0_high), 0xffdf);
|
||||
PATCH_OFFSET(&(entry->tune1_low), 0x21607ff);
|
||||
PATCH_OFFSET(&(entry->tune1_low), 0x21607ff);
|
||||
PATCH_OFFSET(&(entry->tune1_high), 0x27807ff);
|
||||
break;
|
||||
case 7:
|
||||
PATCH_OFFSET(&(entry->tune0_high), 0xdfff);
|
||||
PATCH_OFFSET(&(entry->tune1_low), 0x21607ff);
|
||||
PATCH_OFFSET(&(entry->tune1_low), 0x21607ff);
|
||||
PATCH_OFFSET(&(entry->tune1_high), 0x27b07ff);
|
||||
break;
|
||||
case 8:
|
||||
PATCH_OFFSET(&(entry->tune0_low), 0xdfff);
|
||||
PATCH_OFFSET(&(entry->tune0_low), 0xdfff);
|
||||
PATCH_OFFSET(&(entry->tune0_high), 0xdfff);
|
||||
PATCH_OFFSET(&(entry->tune1_low), 0x21707ff);
|
||||
PATCH_OFFSET(&(entry->tune1_low), 0x21707ff);
|
||||
PATCH_OFFSET(&(entry->tune1_high), 0x27b07ff);
|
||||
break;
|
||||
case 9:
|
||||
PATCH_OFFSET(&(entry->tune0_low), 0xdfff);
|
||||
PATCH_OFFSET(&(entry->tune0_low), 0xdfff);
|
||||
PATCH_OFFSET(&(entry->tune0_high), 0xdfff);
|
||||
PATCH_OFFSET(&(entry->tune1_low), 0x21707ff);
|
||||
PATCH_OFFSET(&(entry->tune1_low), 0x21707ff);
|
||||
PATCH_OFFSET(&(entry->tune1_high), 0x27c07ff);
|
||||
break;
|
||||
case 10:
|
||||
PATCH_OFFSET(&(entry->tune0_low), 0xdfff);
|
||||
PATCH_OFFSET(&(entry->tune0_low), 0xdfff);
|
||||
PATCH_OFFSET(&(entry->tune0_high), 0xdfff);
|
||||
PATCH_OFFSET(&(entry->tune1_low), 0x21707ff);
|
||||
PATCH_OFFSET(&(entry->tune1_low), 0x21707ff);
|
||||
PATCH_OFFSET(&(entry->tune1_high), 0x27d07ff);
|
||||
break;
|
||||
case 11:
|
||||
PATCH_OFFSET(&(entry->tune0_low), 0xdfff);
|
||||
PATCH_OFFSET(&(entry->tune0_low), 0xdfff);
|
||||
PATCH_OFFSET(&(entry->tune0_high), 0xdfff);
|
||||
PATCH_OFFSET(&(entry->tune1_low), 0x21707ff);
|
||||
PATCH_OFFSET(&(entry->tune1_low), 0x21707ff);
|
||||
PATCH_OFFSET(&(entry->tune1_high), 0x27e07ff);
|
||||
break;
|
||||
case 12:
|
||||
PATCH_OFFSET(&(entry->tune0_low), 0xdfff);
|
||||
PATCH_OFFSET(&(entry->tune0_low), 0xdfff);
|
||||
PATCH_OFFSET(&(entry->tune0_high), 0xdfff);
|
||||
PATCH_OFFSET(&(entry->tune1_low), 0x21707ff);
|
||||
PATCH_OFFSET(&(entry->tune1_low), 0x21707ff);
|
||||
PATCH_OFFSET(&(entry->tune1_high), 0x27f07ff);
|
||||
break;
|
||||
default:
|
||||
@@ -215,7 +226,7 @@ namespace ams::ldr::hoc::pcv::mariko {
|
||||
|
||||
switch (C.marikoCpuUVHigh) {
|
||||
case 1:
|
||||
PATCH_OFFSET(&(entry->tune1_high), 0);
|
||||
PATCH_OFFSET(&(entry->tune1_high), 0x0);
|
||||
PATCH_OFFSET(&(entry->tune0_high), 0xffff);
|
||||
break;
|
||||
case 2:
|
||||
@@ -279,12 +290,6 @@ namespace ams::ldr::hoc::pcv::mariko {
|
||||
R_THROW(ldr::ResultInvalidGpuFreqMaxPattern());
|
||||
}
|
||||
|
||||
/* Verify the limit. */
|
||||
/* TODO: Make this a little bit cleaner at some point. */
|
||||
if (AsmGetImm16(ins1) != (GpuClkOsLimit & 0xFFFF) || AsmGetImm16(ins2) != (GpuClkOsLimit >> 16)) {
|
||||
R_THROW(ldr::ResultInvalidGpuFreqMaxPattern());
|
||||
}
|
||||
|
||||
u32 max_clock;
|
||||
switch (C.marikoGpuUV) {
|
||||
case 0:
|
||||
@@ -296,8 +301,14 @@ namespace ams::ldr::hoc::pcv::mariko {
|
||||
case 2:
|
||||
max_clock = GetDvfsTableLastEntry(C.marikoGpuDvfsTableHiOPT)->freq;
|
||||
break;
|
||||
case 3:
|
||||
max_clock = GetDvfsTableLastEntry(C.marikoGpuDvfsTableHiOPT15)->freq;
|
||||
break;
|
||||
case 4:
|
||||
max_clock = GetDvfsTableLastEntry(C.marikoGpuDvfsTableHighUV)->freq;
|
||||
break;
|
||||
default:
|
||||
max_clock = GetDvfsTableLastEntry(C.marikoGpuDvfsTable)->freq;
|
||||
max_clock = GetDvfsTableLastEntry(C.marikoGpuDvfsTableHiOPT)->freq;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -306,7 +317,7 @@ namespace ams::ldr::hoc::pcv::mariko {
|
||||
asm_set_rd(asm_set_imm16(GpuAsmPattern[1], max_clock >> 16), rd)
|
||||
};
|
||||
|
||||
PATCH_OFFSET(ptr32, asm_patch[0]);
|
||||
PATCH_OFFSET(ptr32, asm_patch[0]);
|
||||
PATCH_OFFSET(ptr32 + 1, asm_patch[1]);
|
||||
|
||||
R_SUCCEED();
|
||||
@@ -364,14 +375,8 @@ namespace ams::ldr::hoc::pcv::mariko {
|
||||
WRITE_PARAM_ALL_REG(table, emc_cfg, 0xF3200000);
|
||||
}
|
||||
|
||||
u32 refresh_raw = 0xFFFF;
|
||||
if (C.t8_tREFI != 6) {
|
||||
refresh_raw = CEIL(tREFpb_values[C.t8_tREFI] / tCK_avg) - 0x40;
|
||||
refresh_raw = MIN(refresh_raw, static_cast<u32>(0xFFFF));
|
||||
}
|
||||
|
||||
u32 trefbw = refresh_raw + 0x40;
|
||||
trefbw = MIN(trefbw, static_cast<u32>(0x3FFF));
|
||||
trefbw = MIN(trefbw, static_cast<u32>(0x3FFF));
|
||||
|
||||
const u32 dyn_self_ref_control = (static_cast<u32>(7605.0 / tCK_avg) + 260) | (table->burst_regs.emc_dyn_self_ref_control & 0xffff0000);
|
||||
|
||||
@@ -379,7 +384,7 @@ namespace ams::ldr::hoc::pcv::mariko {
|
||||
|
||||
WRITE_PARAM_ALL_REG(table, emc_rd_rcd, GET_CYCLE_CEIL(tRCD));
|
||||
WRITE_PARAM_ALL_REG(table, emc_wr_rcd, GET_CYCLE_CEIL(tRCD));
|
||||
WRITE_PARAM_ALL_REG(table, emc_rc, MIN(GET_CYCLE_CEIL(tRC), static_cast<u32>(0xB8)));
|
||||
WRITE_PARAM_ALL_REG(table, emc_rc, MIN(GET_CYCLE_CEIL(tRC), static_cast<u32>(0xB9)));
|
||||
WRITE_PARAM_ALL_REG(table, emc_ras, MIN(GET_CYCLE_CEIL(tRAS), static_cast<u32>(0x7F)));
|
||||
WRITE_PARAM_ALL_REG(table, emc_rrd, GET_CYCLE_CEIL(tRRD));
|
||||
WRITE_PARAM_ALL_REG(table, emc_rfcpb, GET_CYCLE_CEIL(tRFCpb));
|
||||
@@ -438,22 +443,21 @@ namespace ams::ldr::hoc::pcv::mariko {
|
||||
WRITE_PARAM_ALL_REG(table, emc_rdv_early_mask, rdv);
|
||||
WRITE_PARAM_ALL_REG(table, emc_rdv_mask, rdv + 2);
|
||||
WRITE_PARAM_ALL_REG(table, emc_tr_rdv, rdv);
|
||||
/* TODO: Check this out again at some point. */
|
||||
WRITE_PARAM_ALL_REG(table, emc_cmd_brlshft_2, 0x24);
|
||||
WRITE_PARAM_ALL_REG(table, emc_cmd_brlshft_3, 0x24);
|
||||
|
||||
/* This needs some clean up. */
|
||||
constexpr double MC_ARB_DIV = 4.0;
|
||||
constexpr u32 MC_ARB_SFA = 2;
|
||||
constexpr u32 MC_ARB_SFA = 2;
|
||||
|
||||
table->burst_mc_regs.mc_emem_arb_cfg = table->rate_khz / (33.3 * 1000) / MC_ARB_DIV;
|
||||
table->burst_mc_regs.mc_emem_arb_timing_rcd = CEIL(GET_CYCLE_CEIL(tRCD) / MC_ARB_DIV) - 2;
|
||||
table->burst_mc_regs.mc_emem_arb_timing_rp = CEIL(GET_CYCLE_CEIL(tRPpb) / MC_ARB_DIV) - 1;
|
||||
table->burst_mc_regs.mc_emem_arb_timing_rc = CEIL(GET_CYCLE_CEIL(tRC) / MC_ARB_DIV) - 1;
|
||||
table->burst_mc_regs.mc_emem_arb_timing_ras = CEIL(GET_CYCLE_CEIL(tRAS) / MC_ARB_DIV) - 2;
|
||||
table->burst_mc_regs.mc_emem_arb_timing_faw = CEIL(GET_CYCLE_CEIL(tFAW) / MC_ARB_DIV) - 1;
|
||||
table->burst_mc_regs.mc_emem_arb_timing_rrd = CEIL(GET_CYCLE_CEIL(tRRD) / MC_ARB_DIV) - 1;
|
||||
table->burst_mc_regs.mc_emem_arb_timing_rfcpb = CEIL(GET_CYCLE_CEIL(tRFCpb) / MC_ARB_DIV) - 1;
|
||||
table->burst_mc_regs.mc_emem_arb_cfg = table->rate_khz / (33.3 * 1000) / MC_ARB_DIV;
|
||||
table->burst_mc_regs.mc_emem_arb_timing_rcd = CEIL(GET_CYCLE_CEIL(tRCD) / MC_ARB_DIV) - 2;
|
||||
table->burst_mc_regs.mc_emem_arb_timing_rp = CEIL(GET_CYCLE_CEIL(tRPpb) / MC_ARB_DIV) - 1;
|
||||
table->burst_mc_regs.mc_emem_arb_timing_rc = CEIL(GET_CYCLE_CEIL(tRC) / MC_ARB_DIV) - 1;
|
||||
table->burst_mc_regs.mc_emem_arb_timing_ras = CEIL(GET_CYCLE_CEIL(tRAS) / MC_ARB_DIV) - 2;
|
||||
table->burst_mc_regs.mc_emem_arb_timing_faw = CEIL(GET_CYCLE_CEIL(tFAW) / MC_ARB_DIV) - 1;
|
||||
table->burst_mc_regs.mc_emem_arb_timing_rrd = CEIL(GET_CYCLE_CEIL(tRRD) / MC_ARB_DIV) - 1;
|
||||
table->burst_mc_regs.mc_emem_arb_timing_rfcpb = CEIL(GET_CYCLE_CEIL(tRFCpb) / MC_ARB_DIV) - 1;
|
||||
table->burst_mc_regs.mc_emem_arb_timing_rap2pre = CEIL(tR2P / MC_ARB_DIV);
|
||||
table->burst_mc_regs.mc_emem_arb_timing_wap2pre = CEIL(tW2P / MC_ARB_DIV) + MC_ARB_SFA;
|
||||
|
||||
@@ -526,12 +530,12 @@ namespace ams::ldr::hoc::pcv::mariko {
|
||||
table->la_scale_regs.mc_latency_allowance_hc_1 = (table->la_scale_regs.mc_latency_allowance_hc_1 & Mask2) | allowance1;
|
||||
table->la_scale_regs.mc_latency_allowance_vi2_0 = (table->la_scale_regs.mc_latency_allowance_vi2_0 & Mask2) | allowance1;
|
||||
|
||||
table->dram_timings.t_rp = tRFCpb;
|
||||
table->dram_timings.t_rp = tRFCpb;
|
||||
table->dram_timings.t_rfc = tRFCab;
|
||||
|
||||
table->dram_timings.rl = RL;
|
||||
table->emc_mrw2 = (table->emc_mrw2 & ~0xFFu) | static_cast<u32>(mrw2);
|
||||
table->emc_cfg_2 = 0x11083D;
|
||||
table->emc_mrw2 = (table->emc_mrw2 & ~0xFFu) | static_cast<u32>(mrw2);
|
||||
table->emc_cfg_2 = 0x11083D;
|
||||
}
|
||||
|
||||
void MemMtcPllmbDivisor(MarikoMtcTable *table) {
|
||||
@@ -544,11 +548,11 @@ namespace ams::ldr::hoc::pcv::mariko {
|
||||
|
||||
bool remainder_check = (table->rate_khz - PllOscInKHz * (table->rate_khz / PllOscInKHz)) > (table->rate_khz - PllOscHalfKHz * divm_candidate_half) && static_cast<int>(((target_freq_d / PllOscHalfKHz - divm_candidate_half - 0.5) * 8192.0)) != 0;
|
||||
|
||||
u32 divm_final = remainder_check + 1;
|
||||
u32 divm_final = remainder_check + 1;
|
||||
table->pllmb_divm = divm_final;
|
||||
|
||||
double div_step_d = static_cast<double>(PllOscInKHz) / divm_final;
|
||||
s32 divn_integer = static_cast<u8>(table->rate_khz / div_step_d);
|
||||
s32 divn_integer = static_cast<u8>(table->rate_khz / div_step_d);
|
||||
table->pllmb_divn = divn_integer;
|
||||
|
||||
u32 divn_fraction = static_cast<s32>((target_freq_d / div_step_d - divn_integer - 0.5) * 8192.0);
|
||||
@@ -559,34 +563,34 @@ namespace ams::ldr::hoc::pcv::mariko {
|
||||
s32 divn_fraction_ssc = static_cast<s32>((actual_freq_khz * 0.997 / div_step_d - divn_integer - 0.5) * 8192.0);
|
||||
|
||||
double delta_scaled = (0.3 / div_step_d + 0.3 / div_step_d) * (divn_fraction - divn_fraction_ssc);
|
||||
s32 delta_int = static_cast<s32>(delta_scaled);
|
||||
double delta_frac = delta_scaled - delta_int;
|
||||
s32 delta_int = static_cast<s32>(delta_scaled);
|
||||
double delta_frac = delta_scaled - delta_int;
|
||||
|
||||
u32 setup_value = 0;
|
||||
if (delta_frac <= 0.5) {
|
||||
double round_val = (delta_int + ROUND(delta_frac + delta_frac)) ? 0.5 : 0.0;
|
||||
setup_value = ROUND(delta_frac + delta_frac) ? static_cast<u32>(round_val + round_val) | 0x1000 : static_cast<u32>(round_val);
|
||||
setup_value = ROUND(delta_frac + delta_frac) ? static_cast<u32>(round_val + round_val) | 0x1000 : static_cast<u32>(round_val);
|
||||
} else {
|
||||
s32 frac_doubled = ROUND(delta_frac - 0.5 + delta_frac - 0.5);
|
||||
double round_val = 1.0;
|
||||
setup_value = frac_doubled ? static_cast<u32>(round_val) : static_cast<u32>(round_val + round_val) | 0x1000;
|
||||
setup_value = frac_doubled ? static_cast<u32>(round_val) : static_cast<u32>(round_val + round_val) | 0x1000;
|
||||
}
|
||||
|
||||
u32 ctrl1 = static_cast<u16>(divn_fraction_ssc) | (static_cast<u16>(divn_fraction) << 16);
|
||||
u32 ctrl2 = static_cast<u16>(divn_fraction) | (static_cast<u16>(setup_value) << 16);
|
||||
u32 ctrl2 = static_cast<u16>(divn_fraction) | (static_cast<u16>(setup_value) << 16);
|
||||
|
||||
table->pllm_ss_ctrl1 = ctrl1;
|
||||
table->pllm_ss_ctrl2 = ctrl2;
|
||||
table->pllm_ss_ctrl1 = ctrl1;
|
||||
table->pllm_ss_ctrl2 = ctrl2;
|
||||
table->pllmb_ss_ctrl1 = ctrl1;
|
||||
table->pllmb_ss_ctrl2 = ctrl2;
|
||||
} else {
|
||||
table->pllm_ss_cfg &= 0xBFFFFFFF;
|
||||
table->pllm_ss_cfg &= 0xBFFFFFFF;
|
||||
table->pllmb_ss_cfg &= 0xBFFFFFFF;
|
||||
|
||||
u64 pair = (static_cast<u64>(divn_fraction) << 32) | static_cast<u64>(table->rate_khz);
|
||||
u32 pll_misc = (table->pllm_ss_ctrl2 & 0xFFFF0000) | static_cast<u32>((pair - actual_freq_khz) >> 32);
|
||||
u64 pair = (static_cast<u64>(divn_fraction) << 32) | static_cast<u64>(table->rate_khz);
|
||||
u32 pll_misc = (table->pllm_ss_ctrl2 & 0xFFFF0000) | static_cast<u32>((pair - actual_freq_khz) >> 32);
|
||||
|
||||
table->pllm_ss_ctrl2 = pll_misc;
|
||||
table->pllm_ss_ctrl2 = pll_misc;
|
||||
table->pllmb_ss_ctrl2 = pll_misc;
|
||||
}
|
||||
}
|
||||
@@ -615,15 +619,34 @@ namespace ams::ldr::hoc::pcv::mariko {
|
||||
newEmcList.resize(std::min(newEmcList.size(), DvfsTableEntryLimit));
|
||||
}
|
||||
|
||||
void MtcGenerateFreqTables() {
|
||||
if (C.marikoEmcMaxClock <= EmcClkOSLimit) {
|
||||
return;
|
||||
void MtcGenerate133StepTable() {
|
||||
const u32 stepFreqs133[] = { 1733000, 1866000, 2000000, 2133000, 2266000, 2400000, 2533000, 2666000, 2800000, 2933000, 3066000, 3200000, 3333000, 3466000, }; // Avoid rounding issues
|
||||
constexpr u32 StepFreqs133Size = std::size(stepFreqs133);
|
||||
|
||||
for (u32 i = 0; i < StepFreqs133Size; ++i) {
|
||||
if (stepFreqs133[i] <= C.marikoEmcMaxClock) {
|
||||
newEmcList.push_back(stepFreqs133[i]);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (newEmcList.back() != C.marikoEmcMaxClock) {
|
||||
newEmcList.push_back(static_cast<u32>(C.marikoEmcMaxClock));
|
||||
}
|
||||
|
||||
newEmcList.resize(std::min(newEmcList.size(), DvfsTableEntryLimit));
|
||||
}
|
||||
|
||||
void MtcGenerateFreqTables() {
|
||||
newEmcList.clear();
|
||||
newEmcList.reserve(DvfsTableEntryCount);
|
||||
newEmcList.insert(newEmcList.end(), std::begin(EmcListDefault), std::end(EmcListDefault));
|
||||
|
||||
if (C.marikoEmcMaxClock <= EmcClkOSLimit) {
|
||||
return;
|
||||
}
|
||||
|
||||
u32 stepRate = 0;
|
||||
switch (C.stepMode) {
|
||||
case StepMode_66MHz:
|
||||
@@ -635,6 +658,9 @@ namespace ams::ldr::hoc::pcv::mariko {
|
||||
case StepMode_Jedec:
|
||||
MtcGenerateJedecTable();
|
||||
return;
|
||||
case StepMode_133MHz:
|
||||
MtcGenerate133StepTable();
|
||||
return;
|
||||
default:
|
||||
stepRate = 66667;
|
||||
break;
|
||||
@@ -665,7 +691,7 @@ namespace ams::ldr::hoc::pcv::mariko {
|
||||
|
||||
Result MtcValidateAllTables(MarikoMtcTable *tableStart, const u32 *validationList, u32 tableCount) {
|
||||
for (u32 i = 0; i < tableCount; ++i) {
|
||||
R_UNLESS(R_SUCCEEDED(VerifyMtcTable(&tableStart[i], validationList[i])), ldr::ResultInvalidMtcTable());
|
||||
R_TRY(VerifyMtcTable(&tableStart[i], validationList[i]));
|
||||
}
|
||||
|
||||
R_SUCCEED();
|
||||
@@ -687,9 +713,9 @@ namespace ams::ldr::hoc::pcv::mariko {
|
||||
return MtcTableIndex_Invalid;
|
||||
}
|
||||
|
||||
NORETURN void AbortInvalidDramId() {
|
||||
NORETURN void AbortInvalidMtc(const char *crashMsg) {
|
||||
panic::SmcError(panic::Emc);
|
||||
CRASH("Invalid dram id\n");
|
||||
CRASH(crashMsg);
|
||||
}
|
||||
|
||||
u32 GetMtcOffset(MtcTableIndex index) {
|
||||
@@ -718,15 +744,9 @@ namespace ams::ldr::hoc::pcv::mariko {
|
||||
}
|
||||
}
|
||||
|
||||
bool patchedMtc = false;
|
||||
Result MemFreqMtcTable(u32 *ptr) {
|
||||
if (C.marikoEmcMaxClock <= EmcClkOSLimit || patchedMtc) {
|
||||
R_SKIP();
|
||||
}
|
||||
|
||||
static const DramId dramId = [] {
|
||||
DramId id = GetDramId();
|
||||
id = IOWA_4GB_SAMSUNG_K4U6E3S4AA_MGCL;
|
||||
return id;
|
||||
}();
|
||||
|
||||
@@ -734,7 +754,7 @@ namespace ams::ldr::hoc::pcv::mariko {
|
||||
MtcTableIndex idx = GetMtcDramIndex(dramId);
|
||||
/* If for some reason this happens, there is no chance of recovering this. */
|
||||
if (idx == MtcTableIndex_Invalid) {
|
||||
AbortInvalidDramId();
|
||||
AbortInvalidMtc("Invalid dramId");
|
||||
}
|
||||
return idx;
|
||||
}();
|
||||
@@ -743,22 +763,26 @@ namespace ams::ldr::hoc::pcv::mariko {
|
||||
static const u32 mtcOffset = GetMtcOffset(mtcIndex);
|
||||
|
||||
/* Offset from 1600MHz pointer to 204Mhz table start. */
|
||||
constexpr u32 StartAdjustment = offsetof(MarikoMtcTable, rate_khz) + sizeof(MarikoMtcTable) * 2;
|
||||
constexpr u32 StartAdjustment = offsetof(MarikoMtcTable, rate_khz) + sizeof(MarikoMtcTable) * (mariko::MtcTableCountDefault - 1);
|
||||
u8 *startPtr = reinterpret_cast<u8 *>(ptr) - StartAdjustment;
|
||||
MarikoMtcTable *table = reinterpret_cast<MarikoMtcTable *>(startPtr + mtcOffset);
|
||||
R_UNLESS(R_SUCCEEDED(MtcValidateAllTables(table, EmcListDefault, EmcListSizeDefault)), ldr::ResultInvalidMtcTable());
|
||||
|
||||
table = reinterpret_cast<MarikoMtcTable *>(startPtr);
|
||||
R_TRY(MtcValidateAllTables(table, EmcListDefault, EmcListSizeDefault));
|
||||
|
||||
PrepareMtcMemoryRegion(startPtr, table);
|
||||
table = reinterpret_cast<MarikoMtcTable *>(startPtr);
|
||||
|
||||
if (R_FAILED(MtcValidateAllTables(table, EmcListDefault, EmcListSizeDefault))) {
|
||||
panic::SmcError(panic::Emc);
|
||||
AbortInvalidMtc("Failed mtc validation");
|
||||
}
|
||||
|
||||
if (C.marikoEmcMaxClock <= EmcClkOSLimit) {
|
||||
R_SKIP();
|
||||
}
|
||||
|
||||
MtcExtendTables(table);
|
||||
|
||||
if (R_FAILED(MtcValidateAllTables(table, newEmcList.data(), newEmcList.size()))) {
|
||||
panic::SmcError(panic::Emc);
|
||||
AbortInvalidMtc("Failed mtc validation");
|
||||
}
|
||||
|
||||
for (u32 i = mariko::MtcTableCountDefault; i < newEmcList.size(); ++i) {
|
||||
@@ -766,7 +790,6 @@ namespace ams::ldr::hoc::pcv::mariko {
|
||||
MemMtcPllmbDivisor(&table[i]);
|
||||
}
|
||||
|
||||
patchedMtc = true;
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
@@ -783,33 +806,95 @@ namespace ams::ldr::hoc::pcv::mariko {
|
||||
R_SKIP();
|
||||
}
|
||||
|
||||
s32 voltAdd = 25 * C.emcDvbShift;
|
||||
#define DVB_VOLT(zero, one, two) std::min(zero + voltAdd, 1050), std::min(one + voltAdd, 1025), std::min(two + voltAdd, 1000),
|
||||
DvbEntry emcDvbTableNew[] = {
|
||||
{ 204000, { 637, 637, 637, } },
|
||||
{ 1331200, { 650, 637, 637, } },
|
||||
{ 1600000, { 675, 650, 637, } },
|
||||
{ 1866000, { DVB_VOLT(700, 675, 650) } },
|
||||
{ 2133000, { DVB_VOLT(725, 700, 675) } },
|
||||
{ 2400000, { DVB_VOLT(750, 725, 700) } },
|
||||
{ 2666000, { DVB_VOLT(775, 750, 725) } },
|
||||
{ 2933000, { DVB_VOLT(800, 775, 750) } },
|
||||
{ 3200000, { DVB_VOLT(800, 800, 775) } },
|
||||
{ 0xFFFFFFFF, { } },
|
||||
s32 max0 = 1050;
|
||||
s32 max1 = 1025;
|
||||
s32 max2 = 1000;
|
||||
|
||||
if (C.marikoSocVmax && C.marikoSocVmax > 1000) {
|
||||
max0 = C.marikoSocVmax;
|
||||
max1 = C.marikoSocVmax;
|
||||
max2 = C.marikoSocVmax;
|
||||
}
|
||||
|
||||
constexpr s32 MinVolt = 637;
|
||||
|
||||
auto ClampVolt = [&](s32 value, s32 max, s32 voltAdd) {
|
||||
return std::clamp(value + voltAdd, MinVolt, max);
|
||||
};
|
||||
|
||||
u32 j = MtcTableCountDefault;
|
||||
for (u32 i = MtcTableCountDefault; i < newEmcList.size(); ++i) {
|
||||
if (newEmcList[i] >= emcDvbTableNew[j].freq && newEmcList[i] < emcDvbTableNew[j + 1].freq) {
|
||||
emcDvbTableNew[j].freq = newEmcList[i];
|
||||
++j;
|
||||
} else {
|
||||
break;
|
||||
auto DvbVolt = [&](s32 zero, s32 one, s32 two, u32 index) {
|
||||
const s32 overrideVoltage = C.marikoSocVoltArray[index];
|
||||
s32 voltAdd = 25 * C.emcDvbShift;
|
||||
|
||||
if (overrideVoltage) {
|
||||
zero = one = two = overrideVoltage;
|
||||
voltAdd = 0;
|
||||
}
|
||||
|
||||
return std::array<s32, 3>{
|
||||
ClampVolt(zero, max0, voltAdd),
|
||||
ClampVolt(one, max1, voltAdd),
|
||||
ClampVolt(two, max2, voltAdd)
|
||||
};
|
||||
};
|
||||
|
||||
#define DVB(v) \
|
||||
static_cast<u32>((v)[0]), \
|
||||
static_cast<u32>((v)[1]), \
|
||||
static_cast<u32>((v)[2])
|
||||
|
||||
#define DVB_OC(one, zero, two, idx) \
|
||||
DVB(DvbVolt(one, zero, two, idx))
|
||||
|
||||
DvbEntry emcDvbOcTableBrackets[] = {
|
||||
{ 204000, { 637, 637, 637, }, },
|
||||
{ 1331200, { 650, 637, 637, }, },
|
||||
{ 1600000, { 675, 650, 637, }, },
|
||||
{ 1866000, { DVB_OC( 700, 675, 650, 0) }, },
|
||||
{ 2000000, { DVB_OC( 712, 687, 662, 1) }, },
|
||||
{ 2133000, { DVB_OC( 725, 700, 675, 2) }, },
|
||||
{ 2200000, { DVB_OC( 737, 712, 687, 3) }, },
|
||||
{ 2266000, { DVB_OC( 750, 725, 700, 4) }, },
|
||||
{ 2333000, { DVB_OC( 762, 737, 712, 5) }, },
|
||||
{ 2400000, { DVB_OC( 775, 750, 725, 6) }, },
|
||||
{ 2433000, { DVB_OC( 787, 762, 737, 7) }, },
|
||||
{ 2466000, { DVB_OC( 800, 775, 750, 8) }, },
|
||||
{ 2533000, { DVB_OC( 812, 787, 762, 9) }, },
|
||||
{ 2566000, { DVB_OC( 825, 800, 775, 10) }, },
|
||||
{ 2600000, { DVB_OC( 837, 812, 787, 11) }, },
|
||||
{ 2666000, { DVB_OC( 850, 825, 800, 12) }, },
|
||||
{ 2700000, { DVB_OC( 875, 850, 825, 13) }, },
|
||||
{ 2733000, { DVB_OC( 887, 862, 837, 14) }, },
|
||||
{ 2766000, { DVB_OC( 912, 887, 862, 15) }, },
|
||||
{ 2800000, { DVB_OC( 925, 900, 875, 16) }, },
|
||||
{ 2833000, { DVB_OC( 937, 912, 887, 17) }, },
|
||||
{ 2900000, { DVB_OC( 950, 925, 900, 18) }, },
|
||||
{ 2933000, { DVB_OC( 962, 937, 912, 19) }, },
|
||||
{ 3000000, { DVB_OC( 975, 950, 925, 20) }, },
|
||||
{ 3033000, { DVB_OC( 987, 962, 937, 21) }, },
|
||||
{ 3100000, { DVB_OC(1000, 975, 950, 22) }, },
|
||||
{ 3133000, { DVB_OC(1025, 1000, 975, 23) }, },
|
||||
{ 3166000, { DVB_OC(1037, 1012, 987, 24) }, },
|
||||
{ 3200000, { DVB_OC(1050, 1025, 1000, 25) }, },
|
||||
{ ~0u, { }, },
|
||||
};
|
||||
#undef DVB
|
||||
#undef DVB_OC
|
||||
|
||||
DvbEntry emcDvbTableOc[newEmcList.size()];
|
||||
|
||||
u32 bracketIndex = 0;
|
||||
for (u32 i = 0; i < newEmcList.size(); ++i) {
|
||||
while (newEmcList[i] >= emcDvbOcTableBrackets[bracketIndex + 1].freq) {
|
||||
++bracketIndex;
|
||||
}
|
||||
|
||||
emcDvbTableOc[i].freq = newEmcList[i];
|
||||
std::memcpy(emcDvbTableOc[i].volt, emcDvbOcTableBrackets[bracketIndex].volt, sizeof(emcDvbTableOc[i].volt));
|
||||
}
|
||||
|
||||
std::memset(mem_dvb_table_head, 0, sizeof(EmcDvbTableDefault));
|
||||
std::memcpy(mem_dvb_table_head, &emcDvbTableNew, sizeof(emcDvbTableNew));
|
||||
std::memcpy(mem_dvb_table_head, &emcDvbTableOc, sizeof(emcDvbTableOc));
|
||||
|
||||
/* Max dvfs entry is 32, but HOS doesn't seem to boot if exact freq doesn't exist in dvb table,
|
||||
reason why it's like this
|
||||
@@ -850,7 +935,7 @@ namespace ams::ldr::hoc::pcv::mariko {
|
||||
regulator *entry = reinterpret_cast<regulator *>(reinterpret_cast<u8 *>(ptr) - offsetof(regulator, type_2_3.default_uv));
|
||||
|
||||
constexpr u32 uv_step = 5'000;
|
||||
constexpr u32 uv_min = 250'000;
|
||||
constexpr u32 uv_min = 250'000;
|
||||
|
||||
auto validator = [entry]() {
|
||||
R_UNLESS(entry->id == 2, ldr::ResultInvalidRegulatorEntry());
|
||||
@@ -910,8 +995,127 @@ namespace ams::ldr::hoc::pcv::mariko {
|
||||
u8 movRd = asm_get_rd(mov);
|
||||
u32 movCountPatch = asm_set_rd(asm_set_imm16(MtcMovAsm, newEmcList.size()), movRd);
|
||||
|
||||
PATCH_OFFSET(ptr - BrOffset, NopIns);
|
||||
PATCH_OFFSET(ptr - BrOffset, NopIns);
|
||||
PATCH_OFFSET(ptr - MovOffset, movCountPatch);
|
||||
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result GetSocSpeedo(u32 &socSpeedo) {
|
||||
constexpr u64 FusePhysicalAddress = 0x7000F000;
|
||||
u64 virtualAddress = 0;
|
||||
constexpr u64 Size = 0x1000;
|
||||
|
||||
u64 outSize;
|
||||
/* TODO: use svc::QueryMemoryMapping instead. */
|
||||
R_TRY(svcQueryMemoryMapping(&virtualAddress, &outSize, FusePhysicalAddress, Size));
|
||||
|
||||
constexpr u32 FuseOffset = 2048;
|
||||
constexpr u32 SocSpeedoOffset = 308;
|
||||
socSpeedo = *reinterpret_cast<u32 *>(virtualAddress + FuseOffset + SocSpeedoOffset);
|
||||
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
u32 GetSocProcessId(u32 socSpeedo) {
|
||||
if (socSpeedo <= 1597) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (socSpeedo <= 1708) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* >= 1709. */
|
||||
return 2;
|
||||
}
|
||||
|
||||
Result SocVoltAsm(u32 *compareSpeedos) {
|
||||
constexpr u32 VoltageScanLimit = 10;
|
||||
/* Might actually be speedo id. */
|
||||
u32 *writeProcessId = ScanAssembly(compareSpeedos, VoltageScanLimit, SocVoltWriteProcessIdAsm, asm_compare_no_rd);
|
||||
R_UNLESS(writeProcessId != nullptr, ldr::ResultInvalidSocVoltPattern());
|
||||
u8 writeProcessIdRd = asm_get_rd(*writeProcessId);
|
||||
|
||||
/* This writes 1050mV. */
|
||||
u32 *writeVoltage = ScanAssembly(writeProcessId, VoltageScanLimit, SocVoltWriteVoltageAsm, asm_compare_no_rd);
|
||||
R_UNLESS(writeVoltage != nullptr, ldr::ResultInvalidSocVoltPattern());
|
||||
u8 writeVoltageRd = asm_get_rd(*writeVoltage);
|
||||
|
||||
/* A csel instruction is used to select the soc voltage limit register. */
|
||||
/* We care about its destination register since that is used for verification. */
|
||||
constexpr u32 VoltageSelectScanLimit = 24;
|
||||
u32 *selectVoltage = ScanAssembly(writeVoltage, VoltageSelectScanLimit, SocVoltSelectRegisterAsm, AsmCompareCselNoReg);
|
||||
R_UNLESS(selectVoltage != nullptr, ldr::ResultInvalidSocVoltPattern());
|
||||
/* Todo: check rm and rn? */
|
||||
u8 selectVoltageRd = asm_get_rd(*selectVoltage);
|
||||
|
||||
/* rdCsel is then multiplied by 1000 to convert to uV. */
|
||||
/* This is pretty far down the function. */
|
||||
constexpr u32 MultiplierScanLimit = 200;
|
||||
u32 *multiplier = ScanAssembly(selectVoltage, MultiplierScanLimit, SocVoltMultiplyVoltsAsm, AsmCompareMullNoReg);
|
||||
R_UNLESS(multiplier != nullptr, ldr::ResultInvalidSocVoltPattern());
|
||||
u8 multiplierRn = AsmGetMullRn(*multiplier);
|
||||
u8 multiplierRm = AsmGetMullRm(*multiplier);
|
||||
/* One of the two registers has to be rdCsel. */
|
||||
R_UNLESS((multiplierRn == selectVoltageRd) || (multiplierRm == selectVoltageRd), ldr::ResultInvalidSocVoltPattern());
|
||||
u8 multiplierRd = asm_get_rd(*multiplier);
|
||||
|
||||
/* Subs instruction is then used to verify against absolute limit. */
|
||||
u32 limitValidationPattern = AsmSubsSetRn(SocVoltValidateLimitAsm, multiplierRd);
|
||||
u32 *limitValidation = ScanAssembly(multiplier, VoltageScanLimit, limitValidationPattern, AsmSubsCompareNoReg);
|
||||
R_UNLESS(limitValidation != nullptr, ldr::ResultInvalidSocVoltPattern());
|
||||
|
||||
/* There is a b.gt instruction right after (checks for socVoltageCap < socVoltageMax). */
|
||||
u32 *branchToAbort = limitValidation + 1;
|
||||
R_UNLESS(AsmCompareBrConNoImm19(*branchToAbort, SocVoltBranchToAbortAsm), ldr::ResultInvalidSocVoltPattern());
|
||||
|
||||
if (!C.marikoSocVmax || C.marikoSocVmax <= 1000) {
|
||||
R_SKIP();
|
||||
}
|
||||
|
||||
/* Adjust 1598 speedo minimum to ensure it always goes down process id 0 branch. */
|
||||
/* 2200 should be high enough :D */
|
||||
u32 compareSpeedosPatch = AsmSubsSetImm12(*compareSpeedos, 2200);
|
||||
PATCH_OFFSET(compareSpeedos, compareSpeedosPatch);
|
||||
|
||||
u32 socSpeedo = 0;
|
||||
R_TRY(GetSocSpeedo(socSpeedo));
|
||||
|
||||
/* Adjust processId from 0 to [process id of switch booting this]. */
|
||||
/* We're overwriting the orr instruction entirly. */
|
||||
u32 processId = GetSocProcessId(socSpeedo);
|
||||
u32 writeProcessIdPatch = asm_set_rd(asm_set_imm16(SocVoltWriteVoltageAsm, processId), writeProcessIdRd);
|
||||
PATCH_OFFSET(writeProcessId, writeProcessIdPatch);
|
||||
|
||||
/* Adjust voltage limit. */
|
||||
u32 voltageLimitPatch = asm_set_rd(asm_set_imm16(SocVoltWriteVoltageAsm, C.marikoSocVmax), writeVoltageRd);
|
||||
PATCH_OFFSET(writeVoltage, voltageLimitPatch);
|
||||
|
||||
/* Branches to an abort if limits are invalid -- we patch the branch instruction with NOP. */
|
||||
PATCH_OFFSET(branchToAbort, NopIns);
|
||||
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result SocVoltLimit(u32 *ptr) {
|
||||
R_UNLESS(!std::memcmp(ptr - SocVoltLimitMaxDefaultIndex, socVoltLimitArray, sizeof(socVoltLimitArray)), ldr::ResultInvalidSocVoltLimit());
|
||||
if (!C.marikoSocVmax || C.marikoSocVmax <= SocVoltLimitOfficial) {
|
||||
R_SKIP();
|
||||
}
|
||||
|
||||
constexpr u32 Step = 25;
|
||||
u32 maxVolt = C.marikoSocVmax;
|
||||
if (maxVolt % Step) {
|
||||
maxVolt = maxVolt / Step * Step; /* Round. */
|
||||
}
|
||||
|
||||
u32 volt = SocVoltLimitOfficial;
|
||||
for (u32 i = 1; i < DvfsTableEntryCount - SocVoltLimitMaxDefaultIndex && volt < maxVolt; ++i) {
|
||||
volt += Step;
|
||||
PATCH_OFFSET(ptr + i, volt);
|
||||
}
|
||||
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
@@ -933,13 +1137,15 @@ namespace ams::ldr::hoc::pcv::mariko {
|
||||
{ "GPU Freq Asm", &GpuFreqMaxAsm, 2, &GpuMaxClockPatternFn },
|
||||
{ "GPU PLL Max", &GpuFreqPllMax, 1, nullptr, GpuClkPllMax },
|
||||
{ "GPU PLL Limit", &GpuFreqPllLimit, 4, nullptr, GpuClkPllLimit },
|
||||
{ "MEM Freq Mtc", &MemFreqMtcTable, 0, nullptr, EmcClkOSLimit },
|
||||
{ "MEM Freq Mtc", &MemFreqMtcTable, 1, nullptr, EmcClkOSLimit },
|
||||
{ "MEM Freq Dvb", &MemFreqDvbTable, 1, nullptr, EmcClkOSLimit },
|
||||
{ "MEM Freq Max", &MemFreqMax, 0, nullptr, EmcClkOSLimit },
|
||||
{ "MEM Freq PLLM", &MemFreqPllmLimit, 2, nullptr, EmcClkPllmLimit },
|
||||
{ "MEM Vddq", &EmcVddqVolt, 2, nullptr, EmcVddqDefault },
|
||||
{ "MEM Vdd2", &MemVoltHandler, 2, nullptr, MemVdd2Default },
|
||||
{ "Mem Table Asm", &MemMtcTableAsm, 0, &MemMtcGetGetTablePatternFn },
|
||||
{ "MEM Table Asm", &MemMtcTableAsm, 1, &MemMtcGetGetTablePatternFn },
|
||||
{ "SOC Volt Asm", &SocVoltAsm, 1, &SocVoltPatternFn },
|
||||
{ "SOC Volt Limit", &SocVoltLimit, 1, nullptr, SocVoltLimitOfficial },
|
||||
};
|
||||
|
||||
for (uintptr_t ptr = mapped_nso; ptr <= mapped_nso + nso_size - sizeof(MarikoMtcTable); ptr += sizeof(u32)) {
|
||||
@@ -954,9 +1160,7 @@ namespace ams::ldr::hoc::pcv::mariko {
|
||||
for (auto &entry : patches) {
|
||||
LOGGING("%s Count: %zu", entry.description, entry.patched_count);
|
||||
if (R_FAILED(entry.CheckResult())) {
|
||||
#if defined(AMS_BUILD_FOR_AUDITING) || defined(AMS_BUILD_FOR_DEBUGGING)
|
||||
panic::SmcError(panic::Patch);
|
||||
#endif
|
||||
panic::SmcError(panic::Patch);
|
||||
|
||||
CRASH(entry.description);
|
||||
}
|
||||
|
||||
@@ -48,11 +48,11 @@ namespace ams::ldr::hoc::pcv::mariko {
|
||||
{ },
|
||||
};
|
||||
|
||||
constexpr u32 CpuClkOfficial = 1963'500;
|
||||
constexpr u32 CpuVoltOfficial = 1120;
|
||||
constexpr u32 CpuVminOfficial = 620;
|
||||
|
||||
constexpr u32 CpuTune0Low = 0xFFCF;
|
||||
constexpr u32 CpuClkOfficial = 1963'500;
|
||||
constexpr u32 CpuVoltOfficial = 1120;
|
||||
constexpr u32 CpuHighVminOfficial = 850;
|
||||
constexpr u32 CpuVminOfficial = 620;
|
||||
constexpr u32 CpuTune0Low = 0xFFCF;
|
||||
|
||||
static const u32 cpuVoltagePatchValues[] = { 850, 38, 1120, 1000, 100, 1000, 0 };
|
||||
static const s32 cpuVoltagePatchOffsets[] = { -2, -1, 5, 6, 7, 8, 9 };
|
||||
@@ -112,7 +112,7 @@ namespace ams::ldr::hoc::pcv::mariko {
|
||||
|
||||
struct DvbEntry {
|
||||
u64 freq;
|
||||
s32 volt[4] = {};
|
||||
u32 volt[4] = {};
|
||||
};
|
||||
|
||||
constexpr DvbEntry EmcDvbTableDefault[] = {
|
||||
@@ -124,16 +124,35 @@ namespace ams::ldr::hoc::pcv::mariko {
|
||||
{ 1600000, { 675, 650, 637, } },
|
||||
};
|
||||
|
||||
/* Movz */
|
||||
/*
|
||||
SF | OPC | HW | Imm16 | RD
|
||||
31 | 30 29 28 27 26 25 24 23 | 22 21 | 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 | 4 3 2 1 0
|
||||
*/
|
||||
constexpr u32 SocVoltCompareSpeedoAsm = 0x7118FAFF; /* subs imm, compares to >=1598 max speedo and then goes down process id 1 route. */
|
||||
constexpr u32 SocVoltWriteProcessIdAsm = 0x2A1F03F4; /* orr, writes id 0. */
|
||||
constexpr u32 SocVoltWriteVoltageAsm = 0x52808358; /* Movz imm, writes 1050mV. */
|
||||
constexpr u32 SocVoltSelectRegisterAsm = 0x1A9A3118; /* Csel, selects the voltage -- we need the register of this. */
|
||||
constexpr u32 SocVoltMultiplyVoltsAsm = 0x1B1A7F0B; /* Mul, converts from mV -> uV */
|
||||
constexpr u32 SocVoltValidateLimitAsm = 0x6B0A017F; /* Subs, checks limits */
|
||||
constexpr u32 SocVoltBranchToAbortAsm = 0x540020AC; /* B.ge Branches to abort if limits are invalid. */
|
||||
|
||||
ALWAYS_INLINE bool SocVoltPatternFn(u32 *ptr) {
|
||||
return asm_compare_no_rd(*ptr, SocVoltCompareSpeedoAsm);
|
||||
}
|
||||
|
||||
constexpr u32 SocVoltLimitOfficial = 1050;
|
||||
constexpr u32 SocVoltLimitMaxDefaultIndex = 17;
|
||||
static const u32 socVoltLimitArray[DvfsTableEntryCount] = { 637, 650, 675, 700, 725, 750, 775, 800, 825, 850, 875, 900, 925, 950, 975, 1000, 1025, 1050, };
|
||||
|
||||
constexpr u32 EmcListDefault[] = { 204000, 1331200, 1600000, };
|
||||
constexpr u32 EmcListSizeDefault = std::size(EmcListDefault);
|
||||
constexpr u32 EmcListEndDefault = EmcListSizeDefault - 1;
|
||||
constexpr u32 EmcRateStep = 33'000;
|
||||
constexpr u32 EmcRateStepScale = 33'200;
|
||||
|
||||
constexpr u32 EmcClkOSAlt = 1331'200;
|
||||
constexpr u32 EmcClkOSAlt = 1331'200;
|
||||
constexpr u32 EmcClkPllmLimit = 2133'000'000;
|
||||
constexpr u32 EmcVddqDefault = 600'000;
|
||||
constexpr u32 MemVdd2Default = 1100'000;
|
||||
constexpr u32 EmcVddqDefault = 600'000;
|
||||
constexpr u32 MemVdd2Default = 1100'000;
|
||||
|
||||
constexpr u32 MTC_TABLE_REV = 3;
|
||||
constexpr u32 MtcTableCountDefault = 3;
|
||||
@@ -209,7 +228,7 @@ namespace ams::ldr::hoc::pcv::mariko {
|
||||
MtcTableIndex index;
|
||||
};
|
||||
|
||||
constexpr MtcDramIndex mtcIndexTable[] = {
|
||||
const inline MtcDramIndex mtcIndexTable[] = {
|
||||
{ HOAG_4GB_HYNIX_H9HCNNNBKMMLXR_NEE, T210b0SdevEmcDvfsTableH1y4gb01, },
|
||||
{ AULA_4GB_HYNIX_H9HCNNNBKMMLXR_NEE, T210b0SdevEmcDvfsTableH1y4gb01, },
|
||||
{ IOWA_4GB_HYNIX_H9HCNNNBKMMLXR_NEE, T210b0SdevEmcDvfsTableH1y4gb01, },
|
||||
@@ -260,8 +279,8 @@ namespace ams::ldr::hoc::pcv::mariko {
|
||||
|
||||
/* Adrp */
|
||||
/*
|
||||
OP | ImmLow | ImmHigh | RD
|
||||
31 | 30 29 28 27 26 25 24 | 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 | 4 3 2 1 0
|
||||
OP | ImmLow | | ImmHigh | RD
|
||||
31 | 30 29 | 28 27 26 25 24 | 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 | 4 3 2 1 0
|
||||
*/
|
||||
|
||||
/* ADD (immediate) */
|
||||
|
||||
@@ -20,12 +20,8 @@
|
||||
|
||||
namespace ams::ldr::hoc::ptm {
|
||||
|
||||
Result CpuPtmBoost(perf_conf_entry* entry) {
|
||||
#ifdef ATMOSPHERE_IS_STRATOSPHERE
|
||||
Result CpuPtmBoost(perf_conf_entry *entry) {
|
||||
bool isMariko = (spl::GetSocType() == spl::SocType_Mariko);
|
||||
#else
|
||||
bool isMariko = true;
|
||||
#endif
|
||||
|
||||
if (!C.eristaCpuBoostClock || !C.marikoCpuBoostClock) {
|
||||
R_SUCCEED();
|
||||
@@ -39,19 +35,19 @@ namespace ams::ldr::hoc::ptm {
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result MemPtm(perf_conf_entry* entry) {
|
||||
Result MemPtm(perf_conf_entry *entry) {
|
||||
PATCH_OFFSET(&(entry->emc_freq_1), memPtmLimit);
|
||||
PATCH_OFFSET(&(entry->emc_freq_2), memPtmLimit);
|
||||
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
bool PtmEntryIsValid(perf_conf_entry* entry) {
|
||||
bool PtmEntryIsValid(perf_conf_entry *entry) {
|
||||
return (entry->cpu_freq_1 == entry->cpu_freq_2 && entry->gpu_freq_1 == entry->gpu_freq_2 && entry->emc_freq_1 == entry->emc_freq_2);
|
||||
}
|
||||
|
||||
bool PtmTablePatternFn(u32* ptr) {
|
||||
perf_conf_entry* entry = reinterpret_cast<perf_conf_entry *>(ptr);
|
||||
bool PtmTablePatternFn(u32 *ptr) {
|
||||
perf_conf_entry *entry = reinterpret_cast<perf_conf_entry *>(ptr);
|
||||
if (!PtmEntryIsValid(entry)) {
|
||||
return false;
|
||||
}
|
||||
@@ -60,9 +56,9 @@ namespace ams::ldr::hoc::ptm {
|
||||
}
|
||||
|
||||
void Patch(uintptr_t mapped_nso, size_t nso_size) {
|
||||
perf_conf_entry* confTable = nullptr;
|
||||
perf_conf_entry *confTable = nullptr;
|
||||
for (uintptr_t ptr = mapped_nso; ptr <= mapped_nso + nso_size - sizeof(perf_conf_entry) * entryCnt; ptr += sizeof(u32)) {
|
||||
u32* ptr32 = reinterpret_cast<u32 *>(ptr);
|
||||
u32 *ptr32 = reinterpret_cast<u32 *>(ptr);
|
||||
if (PtmTablePatternFn(ptr32)) {
|
||||
confTable = reinterpret_cast<perf_conf_entry *>(ptr);
|
||||
break;
|
||||
@@ -76,11 +72,7 @@ namespace ams::ldr::hoc::ptm {
|
||||
PatcherEntry<perf_conf_entry> cpuPtmBoostPatch = { "CPU Ptm Boost", &CpuPtmBoost, 2, };
|
||||
PatcherEntry<perf_conf_entry> memPtmPatch = { "MEM Ptm", &MemPtm, 16, };
|
||||
|
||||
#ifdef ATMOSPHERE_IS_STRATOSPHERE
|
||||
bool isMariko = (spl::GetSocType() == spl::SocType_Mariko);
|
||||
#else
|
||||
bool isMariko = true;
|
||||
#endif
|
||||
|
||||
for (u32 i = 0; i < entryCnt; i++) {
|
||||
perf_conf_entry *entry = confTable + i;
|
||||
@@ -92,7 +84,7 @@ namespace ams::ldr::hoc::ptm {
|
||||
|
||||
switch (entry->cpu_freq_1) {
|
||||
case cpuPtmBoost:
|
||||
cpuPtmBoostPatch.Apply(entry);
|
||||
R_DISCARD(cpuPtmBoostPatch.Apply(entry));
|
||||
break;
|
||||
case cpuPtmDefault:
|
||||
case cpuPtmDevOC:
|
||||
@@ -107,7 +99,7 @@ namespace ams::ldr::hoc::ptm {
|
||||
case memPtmAlt:
|
||||
case memPtmClamp:
|
||||
if (isMariko) {
|
||||
memPtmPatch.Apply(entry);
|
||||
R_DISCARD(memPtmPatch.Apply(entry));
|
||||
}
|
||||
break;
|
||||
default:
|
||||
@@ -117,13 +109,15 @@ namespace ams::ldr::hoc::ptm {
|
||||
}
|
||||
|
||||
LOGGING("%s Count: %zu", cpuPtmBoostPatch.description, cpuPtmBoostPatch.patched_count);
|
||||
if (R_FAILED(cpuPtmBoostPatch.CheckResult()))
|
||||
if (R_FAILED(cpuPtmBoostPatch.CheckResult())) {
|
||||
CRASH(cpuPtmBoostPatch.description);
|
||||
}
|
||||
|
||||
if (isMariko) {
|
||||
LOGGING("%s Count: %zu", memPtmPatch.description, memPtmPatch.patched_count);
|
||||
if (R_FAILED(memPtmPatch.CheckResult()))
|
||||
if (R_FAILED(memPtmPatch.CheckResult())) {
|
||||
CRASH(memPtmPatch.description);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
|
||||
namespace ams::ldr::hoc::ptm {
|
||||
|
||||
typedef struct {
|
||||
struct perf_conf_entry {
|
||||
u32 conf_id;
|
||||
u32 cpu_freq_1; // min-max pair?
|
||||
u32 cpu_freq_2;
|
||||
@@ -31,7 +31,7 @@ namespace ams::ldr::hoc::ptm {
|
||||
u32 emc_freq_1;
|
||||
u32 emc_freq_2;
|
||||
u32 padding;
|
||||
} perf_conf_entry;
|
||||
};
|
||||
|
||||
constexpr u32 entryCnt = 16;
|
||||
constexpr u32 cpuPtmDefault = 1020'000'000;
|
||||
|
||||
9
Source/Benchmark-Toolbox/.gitignore
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
# build artifacts
|
||||
build/
|
||||
*.nro
|
||||
*.elf
|
||||
*.nacp
|
||||
*.map
|
||||
|
||||
# generated nanovg shaders (regenerated by the build)
|
||||
resources/shaders/
|
||||
207
Source/Benchmark-Toolbox/Makefile
Normal file
@@ -0,0 +1,207 @@
|
||||
#---------------------------------------------------------------------------------
|
||||
.SUFFIXES:
|
||||
#---------------------------------------------------------------------------------
|
||||
|
||||
ifeq ($(strip $(DEVKITPRO)),)
|
||||
$(error "Please set DEVKITPRO in your environment. export DEVKITPRO=<path to>/devkitpro")
|
||||
endif
|
||||
|
||||
TOPDIR ?= $(CURDIR)
|
||||
include $(DEVKITPRO)/libnx/switch_rules
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
TARGET := Benchmark-Toolbox
|
||||
BUILD := build
|
||||
SOURCES := source source/furmark source/memtester source/cpustress
|
||||
DATA := data
|
||||
ICON := icon.jpg
|
||||
INCLUDES := source source/furmark source/memtester source/cpustress ../hoc-clk/common/include
|
||||
|
||||
APP_TITLE := Benchmark Toolbox
|
||||
APP_AUTHOR := Horizon-OC
|
||||
APP_VERSION := 2.0.0
|
||||
|
||||
ROMFS := resources
|
||||
BOREALIS_PATH := lib/borealis
|
||||
|
||||
# Output folder (in romfs) for borealis' autogenerated nanovg shaders
|
||||
OUT_SHADERS := shaders
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# options for code generation
|
||||
#---------------------------------------------------------------------------------
|
||||
ARCH := -march=armv8-a+crc+crypto -mtune=cortex-a57 -mtp=soft -fPIE
|
||||
|
||||
CFLAGS := -g -Wall -O2 -ffunction-sections \
|
||||
$(ARCH) $(DEFINES)
|
||||
|
||||
CFLAGS += $(INCLUDE) -D__SWITCH__ -pthread
|
||||
|
||||
# -include optional: borealis' nanovg dk_renderer.hpp uses std::optional without
|
||||
# including <optional> (newer libstdc++ dropped the transitive include).
|
||||
CXXFLAGS := $(CFLAGS) -std=gnu++17 -O2 -Wno-volatile -fexceptions -include optional
|
||||
|
||||
ASFLAGS := -g $(ARCH)
|
||||
LDFLAGS = -specs=$(DEVKITPRO)/libnx/switch.specs -g $(ARCH) -Wl,-Map,$(notdir $*.map) -pthread
|
||||
|
||||
# borealis.mk prepends -ldeko3d -lm. gpu_bw.c uses EGL/GLES; the Furmark tests
|
||||
# use desktop GL via glad. Add the full GL stack.
|
||||
LIBS := -lglad -lGLESv2 -lEGL -lglapi -ldrm_nouveau -lnx
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
LIBDIRS := $(PORTLIBS) $(LIBNX)
|
||||
|
||||
# Pull in borealis: appends its SOURCES / INCLUDES / LIBS / CXXFLAGS.
|
||||
# Run `git submodule update --init --recursive` so lib/borealis is populated.
|
||||
include $(TOPDIR)/$(BOREALIS_PATH)/library/borealis.mk
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
ifneq ($(BUILD),$(notdir $(CURDIR)))
|
||||
#---------------------------------------------------------------------------------
|
||||
|
||||
export OUTPUT := $(CURDIR)/$(TARGET)
|
||||
export TOPDIR := $(CURDIR)
|
||||
|
||||
export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \
|
||||
$(foreach dir,$(DATA),$(CURDIR)/$(dir))
|
||||
|
||||
export DEPSDIR := $(CURDIR)/$(BUILD)
|
||||
|
||||
CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c)))
|
||||
CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp)))
|
||||
SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s)))
|
||||
GLSLFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.glsl)))
|
||||
BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*)))
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
ifeq ($(strip $(CPPFILES)),)
|
||||
export LD := $(CC)
|
||||
else
|
||||
export LD := $(CXX)
|
||||
endif
|
||||
#---------------------------------------------------------------------------------
|
||||
|
||||
export OFILES_BIN := $(addsuffix .o,$(BINFILES))
|
||||
export OFILES_SRC := $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o)
|
||||
export OFILES := $(OFILES_BIN) $(OFILES_SRC)
|
||||
export HFILES_BIN := $(addsuffix .h,$(subst .,_,$(BINFILES)))
|
||||
|
||||
ifneq ($(strip $(ROMFS)),)
|
||||
ROMFS_TARGETS :=
|
||||
ROMFS_FOLDERS :=
|
||||
ifneq ($(strip $(OUT_SHADERS)),)
|
||||
ROMFS_SHADERS := $(ROMFS)/$(OUT_SHADERS)
|
||||
ROMFS_TARGETS += $(patsubst %.glsl, $(ROMFS_SHADERS)/%.dksh, $(GLSLFILES))
|
||||
ROMFS_FOLDERS += $(ROMFS_SHADERS)
|
||||
endif
|
||||
|
||||
export ROMFS_DEPS := $(foreach file,$(ROMFS_TARGETS),$(CURDIR)/$(file))
|
||||
endif
|
||||
|
||||
export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \
|
||||
$(foreach dir,$(LIBDIRS),-I$(dir)/include) \
|
||||
-I$(CURDIR)/$(BUILD)
|
||||
|
||||
export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib)
|
||||
|
||||
export APP_ICON := $(TOPDIR)/$(ICON)
|
||||
|
||||
ifeq ($(strip $(NO_ICON)),)
|
||||
export NROFLAGS += --icon=$(APP_ICON)
|
||||
endif
|
||||
|
||||
ifeq ($(strip $(NO_NACP)),)
|
||||
export NROFLAGS += --nacp=$(CURDIR)/$(TARGET).nacp
|
||||
endif
|
||||
|
||||
ifneq ($(APP_TITLEID),)
|
||||
export NACPFLAGS += --titleid=$(APP_TITLEID)
|
||||
endif
|
||||
|
||||
ifneq ($(ROMFS),)
|
||||
export NROFLAGS += --romfsdir=$(CURDIR)/$(ROMFS)
|
||||
endif
|
||||
|
||||
.PHONY: all clean
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
all: $(ROMFS_TARGETS) | $(BUILD)
|
||||
@MSYS2_ARG_CONV_EXCL="-D;$(MSYS2_ARG_CONV_EXCL)" $(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile
|
||||
|
||||
$(BUILD):
|
||||
@mkdir -p $@
|
||||
|
||||
ifneq ($(strip $(ROMFS_TARGETS)),)
|
||||
|
||||
$(ROMFS_TARGETS): | $(ROMFS_FOLDERS)
|
||||
|
||||
$(ROMFS_FOLDERS):
|
||||
@mkdir -p $@
|
||||
|
||||
$(ROMFS_SHADERS)/%_vsh.dksh: %_vsh.glsl
|
||||
@echo {vert} $(notdir $<)
|
||||
@uam -s vert -o $@ $<
|
||||
|
||||
$(ROMFS_SHADERS)/%_tcsh.dksh: %_tcsh.glsl
|
||||
@echo {tess_ctrl} $(notdir $<)
|
||||
@uam -s tess_ctrl -o $@ $<
|
||||
|
||||
$(ROMFS_SHADERS)/%_tesh.dksh: %_tesh.glsl
|
||||
@echo {tess_eval} $(notdir $<)
|
||||
@uam -s tess_eval -o $@ $<
|
||||
|
||||
$(ROMFS_SHADERS)/%_gsh.dksh: %_gsh.glsl
|
||||
@echo {geom} $(notdir $<)
|
||||
@uam -s geom -o $@ $<
|
||||
|
||||
$(ROMFS_SHADERS)/%_fsh.dksh: %_fsh.glsl
|
||||
@echo {frag} $(notdir $<)
|
||||
@uam -s frag -o $@ $<
|
||||
|
||||
$(ROMFS_SHADERS)/%.dksh: %.glsl
|
||||
@echo {comp} $(notdir $<)
|
||||
@uam -s comp -o $@ $<
|
||||
|
||||
endif
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
clean:
|
||||
@echo clean ...
|
||||
@rm -fr $(BUILD) $(ROMFS_FOLDERS) $(TARGET).nro $(TARGET).nacp $(TARGET).elf
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
else
|
||||
.PHONY: all
|
||||
|
||||
DEPENDS := $(OFILES:.o=.d)
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
all : $(OUTPUT).nro
|
||||
|
||||
ifeq ($(strip $(NO_NACP)),)
|
||||
$(OUTPUT).nro : $(OUTPUT).elf $(OUTPUT).nacp $(ROMFS_DEPS)
|
||||
else
|
||||
$(OUTPUT).nro : $(OUTPUT).elf $(ROMFS_DEPS)
|
||||
endif
|
||||
|
||||
$(OUTPUT).elf : $(OFILES)
|
||||
|
||||
$(OFILES_SRC) : $(HFILES_BIN)
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
%.bin.o %_bin.h : %.bin
|
||||
#---------------------------------------------------------------------------------
|
||||
@echo $(notdir $<)
|
||||
@$(bin2o)
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
%.png.o %_png.h : %.png
|
||||
#---------------------------------------------------------------------------------
|
||||
@echo $(notdir $<)
|
||||
@$(bin2o)
|
||||
|
||||
-include $(DEPENDS)
|
||||
|
||||
#---------------------------------------------------------------------------------------
|
||||
endif
|
||||
#---------------------------------------------------------------------------------------
|
||||
BIN
Source/Benchmark-Toolbox/data/colormap.png
Normal file
|
After Width: | Height: | Size: 413 B |
BIN
Source/Benchmark-Toolbox/data/compute_shader.bin
Normal file
BIN
Source/Benchmark-Toolbox/data/fur.png
Normal file
|
After Width: | Height: | Size: 647 KiB |
BIN
Source/Benchmark-Toolbox/data/noise.png
Normal file
|
After Width: | Height: | Size: 403 KiB |
BIN
Source/Benchmark-Toolbox/data/sk.png
Normal file
|
After Width: | Height: | Size: 1.1 MiB |
BIN
Source/Benchmark-Toolbox/data/wall.png
Normal file
|
After Width: | Height: | Size: 151 KiB |
BIN
Source/Benchmark-Toolbox/data/wunk.png
Normal file
|
After Width: | Height: | Size: 1.1 MiB |
BIN
Source/Benchmark-Toolbox/icon.jpg
Normal file
|
After Width: | Height: | Size: 9.7 KiB |
21
Source/Benchmark-Toolbox/lib/borealis/.clang-format
Normal file
@@ -0,0 +1,21 @@
|
||||
---
|
||||
AccessModifierOffset: -2
|
||||
AlignConsecutiveAssignments: 'true'
|
||||
BasedOnStyle: WebKit
|
||||
BreakBeforeBraces: Allman
|
||||
IncludeBlocks: Regroup
|
||||
IncludeCategories:
|
||||
- Regex: '^<borealis/.*\.hpp>'
|
||||
Priority: 2
|
||||
- Regex: '^<.*\.h>'
|
||||
Priority: 1
|
||||
- Regex: '^<.*'
|
||||
Priority: 2
|
||||
- Regex: '.*'
|
||||
Priority: 3
|
||||
IndentCaseLabels: 'true'
|
||||
PointerAlignment: Left
|
||||
SortIncludes: 'true'
|
||||
Standard: Cpp11
|
||||
|
||||
...
|
||||
12
Source/Benchmark-Toolbox/lib/borealis/AUTHORS
Normal file
@@ -0,0 +1,12 @@
|
||||
# List of borealis's significant contributors
|
||||
#
|
||||
# This does not necessarily list everyone who has contributed code.
|
||||
# To see the full list of contributors, see the contributors page on GitHub
|
||||
# https://github.com/natinusala/borealis/graphs/contributors
|
||||
natinusala
|
||||
p-sam
|
||||
WerWolv
|
||||
bylaws
|
||||
H0neyBadger
|
||||
D3fau4
|
||||
Behemoth
|
||||
201
Source/Benchmark-Toolbox/lib/borealis/LICENSE
Normal file
@@ -0,0 +1,201 @@
|
||||
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.
|
||||
@@ -37,24 +37,34 @@ include $(DEVKITPRO)/libnx/switch_rules
|
||||
# of a homebrew executable (.nro). This is intended to be used for sysmodules.
|
||||
# NACP building is skipped as well.
|
||||
#---------------------------------------------------------------------------------
|
||||
TARGET := $(notdir $(CURDIR))
|
||||
BUILD := build
|
||||
SOURCES := source
|
||||
TARGET := borealis_demo
|
||||
BUILD := build.nx
|
||||
SOURCES := demo
|
||||
DATA := data
|
||||
INCLUDES := include
|
||||
#ROMFS := romfs
|
||||
ICON := resources/img/demo_icon.jpg
|
||||
INCLUDES := demo
|
||||
|
||||
APP_TITLE := borealis demo
|
||||
APP_AUTHOR := natinusala
|
||||
APP_VERSION := 1.0
|
||||
|
||||
ROMFS := resources
|
||||
BOREALIS_PATH := .
|
||||
|
||||
# Output folders for autogenerated files in romfs
|
||||
OUT_SHADERS := shaders
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# options for code generation
|
||||
#---------------------------------------------------------------------------------
|
||||
ARCH := -march=armv8-a+crc+crypto -mtune=cortex-a57 -mtp=soft -fPIE -fPIC
|
||||
ARCH := -march=armv8-a+crc+crypto -mtune=cortex-a57 -mtp=soft -fPIE
|
||||
|
||||
CFLAGS := -g -Wall -O2 -ffunction-sections \
|
||||
$(ARCH) $(DEFINES)
|
||||
|
||||
CFLAGS += $(INCLUDE) -D__SWITCH__
|
||||
|
||||
CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions
|
||||
CXXFLAGS := $(CFLAGS) -std=c++1z -O2 -Wno-volatile
|
||||
|
||||
ASFLAGS := -g $(ARCH)
|
||||
LDFLAGS = -specs=$(DEVKITPRO)/libnx/switch.specs -g $(ARCH) -Wl,-Map,$(notdir $*.map)
|
||||
@@ -67,6 +77,7 @@ LIBS := -lnx
|
||||
#---------------------------------------------------------------------------------
|
||||
LIBDIRS := $(PORTLIBS) $(LIBNX)
|
||||
|
||||
include $(TOPDIR)/library/borealis.mk
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# no real need to edit anything past this point unless you need to add additional
|
||||
@@ -86,6 +97,7 @@ export DEPSDIR := $(CURDIR)/$(BUILD)
|
||||
CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c)))
|
||||
CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp)))
|
||||
SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s)))
|
||||
GLSLFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.glsl)))
|
||||
BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*)))
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
@@ -107,6 +119,18 @@ export OFILES_SRC := $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o)
|
||||
export OFILES := $(OFILES_BIN) $(OFILES_SRC)
|
||||
export HFILES_BIN := $(addsuffix .h,$(subst .,_,$(BINFILES)))
|
||||
|
||||
ifneq ($(strip $(ROMFS)),)
|
||||
ROMFS_TARGETS :=
|
||||
ROMFS_FOLDERS :=
|
||||
ifneq ($(strip $(OUT_SHADERS)),)
|
||||
ROMFS_SHADERS := $(ROMFS)/$(OUT_SHADERS)
|
||||
ROMFS_TARGETS += $(patsubst %.glsl, $(ROMFS_SHADERS)/%.dksh, $(GLSLFILES))
|
||||
ROMFS_FOLDERS += $(ROMFS_SHADERS)
|
||||
endif
|
||||
|
||||
export ROMFS_DEPS := $(foreach file,$(ROMFS_TARGETS),$(CURDIR)/$(file))
|
||||
endif
|
||||
|
||||
export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \
|
||||
$(foreach dir,$(LIBDIRS),-I$(dir)/include) \
|
||||
-I$(CURDIR)/$(BUILD)
|
||||
@@ -155,22 +179,55 @@ ifneq ($(ROMFS),)
|
||||
export NROFLAGS += --romfsdir=$(CURDIR)/$(ROMFS)
|
||||
endif
|
||||
|
||||
.PHONY: $(BUILD) clean all
|
||||
.PHONY: all clean
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
all: $(BUILD)
|
||||
all: $(ROMFS_TARGETS) | $(BUILD)
|
||||
@MSYS2_ARG_CONV_EXCL="-D;$(MSYS2_ARG_CONV_EXCL)" $(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile
|
||||
|
||||
$(BUILD):
|
||||
@[ -d $@ ] || mkdir -p $@
|
||||
@$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile
|
||||
@mkdir -p $@
|
||||
|
||||
ifneq ($(strip $(ROMFS_TARGETS)),)
|
||||
|
||||
$(ROMFS_TARGETS): | $(ROMFS_FOLDERS)
|
||||
|
||||
$(ROMFS_FOLDERS):
|
||||
@mkdir -p $@
|
||||
|
||||
$(ROMFS_SHADERS)/%_vsh.dksh: %_vsh.glsl
|
||||
@echo {vert} $(notdir $<)
|
||||
@uam -s vert -o $@ $<
|
||||
|
||||
$(ROMFS_SHADERS)/%_tcsh.dksh: %_tcsh.glsl
|
||||
@echo {tess_ctrl} $(notdir $<)
|
||||
@uam -s tess_ctrl -o $@ $<
|
||||
|
||||
$(ROMFS_SHADERS)/%_tesh.dksh: %_tesh.glsl
|
||||
@echo {tess_eval} $(notdir $<)
|
||||
@uam -s tess_eval -o $@ $<
|
||||
|
||||
$(ROMFS_SHADERS)/%_gsh.dksh: %_gsh.glsl
|
||||
@echo {geom} $(notdir $<)
|
||||
@uam -s geom -o $@ $<
|
||||
|
||||
$(ROMFS_SHADERS)/%_fsh.dksh: %_fsh.glsl
|
||||
@echo {frag} $(notdir $<)
|
||||
@uam -s frag -o $@ $<
|
||||
|
||||
$(ROMFS_SHADERS)/%.dksh: %.glsl
|
||||
@echo {comp} $(notdir $<)
|
||||
@uam -s comp -o $@ $<
|
||||
|
||||
endif
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
clean:
|
||||
@echo clean ...
|
||||
ifeq ($(strip $(APP_JSON)),)
|
||||
@rm -fr $(BUILD) $(TARGET).nro $(TARGET).nacp $(TARGET).elf
|
||||
@rm -fr $(BUILD) $(ROMFS_FOLDERS) $(TARGET).nro $(TARGET).nacp $(TARGET).elf
|
||||
else
|
||||
@rm -fr $(BUILD) $(TARGET).nsp $(TARGET).nso $(TARGET).npdm $(TARGET).elf
|
||||
@rm -fr $(BUILD) $(ROMFS_FOLDERS) $(TARGET).nsp $(TARGET).nso $(TARGET).npdm $(TARGET).elf
|
||||
endif
|
||||
|
||||
|
||||
@@ -188,9 +245,9 @@ ifeq ($(strip $(APP_JSON)),)
|
||||
all : $(OUTPUT).nro
|
||||
|
||||
ifeq ($(strip $(NO_NACP)),)
|
||||
$(OUTPUT).nro : $(OUTPUT).elf $(OUTPUT).nacp
|
||||
$(OUTPUT).nro : $(OUTPUT).elf $(OUTPUT).nacp $(ROMFS_DEPS)
|
||||
else
|
||||
$(OUTPUT).nro : $(OUTPUT).elf
|
||||
$(OUTPUT).nro : $(OUTPUT).elf $(ROMFS_DEPS)
|
||||
endif
|
||||
|
||||
else
|
||||
@@ -219,4 +276,4 @@ $(OFILES_SRC) : $(HFILES_BIN)
|
||||
|
||||
#---------------------------------------------------------------------------------------
|
||||
endif
|
||||
#---------------------------------------------------------------------------------------
|
||||
#---------------------------------------------------------------------------------------
|
||||
13
Source/Benchmark-Toolbox/lib/borealis/NOTICE
Normal file
@@ -0,0 +1,13 @@
|
||||
Copyright 2019-2021 borealis contributors
|
||||
|
||||
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.
|
||||
79
Source/Benchmark-Toolbox/lib/borealis/README.md
Normal file
@@ -0,0 +1,79 @@
|
||||

|
||||
# borealis
|
||||
|
||||
Controller and TV oriented UI library for PC and Nintendo Switch (libnx).
|
||||
|
||||
⚠️ Warning: the project is a WIP - See the Projects tab to follow the journey towards a stable version!
|
||||
|
||||
The code for the old version is available in the `legacy` branch.
|
||||
|
||||
⚠️ The wiki only contains the documentation for the old version of the library, it has yet to be updated!
|
||||
|
||||
- Mimicks the Nintendo Switch system UI, but can also be used to make anything else painlessly
|
||||
- Hardware acceleration and vector graphics with automatic scaling for TV usage (powered by nanovg)
|
||||
- Can be ported to new platforms and graphics APIs by providing a nanovg implementation
|
||||
- Powerful layout engine using flex box as a base for everything (powered by Yoga Layout)
|
||||
- Automated navigation paths for out-of-the-box controller navigation
|
||||
- Out of the box touch support
|
||||
- Define user interfaces using XML and only write code when it matters
|
||||
- Use and restyle built-in components or make your own from scratch
|
||||
- Display large amount of data efficiently using recycling lists
|
||||
- Integrated internationalization and storage systems
|
||||
- Integrated toolbox (logger, animations, timers, background tasks...)
|
||||
|
||||
## Building the demo for Switch
|
||||
|
||||
To build for Switch, a standard development environment must first be set up. In order to do so, [refer to the Getting Started guide](https://devkitpro.org/wiki/Getting_Started).
|
||||
|
||||
```bash
|
||||
(sudo) (dkp-)pacman -S switch-glfw switch-mesa switch-glm
|
||||
make -j
|
||||
nxlink -s borealis_demo.nro
|
||||
```
|
||||
|
||||
## Building the demo for PC
|
||||
|
||||
To build for PC, the following components are required:
|
||||
|
||||
- meson/ninja build system
|
||||
- A C++ compiler supporting the C++17 standard
|
||||
- GLFW version 3.3 or higher (as a static library)
|
||||
- GLM version 0.9.8 or higher
|
||||
|
||||
Please refer to the usual sources of information for your particular operating system. Usually the commands needed to build this project will look like this:
|
||||
|
||||
```bash
|
||||
meson build
|
||||
ninja -C build
|
||||
./build/borealis_demo
|
||||
```
|
||||
|
||||
Also, please note that the `resources` folder must be available in the working directory, otherwise the program will fail to find the shaders.
|
||||
|
||||
### Building the demo for Windows using msys2
|
||||
|
||||
msys2 provides all packages needed to build this project:
|
||||
|
||||
```bash
|
||||
pacman -S mingw-w64-x86_64-gcc mingw-w64-x86_64-meson mingw-w64-x86_64-ninja mingw-w64-x86_64-pkg-config mingw-w64-x86_64-glfw mingw-w64-x86_64-glm
|
||||
meson build
|
||||
ninja -C build
|
||||
./build/borealis_demo
|
||||
```
|
||||
|
||||
### Including in your project (TL;DR: see the demo makefile in this repo)
|
||||
0. Your project must be built as C++17 (`-std=c++1z`). You also need to remove `-fno-rtti` and `-fno-exceptions` if you have them
|
||||
1. Use a submodule (or even better, a [subrepo](https://github.com/ingydotnet/git-subrepo)) to clone this repository in your project
|
||||
2. Copy the `resources` folder to the root of your project
|
||||
3. For PC (meson):
|
||||
1. take a standard meson file
|
||||
2. use `subdir` to import the library folder
|
||||
3. use the `borealis_files`, `borealis_dependencies`, `borealis_include` and `borealis_cpp_args` variables for respectively objects to build, dependencies (glfw...), includes directory and cpp args
|
||||
4. add a `BRLS_RESOURCES` define pointing to the resources folder at runtime (so `resources`)
|
||||
4. For Switch:
|
||||
1. take a standard deko3d homebrew makefile (from the switch-examples repo)
|
||||
2. add a `BOREALIS_PATH` variable containing the subfolder you put the library in
|
||||
3. set `ROMFS` to the resources folder - borealis resources path is set to `romfs:/` in borealis.mk
|
||||
4. use `include` to load `borealis.mk` (after `LIBDIRS` and `BOREALIS_PATH`)
|
||||
5. it's important for `OUT_SHADERS` to be set to `shaders` since nanovg will look for the shaders there
|
||||
6. if you have issues with the `BRLS_RESOURCES` define (missing quote terminator), change the `@$(MAKE)` line to `@MSYS2_ARG_CONV_EXCL="-D;$(MSYS2_ARG_CONV_EXCL)" $(MAKE)` in the Makefile (as in the demo Makefile)
|
||||
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
Copyright 2020-2021 natinusala
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#include "captioned_image.hpp"
|
||||
|
||||
CaptionedImage::CaptionedImage()
|
||||
{
|
||||
// Load the XML file and inflate ourself with its content
|
||||
// The top-level Box in the XML corresponds to us, and every XML child
|
||||
// is added to our children (and the attributes are applied)
|
||||
// The CaptionedImage instance basically becomes what's written in the XML
|
||||
this->inflateFromXMLRes("xml/views/captioned_image.xml");
|
||||
|
||||
// The label stays hidden until focused, so hide it right away
|
||||
this->label->hide([] {});
|
||||
|
||||
// Forward Image and Label XML attributes
|
||||
this->forwardXMLAttribute("scalingType", this->image);
|
||||
this->forwardXMLAttribute("image", this->image);
|
||||
this->forwardXMLAttribute("focusUp", this->image);
|
||||
this->forwardXMLAttribute("focusRight", this->image);
|
||||
this->forwardXMLAttribute("focusDown", this->image);
|
||||
this->forwardXMLAttribute("focusLeft", this->image);
|
||||
this->forwardXMLAttribute("imageWidth", this->image, "width");
|
||||
this->forwardXMLAttribute("imageHeight", this->image, "height");
|
||||
|
||||
this->forwardXMLAttribute("caption", this->label, "text");
|
||||
}
|
||||
|
||||
void CaptionedImage::onChildFocusGained(brls::View* directChild, brls::View* focusedView)
|
||||
{
|
||||
// Called when a child of ours gets focused, in that case it's the Image
|
||||
|
||||
Box::onChildFocusGained(directChild, focusedView);
|
||||
|
||||
this->label->show([] {});
|
||||
}
|
||||
|
||||
void CaptionedImage::onChildFocusLost(brls::View* directChild, brls::View* focusedView)
|
||||
{
|
||||
// Called when a child of ours losts focused, in that case it's the Image
|
||||
|
||||
Box::onChildFocusLost(directChild, focusedView);
|
||||
|
||||
this->label->hide([] {});
|
||||
}
|
||||
|
||||
brls::View* CaptionedImage::create()
|
||||
{
|
||||
// Called by the XML engine to create a new CaptionedImage
|
||||
return new CaptionedImage();
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
Copyright 2020-2021 natinusala
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <borealis.hpp>
|
||||
|
||||
class CaptionedImage : public brls::Box
|
||||
{
|
||||
public:
|
||||
CaptionedImage();
|
||||
|
||||
void onChildFocusGained(brls::View* directChild, brls::View* focusedView) override;
|
||||
void onChildFocusLost(brls::View* directChild, brls::View* focusedView) override;
|
||||
|
||||
static brls::View* create();
|
||||
|
||||
private:
|
||||
BRLS_BIND(brls::Image, image, "image");
|
||||
BRLS_BIND(brls::Label, label, "label");
|
||||
};
|
||||
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
Copyright 2021 natinusala
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#include "components_tab.hpp"
|
||||
|
||||
ComponentsTab::ComponentsTab()
|
||||
{
|
||||
// Inflate the tab from the XML file
|
||||
this->inflateFromXMLRes("xml/tabs/components.xml");
|
||||
|
||||
// Bind the button click to a method using the macro (just for the sake of showcasing it, it's overkill in this situation)
|
||||
BRLS_REGISTER_CLICK_BY_ID("button_primary", this->onPrimaryButtonClicked);
|
||||
|
||||
// Get a handle to the button and register the action directly
|
||||
brls::Button* highlightButton = (brls::Button*)this->getView("button_highlight");
|
||||
highlightButton->registerAction(
|
||||
"Honk", brls::BUTTON_A, [](brls::View* view) { return true; }, false, brls::SOUND_HONK);
|
||||
}
|
||||
|
||||
bool ComponentsTab::onPrimaryButtonClicked(brls::View* view)
|
||||
{
|
||||
brls::Logger::info("Clicked");
|
||||
return true;
|
||||
}
|
||||
|
||||
brls::View* ComponentsTab::create()
|
||||
{
|
||||
// Called by the XML engine to create a new ComponentsTab
|
||||
return new ComponentsTab();
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
Copyright 2021 natinusala
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <borealis.hpp>
|
||||
|
||||
class ComponentsTab : public brls::Box
|
||||
{
|
||||
public:
|
||||
ComponentsTab();
|
||||
|
||||
static brls::View* create();
|
||||
|
||||
private:
|
||||
bool onPrimaryButtonClicked(brls::View* view);
|
||||
};
|
||||
82
Source/Benchmark-Toolbox/lib/borealis/demo/main.cpp
Normal file
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
Copyright 2020-2021 natinusala
|
||||
Copyright 2019 p-sam
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
// Switch include only necessary for demo videos recording
|
||||
#ifdef __SWITCH__
|
||||
#include <switch.h>
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <borealis.hpp>
|
||||
#include <string>
|
||||
|
||||
#include "captioned_image.hpp"
|
||||
#include "components_tab.hpp"
|
||||
#include "main_activity.hpp"
|
||||
#include "recycling_list_tab.hpp"
|
||||
|
||||
using namespace brls::literals; // for _i18n
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
// Enable recording for Twitter memes
|
||||
#ifdef __SWITCH__
|
||||
appletInitializeGamePlayRecording();
|
||||
#endif
|
||||
|
||||
// Set log level
|
||||
// We recommend to use INFO for real apps
|
||||
brls::Logger::setLogLevel(brls::LogLevel::DEBUG);
|
||||
|
||||
// Init the app and i18n
|
||||
if (!brls::Application::init())
|
||||
{
|
||||
brls::Logger::error("Unable to init Borealis application");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
brls::Application::createWindow("demo/title"_i18n);
|
||||
|
||||
// Have the application register an action on every activity that will quit when you press BUTTON_START
|
||||
brls::Application::setGlobalQuit(true);
|
||||
|
||||
// Register custom views (including tabs, which are views)
|
||||
brls::Application::registerXMLView("CaptionedImage", CaptionedImage::create);
|
||||
brls::Application::registerXMLView("RecyclingListTab", RecyclingListTab::create);
|
||||
brls::Application::registerXMLView("ComponentsTab", ComponentsTab::create);
|
||||
|
||||
// Add custom values to the theme
|
||||
brls::getLightTheme().addColor("captioned_image/caption", nvgRGB(2, 176, 183));
|
||||
brls::getDarkTheme().addColor("captioned_image/caption", nvgRGB(51, 186, 227));
|
||||
|
||||
// Add custom values to the style
|
||||
brls::getStyle().addMetric("about/padding_top_bottom", 50);
|
||||
brls::getStyle().addMetric("about/padding_sides", 75);
|
||||
brls::getStyle().addMetric("about/description_margin", 50);
|
||||
|
||||
// Create and push the main activity to the stack
|
||||
brls::Application::pushActivity(new MainActivity());
|
||||
|
||||
// Run the app
|
||||
while (brls::Application::mainLoop())
|
||||
;
|
||||
|
||||
// Exit
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
17
Source/Benchmark-Toolbox/lib/borealis/demo/main_activity.cpp
Normal file
@@ -0,0 +1,17 @@
|
||||
/*
|
||||
Copyright 2020-2021 natinusala
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#include "main_activity.hpp"
|
||||
26
Source/Benchmark-Toolbox/lib/borealis/demo/main_activity.hpp
Normal file
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
Copyright 2020-2021 natinusala
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <borealis.hpp>
|
||||
|
||||
class MainActivity : public brls::Activity
|
||||
{
|
||||
public:
|
||||
// Declare that the content of this activity is the given XML file
|
||||
CONTENT_FROM_XML_RES("activity/main.xml");
|
||||
};
|
||||
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
Copyright 2020-2021 natinusala
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#include "recycling_list_tab.hpp"
|
||||
|
||||
RecyclingListTab::RecyclingListTab()
|
||||
{
|
||||
// Inflate the tab from the XML file
|
||||
this->inflateFromXMLRes("xml/tabs/recycling_list.xml");
|
||||
}
|
||||
|
||||
brls::View* RecyclingListTab::create()
|
||||
{
|
||||
// Called by the XML engine to create a new RecyclingListTab
|
||||
return new RecyclingListTab();
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
Copyright 2020-2021 natinusala
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <borealis.hpp>
|
||||
|
||||
class RecyclingListTab : public brls::Box
|
||||
{
|
||||
public:
|
||||
RecyclingListTab();
|
||||
|
||||
static brls::View* create();
|
||||
};
|
||||
35
Source/Benchmark-Toolbox/lib/borealis/library/borealis.mk
Normal file
@@ -0,0 +1,35 @@
|
||||
mkfile_path := $(abspath $(lastword $(MAKEFILE_LIST)))
|
||||
current_dir := $(BOREALIS_PATH)/$(notdir $(patsubst %/,%,$(dir $(mkfile_path))))
|
||||
|
||||
LIBS := -ldeko3d -lm $(LIBS)
|
||||
|
||||
include $(TOPDIR)/$(current_dir)/lib/extern/switch-libpulsar/deps.mk
|
||||
|
||||
SOURCES := $(SOURCES) \
|
||||
$(current_dir)/lib/core \
|
||||
$(current_dir)/lib/views \
|
||||
$(current_dir)/lib/platforms/switch \
|
||||
$(current_dir)/lib/extern/glad \
|
||||
$(current_dir)/lib/extern/nanovg-deko3d/source \
|
||||
$(current_dir)/lib/extern/nanovg-deko3d/source/framework \
|
||||
$(current_dir)/lib/extern/nanovg-deko3d/shaders \
|
||||
$(current_dir)/lib/extern/libretro-common/compat \
|
||||
$(current_dir)/lib/extern/libretro-common/encodings \
|
||||
$(current_dir)/lib/extern/libretro-common/features \
|
||||
$(current_dir)/lib/extern/nxfmtwrapper \
|
||||
$(current_dir)/lib/extern/yoga/src/yoga/event \
|
||||
$(current_dir)/lib/extern/yoga/src/yoga \
|
||||
$(current_dir)/lib/extern/tinyxml2/ \
|
||||
$(addprefix $(current_dir)/lib/extern/switch-libpulsar/, $(PLSR_SOURCES))
|
||||
|
||||
INCLUDES := $(INCLUDES) \
|
||||
$(current_dir)/include \
|
||||
$(current_dir)/lib/extern/fmt/include \
|
||||
$(current_dir)/lib/extern/yoga/src \
|
||||
$(current_dir)/lib/extern/nanovg-deko3d/include \
|
||||
$(current_dir)/lib/extern/tweeny/include \
|
||||
$(current_dir)/include/borealis/extern \
|
||||
$(current_dir)/include/borealis/extern/tinyxml2 \
|
||||
$(addprefix $(current_dir)/lib/extern/switch-libpulsar/, $(PLSR_INCLUDES))
|
||||
|
||||
CXXFLAGS := $(CXXFLAGS) -DYG_ENABLE_EVENTS -fdata-sections -DBRLS_RESOURCES="\"romfs:/\""
|
||||
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
Copyright 2019-2021 natinusala
|
||||
Copyright 2019 p-sam
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
// Core
|
||||
#include <borealis/core/actions.hpp>
|
||||
#include <borealis/core/activity.hpp>
|
||||
#include <borealis/core/animation.hpp>
|
||||
#include <borealis/core/application.hpp>
|
||||
#include <borealis/core/assets.hpp>
|
||||
#include <borealis/core/audio.hpp>
|
||||
#include <borealis/core/bind.hpp>
|
||||
#include <borealis/core/box.hpp>
|
||||
#include <borealis/core/event.hpp>
|
||||
#include <borealis/core/font.hpp>
|
||||
#include <borealis/core/frame_context.hpp>
|
||||
#include <borealis/core/i18n.hpp>
|
||||
#include <borealis/core/input.hpp>
|
||||
#include <borealis/core/logger.hpp>
|
||||
#include <borealis/core/platform.hpp>
|
||||
#include <borealis/core/style.hpp>
|
||||
#include <borealis/core/task.hpp>
|
||||
#include <borealis/core/theme.hpp>
|
||||
#include <borealis/core/time.hpp>
|
||||
#include <borealis/core/timer.hpp>
|
||||
#include <borealis/core/video.hpp>
|
||||
#include <borealis/core/view.hpp>
|
||||
|
||||
//Views
|
||||
#include <borealis/views/applet_frame.hpp>
|
||||
#include <borealis/views/button.hpp>
|
||||
#include <borealis/views/header.hpp>
|
||||
#include <borealis/views/image.hpp>
|
||||
#include <borealis/views/label.hpp>
|
||||
#include <borealis/views/rectangle.hpp>
|
||||
#include <borealis/views/scrolling_frame.hpp>
|
||||
#include <borealis/views/sidebar.hpp>
|
||||
#include <borealis/views/tab_frame.hpp>
|
||||
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
Copyright 2020 WerWolv
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <borealis/core/audio.hpp>
|
||||
#include <borealis/core/input.hpp>
|
||||
#include <functional>
|
||||
#include <string>
|
||||
|
||||
namespace brls
|
||||
{
|
||||
|
||||
class View;
|
||||
|
||||
typedef std::function<bool(View*)> ActionListener;
|
||||
|
||||
typedef int ActionIdentifier;
|
||||
|
||||
#define ACTION_NONE -1
|
||||
|
||||
struct Action
|
||||
{
|
||||
enum ControllerButton button;
|
||||
|
||||
ActionIdentifier identifier;
|
||||
std::string hintText;
|
||||
bool available;
|
||||
bool hidden;
|
||||
enum Sound sound;
|
||||
ActionListener actionListener;
|
||||
|
||||
bool operator==(const enum ControllerButton other)
|
||||
{
|
||||
return this->button == other;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace brls
|
||||
@@ -0,0 +1,162 @@
|
||||
/*
|
||||
Copyright 2020 natinusala
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <borealis/core/view.hpp>
|
||||
|
||||
namespace brls
|
||||
{
|
||||
|
||||
#define CONTENT_FROM_XML_RES(x) \
|
||||
brls::View* createContentView() override { return brls::View::createFromXMLResource(x); }
|
||||
#define CONTENT_FROM_XML_FILE(x) \
|
||||
brls::View* createContentView() override { return brls::View::createFromXMLFile(x); }
|
||||
#define CONTENT_FROM_XML_STR(x) \
|
||||
brls::View* createContentView() override { return brls::View::createFromXMLString(x); }
|
||||
|
||||
// An activity is a "screen" of your app in which the library adds
|
||||
// the UI components. The app is made of a stack of activities, each activity
|
||||
// containing a views tree.
|
||||
class Activity
|
||||
{
|
||||
public:
|
||||
Activity();
|
||||
virtual ~Activity();
|
||||
|
||||
/**
|
||||
* Sets the content view of this activity, aka
|
||||
* the root view of the tree.
|
||||
*
|
||||
* When the activity is pushed, setContentView() is
|
||||
* automatically called with the result of createContentView().
|
||||
* As such, you should override createContentView() if you want
|
||||
* to use XML in your activity.
|
||||
*/
|
||||
void setContentView(View* view);
|
||||
|
||||
/**
|
||||
* Called when the activity is created. Should return the activity content view, if any.
|
||||
*
|
||||
* Returning nullptr means the content is not known when the activity is created.
|
||||
*
|
||||
* You can use View::createFromXMLFile(), View::createFromXMLResource() and View::createFromXMLString() to load
|
||||
* a view from respectively an XML file path, an XML name in the resources/xml romfs directory and an XML string.
|
||||
*
|
||||
* The CONTENT_FROM_XML_FILE, CONTENT_FROM_XML_RES, CONTENT_FROM_XML_STR macros
|
||||
* are made to make this process simpler: just use them in the public block of your activity
|
||||
* header and it will override createContentView() with the right code for you.
|
||||
*
|
||||
* The onContentAvailable() method will be called once the content has been created, so that
|
||||
* you can get the references to the activity views (by id).
|
||||
*/
|
||||
virtual View* createContentView();
|
||||
|
||||
/**
|
||||
* Called when the content view is created, so that
|
||||
* you can get the references to the activity views (by id).
|
||||
*/
|
||||
virtual void onContentAvailable() {};
|
||||
|
||||
View* getContentView();
|
||||
|
||||
/**
|
||||
* Returns the view with the corresponding id, or nullptr
|
||||
* if it hasn't been found in the activity.
|
||||
*/
|
||||
View* getView(std::string id);
|
||||
|
||||
/**
|
||||
* Resizes the activity to fit the window. Called when the activity
|
||||
* is created and when the window is resized (Switch dock counts as window resize).
|
||||
*/
|
||||
void resizeToFitWindow();
|
||||
|
||||
/**
|
||||
* Returns the duration of the activity show / hide animation.
|
||||
*/
|
||||
virtual float getShowAnimationDuration(TransitionAnimation animation);
|
||||
|
||||
/**
|
||||
* Is this activity translucent, aka can we see the
|
||||
* activities under it in the stack?
|
||||
*/
|
||||
bool isTranslucent();
|
||||
|
||||
void willAppear(bool resetState = false);
|
||||
void willDisappear(bool resetState = false);
|
||||
|
||||
/**
|
||||
* If set to true, will force the activity to be translucent.
|
||||
*/
|
||||
void setInFadeAnimation(bool translucent);
|
||||
|
||||
/**
|
||||
* Shows the activity with a fade in animation, or no animation at all.
|
||||
*/
|
||||
void show(std::function<void(void)> cb, bool animate, float animationDuration);
|
||||
|
||||
/**
|
||||
* Hides the activity with a fade in animation, or no animation at all.
|
||||
*/
|
||||
void hide(std::function<void(void)> cb, bool animate, float animationDuration);
|
||||
|
||||
bool isHidden();
|
||||
|
||||
/**
|
||||
* Registers an action with the given parameters on the content view. The listener will be fired
|
||||
* when the user presses the key.
|
||||
*
|
||||
* The listener should return true if the action was consumed, false otherwise.
|
||||
* The sound will only be played if the listener returned true.
|
||||
*
|
||||
* A hidden action will not show up in the bottom-right hints.
|
||||
*
|
||||
* Must be called after the content view is set.
|
||||
*
|
||||
* Returns the identifier for the action, so it can be unregistered later on. Returns ACTION_NONE if the
|
||||
* action was not registered.
|
||||
*/
|
||||
ActionIdentifier registerAction(std::string hintText, enum ControllerButton button, ActionListener actionListener, bool hidden = false, enum Sound sound = SOUND_NONE);
|
||||
|
||||
/**
|
||||
* Unregisters an action with the given identifier on the content view.
|
||||
*
|
||||
* Must be called after the content view is set.
|
||||
*/
|
||||
void unregisterAction(ActionIdentifier identifier);
|
||||
|
||||
/**
|
||||
* Registers an action to exit the application with the default button BUTTON_START.
|
||||
*
|
||||
* Must be called after the content view is set.
|
||||
*
|
||||
* Returns the identifier for the action, so it can be unregistered later on. Returns ACTION_NONE if the
|
||||
* action was not registered.
|
||||
*/
|
||||
ActionIdentifier registerExitAction(enum ControllerButton button = brls::BUTTON_START);
|
||||
|
||||
void onWindowSizeChanged();
|
||||
|
||||
View* getDefaultFocus();
|
||||
|
||||
void setAlpha(float alpha);
|
||||
|
||||
private:
|
||||
View* contentView = nullptr;
|
||||
};
|
||||
|
||||
} // namespace brls
|
||||
@@ -0,0 +1,104 @@
|
||||
/*
|
||||
Copyright 2021 natinusala
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <tweeny.h>
|
||||
|
||||
#include <borealis/core/time.hpp>
|
||||
|
||||
namespace brls
|
||||
{
|
||||
|
||||
using EasingFunction = tweeny::easing::enumerated;
|
||||
|
||||
// An animatable is a float which value can be animated from an initial value to a target value,
|
||||
// during a given amount of time. An easing function can also be specified.
|
||||
//
|
||||
// Declare the animatable and then use reset(initialValue) to reset the animation.
|
||||
// Add as many steps as you like by calling addStep(targetValue, duration, easing) one or multiple times.
|
||||
// Then, start and stop the animation with start() and stop().
|
||||
//
|
||||
// setEndCallback() and setTickCallback() allow you to execute code as long as the animation runs and / or once when it finishes.
|
||||
// Use .getValue() to get the current value at any time.
|
||||
//
|
||||
// An animatable has overloads for float conversion, comparison (==) and assignment operator (=) to allow
|
||||
// basic usage as a simple float. Assignment operator is a shortcut to the reset() method.
|
||||
class Animatable : public FiniteTicking
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Creates an animatable with the given initial value.
|
||||
*/
|
||||
Animatable(float value = 0.0f);
|
||||
|
||||
/**
|
||||
* Returns the current animatable value.
|
||||
*/
|
||||
float getValue();
|
||||
|
||||
/**
|
||||
* Stops and resets the animation, going back to the given initial value.
|
||||
* All steps are removed.
|
||||
* If an animation was already ongoing for that animatable, its end callback
|
||||
* will be called.
|
||||
*/
|
||||
void reset(float initialValue);
|
||||
|
||||
/**
|
||||
* Stops and resets the animation. The value will stay where it's at.
|
||||
* All steps are removed.
|
||||
* If an animation was already ongoing for that animatable, its end callback
|
||||
* will be called.
|
||||
*/
|
||||
void reset();
|
||||
|
||||
/**
|
||||
* Adds an animation step to the target value, lasting the specified duration in milliseconds.
|
||||
*
|
||||
* An animation can have multiple steps. Target value can be greater and lower than the previous step (it can go forwards or backwards).
|
||||
* Easing function is optional, default is EasingFunction::linear.
|
||||
*
|
||||
* Duration is int32_t due to internal limitations, so a step cannot last for longer than 2 147 483 647ms.
|
||||
* The sum of the duration of all steps cannot exceed 71582min.
|
||||
*/
|
||||
void addStep(float targetValue, int32_t duration, EasingFunction easing = EasingFunction::linear);
|
||||
|
||||
/**
|
||||
* Returns the progress of the animation between 0.0f and 1.0f.
|
||||
*/
|
||||
float getProgress();
|
||||
|
||||
operator float() const;
|
||||
operator float();
|
||||
void operator=(const float value);
|
||||
bool operator==(const float value);
|
||||
|
||||
protected:
|
||||
bool onUpdate(Time delta) override;
|
||||
|
||||
void onReset() override;
|
||||
void onRewind() override;
|
||||
|
||||
private:
|
||||
float currentValue = 0.0f;
|
||||
tweeny::tween<float> tween;
|
||||
};
|
||||
|
||||
void updateHighlightAnimation();
|
||||
void getHighlightAnimation(float* gradient_x, float* gradient_y, float* color);
|
||||
|
||||
} // namespace brls
|
||||
@@ -0,0 +1,246 @@
|
||||
/*
|
||||
Copyright 2019-2021 natinusala
|
||||
Copyright 2019 p-sam
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <nanovg.h>
|
||||
#include <tinyxml2.h>
|
||||
|
||||
#include <borealis/core/activity.hpp>
|
||||
#include <borealis/core/audio.hpp>
|
||||
#include <borealis/core/font.hpp>
|
||||
#include <borealis/core/frame_context.hpp>
|
||||
#include <borealis/core/logger.hpp>
|
||||
#include <borealis/core/platform.hpp>
|
||||
#include <borealis/core/style.hpp>
|
||||
#include <borealis/core/theme.hpp>
|
||||
#include <borealis/core/view.hpp>
|
||||
#include <borealis/views/label.hpp>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
namespace brls
|
||||
{
|
||||
|
||||
typedef std::function<View*(void)> XMLViewCreator;
|
||||
|
||||
class Application
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Inits the borealis application.
|
||||
* Returns true if it succeeded, false otherwise.
|
||||
*/
|
||||
static bool init();
|
||||
|
||||
/**
|
||||
* Creates the application window with the given title.
|
||||
* Must be called after calling init().
|
||||
*/
|
||||
static void createWindow(std::string title);
|
||||
|
||||
/**
|
||||
* Application main loop iteration.
|
||||
* Must be called in an infinite loop until it returns false.
|
||||
*/
|
||||
static bool mainLoop();
|
||||
|
||||
static Platform* getPlatform();
|
||||
static AudioPlayer* getAudioPlayer();
|
||||
|
||||
static NVGcontext* getNVGContext();
|
||||
inline static float contentWidth, contentHeight;
|
||||
|
||||
/**
|
||||
* Called by the video context when the content window is resized
|
||||
* and when the context is ready (to setup the initial content scaling).
|
||||
*/
|
||||
static void onWindowResized(int width, int height);
|
||||
|
||||
/**
|
||||
* Pushes a view on this applications's view stack.
|
||||
*
|
||||
* The view will automatically be resized to take
|
||||
* the whole screen.
|
||||
*
|
||||
* The view will gain focus if applicable.
|
||||
*
|
||||
* The first activity to be pushed cannot be popped.
|
||||
*/
|
||||
static void pushActivity(Activity* view, TransitionAnimation animation = TransitionAnimation::FADE);
|
||||
|
||||
/**
|
||||
* Pops the last pushed activity from the stack
|
||||
* and gives focus back where it was before.
|
||||
*/
|
||||
static void popActivity(
|
||||
TransitionAnimation animation = TransitionAnimation::FADE, std::function<void(void)> cb = [] {});
|
||||
|
||||
/**
|
||||
* Gives the focus to the given view
|
||||
* or clears the focus if given nullptr.
|
||||
*/
|
||||
static void giveFocus(View* view);
|
||||
|
||||
inline static Style getStyle()
|
||||
{
|
||||
return brls::getStyle();
|
||||
}
|
||||
|
||||
static Theme getTheme();
|
||||
static ThemeVariant getThemeVariant();
|
||||
|
||||
/**
|
||||
* Loads a font from a given file and stores it in the font stash.
|
||||
* Returns true if the operation succeeded.
|
||||
*/
|
||||
static bool loadFontFromFile(std::string fontName, std::string filePath);
|
||||
|
||||
/**
|
||||
* Loads a font from a given memory buffer and stores it in the font stash.
|
||||
* Returns true if the operation succeeded.
|
||||
*/
|
||||
static bool loadFontFromMemory(std::string fontName, void* data, size_t size, bool freeData);
|
||||
|
||||
/**
|
||||
* Returns the nanovg handle to the given font name, or FONT_INVALID if
|
||||
* no such font is currently loaded.
|
||||
*/
|
||||
static int getFont(std::string fontName);
|
||||
|
||||
static void notify(std::string text);
|
||||
|
||||
static void onControllerButtonPressed(enum ControllerButton button, bool repeating);
|
||||
|
||||
/**
|
||||
* "Crashes" the app (displays a fullscreen CrashFrame)
|
||||
*/
|
||||
static void crash(std::string text);
|
||||
|
||||
static void quit();
|
||||
|
||||
/**
|
||||
* Blocks any and all user inputs
|
||||
*/
|
||||
static void blockInputs();
|
||||
|
||||
/**
|
||||
* Unblocks inputs after a call to
|
||||
* blockInputs()
|
||||
*/
|
||||
static void unblockInputs();
|
||||
|
||||
static void setCommonFooter(std::string footer);
|
||||
static std::string* getCommonFooter();
|
||||
|
||||
static void setDisplayFramerate(bool enabled);
|
||||
static void toggleFramerateDisplay();
|
||||
|
||||
static void setMaximumFPS(unsigned fps);
|
||||
|
||||
inline static float windowScale;
|
||||
|
||||
/**
|
||||
* Sets whether BUTTON_START will globally be used to close the application.
|
||||
*/
|
||||
static void setGlobalQuit(bool enabled);
|
||||
|
||||
/**
|
||||
* Sets whether BUTTON_BACK will globally be used to toggle an FPS display.
|
||||
*/
|
||||
static void setGlobalFPSToggle(bool enabled);
|
||||
|
||||
static GenericEvent* getGlobalFocusChangeEvent();
|
||||
static VoidEvent* getGlobalHintsUpdateEvent();
|
||||
|
||||
static View* getCurrentFocus();
|
||||
|
||||
static std::string getTitle();
|
||||
|
||||
/**
|
||||
* Registers a view to be created from XML. You must give the name of the XML node as well
|
||||
* as a function that creates the view.
|
||||
*
|
||||
* If you need attributes, register them with the given functions in the view
|
||||
* class constructor directly. They will be called one by one after the view is instantiated.
|
||||
*
|
||||
* You should not add any children in the function, it is already taken care of.
|
||||
*/
|
||||
static void registerXMLView(std::string name, XMLViewCreator creator);
|
||||
|
||||
static bool XMLViewsRegisterContains(std::string name);
|
||||
static XMLViewCreator getXMLViewCreator(std::string name);
|
||||
|
||||
/**
|
||||
* Returns the current system locale.
|
||||
*/
|
||||
static std::string getLocale();
|
||||
|
||||
private:
|
||||
inline static bool inited = false;
|
||||
inline static bool quitRequested = false;
|
||||
|
||||
inline static Platform* platform = nullptr;
|
||||
|
||||
inline static std::string title;
|
||||
|
||||
inline static FontStash fontStash;
|
||||
|
||||
inline static std::vector<Activity*> activitiesStack;
|
||||
inline static std::vector<View*> focusStack;
|
||||
|
||||
inline static unsigned windowWidth, windowHeight;
|
||||
|
||||
inline static View* currentFocus;
|
||||
|
||||
inline static unsigned blockInputsTokens = 0; // any value > 0 means inputs are blocked
|
||||
|
||||
inline static std::string commonFooter = "";
|
||||
|
||||
inline static bool globalQuitEnabled = false;
|
||||
inline static ActionIdentifier gloablQuitIdentifier = ACTION_NONE;
|
||||
inline static bool globalFPSToggleEnabled = false;
|
||||
inline static ActionIdentifier gloablFPSToggleIdentifier = ACTION_NONE;
|
||||
|
||||
inline static View* repetitionOldFocus = nullptr;
|
||||
|
||||
inline static GenericEvent globalFocusChangeEvent;
|
||||
inline static VoidEvent globalHintsUpdateEvent;
|
||||
|
||||
inline static std::unordered_map<std::string, XMLViewCreator> xmlViewsRegister;
|
||||
|
||||
static void navigate(FocusDirection direction);
|
||||
|
||||
static void onWindowSizeChanged();
|
||||
|
||||
static void frame();
|
||||
static void clear();
|
||||
static void exit();
|
||||
|
||||
/**
|
||||
* Handles actions for the currently focused view and
|
||||
* the given button
|
||||
* Returns true if at least one action has been fired
|
||||
*/
|
||||
static bool handleAction(char button);
|
||||
|
||||
static void registerBuiltInXMLViews();
|
||||
|
||||
static ActionIdentifier registerFPSToggleAction(Activity* activity);
|
||||
};
|
||||
|
||||
} // namespace brls
|
||||
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
Copyright 2019-2021 natinusala
|
||||
Copyright 2019 p-sam
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef BRLS_RESOURCES
|
||||
#error BRLS_RESOURCES define missing
|
||||
#endif
|
||||
#define BRLS_ASSET(_str) BRLS_RESOURCES _str
|
||||
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
Copyright 2021 natinusala
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace brls
|
||||
{
|
||||
|
||||
enum Sound
|
||||
{
|
||||
SOUND_NONE = 0, // no sound
|
||||
|
||||
SOUND_FOCUS_CHANGE, // played when the focus changes
|
||||
SOUND_FOCUS_ERROR, // played when the user wants to go somewhere impossible (while the highlight wiggles)
|
||||
SOUND_CLICK, // played when the click action runs
|
||||
SOUND_FOCUS_SIDEBAR, // played when the focus changes to a sidebar item
|
||||
SOUND_CLICK_ERROR, // played when the user clicks a disabled button / a view focused with no click action
|
||||
SOUND_HONK, // honk
|
||||
SOUND_CLICK_SIDEBAR, // played when a sidebar item is clicked
|
||||
|
||||
_SOUND_MAX, // not an actual sound, just used to count of many sounds there are
|
||||
};
|
||||
|
||||
// Platform agnostic Audio player
|
||||
// Each platform's AudioPlayer is responsible for managing the enum Sound -> internal representation map
|
||||
class AudioPlayer
|
||||
{
|
||||
public:
|
||||
virtual ~AudioPlayer() {};
|
||||
|
||||
/**
|
||||
* Preemptively loads the given sound so that it's ready to be played
|
||||
* when needed.
|
||||
*
|
||||
* Returns a boolean indicating if the sound has been loaded or not.
|
||||
*/
|
||||
virtual bool load(enum Sound sound) = 0;
|
||||
|
||||
/**
|
||||
* Plays the given sound.
|
||||
*
|
||||
* The AudioPlayer should not assume that the sound has been
|
||||
* loaded already, and must load it if needed.
|
||||
*
|
||||
* Returns a boolean indicating if the sound has been played or not.
|
||||
*/
|
||||
virtual bool play(enum Sound sound) = 0;
|
||||
};
|
||||
|
||||
// An AudioPlayer that does nothing
|
||||
class NullAudioPlayer : public AudioPlayer
|
||||
{
|
||||
public:
|
||||
bool load(enum Sound sound) override
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool play(enum Sound sound) override
|
||||
{
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace brls
|
||||
@@ -0,0 +1,126 @@
|
||||
/*
|
||||
Copyright 2021 natinusala
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <borealis/core/activity.hpp>
|
||||
#include <borealis/core/view.hpp>
|
||||
|
||||
namespace brls
|
||||
{
|
||||
|
||||
// Exception thrown when using a BoundView with an unknown ID for
|
||||
// the given owner.
|
||||
class ViewNotFoundException : public std::exception
|
||||
{
|
||||
public:
|
||||
ViewNotFoundException(View* owner, std::string searchedId);
|
||||
ViewNotFoundException(Activity* owner, std::string searchedId);
|
||||
|
||||
const char* what() const noexcept;
|
||||
|
||||
private:
|
||||
std::string errorMessage;
|
||||
};
|
||||
|
||||
#define BRLS_BIND(type, name, id) brls::BoundView<type> name = brls::BoundView<type>(id, this)
|
||||
|
||||
// A BoundView represents a "child" view, bound to its "parent" view class.
|
||||
// Dereferencing operator has been overridden to directly resolve the view by ID and forward the call to the view pointer for you.
|
||||
// Allows easy access of child views inside the parent class when used with the BRLS_BIND macro.
|
||||
// Does NOT do any type check - it assumes the type you give it is the same as the view you are trying to get.
|
||||
template <typename T>
|
||||
class BoundView
|
||||
{
|
||||
public:
|
||||
BoundView(std::string id, View* owner)
|
||||
: id(id)
|
||||
, ownerView(owner)
|
||||
{
|
||||
}
|
||||
|
||||
BoundView(std::string id, Activity* owner)
|
||||
: id(id)
|
||||
, ownerActivity(owner)
|
||||
{
|
||||
}
|
||||
|
||||
T* getView()
|
||||
{
|
||||
this->resolve();
|
||||
return this->view;
|
||||
}
|
||||
|
||||
operator T*()
|
||||
{
|
||||
return this->getView();
|
||||
}
|
||||
|
||||
T* operator->()
|
||||
{
|
||||
return this->getView();
|
||||
}
|
||||
|
||||
bool operator==(const T* value)
|
||||
{
|
||||
return this->getView() == value;
|
||||
}
|
||||
|
||||
private:
|
||||
std::string id = "";
|
||||
|
||||
T* view = nullptr;
|
||||
|
||||
View* ownerView = nullptr;
|
||||
Activity* ownerActivity = nullptr;
|
||||
|
||||
/**
|
||||
* Resolve the view pointer by id.
|
||||
*
|
||||
* Not called in the constructor
|
||||
* on purpose because the owner might now be ready when
|
||||
* the BoundView is constructed, so wait for the first
|
||||
* actual call before resolving the view.
|
||||
*/
|
||||
void resolve()
|
||||
{
|
||||
if (this->view)
|
||||
return;
|
||||
|
||||
// Resolve by owner activity first
|
||||
if (this->ownerView)
|
||||
{
|
||||
this->view = (T*)this->ownerView->getView(this->id);
|
||||
|
||||
if (!this->view)
|
||||
throw ViewNotFoundException(this->ownerView, this->id);
|
||||
}
|
||||
// Then resolve by owner view
|
||||
else if (this->ownerActivity)
|
||||
{
|
||||
this->view = (T*)this->ownerActivity->getView(this->id);
|
||||
|
||||
if (!this->view)
|
||||
throw ViewNotFoundException(this->ownerActivity, this->id);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw std::logic_error("No owner view or activity given to BoundView");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace brls
|
||||
@@ -0,0 +1,280 @@
|
||||
/*
|
||||
Copyright 2020-2021 natinusala
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <borealis/core/view.hpp>
|
||||
|
||||
namespace brls
|
||||
{
|
||||
|
||||
enum class JustifyContent
|
||||
{
|
||||
FLEX_START,
|
||||
CENTER,
|
||||
FLEX_END,
|
||||
SPACE_BETWEEN,
|
||||
SPACE_AROUND,
|
||||
SPACE_EVENLY,
|
||||
};
|
||||
|
||||
enum class AlignItems
|
||||
{
|
||||
AUTO,
|
||||
FLEX_START,
|
||||
CENTER,
|
||||
FLEX_END,
|
||||
STRETCH,
|
||||
BASELINE,
|
||||
SPACE_BETWEEN,
|
||||
SPACE_AROUND,
|
||||
};
|
||||
|
||||
enum class Axis
|
||||
{
|
||||
ROW,
|
||||
COLUMN,
|
||||
};
|
||||
|
||||
enum class Direction
|
||||
{
|
||||
INHERIT,
|
||||
LEFT_TO_RIGHT,
|
||||
RIGHT_TO_LEFT,
|
||||
};
|
||||
|
||||
// Generic FlexBox layout
|
||||
class Box : public View
|
||||
{
|
||||
public:
|
||||
Box(Axis flexDirection);
|
||||
Box();
|
||||
|
||||
void draw(NVGcontext* vg, float x, float y, float width, float height, Style style, FrameContext* ctx) override;
|
||||
View* getDefaultFocus() override;
|
||||
View* getNextFocus(FocusDirection direction, View* currentView) override;
|
||||
void willAppear(bool resetState) override;
|
||||
void willDisappear(bool resetState) override;
|
||||
void onWindowSizeChanged() override;
|
||||
void onFocusGained() override;
|
||||
void onFocusLost() override;
|
||||
void onParentFocusGained(View* focusedView) override;
|
||||
void onParentFocusLost(View* focusedView) override;
|
||||
bool applyXMLAttribute(std::string name, std::string value) override;
|
||||
|
||||
static View* create();
|
||||
|
||||
/**
|
||||
* Adds a view to this Box.
|
||||
* Returns the position the view was added at.
|
||||
*/
|
||||
virtual void addView(View* view);
|
||||
|
||||
/**
|
||||
* Adds a view to this Box at the given position.
|
||||
* Returns the position the view was added at.
|
||||
*/
|
||||
virtual void addView(View* view, size_t position);
|
||||
|
||||
/**
|
||||
* Removes the given view from the Box. It will be freed.
|
||||
*/
|
||||
virtual void removeView(View* view);
|
||||
|
||||
/**
|
||||
* Sets the padding of the view, aka the internal space to give
|
||||
* between this view boundaries and its children.
|
||||
*
|
||||
* Only does one layout pass instead of four when using the four methods separately.
|
||||
*/
|
||||
virtual void setPadding(float padding);
|
||||
|
||||
/**
|
||||
* Sets the padding of the view, aka the internal space to give
|
||||
* between this view boundaries and its children.
|
||||
*
|
||||
* Only does one layout pass instead of four when using the four methods separately.
|
||||
*/
|
||||
virtual void setPadding(float top, float right, float bottom, float left);
|
||||
|
||||
/**
|
||||
* Sets the padding of the view, aka the internal space to give
|
||||
* between this view boundaries and its children.
|
||||
*/
|
||||
virtual void setPaddingTop(float top);
|
||||
|
||||
/**
|
||||
* Sets the padding of the view, aka the internal space to give
|
||||
* between this view boundaries and its children.
|
||||
*/
|
||||
virtual void setPaddingRight(float right);
|
||||
|
||||
/**
|
||||
* Sets the padding of the view, aka the internal space to give
|
||||
* between this view boundaries and its children.
|
||||
*/
|
||||
virtual void setPaddingBottom(float bottom);
|
||||
|
||||
/**
|
||||
* Sets the padding of the view, aka the internal space to give
|
||||
* between this view boundaries and its children.
|
||||
*/
|
||||
virtual void setPaddingLeft(float left);
|
||||
|
||||
/**
|
||||
* Sets the children alignment along the Box axis.
|
||||
*
|
||||
* Default is FLEX_START.
|
||||
*/
|
||||
void setJustifyContent(JustifyContent justify);
|
||||
|
||||
/**
|
||||
* Sets the children alignment along the Box cross axis.
|
||||
*
|
||||
* Default is AUTO.
|
||||
*/
|
||||
void setAlignItems(AlignItems alignment);
|
||||
|
||||
/**
|
||||
* Sets the direction of the box, aka place the views
|
||||
* left to right or right to left (flips the children).
|
||||
*
|
||||
* Default is INHERIT.
|
||||
*/
|
||||
void setDirection(Direction direction);
|
||||
|
||||
void setAxis(Axis axis);
|
||||
|
||||
std::vector<View*>& getChildren();
|
||||
|
||||
/**
|
||||
* Returns the bounds used for culling children.
|
||||
*/
|
||||
virtual void getCullingBounds(float* top, float* right, float* bottom, float* left);
|
||||
|
||||
/**
|
||||
* Registers an XML attribute to be forwarded to the given view. Works regardless of the target attribute type.
|
||||
* Useful to expose attributes of children views in the parent box without copy pasting them individually.
|
||||
*
|
||||
* The forwarded attribute value will override the value of the regular attribute if it already exists in the target view.
|
||||
*/
|
||||
void forwardXMLAttribute(std::string attributeName, View* target);
|
||||
|
||||
/**
|
||||
* Registers an XML attribute to be forwarded to the given view, while changing the target attribute name.
|
||||
* Works regardless of the target attribute type.
|
||||
* Useful to expose attributes of children views in the parent box without copy pasting them individually, but with a different name.
|
||||
*
|
||||
* The forwarded attribute value will override the value of the regular attribute if it already exists in the target view.
|
||||
*/
|
||||
void forwardXMLAttribute(std::string attributeName, View* target, std::string targetAttributeName);
|
||||
|
||||
/**
|
||||
* Fired when focus is gained on one of this view's children, or one of the children
|
||||
* of the children...
|
||||
*
|
||||
* directChild is guaranteed to be one of your children. It may not be the view that has been
|
||||
* focused.
|
||||
*
|
||||
* If focusedView == directChild, then the child of yours has been focused.
|
||||
* Otherwise, focusedView is a child of directChild.
|
||||
*/
|
||||
virtual void onChildFocusGained(View* directChild, View* focusedView);
|
||||
|
||||
/**
|
||||
* Fired when focus is lost on one of this view's children. Works similarly to
|
||||
* onChildFocusGained().
|
||||
*/
|
||||
virtual void onChildFocusLost(View* directChild, View* focusedView);
|
||||
|
||||
View* getView(std::string id) override;
|
||||
|
||||
private:
|
||||
Axis axis;
|
||||
|
||||
std::vector<View*> children;
|
||||
|
||||
size_t defaultFocusedIndex = 0;
|
||||
|
||||
std::unordered_map<std::string, std::pair<std::string, View*>> forwardedAttributes;
|
||||
|
||||
protected:
|
||||
/**
|
||||
* Inflates the Box with the given XML string.
|
||||
*
|
||||
* The root element MUST be a brls::Box, corresponding to the inflated Box itself. Its
|
||||
* attributes will be applied to the Box.
|
||||
*
|
||||
* Each child node in the root brls::Box will be treated as a view and added
|
||||
* as a child of the Box.
|
||||
*/
|
||||
void inflateFromXMLString(std::string xml);
|
||||
|
||||
/**
|
||||
* Inflates the Box with the given XML element.
|
||||
*
|
||||
* The root element MUST be a brls::Box, corresponding to the inflated Box itself. Its
|
||||
* attributes will be applied to the Box.
|
||||
*
|
||||
* Each child node in the root brls::Box will be treated as a view and added
|
||||
* as a child of the Box.
|
||||
*/
|
||||
void inflateFromXMLElement(tinyxml2::XMLElement* element);
|
||||
|
||||
/**
|
||||
* Inflates the Box with the given XML resource.
|
||||
*
|
||||
* The root element MUST be a brls::Box, corresponding to the inflated Box itself. Its
|
||||
* attributes will be applied to the Box.
|
||||
*
|
||||
* Each child node in the root brls::Box will be treated as a view and added
|
||||
* as a child of the Box.
|
||||
*/
|
||||
void inflateFromXMLRes(std::string res);
|
||||
|
||||
/**
|
||||
* Inflates the Box with the given XML file path.
|
||||
*
|
||||
* The root element MUST be a brls::Box, corresponding to the inflated Box itself. Its
|
||||
* attributes will be applied to the Box.
|
||||
*
|
||||
* Each child node in the root brls::Box will be treated as a view and added
|
||||
* as a child of the Box.
|
||||
*/
|
||||
void inflateFromXMLFile(std::string path);
|
||||
|
||||
/**
|
||||
* Handles a child XML element.
|
||||
*
|
||||
* By default, calls createFromXMLElement() and adds the result
|
||||
* to the children of the Box.
|
||||
*/
|
||||
void handleXMLElement(tinyxml2::XMLElement* element) override;
|
||||
};
|
||||
|
||||
// An empty view that has auto x auto and grow=1.0 to push
|
||||
// all the next views in its box to the right (or to the bottom)
|
||||
class Padding : public View
|
||||
{
|
||||
public:
|
||||
Padding();
|
||||
|
||||
void draw(NVGcontext* vg, float x, float y, float width, float height, Style style, FrameContext* ctx) override;
|
||||
|
||||
static View* create();
|
||||
};
|
||||
|
||||
} // namespace brls
|
||||
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
Copyright 2020 natinusala
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <algorithm>
|
||||
#include <functional>
|
||||
#include <list>
|
||||
|
||||
namespace brls
|
||||
{
|
||||
|
||||
// Simple observer pattern implementation
|
||||
//
|
||||
// Usage:
|
||||
// 1. typedef your event type
|
||||
// 2. create as many events as you want using that type
|
||||
// 3. call subscribe on the events with your observers
|
||||
// 4. call fire when you want to fire the events
|
||||
// it wil return true if at least one subscriber exists
|
||||
// for that event
|
||||
template <typename... Ts>
|
||||
class Event
|
||||
{
|
||||
public:
|
||||
typedef std::function<void(Ts...)> Callback;
|
||||
typedef std::list<Callback> CallbacksList;
|
||||
typedef typename CallbacksList::iterator Subscription;
|
||||
|
||||
Subscription subscribe(Callback cb);
|
||||
void unsubscribe(Subscription subscription);
|
||||
bool fire(Ts... args);
|
||||
|
||||
private:
|
||||
CallbacksList callbacks;
|
||||
};
|
||||
|
||||
template <typename... Ts>
|
||||
typename Event<Ts...>::Subscription Event<Ts...>::subscribe(Event<Ts...>::Callback cb)
|
||||
{
|
||||
this->callbacks.push_back(cb);
|
||||
return --this->callbacks.end();
|
||||
}
|
||||
|
||||
template <typename... Ts>
|
||||
void Event<Ts...>::unsubscribe(Event<Ts...>::Subscription subscription)
|
||||
{
|
||||
this->callbacks.erase(subscription);
|
||||
}
|
||||
|
||||
template <typename... Ts>
|
||||
bool Event<Ts...>::fire(Ts... args)
|
||||
{
|
||||
for (Callback cb : this->callbacks)
|
||||
cb(args...);
|
||||
|
||||
return !this->callbacks.empty();
|
||||
}
|
||||
|
||||
}; // namespace brls
|
||||
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
Copyright 2021 natinusala
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
|
||||
namespace brls
|
||||
{
|
||||
|
||||
static constexpr const int FONT_INVALID = -1;
|
||||
|
||||
static const std::string FONT_REGULAR = "regular"; // regular Latin font
|
||||
static const std::string FONT_KOREAN_REGULAR = "korean"; // regular Korean font
|
||||
static const std::string FONT_MATERIAL_ICONS = "material"; // Material icons font
|
||||
static const std::string FONT_SWITCH_ICONS = "switch"; // Switch icons font (see the HOS shared symbols font for an example)
|
||||
|
||||
typedef std::unordered_map<std::string, int> FontStash;
|
||||
|
||||
// Platform interface to load fonts from disk or other sources (system / shared font...)
|
||||
class FontLoader
|
||||
{
|
||||
public:
|
||||
virtual ~FontLoader() {}
|
||||
/**
|
||||
* Called once on init to load every font in the font stash.
|
||||
*
|
||||
* The implementation must use the Application::loadFont and
|
||||
* Application::loadFontFromMemory methods to load as much as possible
|
||||
* of the "built-in" fonts defined in the FONT_* constants above.
|
||||
*/
|
||||
virtual void loadFonts() = 0;
|
||||
|
||||
protected:
|
||||
/**
|
||||
* Convenience method to load a font from a file path
|
||||
* with some more logging.
|
||||
*/
|
||||
bool loadFontFromFile(std::string fontName, std::string filePath);
|
||||
|
||||
/**
|
||||
* Can be called internally to load the Material icons font from resources.
|
||||
* Returns true if the operation succeeds.
|
||||
*/
|
||||
bool loadMaterialFromResources();
|
||||
};
|
||||
|
||||
} // namespace brls
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
Copyright 2019 natinusala
|
||||
Copyright 2019 psam
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <nanovg.h>
|
||||
|
||||
#include <borealis/core/font.hpp>
|
||||
#include <borealis/core/style.hpp>
|
||||
#include <borealis/core/theme.hpp>
|
||||
|
||||
namespace brls
|
||||
{
|
||||
|
||||
class FrameContext
|
||||
{
|
||||
public:
|
||||
NVGcontext* vg = nullptr;
|
||||
float pixelRatio = 0.0;
|
||||
FontStash* fontStash = nullptr;
|
||||
Theme theme = nullptr;
|
||||
};
|
||||
|
||||
} // namespace brls
|
||||
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
Copyright 2020-2021 natinusala
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <fmt/core.h>
|
||||
|
||||
#include <borealis/core/logger.hpp>
|
||||
#include <string>
|
||||
|
||||
namespace brls
|
||||
{
|
||||
|
||||
const std::string LOCALE_JA = "ja";
|
||||
const std::string LOCALE_EN_US = "en-US";
|
||||
const std::string LOCALE_EN_GB = "en-GB";
|
||||
const std::string LOCALE_FR = "fr";
|
||||
const std::string LOCALE_FR_CA = "fr-CA";
|
||||
const std::string LOCALE_DE = "de";
|
||||
const std::string LOCALE_IT = "it";
|
||||
const std::string LOCALE_ES = "es";
|
||||
const std::string LOCALE_ZH_CN = "zh-CN";
|
||||
const std::string LOCALE_ZH_HANS = "zh-Hans";
|
||||
const std::string LOCALE_ZH_HANT = "zh-Hant";
|
||||
const std::string LOCALE_ZH_TW = "zh-TW";
|
||||
const std::string LOCALE_Ko = "ko";
|
||||
const std::string LOCALE_NL = "nl";
|
||||
const std::string LOCALE_PT = "pt";
|
||||
const std::string LOCALE_PT_BR = "pt-BR";
|
||||
const std::string LOCALE_RU = "ru";
|
||||
const std::string LOCALE_ES_419 = "es-419";
|
||||
|
||||
const std::string LOCALE_DEFAULT = LOCALE_EN_US;
|
||||
|
||||
namespace internal
|
||||
{
|
||||
std::string getRawStr(std::string stringName);
|
||||
} // namespace internal
|
||||
|
||||
/**
|
||||
* Returns the translation for the given string,
|
||||
* after injecting format parameters (if any)
|
||||
*/
|
||||
template <typename... Args>
|
||||
std::string getStr(std::string stringName, Args&&... args)
|
||||
{
|
||||
std::string rawStr = internal::getRawStr(stringName);
|
||||
|
||||
try
|
||||
{
|
||||
return fmt::format(rawStr, args...);
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
Logger::error("Invalid format \"{}\" from string \"{}\": {}", rawStr, stringName, e.what());
|
||||
return stringName;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads all translations of the current system locale + default locale
|
||||
* Must be called before trying to get a translation!
|
||||
*/
|
||||
void loadTranslations();
|
||||
|
||||
inline namespace literals
|
||||
{
|
||||
/**
|
||||
* Returns the translation for the given string, without
|
||||
* injecting any parameters
|
||||
* Shortcut to brls::getStr(stringName)
|
||||
*/
|
||||
std::string operator"" _i18n(const char* str, size_t len);
|
||||
} // namespace literals
|
||||
} // namespace brls
|
||||
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
Copyright 2021 natinusala
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace brls
|
||||
{
|
||||
|
||||
// Abstract buttons enum - names correspond to a generic Xbox controller
|
||||
// LT and RT should not be buttons but for the sake of simplicity we'll assume they are.
|
||||
// Similarly, DPAD (also called HAT) is assumed to be buttons here.
|
||||
enum ControllerButton
|
||||
{
|
||||
BUTTON_LT = 0,
|
||||
BUTTON_LB,
|
||||
|
||||
BUTTON_LSB,
|
||||
|
||||
BUTTON_UP,
|
||||
BUTTON_RIGHT,
|
||||
BUTTON_DOWN,
|
||||
BUTTON_LEFT,
|
||||
|
||||
BUTTON_BACK,
|
||||
BUTTON_GUIDE,
|
||||
BUTTON_START,
|
||||
|
||||
BUTTON_RSB,
|
||||
|
||||
BUTTON_Y,
|
||||
BUTTON_B,
|
||||
BUTTON_A,
|
||||
BUTTON_X,
|
||||
|
||||
BUTTON_RB,
|
||||
BUTTON_RT,
|
||||
|
||||
_BUTTON_MAX,
|
||||
};
|
||||
|
||||
// Abstract axis enum - names correspond to a generic Xbox controller
|
||||
enum ControllerAxis
|
||||
{
|
||||
LEFT_X,
|
||||
LEFT_Y,
|
||||
|
||||
// No Z axis, LT and RT are in the buttons enum for the sake of simplicity
|
||||
|
||||
RIGHT_X, // also called 5th axis
|
||||
RIGHT_Y, // also called 4th axis
|
||||
|
||||
_AXES_MAX,
|
||||
};
|
||||
|
||||
// Represents the state of the controller (a gamepad or a keyboard) in the current frame
|
||||
typedef struct ControllerState
|
||||
{
|
||||
bool buttons[_BUTTON_MAX]; // true: pressed
|
||||
float axes[_AXES_MAX]; // from 0.0f to 1.0f
|
||||
} ControllerState;
|
||||
|
||||
// Interface responsible for reporting input state to the application - button presses,
|
||||
// axis position and touch screen state
|
||||
class InputManager
|
||||
{
|
||||
public:
|
||||
virtual ~InputManager() {}
|
||||
|
||||
/**
|
||||
* Called once every frame to fill the given ControllerState struct with the controller state.
|
||||
*/
|
||||
virtual void updateControllerState(ControllerState* state) = 0;
|
||||
};
|
||||
|
||||
}; // namespace brls
|
||||
@@ -0,0 +1,91 @@
|
||||
/*
|
||||
Copyright 2019 natinusala
|
||||
Copyright 2019 p-sam
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <fmt/core.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace brls
|
||||
{
|
||||
|
||||
enum class LogLevel
|
||||
{
|
||||
ERROR = 0,
|
||||
WARNING,
|
||||
INFO,
|
||||
DEBUG
|
||||
};
|
||||
|
||||
class Logger
|
||||
{
|
||||
public:
|
||||
static void setLogLevel(LogLevel logLevel);
|
||||
|
||||
template <typename... Args>
|
||||
inline static void log(LogLevel logLevel, std::string prefix, std::string color, std::string format, Args&&... args)
|
||||
{
|
||||
if (Logger::logLevel < logLevel)
|
||||
return;
|
||||
|
||||
try
|
||||
{
|
||||
fmt::print("\033{}[{}]\033[0m ", color, prefix);
|
||||
fmt::print(format, args...);
|
||||
fmt::print("\n");
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
// will be printed after the first fmt::print (so after the log tag)
|
||||
printf("! Invalid log format string: \"%s\": %s\n", format.c_str(), e.what());
|
||||
}
|
||||
|
||||
#ifdef __MINGW32__
|
||||
fflush(0);
|
||||
#endif
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
inline static void error(std::string format, Args&&... args)
|
||||
{
|
||||
Logger::log(LogLevel::ERROR, "ERROR", "[0;31m", format, args...);
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
inline static void warning(std::string format, Args&&... args)
|
||||
{
|
||||
Logger::log(LogLevel::WARNING, "WARNING", "[0;33m", format, args...);
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
inline static void info(std::string format, Args&&... args)
|
||||
{
|
||||
Logger::log(LogLevel::INFO, "INFO", "[0;34m", format, args...);
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
inline static void debug(std::string format, Args&&... args)
|
||||
{
|
||||
Logger::log(LogLevel::DEBUG, "DEBUG", "[0;32m", format, args...);
|
||||
}
|
||||
|
||||
private:
|
||||
inline static LogLevel logLevel = LogLevel::INFO;
|
||||
};
|
||||
|
||||
} // namespace brls
|
||||
@@ -0,0 +1,106 @@
|
||||
/*
|
||||
Copyright 2021 natinusala
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <borealis/core/audio.hpp>
|
||||
#include <borealis/core/font.hpp>
|
||||
#include <borealis/core/input.hpp>
|
||||
#include <borealis/core/theme.hpp>
|
||||
#include <borealis/core/video.hpp>
|
||||
#include <string>
|
||||
|
||||
namespace brls
|
||||
{
|
||||
|
||||
// Interface to provide everything platform specific required to run borealis: graphics context, inputs, audio...
|
||||
// The best platform is automatically selected when the application starts, and cannot be changed by the user at the moment
|
||||
class Platform
|
||||
{
|
||||
public:
|
||||
virtual ~Platform() {};
|
||||
|
||||
/**
|
||||
* Called on startup, right after instanciation, to create and open a window
|
||||
* with the given title and size.
|
||||
*/
|
||||
virtual void createWindow(std::string title, uint32_t width, uint32_t height) = 0;
|
||||
|
||||
/**
|
||||
* Returns the human-readable name of the platform.
|
||||
*/
|
||||
virtual std::string getName() = 0;
|
||||
|
||||
/**
|
||||
* Called at every iteration of the main loop.
|
||||
* Must return false if the app should continue running
|
||||
* (for example, return false if the X button was pressed on the window).
|
||||
*/
|
||||
virtual bool mainLoopIteration() = 0;
|
||||
|
||||
/**
|
||||
* Can be called at anytime to get the current system theme variant.
|
||||
*
|
||||
* For now, the variant is assumed to stay the same during the whole time
|
||||
* the app is running (no variant hot swap).
|
||||
*
|
||||
* As such, the result should be cached by the platform code.
|
||||
*/
|
||||
virtual ThemeVariant getThemeVariant() = 0;
|
||||
|
||||
/**
|
||||
* Can be called at anytime to get the current locale
|
||||
*
|
||||
* For now, the locale is assumed to stay the same during the whole time
|
||||
* the app is running (no locale hot swap)
|
||||
*
|
||||
* As such, the result should be cached by the platform code.
|
||||
* The method should return one of the locale constants
|
||||
* defined in the i18n header file.
|
||||
*/
|
||||
virtual std::string getLocale() = 0;
|
||||
|
||||
/**
|
||||
* Returns the AudioPlayer for the platform.
|
||||
* Cannot return nullptr.
|
||||
*/
|
||||
virtual AudioPlayer* getAudioPlayer() = 0;
|
||||
|
||||
/**
|
||||
* Returns the VideoContext for the platform.
|
||||
* Cannot return nullptr.
|
||||
*/
|
||||
virtual VideoContext* getVideoContext() = 0;
|
||||
|
||||
/**
|
||||
* Returns the InputManager for the platform.
|
||||
* Cannot return nullptr.
|
||||
*/
|
||||
virtual InputManager* getInputManager() = 0;
|
||||
|
||||
/**
|
||||
* Returns the FontLoader for the platform.
|
||||
* Cannot return nullptr.
|
||||
*/
|
||||
virtual FontLoader* getFontLoader() = 0;
|
||||
|
||||
/**
|
||||
* Selects and returns the best platform.
|
||||
*/
|
||||
static Platform* createPlatform();
|
||||
};
|
||||
|
||||
} // namespace brls
|
||||
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
Copyright 2019-2020 natinusala
|
||||
Copyright 2019 WerWolv
|
||||
Copyright 2019 p-sam
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <initializer_list>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
|
||||
namespace brls
|
||||
{
|
||||
|
||||
class StyleValues
|
||||
{
|
||||
public:
|
||||
StyleValues(std::initializer_list<std::pair<std::string, float>> list);
|
||||
|
||||
void addMetric(std::string name, float value);
|
||||
float getMetric(std::string name);
|
||||
|
||||
private:
|
||||
std::unordered_map<std::string, float> values;
|
||||
};
|
||||
|
||||
// Simple wrapper around StyleValues for the array operator
|
||||
class Style
|
||||
{
|
||||
public:
|
||||
Style(StyleValues* values);
|
||||
float operator[](std::string name);
|
||||
|
||||
void addMetric(std::string name, float value);
|
||||
float getMetric(std::string name);
|
||||
|
||||
private:
|
||||
StyleValues* values;
|
||||
};
|
||||
|
||||
Style getStyle();
|
||||
|
||||
} // namespace brls
|
||||
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
Copyright 2021 natinusala
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <borealis/core/timer.hpp>
|
||||
|
||||
namespace brls
|
||||
{
|
||||
|
||||
// A RepeatingTask is a task executed repeatedly on the main thread at a given period in ms
|
||||
class RepeatingTask : private RepeatingTimer
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Create a RepeatingTask with the given period in ms.
|
||||
*
|
||||
* The task is guaranteed to wait for at least the given period of time between
|
||||
* handler runs, but it can wait for slightly longer (usually less than a ms late)
|
||||
*/
|
||||
RepeatingTask(Time period);
|
||||
|
||||
/**
|
||||
* Task handler executed repeatedly on the main thread at the given period.
|
||||
*/
|
||||
virtual void run() = 0;
|
||||
|
||||
/**
|
||||
* Starts the task.
|
||||
*/
|
||||
void start();
|
||||
|
||||
/**
|
||||
* Stops the task.
|
||||
*/
|
||||
void stop();
|
||||
};
|
||||
} // namespace brls
|
||||
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
Copyright 2019-2020 natinusala
|
||||
Copyright 2019 p-sam
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <nanovg.h>
|
||||
|
||||
#include <initializer_list>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
|
||||
namespace brls
|
||||
{
|
||||
|
||||
enum class ThemeVariant
|
||||
{
|
||||
LIGHT,
|
||||
DARK
|
||||
};
|
||||
|
||||
class ThemeValues
|
||||
{
|
||||
public:
|
||||
ThemeValues(std::initializer_list<std::pair<std::string, NVGcolor>> list);
|
||||
|
||||
void addColor(std::string name, NVGcolor color);
|
||||
NVGcolor getColor(std::string name);
|
||||
|
||||
private:
|
||||
std::unordered_map<std::string, NVGcolor> values;
|
||||
};
|
||||
|
||||
// Simple wrapper around ThemeValues for the array operator
|
||||
class Theme
|
||||
{
|
||||
public:
|
||||
Theme(ThemeValues* values);
|
||||
NVGcolor operator[](std::string name);
|
||||
|
||||
void addColor(std::string name, NVGcolor color);
|
||||
NVGcolor getColor(std::string name);
|
||||
|
||||
private:
|
||||
ThemeValues* values;
|
||||
};
|
||||
|
||||
Theme getLightTheme();
|
||||
Theme getDarkTheme();
|
||||
|
||||
} // namespace brls
|
||||
@@ -0,0 +1,157 @@
|
||||
/*
|
||||
Copyright 2021 natinusala
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <libretro-common/features/features_cpu.h>
|
||||
#include <libretro-common/libretro.h>
|
||||
|
||||
#include <functional>
|
||||
#include <vector>
|
||||
|
||||
namespace brls
|
||||
{
|
||||
|
||||
typedef retro_time_t Time;
|
||||
|
||||
/**
|
||||
* Returns the current CPU time in microseconds.
|
||||
*/
|
||||
inline Time getCPUTimeUsec()
|
||||
{
|
||||
return cpu_features_get_time_usec();
|
||||
}
|
||||
|
||||
typedef std::function<void()> TickingGenericCallback;
|
||||
|
||||
typedef std::function<void(bool)> TickingEndCallback;
|
||||
typedef TickingGenericCallback TickingTickCallback;
|
||||
|
||||
// Interface representing something that "ticks" every frame for a certain amount of frames,
|
||||
// like a timer, an animation, a background task...
|
||||
// The library manages a list of running tickings. Each ticking is reponsible for managing its own
|
||||
// lifetime by returning true or false in onUpdate.
|
||||
class Ticking
|
||||
{
|
||||
public:
|
||||
virtual ~Ticking();
|
||||
|
||||
/**
|
||||
* Starts the ticking, pushing it to the list of running tickings.
|
||||
* If the ticking is finished, it will be restarted.
|
||||
* If the ticking is already running, this method will have no effect.
|
||||
*/
|
||||
void start();
|
||||
|
||||
/**
|
||||
* Stops the ticking if it was running, and executes the end callback.
|
||||
*/
|
||||
void stop();
|
||||
|
||||
/**
|
||||
* Sets a callback to be executed when the
|
||||
* ticking finishes.
|
||||
* The callback argument will be set to true if the ticking stopped
|
||||
* on its own, false if it was stopped early by the user.
|
||||
*/
|
||||
void setEndCallback(TickingEndCallback endCallback);
|
||||
|
||||
/**
|
||||
* Sets a callback to be executed at every tick
|
||||
* until the ticking finishes.
|
||||
*
|
||||
* The last animation tick will execute the tick callback
|
||||
* then the end callback.
|
||||
*/
|
||||
void setTickCallback(TickingTickCallback tickCallback);
|
||||
|
||||
/**
|
||||
* Returns true if the ticking is currently running.
|
||||
*/
|
||||
bool isRunning();
|
||||
|
||||
/**
|
||||
* Called internally by the main loop. Takes all running tickings
|
||||
* and updates them.
|
||||
*/
|
||||
static void updateTickings();
|
||||
|
||||
inline static std::vector<Ticking*> runningTickings;
|
||||
|
||||
protected:
|
||||
/**
|
||||
* Executed every frame while the ticking lives.
|
||||
* Delta is the time difference in ms between the last frame
|
||||
* and the current one.
|
||||
* Must return false if the ticking is finished and should be
|
||||
* removed from the list of active tickings.
|
||||
* The end callback will automatically be called then.
|
||||
*/
|
||||
virtual bool onUpdate(Time delta) = 0;
|
||||
|
||||
/**
|
||||
* Called when the ticking becomes active.
|
||||
*/
|
||||
virtual void onStart() {};
|
||||
|
||||
/**
|
||||
* Called when the ticking is stopped, either by the user
|
||||
* or because it finished.
|
||||
*/
|
||||
virtual void onStop() {};
|
||||
|
||||
private:
|
||||
void stop(bool finished);
|
||||
|
||||
bool running = false;
|
||||
|
||||
TickingEndCallback endCallback = [](bool finished) {};
|
||||
TickingTickCallback tickCallback = [] {};
|
||||
};
|
||||
|
||||
// Represents a "finite" ticking that runs for a known amount of time
|
||||
// and can be seek / reset / rewound.
|
||||
class FiniteTicking : public Ticking
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Rewinds the ticking to go back to the beginning
|
||||
* without losing its state (as opposed to reset() that clears
|
||||
* everything in the ticking).
|
||||
* Does not start or stop it.
|
||||
*/
|
||||
void rewind();
|
||||
|
||||
/**
|
||||
* Stops and resets the ticking, clearing its state
|
||||
* in the process (as opposed to rewind() that just restarts
|
||||
* the ticking from the beginning without losing the state).
|
||||
*/
|
||||
void reset();
|
||||
|
||||
protected:
|
||||
/**
|
||||
* Called when the ticking gets rewound.
|
||||
*/
|
||||
virtual void onRewind() {};
|
||||
|
||||
/**
|
||||
* Called when the ticking gets reset.
|
||||
*/
|
||||
virtual void onReset() {};
|
||||
};
|
||||
|
||||
} // namespace brls
|
||||
@@ -0,0 +1,93 @@
|
||||
/*
|
||||
Copyright 2021 natinusala
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <borealis/core/time.hpp>
|
||||
|
||||
namespace brls
|
||||
{
|
||||
|
||||
// A Timer allows to run a callback once after a given period of time, in ms
|
||||
// Add the callback with setEndCallback(), set the duration with setDuration() then start the timer
|
||||
class Timer : public FiniteTicking
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Starts the timer directly with a given duration, in ms.
|
||||
*/
|
||||
void start(Time duration);
|
||||
|
||||
/**
|
||||
* Starts the timer with the already set duration.
|
||||
*/
|
||||
void start();
|
||||
|
||||
/**
|
||||
* Sets the duration of the timer, in ms.
|
||||
* Does not stop or reset it.
|
||||
*/
|
||||
void setDuration(Time duration);
|
||||
|
||||
void onStart() override;
|
||||
bool onUpdate(Time delta) override;
|
||||
void onReset() override;
|
||||
void onRewind() override;
|
||||
|
||||
protected:
|
||||
Time duration = 0;
|
||||
Time progress = 0;
|
||||
};
|
||||
|
||||
// A RepeatingTimer allows to run a callback repeatedly at a given time interval, in ms
|
||||
// Add the callback with setCallback(), set the period with setPeriod() then start the timer
|
||||
class RepeatingTimer : public Ticking
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Starts the timer directly with a given period, in ms.
|
||||
*/
|
||||
void start(Time period);
|
||||
|
||||
/**
|
||||
* Starts the timer with the already set period.
|
||||
*/
|
||||
void start();
|
||||
|
||||
/**
|
||||
* Sets the period of the timer, in ms.
|
||||
* Does not stop or reset it.
|
||||
*/
|
||||
void setPeriod(Time period);
|
||||
|
||||
/**
|
||||
* Sets the callback of the timer.
|
||||
* Tick callback is still executed every tick.
|
||||
* End callback is executed when the timer is stopped.
|
||||
*/
|
||||
void setCallback(TickingGenericCallback callback);
|
||||
|
||||
void onStart() override;
|
||||
bool onUpdate(Time delta) override;
|
||||
|
||||
protected:
|
||||
Time period = 0;
|
||||
Time progress = 0;
|
||||
|
||||
TickingGenericCallback callback = [] {};
|
||||
};
|
||||
|
||||
} // namespace brls
|
||||
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
Copyright 2021 natinusala
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <borealis/core/logger.hpp>
|
||||
#include <stdexcept>
|
||||
|
||||
namespace brls
|
||||
{
|
||||
|
||||
/**
|
||||
* Prints the given error message message and throws a std::logic_error.
|
||||
*/
|
||||
[[noreturn]] void fatal(std::string message);
|
||||
|
||||
} // namespace brls
|
||||
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
Copyright 2021 natinusala
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <nanovg.h>
|
||||
|
||||
// A VideoContext is responsible for providing a nanovg context for the app
|
||||
// (so by extension it manages all the graphics state as well as the window / context).
|
||||
// The VideoContext implementation must also provide the nanovg implementation. As such, there
|
||||
// can only be one VideoContext linked at any time in the binary.
|
||||
// Context creation and teardown can be done in the constructor and destructor.
|
||||
class VideoContext
|
||||
{
|
||||
public:
|
||||
virtual ~VideoContext() {};
|
||||
|
||||
/**
|
||||
* Called at the beginning of every frame to clear the window
|
||||
*/
|
||||
virtual void clear(NVGcolor color) = 0;
|
||||
|
||||
/**
|
||||
* Called at the beginning of every frame to begin it.
|
||||
*/
|
||||
virtual void beginFrame() = 0;
|
||||
|
||||
/**
|
||||
* Called at the end of every frame to end it (swap buffers...).
|
||||
*/
|
||||
virtual void endFrame() = 0;
|
||||
|
||||
/**
|
||||
* Can be called by the application to reset the graphics
|
||||
* state, in case there is a need to use the graphics API
|
||||
* directly (for instance direct OpenGL calls).
|
||||
*/
|
||||
virtual void resetState() = 0;
|
||||
|
||||
virtual NVGcontext* getNVGContext() = 0;
|
||||
};
|
||||
3274
Source/Benchmark-Toolbox/lib/borealis/library/include/borealis/extern/glad/glad.h
vendored
Normal file
39
Source/Benchmark-Toolbox/lib/borealis/library/include/borealis/extern/libretro-common/boolean.h
vendored
Normal file
@@ -0,0 +1,39 @@
|
||||
/* Copyright (C) 2010-2018 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (boolean.h).
|
||||
* ---------------------------------------------------------------------------------------
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef __LIBRETRO_SDK_BOOLEAN_H
|
||||
#define __LIBRETRO_SDK_BOOLEAN_H
|
||||
|
||||
#ifndef __cplusplus
|
||||
|
||||
#if defined(_MSC_VER) && _MSC_VER < 1800 && !defined(SN_TARGET_PS3)
|
||||
/* Hack applied for MSVC when compiling in C89 mode as it isn't C99 compliant. */
|
||||
#define bool unsigned char
|
||||
#define true 1
|
||||
#define false 0
|
||||
#else
|
||||
#include <stdbool.h>
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,59 @@
|
||||
/* Copyright (C) 2010-2018 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (strl.h).
|
||||
* ---------------------------------------------------------------------------------------
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef __LIBRETRO_SDK_COMPAT_STRL_H
|
||||
#define __LIBRETRO_SDK_COMPAT_STRL_H
|
||||
|
||||
#include <string.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#if defined(RARCH_INTERNAL) && defined(HAVE_CONFIG_H)
|
||||
#include "../../../config.h"
|
||||
#endif
|
||||
|
||||
#include <libretro-common/retro_common_api.h>
|
||||
|
||||
RETRO_BEGIN_DECLS
|
||||
|
||||
#ifdef __MACH__
|
||||
#ifndef HAVE_STRL
|
||||
#define HAVE_STRL
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_STRL
|
||||
/* Avoid possible naming collisions during link since
|
||||
* we prefer to use the actual name. */
|
||||
#define strlcpy(dst, src, size) strlcpy_retro__(dst, src, size)
|
||||
|
||||
#define strlcat(dst, src, size) strlcat_retro__(dst, src, size)
|
||||
|
||||
size_t strlcpy(char *dest, const char *source, size_t size);
|
||||
size_t strlcat(char *dest, const char *source, size_t size);
|
||||
|
||||
#endif
|
||||
|
||||
char *strldup(const char *s, size_t n);
|
||||
|
||||
RETRO_END_DECLS
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,67 @@
|
||||
/* Copyright (C) 2010-2018 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (utf.h).
|
||||
* ---------------------------------------------------------------------------------------
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef _LIBRETRO_ENCODINGS_UTF_H
|
||||
#define _LIBRETRO_ENCODINGS_UTF_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#include <libretro-common/boolean.h>
|
||||
|
||||
#include <libretro-common/retro_common_api.h>
|
||||
|
||||
RETRO_BEGIN_DECLS
|
||||
|
||||
enum CodePage
|
||||
{
|
||||
CODEPAGE_LOCAL = 0, /* CP_ACP */
|
||||
CODEPAGE_UTF8 = 65001 /* CP_UTF8 */
|
||||
};
|
||||
|
||||
size_t utf8_conv_utf32(uint32_t *out, size_t out_chars,
|
||||
const char *in, size_t in_size);
|
||||
|
||||
bool utf16_conv_utf8(uint8_t *out, size_t *out_chars,
|
||||
const uint16_t *in, size_t in_size);
|
||||
|
||||
size_t utf8len(const char *string);
|
||||
|
||||
size_t utf8cpy(char *d, size_t d_len, const char *s, size_t chars);
|
||||
|
||||
const char *utf8skip(const char *str, size_t chars);
|
||||
|
||||
uint32_t utf8_walk(const char **string);
|
||||
|
||||
bool utf16_to_char_string(const uint16_t *in, char *s, size_t len);
|
||||
|
||||
char* utf8_to_local_string_alloc(const char *str);
|
||||
|
||||
char* local_to_utf8_string_alloc(const char *str);
|
||||
|
||||
wchar_t* utf8_to_utf16_string_alloc(const char *str);
|
||||
|
||||
char* utf16_to_utf8_string_alloc(const wchar_t *str);
|
||||
|
||||
RETRO_END_DECLS
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,75 @@
|
||||
/* Copyright (C) 2010-2018 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (features_cpu.h).
|
||||
* ---------------------------------------------------------------------------------------
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef _LIBRETRO_SDK_CPU_INFO_H
|
||||
#define _LIBRETRO_SDK_CPU_INFO_H
|
||||
|
||||
#include <libretro-common/retro_common_api.h>
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <libretro-common/libretro.h>
|
||||
|
||||
RETRO_BEGIN_DECLS
|
||||
|
||||
/**
|
||||
* cpu_features_get_perf_counter:
|
||||
*
|
||||
* Gets performance counter.
|
||||
*
|
||||
* Returns: performance counter.
|
||||
**/
|
||||
retro_perf_tick_t cpu_features_get_perf_counter(void);
|
||||
|
||||
/**
|
||||
* cpu_features_get_time_usec:
|
||||
*
|
||||
* Gets time in microseconds, from an undefined epoch.
|
||||
* The epoch may change between computers or across reboots.
|
||||
*
|
||||
* Returns: time in microseconds
|
||||
**/
|
||||
retro_time_t cpu_features_get_time_usec(void);
|
||||
|
||||
/**
|
||||
* cpu_features_get:
|
||||
*
|
||||
* Gets CPU features.
|
||||
*
|
||||
* Returns: bitmask of all CPU features available.
|
||||
**/
|
||||
uint64_t cpu_features_get(void);
|
||||
|
||||
/**
|
||||
* cpu_features_get_core_amount:
|
||||
*
|
||||
* Gets the amount of available CPU cores.
|
||||
*
|
||||
* Returns: amount of CPU cores available.
|
||||
**/
|
||||
unsigned cpu_features_get_core_amount(void);
|
||||
|
||||
void cpu_features_get_model_name(char *name, int len);
|
||||
|
||||
RETRO_END_DECLS
|
||||
|
||||
#endif
|
||||
2537
Source/Benchmark-Toolbox/lib/borealis/library/include/borealis/extern/libretro-common/libretro.h
vendored
Normal file
@@ -0,0 +1,37 @@
|
||||
/* Copyright (C) 2010-2018 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (retro_assert.h).
|
||||
* ---------------------------------------------------------------------------------------
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef __RETRO_ASSERT_H
|
||||
#define __RETRO_ASSERT_H
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#ifdef RARCH_INTERNAL
|
||||
#include <stdio.h>
|
||||
#define retro_assert(cond) do { \
|
||||
if (!(cond)) { printf("Assertion failed at %s:%d.\n", __FILE__, __LINE__); abort(); } \
|
||||
} while(0)
|
||||
#else
|
||||
#define retro_assert(cond) assert(cond)
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,117 @@
|
||||
/* Copyright (C) 2010-2018 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (retro_common_api.h).
|
||||
* ---------------------------------------------------------------------------------------
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef _LIBRETRO_COMMON_RETRO_COMMON_API_H
|
||||
#define _LIBRETRO_COMMON_RETRO_COMMON_API_H
|
||||
|
||||
/*
|
||||
This file is designed to normalize the libretro-common compiling environment
|
||||
for public API headers. This should be leaner than a normal compiling environment,
|
||||
since it gets #included into other project's sources.
|
||||
*/
|
||||
|
||||
/* ------------------------------------ */
|
||||
|
||||
/*
|
||||
Ordinarily we want to put #ifdef __cplusplus extern "C" in C library
|
||||
headers to enable them to get used by c++ sources.
|
||||
However, we want to support building this library as C++ as well, so a
|
||||
special technique is called for.
|
||||
*/
|
||||
|
||||
#define RETRO_BEGIN_DECLS
|
||||
#define RETRO_END_DECLS
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
#ifdef CXX_BUILD
|
||||
/* build wants everything to be built as c++, so no extern "C" */
|
||||
#else
|
||||
#undef RETRO_BEGIN_DECLS
|
||||
#undef RETRO_END_DECLS
|
||||
#define RETRO_BEGIN_DECLS extern "C" {
|
||||
#define RETRO_END_DECLS }
|
||||
#endif
|
||||
|
||||
#else
|
||||
|
||||
/* header is included by a C source file, so no extern "C" */
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
IMO, this non-standard ssize_t should not be used.
|
||||
However, it's a good example of how to handle something like this.
|
||||
*/
|
||||
#ifdef _MSC_VER
|
||||
#ifndef HAVE_SSIZE_T
|
||||
#define HAVE_SSIZE_T
|
||||
#if defined(_WIN64)
|
||||
typedef __int64 ssize_t;
|
||||
#elif defined(_WIN32)
|
||||
typedef int ssize_t;
|
||||
#endif
|
||||
#endif
|
||||
#elif defined(__MACH__)
|
||||
#include <sys/types.h>
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#if _MSC_VER >= 1800
|
||||
#include <inttypes.h>
|
||||
#else
|
||||
#ifndef PRId64
|
||||
#define PRId64 "I64d"
|
||||
#define PRIu64 "I64u"
|
||||
#define PRIuPTR "Iu"
|
||||
#endif
|
||||
#endif
|
||||
#else
|
||||
/* C++11 says this one isn't needed, but apparently (some versions of) mingw require it anyways */
|
||||
/* https://stackoverflow.com/questions/8132399/how-to-printf-uint64-t-fails-with-spurious-trailing-in-format */
|
||||
/* https://github.com/libretro/RetroArch/issues/6009 */
|
||||
#define __STDC_FORMAT_MACROS
|
||||
#include <inttypes.h>
|
||||
#endif
|
||||
#ifndef PRId64
|
||||
#error "inttypes.h is being screwy"
|
||||
#endif
|
||||
#define STRING_REP_INT64 "%" PRId64
|
||||
#define STRING_REP_UINT64 "%" PRIu64
|
||||
#define STRING_REP_USIZE "%" PRIuPTR
|
||||
|
||||
/*
|
||||
I would like to see retro_inline.h moved in here; possibly boolean too.
|
||||
|
||||
rationale: these are used in public APIs, and it is easier to find problems
|
||||
and write code that works the first time portably when theyre included uniformly
|
||||
than to do the analysis from scratch each time you think you need it, for each feature.
|
||||
|
||||
Moreover it helps force you to make hard decisions: if you EVER bring in boolean.h,
|
||||
then you should pay the price everywhere, so you can see how much grief it will cause.
|
||||
|
||||
Of course, another school of thought is that you should do as little damage as possible
|
||||
in as few places as possible...
|
||||
*/
|
||||
|
||||
/* _LIBRETRO_COMMON_RETRO_COMMON_API_H */
|
||||
#endif
|
||||
@@ -0,0 +1,39 @@
|
||||
/* Copyright (C) 2010-2018 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (retro_inline.h).
|
||||
* ---------------------------------------------------------------------------------------
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef __LIBRETRO_SDK_INLINE_H
|
||||
#define __LIBRETRO_SDK_INLINE_H
|
||||
|
||||
#ifndef INLINE
|
||||
|
||||
#if defined(_WIN32) || defined(__INTEL_COMPILER)
|
||||
#define INLINE __inline
|
||||
#elif defined(__STDC_VERSION__) && __STDC_VERSION__>=199901L
|
||||
#define INLINE inline
|
||||
#elif defined(__GNUC__)
|
||||
#define INLINE __inline__
|
||||
#else
|
||||
#define INLINE
|
||||
#endif
|
||||
|
||||
#endif
|
||||
#endif
|
||||
@@ -0,0 +1,94 @@
|
||||
/* Copyright (C) 2010-2018 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (retro_math.h).
|
||||
* ---------------------------------------------------------------------------------------
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef _LIBRETRO_COMMON_MATH_H
|
||||
#define _LIBRETRO_COMMON_MATH_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#if defined(_WIN32) && !defined(_XBOX)
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
#elif defined(_WIN32) && defined(_XBOX)
|
||||
#include <Xtl.h>
|
||||
#endif
|
||||
|
||||
#include <limits.h>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#include <libretro-common/compat/msvc.h>
|
||||
#endif
|
||||
#include <libretro-common/retro_inline.h>
|
||||
|
||||
#ifndef M_PI
|
||||
#if !defined(USE_MATH_DEFINES)
|
||||
#define M_PI 3.14159265358979323846264338327
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef MAX
|
||||
#define MAX(a, b) ((a) > (b) ? (a) : (b))
|
||||
#endif
|
||||
|
||||
#ifndef MIN
|
||||
#define MIN(a, b) ((a) < (b) ? (a) : (b))
|
||||
#endif
|
||||
|
||||
/**
|
||||
* next_pow2:
|
||||
* @v : initial value
|
||||
*
|
||||
* Get next power of 2 value based on initial value.
|
||||
*
|
||||
* Returns: next power of 2 value (derived from @v).
|
||||
**/
|
||||
static INLINE uint32_t next_pow2(uint32_t v)
|
||||
{
|
||||
v--;
|
||||
v |= v >> 1;
|
||||
v |= v >> 2;
|
||||
v |= v >> 4;
|
||||
v |= v >> 8;
|
||||
v |= v >> 16;
|
||||
v++;
|
||||
return v;
|
||||
}
|
||||
|
||||
/**
|
||||
* prev_pow2:
|
||||
* @v : initial value
|
||||
*
|
||||
* Get previous power of 2 value based on initial value.
|
||||
*
|
||||
* Returns: previous power of 2 value (derived from @v).
|
||||
**/
|
||||
static INLINE uint32_t prev_pow2(uint32_t v)
|
||||
{
|
||||
v |= v >> 1;
|
||||
v |= v >> 2;
|
||||
v |= v >> 4;
|
||||
v |= v >> 8;
|
||||
v |= v >> 16;
|
||||
return v - (v >> 1);
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,182 @@
|
||||
/* Copyright (C) 2010-2018 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (retro_miscellaneous.h).
|
||||
* ---------------------------------------------------------------------------------------
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef __RARCH_MISCELLANEOUS_H
|
||||
#define __RARCH_MISCELLANEOUS_H
|
||||
|
||||
#define RARCH_MAX_SUBSYSTEMS 10
|
||||
#define RARCH_MAX_SUBSYSTEM_ROMS 10
|
||||
|
||||
#include <stdint.h>
|
||||
#include <libretro-common/boolean.h>
|
||||
#include <libretro-common/retro_inline.h>
|
||||
|
||||
#if defined(_WIN32) && !defined(_XBOX)
|
||||
#ifndef WIN32_LEAN_AND_MEAN
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#endif
|
||||
#include <windows.h>
|
||||
#elif defined(_WIN32) && defined(_XBOX)
|
||||
#include <Xtl.h>
|
||||
#endif
|
||||
|
||||
#if defined(__CELLOS_LV2__)
|
||||
#include <sys/fs_external.h>
|
||||
#endif
|
||||
|
||||
#include <limits.h>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#include <libretro-common/compat/msvc.h>
|
||||
#endif
|
||||
|
||||
static INLINE void bits_or_bits(uint32_t *a, uint32_t *b, uint32_t count)
|
||||
{
|
||||
uint32_t i;
|
||||
for (i = 0; i < count;i++)
|
||||
a[i] |= b[i];
|
||||
}
|
||||
|
||||
static INLINE void bits_clear_bits(uint32_t *a, uint32_t *b, uint32_t count)
|
||||
{
|
||||
uint32_t i;
|
||||
for (i = 0; i < count;i++)
|
||||
a[i] &= ~b[i];
|
||||
}
|
||||
|
||||
static INLINE bool bits_any_set(uint32_t* ptr, uint32_t count)
|
||||
{
|
||||
uint32_t i;
|
||||
for (i = 0; i < count; i++)
|
||||
{
|
||||
if (ptr[i] != 0)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifndef PATH_MAX_LENGTH
|
||||
#if defined(__CELLOS_LV2__)
|
||||
#define PATH_MAX_LENGTH CELL_FS_MAX_FS_PATH_LENGTH
|
||||
#elif defined(_XBOX1) || defined(_3DS) || defined(PSP) || defined(PS2) || defined(GEKKO)|| defined(WIIU) || defined(ORBIS)
|
||||
#define PATH_MAX_LENGTH 512
|
||||
#else
|
||||
#define PATH_MAX_LENGTH 4096
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef MAX
|
||||
#define MAX(a, b) ((a) > (b) ? (a) : (b))
|
||||
#endif
|
||||
|
||||
#ifndef MIN
|
||||
#define MIN(a, b) ((a) < (b) ? (a) : (b))
|
||||
#endif
|
||||
|
||||
#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
|
||||
|
||||
#define BITS_GET_ELEM(a, i) ((a).data[i])
|
||||
#define BITS_GET_ELEM_PTR(a, i) ((a)->data[i])
|
||||
|
||||
#define BIT_SET(a, bit) ((a)[(bit) >> 3] |= (1 << ((bit) & 7)))
|
||||
#define BIT_CLEAR(a, bit) ((a)[(bit) >> 3] &= ~(1 << ((bit) & 7)))
|
||||
#define BIT_GET(a, bit) (((a)[(bit) >> 3] >> ((bit) & 7)) & 1)
|
||||
|
||||
#define BIT16_SET(a, bit) ((a) |= (1 << ((bit) & 15)))
|
||||
#define BIT16_CLEAR(a, bit) ((a) &= ~(1 << ((bit) & 15)))
|
||||
#define BIT16_GET(a, bit) (((a) >> ((bit) & 15)) & 1)
|
||||
#define BIT16_CLEAR_ALL(a) ((a) = 0)
|
||||
|
||||
#define BIT32_SET(a, bit) ((a) |= (1 << ((bit) & 31)))
|
||||
#define BIT32_CLEAR(a, bit) ((a) &= ~(1 << ((bit) & 31)))
|
||||
#define BIT32_GET(a, bit) (((a) >> ((bit) & 31)) & 1)
|
||||
#define BIT32_CLEAR_ALL(a) ((a) = 0)
|
||||
|
||||
#define BIT64_SET(a, bit) ((a) |= (UINT64_C(1) << ((bit) & 63)))
|
||||
#define BIT64_CLEAR(a, bit) ((a) &= ~(UINT64_C(1) << ((bit) & 63)))
|
||||
#define BIT64_GET(a, bit) (((a) >> ((bit) & 63)) & 1)
|
||||
#define BIT64_CLEAR_ALL(a) ((a) = 0)
|
||||
|
||||
#define BIT128_SET(a, bit) ((a).data[(bit) >> 5] |= (1 << ((bit) & 31)))
|
||||
#define BIT128_CLEAR(a, bit) ((a).data[(bit) >> 5] &= ~(1 << ((bit) & 31)))
|
||||
#define BIT128_GET(a, bit) (((a).data[(bit) >> 5] >> ((bit) & 31)) & 1)
|
||||
#define BIT128_CLEAR_ALL(a) memset(&(a), 0, sizeof(a))
|
||||
|
||||
#define BIT128_SET_PTR(a, bit) BIT128_SET(*a, bit)
|
||||
#define BIT128_CLEAR_PTR(a, bit) BIT128_CLEAR(*a, bit)
|
||||
#define BIT128_GET_PTR(a, bit) BIT128_GET(*a, bit)
|
||||
#define BIT128_CLEAR_ALL_PTR(a) BIT128_CLEAR_ALL(*a)
|
||||
|
||||
#define BIT256_SET(a, bit) BIT128_SET(a, bit)
|
||||
#define BIT256_CLEAR(a, bit) BIT128_CLEAR(a, bit)
|
||||
#define BIT256_GET(a, bit) BIT128_GET(a, bit)
|
||||
#define BIT256_CLEAR_ALL(a) BIT128_CLEAR_ALL(a)
|
||||
|
||||
#define BIT256_SET_PTR(a, bit) BIT256_SET(*a, bit)
|
||||
#define BIT256_CLEAR_PTR(a, bit) BIT256_CLEAR(*a, bit)
|
||||
#define BIT256_GET_PTR(a, bit) BIT256_GET(*a, bit)
|
||||
#define BIT256_CLEAR_ALL_PTR(a) BIT256_CLEAR_ALL(*a)
|
||||
|
||||
#define BITS_COPY16_PTR(a,bits) \
|
||||
{ \
|
||||
BIT128_CLEAR_ALL_PTR(a); \
|
||||
BITS_GET_ELEM_PTR(a, 0) = (bits) & 0xffff; \
|
||||
}
|
||||
|
||||
#define BITS_COPY32_PTR(a,bits) \
|
||||
{ \
|
||||
BIT128_CLEAR_ALL_PTR(a); \
|
||||
BITS_GET_ELEM_PTR(a, 0) = (bits); \
|
||||
}
|
||||
|
||||
/* Helper macros and struct to keep track of many booleans. */
|
||||
/* This struct has 256 bits. */
|
||||
typedef struct
|
||||
{
|
||||
uint32_t data[8];
|
||||
} retro_bits_t;
|
||||
|
||||
#ifdef _WIN32
|
||||
# ifdef _WIN64
|
||||
# define PRI_SIZET PRIu64
|
||||
# else
|
||||
# if _MSC_VER == 1800
|
||||
# define PRI_SIZET PRIu32
|
||||
# else
|
||||
# define PRI_SIZET "u"
|
||||
# endif
|
||||
# endif
|
||||
#elif PS2
|
||||
# define PRI_SIZET "u"
|
||||
#else
|
||||
# if (SIZE_MAX == 0xFFFF)
|
||||
# define PRI_SIZET "hu"
|
||||
# elif (SIZE_MAX == 0xFFFFFFFF)
|
||||
# define PRI_SIZET "u"
|
||||
# elif (SIZE_MAX == 0xFFFFFFFFFFFFFFFF)
|
||||
# define PRI_SIZET "lu"
|
||||
# else
|
||||
# error PRI_SIZET: unknown SIZE_MAX
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#endif
|
||||
116
Source/Benchmark-Toolbox/lib/borealis/library/include/borealis/extern/libretro-common/retro_timers.h
vendored
Normal file
@@ -0,0 +1,116 @@
|
||||
/* Copyright (C) 2010-2018 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (retro_timers.h).
|
||||
* ---------------------------------------------------------------------------------------
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef __LIBRETRO_COMMON_TIMERS_H
|
||||
#define __LIBRETRO_COMMON_TIMERS_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#if defined(__CELLOS_LV2__) && !defined(__PSL1GHT__)
|
||||
#include <sys/timer.h>
|
||||
#elif defined(XENON)
|
||||
#include <time/time.h>
|
||||
#elif defined(GEKKO) || defined(__PSL1GHT__) || defined(__QNX__)
|
||||
#include <unistd.h>
|
||||
#elif defined(WIIU)
|
||||
#include <wiiu/os/thread.h>
|
||||
#elif defined(PSP)
|
||||
#include <pspthreadman.h>
|
||||
#elif defined(VITA)
|
||||
#include <psp2/kernel/threadmgr.h>
|
||||
#elif defined(PS2)
|
||||
#include <SDL/SDL_timer.h>
|
||||
#elif defined(_3DS)
|
||||
#include <3ds.h>
|
||||
#else
|
||||
#include <time.h>
|
||||
#endif
|
||||
|
||||
#if defined(_WIN32) && !defined(_XBOX)
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
#elif defined(_WIN32) && defined(_XBOX)
|
||||
#include <Xtl.h>
|
||||
#endif
|
||||
|
||||
#include <limits.h>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#include <libretro-common/compat/msvc.h>
|
||||
#endif
|
||||
#include <libretro-common/retro_inline.h>
|
||||
|
||||
#ifdef DJGPP
|
||||
#define timespec timeval
|
||||
#define tv_nsec tv_usec
|
||||
#include <unistd.h>
|
||||
|
||||
extern int nanosleep(const struct timespec *rqtp, struct timespec *rmtp);
|
||||
|
||||
static int nanosleepDOS(const struct timespec *rqtp, struct timespec *rmtp)
|
||||
{
|
||||
usleep(1000000 * rqtp->tv_sec + rqtp->tv_nsec / 1000);
|
||||
|
||||
if (rmtp)
|
||||
rmtp->tv_sec = rmtp->tv_nsec=0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define nanosleep nanosleepDOS
|
||||
#endif
|
||||
|
||||
/**
|
||||
* retro_sleep:
|
||||
* @msec : amount in milliseconds to sleep
|
||||
*
|
||||
* Sleeps for a specified amount of milliseconds (@msec).
|
||||
**/
|
||||
static INLINE void retro_sleep(unsigned msec)
|
||||
{
|
||||
#if defined(__CELLOS_LV2__) && !defined(__PSL1GHT__)
|
||||
sys_timer_usleep(1000 * msec);
|
||||
#elif defined(PSP) || defined(VITA)
|
||||
sceKernelDelayThread(1000 * msec);
|
||||
#elif defined(PS2)
|
||||
SDL_Delay(msec);
|
||||
#elif defined(_3DS)
|
||||
svcSleepThread(1000000 * (s64)msec);
|
||||
#elif defined(__WINRT__) || defined(WINAPI_FAMILY) && WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP
|
||||
SleepEx(msec, FALSE);
|
||||
#elif defined(_WIN32)
|
||||
Sleep(msec);
|
||||
#elif defined(XENON)
|
||||
udelay(1000 * msec);
|
||||
#elif defined(GEKKO) || defined(__PSL1GHT__) || defined(__QNX__)
|
||||
usleep(1000 * msec);
|
||||
#elif defined(WIIU)
|
||||
OSSleepTicks(ms_to_ticks(msec));
|
||||
#else
|
||||
struct timespec tv = {0};
|
||||
tv.tv_sec = msec / 1000;
|
||||
tv.tv_nsec = (msec % 1000) * 1000000;
|
||||
nanosleep(&tv, NULL);
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,111 @@
|
||||
/* Copyright (C) 2010-2018 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (file_stream.h).
|
||||
* ---------------------------------------------------------------------------------------
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef __LIBRETRO_SDK_FILE_STREAM_H
|
||||
#define __LIBRETRO_SDK_FILE_STREAM_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <libretro-common/libretro.h>
|
||||
#include <libretro-common/retro_common_api.h>
|
||||
#include <libretro-common/retro_inline.h>
|
||||
#include <libretro-common/boolean.h>
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
#define FILESTREAM_REQUIRED_VFS_VERSION 2
|
||||
|
||||
RETRO_BEGIN_DECLS
|
||||
|
||||
typedef struct RFILE RFILE;
|
||||
|
||||
#define FILESTREAM_REQUIRED_VFS_VERSION 2
|
||||
|
||||
void filestream_vfs_init(const struct retro_vfs_interface_info* vfs_info);
|
||||
|
||||
int64_t filestream_get_size(RFILE *stream);
|
||||
|
||||
int64_t filestream_truncate(RFILE *stream, int64_t length);
|
||||
|
||||
/**
|
||||
* filestream_open:
|
||||
* @path : path to file
|
||||
* @mode : file mode to use when opening (read/write)
|
||||
* @bufsize : optional buffer size (-1 or 0 to use default)
|
||||
*
|
||||
* Opens a file for reading or writing, depending on the requested mode.
|
||||
* Returns a pointer to an RFILE if opened successfully, otherwise NULL.
|
||||
**/
|
||||
RFILE *filestream_open(const char *path, unsigned mode, unsigned hints);
|
||||
|
||||
int64_t filestream_seek(RFILE *stream, int64_t offset, int seek_position);
|
||||
|
||||
int64_t filestream_read(RFILE *stream, void *data, int64_t len);
|
||||
|
||||
int64_t filestream_write(RFILE *stream, const void *data, int64_t len);
|
||||
|
||||
int64_t filestream_tell(RFILE *stream);
|
||||
|
||||
void filestream_rewind(RFILE *stream);
|
||||
|
||||
int filestream_close(RFILE *stream);
|
||||
|
||||
int64_t filestream_read_file(const char *path, void **buf, int64_t *len);
|
||||
|
||||
char *filestream_gets(RFILE *stream, char *s, size_t len);
|
||||
|
||||
int filestream_getc(RFILE *stream);
|
||||
|
||||
int filestream_scanf(RFILE *stream, const char* format, ...);
|
||||
|
||||
int filestream_eof(RFILE *stream);
|
||||
|
||||
bool filestream_write_file(const char *path, const void *data, int64_t size);
|
||||
|
||||
int filestream_putc(RFILE *stream, int c);
|
||||
|
||||
int filestream_vprintf(RFILE *stream, const char* format, va_list args);
|
||||
|
||||
int filestream_printf(RFILE *stream, const char* format, ...);
|
||||
|
||||
int filestream_error(RFILE *stream);
|
||||
|
||||
int filestream_flush(RFILE *stream);
|
||||
|
||||
int filestream_delete(const char *path);
|
||||
|
||||
int filestream_rename(const char *old_path, const char *new_path);
|
||||
|
||||
const char *filestream_get_path(RFILE *stream);
|
||||
|
||||
bool filestream_exists(const char *path);
|
||||
|
||||
char *filestream_getline(RFILE *stream);
|
||||
|
||||
RETRO_END_DECLS
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,134 @@
|
||||
/* Copyright (C) 2010-2019 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (stdstring.h).
|
||||
* ---------------------------------------------------------------------------------------
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef __LIBRETRO_SDK_STDSTRING_H
|
||||
#define __LIBRETRO_SDK_STDSTRING_H
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <ctype.h>
|
||||
#include <string.h>
|
||||
#include <libretro-common/boolean.h>
|
||||
|
||||
#include <libretro-common/retro_common_api.h>
|
||||
#include <libretro-common/retro_inline.h>
|
||||
#include <libretro-common/compat/strl.h>
|
||||
|
||||
RETRO_BEGIN_DECLS
|
||||
|
||||
static INLINE bool string_is_empty(const char *data)
|
||||
{
|
||||
return !data || (*data == '\0');
|
||||
}
|
||||
|
||||
static INLINE bool string_is_equal(const char *a, const char *b)
|
||||
{
|
||||
return (a && b) ? !strcmp(a, b) : false;
|
||||
}
|
||||
|
||||
#define STRLEN_CONST(x) ((sizeof((x))-1))
|
||||
|
||||
#define string_is_not_equal(a, b) !string_is_equal((a), (b))
|
||||
|
||||
#define string_add_pair_open(s, size) strlcat((s), " (", (size))
|
||||
#define string_add_pair_close(s, size) strlcat((s), ")", (size))
|
||||
#define string_add_bracket_open(s, size) strlcat((s), "{", (size))
|
||||
#define string_add_bracket_close(s, size) strlcat((s), "}", (size))
|
||||
#define string_add_single_quote(s, size) strlcat((s), "'", (size))
|
||||
#define string_add_quote(s, size) strlcat((s), "\"", (size))
|
||||
#define string_add_colon(s, size) strlcat((s), ":", (size))
|
||||
#define string_add_glob_open(s, size) strlcat((s), "glob('*", (size))
|
||||
#define string_add_glob_close(s, size) strlcat((s), "*')", (size))
|
||||
|
||||
#define string_is_not_equal_fast(a, b, size) (memcmp(a, b, size) != 0)
|
||||
#define string_is_equal_fast(a, b, size) (memcmp(a, b, size) == 0)
|
||||
|
||||
static INLINE void string_add_between_pairs(char *s, const char *str,
|
||||
size_t size)
|
||||
{
|
||||
string_add_pair_open(s, size);
|
||||
strlcat(s, str, size);
|
||||
string_add_pair_close(s, size);
|
||||
}
|
||||
|
||||
static INLINE bool string_is_equal_case_insensitive(const char *a,
|
||||
const char *b)
|
||||
{
|
||||
int result = 0;
|
||||
const unsigned char *p1 = (const unsigned char*)a;
|
||||
const unsigned char *p2 = (const unsigned char*)b;
|
||||
|
||||
if (!a || !b)
|
||||
return false;
|
||||
if (p1 == p2)
|
||||
return true;
|
||||
|
||||
while ((result = tolower (*p1) - tolower (*p2++)) == 0)
|
||||
if (*p1++ == '\0')
|
||||
break;
|
||||
|
||||
return (result == 0);
|
||||
}
|
||||
|
||||
static INLINE bool string_is_equal_noncase(const char *a, const char *b)
|
||||
{
|
||||
int result = 0;
|
||||
const unsigned char *p1 = (const unsigned char*)a;
|
||||
const unsigned char *p2 = (const unsigned char*)b;
|
||||
|
||||
if (!a || !b)
|
||||
return false;
|
||||
if (p1 == p2)
|
||||
return false;
|
||||
|
||||
while ((result = tolower (*p1) - tolower (*p2++)) == 0)
|
||||
if (*p1++ == '\0')
|
||||
break;
|
||||
|
||||
return (result == 0);
|
||||
}
|
||||
|
||||
char *string_to_upper(char *s);
|
||||
|
||||
char *string_to_lower(char *s);
|
||||
|
||||
char *string_ucwords(char *s);
|
||||
|
||||
char *string_replace_substring(const char *in, const char *pattern,
|
||||
const char *by);
|
||||
|
||||
/* Remove leading whitespaces */
|
||||
char *string_trim_whitespace_left(char *const s);
|
||||
|
||||
/* Remove trailing whitespaces */
|
||||
char *string_trim_whitespace_right(char *const s);
|
||||
|
||||
/* Remove leading and trailing whitespaces */
|
||||
char *string_trim_whitespace(char *const s);
|
||||
|
||||
/* max_lines == 0 means no limit */
|
||||
char *word_wrap(char *buffer, const char *string,
|
||||
int line_width, bool unicode, unsigned max_lines);
|
||||
|
||||
RETRO_END_DECLS
|
||||
|
||||
#endif
|
||||
18
Source/Benchmark-Toolbox/lib/borealis/library/include/borealis/extern/nanovg-gl/LICENSE.txt
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
Copyright (c) 2013 Mikko Mononen memon@inside.org
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
|
||||
1768
Source/Benchmark-Toolbox/lib/borealis/library/include/borealis/extern/nanovg-gl/fontstash.h
vendored
Normal file
685
Source/Benchmark-Toolbox/lib/borealis/library/include/borealis/extern/nanovg-gl/nanovg.h
vendored
Normal file
@@ -0,0 +1,685 @@
|
||||
//
|
||||
// Copyright (c) 2013 Mikko Mononen memon@inside.org
|
||||
//
|
||||
// This software is provided 'as-is', without any express or implied
|
||||
// warranty. In no event will the authors be held liable for any damages
|
||||
// arising from the use of this software.
|
||||
// Permission is granted to anyone to use this software for any purpose,
|
||||
// including commercial applications, and to alter it and redistribute it
|
||||
// freely, subject to the following restrictions:
|
||||
// 1. The origin of this software must not be misrepresented; you must not
|
||||
// claim that you wrote the original software. If you use this software
|
||||
// in a product, an acknowledgment in the product documentation would be
|
||||
// appreciated but is not required.
|
||||
// 2. Altered source versions must be plainly marked as such, and must not be
|
||||
// misrepresented as being the original software.
|
||||
// 3. This notice may not be removed or altered from any source distribution.
|
||||
//
|
||||
|
||||
#ifndef NANOVG_H
|
||||
#define NANOVG_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define NVG_PI 3.14159265358979323846264338327f
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable: 4201) // nonstandard extension used : nameless struct/union
|
||||
#endif
|
||||
|
||||
typedef struct NVGcontext NVGcontext;
|
||||
|
||||
struct NVGcolor {
|
||||
union {
|
||||
float rgba[4];
|
||||
struct {
|
||||
float r,g,b,a;
|
||||
};
|
||||
};
|
||||
};
|
||||
typedef struct NVGcolor NVGcolor;
|
||||
|
||||
struct NVGpaint {
|
||||
float xform[6];
|
||||
float extent[2];
|
||||
float radius;
|
||||
float feather;
|
||||
NVGcolor innerColor;
|
||||
NVGcolor outerColor;
|
||||
int image;
|
||||
};
|
||||
typedef struct NVGpaint NVGpaint;
|
||||
|
||||
enum NVGwinding {
|
||||
NVG_CCW = 1, // Winding for solid shapes
|
||||
NVG_CW = 2, // Winding for holes
|
||||
};
|
||||
|
||||
enum NVGsolidity {
|
||||
NVG_SOLID = 1, // CCW
|
||||
NVG_HOLE = 2, // CW
|
||||
};
|
||||
|
||||
enum NVGlineCap {
|
||||
NVG_BUTT,
|
||||
NVG_ROUND,
|
||||
NVG_SQUARE,
|
||||
NVG_BEVEL,
|
||||
NVG_MITER,
|
||||
};
|
||||
|
||||
enum NVGalign {
|
||||
// Horizontal align
|
||||
NVG_ALIGN_LEFT = 1<<0, // Default, align text horizontally to left.
|
||||
NVG_ALIGN_CENTER = 1<<1, // Align text horizontally to center.
|
||||
NVG_ALIGN_RIGHT = 1<<2, // Align text horizontally to right.
|
||||
// Vertical align
|
||||
NVG_ALIGN_TOP = 1<<3, // Align text vertically to top.
|
||||
NVG_ALIGN_MIDDLE = 1<<4, // Align text vertically to middle.
|
||||
NVG_ALIGN_BOTTOM = 1<<5, // Align text vertically to bottom.
|
||||
NVG_ALIGN_BASELINE = 1<<6, // Default, align text vertically to baseline.
|
||||
};
|
||||
|
||||
enum NVGblendFactor {
|
||||
NVG_ZERO = 1<<0,
|
||||
NVG_ONE = 1<<1,
|
||||
NVG_SRC_COLOR = 1<<2,
|
||||
NVG_ONE_MINUS_SRC_COLOR = 1<<3,
|
||||
NVG_DST_COLOR = 1<<4,
|
||||
NVG_ONE_MINUS_DST_COLOR = 1<<5,
|
||||
NVG_SRC_ALPHA = 1<<6,
|
||||
NVG_ONE_MINUS_SRC_ALPHA = 1<<7,
|
||||
NVG_DST_ALPHA = 1<<8,
|
||||
NVG_ONE_MINUS_DST_ALPHA = 1<<9,
|
||||
NVG_SRC_ALPHA_SATURATE = 1<<10,
|
||||
};
|
||||
|
||||
enum NVGcompositeOperation {
|
||||
NVG_SOURCE_OVER,
|
||||
NVG_SOURCE_IN,
|
||||
NVG_SOURCE_OUT,
|
||||
NVG_ATOP,
|
||||
NVG_DESTINATION_OVER,
|
||||
NVG_DESTINATION_IN,
|
||||
NVG_DESTINATION_OUT,
|
||||
NVG_DESTINATION_ATOP,
|
||||
NVG_LIGHTER,
|
||||
NVG_COPY,
|
||||
NVG_XOR,
|
||||
};
|
||||
|
||||
struct NVGcompositeOperationState {
|
||||
int srcRGB;
|
||||
int dstRGB;
|
||||
int srcAlpha;
|
||||
int dstAlpha;
|
||||
};
|
||||
typedef struct NVGcompositeOperationState NVGcompositeOperationState;
|
||||
|
||||
struct NVGglyphPosition {
|
||||
const char* str; // Position of the glyph in the input string.
|
||||
float x; // The x-coordinate of the logical glyph position.
|
||||
float minx, maxx; // The bounds of the glyph shape.
|
||||
};
|
||||
typedef struct NVGglyphPosition NVGglyphPosition;
|
||||
|
||||
struct NVGtextRow {
|
||||
const char* start; // Pointer to the input text where the row starts.
|
||||
const char* end; // Pointer to the input text where the row ends (one past the last character).
|
||||
const char* next; // Pointer to the beginning of the next row.
|
||||
float width; // Logical width of the row.
|
||||
float minx, maxx; // Actual bounds of the row. Logical with and bounds can differ because of kerning and some parts over extending.
|
||||
};
|
||||
typedef struct NVGtextRow NVGtextRow;
|
||||
|
||||
enum NVGimageFlags {
|
||||
NVG_IMAGE_GENERATE_MIPMAPS = 1<<0, // Generate mipmaps during creation of the image.
|
||||
NVG_IMAGE_REPEATX = 1<<1, // Repeat image in X direction.
|
||||
NVG_IMAGE_REPEATY = 1<<2, // Repeat image in Y direction.
|
||||
NVG_IMAGE_FLIPY = 1<<3, // Flips (inverses) image in Y direction when rendered.
|
||||
NVG_IMAGE_PREMULTIPLIED = 1<<4, // Image data has premultiplied alpha.
|
||||
NVG_IMAGE_NEAREST = 1<<5, // Image interpolation is Nearest instead Linear
|
||||
};
|
||||
|
||||
// Begin drawing a new frame
|
||||
// Calls to nanovg drawing API should be wrapped in nvgBeginFrame() & nvgEndFrame()
|
||||
// nvgBeginFrame() defines the size of the window to render to in relation currently
|
||||
// set viewport (i.e. glViewport on GL backends). Device pixel ration allows to
|
||||
// control the rendering on Hi-DPI devices.
|
||||
// For example, GLFW returns two dimension for an opened window: window size and
|
||||
// frame buffer size. In that case you would set windowWidth/Height to the window size
|
||||
// devicePixelRatio to: frameBufferWidth / windowWidth.
|
||||
void nvgBeginFrame(NVGcontext* ctx, float windowWidth, float windowHeight, float devicePixelRatio);
|
||||
|
||||
// Cancels drawing the current frame.
|
||||
void nvgCancelFrame(NVGcontext* ctx);
|
||||
|
||||
// Ends drawing flushing remaining render state.
|
||||
void nvgEndFrame(NVGcontext* ctx);
|
||||
|
||||
//
|
||||
// Composite operation
|
||||
//
|
||||
// The composite operations in NanoVG are modeled after HTML Canvas API, and
|
||||
// the blend func is based on OpenGL (see corresponding manuals for more info).
|
||||
// The colors in the blending state have premultiplied alpha.
|
||||
|
||||
// Sets the composite operation. The op parameter should be one of NVGcompositeOperation.
|
||||
void nvgGlobalCompositeOperation(NVGcontext* ctx, int op);
|
||||
|
||||
// Sets the composite operation with custom pixel arithmetic. The parameters should be one of NVGblendFactor.
|
||||
void nvgGlobalCompositeBlendFunc(NVGcontext* ctx, int sfactor, int dfactor);
|
||||
|
||||
// Sets the composite operation with custom pixel arithmetic for RGB and alpha components separately. The parameters should be one of NVGblendFactor.
|
||||
void nvgGlobalCompositeBlendFuncSeparate(NVGcontext* ctx, int srcRGB, int dstRGB, int srcAlpha, int dstAlpha);
|
||||
|
||||
//
|
||||
// Color utils
|
||||
//
|
||||
// Colors in NanoVG are stored as unsigned ints in ABGR format.
|
||||
|
||||
// Returns a color value from red, green, blue values. Alpha will be set to 255 (1.0f).
|
||||
NVGcolor nvgRGB(unsigned char r, unsigned char g, unsigned char b);
|
||||
|
||||
// Returns a color value from red, green, blue values. Alpha will be set to 1.0f.
|
||||
NVGcolor nvgRGBf(float r, float g, float b);
|
||||
|
||||
|
||||
// Returns a color value from red, green, blue and alpha values.
|
||||
NVGcolor nvgRGBA(unsigned char r, unsigned char g, unsigned char b, unsigned char a);
|
||||
|
||||
// Returns a color value from red, green, blue and alpha values.
|
||||
NVGcolor nvgRGBAf(float r, float g, float b, float a);
|
||||
|
||||
|
||||
// Linearly interpolates from color c0 to c1, and returns resulting color value.
|
||||
NVGcolor nvgLerpRGBA(NVGcolor c0, NVGcolor c1, float u);
|
||||
|
||||
// Sets transparency of a color value.
|
||||
NVGcolor nvgTransRGBA(NVGcolor c0, unsigned char a);
|
||||
|
||||
// Sets transparency of a color value.
|
||||
NVGcolor nvgTransRGBAf(NVGcolor c0, float a);
|
||||
|
||||
// Returns color value specified by hue, saturation and lightness.
|
||||
// HSL values are all in range [0..1], alpha will be set to 255.
|
||||
NVGcolor nvgHSL(float h, float s, float l);
|
||||
|
||||
// Returns color value specified by hue, saturation and lightness and alpha.
|
||||
// HSL values are all in range [0..1], alpha in range [0..255]
|
||||
NVGcolor nvgHSLA(float h, float s, float l, unsigned char a);
|
||||
|
||||
//
|
||||
// State Handling
|
||||
//
|
||||
// NanoVG contains state which represents how paths will be rendered.
|
||||
// The state contains transform, fill and stroke styles, text and font styles,
|
||||
// and scissor clipping.
|
||||
|
||||
// Pushes and saves the current render state into a state stack.
|
||||
// A matching nvgRestore() must be used to restore the state.
|
||||
void nvgSave(NVGcontext* ctx);
|
||||
|
||||
// Pops and restores current render state.
|
||||
void nvgRestore(NVGcontext* ctx);
|
||||
|
||||
// Resets current render state to default values. Does not affect the render state stack.
|
||||
void nvgReset(NVGcontext* ctx);
|
||||
|
||||
//
|
||||
// Render styles
|
||||
//
|
||||
// Fill and stroke render style can be either a solid color or a paint which is a gradient or a pattern.
|
||||
// Solid color is simply defined as a color value, different kinds of paints can be created
|
||||
// using nvgLinearGradient(), nvgBoxGradient(), nvgRadialGradient() and nvgImagePattern().
|
||||
//
|
||||
// Current render style can be saved and restored using nvgSave() and nvgRestore().
|
||||
|
||||
// Sets whether to draw antialias for nvgStroke() and nvgFill(). It's enabled by default.
|
||||
void nvgShapeAntiAlias(NVGcontext* ctx, int enabled);
|
||||
|
||||
// Sets current stroke style to a solid color.
|
||||
void nvgStrokeColor(NVGcontext* ctx, NVGcolor color);
|
||||
|
||||
// Sets current stroke style to a paint, which can be a one of the gradients or a pattern.
|
||||
void nvgStrokePaint(NVGcontext* ctx, NVGpaint paint);
|
||||
|
||||
// Sets current fill style to a solid color.
|
||||
void nvgFillColor(NVGcontext* ctx, NVGcolor color);
|
||||
|
||||
// Sets current fill style to a paint, which can be a one of the gradients or a pattern.
|
||||
void nvgFillPaint(NVGcontext* ctx, NVGpaint paint);
|
||||
|
||||
// Sets the miter limit of the stroke style.
|
||||
// Miter limit controls when a sharp corner is beveled.
|
||||
void nvgMiterLimit(NVGcontext* ctx, float limit);
|
||||
|
||||
// Sets the stroke width of the stroke style.
|
||||
void nvgStrokeWidth(NVGcontext* ctx, float size);
|
||||
|
||||
// Sets how the end of the line (cap) is drawn,
|
||||
// Can be one of: NVG_BUTT (default), NVG_ROUND, NVG_SQUARE.
|
||||
void nvgLineCap(NVGcontext* ctx, int cap);
|
||||
|
||||
// Sets how sharp path corners are drawn.
|
||||
// Can be one of NVG_MITER (default), NVG_ROUND, NVG_BEVEL.
|
||||
void nvgLineJoin(NVGcontext* ctx, int join);
|
||||
|
||||
// Sets the transparency applied to all rendered shapes.
|
||||
// Already transparent paths will get proportionally more transparent as well.
|
||||
void nvgGlobalAlpha(NVGcontext* ctx, float alpha);
|
||||
|
||||
//
|
||||
// Transforms
|
||||
//
|
||||
// The paths, gradients, patterns and scissor region are transformed by an transformation
|
||||
// matrix at the time when they are passed to the API.
|
||||
// The current transformation matrix is a affine matrix:
|
||||
// [sx kx tx]
|
||||
// [ky sy ty]
|
||||
// [ 0 0 1]
|
||||
// Where: sx,sy define scaling, kx,ky skewing, and tx,ty translation.
|
||||
// The last row is assumed to be 0,0,1 and is not stored.
|
||||
//
|
||||
// Apart from nvgResetTransform(), each transformation function first creates
|
||||
// specific transformation matrix and pre-multiplies the current transformation by it.
|
||||
//
|
||||
// Current coordinate system (transformation) can be saved and restored using nvgSave() and nvgRestore().
|
||||
|
||||
// Resets current transform to a identity matrix.
|
||||
void nvgResetTransform(NVGcontext* ctx);
|
||||
|
||||
// Premultiplies current coordinate system by specified matrix.
|
||||
// The parameters are interpreted as matrix as follows:
|
||||
// [a c e]
|
||||
// [b d f]
|
||||
// [0 0 1]
|
||||
void nvgTransform(NVGcontext* ctx, float a, float b, float c, float d, float e, float f);
|
||||
|
||||
// Translates current coordinate system.
|
||||
void nvgTranslate(NVGcontext* ctx, float x, float y);
|
||||
|
||||
// Rotates current coordinate system. Angle is specified in radians.
|
||||
void nvgRotate(NVGcontext* ctx, float angle);
|
||||
|
||||
// Skews the current coordinate system along X axis. Angle is specified in radians.
|
||||
void nvgSkewX(NVGcontext* ctx, float angle);
|
||||
|
||||
// Skews the current coordinate system along Y axis. Angle is specified in radians.
|
||||
void nvgSkewY(NVGcontext* ctx, float angle);
|
||||
|
||||
// Scales the current coordinate system.
|
||||
void nvgScale(NVGcontext* ctx, float x, float y);
|
||||
|
||||
// Stores the top part (a-f) of the current transformation matrix in to the specified buffer.
|
||||
// [a c e]
|
||||
// [b d f]
|
||||
// [0 0 1]
|
||||
// There should be space for 6 floats in the return buffer for the values a-f.
|
||||
void nvgCurrentTransform(NVGcontext* ctx, float* xform);
|
||||
|
||||
|
||||
// The following functions can be used to make calculations on 2x3 transformation matrices.
|
||||
// A 2x3 matrix is represented as float[6].
|
||||
|
||||
// Sets the transform to identity matrix.
|
||||
void nvgTransformIdentity(float* dst);
|
||||
|
||||
// Sets the transform to translation matrix matrix.
|
||||
void nvgTransformTranslate(float* dst, float tx, float ty);
|
||||
|
||||
// Sets the transform to scale matrix.
|
||||
void nvgTransformScale(float* dst, float sx, float sy);
|
||||
|
||||
// Sets the transform to rotate matrix. Angle is specified in radians.
|
||||
void nvgTransformRotate(float* dst, float a);
|
||||
|
||||
// Sets the transform to skew-x matrix. Angle is specified in radians.
|
||||
void nvgTransformSkewX(float* dst, float a);
|
||||
|
||||
// Sets the transform to skew-y matrix. Angle is specified in radians.
|
||||
void nvgTransformSkewY(float* dst, float a);
|
||||
|
||||
// Sets the transform to the result of multiplication of two transforms, of A = A*B.
|
||||
void nvgTransformMultiply(float* dst, const float* src);
|
||||
|
||||
// Sets the transform to the result of multiplication of two transforms, of A = B*A.
|
||||
void nvgTransformPremultiply(float* dst, const float* src);
|
||||
|
||||
// Sets the destination to inverse of specified transform.
|
||||
// Returns 1 if the inverse could be calculated, else 0.
|
||||
int nvgTransformInverse(float* dst, const float* src);
|
||||
|
||||
// Transform a point by given transform.
|
||||
void nvgTransformPoint(float* dstx, float* dsty, const float* xform, float srcx, float srcy);
|
||||
|
||||
// Converts degrees to radians and vice versa.
|
||||
float nvgDegToRad(float deg);
|
||||
float nvgRadToDeg(float rad);
|
||||
|
||||
//
|
||||
// Images
|
||||
//
|
||||
// NanoVG allows you to load jpg, png, psd, tga, pic and gif files to be used for rendering.
|
||||
// In addition you can upload your own image. The image loading is provided by stb_image.
|
||||
// The parameter imageFlags is combination of flags defined in NVGimageFlags.
|
||||
|
||||
// Creates image by loading it from the disk from specified file name.
|
||||
// Returns handle to the image.
|
||||
int nvgCreateImage(NVGcontext* ctx, const char* filename, int imageFlags);
|
||||
|
||||
// Creates image by loading it from the specified chunk of memory.
|
||||
// Returns handle to the image.
|
||||
int nvgCreateImageMem(NVGcontext* ctx, int imageFlags, unsigned char* data, int ndata);
|
||||
|
||||
// Creates image from specified image data.
|
||||
// Returns handle to the image.
|
||||
int nvgCreateImageRGBA(NVGcontext* ctx, int w, int h, int imageFlags, const unsigned char* data);
|
||||
|
||||
// Updates image data specified by image handle.
|
||||
void nvgUpdateImage(NVGcontext* ctx, int image, const unsigned char* data);
|
||||
|
||||
// Returns the dimensions of a created image.
|
||||
void nvgImageSize(NVGcontext* ctx, int image, int* w, int* h);
|
||||
|
||||
// Deletes created image.
|
||||
void nvgDeleteImage(NVGcontext* ctx, int image);
|
||||
|
||||
//
|
||||
// Paints
|
||||
//
|
||||
// NanoVG supports four types of paints: linear gradient, box gradient, radial gradient and image pattern.
|
||||
// These can be used as paints for strokes and fills.
|
||||
|
||||
// Creates and returns a linear gradient. Parameters (sx,sy)-(ex,ey) specify the start and end coordinates
|
||||
// of the linear gradient, icol specifies the start color and ocol the end color.
|
||||
// The gradient is transformed by the current transform when it is passed to nvgFillPaint() or nvgStrokePaint().
|
||||
NVGpaint nvgLinearGradient(NVGcontext* ctx, float sx, float sy, float ex, float ey,
|
||||
NVGcolor icol, NVGcolor ocol);
|
||||
|
||||
// Creates and returns a box gradient. Box gradient is a feathered rounded rectangle, it is useful for rendering
|
||||
// drop shadows or highlights for boxes. Parameters (x,y) define the top-left corner of the rectangle,
|
||||
// (w,h) define the size of the rectangle, r defines the corner radius, and f feather. Feather defines how blurry
|
||||
// the border of the rectangle is. Parameter icol specifies the inner color and ocol the outer color of the gradient.
|
||||
// The gradient is transformed by the current transform when it is passed to nvgFillPaint() or nvgStrokePaint().
|
||||
NVGpaint nvgBoxGradient(NVGcontext* ctx, float x, float y, float w, float h,
|
||||
float r, float f, NVGcolor icol, NVGcolor ocol);
|
||||
|
||||
// Creates and returns a radial gradient. Parameters (cx,cy) specify the center, inr and outr specify
|
||||
// the inner and outer radius of the gradient, icol specifies the start color and ocol the end color.
|
||||
// The gradient is transformed by the current transform when it is passed to nvgFillPaint() or nvgStrokePaint().
|
||||
NVGpaint nvgRadialGradient(NVGcontext* ctx, float cx, float cy, float inr, float outr,
|
||||
NVGcolor icol, NVGcolor ocol);
|
||||
|
||||
// Creates and returns an image patter. Parameters (ox,oy) specify the left-top location of the image pattern,
|
||||
// (ex,ey) the size of one image, angle rotation around the top-left corner, image is handle to the image to render.
|
||||
// The gradient is transformed by the current transform when it is passed to nvgFillPaint() or nvgStrokePaint().
|
||||
NVGpaint nvgImagePattern(NVGcontext* ctx, float ox, float oy, float ex, float ey,
|
||||
float angle, int image, float alpha);
|
||||
|
||||
//
|
||||
// Scissoring
|
||||
//
|
||||
// Scissoring allows you to clip the rendering into a rectangle. This is useful for various
|
||||
// user interface cases like rendering a text edit or a timeline.
|
||||
|
||||
// Sets the current scissor rectangle.
|
||||
// The scissor rectangle is transformed by the current transform.
|
||||
void nvgScissor(NVGcontext* ctx, float x, float y, float w, float h);
|
||||
|
||||
// Intersects current scissor rectangle with the specified rectangle.
|
||||
// The scissor rectangle is transformed by the current transform.
|
||||
// Note: in case the rotation of previous scissor rect differs from
|
||||
// the current one, the intersection will be done between the specified
|
||||
// rectangle and the previous scissor rectangle transformed in the current
|
||||
// transform space. The resulting shape is always rectangle.
|
||||
void nvgIntersectScissor(NVGcontext* ctx, float x, float y, float w, float h);
|
||||
|
||||
// Reset and disables scissoring.
|
||||
void nvgResetScissor(NVGcontext* ctx);
|
||||
|
||||
//
|
||||
// Paths
|
||||
//
|
||||
// Drawing a new shape starts with nvgBeginPath(), it clears all the currently defined paths.
|
||||
// Then you define one or more paths and sub-paths which describe the shape. The are functions
|
||||
// to draw common shapes like rectangles and circles, and lower level step-by-step functions,
|
||||
// which allow to define a path curve by curve.
|
||||
//
|
||||
// NanoVG uses even-odd fill rule to draw the shapes. Solid shapes should have counter clockwise
|
||||
// winding and holes should have counter clockwise order. To specify winding of a path you can
|
||||
// call nvgPathWinding(). This is useful especially for the common shapes, which are drawn CCW.
|
||||
//
|
||||
// Finally you can fill the path using current fill style by calling nvgFill(), and stroke it
|
||||
// with current stroke style by calling nvgStroke().
|
||||
//
|
||||
// The curve segments and sub-paths are transformed by the current transform.
|
||||
|
||||
// Clears the current path and sub-paths.
|
||||
void nvgBeginPath(NVGcontext* ctx);
|
||||
|
||||
// Starts new sub-path with specified point as first point.
|
||||
void nvgMoveTo(NVGcontext* ctx, float x, float y);
|
||||
|
||||
// Adds line segment from the last point in the path to the specified point.
|
||||
void nvgLineTo(NVGcontext* ctx, float x, float y);
|
||||
|
||||
// Adds cubic bezier segment from last point in the path via two control points to the specified point.
|
||||
void nvgBezierTo(NVGcontext* ctx, float c1x, float c1y, float c2x, float c2y, float x, float y);
|
||||
|
||||
// Adds quadratic bezier segment from last point in the path via a control point to the specified point.
|
||||
void nvgQuadTo(NVGcontext* ctx, float cx, float cy, float x, float y);
|
||||
|
||||
// Adds an arc segment at the corner defined by the last path point, and two specified points.
|
||||
void nvgArcTo(NVGcontext* ctx, float x1, float y1, float x2, float y2, float radius);
|
||||
|
||||
// Closes current sub-path with a line segment.
|
||||
void nvgClosePath(NVGcontext* ctx);
|
||||
|
||||
// Sets the current sub-path winding, see NVGwinding and NVGsolidity.
|
||||
void nvgPathWinding(NVGcontext* ctx, int dir);
|
||||
|
||||
// Creates new circle arc shaped sub-path. The arc center is at cx,cy, the arc radius is r,
|
||||
// and the arc is drawn from angle a0 to a1, and swept in direction dir (NVG_CCW, or NVG_CW).
|
||||
// Angles are specified in radians.
|
||||
void nvgArc(NVGcontext* ctx, float cx, float cy, float r, float a0, float a1, int dir);
|
||||
|
||||
// Creates new rectangle shaped sub-path.
|
||||
void nvgRect(NVGcontext* ctx, float x, float y, float w, float h);
|
||||
|
||||
// Creates new rounded rectangle shaped sub-path.
|
||||
void nvgRoundedRect(NVGcontext* ctx, float x, float y, float w, float h, float r);
|
||||
|
||||
// Creates new rounded rectangle shaped sub-path with varying radii for each corner.
|
||||
void nvgRoundedRectVarying(NVGcontext* ctx, float x, float y, float w, float h, float radTopLeft, float radTopRight, float radBottomRight, float radBottomLeft);
|
||||
|
||||
// Creates new ellipse shaped sub-path.
|
||||
void nvgEllipse(NVGcontext* ctx, float cx, float cy, float rx, float ry);
|
||||
|
||||
// Creates new circle shaped sub-path.
|
||||
void nvgCircle(NVGcontext* ctx, float cx, float cy, float r);
|
||||
|
||||
// Fills the current path with current fill style.
|
||||
void nvgFill(NVGcontext* ctx);
|
||||
|
||||
// Fills the current path with current stroke style.
|
||||
void nvgStroke(NVGcontext* ctx);
|
||||
|
||||
|
||||
//
|
||||
// Text
|
||||
//
|
||||
// NanoVG allows you to load .ttf files and use the font to render text.
|
||||
//
|
||||
// The appearance of the text can be defined by setting the current text style
|
||||
// and by specifying the fill color. Common text and font settings such as
|
||||
// font size, letter spacing and text align are supported. Font blur allows you
|
||||
// to create simple text effects such as drop shadows.
|
||||
//
|
||||
// At render time the font face can be set based on the font handles or name.
|
||||
//
|
||||
// Font measure functions return values in local space, the calculations are
|
||||
// carried in the same resolution as the final rendering. This is done because
|
||||
// the text glyph positions are snapped to the nearest pixels sharp rendering.
|
||||
//
|
||||
// The local space means that values are not rotated or scale as per the current
|
||||
// transformation. For example if you set font size to 12, which would mean that
|
||||
// line height is 16, then regardless of the current scaling and rotation, the
|
||||
// returned line height is always 16. Some measures may vary because of the scaling
|
||||
// since aforementioned pixel snapping.
|
||||
//
|
||||
// While this may sound a little odd, the setup allows you to always render the
|
||||
// same way regardless of scaling. I.e. following works regardless of scaling:
|
||||
//
|
||||
// const char* txt = "Text me up.";
|
||||
// nvgTextBounds(vg, x,y, txt, NULL, bounds);
|
||||
// nvgBeginPath(vg);
|
||||
// nvgRoundedRect(vg, bounds[0],bounds[1], bounds[2]-bounds[0], bounds[3]-bounds[1]);
|
||||
// nvgFill(vg);
|
||||
//
|
||||
// Note: currently only solid color fill is supported for text.
|
||||
|
||||
// Creates font by loading it from the disk from specified file name.
|
||||
// Returns handle to the font.
|
||||
int nvgCreateFont(NVGcontext* ctx, const char* name, const char* filename);
|
||||
|
||||
// Creates font by loading it from the specified memory chunk.
|
||||
// Returns handle to the font.
|
||||
int nvgCreateFontMem(NVGcontext* ctx, const char* name, unsigned char* data, int ndata, int freeData);
|
||||
|
||||
// Finds a loaded font of specified name, and returns handle to it, or -1 if the font is not found.
|
||||
int nvgFindFont(NVGcontext* ctx, const char* name);
|
||||
|
||||
// Adds a fallback font by handle.
|
||||
int nvgAddFallbackFontId(NVGcontext* ctx, int baseFont, int fallbackFont);
|
||||
|
||||
// Adds a fallback font by name.
|
||||
int nvgAddFallbackFont(NVGcontext* ctx, const char* baseFont, const char* fallbackFont);
|
||||
|
||||
// Sets the font size of current text style.
|
||||
void nvgFontSize(NVGcontext* ctx, float size);
|
||||
|
||||
// Sets the blur of current text style.
|
||||
void nvgFontBlur(NVGcontext* ctx, float blur);
|
||||
|
||||
// Sets the letter spacing of current text style.
|
||||
void nvgTextLetterSpacing(NVGcontext* ctx, float spacing);
|
||||
|
||||
// Sets the proportional line height of current text style. The line height is specified as multiple of font size.
|
||||
void nvgTextLineHeight(NVGcontext* ctx, float lineHeight);
|
||||
|
||||
// Sets the text align of current text style, see NVGalign for options.
|
||||
void nvgTextAlign(NVGcontext* ctx, int align);
|
||||
|
||||
// Sets the font face based on specified id of current text style.
|
||||
void nvgFontFaceId(NVGcontext* ctx, int font);
|
||||
|
||||
// Sets the font face based on specified name of current text style.
|
||||
void nvgFontFace(NVGcontext* ctx, const char* font);
|
||||
|
||||
// Draws text string at specified location. If end is specified only the sub-string up to the end is drawn.
|
||||
float nvgText(NVGcontext* ctx, float x, float y, const char* string, const char* end);
|
||||
|
||||
// Draws multi-line text string at specified location wrapped at the specified width. If end is specified only the sub-string up to the end is drawn.
|
||||
// White space is stripped at the beginning of the rows, the text is split at word boundaries or when new-line characters are encountered.
|
||||
// Words longer than the max width are slit at nearest character (i.e. no hyphenation).
|
||||
void nvgTextBox(NVGcontext* ctx, float x, float y, float breakRowWidth, const char* string, const char* end);
|
||||
|
||||
// Measures the specified text string. Parameter bounds should be a pointer to float[4],
|
||||
// if the bounding box of the text should be returned. The bounds value are [xmin,ymin, xmax,ymax]
|
||||
// Returns the horizontal advance of the measured text (i.e. where the next character should drawn).
|
||||
// Measured values are returned in local coordinate space.
|
||||
float nvgTextBounds(NVGcontext* ctx, float x, float y, const char* string, const char* end, float* bounds);
|
||||
|
||||
// Measures the specified multi-text string. Parameter bounds should be a pointer to float[4],
|
||||
// if the bounding box of the text should be returned. The bounds value are [xmin,ymin, xmax,ymax]
|
||||
// Measured values are returned in local coordinate space.
|
||||
void nvgTextBoxBounds(NVGcontext* ctx, float x, float y, float breakRowWidth, const char* string, const char* end, float* bounds);
|
||||
|
||||
// Calculates the glyph x positions of the specified text. If end is specified only the sub-string will be used.
|
||||
// Measured values are returned in local coordinate space.
|
||||
int nvgTextGlyphPositions(NVGcontext* ctx, float x, float y, const char* string, const char* end, NVGglyphPosition* positions, int maxPositions);
|
||||
|
||||
// Returns the vertical metrics based on the current text style.
|
||||
// Measured values are returned in local coordinate space.
|
||||
void nvgTextMetrics(NVGcontext* ctx, float* ascender, float* descender, float* lineh);
|
||||
|
||||
// Breaks the specified text into lines. If end is specified only the sub-string will be used.
|
||||
// White space is stripped at the beginning of the rows, the text is split at word boundaries or when new-line characters are encountered.
|
||||
// Words longer than the max width are slit at nearest character (i.e. no hyphenation).
|
||||
int nvgTextBreakLines(NVGcontext* ctx, const char* string, const char* end, float breakRowWidth, NVGtextRow* rows, int maxRows);
|
||||
|
||||
//
|
||||
// Internal Render API
|
||||
//
|
||||
enum NVGtexture {
|
||||
NVG_TEXTURE_ALPHA = 0x01,
|
||||
NVG_TEXTURE_RGBA = 0x02,
|
||||
};
|
||||
|
||||
struct NVGscissor {
|
||||
float xform[6];
|
||||
float extent[2];
|
||||
};
|
||||
typedef struct NVGscissor NVGscissor;
|
||||
|
||||
struct NVGvertex {
|
||||
float x,y,u,v;
|
||||
};
|
||||
typedef struct NVGvertex NVGvertex;
|
||||
|
||||
struct NVGpath {
|
||||
int first;
|
||||
int count;
|
||||
unsigned char closed;
|
||||
int nbevel;
|
||||
NVGvertex* fill;
|
||||
int nfill;
|
||||
NVGvertex* stroke;
|
||||
int nstroke;
|
||||
int winding;
|
||||
int convex;
|
||||
};
|
||||
typedef struct NVGpath NVGpath;
|
||||
|
||||
struct NVGparams {
|
||||
void* userPtr;
|
||||
int edgeAntiAlias;
|
||||
int (*renderCreate)(void* uptr);
|
||||
int (*renderCreateTexture)(void* uptr, int type, int w, int h, int imageFlags, const unsigned char* data);
|
||||
int (*renderDeleteTexture)(void* uptr, int image);
|
||||
int (*renderUpdateTexture)(void* uptr, int image, int x, int y, int w, int h, const unsigned char* data);
|
||||
int (*renderGetTextureSize)(void* uptr, int image, int* w, int* h);
|
||||
void (*renderViewport)(void* uptr, float width, float height, float devicePixelRatio);
|
||||
void (*renderCancel)(void* uptr);
|
||||
void (*renderFlush)(void* uptr);
|
||||
void (*renderFill)(void* uptr, NVGpaint* paint, NVGcompositeOperationState compositeOperation, NVGscissor* scissor, float fringe, const float* bounds, const NVGpath* paths, int npaths);
|
||||
void (*renderStroke)(void* uptr, NVGpaint* paint, NVGcompositeOperationState compositeOperation, NVGscissor* scissor, float fringe, float strokeWidth, const NVGpath* paths, int npaths);
|
||||
void (*renderTriangles)(void* uptr, NVGpaint* paint, NVGcompositeOperationState compositeOperation, NVGscissor* scissor, const NVGvertex* verts, int nverts);
|
||||
void (*renderDelete)(void* uptr);
|
||||
};
|
||||
typedef struct NVGparams NVGparams;
|
||||
|
||||
// Constructor and destructor, called by the render back-end.
|
||||
NVGcontext* nvgCreateInternal(NVGparams* params);
|
||||
void nvgDeleteInternal(NVGcontext* ctx);
|
||||
|
||||
NVGparams* nvgInternalParams(NVGcontext* ctx);
|
||||
|
||||
// Debug function to dump cached path data.
|
||||
void nvgDebugDumpPathCache(NVGcontext* ctx);
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
#define NVG_NOTUSED(v) for (;;) { (void)(1 ? (void)0 : ( (void)(v) ) ); break; }
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // NANOVG_H
|
||||