mirror of
https://github.com/flyinghead/flycast.git
synced 2026-11-08 01:48:31 -10:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
392a429e8b | ||
|
|
0491f2e6a5 | ||
|
|
33d9a58cf9 | ||
|
|
401332d520 | ||
|
|
8511d1ad3c | ||
|
|
d794b53512 | ||
|
|
594d82b223 | ||
|
|
74cbee908f | ||
|
|
4886dcb1c2 | ||
|
|
16fc172ffc | ||
|
|
dfb2ae8987 | ||
|
|
4529a31372 | ||
|
|
5a29ac489f | ||
|
|
c4c3c2ae93 | ||
|
|
f65907a256 | ||
|
|
37a9077304 | ||
|
|
27a913fc02 | ||
|
|
97442c0411 | ||
|
|
5b12f9ca68 | ||
|
|
6a298289a9 | ||
|
|
59ef8579d2 | ||
|
|
14f759eeb7 | ||
|
|
230d971d4d | ||
|
|
5a150f4121 | ||
|
|
f178e5d76e | ||
|
|
9222fa8442 | ||
|
|
77359cefb2 | ||
|
|
a6dc38a35b | ||
|
|
eab952fcbe | ||
|
|
1666eb0875 | ||
|
|
5bce763f66 | ||
|
|
0f4fca415b | ||
|
|
f2fe918379 | ||
|
|
a9be4d111c | ||
|
|
ce07a7fbf5 | ||
|
|
e44c03fa0e | ||
|
|
1dac3695fd | ||
|
|
997f6179dd | ||
|
|
bed524f0d0 | ||
|
|
410b37b041 | ||
|
|
ead4b51d6f | ||
|
|
043bb5ee99 | ||
|
|
4747e61908 | ||
|
|
548cf6fe2e | ||
|
|
339d288dfb | ||
|
|
8f7e4bf2d3 | ||
|
|
922ca3e54b | ||
|
|
4b09de2fc1 | ||
|
|
98db7a6cd5 | ||
|
|
3405b5b2a6 | ||
|
|
4320685ff8 | ||
|
|
cd3fe7393c | ||
|
|
2da0d392fd | ||
|
|
8d1bf3382c | ||
|
|
b1489d665e | ||
|
|
fc56bd283e | ||
|
|
807e4a20ed | ||
|
|
943311752e | ||
|
|
e7ad12b031 | ||
|
|
b2bc6251c7 | ||
|
|
6f38dc3210 | ||
|
|
4bb32466bd | ||
|
|
e26d356265 | ||
|
|
265c5c6c3d | ||
|
|
2b1eb55daa | ||
|
|
bd136b1856 | ||
|
|
bd8adf1da1 | ||
|
|
11625176c2 | ||
|
|
c64441a02f | ||
|
|
8e9eee246d | ||
|
|
d0ec876936 | ||
|
|
b19cbcbf29 | ||
|
|
bf2bd7efed | ||
|
|
d15d5be44a | ||
|
|
70c8d1d22b | ||
|
|
3917c0181b | ||
|
|
6f58d204b6 | ||
|
|
d450c84a14 | ||
|
|
3b7036d14a | ||
|
|
5d628f8167 | ||
|
|
d1ed878446 | ||
|
|
28ea3dc69c | ||
|
|
031a645ffc | ||
|
|
0a526d7c94 | ||
|
|
3d594054eb | ||
|
|
3b651463dc | ||
|
|
4e6b5b270b | ||
|
|
fd8f2e24b8 | ||
|
|
82b4c55f09 | ||
|
|
8176646c5a | ||
|
|
3f0dd626c1 | ||
|
|
8edd8fc447 | ||
|
|
0c7dca9cb7 | ||
|
|
086e8bc20c | ||
|
|
11880bca30 | ||
|
|
37187467e7 | ||
|
|
7b0c106fc2 | ||
|
|
fd654614ae | ||
|
|
4ee24ca612 | ||
|
|
4b3704953f | ||
|
|
6ea9a34e8a | ||
|
|
c018d46d00 | ||
|
|
400da2bdfe | ||
|
|
3b5536dd43 | ||
|
|
34e2f426ac | ||
|
|
a246964a99 | ||
|
|
b4b4b3ab1e | ||
|
|
af5f67c15d | ||
|
|
909ea496ac | ||
|
|
3347dc1a46 | ||
|
|
dd5e148e2b | ||
|
|
1f818ca750 | ||
|
|
ab6b95ff4d | ||
|
|
760c62a3da | ||
|
|
b2d8ad633d | ||
|
|
f9b47b6f91 | ||
|
|
372ef91211 | ||
|
|
3375f6c476 | ||
|
|
c5396a041e | ||
|
|
851dd22664 | ||
|
|
ac32a80352 | ||
|
|
eff11d6a07 | ||
|
|
b6c135b0c6 | ||
|
|
0fe7073496 | ||
|
|
d5c5839a92 | ||
|
|
7ac45a7e46 | ||
|
|
0243f81c26 | ||
|
|
2dfa647445 | ||
|
|
9c5408a6d3 | ||
|
|
d3dcb13ef9 | ||
|
|
2cb2ac23e0 | ||
|
|
e38b0ac01f | ||
|
|
09b27ddd5c | ||
|
|
33833cfd1e | ||
|
|
3c5c1e0b66 | ||
|
|
3f446a5835 | ||
|
|
df3c676a04 | ||
|
|
9ff3ab618c | ||
|
|
ba33b8c3f7 | ||
|
|
eab13e85bc | ||
|
|
a1f1c9825a | ||
|
|
43a9c1384a | ||
|
|
b4ab21a768 | ||
|
|
30365d13ef | ||
|
|
f7eae0ff9e | ||
|
|
e26f170558 | ||
|
|
40e400ab08 | ||
|
|
5743502cdd | ||
|
|
8f33b63153 | ||
|
|
6fca05f00e | ||
|
|
8c07a2e1d6 | ||
|
|
ffbe266413 | ||
|
|
5d3b7fae6b | ||
|
|
738b95d2be | ||
|
|
48c58dbd18 | ||
|
|
54b06a5c34 | ||
|
|
d3a46a1e33 | ||
|
|
4fe2f4760f | ||
|
|
c0809d771d | ||
|
|
54ed92e2b0 | ||
|
|
6ea61b9084 | ||
|
|
f3e0f09ca9 | ||
|
|
301b1a0f00 | ||
|
|
b787427446 | ||
|
|
5df5c70994 | ||
|
|
75defb590b | ||
|
|
fbeaf8ba16 | ||
|
|
3f79b6baed | ||
|
|
34f095a91e | ||
|
|
09247b4503 | ||
|
|
109e084e18 | ||
|
|
af043c55cd | ||
|
|
04999d8969 | ||
|
|
26b8684e78 | ||
|
|
eefcb0e05d | ||
|
|
449d256995 | ||
|
|
0897f0ed8a | ||
|
|
9bdb90e605 | ||
|
|
5b75975237 | ||
|
|
c73336a86f | ||
|
|
27318443a7 | ||
|
|
df93c069f2 | ||
|
|
7358f29556 | ||
|
|
8801b2ae16 | ||
|
|
b10db5a078 | ||
|
|
71341a27e4 | ||
|
|
7e7f645f37 | ||
|
|
146e90dae6 | ||
|
|
bb5bd71437 | ||
|
|
e8217ca0c5 | ||
|
|
8f033723a1 | ||
|
|
b097aa3331 | ||
|
|
64b9e51af0 | ||
|
|
9b91430513 | ||
|
|
d9ec0cb3ab | ||
|
|
39d68ec7fa | ||
|
|
a1a782df38 | ||
|
|
acc106e988 | ||
|
|
11de0eda13 | ||
|
|
a7148ad7ae | ||
|
|
27f19a5b54 | ||
|
|
b973453317 | ||
|
|
ffaada9e9d | ||
|
|
1953eb0eea | ||
|
|
c3275d3c6f | ||
|
|
5e769d5cd2 | ||
|
|
f26e10e44a | ||
|
|
3d60fc8c60 | ||
|
|
7adeb53aee | ||
|
|
eacadf24a6 | ||
|
|
8e14c7f394 | ||
|
|
a842edb09e | ||
|
|
e2247e4872 | ||
|
|
eb662da389 | ||
|
|
2b79f93d6b | ||
|
|
ffc32d2d86 | ||
|
|
892cdb7cea | ||
|
|
90ed30f70c | ||
|
|
5f4eefab58 | ||
|
|
34f8ab292f | ||
|
|
7538424efb | ||
|
|
3976fe1be2 | ||
|
|
c57b2e1aa7 | ||
|
|
9cc3d1030d | ||
|
|
48e964235c | ||
|
|
e148fabeae | ||
|
|
d3b8a67cba | ||
|
|
03f2ef6df0 | ||
|
|
e1ab9af89d | ||
|
|
3330225de4 | ||
|
|
58ce9a4159 | ||
|
|
1b5c8678a4 | ||
|
|
c20ec680a8 | ||
|
|
57cc7b4a60 | ||
|
|
cdef7f7444 | ||
|
|
f62582a4bd | ||
|
|
30e1a858da | ||
|
|
b04f0eb530 | ||
|
|
ef3d3bd246 | ||
|
|
2ca596ae20 | ||
|
|
1273c06d4b | ||
|
|
25a882341d | ||
|
|
75064f5683 | ||
|
|
93aaf50b4f | ||
|
|
332be9c8aa | ||
|
|
77776be20b | ||
|
|
f7676faa68 | ||
|
|
93f463296d | ||
|
|
aff64d43d4 | ||
|
|
240be07bbb | ||
|
|
786ccf4139 | ||
|
|
10a5ed6cec | ||
|
|
b9ba3f1e63 | ||
|
|
34fda43d9c | ||
|
|
b602cc9c57 | ||
|
|
63534c5d56 | ||
|
|
0267de4997 | ||
|
|
56c00b0eb5 | ||
|
|
3114394019 | ||
|
|
e5f13b6858 | ||
|
|
3193d2cf5d | ||
|
|
0f18e2e167 | ||
|
|
5908b1a84a | ||
|
|
4d6168dd0b | ||
|
|
2d1c602a69 | ||
|
|
130675aae3 | ||
|
|
75d5cc4d63 | ||
|
|
5a110fd666 | ||
|
|
13436a4dda | ||
|
|
2631706fe2 | ||
|
|
ea6d5f8732 | ||
|
|
305cae496f | ||
|
|
416085980f | ||
|
|
8b35fb80b4 | ||
|
|
5c1249c55f | ||
|
|
fac44e4a2f | ||
|
|
4ea317d51f | ||
|
|
310d5e612e | ||
|
|
62778b1a68 | ||
|
|
604415b0d2 | ||
|
|
49ea1135ee | ||
|
|
46e2d52b75 | ||
|
|
44f77408e4 | ||
|
|
2860aa96f4 | ||
|
|
8b0a5fa480 | ||
|
|
b150ba2b62 | ||
|
|
48bce25820 | ||
|
|
562f78cd71 | ||
|
|
9e0573aa98 | ||
|
|
d23b3b6bc7 | ||
|
|
1d9f8ab438 | ||
|
|
df3c075fba | ||
|
|
9cdd0aab9f | ||
|
|
e4d9220f3f | ||
|
|
0bf9c64b1b | ||
|
|
4e74619d9e | ||
|
|
0414a90500 | ||
|
|
5866e97d18 | ||
|
|
387e2427b4 | ||
|
|
5187258f4b | ||
|
|
e1da1c3a55 | ||
|
|
84356e3b26 | ||
|
|
c7499df3a8 | ||
|
|
03f7a0f605 | ||
|
|
f3c838d19d | ||
|
|
d6f3ca986d | ||
|
|
b9df7d3469 | ||
|
|
bf1d4a56ae | ||
|
|
a682e20bbd | ||
|
|
5b9dd96064 | ||
|
|
a99a72589b | ||
|
|
77ed9c20de | ||
|
|
7cb0fe53d7 | ||
|
|
3db0fce9b6 | ||
|
|
6a15e7a3aa | ||
|
|
431d71de5e | ||
|
|
914fa29d31 | ||
|
|
c143cae09b | ||
|
|
a35e8214df | ||
|
|
d84108de32 | ||
|
|
1513c6cab8 | ||
|
|
34104724a6 | ||
|
|
b70c2791b2 | ||
|
|
ccdd53ee0e | ||
|
|
57a3e4ca53 | ||
|
|
b92ac1544e | ||
|
|
26d386f833 | ||
|
|
ce0060126e | ||
|
|
4389a3ffa6 | ||
|
|
b3fa453d75 | ||
|
|
32c274f407 | ||
|
|
cb2d3e3776 | ||
|
|
28f5dd983e | ||
|
|
160828a4c7 | ||
|
|
aee932808e | ||
|
|
77636391fc | ||
|
|
944af44c7f | ||
|
|
5c27648699 | ||
|
|
7ef35eaf68 | ||
|
|
bb733323ce | ||
|
|
1b6bf25e7a | ||
|
|
aa65b81f89 | ||
|
|
da9f030a0e | ||
|
|
a0e1eb0005 | ||
|
|
5cc15429cd | ||
|
|
18656f5986 | ||
|
|
536be34853 | ||
|
|
5b513cac5b | ||
|
|
5efdf58e85 | ||
|
|
a93f3697d6 | ||
|
|
b98e833c57 | ||
|
|
2e89848041 | ||
|
|
bb4ba3ed89 | ||
|
|
a5a338d408 | ||
|
|
3114344414 | ||
|
|
20ba79668f | ||
|
|
7a4f9d8667 | ||
|
|
22bff1b017 | ||
|
|
9344856c7e | ||
|
|
b2c1d134e1 | ||
|
|
160d3e7ef3 | ||
|
|
3cf4808033 | ||
|
|
1bd894f941 | ||
|
|
8dc55721d0 | ||
|
|
c94deaee9d | ||
|
|
95583583ca | ||
|
|
42752acef5 | ||
|
|
45c700ab60 | ||
|
|
a3902fc278 | ||
|
|
0606f3e63e | ||
|
|
0558c957e8 | ||
|
|
2ca9187137 | ||
|
|
5add29cbed | ||
|
|
5a1c3f80f5 | ||
|
|
a0e8e9a9df | ||
|
|
45f4378184 | ||
|
|
c7d030c2e6 | ||
|
|
2bee6b1ce4 | ||
|
|
522505273e | ||
|
|
0481f5464d | ||
|
|
7478476f9c | ||
|
|
76c3695f6e | ||
|
|
e18ada7225 | ||
|
|
f3a33642f8 | ||
|
|
2f03c1b147 | ||
|
|
b7e2f5e489 | ||
|
|
d01cbde41c | ||
|
|
11068012fe | ||
|
|
a06791780d | ||
|
|
ee1a7167f6 | ||
|
|
10aaec1619 | ||
|
|
32d8d9a8c3 | ||
|
|
553f77c675 | ||
|
|
9402981b43 | ||
|
|
9038ef6d8a | ||
|
|
1d290560e0 | ||
|
|
59e844db15 | ||
|
|
6853238c8b | ||
|
|
f0aa1abf89 | ||
|
|
cfd3677746 | ||
|
|
50a10598e4 | ||
|
|
9bfd48cf40 | ||
|
|
b72750c7d5 | ||
|
|
b9fdd5070b | ||
|
|
6c3d77b012 | ||
|
|
7fee0d2d29 | ||
|
|
dfd4dbebc4 | ||
|
|
34a5e7f47d | ||
|
|
3f8d645c42 | ||
|
|
ecd0305a60 | ||
|
|
667e3906d8 | ||
|
|
e5b1d56a7c | ||
|
|
d789b57412 | ||
|
|
825778445a | ||
|
|
20517cf0da | ||
|
|
989d3b1370 | ||
|
|
421245aeba | ||
|
|
686f08e7dd | ||
|
|
4af1d096de | ||
|
|
27a0497dd5 | ||
|
|
9ea0563a7a | ||
|
|
a46677e64e | ||
|
|
a7f2008763 | ||
|
|
53e0f12c22 | ||
|
|
34961daaec | ||
|
|
f5389bcd0b | ||
|
|
67eee05c14 | ||
|
|
bb1b1059d4 | ||
|
|
94f35ca54f | ||
|
|
1507097bcd | ||
|
|
e4599e36ed | ||
|
|
15617c1816 | ||
|
|
fb64fc418e | ||
|
|
5656370388 | ||
|
|
354d649ebd | ||
|
|
fff03f64a3 | ||
|
|
a99aa5217b | ||
|
|
89abb7925b | ||
|
|
dea8e74182 | ||
|
|
92c5892d4c | ||
|
|
21f9e9fbc2 | ||
|
|
78fa3ee09e | ||
|
|
de1584d97c | ||
|
|
a40c51e682 | ||
|
|
c860807fef | ||
|
|
b91f82c7e5 | ||
|
|
d38ce47081 | ||
|
|
5f55a9fd3f | ||
|
|
a085fd2f6d | ||
|
|
36c2f5137c | ||
|
|
5e9c168fc9 | ||
|
|
59c2343cad | ||
|
|
b42387e929 | ||
|
|
df78a781ec | ||
|
|
974dc2e233 | ||
|
|
6bf38e5085 | ||
|
|
792aa38d34 | ||
|
|
516982c66c | ||
|
|
a9fa33c17a | ||
|
|
d0584b8652 | ||
|
|
58c8a33d11 | ||
|
|
b4dcc64ef6 | ||
|
|
7531f5df20 | ||
|
|
c4d77165a6 | ||
|
|
aa95c71ead | ||
|
|
6612e3fef8 | ||
|
|
fbd52a72d4 | ||
|
|
d618abc320 | ||
|
|
b7163dda83 | ||
|
|
d259a2e2f5 | ||
|
|
e2f8de33e8 | ||
|
|
42ad5532b2 | ||
|
|
1e30f483c2 | ||
|
|
bdd2d5af7f | ||
|
|
76638df001 | ||
|
|
3efb87ba6d | ||
|
|
c9f238362d | ||
|
|
129673a84b | ||
|
|
7c1c5817d3 | ||
|
|
e394840344 | ||
|
|
fc33002284 | ||
|
|
dff967f60a | ||
|
|
a3708a7e95 | ||
|
|
1cadeb276e | ||
|
|
2b28e819e5 | ||
|
|
db846ca933 | ||
|
|
9cb7d9e5d5 | ||
|
|
93ae9d0375 | ||
|
|
e03e11b8a9 | ||
|
|
52df0133f0 | ||
|
|
d5aeb482d9 | ||
|
|
7eec648690 | ||
|
|
897e06b887 | ||
|
|
aa38771cd0 | ||
|
|
c77ddba109 | ||
|
|
cd8a88366d | ||
|
|
f892630e4b | ||
|
|
9d4d486524 | ||
|
|
d8a3ee9c3a | ||
|
|
fc6142b332 | ||
|
|
5fc84acdfb | ||
|
|
037dc3b4b9 | ||
|
|
96aac66133 | ||
|
|
4d5ced1ce6 | ||
|
|
da3cfd9d58 | ||
|
|
65aadb9dcb | ||
|
|
cec46990ea | ||
|
|
2e5309bfa3 | ||
|
|
742090bb1f | ||
|
|
f3a64e5891 | ||
|
|
32ccb754ff | ||
|
|
32d11dd89c | ||
|
|
760813e45a | ||
|
|
e221f6fed2 |
No files matched your search
@@ -4,13 +4,14 @@ on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: Android
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Set up build environment
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get -y install ccache libcurl4-openssl-dev ninja-build
|
||||
sudo apt-get -y install ccache cmake libcurl4-openssl-dev ninja-build
|
||||
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
@@ -69,20 +70,16 @@ jobs:
|
||||
mv libflycast.so.sym symbols/libflycast.so/$BUILD_ID
|
||||
done
|
||||
|
||||
- name: Configure AWS Credentials
|
||||
id: aws-credentials
|
||||
uses: aws-actions/configure-aws-credentials@v4
|
||||
- name: Setup Rclone
|
||||
uses: AnimMouse/setup-rclone@v1
|
||||
with:
|
||||
aws-access-key-id: AKIAJOZQS4H2PHQWYFCA
|
||||
aws-secret-access-key: ${{ secrets.S3_SECRET_KEY }}
|
||||
aws-region: us-east-2
|
||||
if: github.repository == 'flyinghead/flycast' && github.event_name == 'push'
|
||||
rclone_config: ${{ secrets.RCLONE_CONFIG }}
|
||||
|
||||
- name: Upload to S3
|
||||
run: |
|
||||
cp shell/android-studio/flycast/build/outputs/bundle/release/*.aab shell/android-studio/flycast/build/outputs/apk/release/
|
||||
aws s3 sync shell/android-studio/flycast/build/outputs/apk/release s3://flycast-builds/android/${GITHUB_REF#refs/}-$GITHUB_SHA --acl public-read --exclude='*.json' --follow-symlinks
|
||||
if: ${{ steps.aws-credentials.outputs.aws-account-id != '' }}
|
||||
rclone copy shell/android-studio/flycast/build/outputs/apk/release scaleway:flycast-builds/android/${GITHUB_REF#refs/}-$GITHUB_SHA --exclude '*.json'
|
||||
if: github.repository == 'flyinghead/flycast' && github.event_name == 'push'
|
||||
|
||||
- name: Setup Sentry CLI
|
||||
uses: mathieu-bour/setup-sentry-cli@v2
|
||||
|
||||
@@ -13,14 +13,14 @@ jobs:
|
||||
architecture: [ arm64, x86-64 ]
|
||||
include:
|
||||
- operating_system: freebsd
|
||||
version: '14.1'
|
||||
pkginstall: sudo pkg install -y alsa-lib ccache cmake evdev-proto git libao libevdev libudev-devd libzip lua54 miniupnpc ninja pkgconf pulseaudio sdl2
|
||||
version: '14.3'
|
||||
pkginstall: sudo pkg update && sudo pkg install -y alsa-lib ccache cmake evdev-proto git libao libevdev libudev-devd libzip lua54 miniupnpc ninja pkgconf pulseaudio sdl2 libcdio
|
||||
- operating_system: netbsd
|
||||
version: '10.0'
|
||||
pkginstall: sudo pkgin update && sudo pkgin -y install alsa-lib ccache cmake gcc12 git libao libzip lua54 miniupnpc ninja-build pkgconf pulseaudio SDL2 && export PATH=/usr/pkg/gcc12/bin:$PATH
|
||||
version: '10.1'
|
||||
pkginstall: sudo pkgin update && sudo pkgin -y install alsa-lib ccache clang cmake git libao libzip lua54 miniupnpc ninja-build pkgconf pulseaudio SDL2 libcdio
|
||||
- operating_system: openbsd
|
||||
version: '7.5'
|
||||
pkginstall: sudo pkg_add ccache cmake git libao libzip miniupnpc ninja pkgconf pulseaudio sdl2
|
||||
version: '7.7'
|
||||
pkginstall: sudo pkg_add -u && sudo pkg_add ccache cmake git libao libzip miniupnpc ninja pkgconf pulseaudio sdl2 libcdio
|
||||
exclude:
|
||||
- architecture: arm64
|
||||
|
||||
@@ -36,7 +36,7 @@ jobs:
|
||||
key: ccache-${{ matrix.operating_system }}-${{ matrix.architecture }}-${{ github.sha }}
|
||||
restore-keys: ccache-${{ matrix.operating_system }}-${{ matrix.architecture }}-
|
||||
|
||||
- uses: cross-platform-actions/[email protected]5.0
|
||||
- uses: cross-platform-actions/[email protected]9.0
|
||||
with:
|
||||
operating_system: ${{ matrix.operating_system }}
|
||||
architecture: ${{ matrix.architecture }}
|
||||
@@ -44,5 +44,5 @@ jobs:
|
||||
environment_variables: CCACHE_DIR
|
||||
run: |
|
||||
${{ matrix.pkginstall }}
|
||||
cmake -B build -DCMAKE_BUILD_TYPE=Release -G Ninja
|
||||
cmake -B build -DUSE_LIBCDIO=ON -DCMAKE_BUILD_TYPE=Release -G Ninja
|
||||
cmake --build build --config Release
|
||||
+18
-25
@@ -19,12 +19,11 @@ jobs:
|
||||
config:
|
||||
- {name: i686-pc-windows-msvc, os: windows-latest, shell: cmd, arch: x86, cmakeArgs: -G Ninja, buildType: Release}
|
||||
- {name: apple-darwin, os: macos-latest, shell: sh, cmakeArgs: -G Xcode -DUSE_DISCORD=ON, destDir: osx, buildType: RelWithDebInfo}
|
||||
- {name: apple-ios, os: macos-latest, shell: sh, cmakeArgs: -DCMAKE_SYSTEM_NAME=iOS -G Xcode, destDir: ios, buildType: Release}
|
||||
- {name: x86_64-pc-linux-gnu, os: ubuntu-20.04, shell: sh, cmakeArgs: -G Ninja -DUSE_DISCORD=ON, destDir: linux, buildType: RelWithDebInfo}
|
||||
- {name: x86_64-pc-linux-gnu, os: ubuntu-22.04, shell: sh, cmakeArgs: -G Ninja -DUSE_DISCORD=ON -DUSE_LIBCDIO=ON, destDir: linux, buildType: RelWithDebInfo}
|
||||
- {name: x86_64-pc-windows-msvc, os: windows-latest, shell: cmd, arch: x64, cmakeArgs: -G Ninja -DUSE_DISCORD=ON, buildType: Release}
|
||||
- {name: x86_64-w64-mingw32, os: windows-latest, shell: 'msys2 {0}', cmakeArgs: -G Ninja -DUSE_DISCORD=ON, destDir: win, buildType: RelWithDebInfo}
|
||||
- {name: libretro-x86_64-pc-linux-gnu, os: ubuntu-latest, shell: sh, cmakeArgs: -DLIBRETRO=ON -DCMAKE_POSITION_INDEPENDENT_CODE=TRUE -G Ninja, buildType: Release}
|
||||
- {name: libretro-x86_64-w64-mingw32, os: windows-latest, shell: 'msys2 {0}', cmakeArgs: -DLIBRETRO=ON -G Ninja, buildType: Release}
|
||||
- {name: x86_64-w64-mingw32, os: windows-latest, shell: 'msys2 {0}', cmakeArgs: -G Ninja -DUSE_DISCORD=ON -DUSE_LIBCDIO=ON, destDir: win, buildType: RelWithDebInfo}
|
||||
- {name: libretro-x86_64-pc-linux-gnu, os: ubuntu-22.04, shell: sh, cmakeArgs: -DLIBRETRO=ON -DUSE_LIBCDIO=ON -DCMAKE_POSITION_INDEPENDENT_CODE=TRUE -G Ninja, buildType: Release}
|
||||
- {name: libretro-x86_64-w64-mingw32, os: windows-latest, shell: 'msys2 {0}', cmakeArgs: -DLIBRETRO=ON -DUSE_LIBCDIO=ON -G Ninja, buildType: Release}
|
||||
|
||||
steps:
|
||||
- name: Set up build environment (macOS)
|
||||
@@ -32,9 +31,9 @@ jobs:
|
||||
# Unlink and re-link to prevent errors when github mac runner images install python outside of brew. See https://github.com/actions/setup-python/issues/577
|
||||
brew list -1 | grep python | while read formula; do brew unlink $formula; brew link --overwrite $formula; done
|
||||
brew update || :
|
||||
brew install libao ldid ninja pulseaudio
|
||||
brew install libao ldid pulseaudio
|
||||
brew uninstall --ignore-dependencies zstd
|
||||
VULKAN_VER=1.3.261.1 && aria2c https://sdk.lunarg.com/sdk/download/$VULKAN_VER/mac/vulkansdk-macos-$VULKAN_VER.dmg
|
||||
VULKAN_VER=1.3.290.0 && aria2c https://sdk.lunarg.com/sdk/download/$VULKAN_VER/mac/vulkansdk-macos-$VULKAN_VER.dmg
|
||||
hdiutil attach ./vulkansdk-macos-*.dmg -mountpoint /Volumes/VulkanSDK
|
||||
sudo /Volumes/VulkanSDK/InstallVulkan.app/Contents/MacOS/InstallVulkan --root $HOME/VulkanSDK --accept-licenses --default-answer --confirm-command install
|
||||
hdiutil detach /Volumes/VulkanSDK
|
||||
@@ -45,7 +44,7 @@ jobs:
|
||||
run: |
|
||||
sudo add-apt-repository ppa:christianrauch/libdecoration
|
||||
sudo apt-get update
|
||||
sudo apt-get -y install ccache libao-dev libasound2-dev libevdev-dev libgl1-mesa-dev liblua5.3-dev libminiupnpc-dev libpulse-dev libsdl2-dev libudev-dev libzip-dev ninja-build libcurl4-openssl-dev
|
||||
sudo apt-get -y install ccache libao-dev libasound2-dev libevdev-dev libgl1-mesa-dev liblua5.3-dev libminiupnpc-dev libpulse-dev libsdl2-dev libudev-dev libzip-dev ninja-build libcurl4-openssl-dev libcdio-dev libfuse2
|
||||
sudo apt-get -y install libwayland-dev libdecor-0-dev libaudio-dev libjack-dev libsndio-dev libsamplerate0-dev libx11-dev libxext-dev libxrandr-dev libxcursor-dev libxfixes-dev libxi-dev libxss-dev libxkbcommon-dev libdrm-dev libgbm-dev libgles2-mesa-dev libegl1-mesa-dev libdbus-1-dev libibus-1.0-dev libudev-dev fcitx-libs-dev
|
||||
if: runner.os == 'Linux'
|
||||
|
||||
@@ -53,7 +52,7 @@ jobs:
|
||||
uses: msys2/setup-msys2@v2
|
||||
with:
|
||||
msystem: MINGW64
|
||||
install: git make mingw-w64-x86_64-ccache mingw-w64-x86_64-cmake mingw-w64-x86_64-lua mingw-w64-x86_64-ninja mingw-w64-x86_64-SDL2 mingw-w64-x86_64-toolchain
|
||||
install: git make mingw-w64-x86_64-ccache mingw-w64-x86_64-cmake mingw-w64-x86_64-lua mingw-w64-x86_64-ninja mingw-w64-x86_64-SDL2 mingw-w64-x86_64-toolchain mingw-w64-x86_64-libcdio
|
||||
if: matrix.config.shell == 'msys2 {0}'
|
||||
|
||||
- name: Set up build environment (Windows, Visual Studio)
|
||||
@@ -73,13 +72,9 @@ jobs:
|
||||
submodules: recursive
|
||||
|
||||
- name: Compile a universal OpenMP (macOS)
|
||||
run: HOMEBREW_NO_INSTALLED_DEPENDENTS_CHECK=1 brew reinstall --build-from-source --formula ./shell/apple/libomp.rb
|
||||
run: HOMEBREW_NO_INSTALLED_DEPENDENTS_CHECK=1 HOMEBREW_DEVELOPER=1 brew reinstall --build-from-source --formula ./shell/apple/libomp.rb
|
||||
if: matrix.config.name == 'apple-darwin'
|
||||
|
||||
- name: Compile OpenMP.xcframework (iOS)
|
||||
run: ./shell/apple/emulator-ios/OpenMP/build_ios_openmp.sh --disableSimulator
|
||||
if: matrix.config.name == 'apple-ios'
|
||||
|
||||
- uses: actions/cache@v4
|
||||
with:
|
||||
path: ${{ env.CCACHE_DIR }}
|
||||
@@ -129,7 +124,9 @@ jobs:
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: flycast-${{ matrix.config.name }}
|
||||
path: artifact/bin
|
||||
path: |
|
||||
artifact/bin
|
||||
artifact/lib/libretro
|
||||
|
||||
- name: Package app (macos)
|
||||
run: |
|
||||
@@ -143,19 +140,15 @@ jobs:
|
||||
rm artifact/bin/flycast.exe
|
||||
if: matrix.config.name == 'x86_64-w64-mingw32'
|
||||
|
||||
- name: Configure AWS Credentials
|
||||
id: aws-credentials
|
||||
uses: aws-actions/configure-aws-credentials@v4
|
||||
- name: Setup Rclone
|
||||
uses: AnimMouse/setup-rclone@v1
|
||||
with:
|
||||
aws-access-key-id: AKIAJOZQS4H2PHQWYFCA
|
||||
aws-secret-access-key: ${{ secrets.S3_SECRET_KEY }}
|
||||
aws-region: us-east-2
|
||||
if: github.repository == 'flyinghead/flycast' && github.event_name == 'push' && matrix.config.destDir != ''
|
||||
rclone_config: ${{ secrets.RCLONE_CONFIG }}
|
||||
|
||||
- name: Upload to S3
|
||||
run: aws s3 sync artifact/bin s3://flycast-builds/${{ matrix.config.destDir }}/${GITHUB_REF#refs/}-$GITHUB_SHA --acl public-read --follow-symlinks
|
||||
run: rclone copy artifact/bin scaleway:flycast-builds/${{ matrix.config.destDir }}/${GITHUB_REF#refs/}-$GITHUB_SHA
|
||||
shell: bash
|
||||
if: ${{ steps.aws-credentials.outputs.aws-account-id != '' }}
|
||||
if: github.repository == 'flyinghead/flycast' && github.event_name == 'push' && matrix.config.destDir != ''
|
||||
|
||||
- name: Setup Sentry CLI
|
||||
uses: mathieu-bour/setup-sentry-cli@v2
|
||||
@@ -179,4 +172,4 @@ jobs:
|
||||
env:
|
||||
SENTRY_TOKEN: ${{ secrets.SENTRY_TOKEN }}
|
||||
if: ${{ env.SENTRY_TOKEN != '' && (matrix.config.name == 'x86_64-w64-mingw32' || matrix.config.name == 'apple-darwin' || matrix.config.name == 'x86_64-pc-linux-gnu') }}
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: ${{ matrix.config.name }}
|
||||
name: Switch ${{ matrix.config.name }}
|
||||
runs-on: ubuntu-latest
|
||||
container: devkitpro/devkita64:latest
|
||||
|
||||
@@ -18,7 +18,7 @@ jobs:
|
||||
- name: Set up build environment
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get -y install awscli ccache
|
||||
sudo apt-get -y install ccache cmake
|
||||
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
@@ -42,21 +42,20 @@ jobs:
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: flycast-switch-${{ matrix.config.name }}
|
||||
path: artifact/bin
|
||||
path: |
|
||||
artifact/bin
|
||||
artifact/lib/libretro
|
||||
|
||||
- name: Package app
|
||||
run: zip -m artifact/bin/flycast.nro.zip artifact/bin/flycast.nro
|
||||
if: hashFiles('artifact/bin/flycast.nro') != ''
|
||||
|
||||
- name: Configure AWS Credentials
|
||||
id: aws-credentials
|
||||
uses: aws-actions/configure-aws-credentials@v4
|
||||
- name: Setup Rclone
|
||||
uses: AnimMouse/setup-rclone@v1
|
||||
with:
|
||||
aws-access-key-id: AKIAJOZQS4H2PHQWYFCA
|
||||
aws-secret-access-key: ${{ secrets.S3_SECRET_KEY }}
|
||||
aws-region: us-east-2
|
||||
if: github.repository == 'flyinghead/flycast' && github.event_name == 'push' && matrix.config.destDir != ''
|
||||
rclone_config: ${{ secrets.RCLONE_CONFIG }}
|
||||
version: v1.69.1
|
||||
|
||||
- name: Upload to S3
|
||||
run: aws s3 sync artifact/bin s3://flycast-builds/${{ matrix.config.destDir }}/${GITHUB_REF#refs/}-$GITHUB_SHA --acl public-read --follow-symlinks
|
||||
if: ${{ steps.aws-credentials.outputs.aws-account-id != '' }}
|
||||
run: rclone copy artifact/bin scaleway:flycast-builds/${{ matrix.config.destDir }}/${GITHUB_REF#refs/}-$GITHUB_SHA
|
||||
if: github.repository == 'flyinghead/flycast' && github.event_name == 'push' && matrix.config.destDir != ''
|
||||
+13
-12
@@ -4,8 +4,13 @@ on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: UWP
|
||||
runs-on: windows-latest
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
arch: [ Win32, x64, ARM64 ]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
@@ -14,7 +19,7 @@ jobs:
|
||||
|
||||
- name: CMake
|
||||
run: |
|
||||
cmake -B build -DCMAKE_BUILD_TYPE=Release -G "Visual Studio 17 2022" -A x64 -DCMAKE_SYSTEM_NAME=WindowsStore -DCMAKE_SYSTEM_VERSION=10.0.22000.0
|
||||
cmake -B build -DCMAKE_BUILD_TYPE=Release -G "Visual Studio 17 2022" -A ${{ matrix.arch }} -DCMAKE_SYSTEM_NAME=WindowsStore -DCMAKE_SYSTEM_VERSION=10.0.22000.0
|
||||
cmake --build build --config Release -- /m
|
||||
shell: cmd
|
||||
|
||||
@@ -23,7 +28,7 @@ jobs:
|
||||
- name: Package app
|
||||
run: |
|
||||
mkdir build\artifact
|
||||
cd build\AppPackages\flycast\flycast_*_x64_Test
|
||||
cd build\AppPackages\flycast\flycast_*_Test
|
||||
mkdir tmp
|
||||
ren *.msix flycast.msix
|
||||
makeappx.exe unpack /p .\flycast.msix /d tmp
|
||||
@@ -36,19 +41,15 @@ jobs:
|
||||
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: flycast-uwp
|
||||
name: flycast-uwp-${{ matrix.arch }}
|
||||
path: build/artifact
|
||||
|
||||
- name: Configure AWS Credentials
|
||||
id: aws-credentials
|
||||
uses: aws-actions/configure-aws-credentials@v4
|
||||
- name: Setup Rclone
|
||||
uses: AnimMouse/setup-rclone@v1
|
||||
with:
|
||||
aws-access-key-id: AKIAJOZQS4H2PHQWYFCA
|
||||
aws-secret-access-key: ${{ secrets.S3_SECRET_KEY }}
|
||||
aws-region: us-east-2
|
||||
if: github.repository == 'flyinghead/flycast' && github.event_name == 'push'
|
||||
rclone_config: ${{ secrets.RCLONE_CONFIG }}
|
||||
|
||||
- name: Upload to S3
|
||||
run: aws s3 sync build/artifact s3://flycast-builds/xbox/${GITHUB_REF#refs/}-$GITHUB_SHA --acl public-read --follow-symlinks
|
||||
run: rclone copy build/artifact scaleway:flycast-builds/xbox/${GITHUB_REF#refs/}-$GITHUB_SHA
|
||||
shell: bash
|
||||
if: ${{ steps.aws-credentials.outputs.aws-account-id != '' }}
|
||||
if: github.repository == 'flyinghead/flycast' && github.event_name == 'push' && matrix.arch == 'x64'
|
||||
@@ -17,3 +17,6 @@ cmake-build-*/
|
||||
# Dependencies from .gitmodules
|
||||
core/deps/breakpad/
|
||||
core/deps/glslang/
|
||||
.cache/
|
||||
compile_commands.json
|
||||
CMakeUserPresets.json
|
||||
+15
-6
@@ -9,34 +9,38 @@
|
||||
variables:
|
||||
GIT_SUBMODULE_STRATEGY: recursive
|
||||
CORENAME: flycast
|
||||
CORE_ARGS: -DLIBRETRO=ON -DCMAKE_BUILD_TYPE=Release
|
||||
CORE_ARGS: -DLIBRETRO=ON -DUSE_LIBCDIO=ON
|
||||
|
||||
.core-defs-linux:
|
||||
extends: .core-defs
|
||||
variables:
|
||||
CORE_ARGS: -DLIBRETRO=ON -DCMAKE_POSITION_INDEPENDENT_CODE=TRUE -DCMAKE_BUILD_TYPE=Release
|
||||
CORE_ARGS: -DLIBRETRO=ON -DUSE_LIBCDIO=ON -DCMAKE_POSITION_INDEPENDENT_CODE=TRUE
|
||||
CC: /usr/bin/gcc-12
|
||||
CXX: /usr/bin/g++-12
|
||||
|
||||
.core-defs-osx-x64:
|
||||
extends: .core-defs
|
||||
variables:
|
||||
CORE_ARGS: -DLIBRETRO=ON -G Xcode -DCMAKE_BUILD_TYPE=Release -DCMAKE_OSX_ARCHITECTURES=x86_64
|
||||
CORE_ARGS: -DLIBRETRO=ON -G Xcode -DCMAKE_OSX_ARCHITECTURES=x86_64
|
||||
EXTRA_PATH: Release
|
||||
|
||||
.core-defs-osx-arm64:
|
||||
extends: .core-defs
|
||||
variables:
|
||||
CORE_ARGS: -DLIBRETRO=ON -G Xcode -DCMAKE_BUILD_TYPE=Release
|
||||
CORE_ARGS: -DLIBRETRO=ON -G Xcode
|
||||
EXTRA_PATH: Release
|
||||
|
||||
.core-defs-ios-arm64:
|
||||
extends: .core-defs
|
||||
variables:
|
||||
CORE_ARGS: -DLIBRETRO=ON -DCMAKE_BUILD_TYPE=Release
|
||||
CORE_ARGS: -DLIBRETRO=ON -DUSE_OPENMP=OFF -DCMAKE_OSX_DEPLOYMENT_TARGET=13.0
|
||||
IOS_MINVER: 13.0
|
||||
MINVER: 13.0
|
||||
|
||||
.core-defs-android:
|
||||
extends: .core-defs
|
||||
script:
|
||||
- cmake $CORE_ARGS -DANDROID_PLATFORM=android-$API_LEVEL -DCMAKE_TOOLCHAIN_FILE=$NDK_ROOT/build/cmake/android.toolchain.cmake -DANDROID_STL=c++_static -DANDROID_ABI=$ANDROID_ABI -DANDROID_ARM_MODE=arm "$CMAKE_SOURCE_ROOT" -B$BUILD_DIR
|
||||
- cmake -DLIBRETRO=ON -DUSE_OPENMP=OFF -DANDROID_PLATFORM=android-$API_LEVEL -DCMAKE_TOOLCHAIN_FILE=$NDK_ROOT/build/cmake/android.toolchain.cmake -DANDROID_STL=c++_static -DANDROID_ABI=$ANDROID_ABI -DANDROID_ARM_MODE=arm "$CMAKE_SOURCE_ROOT" -B$BUILD_DIR
|
||||
- cmake --build $BUILD_DIR --target ${CORENAME}_libretro --config Release -- -j $NUMPROC
|
||||
- mv $BUILD_DIR/${CORENAME}_libretro.so $LIBNAME
|
||||
- if [ $STRIP_CORE_LIB -eq 1 ]; then $NDK_ROOT/toolchains/llvm/prebuilt/linux-x86_64/bin/llvm-strip $LIBNAME; fi
|
||||
@@ -108,18 +112,22 @@ libretro-build-linux-x64:
|
||||
extends:
|
||||
- .libretro-linux-cmake-x86_64
|
||||
- .core-defs-linux
|
||||
image: $CI_SERVER_HOST:5050/libretro-infrastructure/libretro-build-amd64-ubuntu:backports
|
||||
|
||||
# Linux 32-bit
|
||||
libretro-build-linux-i686:
|
||||
extends:
|
||||
- .libretro-linux-cmake-x86
|
||||
- .core-defs-linux
|
||||
image: $CI_SERVER_HOST:5050/libretro-infrastructure/libretro-build-i386-ubuntu:backports
|
||||
|
||||
# MacOS 64-bit
|
||||
libretro-build-osx-x64:
|
||||
extends:
|
||||
- .libretro-osx-cmake-x86
|
||||
- .core-defs-osx-x64
|
||||
tags:
|
||||
- mac-apple-silicon
|
||||
|
||||
# MacOS arm 64-bit
|
||||
libretro-build-osx-arm64:
|
||||
@@ -169,3 +177,4 @@ libretro-build-tvos-arm64:
|
||||
extends:
|
||||
- .libretro-tvos-cmake-arm64
|
||||
- .core-defs-ios-arm64
|
||||
|
||||
+19
-1
@@ -3,7 +3,7 @@
|
||||
url = https://github.com/libsdl-org/SDL.git
|
||||
[submodule "core/deps/libchdr"]
|
||||
path = core/deps/libchdr
|
||||
url = https://github.com/rtissera/libchdr.git
|
||||
url = https://github.com/flyinghead/libchdr.git
|
||||
ignore = dirty
|
||||
[submodule "core/deps/luabridge"]
|
||||
path = core/deps/luabridge
|
||||
@@ -41,3 +41,21 @@
|
||||
[submodule "core/deps/googletest"]
|
||||
path = core/deps/googletest
|
||||
url = https://github.com/google/googletest.git
|
||||
[submodule "core/deps/asio"]
|
||||
path = core/deps/asio
|
||||
url = https://github.com/flyinghead/asio.git
|
||||
[submodule "core/deps/xbyak"]
|
||||
path = core/deps/xbyak
|
||||
url = https://github.com/herumi/xbyak.git
|
||||
[submodule "core/deps/libjuice"]
|
||||
path = core/deps/libjuice
|
||||
url = https://github.com/paullouisageneau/libjuice.git
|
||||
[submodule "core/deps/websocketpp"]
|
||||
path = core/deps/websocketpp
|
||||
url = https://github.com/zaphoyd/websocketpp.git
|
||||
[submodule "core/deps/DreamPicoPort-API"]
|
||||
path = core/deps/DreamPicoPort-API
|
||||
url = https://github.com/OrangeFox86/DreamPicoPort-API.git
|
||||
[submodule "core/deps/libusb-cmake"]
|
||||
path = core/deps/libusb-cmake
|
||||
url = https://github.com/libusb/libusb-cmake.git
|
||||
+229
-494
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"version": 2,
|
||||
"configurePresets": [
|
||||
{
|
||||
"name": "clang",
|
||||
"generator": "Ninja",
|
||||
"binaryDir": "build-clang",
|
||||
"cacheVariables": {
|
||||
"CMAKE_BUILD_TYPE": "Debug",
|
||||
"CMAKE_EXPORT_COMPILE_COMMANDS": "ON"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "gcc",
|
||||
"generator": "Ninja",
|
||||
"binaryDir": "build-gcc",
|
||||
"cacheVariables": {
|
||||
"CMAKE_BUILD_TYPE": "Debug",
|
||||
"CMAKE_EXPORT_COMPILE_COMMANDS": "ON"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -6,7 +6,7 @@
|
||||
[](https://github.com/flyinghead/flycast/actions/workflows/uwp.yml)
|
||||
[](https://github.com/flyinghead/flycast/actions/workflows/bsd.yml)
|
||||
|
||||

|
||||
<img src="shell/linux/flycast.png" alt="flycast logo" width="150"/>
|
||||
|
||||
**Flycast** is a multi-platform Sega Dreamcast, Naomi, Naomi 2, and Atomiswave emulator derived from [**reicast**](https://github.com/skmp/reicast-emulator).
|
||||
|
||||
@@ -38,6 +38,10 @@ Install Flycast from [**Google Play**](https://play.google.com/store/apps/detail
|
||||
|
||||
`brew install --cask flycast`
|
||||
|
||||
### iOS
|
||||
|
||||
Due to persistent harassment from an iOS user, support for this platform has been dropped.
|
||||
|
||||
### Xbox One/Series 
|
||||
|
||||
Grab the latest build from [**the builds page**](https://flyinghead.github.io/flycast-builds/), or the [**GitHub Actions**](https://github.com/flyinghead/flycast/actions/workflows/uwp.yml). Then install it using the **Xbox Device Portal**.
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
cmrc_add_resource_library(flycast-resources ALIAS flycast::res NAMESPACE flycast)
|
||||
|
||||
cmrc_add_resources(flycast-resources
|
||||
WHENCE resources
|
||||
resources/flash/alienfnt.nvmem.zip # network settings
|
||||
resources/flash/gunsur2.nvmem.zip
|
||||
resources/flash/mazan.nvmem.zip # free play, calibrated
|
||||
resources/flash/otrigger.nvmem.zip
|
||||
resources/flash/wldkicks.nvmem.zip # free play
|
||||
resources/flash/wldkicksj.nvmem.zip # free play
|
||||
resources/flash/wldkicksu.nvmem.zip # free play
|
||||
resources/flash/f355.nvmem.zip # printer on
|
||||
resources/flash/f355twin.nvmem.zip # printer on
|
||||
resources/flash/f355twn2.nvmem.zip # printer on
|
||||
resources/flash/dirtypig.nvmem.zip # 4 players
|
||||
resources/flash/dirtypig.nvmem2.zip
|
||||
resources/flash/vf4.nvmem.zip # card all day, stage select
|
||||
resources/flash/vf4evob.nvmem.zip # card all day, stage select
|
||||
resources/flash/vf4tuned.nvmem.zip # card all day, stage select, 45 sec time limit, 3 match
|
||||
resources/flash/magicpop.nvmem.zip # debug: comm and all errors disabled
|
||||
resources/flash/ochaken.nvmem.zip # debug: comm and all errors disabled
|
||||
resources/flash/puyomedal.nvmem.zip # debug: comm and all errors disabled
|
||||
resources/flash/unomedal.nvmem.zip # debug: comm and all errors disabled
|
||||
resources/flash/westdrmg.nvmem.zip # debug: comm and all errors disabled
|
||||
resources/flash/smarinef.nvmem.zip # standard cabinet
|
||||
resources/picture/f355_print_template.png)
|
||||
|
||||
cmrc_add_resources(flycast-resources
|
||||
fonts/printer_ascii8x16.bin.zip
|
||||
fonts/printer_ascii12x24.bin.zip
|
||||
fonts/printer_kanji16x16.bin.zip
|
||||
fonts/printer_kanji24x24.bin.zip)
|
||||
|
||||
if(NOT LIBRETRO)
|
||||
cmrc_add_resources(flycast-resources
|
||||
fonts/Roboto-Medium.ttf.zip
|
||||
fonts/Roboto-Regular.ttf.zip
|
||||
fonts/fa-solid-900.ttf.zip)
|
||||
if(ANDROID OR IOS)
|
||||
cmrc_add_resources(flycast-resources
|
||||
WHENCE resources
|
||||
resources/picture/buttons.png
|
||||
resources/picture/buttons-arcade.png)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
cmrc_add_resources(flycast-resources fonts/biosfont.bin.zip)
|
||||
@@ -0,0 +1,3 @@
|
||||
target_sources(${PROJECT_NAME} PRIVATE
|
||||
achievements.cpp
|
||||
achievements.h)
|
||||
@@ -37,8 +37,9 @@
|
||||
#include <atomic>
|
||||
#include <utility>
|
||||
#include <xxhash.h>
|
||||
#include <thread>
|
||||
#include <functional>
|
||||
#include "util/worker_thread.h"
|
||||
#include "util/periodic_thread.h"
|
||||
|
||||
namespace achievements
|
||||
{
|
||||
@@ -74,10 +75,8 @@ private:
|
||||
std::string getOrDownloadImage(const char *url);
|
||||
std::pair<std::string, bool> getCachedImage(const char *url);
|
||||
void diskChange();
|
||||
void asyncTask(std::function<void()> f);
|
||||
void startThread();
|
||||
void stopThread();
|
||||
void backgroundThread();
|
||||
void asyncTask(std::function<void()>&& f);
|
||||
void stopThreads();
|
||||
|
||||
static void clientLoginWithTokenCallback(int result, const char *error_message, rc_client_t *client, void *userdata);
|
||||
static void clientLoginWithPasswordCallback(int result, const char *error_message, rc_client_t *client, void *userdata);
|
||||
@@ -112,11 +111,12 @@ private:
|
||||
std::string cachePath;
|
||||
std::unordered_map<u64, std::string> cacheMap;
|
||||
std::mutex cacheMutex;
|
||||
std::vector<std::function<void()>> tasks;
|
||||
std::mutex taskMutex;
|
||||
std::thread taskThread;
|
||||
cResetEvent resetEvent;
|
||||
bool threadRunning = false;
|
||||
WorkerThread taskThread {"RA-background"};
|
||||
|
||||
PeriodicThread idleThread { "RA-idle", [this]() {
|
||||
if (active)
|
||||
rc_client_idle(rc_client);
|
||||
}};
|
||||
};
|
||||
|
||||
bool init() {
|
||||
@@ -176,6 +176,7 @@ Achievements::Achievements()
|
||||
EventManager::listen(Event::Pause, emuEventCallback, this);
|
||||
EventManager::listen(Event::Resume, emuEventCallback, this);
|
||||
EventManager::listen(Event::DiskChange, emuEventCallback, this);
|
||||
idleThread.setPeriod(1000);
|
||||
}
|
||||
|
||||
Achievements::~Achievements()
|
||||
@@ -188,44 +189,13 @@ Achievements::~Achievements()
|
||||
term();
|
||||
}
|
||||
|
||||
void Achievements::asyncTask(std::function<void()> f)
|
||||
{
|
||||
{
|
||||
std::lock_guard<std::mutex> _(taskMutex);
|
||||
tasks.emplace_back(f);
|
||||
}
|
||||
resetEvent.Set();
|
||||
void Achievements::asyncTask(std::function<void()>&& f) {
|
||||
taskThread.run(std::move(f));
|
||||
}
|
||||
|
||||
void Achievements::startThread()
|
||||
{
|
||||
threadRunning = true;
|
||||
taskThread = std::thread(&Achievements::backgroundThread, this);
|
||||
}
|
||||
|
||||
void Achievements::stopThread()
|
||||
{
|
||||
threadRunning = false;
|
||||
resetEvent.Set();
|
||||
if (taskThread.joinable())
|
||||
taskThread.join();
|
||||
}
|
||||
|
||||
void Achievements::backgroundThread()
|
||||
{
|
||||
ThreadName _("RA-background");
|
||||
while (threadRunning)
|
||||
{
|
||||
if (!resetEvent.Wait(1000) && active && paused)
|
||||
rc_client_idle(rc_client);
|
||||
std::vector<std::function<void()>> localTasks;
|
||||
{
|
||||
std::lock_guard<std::mutex> _(taskMutex);
|
||||
std::swap(tasks, localTasks);
|
||||
}
|
||||
for (auto& f : localTasks)
|
||||
f();
|
||||
}
|
||||
void Achievements::stopThreads() {
|
||||
taskThread.stop();
|
||||
idleThread.stop();
|
||||
}
|
||||
|
||||
bool Achievements::init()
|
||||
@@ -243,7 +213,6 @@ bool Achievements::init()
|
||||
//rc_client_set_unofficial_enabled(rc_client, 0);
|
||||
//rc_client_set_spectator_mode_enabled(rc_client, 0);
|
||||
loadCache();
|
||||
startThread();
|
||||
|
||||
if (!config::AchievementsUserName.get().empty() && !config::AchievementsToken.get().empty())
|
||||
{
|
||||
@@ -301,7 +270,7 @@ void Achievements::loadCache()
|
||||
}
|
||||
|
||||
static u64 hashUrl(const char *url) {
|
||||
return XXH64(url, strlen(url), 13);
|
||||
return XXH3_64bits(url, strlen(url));
|
||||
}
|
||||
|
||||
std::pair<std::string, bool> Achievements::getCachedImage(const char *url)
|
||||
@@ -357,7 +326,7 @@ void Achievements::term()
|
||||
if (rc_client == nullptr)
|
||||
return;
|
||||
unloadGame();
|
||||
stopThread();
|
||||
stopThreads();
|
||||
rc_client_destroy(rc_client);
|
||||
rc_client = nullptr;
|
||||
}
|
||||
@@ -779,8 +748,7 @@ std::string Achievements::getGameHash()
|
||||
{
|
||||
if (settings.platform.isConsole())
|
||||
{
|
||||
const u32 diskType = libGDR_GetDiscType();
|
||||
if (diskType == NoDisk || diskType == Open)
|
||||
if (!gdr::isLoaded())
|
||||
return {};
|
||||
// Reopen the disk locally to avoid threading issues (CHD)
|
||||
try {
|
||||
@@ -814,15 +782,19 @@ std::string Achievements::getGameHash()
|
||||
return hash;
|
||||
}
|
||||
|
||||
void Achievements::pauseGame() {
|
||||
void Achievements::pauseGame()
|
||||
{
|
||||
paused = true;
|
||||
if (active)
|
||||
idleThread.start();
|
||||
}
|
||||
|
||||
void Achievements::resumeGame()
|
||||
{
|
||||
paused = false;
|
||||
if (config::EnableAchievements)
|
||||
if (config::EnableAchievements && !settings.naomi.slave)
|
||||
{
|
||||
idleThread.stop();
|
||||
loadGame();
|
||||
if (settings.raHardcoreMode && !config::AchievementsHardcoreMode)
|
||||
{
|
||||
@@ -956,15 +928,15 @@ void Achievements::unloadGame()
|
||||
paused = false;
|
||||
EventManager::unlisten(Event::VBlank, emuEventCallback, this);
|
||||
// wait for all async tasks before unloading the game
|
||||
stopThread();
|
||||
startThread();
|
||||
stopThreads();
|
||||
rc_client_unload_game(rc_client);
|
||||
settings.raHardcoreMode = false;
|
||||
}
|
||||
|
||||
void Achievements::diskChange()
|
||||
{
|
||||
if (!active)
|
||||
if (!active || settings.content.path.empty())
|
||||
// Don't unload the game when the lid is open while swapping disks
|
||||
return;
|
||||
std::string hash = getGameHash();
|
||||
if (hash == "") {
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
target_sources(${PROJECT_NAME} PRIVATE
|
||||
7zArchive.cpp
|
||||
7zArchive.h
|
||||
archive.cpp
|
||||
archive.h
|
||||
rzip.cpp
|
||||
rzip.h
|
||||
ZipArchive.cpp
|
||||
ZipArchive.h)
|
||||
@@ -0,0 +1,17 @@
|
||||
target_sources(${PROJECT_NAME} PRIVATE
|
||||
audiostream.h)
|
||||
|
||||
if(NOT LIBRETRO)
|
||||
target_sources(${PROJECT_NAME} PRIVATE
|
||||
audiobackend_alsa.cpp
|
||||
audiobackend_coreaudio.cpp
|
||||
audiobackend_directsound.cpp
|
||||
audiobackend_libao.cpp
|
||||
audiobackend_null.cpp
|
||||
audiobackend_oboe.cpp
|
||||
audiobackend_omx.cpp
|
||||
audiobackend_oss.cpp
|
||||
audiobackend_pulseaudio.cpp
|
||||
audiobackend_sdl2.cpp
|
||||
audiostream.cpp)
|
||||
endif()
|
||||
@@ -19,17 +19,20 @@ public:
|
||||
|
||||
u32 push(const void* frame, u32 samples, bool wait) override
|
||||
{
|
||||
if (wait)
|
||||
if (wait && last_time.time_since_epoch() != the_clock::duration::zero())
|
||||
{
|
||||
if (last_time.time_since_epoch() != the_clock::duration::zero())
|
||||
{
|
||||
auto fduration = std::chrono::nanoseconds(1000000000L * samples / 44100);
|
||||
auto duration = fduration - (the_clock::now() - last_time);
|
||||
auto fduration = std::chrono::nanoseconds(1'000'000'000LL * samples / 44100);
|
||||
auto duration = fduration - (the_clock::now() - last_time);
|
||||
if (duration > std::chrono::nanoseconds::zero())
|
||||
std::this_thread::sleep_for(duration);
|
||||
last_time += fduration;
|
||||
}
|
||||
else
|
||||
if (duration < -std::chrono::milliseconds(67))
|
||||
// if ~4 frames ahead, reset time (fast forward detection)
|
||||
last_time = the_clock::now();
|
||||
else
|
||||
last_time += fduration;
|
||||
}
|
||||
else {
|
||||
last_time = the_clock::now();
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -10,29 +10,87 @@ class OSSAudioBackend : public AudioBackend
|
||||
int audioFD = -1;
|
||||
int recordFD = -1;
|
||||
|
||||
static int openDevice(int flags)
|
||||
{
|
||||
const char* path = "/dev/dsp";
|
||||
int fd = open(path, flags);
|
||||
|
||||
if (fd < 0)
|
||||
ERROR_LOG(AUDIO, "OSS: open(%s) failed: %s", path, strerror(errno));
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
static bool setRate(int fd, int rate)
|
||||
{
|
||||
int tmp = rate;
|
||||
|
||||
if (ioctl(fd, SNDCTL_DSP_SPEED, &tmp) < 0)
|
||||
{
|
||||
ERROR_LOG(AUDIO, "OSS: ioctl(SNDCTL_DSP_SPEED) failed: %s", strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (tmp != rate)
|
||||
{
|
||||
ERROR_LOG(AUDIO, "OSS: sample rate unsupported: %d => %d", rate, tmp);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool setChannels(int fd, int channels)
|
||||
{
|
||||
int tmp = channels;
|
||||
|
||||
if (ioctl(fd, SNDCTL_DSP_CHANNELS, &tmp) < 0)
|
||||
{
|
||||
ERROR_LOG(AUDIO, "OSS: ioctl(SNDCTL_DSP_CHANNELS) failed: %s", strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (tmp != channels)
|
||||
{
|
||||
ERROR_LOG(AUDIO, "OSS: channels unsupported: %d => %d", channels, tmp);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool setFormat(int fd, int format)
|
||||
{
|
||||
int tmp = format;
|
||||
|
||||
if (ioctl(fd, SNDCTL_DSP_SETFMT, &tmp) < 0)
|
||||
{
|
||||
ERROR_LOG(AUDIO, "OSS: ioctl(SNDCTL_DSP_SETFMT) failed: %s", strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (tmp != format)
|
||||
{
|
||||
ERROR_LOG(AUDIO, "OSS: sample format unsupported: %#.8x => %#.8x", format, tmp);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public:
|
||||
OSSAudioBackend()
|
||||
: AudioBackend("oss", "Open Sound System") {}
|
||||
|
||||
bool init() override
|
||||
{
|
||||
audioFD = open("/dev/dsp", O_WRONLY);
|
||||
if (audioFD < 0)
|
||||
audioFD = openDevice(O_WRONLY);
|
||||
|
||||
if (audioFD < 0 || !setRate(audioFD, 44100) || !setChannels(audioFD, 2) || !setFormat(audioFD, AFMT_S16_LE))
|
||||
{
|
||||
WARN_LOG(AUDIO, "Couldn't open /dev/dsp.");
|
||||
term();
|
||||
return false;
|
||||
}
|
||||
INFO_LOG(AUDIO, "sound enabled, dsp opened for write");
|
||||
int tmp=44100;
|
||||
int err_ret;
|
||||
err_ret=ioctl(audioFD,SNDCTL_DSP_SPEED,&tmp);
|
||||
INFO_LOG(AUDIO, "set Frequency to %i, return %i (rate=%i)", 44100, err_ret, tmp);
|
||||
int channels=2;
|
||||
err_ret=ioctl(audioFD, SNDCTL_DSP_CHANNELS, &channels);
|
||||
INFO_LOG(AUDIO, "set dsp to stereo (%i => %i)", channels, err_ret);
|
||||
int format=AFMT_S16_LE;
|
||||
err_ret=ioctl(audioFD, SNDCTL_DSP_SETFMT, &format);
|
||||
INFO_LOG(AUDIO, "set dsp to %s audio (%i/%i => %i)", "16bits signed", AFMT_S16_LE, format, err_ret);
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -54,34 +112,11 @@ public:
|
||||
|
||||
bool initRecord(u32 sampling_freq) override
|
||||
{
|
||||
recordFD = open("/dev/dsp", O_RDONLY);
|
||||
if (recordFD < 0)
|
||||
recordFD = openDevice(O_RDONLY);
|
||||
|
||||
if (recordFD < 0 || !setRate(recordFD, sampling_freq) || !setChannels(recordFD, 1) || !setFormat(recordFD, AFMT_S16_NE /* Native 16 bits */ ))
|
||||
{
|
||||
INFO_LOG(AUDIO, "OSS: can't open default audio capture device");
|
||||
return false;
|
||||
}
|
||||
int tmp = AFMT_S16_NE; // Native 16 bits
|
||||
if (ioctl(recordFD, SNDCTL_DSP_SETFMT, &tmp) == -1 || tmp != AFMT_S16_NE)
|
||||
{
|
||||
INFO_LOG(AUDIO, "OSS: can't set sample format");
|
||||
close(recordFD);
|
||||
recordFD = -1;
|
||||
return false;
|
||||
}
|
||||
tmp = 1;
|
||||
if (ioctl(recordFD, SNDCTL_DSP_CHANNELS, &tmp) == -1)
|
||||
{
|
||||
INFO_LOG(AUDIO, "OSS: can't set channel count");
|
||||
close(recordFD);
|
||||
recordFD = -1;
|
||||
return false;
|
||||
}
|
||||
tmp = sampling_freq;
|
||||
if (ioctl(recordFD, SNDCTL_DSP_SPEED, &tmp) == -1)
|
||||
{
|
||||
INFO_LOG(AUDIO, "OSS: can't set sample rate");
|
||||
close(recordFD);
|
||||
recordFD = -1;
|
||||
termRecord();
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
#include "audiostream.h"
|
||||
#include "cfg/option.h"
|
||||
#include "emulator.h"
|
||||
|
||||
static void registerForEvents();
|
||||
|
||||
struct SoundFrame { s16 l; s16 r; };
|
||||
|
||||
@@ -60,6 +63,7 @@ void WriteSample(s16 r, s16 l)
|
||||
|
||||
void InitAudio()
|
||||
{
|
||||
registerForEvents();
|
||||
TermAudio();
|
||||
|
||||
std::string slug = config::AudioBackend;
|
||||
@@ -138,3 +142,19 @@ void StopAudioRecording()
|
||||
currentBackend->termRecord();
|
||||
audio_recording_started = false;
|
||||
}
|
||||
|
||||
static void registerForEvents()
|
||||
{
|
||||
static bool done;
|
||||
if (done)
|
||||
return;
|
||||
done = true;
|
||||
// Empty the audio buffer when loading a state or terminating the game
|
||||
const auto& callback = [](Event, void *) {
|
||||
writePtr = 0;
|
||||
};
|
||||
EventManager::listen(Event::Terminate, callback);
|
||||
EventManager::listen(Event::LoadState, callback);
|
||||
}
|
||||
|
||||
|
||||
+15
-10
@@ -15,12 +15,8 @@
|
||||
//HOST_CPU
|
||||
#define CPU_X86 0x20000001
|
||||
#define CPU_ARM 0x20000002
|
||||
#define CPU_MIPS 0x20000003
|
||||
#define CPU_ARM64 0x20000003
|
||||
#define CPU_X64 0x20000004
|
||||
#define CPU_GENERIC 0x20000005 //used for pnacl, emscripten, etc
|
||||
#define CPU_PPC 0x20000006
|
||||
#define CPU_PPC64 0x20000007
|
||||
#define CPU_ARM64 0x20000008
|
||||
|
||||
//FEAT_SHREC, FEAT_AREC, FEAT_DSPREC
|
||||
#define DYNAREC_NONE 0x40000001
|
||||
@@ -36,10 +32,19 @@
|
||||
#define HOST_CPU CPU_ARM
|
||||
#elif defined(__aarch64__) || defined(_M_ARM64)
|
||||
#define HOST_CPU CPU_ARM64
|
||||
#elif defined(__mips__)
|
||||
#define HOST_CPU CPU_MIPS
|
||||
#else
|
||||
#define HOST_CPU CPU_GENERIC
|
||||
#error Unsupported architecture
|
||||
#endif
|
||||
|
||||
#if defined(__APPLE__)
|
||||
#include "TargetConditionals.h"
|
||||
#if TARGET_OS_SIMULATOR
|
||||
// iOS simulator
|
||||
#define TARGET_NO_REC
|
||||
#endif
|
||||
#if defined(TARGET_MAC) && HOST_CPU == CPU_ARM64
|
||||
#define TARGET_ARM_MAC
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(TARGET_NO_REC)
|
||||
@@ -93,14 +98,14 @@
|
||||
|
||||
#ifdef _WIN32
|
||||
#if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_APP)
|
||||
#define TARGET_UWP
|
||||
#define TARGET_UWP 1
|
||||
#endif
|
||||
#ifdef HAVE_D3D11
|
||||
#define USE_DX11
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if !defined(LIBRETRO) && !defined(TARGET_NO_EXCEPTIONS)
|
||||
#if !defined(LIBRETRO)
|
||||
#define USE_GGPO
|
||||
#endif
|
||||
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
target_sources(${PROJECT_NAME} PRIVATE
|
||||
option.h)
|
||||
|
||||
if(NOT LIBRETRO)
|
||||
target_sources(${PROJECT_NAME} PRIVATE
|
||||
cfg.cpp
|
||||
cfg.h
|
||||
cl.cpp
|
||||
ini.cpp
|
||||
ini.h
|
||||
option.cpp)
|
||||
endif()
|
||||
@@ -130,3 +130,12 @@ void cfgSetAutoSave(bool autoSave)
|
||||
if (autoSave)
|
||||
saveConfigFile();
|
||||
}
|
||||
|
||||
void cfgSaveFloat(const std::string& section, const std::string& key, float value)
|
||||
{
|
||||
cfgdb.set_float(section, key, value);
|
||||
}
|
||||
float cfgLoadFloat(const std::string& section, const std::string& key, float def)
|
||||
{
|
||||
return cfgdb.get_float(section, key, def);
|
||||
}
|
||||
@@ -11,6 +11,8 @@ std::string cfgLoadStr(const std::string& section, const std::string& key, const
|
||||
void cfgSaveStr(const std::string& section, const std::string& key, const std::string& value);
|
||||
void cfgSaveBool(const std::string& section, const std::string& key, bool value);
|
||||
bool cfgLoadBool(const std::string& section, const std::string& key, bool def);
|
||||
void cfgSaveFloat(const std::string& section, const std::string& key, float value);
|
||||
float cfgLoadFloat(const std::string& section, const std::string& key, float def);
|
||||
void cfgSetVirtual(const std::string& section, const std::string& key, const std::string& value);
|
||||
bool cfgIsVirtual(const std::string& section, const std::string& key);
|
||||
|
||||
|
||||
@@ -47,6 +47,11 @@ bool ConfigEntry::get_bool()
|
||||
}
|
||||
}
|
||||
|
||||
float ConfigEntry::get_float()
|
||||
{
|
||||
return atof(this->value.c_str());
|
||||
}
|
||||
|
||||
/* ConfigSection */
|
||||
|
||||
bool ConfigSection::has_entry(const std::string& name)
|
||||
@@ -192,6 +197,15 @@ bool ConfigFile::get_bool(const std::string& section_name, const std::string& en
|
||||
}
|
||||
}
|
||||
|
||||
float ConfigFile::get_float(const std::string& section_name, const std::string& entry_name, float default_value)
|
||||
{
|
||||
ConfigEntry* entry = get_entry(section_name, entry_name);
|
||||
if (entry == nullptr)
|
||||
return default_value;
|
||||
else
|
||||
return entry->get_float();
|
||||
}
|
||||
|
||||
void ConfigFile::set(const std::string& section_name, const std::string& entry_name, const std::string& value, bool is_virtual)
|
||||
{
|
||||
ConfigSection* section = this->get_section(section_name, is_virtual);
|
||||
@@ -222,6 +236,13 @@ void ConfigFile::set_bool(const std::string& section_name, const std::string& en
|
||||
this->set(section_name, entry_name, str_value, is_virtual);
|
||||
}
|
||||
|
||||
void ConfigFile::set_float(const std::string& section_name, const std::string& entry_name, float value, bool is_virtual)
|
||||
{
|
||||
std::stringstream str_value;
|
||||
str_value << value;
|
||||
this->set(section_name, entry_name, str_value.str(), is_virtual);
|
||||
}
|
||||
|
||||
void ConfigFile::parse(FILE* file)
|
||||
{
|
||||
if (file == nullptr)
|
||||
|
||||
@@ -13,6 +13,7 @@ struct ConfigEntry {
|
||||
int get_int();
|
||||
bool get_bool();
|
||||
int64_t get_int64();
|
||||
float get_float();
|
||||
};
|
||||
|
||||
struct ConfigSection {
|
||||
@@ -45,11 +46,13 @@ struct ConfigFile {
|
||||
int get_int(const std::string& section_name, const std::string& entry_name, int default_value = 0);
|
||||
int64_t get_int64(const std::string& section_name, const std::string& entry_name, int64_t default_value = 0);
|
||||
bool get_bool(const std::string& section_name, const std::string& entry_name, bool default_value = false);
|
||||
float get_float(const std::string& section_name, const std::string& entry_name, float default_value = 0.f);
|
||||
/* setting values */
|
||||
void set(const std::string& section_name, const std::string& entry_name, const std::string& value, bool is_virtual = false);
|
||||
void set_int(const std::string& section_name, const std::string& entry_name, int value, bool is_virtual = false);
|
||||
void set_int64(const std::string& section_name, const std::string& entry_name, int64_t value, bool is_virtual = false);
|
||||
void set_bool(const std::string& section_name, const std::string& entry_name, bool value, bool is_virtual = false);
|
||||
void set_float(const std::string& section_name, const std::string& entry_name, float value, bool is_virtual = false);
|
||||
|
||||
void delete_section(const std::string& section_name);
|
||||
void delete_entry(const std::string& section_name, const std::string& entry_name);
|
||||
|
||||
+40
-10
@@ -40,6 +40,7 @@ Option<bool> ForceFreePlay("ForceFreePlay", true);
|
||||
Option<bool, false> FetchBoxart("FetchBoxart", true);
|
||||
Option<bool, false> BoxartDisplayMode("BoxartDisplayMode", true);
|
||||
Option<int, false> UIScaling("UIScaling", 100);
|
||||
Option<int, false> UITheme("UITheme", 0);
|
||||
|
||||
// Sound
|
||||
|
||||
@@ -71,11 +72,13 @@ Option<bool> ShowFPS("rend.ShowFPS");
|
||||
Option<bool> RenderToTextureBuffer("rend.RenderToTextureBuffer");
|
||||
Option<bool> TranslucentPolygonDepthMask("rend.TranslucentPolygonDepthMask");
|
||||
Option<bool> ModifierVolumes("rend.ModifierVolumes", true);
|
||||
Option<int> TextureUpscale("rend.TextureUpscale", 1);
|
||||
Option<int> TextureUpscale("rend.TextureUpscale2", 1);
|
||||
Option<int> MaxFilteredTextureSize("rend.MaxFilteredTextureSize", 256);
|
||||
Option<float> ExtraDepthScale("rend.ExtraDepthScale", 1.f);
|
||||
Option<bool> CustomTextures("rend.CustomTextures");
|
||||
Option<bool> PreloadCustomTextures("rend.PreloadCustomTextures");
|
||||
Option<bool> DumpTextures("rend.DumpTextures");
|
||||
Option<bool> DumpReplacedTextures("rend.DumpReplacedTextures");
|
||||
Option<int> ScreenStretching("rend.ScreenStretching", 100);
|
||||
Option<bool> Fog("rend.Fog", true);
|
||||
Option<bool> FloatVMUs("rend.FloatVMUs");
|
||||
@@ -98,6 +101,8 @@ Option<int> SkipFrame("ta.skip");
|
||||
Option<int> MaxThreads("pvr.MaxThreads", 3);
|
||||
Option<int> AutoSkipFrame("pvr.AutoSkipFrame", 0);
|
||||
Option<int> RenderResolution("rend.Resolution", 480);
|
||||
Option<bool> IntegerScale("rend.IntegerScale", false);
|
||||
Option<bool> LinearInterpolation("rend.LinearInterpolation", true);
|
||||
Option<bool> VSync("rend.vsync", true);
|
||||
Option<int64_t> PixelBufferSize("rend.PixelBufferSize", 512_MB);
|
||||
Option<int> AnisotropicFiltering("rend.AnisotropicFiltering", 1);
|
||||
@@ -105,7 +110,11 @@ Option<int> TextureFiltering("rend.TextureFiltering", 0); // Default
|
||||
Option<bool> ThreadedRendering("rend.ThreadedRendering", true);
|
||||
Option<bool> DupeFrames("rend.DupeFrames", false);
|
||||
Option<int> PerPixelLayers("rend.PerPixelLayers", 32);
|
||||
#ifdef TARGET_UWP
|
||||
Option<bool> NativeDepthInterpolation("rend.NativeDepthInterpolation", true);
|
||||
#else
|
||||
Option<bool> NativeDepthInterpolation("rend.NativeDepthInterpolation", false);
|
||||
#endif
|
||||
Option<bool> EmulateFramebuffer("rend.EmulateFramebuffer", false);
|
||||
Option<bool> FixUpscaleBleedingEdge("rend.FixUpscaleBleedingEdge", true);
|
||||
Option<bool> CustomGpuDriver("rend.CustomGpuDriver", false);
|
||||
@@ -129,12 +138,22 @@ Option<bool> RamMod32MB("Dreamcast.RamMod32MB", false);
|
||||
Option<bool> OpenGlChecks("OpenGlChecks", false, "validate");
|
||||
|
||||
Option<std::vector<std::string>, false> ContentPath("Dreamcast.ContentPath");
|
||||
Option<std::vector<std::string>, false> BiosPath("Dreamcast.BiosPath");
|
||||
Option<std::string, false> VMUPath("Dreamcast.VMUPath");
|
||||
Option<std::vector<std::string>, false> SavestatePath("Dreamcast.SavestatePath");
|
||||
Option<std::string, false> SavePath("Dreamcast.SavePath");
|
||||
Option<std::vector<std::string>, false> TexturePath("Dreamcast.TexturePath");
|
||||
Option<std::string, false> TextureDumpPath("Dreamcast.TextureDumpPath");
|
||||
Option<std::string, false> BoxartPath("Dreamcast.BoxartPath");
|
||||
Option<std::vector<std::string>, false> MappingsPath("Dreamcast.MappingsPath");
|
||||
Option<std::vector<std::string>, false> CheatPath("Dreamcast.CheatPath");
|
||||
Option<bool, false> HideLegacyNaomiRoms("Dreamcast.HideLegacyNaomiRoms", true);
|
||||
Option<bool, false> UploadCrashLogs("UploadCrashLogs", true);
|
||||
Option<bool, false> DiscordPresence("DiscordPresence", true);
|
||||
#if defined(__ANDROID__) && !defined(LIBRETRO)
|
||||
Option<bool, false> UseSafFilePicker("UseSafFilePicker", true);
|
||||
#endif
|
||||
OptionString LogServer("LogServer", "", "log");
|
||||
|
||||
// Profiler
|
||||
Option<bool> ProfilerEnabled("Profiler.Enabled");
|
||||
@@ -161,6 +180,8 @@ Option<int> GGPOChatTimeout("GGPOChatTimeout", 10, "network");
|
||||
Option<bool> NetworkOutput("NetworkOutput", false, "network");
|
||||
Option<int> MultiboardSlaves("MultiboardSlaves", 1, "network");
|
||||
Option<bool> BattleCableEnable("BattleCable", false, "network");
|
||||
Option<bool> UseDCNet("DCNet", false, "network");
|
||||
OptionString ISPUsername("ISPUsername", "flycast1", "network");
|
||||
|
||||
#ifdef USE_OMX
|
||||
Option<int> OmxAudioLatency("audio_latency", 100, "omx");
|
||||
@@ -179,23 +200,32 @@ std::array<Option<MapleDeviceType>, 4> MapleMainDevices {
|
||||
Option<MapleDeviceType>("device3", MDT_None, "input"),
|
||||
Option<MapleDeviceType>("device4", MDT_None, "input"),
|
||||
};
|
||||
std::array<std::array<Option<MapleDeviceType>, 2>, 4> MapleExpansionDevices {
|
||||
Option<MapleDeviceType>("device1.1", MDT_SegaVMU, "input"),
|
||||
Option<MapleDeviceType>("device1.2", MDT_SegaVMU, "input"),
|
||||
std::array<std::array<Option<MapleDeviceType>, 2>, 4> MapleExpansionDevices {{
|
||||
{{Option<MapleDeviceType>("device1.1", MDT_SegaVMU, "input"),
|
||||
Option<MapleDeviceType>("device1.2", MDT_SegaVMU, "input")}},
|
||||
|
||||
Option<MapleDeviceType>("device2.1", MDT_None, "input"),
|
||||
Option<MapleDeviceType>("device2.2", MDT_None, "input"),
|
||||
{{Option<MapleDeviceType>("device2.1", MDT_None, "input"),
|
||||
Option<MapleDeviceType>("device2.2", MDT_None, "input")}},
|
||||
|
||||
Option<MapleDeviceType>("device3.1", MDT_None, "input"),
|
||||
Option<MapleDeviceType>("device3.2", MDT_None, "input"),
|
||||
{{Option<MapleDeviceType>("device3.1", MDT_None, "input"),
|
||||
Option<MapleDeviceType>("device3.2", MDT_None, "input")}},
|
||||
|
||||
Option<MapleDeviceType>("device4.1", MDT_None, "input"),
|
||||
Option<MapleDeviceType>("device4.2", MDT_None, "input"),
|
||||
{{Option<MapleDeviceType>("device4.1", MDT_None, "input"),
|
||||
Option<MapleDeviceType>("device4.2", MDT_None, "input")}},
|
||||
}};
|
||||
|
||||
std::array<Option<bool>, 4> UseNetworkExpansionDevices{
|
||||
Option<bool>("device1.UseNetworkExpansionDevices", false, "input"),
|
||||
Option<bool>("device2.UseNetworkExpansionDevices", false, "input"),
|
||||
Option<bool>("device3.UseNetworkExpansionDevices", false, "input"),
|
||||
Option<bool>("device4.UseNetworkExpansionDevices", false, "input"),
|
||||
};
|
||||
|
||||
Option<bool> PerGameVmu("PerGameVmu", false, "config");
|
||||
#ifdef _WIN32
|
||||
Option<bool, false> UseRawInput("RawInput", false, "input");
|
||||
#endif
|
||||
Option<bool> UsePhysicalVmuMemory("UsePhysicalVmuMemory", true);
|
||||
|
||||
#ifdef USE_LUA
|
||||
Option<std::string, false> LuaFileName("LuaFileName", "flycast.lua");
|
||||
|
||||
+21
-8
@@ -202,11 +202,7 @@ protected:
|
||||
std::enable_if_t<std::is_same_v<float, U>, T>
|
||||
doLoad(const std::string& section, const std::string& name) const
|
||||
{
|
||||
std::string strValue = cfgLoadStr(section, name, "");
|
||||
if (strValue.empty())
|
||||
return value;
|
||||
else
|
||||
return (float)atof(strValue.c_str());
|
||||
return cfgLoadFloat(section, name, value);
|
||||
}
|
||||
|
||||
template <typename U = T>
|
||||
@@ -301,9 +297,7 @@ protected:
|
||||
std::enable_if_t<std::is_same_v<float, U>>
|
||||
doSave(const std::string& section, const std::string& name) const
|
||||
{
|
||||
char buf[64];
|
||||
snprintf(buf, sizeof(buf), "%f", value);
|
||||
cfgSaveStr(section, name, buf);
|
||||
cfgSaveFloat(section, name, value);
|
||||
}
|
||||
|
||||
template <typename U = T>
|
||||
@@ -373,6 +367,7 @@ extern Option<bool> ForceFreePlay;
|
||||
extern Option<bool, false> FetchBoxart;
|
||||
extern Option<bool, false> BoxartDisplayMode;
|
||||
extern Option<int, false> UIScaling;
|
||||
extern Option<int, false> UITheme; // 0 -> Dark, 1 -> Light, 2 -> Dreamcast, 3 -> High Contrast, 4 -> Nintendo, 5 -> Aqua Chill
|
||||
|
||||
// Sound
|
||||
|
||||
@@ -451,7 +446,9 @@ extern Option<int> PerPixelLayers;
|
||||
#endif
|
||||
extern Option<float> ExtraDepthScale;
|
||||
extern Option<bool> CustomTextures;
|
||||
extern Option<bool> PreloadCustomTextures;
|
||||
extern Option<bool> DumpTextures;
|
||||
extern Option<bool> DumpReplacedTextures;
|
||||
extern Option<int> ScreenStretching; // in percent. 150 means stretch from 4/3 to 6/3
|
||||
extern Option<bool> Fog;
|
||||
extern Option<bool> FloatVMUs;
|
||||
@@ -465,6 +462,8 @@ extern Option<int> SkipFrame;
|
||||
extern Option<int> MaxThreads;
|
||||
extern Option<int> AutoSkipFrame; // 0: none, 1: some, 2: more
|
||||
extern Option<int> RenderResolution;
|
||||
extern Option<bool> IntegerScale;
|
||||
extern Option<bool> LinearInterpolation;
|
||||
extern Option<bool> VSync;
|
||||
extern Option<int64_t> PixelBufferSize;
|
||||
extern Option<int> AnisotropicFiltering;
|
||||
@@ -495,12 +494,22 @@ extern Option<bool> RamMod32MB;
|
||||
extern Option<bool> OpenGlChecks;
|
||||
|
||||
extern Option<std::vector<std::string>, false> ContentPath;
|
||||
extern Option<std::vector<std::string>, false> BiosPath;
|
||||
extern Option<std::string, false> VMUPath;
|
||||
extern Option<std::vector<std::string>, false> SavestatePath;
|
||||
extern Option<std::string, false> SavePath;
|
||||
extern Option<std::vector<std::string>, false> TexturePath;
|
||||
extern Option<std::string, false> TextureDumpPath;
|
||||
extern Option<std::string, false> BoxartPath;
|
||||
extern Option<std::vector<std::string>, false> MappingsPath;
|
||||
extern Option<std::vector<std::string>, false> CheatPath;
|
||||
extern Option<bool, false> HideLegacyNaomiRoms;
|
||||
extern Option<bool, false> UploadCrashLogs;
|
||||
extern Option<bool, false> DiscordPresence;
|
||||
#if defined(__ANDROID__) && !defined(LIBRETRO)
|
||||
extern Option<bool, false> UseSafFilePicker;
|
||||
#endif
|
||||
extern OptionString LogServer;
|
||||
|
||||
// Profiling
|
||||
extern Option<bool> ProfilerEnabled;
|
||||
@@ -527,6 +536,8 @@ extern Option<int> GGPOChatTimeout;
|
||||
extern Option<bool> NetworkOutput;
|
||||
extern Option<int> MultiboardSlaves;
|
||||
extern Option<bool> BattleCableEnable;
|
||||
extern Option<bool> UseDCNet;
|
||||
extern OptionString ISPUsername;
|
||||
|
||||
#ifdef USE_OMX
|
||||
extern Option<int> OmxAudioLatency;
|
||||
@@ -540,12 +551,14 @@ extern Option<int> VirtualGamepadVibration;
|
||||
extern Option<int> VirtualGamepadTransparency;
|
||||
extern std::array<Option<MapleDeviceType>, 4> MapleMainDevices;
|
||||
extern std::array<std::array<Option<MapleDeviceType>, 2>, 4> MapleExpansionDevices;
|
||||
extern std::array<Option<bool>, 4> UseNetworkExpansionDevices;
|
||||
extern Option<bool> PerGameVmu;
|
||||
#ifdef _WIN32
|
||||
extern Option<bool, false> UseRawInput;
|
||||
#else
|
||||
constexpr bool UseRawInput = false;
|
||||
#endif
|
||||
extern Option<bool> UsePhysicalVmuMemory;
|
||||
|
||||
#ifdef USE_LUA
|
||||
extern Option<std::string, false> LuaFileName;
|
||||
|
||||
+211
-6
@@ -83,7 +83,7 @@ const WidescreenCheat CheatManager::widescreen_cheats[] =
|
||||
{ "T30006M", nullptr, { 0x4CF42C, 0x4CF45C, 0x3E1A36, 0x3E1A34, 0x3E1A3C, 0x3E1A54, 0x3E1A5C },
|
||||
{ 0x43F00000, 0x3F400000, 0x08010000, 0, 0, 0, 0 } },
|
||||
{ "MK-5103750", nullptr, { 0x1FE270 }, { 0x43700000 } }, // Daytona USA (PAL)
|
||||
{ "MK-51037", nullptr, { 0x1FC6D0 }, { 0x43700000 } }, // Daytona USA (USA)
|
||||
// breaks online connection { "MK-51037", nullptr, { 0x1FC6D0 }, { 0x43700000 } }, // Daytona USA (USA)
|
||||
{ "T9501N-50", nullptr, { 0x9821D4 }, { 0x3F400000 } }, // Deadly Skies (PAL)
|
||||
{ "T8116D 50", nullptr, { 0x2E5530 }, { 0x43700000 } }, // Dead or Alive 2 (PAL)
|
||||
{ "T3601N", nullptr, { 0x2F0670 }, { 0x43700000 } }, // Dead or Alive 2 (USA)
|
||||
@@ -165,10 +165,11 @@ const WidescreenCheat CheatManager::widescreen_cheats[] =
|
||||
{ 0x43F00000, 0x3F400000, 0x3F800000 } }, // Napple Tale: Arsia in Daydream (JP)
|
||||
//crash { "MK-51178", nullptr, { 0x23AF00, 0x23B160, 0x144D40, 0x2105B4, 0x705B40 },
|
||||
// { 0xBFAAAAAB, 0xBFAAAAAB, 0xBFAAAAAB, 0xBFAAAAAB, 0x44558000 } }, // NBA 2K2
|
||||
{ "T9504M", nullptr, { 0xCDE848, 0xCDE844 }, { 0x3F400000, 0x3FA00000 } }, // Nightmare Creatures II (USA)
|
||||
{ "T-9502D-50", nullptr, { 0xBDE9B0, 0xBDE9C4 }, { 0x3F400000, 0x3FA00000 } }, // Nightmare Creatures II (PAL)
|
||||
// { "T9504M", nullptr, { 0xCDE848, 0xCDE844 }, { 0x3F400000, 0x3FA00000 } }, // Nightmare Creatures II (USA)
|
||||
// { "T-9502D-50", nullptr, { 0xBDE9B0, 0xBDE9C4 }, { 0x3F400000, 0x3FA00000 } }, // Nightmare Creatures II (PAL)
|
||||
{ "MK-5110250", nullptr, { 0x87B5A4 }, { 0x43700000 } }, // Outtrigger (PAL)
|
||||
{ "HDR-0118", nullptr, { 0x83E284 }, { 0x43700000 } }, // Outtrigger (JP)
|
||||
{ "MK-51102", nullptr, { 0x83E284 }, { 0x43700000 } }, // Outtrigger (US)
|
||||
{ "T15103D 50", nullptr, { 0x1EEE78 }, { 0x3F400000 } }, // PenPen (PAL)
|
||||
{ "T17001M", nullptr, { 0x1C3828 }, { 0x3F400000 } }, // PenPen TriIcelon (JP)
|
||||
{ "MK-5110050", nullptr, { 0x548E04, 0x0923C0 }, { 0x43E80000, 0x3F966666 } }, // Phantasy Star Online (PAL) TODO
|
||||
@@ -445,13 +446,42 @@ void CheatManager::reset(const std::string& gameId)
|
||||
cheats.clear();
|
||||
setActive(false);
|
||||
this->gameId = gameId;
|
||||
|
||||
#ifndef LIBRETRO
|
||||
if (!settings.raHardcoreMode)
|
||||
{
|
||||
std::string cheatFile = cfgLoadStr("cheats", gameId, "");
|
||||
if (!cheatFile.empty())
|
||||
loadCheatFile(cheatFile);
|
||||
else
|
||||
{
|
||||
// Try to auto-locate a cheat file in user-defined CheatPath
|
||||
std::string romName = settings.content.fileName;
|
||||
const char* exts[] = { ".cht", ".txt" };
|
||||
for (const auto& base : config::CheatPath.get())
|
||||
{
|
||||
if (base.empty())
|
||||
continue;
|
||||
for (const char* ext : exts)
|
||||
{
|
||||
try
|
||||
{
|
||||
std::string candidate = hostfs::storage().getSubPath(base, romName + ext);
|
||||
if (hostfs::storage().exists(candidate))
|
||||
{
|
||||
loadCheatFile(candidate);
|
||||
cfgSaveStr("cheats", gameId, candidate);
|
||||
goto found_cheats;
|
||||
}
|
||||
}
|
||||
catch (const hostfs::StorageException&)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
found_cheats:
|
||||
#endif
|
||||
size_t cheatCount = cheats.size();
|
||||
if (gameId == "Fixed BOOT strapper") // Extreme Hunting 2
|
||||
@@ -481,6 +511,117 @@ void CheatManager::reset(const std::string& gameId)
|
||||
else if (gameId == "SAMURAI SPIRITS 6" || gameId == "T0002M") {
|
||||
cheats.emplace_back(Cheat::Type::setValue, "fix depth", true, 16, 0x0003e602, 0x0009, true); // nop (shift by 8 bits instead of 10)
|
||||
}
|
||||
else if (gameId == "T-8107N") { // Fur Fighters (US)
|
||||
// force logging on to use more cycles
|
||||
cheats.emplace_back(Cheat::Type::setValue, "enable logging", true, 32, 0x00314248, 1, true);
|
||||
}
|
||||
else if (gameId == "T-8113D-50") { // Fur Fighters (EU)
|
||||
// force logging on to use more cycles
|
||||
cheats.emplace_back(Cheat::Type::setValue, "enable logging", true, 32, 0x00314228, 1, true);
|
||||
}
|
||||
// Dricas auth bypass
|
||||
else if (gameId == "T6807M") // Aero Dancing i
|
||||
{
|
||||
// modem
|
||||
cheats.emplace_back(Cheat::Type::runNextIfEq, "bypass auth ifeq", true, 32, 0x0004b7a0, 0x2fd62fe6, true);
|
||||
cheats.emplace_back(Cheat::Type::setValue, "bypass dricas auth", true, 32, 0x0004b7a0, 0xe000000b, true); // rts, _mov #0, r0
|
||||
// BBA
|
||||
cheats.emplace_back(Cheat::Type::runNextIfEq, "bba bypass auth ifeq", true, 32, 0x0004af5c, 0x2fd62fe6, true);
|
||||
cheats.emplace_back(Cheat::Type::setValue, "bba bypass dricas auth", true, 32, 0x0004af5c, 0xe000000b, true);
|
||||
// IP check
|
||||
cheats.emplace_back(Cheat::Type::runNextIfEq, "ip check ifeq", true, 32, 0x00020860, 0x4f222fe6, true);
|
||||
cheats.emplace_back(Cheat::Type::setValue, "ip check ok", true, 32, 0x00020860, 0xe000000b, true);
|
||||
}
|
||||
else if (gameId == "T6809M") // Aero Dancing i - Jikai Saku Made Matemasen
|
||||
{
|
||||
// modem
|
||||
cheats.emplace_back(Cheat::Type::runNextIfEq, "bypass auth ifeq", true, 32, 0x0004b940, 0x2fd62fe6, true);
|
||||
cheats.emplace_back(Cheat::Type::setValue, "bypass dricas auth", true, 32, 0x0004b940, 0xe000000b, true);
|
||||
// BBA
|
||||
cheats.emplace_back(Cheat::Type::runNextIfEq, "bba bypass auth ifeq", true, 32, 0x0004f848, 0x2fd62fe6, true);
|
||||
cheats.emplace_back(Cheat::Type::setValue, "bba bypass dricas auth", true, 32, 0x0004f848, 0xe000000b, true);
|
||||
// IP check
|
||||
cheats.emplace_back(Cheat::Type::runNextIfEq, "ip check ifeq", true, 32, 0x00020980, 0x4f222fe6, true);
|
||||
cheats.emplace_back(Cheat::Type::setValue, "ip check ok", true, 32, 0x00020980, 0xe000000b, true);
|
||||
}
|
||||
else if (gameId == "T6805M") { // Aero Dancing F - Todoroki Tsubasa no Hatsu Hikou
|
||||
cheats.emplace_back(Cheat::Type::runNextIfEq, "bypass auth ifeq", true, 32, 0x0003ed10, 0x2fd62fe6, true);
|
||||
cheats.emplace_back(Cheat::Type::setValue, "bypass dricas auth", true, 32, 0x0003ed10, 0xe000000b, true);
|
||||
}
|
||||
else if (gameId == "HDR-0106") { // Daytona USA (JP)
|
||||
cheats.emplace_back(Cheat::Type::runNextIfEq, "bypass auth ifeq", true, 32, 0x0003ad30, 0x2fd62fe6, true);
|
||||
cheats.emplace_back(Cheat::Type::setValue, "bypass dricas auth", true, 32, 0x0003ad30, 0xe000000b, true);
|
||||
}
|
||||
else if (gameId == "HDR-0073") { // Sega Tetris
|
||||
cheats.emplace_back(Cheat::Type::runNextIfEq, "bypass auth ifeq", true, 32, 0x000a56f8, 0x2fd62fe6, true);
|
||||
cheats.emplace_back(Cheat::Type::setValue, "bypass dricas auth", true, 32, 0x000a56f8, 0xe000000b, true);
|
||||
}
|
||||
else if (gameId == "T44501M") { // Golf Shiyou Yo 2
|
||||
cheats.emplace_back(Cheat::Type::runNextIfEq, "bypass auth ifeq", true, 32, 0x0013f150, 0x2fd62fe6, true);
|
||||
cheats.emplace_back(Cheat::Type::setValue, "bypass dricas auth", true, 32, 0x0013f150, 0xe000000b, true);
|
||||
}
|
||||
else if (gameId == "HDR-0124") { // Hundred Swords
|
||||
cheats.emplace_back(Cheat::Type::runNextIfEq, "bypass auth ifeq", true, 32, 0x006558ac, 0x1f414f22, true);
|
||||
cheats.emplace_back(Cheat::Type::setValue, "bypass dricas auth", true, 32, 0x006558ac, 0xe000000b, true);
|
||||
}
|
||||
else if (gameId == "T43903M") { // Culdcept II
|
||||
cheats.emplace_back(Cheat::Type::runNextIfEq, "bypass auth ifeq", true, 32, 0x00800524, 0x2fd62fe6, true);
|
||||
cheats.emplace_back(Cheat::Type::setValue, "bypass dricas auth", true, 32, 0x00800524, 0xe000000b, true);
|
||||
}
|
||||
else if (gameId == "T40214N") { // The Next Tetris (US)
|
||||
cheats.emplace_back(Cheat::Type::runNextIfEq, "bypass speed ifeq", true, 32, 0x0016d5d4, 0x2f862fe6, true);
|
||||
cheats.emplace_back(Cheat::Type::setValue, "bypass speed check", true, 32, 0x0016d5d4, 0xe001000b, true);
|
||||
}
|
||||
else if (gameId == "MK-51065") { // Bomberman Online
|
||||
cheats.emplace_back(Cheat::Type::runNextIfEq, "modem automode ifeq", true, 32, 0x00196da8, 0x2c302c30, true); // 0,0,
|
||||
cheats.emplace_back(Cheat::Type::setValue, "modem automode set", true, 32, 0x00196da8, 0x2c302c31, true); // 1,0,
|
||||
}
|
||||
else if (gameId == "MK-51102") { // Outtrigger (US)
|
||||
cheats.emplace_back(Cheat::Type::runNextIfEq, "modem automode ifeq", true, 32, 0x001bdb48, 0x2c302c30, true); // 0,0,
|
||||
cheats.emplace_back(Cheat::Type::setValue, "modem automode set", true, 32, 0x001bdb48, 0x2c302c31, true); // 1,0,
|
||||
}
|
||||
else if (gameId == "HDR-0118") { // Outtrigger (JP)
|
||||
cheats.emplace_back(Cheat::Type::runNextIfEq, "bypass auth ifeq", true, 32, 0x00139f54, 0x2fd62fe6, true);
|
||||
cheats.emplace_back(Cheat::Type::setValue, "bypass dricas auth", true, 32, 0x00139f54, 0xe000000b, true);
|
||||
}
|
||||
else if (gameId == "T13306M") // Mobile Suit Gundam: Federation vs. Zeon
|
||||
{
|
||||
cheats.emplace_back(Cheat::Type::runNextIfEq, "modem rxspeed ifeq", true, 32, 0x0016e710, 0x3434312c, true); // ",144"
|
||||
cheats.emplace_back(Cheat::Type::setValue, "modem rxspeed set", true, 32, 0x0016e710, 0x2020202c, true); // ", "
|
||||
cheats.emplace_back(Cheat::Type::runNextIfEq, "modem txspeed ifeq", true, 32, 0x0016e71c, 0x3434312c, true); // ",144"
|
||||
cheats.emplace_back(Cheat::Type::setValue, "modem txspeed set", true, 32, 0x0016e71c, 0x2020202c, true); // ", "
|
||||
}
|
||||
else if (gameId == "MK-51162") // Propeller Arena
|
||||
{
|
||||
// 0c1f56f0: ,0,28800,28800,28800,28800\\r"\n
|
||||
// 0c1f5770: ,0,28800,28800,28800,28800\\r"\n
|
||||
for (u32 addr = 0x001f56f0; addr <= 0x001f5770; addr += 0x80)
|
||||
{
|
||||
cheats.emplace_back(Cheat::Type::runNextIfEq, "modem automode1 ifeq", true, 32, addr + 0x00, 0x322c302c, true); // ",0,2"
|
||||
cheats.emplace_back(Cheat::Type::setValue, "modem automode1 set", true, 32, addr + 0x00, 0x202c312c, true); // ",1, "
|
||||
cheats.emplace_back(Cheat::Type::runNextIfEq, "modem automode2 ifeq", true, 32, addr + 0x04, 0x30303838, true); // "8800"
|
||||
cheats.emplace_back(Cheat::Type::setValue, "modem automode2 set", true, 32, addr + 0x04, 0x30202020, true); // " 0"
|
||||
cheats.emplace_back(Cheat::Type::runNextIfEq, "modem automode3 ifeq", true, 32, addr + 0x0c, 0x322c3030, true); // "00,2"
|
||||
cheats.emplace_back(Cheat::Type::setValue, "modem automode3 set", true, 32, addr + 0x0c, 0x202c3030, true); // "00, "
|
||||
cheats.emplace_back(Cheat::Type::runNextIfEq, "modem automode4 ifeq", true, 32, addr + 0x10, 0x30303838, true); // "8800"
|
||||
cheats.emplace_back(Cheat::Type::setValue, "modem automode4 set", true, 32, addr + 0x10, 0x30202020, true); // " 0"
|
||||
}
|
||||
}
|
||||
else if (gameId == "HDR-0113") // Power Smash
|
||||
{
|
||||
cheats.emplace_back(Cheat::Type::runNextIfEq, "no dupe SYN ifeq", true, 16, 0x14d258, 0xbbce, true); // bsr SendNormalSYN
|
||||
cheats.emplace_back(Cheat::Type::setValue, "no dupe SYN set", true, 16, 0x14d258, 0x0009, true); // nop
|
||||
cheats.emplace_back(Cheat::Type::runNextIfEq, "no dupe ACK ifeq", true, 16, 0x14af42, 0x430b, true); // jsr TCPInternalSendPacket
|
||||
cheats.emplace_back(Cheat::Type::setValue, "no dupe ACK set", true, 16, 0x14af42, 0x0009, true); // nop
|
||||
}
|
||||
else if (gameId == "HDR-0091") // Pro Yakyuu Team de Asobou Net!
|
||||
{
|
||||
cheats.emplace_back(Cheat::Type::runNextIfEq, "no dupe SYN ifeq", true, 16, 0xe13e0c, 0xbbce, true); // bsr SendNormalSYN
|
||||
cheats.emplace_back(Cheat::Type::setValue, "no dupe SYN set", true, 16, 0xe13e0c, 0x0009, true); // nop
|
||||
cheats.emplace_back(Cheat::Type::runNextIfEq, "no dupe ACK ifeq", true, 16, 0xe11af6, 0x430b, true); // jsr TCPInternalSendPacket
|
||||
cheats.emplace_back(Cheat::Type::setValue, "no dupe ACK set", true, 16, 0xe11af6, 0x0009, true); // nop
|
||||
}
|
||||
|
||||
if (cheats.size() > cheatCount)
|
||||
setActive(true);
|
||||
}
|
||||
@@ -672,6 +813,42 @@ static std::vector<u32> parseCodes(const std::string& s)
|
||||
return codes;
|
||||
}
|
||||
|
||||
// Decrypt (some) Action Replay/Gameshark/Codebreaker/Xploder encrypted codes
|
||||
// Master codes change the encryption method and thus are not supported (07xxxxxx)
|
||||
// Taken from DCcrypt
|
||||
constexpr u32 Seeds[16] = {
|
||||
0xA53A8888,
|
||||
0xA1427921, 0xAC9528B1, 0xC5892354, 0x49671B12,
|
||||
0xACC56121, 0xACB5381E, 0x765436E1, 0x9F2C3E54,
|
||||
0x1133E312, 0xAC5E7894, 0xE9F208B1, 0x4E87DCFE,
|
||||
0x43174312, 0x1D7A6C99, 0x874224A2
|
||||
};
|
||||
|
||||
static u32 decryptCode(u32 v)
|
||||
{
|
||||
constexpr u32 something = 6;
|
||||
|
||||
if ((v & 0xf0000000) == 0)
|
||||
return v;
|
||||
u32 seed = Seeds[v >> 28];
|
||||
if (something & 4)
|
||||
v = (((v << 1) & 0x0FFFFFFE) | ((v >> 27) & 1));
|
||||
if (something & 2) {
|
||||
v = (((v << 1) & 0x0FFFFFFE) | ((v >> 27) & 1));
|
||||
v = (((v << 8) & 0x0FFFFF00) | ((v >> 20) & 0xFF));
|
||||
}
|
||||
if (something & 1)
|
||||
seed >>= 4;
|
||||
u32 ret = (seed & 0x0FFFFFFF) ^ v;
|
||||
//if ((ret & 0x0FF00000) != 0x07100000)
|
||||
// something = (ret & 0x0f) + 6;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static u32 decryptArg(u32 v) {
|
||||
return (((v + 0x543700D0) >> 29) | ((v + 0x543700D0) * 8)) ^ Seeds[0];
|
||||
}
|
||||
|
||||
void CheatManager::addGameSharkCheat(const std::string& name, const std::string& s)
|
||||
{
|
||||
std::vector<u32> codes = parseCodes(s);
|
||||
@@ -687,6 +864,22 @@ void CheatManager::addGameSharkCheat(const std::string& name, const std::string&
|
||||
Cheat cheat{};
|
||||
cheat.description = name;
|
||||
u32 code = (codes[i] & 0xff000000) >> 24;
|
||||
if (code & 0xf0)
|
||||
{
|
||||
// encrypted code
|
||||
codes[i] = decryptCode(codes[i]);
|
||||
code = (codes[i] & 0xff000000) >> 24;
|
||||
if (code == 4 && i + 2 < codes.size()) {
|
||||
// following args are also encrypted
|
||||
codes[i + 1] = decryptArg(codes[i + 1]);
|
||||
codes[i + 2] = decryptArg(codes[i + 2]);
|
||||
}
|
||||
else if (code == 0xd && i + 2 < codes.size()) {
|
||||
// following arg is also encrypted
|
||||
codes[i + 1] = decryptArg(codes[i + 1]);
|
||||
}
|
||||
// TODO Which ops have encrypted args (3, 5, E, F)? Couldn't find any
|
||||
}
|
||||
switch (code)
|
||||
{
|
||||
case 0:
|
||||
@@ -800,9 +993,17 @@ void CheatManager::addGameSharkCheat(const std::string& name, const std::string&
|
||||
cheats.push_back(cheat);
|
||||
}
|
||||
break;
|
||||
// TODO 7 change decryption type
|
||||
// TODO 0xb delay applying codes
|
||||
// TODO 0xc global enable test
|
||||
|
||||
case 7:
|
||||
// change decryption type: 071000XX (example: 07100005)
|
||||
throw FlycastException("Master codes aren't supported");
|
||||
|
||||
// TODO 0xb delay applying codes: 0b0xxxxx
|
||||
// Delay putting on codes for xxxxx cycles. Default 1000 (0x3e7)
|
||||
// TODO 0xc global enable test: 0cxxxxxx vvvvvvvv
|
||||
// If the value at address 8Cxxxxxx is equal to vvvvvvvv, execute ALL codes;
|
||||
// otherwise no codes are executed. Useful for waiting until game has loaded.
|
||||
|
||||
case 0xd:
|
||||
{
|
||||
// enable next code if eq/neq/lt/gt
|
||||
@@ -860,6 +1061,10 @@ void CheatManager::addGameSharkCheat(const std::string& name, const std::string&
|
||||
conditionCheat = cheat;
|
||||
}
|
||||
break;
|
||||
|
||||
// TODO 0xF: 0F-XXXXXX 0000YYYY
|
||||
// 16-Bit Write Once Immediately. (Activator code)
|
||||
|
||||
default:
|
||||
throw FlycastException("Unsupported cheat type");
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
#include "emulator.h"
|
||||
#include "hw/sh4/sh4_if.h"
|
||||
#include "hw/sh4/sh4_mem.h"
|
||||
#include "hw/sh4/sh4_interpreter.h"
|
||||
#include "hw/sh4/dyna/shil.h"
|
||||
#include "cfg/option.h"
|
||||
#include <array>
|
||||
#include <signal.h>
|
||||
@@ -122,9 +122,9 @@ public:
|
||||
for (u32 i = 0; i < Sh4RegList.size(); i++)
|
||||
{
|
||||
if (Sh4RegList[i] == reg_sr_status)
|
||||
allregs[i] = sh4_sr_GetFull();
|
||||
allregs[i] = Sh4cntx.sr.getFull();
|
||||
else if (Sh4RegList[i] != NoReg)
|
||||
allregs[i] = *GetRegPtr(Sh4RegList[i]);
|
||||
allregs[i] = *GetRegPtr(Sh4cntx, Sh4RegList[i]);
|
||||
}
|
||||
*regs = &allregs[0];
|
||||
return allregs.size();
|
||||
@@ -134,7 +134,7 @@ public:
|
||||
{
|
||||
for (u32 i = 0; i < Sh4RegList.size(); i++)
|
||||
if (Sh4RegList[i] != NoReg)
|
||||
*GetRegPtr(Sh4RegList[i]) = regs[i];
|
||||
*GetRegPtr(Sh4cntx, Sh4RegList[i]) = regs[i];
|
||||
}
|
||||
|
||||
u32 readReg(u32 regNum)
|
||||
@@ -143,9 +143,9 @@ public:
|
||||
return 0;
|
||||
Sh4RegType reg = Sh4RegList[regNum];
|
||||
if (reg == reg_sr_status)
|
||||
return sh4_sr_GetFull();
|
||||
return Sh4cntx.sr.getFull();
|
||||
if (reg != NoReg)
|
||||
return *GetRegPtr(reg);
|
||||
return *GetRegPtr(Sh4cntx, reg);
|
||||
return 0;
|
||||
}
|
||||
void writeReg(u32 regNum, u32 value)
|
||||
@@ -154,9 +154,9 @@ public:
|
||||
return;
|
||||
Sh4RegType reg = Sh4RegList[regNum];
|
||||
if (reg == reg_sr_status)
|
||||
sh4_sr_SetFull(value);
|
||||
Sh4cntx.sr.setFull(value);
|
||||
else if (reg != NoReg)
|
||||
*GetRegPtr(reg) = value;
|
||||
*GetRegPtr(Sh4cntx, reg) = value;
|
||||
}
|
||||
|
||||
const u8 *readMem(u32 addr, u32 len)
|
||||
|
||||
+403
-390
File diff suppressed because it is too large.
Load diff
Submodule
+1
Submodule core/deps/DreamPicoPort-API added at 0f6a902bc8.
+1
-1
Submodule core/deps/SDL updated: 79ec168f3c...00d4f1c2c4.
+1
-1
Submodule core/deps/Syphon updated: 486dd8e4ef...53ec412a78.
Submodule
+1
Submodule core/deps/asio added at d3402006e8.
@@ -13,7 +13,7 @@
|
||||
template<class T, int N> class RingBuffer
|
||||
{
|
||||
public:
|
||||
RingBuffer<T, N>() :
|
||||
RingBuffer() :
|
||||
_head(0),
|
||||
_tail(0),
|
||||
_size(0) {
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
template<class T, int N> class StaticBuffer
|
||||
{
|
||||
public:
|
||||
StaticBuffer<T, N>() :
|
||||
StaticBuffer() :
|
||||
_size(0) {
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
cmake_minimum_required(VERSION 3.2 FATAL_ERROR)
|
||||
cmake_policy(VERSION 3.2)
|
||||
cmake_minimum_required(VERSION 3.6 FATAL_ERROR)
|
||||
cmake_policy(VERSION 3.6)
|
||||
|
||||
set(GLM_VERSION "0.9.9")
|
||||
project(glm VERSION ${GLM_VERSION} LANGUAGES CXX)
|
||||
|
||||
+1
-1
Submodule core/deps/glslang updated: 76b52ebf77...fc9889c889.
@@ -222,7 +222,7 @@ void ImGui_ImplOpenGL3_RenderDrawData(ImDrawData* draw_data)
|
||||
glcache.Scissor((int)clip_rect.x, (int)clip_rect.y, (int)clip_rect.z, (int)clip_rect.w); // Support for GL 4.5's glClipControl(GL_UPPER_LEFT)
|
||||
|
||||
// Bind texture, Draw
|
||||
glcache.BindTexture(GL_TEXTURE_2D, (GLuint)(intptr_t)pcmd->TextureId);
|
||||
glcache.BindTexture(GL_TEXTURE_2D, (GLuint)(intptr_t)pcmd->GetTexID());
|
||||
glDrawElements(GL_TRIANGLES, (GLsizei)pcmd->ElemCount, sizeof(ImDrawIdx) == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, (void*)(intptr_t)(pcmd->IdxOffset * sizeof(ImDrawIdx)));
|
||||
}
|
||||
}
|
||||
@@ -255,7 +255,7 @@ static bool ImGui_ImplOpenGL3_CreateFontsTexture()
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
|
||||
|
||||
// Store our identifier
|
||||
io.Fonts->TexID = (ImTextureID)(intptr_t)g_FontTexture;
|
||||
io.Fonts->SetTexID((ImTextureID)g_FontTexture);
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -266,7 +266,6 @@ static void ImGui_ImplOpenGL3_DestroyFontsTexture()
|
||||
{
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
glcache.DeleteTextures(1, &g_FontTexture);
|
||||
io.Fonts->TexID = 0;
|
||||
g_FontTexture = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -586,14 +586,14 @@ void ImGui_ImplVulkan_RenderDrawData(ImDrawData* draw_data, VkCommandBuffer comm
|
||||
vkCmdSetScissor(command_buffer, 0, 1, &scissor);
|
||||
|
||||
// Bind DescriptorSet with font or user texture
|
||||
VkDescriptorSet desc_set[1] = { (VkDescriptorSet)pcmd->TextureId };
|
||||
VkDescriptorSet desc_set = (VkDescriptorSet)pcmd->GetTexID();
|
||||
if (sizeof(ImTextureID) < sizeof(ImU64))
|
||||
{
|
||||
// We don't support texture switches if ImTextureID hasn't been redefined to be 64-bit. Do a flaky check that other textures haven't been used.
|
||||
IM_ASSERT(pcmd->TextureId == (ImTextureID)bd->FontDescriptorSet);
|
||||
desc_set[0] = bd->FontDescriptorSet;
|
||||
IM_ASSERT(pcmd->GetTexID() == (ImTextureID)bd->FontDescriptorSet);
|
||||
desc_set = bd->FontDescriptorSet;
|
||||
}
|
||||
vkCmdBindDescriptorSets(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, bd->PipelineLayout, 0, 1, desc_set, 0, nullptr);
|
||||
vkCmdBindDescriptorSets(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, bd->PipelineLayout, 0, 1, &desc_set, 0, nullptr);
|
||||
|
||||
// Draw
|
||||
vkCmdDrawIndexed(command_buffer, pcmd->ElemCount, 1, pcmd->IdxOffset + global_idx_offset, pcmd->VtxOffset + global_vtx_offset, 0);
|
||||
@@ -820,7 +820,6 @@ void ImGui_ImplVulkan_DestroyFontsTexture()
|
||||
{
|
||||
ImGui_ImplVulkan_RemoveTexture(bd->FontDescriptorSet);
|
||||
bd->FontDescriptorSet = VK_NULL_HANDLE;
|
||||
io.Fonts->SetTexID(0);
|
||||
}
|
||||
|
||||
if (bd->FontView) { vkDestroyImageView(v->Device, bd->FontView, v->Allocator); bd->FontView = VK_NULL_HANDLE; }
|
||||
|
||||
@@ -21,14 +21,14 @@
|
||||
|
||||
//---- Define attributes of all API symbols declarations, e.g. for DLL under Windows
|
||||
// Using Dear ImGui via a shared library is not recommended, because of function call overhead and because we don't guarantee backward nor forward ABI compatibility.
|
||||
// DLL users: heaps and globals are not shared across DLL boundaries! You will need to call SetCurrentContext() + SetAllocatorFunctions()
|
||||
// for each static/DLL boundary you are calling from. Read "Context and Memory Allocators" section of imgui.cpp for more details.
|
||||
//#define IMGUI_API __declspec( dllexport )
|
||||
//#define IMGUI_API __declspec( dllimport )
|
||||
// - Windows DLL users: heaps and globals are not shared across DLL boundaries! You will need to call SetCurrentContext() + SetAllocatorFunctions()
|
||||
// for each static/DLL boundary you are calling from. Read "Context and Memory Allocators" section of imgui.cpp for more details.
|
||||
//#define IMGUI_API __declspec(dllexport) // MSVC Windows: DLL export
|
||||
//#define IMGUI_API __declspec(dllimport) // MSVC Windows: DLL import
|
||||
//#define IMGUI_API __attribute__((visibility("default"))) // GCC/Clang: override visibility when set is hidden
|
||||
|
||||
//---- Don't define obsolete functions/enums/behaviors. Consider enabling from time to time after updating to clean your code of obsolete function/names.
|
||||
//#define IMGUI_DISABLE_OBSOLETE_FUNCTIONS
|
||||
//#define IMGUI_DISABLE_OBSOLETE_KEYIO // 1.87+ disable legacy io.KeyMap[]+io.KeysDown[] in favor io.AddKeyEvent(). This is automatically done by IMGUI_DISABLE_OBSOLETE_FUNCTIONS.
|
||||
|
||||
//---- Disable all of Dear ImGui or don't implement standard windows/tools.
|
||||
// It is very strongly recommended to NOT disable the demo windows and debug tool during development. They are extremely useful in day to day work. Please read comments in imgui_demo.cpp.
|
||||
@@ -42,21 +42,29 @@
|
||||
//#define IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS // [Win32] [Default with non-Visual Studio compilers] Don't implement default IME handler (won't require imm32.lib/.a)
|
||||
//#define IMGUI_DISABLE_WIN32_FUNCTIONS // [Win32] Won't use and link with any Win32 function (clipboard, IME).
|
||||
//#define IMGUI_ENABLE_OSX_DEFAULT_CLIPBOARD_FUNCTIONS // [OSX] Implement default OSX clipboard handler (need to link with '-framework ApplicationServices', this is why this is not the default).
|
||||
//#define IMGUI_DISABLE_DEFAULT_SHELL_FUNCTIONS // Don't implement default platform_io.Platform_OpenInShellFn() handler (Win32: ShellExecute(), require shell32.lib/.a, Mac/Linux: use system("")).
|
||||
//#define IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS // Don't implement ImFormatString/ImFormatStringV so you can implement them yourself (e.g. if you don't want to link with vsnprintf)
|
||||
//#define IMGUI_DISABLE_DEFAULT_MATH_FUNCTIONS // Don't implement ImFabs/ImSqrt/ImPow/ImFmod/ImCos/ImSin/ImAcos/ImAtan2 so you can implement them yourself.
|
||||
//#define IMGUI_DISABLE_FILE_FUNCTIONS // Don't implement ImFileOpen/ImFileClose/ImFileRead/ImFileWrite and ImFileHandle at all (replace them with dummies)
|
||||
//#define IMGUI_DISABLE_DEFAULT_FILE_FUNCTIONS // Don't implement ImFileOpen/ImFileClose/ImFileRead/ImFileWrite and ImFileHandle so you can implement them yourself if you don't want to link with fopen/fclose/fread/fwrite. This will also disable the LogToTTY() function.
|
||||
//#define IMGUI_DISABLE_DEFAULT_ALLOCATORS // Don't implement default allocators calling malloc()/free() to avoid linking with them. You will need to call ImGui::SetAllocatorFunctions().
|
||||
//#define IMGUI_DISABLE_DEFAULT_FONT // Disable default embedded font (ProggyClean.ttf), remove ~9.5 KB from output binary. AddFontDefault() will assert.
|
||||
//#define IMGUI_DISABLE_SSE // Disable use of SSE intrinsics even if available
|
||||
|
||||
//---- Enable Test Engine / Automation features.
|
||||
//#define IMGUI_ENABLE_TEST_ENGINE // Enable imgui_test_engine hooks. Generally set automatically by include "imgui_te_config.h", see Test Engine for details.
|
||||
|
||||
//---- Include imgui_user.h at the end of imgui.h as a convenience
|
||||
// May be convenient for some users to only explicitly include vanilla imgui.h and have extra stuff included.
|
||||
//#define IMGUI_INCLUDE_IMGUI_USER_H
|
||||
//#define IMGUI_USER_H_FILENAME "my_folder/my_imgui_user.h"
|
||||
|
||||
//---- Pack colors to BGRA8 instead of RGBA8 (to avoid converting from one to another)
|
||||
//---- Pack vertex colors as BGRA8 instead of RGBA8 (to avoid converting from one to another). Need dedicated backend support.
|
||||
//#define IMGUI_USE_BGRA_PACKED_COLOR
|
||||
|
||||
//---- Use legacy CRC32-adler tables (used before 1.91.6), in order to preserve old .ini data that you cannot afford to invalidate.
|
||||
//#define IMGUI_USE_LEGACY_CRC32_ADLER
|
||||
|
||||
//---- Use 32-bit for ImWchar (default is 16-bit) to support Unicode planes 1-16. (e.g. point beyond 0xFFFF like emoticons, dingbats, symbols, shapes, ancient languages, etc...)
|
||||
//#define IMGUI_USE_WCHAR32
|
||||
|
||||
@@ -78,10 +86,12 @@
|
||||
// On Windows you may use vcpkg with 'vcpkg install freetype --triplet=x64-windows' + 'vcpkg integrate install'.
|
||||
//#define IMGUI_ENABLE_FREETYPE
|
||||
|
||||
//---- Use FreeType+lunasvg library to render OpenType SVG fonts (SVGinOT)
|
||||
// Requires lunasvg headers to be available in the include path + program to be linked with the lunasvg library (not provided).
|
||||
//---- Use FreeType + plutosvg or lunasvg to render OpenType SVG fonts (SVGinOT)
|
||||
// Only works in combination with IMGUI_ENABLE_FREETYPE.
|
||||
// (implementation is based on Freetype's rsvg-port.c which is licensed under CeCILL-C Free Software License Agreement)
|
||||
// - plutosvg is currently easier to install, as e.g. it is part of vcpkg. It will support more fonts and may load them faster. See misc/freetype/README for instructions.
|
||||
// - Both require headers to be available in the include path + program to be linked with the library code (not provided).
|
||||
// - (note: lunasvg implementation is based on Freetype's rsvg-port.c which is licensed under CeCILL-C Free Software License Agreement)
|
||||
//#define IMGUI_ENABLE_FREETYPE_PLUTOSVG
|
||||
//#define IMGUI_ENABLE_FREETYPE_LUNASVG
|
||||
|
||||
//---- Use stb_truetype to build and rasterize the font atlas (default)
|
||||
@@ -119,6 +129,10 @@
|
||||
//#define IM_DEBUG_BREAK IM_ASSERT(0)
|
||||
//#define IM_DEBUG_BREAK __debugbreak()
|
||||
|
||||
//---- Debug Tools: Enable highlight ID conflicts _before_ hovering items. When io.ConfigDebugHighlightIdConflicts is set.
|
||||
// (THIS WILL SLOW DOWN DEAR IMGUI. Only use occasionally and disable after use)
|
||||
//#define IMGUI_DEBUG_HIGHLIGHT_ALL_ID_CONFLICTS
|
||||
|
||||
//---- Debug Tools: Enable slower asserts
|
||||
//#define IMGUI_DEBUG_PARANOID
|
||||
|
||||
|
||||
+3373
-1631
File diff suppressed because it is too large.
Load diff
+1202
-466
File diff suppressed because it is too large.
Load diff
+3855
-1783
File diff suppressed because it is too large.
Load diff
+2736
-1061
File diff suppressed because it is too large.
Load diff
+816
-519
File diff suppressed because it is too large.
Load diff
@@ -8,6 +8,7 @@
|
||||
// https://github.com/ocornut/imgui/wiki/Useful-Extensions#cness
|
||||
|
||||
#include "imgui.h"
|
||||
#ifndef IMGUI_DISABLE
|
||||
#include "imgui_stdlib.h"
|
||||
|
||||
// Clang warnings with -Weverything
|
||||
@@ -83,3 +84,5 @@ bool ImGui::InputTextWithHint(const char* label, const char* hint, std::string*
|
||||
#if defined(__clang__)
|
||||
#pragma clang diagnostic pop
|
||||
#endif
|
||||
|
||||
#endif // #ifndef IMGUI_DISABLE
|
||||
@@ -9,6 +9,8 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef IMGUI_DISABLE
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace ImGui
|
||||
@@ -19,3 +21,5 @@ namespace ImGui
|
||||
IMGUI_API bool InputTextMultiline(const char* label, std::string* str, const ImVec2& size = ImVec2(0, 0), ImGuiInputTextFlags flags = 0, ImGuiInputTextCallback callback = nullptr, void* user_data = nullptr);
|
||||
IMGUI_API bool InputTextWithHint(const char* label, const char* hint, std::string* str, ImGuiInputTextFlags flags = 0, ImGuiInputTextCallback callback = nullptr, void* user_data = nullptr);
|
||||
}
|
||||
|
||||
#endif // #ifndef IMGUI_DISABLE
|
||||
+212
-101
@@ -1,4 +1,4 @@
|
||||
// dear imgui, v1.90.8
|
||||
// dear imgui, v1.92.1
|
||||
// (tables and columns code)
|
||||
|
||||
/*
|
||||
@@ -221,6 +221,7 @@ Index of this file:
|
||||
#pragma clang diagnostic ignored "-Wunknown-pragmas" // warning: unknown warning group 'xxx'
|
||||
#pragma clang diagnostic ignored "-Wold-style-cast" // warning: use of old-style cast // yes, they are more terse.
|
||||
#pragma clang diagnostic ignored "-Wfloat-equal" // warning: comparing floating point with == or != is unsafe // storing and comparing against same constants (typically 0.0f) is ok.
|
||||
#pragma clang diagnostic ignored "-Wformat" // warning: format specifies type 'int' but the argument has type 'unsigned int'
|
||||
#pragma clang diagnostic ignored "-Wformat-nonliteral" // warning: format string is not a string literal // passing non-literal to vsnformat(). yes, user passing incorrect format strings can crash the code.
|
||||
#pragma clang diagnostic ignored "-Wsign-conversion" // warning: implicit conversion changes signedness
|
||||
#pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant" // warning: zero as null pointer constant // some standard header variations use #define NULL 0
|
||||
@@ -229,9 +230,15 @@ Index of this file:
|
||||
#pragma clang diagnostic ignored "-Wdeprecated-enum-enum-conversion"// warning: bitwise operation between different enumeration types ('XXXFlags_' and 'XXXFlagsPrivate_') is deprecated
|
||||
#pragma clang diagnostic ignored "-Wimplicit-int-float-conversion" // warning: implicit conversion from 'xxx' to 'float' may lose precision
|
||||
#pragma clang diagnostic ignored "-Wunsafe-buffer-usage" // warning: 'xxx' is an unsafe pointer used for buffer access
|
||||
#pragma clang diagnostic ignored "-Wnontrivial-memaccess" // warning: first argument in call to 'memset' is a pointer to non-trivially copyable type
|
||||
#pragma clang diagnostic ignored "-Wswitch-default" // warning: 'switch' missing 'default' label
|
||||
#elif defined(__GNUC__)
|
||||
#pragma GCC diagnostic ignored "-Wpragmas" // warning: unknown option after '#pragma GCC diagnostic' kind
|
||||
#pragma GCC diagnostic ignored "-Wfloat-equal" // warning: comparing floating-point with '==' or '!=' is unsafe
|
||||
#pragma GCC diagnostic ignored "-Wformat-nonliteral" // warning: format not a string literal, format string not checked
|
||||
#pragma GCC diagnostic ignored "-Wdouble-promotion" // warning: implicit conversion from 'float' to 'double' when passing argument to function
|
||||
#pragma GCC diagnostic ignored "-Wformat" // warning: format '%p' expects argument of type 'int'/'void*', but argument X has type 'unsigned int'/'ImGuiWindow*'
|
||||
#pragma GCC diagnostic ignored "-Wstrict-overflow"
|
||||
#pragma GCC diagnostic ignored "-Wclass-memaccess" // [__GNUC__ >= 8] warning: 'memset/memcpy' clearing/writing an object of type 'xxxx' with no trivial copy-assignment; use assignment or value-initialization instead
|
||||
#endif
|
||||
|
||||
@@ -328,13 +335,14 @@ bool ImGui::BeginTableEx(const char* name, ImGuiID id, int columns_count, ImG
|
||||
// - always performing the GetOrAddByKey() O(log N) query in g.Tables.Map[].
|
||||
const bool use_child_window = (flags & (ImGuiTableFlags_ScrollX | ImGuiTableFlags_ScrollY)) != 0;
|
||||
const ImVec2 avail_size = GetContentRegionAvail();
|
||||
const ImVec2 actual_outer_size = CalcItemSize(outer_size, ImMax(avail_size.x, 1.0f), use_child_window ? ImMax(avail_size.y, 1.0f) : 0.0f);
|
||||
const ImVec2 actual_outer_size = ImTrunc(CalcItemSize(outer_size, ImMax(avail_size.x, 1.0f), use_child_window ? ImMax(avail_size.y, 1.0f) : 0.0f));
|
||||
const ImRect outer_rect(outer_window->DC.CursorPos, outer_window->DC.CursorPos + actual_outer_size);
|
||||
const bool outer_window_is_measuring_size = (outer_window->AutoFitFramesX > 0) || (outer_window->AutoFitFramesY > 0); // Doesn't apply to AlwaysAutoResize windows!
|
||||
if (use_child_window && IsClippedEx(outer_rect, 0) && !outer_window_is_measuring_size)
|
||||
{
|
||||
ItemSize(outer_rect);
|
||||
ItemAdd(outer_rect, id);
|
||||
g.NextWindowData.ClearFlags();
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -369,6 +377,7 @@ bool ImGui::BeginTableEx(const char* name, ImGuiID id, int columns_count, ImG
|
||||
table->ColumnsCount = columns_count;
|
||||
table->IsLayoutLocked = false;
|
||||
table->InnerWidth = inner_width;
|
||||
table->NavLayer = (ImS8)outer_window->DC.NavLayerCurrent;
|
||||
temp_data->UserOuterSize = outer_size;
|
||||
|
||||
// Instance data (for instance 0, TableID == TableInstanceID)
|
||||
@@ -409,11 +418,15 @@ bool ImGui::BeginTableEx(const char* name, ImGuiID id, int columns_count, ImG
|
||||
|
||||
// Reset scroll if we are reactivating it
|
||||
if ((previous_flags & (ImGuiTableFlags_ScrollX | ImGuiTableFlags_ScrollY)) == 0)
|
||||
SetNextWindowScroll(ImVec2(0.0f, 0.0f));
|
||||
if ((g.NextWindowData.HasFlags & ImGuiNextWindowDataFlags_HasScroll) == 0)
|
||||
SetNextWindowScroll(ImVec2(0.0f, 0.0f));
|
||||
|
||||
// Create scrolling region (without border and zero window padding)
|
||||
ImGuiWindowFlags child_flags = (flags & ImGuiTableFlags_ScrollX) ? ImGuiWindowFlags_HorizontalScrollbar : ImGuiWindowFlags_None;
|
||||
BeginChildEx(name, instance_id, outer_rect.GetSize(), false, child_flags);
|
||||
ImGuiChildFlags child_child_flags = (g.NextWindowData.HasFlags & ImGuiNextWindowDataFlags_HasChildFlags) ? g.NextWindowData.ChildFlags : ImGuiChildFlags_None;
|
||||
ImGuiWindowFlags child_window_flags = (g.NextWindowData.HasFlags & ImGuiNextWindowDataFlags_HasWindowFlags) ? g.NextWindowData.WindowFlags : ImGuiWindowFlags_None;
|
||||
if (flags & ImGuiTableFlags_ScrollX)
|
||||
child_window_flags |= ImGuiWindowFlags_HorizontalScrollbar;
|
||||
BeginChildEx(name, instance_id, outer_rect.GetSize(), child_child_flags, child_window_flags);
|
||||
table->InnerWindow = g.CurrentWindow;
|
||||
table->WorkRect = table->InnerWindow->WorkRect;
|
||||
table->OuterRect = table->InnerWindow->Rect();
|
||||
@@ -438,6 +451,7 @@ bool ImGui::BeginTableEx(const char* name, ImGuiID id, int columns_count, ImG
|
||||
// But at this point we do NOT have a correct value for .Max.y (unless a height has been explicitly passed in). It will only be updated in EndTable().
|
||||
table->WorkRect = table->OuterRect = table->InnerRect = outer_rect;
|
||||
table->HasScrollbarYPrev = table->HasScrollbarYCurr = false;
|
||||
table->InnerWindow->DC.TreeDepth++; // This is designed to always linking ImGuiTreeNodeFlags_DrawLines linking accross a table
|
||||
}
|
||||
|
||||
// Push a standardized ID for both child-using and not-child-using tables
|
||||
@@ -460,16 +474,27 @@ bool ImGui::BeginTableEx(const char* name, ImGuiID id, int columns_count, ImG
|
||||
temp_data->HostBackupItemWidthStackSize = outer_window->DC.ItemWidthStack.Size;
|
||||
inner_window->DC.PrevLineSize = inner_window->DC.CurrLineSize = ImVec2(0.0f, 0.0f);
|
||||
|
||||
// Make left and top borders not overlap our contents by offsetting HostClipRect (#6765)
|
||||
// Make borders not overlap our contents by offsetting HostClipRect (#6765, #7428, #3752)
|
||||
// (we normally shouldn't alter HostClipRect as we rely on TableMergeDrawChannels() expanding non-clipped column toward the
|
||||
// limits of that rectangle, in order for ImDrawListSplitter::Merge() to merge the draw commands. However since the overlap
|
||||
// problem only affect scrolling tables in this case we can get away with doing it without extra cost).
|
||||
if (inner_window != outer_window)
|
||||
{
|
||||
// FIXME: Because inner_window's Scrollbar doesn't know about border size, since it's not encoded in window->WindowBorderSize,
|
||||
// it already overlaps it and doesn't need an extra offset. Ideally we should be able to pass custom border size with
|
||||
// different x/y values to BeginChild().
|
||||
if (flags & ImGuiTableFlags_BordersOuterV)
|
||||
{
|
||||
table->HostClipRect.Min.x = ImMin(table->HostClipRect.Min.x + TABLE_BORDER_SIZE, table->HostClipRect.Max.x);
|
||||
if (inner_window->DecoOuterSizeX2 == 0.0f)
|
||||
table->HostClipRect.Max.x = ImMax(table->HostClipRect.Max.x - TABLE_BORDER_SIZE, table->HostClipRect.Min.x);
|
||||
}
|
||||
if (flags & ImGuiTableFlags_BordersOuterH)
|
||||
{
|
||||
table->HostClipRect.Min.y = ImMin(table->HostClipRect.Min.y + TABLE_BORDER_SIZE, table->HostClipRect.Max.y);
|
||||
if (inner_window->DecoOuterSizeY2 == 0.0f)
|
||||
table->HostClipRect.Max.y = ImMax(table->HostClipRect.Max.y - TABLE_BORDER_SIZE, table->HostClipRect.Min.y);
|
||||
}
|
||||
}
|
||||
|
||||
// Padding and Spacing
|
||||
@@ -497,7 +522,7 @@ bool ImGui::BeginTableEx(const char* name, ImGuiID id, int columns_count, ImG
|
||||
table->InnerClipRect = (inner_window == outer_window) ? table->WorkRect : inner_window->ClipRect;
|
||||
table->InnerClipRect.ClipWith(table->WorkRect); // We need this to honor inner_width
|
||||
table->InnerClipRect.ClipWithFull(table->HostClipRect);
|
||||
table->InnerClipRect.Max.y = (flags & ImGuiTableFlags_NoHostExtendY) ? ImMin(table->InnerClipRect.Max.y, inner_window->WorkRect.Max.y) : inner_window->ClipRect.Max.y;
|
||||
table->InnerClipRect.Max.y = (flags & ImGuiTableFlags_NoHostExtendY) ? ImMin(table->InnerClipRect.Max.y, inner_window->WorkRect.Max.y) : table->HostClipRect.Max.y;
|
||||
|
||||
table->RowPosY1 = table->RowPosY2 = table->WorkRect.Min.y; // This is needed somehow
|
||||
table->RowTextBaseline = 0.0f; // This will be cleared again by TableBeginRow()
|
||||
@@ -555,6 +580,7 @@ bool ImGui::BeginTableEx(const char* name, ImGuiID id, int columns_count, ImG
|
||||
// Initialize
|
||||
table->SettingsOffset = -1;
|
||||
table->IsSortSpecsDirty = true;
|
||||
table->IsSettingsDirty = true; // Records itself into .ini file even when in default state (#7934)
|
||||
table->InstanceInteracted = -1;
|
||||
table->ContextPopupColumn = -1;
|
||||
table->ReorderColumn = table->ResizedColumn = table->LastResizedColumn = -1;
|
||||
@@ -855,7 +881,7 @@ void ImGui::TableUpdateLayout(ImGuiTable* table)
|
||||
|
||||
// Calculate ideal/auto column width (that's the width required for all contents to be visible without clipping)
|
||||
// Combine width from regular rows + width from headers unless requested not to.
|
||||
if (!column->IsPreserveWidthAuto)
|
||||
if (!column->IsPreserveWidthAuto && table->InstanceCurrent == 0)
|
||||
column->WidthAuto = TableGetColumnWidthAuto(table, column);
|
||||
|
||||
// Non-resizable columns keep their requested width (apply user value regardless of IsPreserveWidthAuto)
|
||||
@@ -954,7 +980,7 @@ void ImGui::TableUpdateLayout(ImGuiTable* table)
|
||||
// [Part 4] Apply final widths based on requested widths
|
||||
const ImRect work_rect = table->WorkRect;
|
||||
const float width_spacings = (table->OuterPaddingX * 2.0f) + (table->CellSpacingX1 + table->CellSpacingX2) * (table->ColumnsEnabledCount - 1);
|
||||
const float width_removed = (table->HasScrollbarYPrev && !table->InnerWindow->ScrollbarY) ? g.Style.ScrollbarSize : 0.0f; // To synchronize decoration width of synched tables with mismatching scrollbar state (#5920)
|
||||
const float width_removed = (table->HasScrollbarYPrev && !table->InnerWindow->ScrollbarY) ? g.Style.ScrollbarSize : 0.0f; // To synchronize decoration width of synced tables with mismatching scrollbar state (#5920)
|
||||
const float width_avail = ImMax(1.0f, (((table->Flags & ImGuiTableFlags_ScrollX) && table->InnerWidth == 0.0f) ? table->InnerClipRect.GetWidth() : work_rect.GetWidth()) - width_removed);
|
||||
const float width_avail_for_stretched_columns = width_avail - width_spacings - sum_width_requests;
|
||||
float width_remaining_for_stretched_columns = width_avail_for_stretched_columns;
|
||||
@@ -1033,7 +1059,8 @@ void ImGui::TableUpdateLayout(ImGuiTable* table)
|
||||
const int column_n = table->DisplayOrderToIndex[order_n];
|
||||
ImGuiTableColumn* column = &table->Columns[column_n];
|
||||
|
||||
column->NavLayerCurrent = (ImS8)(table->FreezeRowsCount > 0 ? ImGuiNavLayer_Menu : ImGuiNavLayer_Main); // Use Count NOT request so Header line changes layer when frozen
|
||||
// Initial nav layer: using FreezeRowsCount, NOT FreezeRowsRequest, so Header line changes layer when frozen
|
||||
column->NavLayerCurrent = (ImS8)(table->FreezeRowsCount > 0 ? ImGuiNavLayer_Menu : (ImGuiNavLayer)table->NavLayer);
|
||||
|
||||
if (offset_x_frozen && table->FreezeColumnsCount == visible_n)
|
||||
{
|
||||
@@ -1059,16 +1086,12 @@ void ImGui::TableUpdateLayout(ImGuiTable* table)
|
||||
continue;
|
||||
}
|
||||
|
||||
// Detect hovered column
|
||||
if (is_hovering_table && mouse_skewed_x >= column->ClipRect.Min.x && mouse_skewed_x < column->ClipRect.Max.x)
|
||||
table->HoveredColumnBody = (ImGuiTableColumnIdx)column_n;
|
||||
|
||||
// Lock start position
|
||||
column->MinX = offset_x;
|
||||
|
||||
// Lock width based on start position and minimum/maximum width for this position
|
||||
float max_width = TableGetMaxColumnWidth(table, column_n);
|
||||
column->WidthGiven = ImMin(column->WidthGiven, max_width);
|
||||
column->WidthMax = TableCalcMaxColumnWidth(table, column_n);
|
||||
column->WidthGiven = ImMin(column->WidthGiven, column->WidthMax);
|
||||
column->WidthGiven = ImMax(column->WidthGiven, ImMin(column->WidthRequest, table->MinColumnWidth));
|
||||
column->MaxX = offset_x + column->WidthGiven + table->CellSpacingX1 + table->CellSpacingX2 + table->CellPaddingX * 2.0f;
|
||||
|
||||
@@ -1117,8 +1140,13 @@ void ImGui::TableUpdateLayout(ImGuiTable* table)
|
||||
column->Flags |= ImGuiTableColumnFlags_IsVisible;
|
||||
if (column->SortOrder != -1)
|
||||
column->Flags |= ImGuiTableColumnFlags_IsSorted;
|
||||
if (table->HoveredColumnBody == column_n)
|
||||
|
||||
// Detect hovered column
|
||||
if (is_hovering_table && mouse_skewed_x >= column->ClipRect.Min.x && mouse_skewed_x < column->ClipRect.Max.x)
|
||||
{
|
||||
column->Flags |= ImGuiTableColumnFlags_IsHovered;
|
||||
table->HoveredColumnBody = (ImGuiTableColumnIdx)column_n;
|
||||
}
|
||||
|
||||
// Alignment
|
||||
// FIXME-TABLE: This align based on the whole column width, not per-cell, and therefore isn't useful in
|
||||
@@ -1148,7 +1176,7 @@ void ImGui::TableUpdateLayout(ImGuiTable* table)
|
||||
}
|
||||
|
||||
// Don't decrement auto-fit counters until container window got a chance to submit its items
|
||||
if (table->HostSkipItems == false)
|
||||
if (table->HostSkipItems == false && table->InstanceCurrent == 0)
|
||||
{
|
||||
column->AutoFitQueue >>= 1;
|
||||
column->CannotSkipItemsQueue >>= 1;
|
||||
@@ -1223,7 +1251,7 @@ void ImGui::TableUpdateLayout(ImGuiTable* table)
|
||||
|
||||
// [Part 11] Default context menu
|
||||
// - To append to this menu: you can call TableBeginContextMenuPopup()/.../EndPopup().
|
||||
// - To modify or replace this: set table->IsContextPopupNoDefaultContents = true, then call TableBeginContextMenuPopup()/.../EndPopup().
|
||||
// - To modify or replace this: set table->DisableDefaultContextMenu = true, then call TableBeginContextMenuPopup()/.../EndPopup().
|
||||
// - You may call TableDrawDefaultContextMenu() with selected flags to display specific sections of the default menu,
|
||||
// e.g. TableDrawDefaultContextMenu(table, table->Flags & ~ImGuiTableFlags_Hideable) will display everything EXCEPT columns visibility options.
|
||||
if (table->DisableDefaultContextMenu == false && TableBeginContextMenuPopup(table))
|
||||
@@ -1249,7 +1277,7 @@ void ImGui::TableUpdateLayout(ImGuiTable* table)
|
||||
if (table->Flags & ImGuiTableFlags_NoClip)
|
||||
table->DrawSplitter->SetCurrentChannel(inner_window->DrawList, TABLE_DRAW_CHANNEL_NOCLIP);
|
||||
else
|
||||
inner_window->DrawList->PushClipRect(inner_window->ClipRect.Min, inner_window->ClipRect.Max, false);
|
||||
inner_window->DrawList->PushClipRect(inner_window->InnerClipRect.Min, inner_window->InnerClipRect.Max, false); // FIXME: use table->InnerClipRect?
|
||||
}
|
||||
|
||||
// Process hit-testing on resizing borders. Actual size change will be applied in EndTable()
|
||||
@@ -1319,7 +1347,11 @@ void ImGui::EndTable()
|
||||
{
|
||||
ImGuiContext& g = *GImGui;
|
||||
ImGuiTable* table = g.CurrentTable;
|
||||
IM_ASSERT(table != NULL && "Only call EndTable() if BeginTable() returns true!");
|
||||
if (table == NULL)
|
||||
{
|
||||
IM_ASSERT_USER_ERROR(table != NULL, "EndTable() call should only be done while in BeginTable() scope!");
|
||||
return;
|
||||
}
|
||||
|
||||
// This assert would be very useful to catch a common error... unfortunately it would probably trigger in some
|
||||
// cases, and for consistency user may sometimes output empty tables (and still benefit from e.g. outer border)
|
||||
@@ -1361,7 +1393,7 @@ void ImGui::EndTable()
|
||||
|
||||
// Setup inner scrolling range
|
||||
// FIXME: This ideally should be done earlier, in BeginTable() SetNextWindowContentSize call, just like writing to inner_window->DC.CursorMaxPos.y,
|
||||
// but since the later is likely to be impossible to do we'd rather update both axises together.
|
||||
// but since the later is likely to be impossible to do we'd rather update both axes together.
|
||||
if (table->Flags & ImGuiTableFlags_ScrollX)
|
||||
{
|
||||
const float outer_padding_for_border = (table->Flags & ImGuiTableFlags_BordersOuterV) ? TABLE_BORDER_SIZE : 0.0f;
|
||||
@@ -1471,12 +1503,15 @@ void ImGui::EndTable()
|
||||
if (inner_window != outer_window)
|
||||
{
|
||||
short backup_nav_layers_active_mask = inner_window->DC.NavLayersActiveMask;
|
||||
inner_window->DC.NavLayersActiveMask |= 1 << ImGuiNavLayer_Main; // So empty table don't appear to navigate differently.
|
||||
inner_window->DC.NavLayersActiveMask |= 1 << table->NavLayer; // So empty table don't appear to navigate differently.
|
||||
g.CurrentTable = NULL; // To avoid error recovery recursing
|
||||
EndChild();
|
||||
g.CurrentTable = table;
|
||||
inner_window->DC.NavLayersActiveMask = backup_nav_layers_active_mask;
|
||||
}
|
||||
else
|
||||
{
|
||||
table->InnerWindow->DC.TreeDepth--;
|
||||
ItemSize(table->OuterRect.GetSize());
|
||||
ItemAdd(table->OuterRect, 0);
|
||||
}
|
||||
@@ -1534,14 +1569,43 @@ void ImGui::EndTable()
|
||||
NavUpdateCurrentWindowIsScrollPushableX();
|
||||
}
|
||||
|
||||
// Called in TableSetupColumn() when initializing and in TableLoadSettings() for defaults before applying stored settings.
|
||||
// 'init_mask' specify which fields to initialize.
|
||||
static void TableInitColumnDefaults(ImGuiTable* table, ImGuiTableColumn* column, ImGuiTableColumnFlags init_mask)
|
||||
{
|
||||
ImGuiTableColumnFlags flags = column->Flags;
|
||||
if (init_mask & ImGuiTableFlags_Resizable)
|
||||
{
|
||||
float init_width_or_weight = column->InitStretchWeightOrWidth;
|
||||
column->WidthRequest = ((flags & ImGuiTableColumnFlags_WidthFixed) && init_width_or_weight > 0.0f) ? init_width_or_weight : -1.0f;
|
||||
column->StretchWeight = (init_width_or_weight > 0.0f && (flags & ImGuiTableColumnFlags_WidthStretch)) ? init_width_or_weight : -1.0f;
|
||||
if (init_width_or_weight > 0.0f) // Disable auto-fit if an explicit width/weight has been specified
|
||||
column->AutoFitQueue = 0x00;
|
||||
}
|
||||
if (init_mask & ImGuiTableFlags_Reorderable)
|
||||
column->DisplayOrder = (ImGuiTableColumnIdx)table->Columns.index_from_ptr(column);
|
||||
if (init_mask & ImGuiTableFlags_Hideable)
|
||||
column->IsUserEnabled = column->IsUserEnabledNextFrame = (flags & ImGuiTableColumnFlags_DefaultHide) ? 0 : 1;
|
||||
if (init_mask & ImGuiTableFlags_Sortable)
|
||||
{
|
||||
// Multiple columns using _DefaultSort will be reassigned unique SortOrder values when building the sort specs.
|
||||
column->SortOrder = (flags & ImGuiTableColumnFlags_DefaultSort) ? 0 : -1;
|
||||
column->SortDirection = (flags & ImGuiTableColumnFlags_DefaultSort) ? ((flags & ImGuiTableColumnFlags_PreferSortDescending) ? (ImS8)ImGuiSortDirection_Descending : (ImU8)(ImGuiSortDirection_Ascending)) : (ImS8)ImGuiSortDirection_None;
|
||||
}
|
||||
}
|
||||
|
||||
// See "COLUMNS SIZING POLICIES" comments at the top of this file
|
||||
// If (init_width_or_weight <= 0.0f) it is ignored
|
||||
void ImGui::TableSetupColumn(const char* label, ImGuiTableColumnFlags flags, float init_width_or_weight, ImGuiID user_id)
|
||||
{
|
||||
ImGuiContext& g = *GImGui;
|
||||
ImGuiTable* table = g.CurrentTable;
|
||||
IM_ASSERT(table != NULL && "Need to call TableSetupColumn() after BeginTable()!");
|
||||
IM_ASSERT(table->IsLayoutLocked == false && "Need to call call TableSetupColumn() before first row!");
|
||||
if (table == NULL)
|
||||
{
|
||||
IM_ASSERT_USER_ERROR(table != NULL, "Call should only be done while in BeginTable() scope!");
|
||||
return;
|
||||
}
|
||||
IM_ASSERT(table->IsLayoutLocked == false && "Need to call TableSetupColumn() before first row!");
|
||||
IM_ASSERT((flags & ImGuiTableColumnFlags_StatusMask_) == 0 && "Illegal to pass StatusMask values to TableSetupColumn()");
|
||||
if (table->DeclColumnsCount >= table->ColumnsCount)
|
||||
{
|
||||
@@ -1558,7 +1622,7 @@ void ImGui::TableSetupColumn(const char* label, ImGuiTableColumnFlags flags, flo
|
||||
IM_ASSERT(init_width_or_weight <= 0.0f && "Can only specify width/weight if sizing policy is set explicitly in either Table or Column.");
|
||||
|
||||
// When passing a width automatically enforce WidthFixed policy
|
||||
// (whereas TableSetupColumnFlags would default to WidthAuto if table is not Resizable)
|
||||
// (whereas TableSetupColumnFlags would default to WidthAuto if table is not resizable)
|
||||
if ((flags & ImGuiTableColumnFlags_WidthMask_) == 0 && init_width_or_weight > 0.0f)
|
||||
if ((table->Flags & ImGuiTableFlags_SizingMask_) == ImGuiTableFlags_SizingFixedFit || (table->Flags & ImGuiTableFlags_SizingMask_) == ImGuiTableFlags_SizingFixedSame)
|
||||
flags |= ImGuiTableColumnFlags_WidthFixed;
|
||||
@@ -1576,27 +1640,10 @@ void ImGui::TableSetupColumn(const char* label, ImGuiTableColumnFlags flags, flo
|
||||
column->InitStretchWeightOrWidth = init_width_or_weight;
|
||||
if (table->IsInitializing)
|
||||
{
|
||||
// Init width or weight
|
||||
ImGuiTableFlags init_flags = ~table->SettingsLoadedFlags;
|
||||
if (column->WidthRequest < 0.0f && column->StretchWeight < 0.0f)
|
||||
{
|
||||
if ((flags & ImGuiTableColumnFlags_WidthFixed) && init_width_or_weight > 0.0f)
|
||||
column->WidthRequest = init_width_or_weight;
|
||||
if (flags & ImGuiTableColumnFlags_WidthStretch)
|
||||
column->StretchWeight = (init_width_or_weight > 0.0f) ? init_width_or_weight : -1.0f;
|
||||
|
||||
// Disable auto-fit if an explicit width/weight has been specified
|
||||
if (init_width_or_weight > 0.0f)
|
||||
column->AutoFitQueue = 0x00;
|
||||
}
|
||||
|
||||
// Init default visibility/sort state
|
||||
if ((flags & ImGuiTableColumnFlags_DefaultHide) && (table->SettingsLoadedFlags & ImGuiTableFlags_Hideable) == 0)
|
||||
column->IsUserEnabled = column->IsUserEnabledNextFrame = false;
|
||||
if (flags & ImGuiTableColumnFlags_DefaultSort && (table->SettingsLoadedFlags & ImGuiTableFlags_Sortable) == 0)
|
||||
{
|
||||
column->SortOrder = 0; // Multiple columns using _DefaultSort will be reassigned unique SortOrder values when building the sort specs.
|
||||
column->SortDirection = (column->Flags & ImGuiTableColumnFlags_PreferSortDescending) ? (ImS8)ImGuiSortDirection_Descending : (ImU8)(ImGuiSortDirection_Ascending);
|
||||
}
|
||||
init_flags |= ImGuiTableFlags_Resizable;
|
||||
TableInitColumnDefaults(table, column, init_flags);
|
||||
}
|
||||
|
||||
// Store name (append with zero-terminator in contiguous buffer)
|
||||
@@ -1605,7 +1652,7 @@ void ImGui::TableSetupColumn(const char* label, ImGuiTableColumnFlags flags, flo
|
||||
if (label != NULL && label[0] != 0)
|
||||
{
|
||||
column->NameOffset = (ImS16)table->ColumnsNames.size();
|
||||
table->ColumnsNames.append(label, label + strlen(label) + 1);
|
||||
table->ColumnsNames.append(label, label + ImStrlen(label) + 1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1614,7 +1661,11 @@ void ImGui::TableSetupScrollFreeze(int columns, int rows)
|
||||
{
|
||||
ImGuiContext& g = *GImGui;
|
||||
ImGuiTable* table = g.CurrentTable;
|
||||
IM_ASSERT(table != NULL && "Need to call TableSetupColumn() after BeginTable()!");
|
||||
if (table == NULL)
|
||||
{
|
||||
IM_ASSERT_USER_ERROR(table != NULL, "Call should only be done while in BeginTable() scope!");
|
||||
return;
|
||||
}
|
||||
IM_ASSERT(table->IsLayoutLocked == false && "Need to call TableSetupColumn() before first row!");
|
||||
IM_ASSERT(columns >= 0 && columns < IMGUI_TABLE_MAX_COLUMNS);
|
||||
IM_ASSERT(rows >= 0 && rows < 128); // Arbitrary limit
|
||||
@@ -1691,9 +1742,11 @@ void ImGui::TableSetColumnEnabled(int column_n, bool enabled)
|
||||
{
|
||||
ImGuiContext& g = *GImGui;
|
||||
ImGuiTable* table = g.CurrentTable;
|
||||
IM_ASSERT(table != NULL);
|
||||
if (!table)
|
||||
if (table == NULL)
|
||||
{
|
||||
IM_ASSERT_USER_ERROR(table != NULL, "Call should only be done while in BeginTable() scope!");
|
||||
return;
|
||||
}
|
||||
IM_ASSERT(table->Flags & ImGuiTableFlags_Hideable); // See comments above
|
||||
if (column_n < 0)
|
||||
column_n = table->CurrentColumn;
|
||||
@@ -1900,7 +1953,10 @@ void ImGui::TableEndRow(ImGuiTable* table)
|
||||
IM_ASSERT(table->IsInsideRow);
|
||||
|
||||
if (table->CurrentColumn != -1)
|
||||
{
|
||||
TableEndCell(table);
|
||||
table->CurrentColumn = -1;
|
||||
}
|
||||
|
||||
// Logging
|
||||
if (g.LogEnabled)
|
||||
@@ -1996,34 +2052,37 @@ void ImGui::TableEndRow(ImGuiTable* table)
|
||||
// We need to do that in TableEndRow() instead of TableBeginRow() so the list clipper can mark end of row and
|
||||
// get the new cursor position.
|
||||
if (unfreeze_rows_request)
|
||||
for (int column_n = 0; column_n < table->ColumnsCount; column_n++)
|
||||
table->Columns[column_n].NavLayerCurrent = ImGuiNavLayer_Main;
|
||||
if (unfreeze_rows_actual)
|
||||
{
|
||||
IM_ASSERT(table->IsUnfrozenRows == false);
|
||||
const float y0 = ImMax(table->RowPosY2 + 1, window->InnerClipRect.Min.y);
|
||||
table->IsUnfrozenRows = true;
|
||||
for (int column_n = 0; column_n < table->ColumnsCount; column_n++)
|
||||
table->Columns[column_n].NavLayerCurrent = table->NavLayer;
|
||||
const float y0 = ImMax(table->RowPosY2 + 1, table->InnerClipRect.Min.y);
|
||||
table_instance->LastFrozenHeight = y0 - table->OuterRect.Min.y;
|
||||
|
||||
// BgClipRect starts as table->InnerClipRect, reduce it now and make BgClipRectForDrawCmd == BgClipRect
|
||||
table->BgClipRect.Min.y = table->Bg2ClipRectForDrawCmd.Min.y = ImMin(y0, window->InnerClipRect.Max.y);
|
||||
table->BgClipRect.Max.y = table->Bg2ClipRectForDrawCmd.Max.y = window->InnerClipRect.Max.y;
|
||||
table->Bg2DrawChannelCurrent = table->Bg2DrawChannelUnfrozen;
|
||||
IM_ASSERT(table->Bg2ClipRectForDrawCmd.Min.y <= table->Bg2ClipRectForDrawCmd.Max.y);
|
||||
|
||||
float row_height = table->RowPosY2 - table->RowPosY1;
|
||||
table->RowPosY2 = window->DC.CursorPos.y = table->WorkRect.Min.y + table->RowPosY2 - table->OuterRect.Min.y;
|
||||
table->RowPosY1 = table->RowPosY2 - row_height;
|
||||
for (int column_n = 0; column_n < table->ColumnsCount; column_n++)
|
||||
if (unfreeze_rows_actual)
|
||||
{
|
||||
ImGuiTableColumn* column = &table->Columns[column_n];
|
||||
column->DrawChannelCurrent = column->DrawChannelUnfrozen;
|
||||
column->ClipRect.Min.y = table->Bg2ClipRectForDrawCmd.Min.y;
|
||||
}
|
||||
IM_ASSERT(table->IsUnfrozenRows == false);
|
||||
table->IsUnfrozenRows = true;
|
||||
|
||||
// Update cliprect ahead of TableBeginCell() so clipper can access to new ClipRect->Min.y
|
||||
SetWindowClipRectBeforeSetChannel(window, table->Columns[0].ClipRect);
|
||||
table->DrawSplitter->SetCurrentChannel(window->DrawList, table->Columns[0].DrawChannelCurrent);
|
||||
// BgClipRect starts as table->InnerClipRect, reduce it now and make BgClipRectForDrawCmd == BgClipRect
|
||||
table->BgClipRect.Min.y = table->Bg2ClipRectForDrawCmd.Min.y = ImMin(y0, table->InnerClipRect.Max.y);
|
||||
table->BgClipRect.Max.y = table->Bg2ClipRectForDrawCmd.Max.y = table->InnerClipRect.Max.y;
|
||||
table->Bg2DrawChannelCurrent = table->Bg2DrawChannelUnfrozen;
|
||||
IM_ASSERT(table->Bg2ClipRectForDrawCmd.Min.y <= table->Bg2ClipRectForDrawCmd.Max.y);
|
||||
|
||||
float row_height = table->RowPosY2 - table->RowPosY1;
|
||||
table->RowPosY2 = window->DC.CursorPos.y = table->WorkRect.Min.y + table->RowPosY2 - table->OuterRect.Min.y;
|
||||
table->RowPosY1 = table->RowPosY2 - row_height;
|
||||
for (int column_n = 0; column_n < table->ColumnsCount; column_n++)
|
||||
{
|
||||
ImGuiTableColumn* column = &table->Columns[column_n];
|
||||
column->DrawChannelCurrent = column->DrawChannelUnfrozen;
|
||||
column->ClipRect.Min.y = table->Bg2ClipRectForDrawCmd.Min.y;
|
||||
}
|
||||
|
||||
// Update cliprect ahead of TableBeginCell() so clipper can access to new ClipRect->Min.y
|
||||
SetWindowClipRectBeforeSetChannel(window, table->Columns[0].ClipRect);
|
||||
table->DrawSplitter->SetCurrentChannel(window->DrawList, table->Columns[0].DrawChannelCurrent);
|
||||
}
|
||||
}
|
||||
|
||||
if (!(table->RowFlags & ImGuiTableRowFlags_Headers))
|
||||
@@ -2062,7 +2121,11 @@ bool ImGui::TableSetColumnIndex(int column_n)
|
||||
{
|
||||
if (table->CurrentColumn != -1)
|
||||
TableEndCell(table);
|
||||
IM_ASSERT(column_n >= 0 && table->ColumnsCount);
|
||||
if ((column_n >= 0 && column_n < table->ColumnsCount) == false)
|
||||
{
|
||||
IM_ASSERT_USER_ERROR(column_n >= 0 && column_n < table->ColumnsCount, "TableSetColumnIndex() invalid column index!");
|
||||
return false;
|
||||
}
|
||||
TableBeginCell(table, column_n);
|
||||
}
|
||||
|
||||
@@ -2133,6 +2196,7 @@ void ImGui::TableBeginCell(ImGuiTable* table, int column_n)
|
||||
g.LastItemData.StatusFlags = 0;
|
||||
}
|
||||
|
||||
// Also see TablePushColumnChannel()
|
||||
if (table->Flags & ImGuiTableFlags_NoClip)
|
||||
{
|
||||
// FIXME: if we end up drawing all borders/bg in EndTable, could remove this and just assert that channel hasn't changed.
|
||||
@@ -2192,8 +2256,8 @@ void ImGui::TableEndCell(ImGuiTable* table)
|
||||
// Note that actual columns widths are computed in TableUpdateLayout().
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
// Maximum column content width given current layout. Use column->MinX so this value on a per-column basis.
|
||||
float ImGui::TableGetMaxColumnWidth(const ImGuiTable* table, int column_n)
|
||||
// Maximum column content width given current layout. Use column->MinX so this value differs on a per-column basis.
|
||||
float ImGui::TableCalcMaxColumnWidth(const ImGuiTable* table, int column_n)
|
||||
{
|
||||
const ImGuiTableColumn* column = &table->Columns[column_n];
|
||||
float max_width = FLT_MAX;
|
||||
@@ -2255,7 +2319,7 @@ void ImGui::TableSetColumnWidth(int column_n, float width)
|
||||
// Compare both requested and actual given width to avoid overwriting requested width when column is stuck (minimum size, bounded)
|
||||
IM_ASSERT(table->MinColumnWidth > 0.0f);
|
||||
const float min_width = table->MinColumnWidth;
|
||||
const float max_width = ImMax(min_width, TableGetMaxColumnWidth(table, column_n));
|
||||
const float max_width = ImMax(min_width, column_0->WidthMax); // Don't use TableCalcMaxColumnWidth() here as it would rely on MinX from last instance (#7933)
|
||||
column_0_width = ImClamp(column_0_width, min_width, max_width);
|
||||
if (column_0->WidthGiven == column_0_width || column_0->WidthRequest == column_0_width)
|
||||
return;
|
||||
@@ -2406,10 +2470,38 @@ void ImGui::TablePopBackgroundChannel()
|
||||
ImGuiContext& g = *GImGui;
|
||||
ImGuiWindow* window = g.CurrentWindow;
|
||||
ImGuiTable* table = g.CurrentTable;
|
||||
ImGuiTableColumn* column = &table->Columns[table->CurrentColumn];
|
||||
|
||||
// Optimization: avoid PopClipRect() + SetCurrentChannel()
|
||||
SetWindowClipRectBeforeSetChannel(window, table->HostBackupInnerClipRect);
|
||||
table->DrawSplitter->SetCurrentChannel(window->DrawList, table->Columns[table->CurrentColumn].DrawChannelCurrent);
|
||||
}
|
||||
|
||||
// Also see TableBeginCell()
|
||||
void ImGui::TablePushColumnChannel(int column_n)
|
||||
{
|
||||
ImGuiContext& g = *GImGui;
|
||||
ImGuiTable* table = g.CurrentTable;
|
||||
|
||||
// Optimization: avoid SetCurrentChannel() + PushClipRect()
|
||||
if (table->Flags & ImGuiTableFlags_NoClip)
|
||||
return;
|
||||
ImGuiWindow* window = g.CurrentWindow;
|
||||
const ImGuiTableColumn* column = &table->Columns[column_n];
|
||||
SetWindowClipRectBeforeSetChannel(window, column->ClipRect);
|
||||
table->DrawSplitter->SetCurrentChannel(window->DrawList, column->DrawChannelCurrent);
|
||||
}
|
||||
|
||||
void ImGui::TablePopColumnChannel()
|
||||
{
|
||||
ImGuiContext& g = *GImGui;
|
||||
ImGuiTable* table = g.CurrentTable;
|
||||
|
||||
// Optimization: avoid PopClipRect() + SetCurrentChannel()
|
||||
if ((table->Flags & ImGuiTableFlags_NoClip) || (table->CurrentColumn == -1)) // Calling TreePop() after TableNextRow() is supported.
|
||||
return;
|
||||
ImGuiWindow* window = g.CurrentWindow;
|
||||
const ImGuiTableColumn* column = &table->Columns[table->CurrentColumn];
|
||||
SetWindowClipRectBeforeSetChannel(window, column->ClipRect);
|
||||
table->DrawSplitter->SetCurrentChannel(window->DrawList, column->DrawChannelCurrent);
|
||||
}
|
||||
|
||||
@@ -2740,7 +2832,7 @@ void ImGui::TableDrawBorders(ImGuiTable* table)
|
||||
const ImU32 outer_col = table->BorderColorStrong;
|
||||
if ((table->Flags & ImGuiTableFlags_BordersOuter) == ImGuiTableFlags_BordersOuter)
|
||||
{
|
||||
inner_drawlist->AddRect(outer_border.Min, outer_border.Max + ImVec2(1, 1), outer_col, 0.0f, 0, border_size);
|
||||
inner_drawlist->AddRect(outer_border.Min, outer_border.Max, outer_col, 0.0f, 0, border_size);
|
||||
}
|
||||
else if (table->Flags & ImGuiTableFlags_BordersOuterV)
|
||||
{
|
||||
@@ -3004,15 +3096,21 @@ float ImGui::TableGetHeaderAngledMaxLabelWidth()
|
||||
// The intent is that advanced users willing to create customized headers would not need to use this helper
|
||||
// and can create their own! For example: TableHeader() may be preceded by Checkbox() or other custom widgets.
|
||||
// See 'Demo->Tables->Custom headers' for a demonstration of implementing a custom version of this.
|
||||
// This code is constructed to not make much use of internal functions, as it is intended to be a template to copy.
|
||||
// This code is intentionally written to not make much use of internal functions, to give you better direction
|
||||
// if you need to write your own.
|
||||
// FIXME-TABLE: TableOpenContextMenu() and TableGetHeaderRowHeight() are not public.
|
||||
void ImGui::TableHeadersRow()
|
||||
{
|
||||
ImGuiContext& g = *GImGui;
|
||||
ImGuiTable* table = g.CurrentTable;
|
||||
IM_ASSERT(table != NULL && "Need to call TableHeadersRow() after BeginTable()!");
|
||||
if (table == NULL)
|
||||
{
|
||||
IM_ASSERT_USER_ERROR(table != NULL, "Call should only be done while in BeginTable() scope!");
|
||||
return;
|
||||
}
|
||||
|
||||
// Layout if not already done (this is automatically done by TableNextRow, we do it here solely to facilitate stepping in debugger as it is frequent to step in TableUpdateLayout)
|
||||
// Call layout if not already done. This is automatically done by TableNextRow: we do it here _only_ to make
|
||||
// it easier to debug-step in TableUpdateLayout(). Your own version of this function doesn't need this.
|
||||
if (!table->IsLayoutLocked)
|
||||
TableUpdateLayout(table);
|
||||
|
||||
@@ -3029,8 +3127,7 @@ void ImGui::TableHeadersRow()
|
||||
if (!TableSetColumnIndex(column_n))
|
||||
continue;
|
||||
|
||||
// Push an id to allow unnamed labels (generally accidental, but let's behave nicely with them)
|
||||
// In your own code you may omit the PushID/PopID all-together, provided you know they won't collide.
|
||||
// Push an id to allow empty/unnamed headers. This is also idiomatic as it ensure there is a consistent ID path to access columns (for e.g. automation)
|
||||
const char* name = (TableGetColumnFlags(column_n) & ImGuiTableColumnFlags_NoHeaderLabel) ? "" : TableGetColumnName(column_n);
|
||||
PushID(column_n);
|
||||
TableHeader(name);
|
||||
@@ -3055,7 +3152,12 @@ void ImGui::TableHeader(const char* label)
|
||||
return;
|
||||
|
||||
ImGuiTable* table = g.CurrentTable;
|
||||
IM_ASSERT(table != NULL && "Need to call TableHeader() after BeginTable()!");
|
||||
if (table == NULL)
|
||||
{
|
||||
IM_ASSERT_USER_ERROR(table != NULL, "Call should only be done while in BeginTable() scope!");
|
||||
return;
|
||||
}
|
||||
|
||||
IM_ASSERT(table->CurrentColumn != -1);
|
||||
const int column_n = table->CurrentColumn;
|
||||
ImGuiTableColumn* column = &table->Columns[column_n];
|
||||
@@ -3121,7 +3223,7 @@ void ImGui::TableHeader(const char* label)
|
||||
if ((table->RowFlags & ImGuiTableRowFlags_Headers) == 0)
|
||||
TableSetBgColor(ImGuiTableBgTarget_CellBg, GetColorU32(ImGuiCol_TableHeaderBg), table->CurrentColumn);
|
||||
}
|
||||
RenderNavHighlight(bb, id, ImGuiNavHighlightFlags_Compact | ImGuiNavHighlightFlags_NoRounding);
|
||||
RenderNavCursor(bb, id, ImGuiNavRenderCursorFlags_Compact | ImGuiNavRenderCursorFlags_NoRounding);
|
||||
if (held)
|
||||
table->HeldHeaderColumn = (ImGuiTableColumnIdx)column_n;
|
||||
window->DC.CursorPos.y -= g.Style.ItemSpacing.y * 0.5f;
|
||||
@@ -3176,7 +3278,7 @@ void ImGui::TableHeader(const char* label)
|
||||
// Render clipped label. Clipping here ensure that in the majority of situations, all our header cells will
|
||||
// be merged into a single draw call.
|
||||
//window->DrawList->AddCircleFilled(ImVec2(ellipsis_max, label_pos.y), 40, IM_COL32_WHITE);
|
||||
RenderTextEllipsis(window->DrawList, label_pos, ImVec2(ellipsis_max, label_pos.y + label_height + g.Style.FramePadding.y), ellipsis_max, ellipsis_max, label, label_end, &label_size);
|
||||
RenderTextEllipsis(window->DrawList, label_pos, ImVec2(ellipsis_max, bb.Max.y), ellipsis_max, label, label_end, &label_size);
|
||||
|
||||
const bool text_clipped = label_size.x > (ellipsis_max - label_pos.x);
|
||||
if (text_clipped && hovered && g.ActiveId == 0)
|
||||
@@ -3230,7 +3332,11 @@ void ImGui::TableAngledHeadersRowEx(ImGuiID row_id, float angle, float max_label
|
||||
ImGuiTable* table = g.CurrentTable;
|
||||
ImGuiWindow* window = g.CurrentWindow;
|
||||
ImDrawList* draw_list = window->DrawList;
|
||||
IM_ASSERT(table != NULL && "Need to call TableHeadersRow() after BeginTable()!");
|
||||
if (table == NULL)
|
||||
{
|
||||
IM_ASSERT_USER_ERROR(table != NULL, "Call should only be done while in BeginTable() scope!");
|
||||
return;
|
||||
}
|
||||
IM_ASSERT(table->CurrentRow == -1 && "Must be first row");
|
||||
|
||||
if (max_label_width == 0.0f)
|
||||
@@ -3269,13 +3375,13 @@ void ImGui::TableAngledHeadersRowEx(ImGuiID row_id, float angle, float max_label
|
||||
ButtonBehavior(row_r, row_id, NULL, NULL);
|
||||
KeepAliveID(row_id);
|
||||
|
||||
const float ascent_scaled = g.Font->Ascent * (g.FontSize / g.Font->FontSize); // FIXME: Standardize those scaling factors better
|
||||
const float ascent_scaled = g.FontBaked->Ascent * g.FontBakedScale; // FIXME: Standardize those scaling factors better
|
||||
const float line_off_for_ascent_x = (ImMax((g.FontSize - ascent_scaled) * 0.5f, 0.0f) / -sin_a) * (flip_label ? -1.0f : 1.0f);
|
||||
const ImVec2 padding = g.Style.CellPadding; // We will always use swapped component
|
||||
const ImVec2 align = g.Style.TableAngledHeadersTextAlign;
|
||||
|
||||
// Draw background and labels in first pass, then all borders.
|
||||
float max_x = 0.0f;
|
||||
float max_x = -FLT_MAX;
|
||||
for (int pass = 0; pass < 2; pass++)
|
||||
for (int order_n = 0; order_n < data_count; order_n++)
|
||||
{
|
||||
@@ -3324,7 +3430,7 @@ void ImGui::TableAngledHeadersRowEx(ImGuiID row_id, float angle, float max_label
|
||||
ImRect clip_r(window->ClipRect.Min, window->ClipRect.Min + ImVec2(clip_width, clip_height));
|
||||
int vtx_idx_begin = draw_list->_VtxCurrentIdx;
|
||||
PushStyleColor(ImGuiCol_Text, request->TextColor);
|
||||
RenderTextEllipsis(draw_list, clip_r.Min, clip_r.Max, clip_r.Max.x, clip_r.Max.x, label_name, label_name_eol, &label_size);
|
||||
RenderTextEllipsis(draw_list, clip_r.Min, clip_r.Max, clip_r.Max.x, label_name, label_name_eol, &label_size);
|
||||
PopStyleColor();
|
||||
int vtx_idx_end = draw_list->_VtxCurrentIdx;
|
||||
|
||||
@@ -3471,7 +3577,7 @@ void ImGui::TableDrawDefaultContextMenu(ImGuiTable* table, ImGuiTableFlags flags
|
||||
Separator();
|
||||
want_separator = true;
|
||||
|
||||
PushItemFlag(ImGuiItemFlags_SelectableDontClosePopup, true);
|
||||
PushItemFlag(ImGuiItemFlags_AutoClosePopups, false);
|
||||
for (int other_column_n = 0; other_column_n < table->ColumnsCount; other_column_n++)
|
||||
{
|
||||
ImGuiTableColumn* other_column = &table->Columns[other_column_n];
|
||||
@@ -3661,6 +3767,14 @@ void ImGui::TableLoadSettings(ImGuiTable* table)
|
||||
table->SettingsLoadedFlags = settings->SaveFlags;
|
||||
table->RefScale = settings->RefScale;
|
||||
|
||||
// Initialize default columns settings
|
||||
for (int column_n = 0; column_n < table->ColumnsCount; column_n++)
|
||||
{
|
||||
ImGuiTableColumn* column = &table->Columns[column_n];
|
||||
TableInitColumnDefaults(table, column, ~0);
|
||||
column->AutoFitQueue = 0x00;
|
||||
}
|
||||
|
||||
// Serialize ImGuiTableSettings/ImGuiTableColumnSettings into ImGuiTable/ImGuiTableColumn
|
||||
ImGuiTableColumnSettings* column_settings = settings->GetColumnSettings();
|
||||
ImU64 display_order_mask = 0;
|
||||
@@ -3677,14 +3791,12 @@ void ImGui::TableLoadSettings(ImGuiTable* table)
|
||||
column->StretchWeight = column_settings->WidthOrWeight;
|
||||
else
|
||||
column->WidthRequest = column_settings->WidthOrWeight;
|
||||
column->AutoFitQueue = 0x00;
|
||||
}
|
||||
if (settings->SaveFlags & ImGuiTableFlags_Reorderable)
|
||||
column->DisplayOrder = column_settings->DisplayOrder;
|
||||
else
|
||||
column->DisplayOrder = (ImGuiTableColumnIdx)column_n;
|
||||
display_order_mask |= (ImU64)1 << column->DisplayOrder;
|
||||
column->IsUserEnabled = column->IsUserEnabledNextFrame = column_settings->IsEnabled;
|
||||
if ((settings->SaveFlags & ImGuiTableFlags_Hideable) && column_settings->IsEnabled != -1)
|
||||
column->IsUserEnabled = column->IsUserEnabledNextFrame = column_settings->IsEnabled == 1;
|
||||
column->SortOrder = column_settings->SortOrder;
|
||||
column->SortDirection = column_settings->SortDirection;
|
||||
}
|
||||
@@ -3780,8 +3892,7 @@ static void TableSettingsHandler_WriteAll(ImGuiContext* ctx, ImGuiSettingsHandle
|
||||
const bool save_visible = (settings->SaveFlags & ImGuiTableFlags_Hideable) != 0;
|
||||
const bool save_order = (settings->SaveFlags & ImGuiTableFlags_Reorderable) != 0;
|
||||
const bool save_sort = (settings->SaveFlags & ImGuiTableFlags_Sortable) != 0;
|
||||
if (!save_size && !save_visible && !save_order && !save_sort)
|
||||
continue;
|
||||
// We need to save the [Table] entry even if all the bools are false, since this records a table with "default settings".
|
||||
|
||||
buf->reserve(buf->size() + 30 + settings->ColumnsCount * 50); // ballpark reserve
|
||||
buf->appendf("[%s][0x%08X,%d]\n", handler->TypeName, settings->ID, settings->ColumnsCount);
|
||||
@@ -4393,7 +4504,7 @@ void ImGui::EndColumns()
|
||||
{
|
||||
ButtonBehavior(column_hit_rect, column_id, &hovered, &held);
|
||||
if (hovered || held)
|
||||
g.MouseCursor = ImGuiMouseCursor_ResizeEW;
|
||||
SetMouseCursor(ImGuiMouseCursor_ResizeEW);
|
||||
if (held && !(column->Flags & ImGuiOldColumnFlags_NoResize))
|
||||
dragging_column = n;
|
||||
}
|
||||
@@ -4425,12 +4536,12 @@ void ImGui::EndColumns()
|
||||
NavUpdateCurrentWindowIsScrollPushableX();
|
||||
}
|
||||
|
||||
void ImGui::Columns(int columns_count, const char* id, bool border)
|
||||
void ImGui::Columns(int columns_count, const char* id, bool borders)
|
||||
{
|
||||
ImGuiWindow* window = GetCurrentWindow();
|
||||
IM_ASSERT(columns_count >= 1);
|
||||
|
||||
ImGuiOldColumnFlags flags = (border ? 0 : ImGuiOldColumnFlags_NoBorder);
|
||||
ImGuiOldColumnFlags flags = (borders ? 0 : ImGuiOldColumnFlags_NoBorder);
|
||||
//flags |= ImGuiOldColumnFlags_NoPreserveWidths; // NB: Legacy behavior
|
||||
ImGuiOldColumns* columns = window->DC.CurrentColumns;
|
||||
if (columns != NULL && columns->Count == columns_count && columns->Flags == flags)
|
||||
|
||||
+2342
-764
File diff suppressed because it is too large.
Load diff
@@ -3,6 +3,8 @@
|
||||
// Those changes would need to be pushed into nothings/stb:
|
||||
// - Fix in stb_textedit_discard_redo (see https://github.com/nothings/stb/issues/321)
|
||||
// - Fix in stb_textedit_find_charpos to handle last line (see https://github.com/ocornut/imgui/issues/6000 + #6783)
|
||||
// - Added name to struct or it may be forward declared in our code.
|
||||
// - Added UTF-8 support (see https://github.com/nothings/stb/issues/188 + https://github.com/ocornut/imgui/pull/7925)
|
||||
// Grep for [DEAR IMGUI] to find the changes.
|
||||
// - Also renamed macros used or defined outside of IMSTB_TEXTEDIT_IMPLEMENTATION block from STB_TEXTEDIT_* to IMSTB_TEXTEDIT_*
|
||||
|
||||
@@ -139,6 +141,7 @@
|
||||
// with previous char)
|
||||
// STB_TEXTEDIT_KEYTOTEXT(k) maps a keyboard input to an insertable character
|
||||
// (return type is int, -1 means not valid to insert)
|
||||
// (not supported if you want to use UTF-8, see below)
|
||||
// STB_TEXTEDIT_GETCHAR(obj,i) returns the i'th character of obj, 0-based
|
||||
// STB_TEXTEDIT_NEWLINE the character returned by _GETCHAR() we recognize
|
||||
// as manually wordwrapping for end-of-line positioning
|
||||
@@ -176,6 +179,13 @@
|
||||
// STB_TEXTEDIT_K_TEXTSTART2 secondary keyboard input to move cursor to start of text
|
||||
// STB_TEXTEDIT_K_TEXTEND2 secondary keyboard input to move cursor to end of text
|
||||
//
|
||||
// To support UTF-8:
|
||||
//
|
||||
// STB_TEXTEDIT_GETPREVCHARINDEX returns index of previous character
|
||||
// STB_TEXTEDIT_GETNEXTCHARINDEX returns index of next character
|
||||
// Do NOT define STB_TEXTEDIT_KEYTOTEXT.
|
||||
// Instead, call stb_textedit_text() directly for text contents.
|
||||
//
|
||||
// Keyboard input must be encoded as a single integer value; e.g. a character code
|
||||
// and some bitflags that represent shift states. to simplify the interface, SHIFT must
|
||||
// be a bitflag, so we can test the shifted state of cursor movements to allow selection,
|
||||
@@ -209,6 +219,7 @@
|
||||
// int stb_textedit_cut(STB_TEXTEDIT_STRING *str, STB_TexteditState *state)
|
||||
// int stb_textedit_paste(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, STB_TEXTEDIT_CHARTYPE *text, int len)
|
||||
// void stb_textedit_key(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, STB_TEXEDIT_KEYTYPE key)
|
||||
// void stb_textedit_text(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, STB_TEXTEDIT_CHARTYPE *text, int text_len)
|
||||
//
|
||||
// Each of these functions potentially updates the string and updates the
|
||||
// state.
|
||||
@@ -243,7 +254,14 @@
|
||||
// various definitions like STB_TEXTEDIT_K_LEFT have the is-key-event bit
|
||||
// set, and make STB_TEXTEDIT_KEYTOCHAR check that the is-key-event bit is
|
||||
// clear. STB_TEXTEDIT_KEYTYPE defaults to int, but you can #define it to
|
||||
// anything other type you wante before including.
|
||||
// anything other type you want before including.
|
||||
// if the STB_TEXTEDIT_KEYTOTEXT function is defined, selected keys are
|
||||
// transformed into text and stb_textedit_text() is automatically called.
|
||||
//
|
||||
// text: (added 2025)
|
||||
// call this to directly send text input the textfield, which is required
|
||||
// for UTF-8 support, because stb_textedit_key() + STB_TEXTEDIT_KEYTOTEXT()
|
||||
// cannot infer text length.
|
||||
//
|
||||
//
|
||||
// When rendering, you can read the cursor position and selection state from
|
||||
@@ -318,7 +336,7 @@ typedef struct
|
||||
int undo_char_point, redo_char_point;
|
||||
} StbUndoState;
|
||||
|
||||
typedef struct
|
||||
typedef struct STB_TexteditState
|
||||
{
|
||||
/////////////////////
|
||||
//
|
||||
@@ -392,6 +410,16 @@ typedef struct
|
||||
#define IMSTB_TEXTEDIT_memmove memmove
|
||||
#endif
|
||||
|
||||
// [DEAR IMGUI]
|
||||
// Functions must be implemented for UTF8 support
|
||||
// Code in this file that uses those functions is modified for [DEAR IMGUI] and deviates from the original stb_textedit.
|
||||
// There is not necessarily a '[DEAR IMGUI]' at the usage sites.
|
||||
#ifndef IMSTB_TEXTEDIT_GETPREVCHARINDEX
|
||||
#define IMSTB_TEXTEDIT_GETPREVCHARINDEX(OBJ, IDX) ((IDX) - 1)
|
||||
#endif
|
||||
#ifndef IMSTB_TEXTEDIT_GETNEXTCHARINDEX
|
||||
#define IMSTB_TEXTEDIT_GETNEXTCHARINDEX(OBJ, IDX) ((IDX) + 1)
|
||||
#endif
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
@@ -438,13 +466,13 @@ static int stb_text_locate_coord(IMSTB_TEXTEDIT_STRING *str, float x, float y)
|
||||
if (x < r.x1) {
|
||||
// search characters in row for one that straddles 'x'
|
||||
prev_x = r.x0;
|
||||
for (k=0; k < r.num_chars; ++k) {
|
||||
for (k=0; k < r.num_chars; k = IMSTB_TEXTEDIT_GETNEXTCHARINDEX(str, i + k) - i) {
|
||||
float w = STB_TEXTEDIT_GETWIDTH(str, i, k);
|
||||
if (x < prev_x+w) {
|
||||
if (x < prev_x+w/2)
|
||||
return k+i;
|
||||
else
|
||||
return k+i+1;
|
||||
return IMSTB_TEXTEDIT_GETNEXTCHARINDEX(str, i + k);
|
||||
}
|
||||
prev_x += w;
|
||||
}
|
||||
@@ -563,7 +591,7 @@ static void stb_textedit_find_charpos(StbFindState *find, IMSTB_TEXTEDIT_STRING
|
||||
|
||||
// now scan to find xpos
|
||||
find->x = r.x0;
|
||||
for (i=0; first+i < n; ++i)
|
||||
for (i=0; first+i < n; i = IMSTB_TEXTEDIT_GETNEXTCHARINDEX(str, first + i) - first)
|
||||
find->x += STB_TEXTEDIT_GETWIDTH(str, first, i);
|
||||
}
|
||||
|
||||
@@ -649,9 +677,9 @@ static int is_word_boundary( IMSTB_TEXTEDIT_STRING *str, int idx )
|
||||
#ifndef STB_TEXTEDIT_MOVEWORDLEFT
|
||||
static int stb_textedit_move_to_word_previous( IMSTB_TEXTEDIT_STRING *str, int c )
|
||||
{
|
||||
--c; // always move at least one character
|
||||
while( c >= 0 && !is_word_boundary( str, c ) )
|
||||
--c;
|
||||
c = IMSTB_TEXTEDIT_GETPREVCHARINDEX( str, c ); // always move at least one character
|
||||
while (c >= 0 && !is_word_boundary(str, c))
|
||||
c = IMSTB_TEXTEDIT_GETPREVCHARINDEX(str, c);
|
||||
|
||||
if( c < 0 )
|
||||
c = 0;
|
||||
@@ -665,9 +693,9 @@ static int stb_textedit_move_to_word_previous( IMSTB_TEXTEDIT_STRING *str, int c
|
||||
static int stb_textedit_move_to_word_next( IMSTB_TEXTEDIT_STRING *str, int c )
|
||||
{
|
||||
const int len = STB_TEXTEDIT_STRINGLEN(str);
|
||||
++c; // always move at least one character
|
||||
c = IMSTB_TEXTEDIT_GETNEXTCHARINDEX(str, c); // always move at least one character
|
||||
while( c < len && !is_word_boundary( str, c ) )
|
||||
++c;
|
||||
c = IMSTB_TEXTEDIT_GETNEXTCHARINDEX(str, c);
|
||||
|
||||
if( c > len )
|
||||
c = len;
|
||||
@@ -720,36 +748,45 @@ static int stb_textedit_paste_internal(IMSTB_TEXTEDIT_STRING *str, STB_TexteditS
|
||||
#define STB_TEXTEDIT_KEYTYPE int
|
||||
#endif
|
||||
|
||||
// API key: process text input
|
||||
// [DEAR IMGUI] Added stb_textedit_text(), extracted out and called by stb_textedit_key() for backward compatibility.
|
||||
static void stb_textedit_text(IMSTB_TEXTEDIT_STRING* str, STB_TexteditState* state, const IMSTB_TEXTEDIT_CHARTYPE* text, int text_len)
|
||||
{
|
||||
// can't add newline in single-line mode
|
||||
if (text[0] == '\n' && state->single_line)
|
||||
return;
|
||||
|
||||
if (state->insert_mode && !STB_TEXT_HAS_SELECTION(state) && state->cursor < STB_TEXTEDIT_STRINGLEN(str)) {
|
||||
stb_text_makeundo_replace(str, state, state->cursor, 1, 1);
|
||||
STB_TEXTEDIT_DELETECHARS(str, state->cursor, 1);
|
||||
if (STB_TEXTEDIT_INSERTCHARS(str, state->cursor, text, text_len)) {
|
||||
state->cursor += text_len;
|
||||
state->has_preferred_x = 0;
|
||||
}
|
||||
} else {
|
||||
stb_textedit_delete_selection(str, state); // implicitly clamps
|
||||
if (STB_TEXTEDIT_INSERTCHARS(str, state->cursor, text, text_len)) {
|
||||
stb_text_makeundo_insert(state, state->cursor, text_len);
|
||||
state->cursor += text_len;
|
||||
state->has_preferred_x = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// API key: process a keyboard input
|
||||
static void stb_textedit_key(IMSTB_TEXTEDIT_STRING *str, STB_TexteditState *state, STB_TEXTEDIT_KEYTYPE key)
|
||||
{
|
||||
retry:
|
||||
switch (key) {
|
||||
default: {
|
||||
#ifdef STB_TEXTEDIT_KEYTOTEXT
|
||||
// This is not suitable for UTF-8 support.
|
||||
int c = STB_TEXTEDIT_KEYTOTEXT(key);
|
||||
if (c > 0) {
|
||||
IMSTB_TEXTEDIT_CHARTYPE ch = (IMSTB_TEXTEDIT_CHARTYPE) c;
|
||||
|
||||
// can't add newline in single-line mode
|
||||
if (c == '\n' && state->single_line)
|
||||
break;
|
||||
|
||||
if (state->insert_mode && !STB_TEXT_HAS_SELECTION(state) && state->cursor < STB_TEXTEDIT_STRINGLEN(str)) {
|
||||
stb_text_makeundo_replace(str, state, state->cursor, 1, 1);
|
||||
STB_TEXTEDIT_DELETECHARS(str, state->cursor, 1);
|
||||
if (STB_TEXTEDIT_INSERTCHARS(str, state->cursor, &ch, 1)) {
|
||||
++state->cursor;
|
||||
state->has_preferred_x = 0;
|
||||
}
|
||||
} else {
|
||||
stb_textedit_delete_selection(str,state); // implicitly clamps
|
||||
if (STB_TEXTEDIT_INSERTCHARS(str, state->cursor, &ch, 1)) {
|
||||
stb_text_makeundo_insert(state, state->cursor, 1);
|
||||
++state->cursor;
|
||||
state->has_preferred_x = 0;
|
||||
}
|
||||
}
|
||||
IMSTB_TEXTEDIT_CHARTYPE ch = (IMSTB_TEXTEDIT_CHARTYPE)c;
|
||||
stb_textedit_text(str, state, &ch, 1);
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -775,7 +812,7 @@ retry:
|
||||
stb_textedit_move_to_first(state);
|
||||
else
|
||||
if (state->cursor > 0)
|
||||
--state->cursor;
|
||||
state->cursor = IMSTB_TEXTEDIT_GETPREVCHARINDEX(str, state->cursor);
|
||||
state->has_preferred_x = 0;
|
||||
break;
|
||||
|
||||
@@ -784,7 +821,7 @@ retry:
|
||||
if (STB_TEXT_HAS_SELECTION(state))
|
||||
stb_textedit_move_to_last(str, state);
|
||||
else
|
||||
++state->cursor;
|
||||
state->cursor = IMSTB_TEXTEDIT_GETNEXTCHARINDEX(str, state->cursor);
|
||||
stb_textedit_clamp(str, state);
|
||||
state->has_preferred_x = 0;
|
||||
break;
|
||||
@@ -794,7 +831,7 @@ retry:
|
||||
stb_textedit_prep_selection_at_cursor(state);
|
||||
// move selection left
|
||||
if (state->select_end > 0)
|
||||
--state->select_end;
|
||||
state->select_end = IMSTB_TEXTEDIT_GETPREVCHARINDEX(str, state->select_end);
|
||||
state->cursor = state->select_end;
|
||||
state->has_preferred_x = 0;
|
||||
break;
|
||||
@@ -844,7 +881,7 @@ retry:
|
||||
case STB_TEXTEDIT_K_RIGHT | STB_TEXTEDIT_K_SHIFT:
|
||||
stb_textedit_prep_selection_at_cursor(state);
|
||||
// move selection right
|
||||
++state->select_end;
|
||||
state->select_end = IMSTB_TEXTEDIT_GETNEXTCHARINDEX(str, state->select_end);
|
||||
stb_textedit_clamp(str, state);
|
||||
state->cursor = state->select_end;
|
||||
state->has_preferred_x = 0;
|
||||
@@ -891,8 +928,9 @@ retry:
|
||||
state->cursor = start;
|
||||
STB_TEXTEDIT_LAYOUTROW(&row, str, state->cursor);
|
||||
x = row.x0;
|
||||
for (i=0; i < row.num_chars; ++i) {
|
||||
for (i=0; i < row.num_chars; ) {
|
||||
float dx = STB_TEXTEDIT_GETWIDTH(str, start, i);
|
||||
int next = IMSTB_TEXTEDIT_GETNEXTCHARINDEX(str, state->cursor);
|
||||
#ifdef IMSTB_TEXTEDIT_GETWIDTH_NEWLINE
|
||||
if (dx == IMSTB_TEXTEDIT_GETWIDTH_NEWLINE)
|
||||
break;
|
||||
@@ -900,7 +938,8 @@ retry:
|
||||
x += dx;
|
||||
if (x > goal_x)
|
||||
break;
|
||||
++state->cursor;
|
||||
i += next - state->cursor;
|
||||
state->cursor = next;
|
||||
}
|
||||
stb_textedit_clamp(str, state);
|
||||
|
||||
@@ -953,8 +992,9 @@ retry:
|
||||
state->cursor = find.prev_first;
|
||||
STB_TEXTEDIT_LAYOUTROW(&row, str, state->cursor);
|
||||
x = row.x0;
|
||||
for (i=0; i < row.num_chars; ++i) {
|
||||
for (i=0; i < row.num_chars; ) {
|
||||
float dx = STB_TEXTEDIT_GETWIDTH(str, find.prev_first, i);
|
||||
int next = IMSTB_TEXTEDIT_GETNEXTCHARINDEX(str, state->cursor);
|
||||
#ifdef IMSTB_TEXTEDIT_GETWIDTH_NEWLINE
|
||||
if (dx == IMSTB_TEXTEDIT_GETWIDTH_NEWLINE)
|
||||
break;
|
||||
@@ -962,7 +1002,8 @@ retry:
|
||||
x += dx;
|
||||
if (x > goal_x)
|
||||
break;
|
||||
++state->cursor;
|
||||
i += next - state->cursor;
|
||||
state->cursor = next;
|
||||
}
|
||||
stb_textedit_clamp(str, state);
|
||||
|
||||
@@ -975,8 +1016,13 @@ retry:
|
||||
// go to previous line
|
||||
// (we need to scan previous line the hard way. maybe we could expose this as a new API function?)
|
||||
prev_scan = find.prev_first > 0 ? find.prev_first - 1 : 0;
|
||||
while (prev_scan > 0 && STB_TEXTEDIT_GETCHAR(str, prev_scan - 1) != STB_TEXTEDIT_NEWLINE)
|
||||
--prev_scan;
|
||||
while (prev_scan > 0)
|
||||
{
|
||||
int prev = IMSTB_TEXTEDIT_GETPREVCHARINDEX(str, prev_scan);
|
||||
if (STB_TEXTEDIT_GETCHAR(str, prev) == STB_TEXTEDIT_NEWLINE)
|
||||
break;
|
||||
prev_scan = prev;
|
||||
}
|
||||
find.first_char = find.prev_first;
|
||||
find.prev_first = prev_scan;
|
||||
}
|
||||
@@ -990,7 +1036,7 @@ retry:
|
||||
else {
|
||||
int n = STB_TEXTEDIT_STRINGLEN(str);
|
||||
if (state->cursor < n)
|
||||
stb_textedit_delete(str, state, state->cursor, 1);
|
||||
stb_textedit_delete(str, state, state->cursor, IMSTB_TEXTEDIT_GETNEXTCHARINDEX(str, state->cursor) - state->cursor);
|
||||
}
|
||||
state->has_preferred_x = 0;
|
||||
break;
|
||||
@@ -1002,8 +1048,9 @@ retry:
|
||||
else {
|
||||
stb_textedit_clamp(str, state);
|
||||
if (state->cursor > 0) {
|
||||
stb_textedit_delete(str, state, state->cursor-1, 1);
|
||||
--state->cursor;
|
||||
int prev = IMSTB_TEXTEDIT_GETPREVCHARINDEX(str, state->cursor);
|
||||
stb_textedit_delete(str, state, prev, state->cursor - prev);
|
||||
state->cursor = prev;
|
||||
}
|
||||
}
|
||||
state->has_preferred_x = 0;
|
||||
@@ -1054,7 +1101,7 @@ retry:
|
||||
if (state->single_line)
|
||||
state->cursor = 0;
|
||||
else while (state->cursor > 0 && STB_TEXTEDIT_GETCHAR(str, state->cursor-1) != STB_TEXTEDIT_NEWLINE)
|
||||
--state->cursor;
|
||||
state->cursor = IMSTB_TEXTEDIT_GETPREVCHARINDEX(str, state->cursor);
|
||||
state->has_preferred_x = 0;
|
||||
break;
|
||||
|
||||
@@ -1066,9 +1113,9 @@ retry:
|
||||
stb_textedit_clamp(str, state);
|
||||
stb_textedit_move_to_first(state);
|
||||
if (state->single_line)
|
||||
state->cursor = n;
|
||||
state->cursor = n;
|
||||
else while (state->cursor < n && STB_TEXTEDIT_GETCHAR(str, state->cursor) != STB_TEXTEDIT_NEWLINE)
|
||||
++state->cursor;
|
||||
state->cursor = IMSTB_TEXTEDIT_GETNEXTCHARINDEX(str, state->cursor);
|
||||
state->has_preferred_x = 0;
|
||||
break;
|
||||
}
|
||||
@@ -1082,7 +1129,7 @@ retry:
|
||||
if (state->single_line)
|
||||
state->cursor = 0;
|
||||
else while (state->cursor > 0 && STB_TEXTEDIT_GETCHAR(str, state->cursor-1) != STB_TEXTEDIT_NEWLINE)
|
||||
--state->cursor;
|
||||
state->cursor = IMSTB_TEXTEDIT_GETPREVCHARINDEX(str, state->cursor);
|
||||
state->select_end = state->cursor;
|
||||
state->has_preferred_x = 0;
|
||||
break;
|
||||
@@ -1097,7 +1144,7 @@ retry:
|
||||
if (state->single_line)
|
||||
state->cursor = n;
|
||||
else while (state->cursor < n && STB_TEXTEDIT_GETCHAR(str, state->cursor) != STB_TEXTEDIT_NEWLINE)
|
||||
++state->cursor;
|
||||
state->cursor = IMSTB_TEXTEDIT_GETNEXTCHARINDEX(str, state->cursor);
|
||||
state->select_end = state->cursor;
|
||||
state->has_preferred_x = 0;
|
||||
break;
|
||||
|
||||
@@ -4516,8 +4516,8 @@ static int stbtt__compute_crossings_x(float x, float y, int nverts, stbtt_vertex
|
||||
q2[0] = (float)x2;
|
||||
q2[1] = (float)y2;
|
||||
if (equal(q0,q1) || equal(q1,q2)) {
|
||||
x0 = (int)verts[i-1].x;
|
||||
y0 = (int)verts[i-1].y;
|
||||
x0 = (int)verts[i-1].x; //-V1048
|
||||
y0 = (int)verts[i-1].y; //-V1048
|
||||
x1 = (int)verts[i ].x;
|
||||
y1 = (int)verts[i ].y;
|
||||
if (y > STBTT_min(y0,y1) && y < STBTT_max(y0,y1) && x > STBTT_min(x0,x1)) {
|
||||
|
||||
+1
-1
Submodule core/deps/libadrenotools updated: 5deac9f1ab...8fae8ce254.
+1
-1
Submodule core/deps/libchdr updated: 9b6ff6c3c2...5f82799f2c.
Submodule
+1
Submodule core/deps/libjuice added at 77daa8befd.
@@ -31,7 +31,7 @@
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
#if defined(_WIN32) && !defined(USE_LIBCDIO) // libcdio has its equivalent version
|
||||
#undef fopen
|
||||
|
||||
void *fopen_utf8(const char * filename, const char * mode)
|
||||
|
||||
Submodule
+1
Submodule core/deps/libusb-cmake added at 000e06eb24.
@@ -190,7 +190,9 @@ int main(int argc, char *argv[]) { }" HAVE_NULLABLE)
|
||||
|
||||
test_big_endian(WORDS_BIGENDIAN)
|
||||
|
||||
find_package(ZLIB 1.1.2 REQUIRED)
|
||||
if(NOT TARGET zlibstatic)
|
||||
find_package(ZLIB 1.1.2 REQUIRED)
|
||||
endif()
|
||||
# so developers on systems where zlib is named differently (Windows, sometimes)
|
||||
# can override the name used in the pkg-config file
|
||||
if (NOT ZLIB_LINK_LIBRARY_NAME)
|
||||
@@ -239,17 +241,22 @@ if(ENABLE_LZMA)
|
||||
endif(ENABLE_LZMA)
|
||||
|
||||
if(ENABLE_ZSTD)
|
||||
find_package(zstd 1.3.6)
|
||||
if(zstd_FOUND)
|
||||
if(TARGET libzstd_static)
|
||||
set(zstd_TARGET libzstd_static)
|
||||
set(HAVE_LIBZSTD 1)
|
||||
if(TARGET zstd::libzstd_shared)
|
||||
set(zstd_TARGET zstd::libzstd_shared)
|
||||
else()
|
||||
set(zstd_TARGET zstd::libzstd_static)
|
||||
endif()
|
||||
else()
|
||||
message(WARNING "-- zstd library not found; zstandard support disabled")
|
||||
endif(zstd_FOUND)
|
||||
find_package(zstd 1.3.6)
|
||||
if(zstd_FOUND)
|
||||
set(HAVE_LIBZSTD 1)
|
||||
if(TARGET zstd::libzstd_shared)
|
||||
set(zstd_TARGET zstd::libzstd_shared)
|
||||
else()
|
||||
set(zstd_TARGET zstd::libzstd_static)
|
||||
endif()
|
||||
else()
|
||||
message(WARNING "-- zstd library not found; zstandard support disabled")
|
||||
endif()
|
||||
endif()
|
||||
endif(ENABLE_ZSTD)
|
||||
|
||||
if (COMMONCRYPTO_FOUND)
|
||||
|
||||
@@ -175,7 +175,11 @@ if(SHARED_LIB_VERSIONNING)
|
||||
set_target_properties(zip PROPERTIES VERSION 5.5 SOVERSION 5)
|
||||
endif()
|
||||
|
||||
target_link_libraries(zip PRIVATE ZLIB::ZLIB)
|
||||
if (TARGET zlibstatic)
|
||||
target_link_libraries(zip PRIVATE zlibstatic)
|
||||
else()
|
||||
target_link_libraries(zip PRIVATE ZLIB::ZLIB)
|
||||
endif()
|
||||
target_include_directories(zip
|
||||
PUBLIC
|
||||
$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/lib>
|
||||
|
||||
+1
-1
Submodule core/deps/luabridge updated: fab7b33b89...5d21e35633.
@@ -338,7 +338,7 @@ receiveDevicesFromMiniSSDPD(int s, int * error)
|
||||
#ifdef DEBUG
|
||||
printf(" usnsize=%u\n", usnsize);
|
||||
#endif /* DEBUG */
|
||||
tmp = (struct UPNPDev *)malloc(sizeof(struct UPNPDev)+urlsize+stsize+usnsize);
|
||||
tmp = (struct UPNPDev *)malloc(sizeof(struct UPNPDev)+urlsize+stsize+usnsize+3);
|
||||
if(tmp == NULL) {
|
||||
if (error)
|
||||
*error = MINISSDPC_MEMORY_ERROR;
|
||||
|
||||
+1
-1
Submodule core/deps/oboe updated: 03242e9ef9...a81bb9f87d.
@@ -7,6 +7,8 @@
|
||||
#include <windows.h>
|
||||
#pragma pack(pop)
|
||||
|
||||
#define PICO_SUPPORT_THREADING
|
||||
|
||||
#if defined(_MSC_VER) || defined(_MSC_EXTENSIONS)
|
||||
#define DELTA_EPOCH_IN_MICROSECS 11644473600000000Ui64
|
||||
#else
|
||||
@@ -54,6 +56,15 @@ static inline void PICO_IDLE(void)
|
||||
|
||||
#define alloca _alloca
|
||||
|
||||
#ifdef PICO_SUPPORT_THREADING
|
||||
#define PICO_SUPPORT_MUTEX
|
||||
/* mutex implementations */
|
||||
extern void* pico_mutex_init(void);
|
||||
extern void pico_mutex_lock(void* mux);
|
||||
extern void pico_mutex_unlock(void* mux);
|
||||
extern void pico_mutex_deinit(void* mux);
|
||||
#endif
|
||||
|
||||
#endif /* PICO_SUPPORT_MSVC */
|
||||
|
||||
|
||||
@@ -170,6 +170,7 @@ struct pico_ip_mreq_source {
|
||||
#define PICO_SOCK_EV_CLOSE 8u
|
||||
#define PICO_SOCK_EV_FIN 0x10u
|
||||
#define PICO_SOCK_EV_ERR 0x80u
|
||||
#define PICO_SOCK_EV_DEL 0x100u
|
||||
|
||||
struct pico_msginfo {
|
||||
struct pico_device *dev;
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
#include "pico_frame.h"
|
||||
#include "pico_constants.h"
|
||||
|
||||
#define PICO_MAX_TIMERS 20
|
||||
#define PICO_MAX_TIMERS 50
|
||||
|
||||
#define PICO_ETH_MRU (1514u)
|
||||
#define PICO_IP_MRU (1500u)
|
||||
|
||||
@@ -319,7 +319,7 @@ static void pppdump(uint8_t *buf, int len, int egress)
|
||||
last_time_ms = PICO_TIME_MS();
|
||||
}
|
||||
|
||||
uint32_t delta = (PICO_TIME_MS() - last_time_ms) / 100;
|
||||
uint32_t delta = PICO_TIME_MS() / 100 - last_time_ms / 100;
|
||||
if (delta < 256)
|
||||
{
|
||||
fputc(6, dumpfp); // Time step (short)
|
||||
|
||||
@@ -295,7 +295,7 @@ static int pico_ethernet_ipv6_dst(struct pico_frame *f, struct pico_eth *const d
|
||||
|
||||
/* Ethernet send, first attempt: try our own address.
|
||||
* Returns 0 if the packet is not for us.
|
||||
* Returns 1 if the packet is cloned to our own receive queue, so the caller can discard the original frame.
|
||||
* Returns 1 if the packet is cloned to our own receive queue and the original frame is dicarded.
|
||||
* */
|
||||
static int32_t pico_ethsend_local(struct pico_frame *f, struct pico_eth_hdr *hdr)
|
||||
{
|
||||
@@ -308,7 +308,9 @@ static int32_t pico_ethsend_local(struct pico_frame *f, struct pico_eth_hdr *hdr
|
||||
dbg("sending out packet destined for our own mac\n");
|
||||
if (pico_ethernet_receive(clone) < 0) {
|
||||
dbg("pico_ethernet_receive() failed\n");
|
||||
return 0;
|
||||
}
|
||||
pico_frame_discard(f);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -317,13 +319,12 @@ static int32_t pico_ethsend_local(struct pico_frame *f, struct pico_eth_hdr *hdr
|
||||
|
||||
/* Ethernet send, second attempt: try bcast.
|
||||
* Returns 0 if the packet is not bcast, so it will be handled somewhere else.
|
||||
* Returns 1 if the packet is handled by the pico_device_broadcast() function, so it can be discarded.
|
||||
* Returns 1 if the packet is handled by the pico_device_broadcast() function and is discarded.
|
||||
* */
|
||||
static int32_t pico_ethsend_bcast(struct pico_frame *f)
|
||||
{
|
||||
if (IS_LIMITED_BCAST(f)) {
|
||||
(void)pico_device_broadcast(f); /* We can discard broadcast even if it's not sent. */
|
||||
return 1;
|
||||
return (pico_device_broadcast(f) > 0); // Return 1 on success, ret > 0
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -242,6 +242,10 @@ static int8_t pico_icmp4_send_echo(struct pico_icmp4_ping_cookie *cookie)
|
||||
if (!dev)
|
||||
return -1;
|
||||
|
||||
// prevent overflow
|
||||
if (cookie->size > PICO_ICMP_MAXCOOKIE)
|
||||
return -1;
|
||||
|
||||
echo = pico_proto_ipv4.alloc(&pico_proto_ipv4, dev, (uint16_t)(PICO_ICMPHDR_UN_SIZE + cookie->size));
|
||||
if (!echo)
|
||||
return -1;
|
||||
|
||||
@@ -92,7 +92,7 @@ PACKED_STRUCT_DEF pico_icmp4_hdr {
|
||||
#define PICO_ICMP_MASKREPLY 18
|
||||
|
||||
#define PICO_ICMP_MAXTYPE 18
|
||||
|
||||
#define PICO_ICMP_MAXCOOKIE 65528
|
||||
|
||||
#define PICO_ICMP_UNREACH_NET 0
|
||||
#define PICO_ICMP_UNREACH_HOST 1
|
||||
|
||||
@@ -190,7 +190,6 @@ static int socket_tcp_do_deliver(struct pico_socket *s, struct pico_frame *f)
|
||||
return 0;
|
||||
}
|
||||
|
||||
dbg("TCP SOCKET> Not s.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
@@ -826,6 +826,8 @@ static void tcp_rcv_sack(struct pico_socket_tcp *t, uint8_t *opt, int len)
|
||||
static int tcpopt_len_check(uint32_t *idx, uint8_t len, uint8_t expected)
|
||||
{
|
||||
if (len != expected) {
|
||||
if (len < 2)
|
||||
return -1;
|
||||
*idx = *idx + len - 2;
|
||||
return -1;
|
||||
}
|
||||
@@ -880,7 +882,7 @@ static inline void tcp_parse_option_timestamp(struct pico_socket_tcp *t, struct
|
||||
t->ts_nxt = long_be(tsval);
|
||||
}
|
||||
|
||||
static void tcp_parse_options(struct pico_frame *f)
|
||||
static int tcp_parse_options(struct pico_frame *f)
|
||||
{
|
||||
struct pico_socket_tcp *t = (struct pico_socket_tcp *)f->sock;
|
||||
uint8_t *opt = f->transport_hdr + PICO_SIZE_TCPHDR;
|
||||
@@ -897,6 +899,10 @@ static void tcp_parse_options(struct pico_frame *f)
|
||||
if (f->payload && ((opt + i) > f->payload))
|
||||
break;
|
||||
|
||||
if (len == 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
tcp_dbg_options("Received option '%d', len = %d \n", type, len);
|
||||
switch (type) {
|
||||
case PICO_TCP_OPTION_NOOP:
|
||||
@@ -924,6 +930,7 @@ static void tcp_parse_options(struct pico_frame *f)
|
||||
i = i + len - 2;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void tcp_send_add_tcpflags(struct pico_socket_tcp *ts, struct pico_frame *f)
|
||||
@@ -1755,7 +1762,8 @@ static int tcp_data_in(struct pico_socket *s, struct pico_frame *f)
|
||||
(void)hdr;
|
||||
|
||||
if (((hdr->len & 0xf0u) >> 2u) <= f->transport_len) {
|
||||
tcp_parse_options(f);
|
||||
if (tcp_parse_options(f) < 0)
|
||||
return -1;
|
||||
f->payload = f->transport_hdr + ((hdr->len & 0xf0u) >> 2u);
|
||||
f->payload_len = payload_len;
|
||||
tcp_dbg("TCP> Received segment. (exp: %x got: %x)\n", t->rcv_nxt, SEQN(f));
|
||||
@@ -2130,7 +2138,8 @@ static int tcp_ack(struct pico_socket *s, struct pico_frame *f)
|
||||
tcp_ack_dbg(s, f);
|
||||
#endif
|
||||
|
||||
tcp_parse_options(f);
|
||||
if (tcp_parse_options(f) < 0)
|
||||
return -1;
|
||||
t->recv_wnd = short_be(hdr->rwnd);
|
||||
|
||||
acked = (uint16_t)tcp_ack_advance_una(t, f, &acked_timestamp);
|
||||
@@ -2446,7 +2455,8 @@ static int tcp_syn(struct pico_socket *s, struct pico_frame *f)
|
||||
f->sock = &new->sock;
|
||||
mtu = (uint16_t)pico_socket_get_mss(&new->sock);
|
||||
new->mss = (uint16_t)(mtu - PICO_SIZE_TCPHDR);
|
||||
tcp_parse_options(f);
|
||||
if (tcp_parse_options(f) < 0)
|
||||
return -1;
|
||||
new->tcpq_in.max_size = PICO_DEFAULT_SOCKETQ;
|
||||
new->tcpq_out.max_size = PICO_DEFAULT_SOCKETQ;
|
||||
new->tcpq_hold.max_size = 2u * mtu;
|
||||
@@ -2793,7 +2803,7 @@ static uint8_t invalid_flags(struct pico_socket *s, uint8_t flags)
|
||||
{ /* PICO_SOCKET_STATE_TCP_UNDEF */ 0, },
|
||||
{ /* PICO_SOCKET_STATE_TCP_CLOSED */ 0, },
|
||||
{ /* PICO_SOCKET_STATE_TCP_LISTEN */ PICO_TCP_SYN, PICO_TCP_SYN | PICO_TCP_PSH },
|
||||
{ /* PICO_SOCKET_STATE_TCP_SYN_SENT */ PICO_TCP_SYNACK, PICO_TCP_RST, PICO_TCP_RSTACK},
|
||||
{ /* PICO_SOCKET_STATE_TCP_SYN_SENT */ PICO_TCP_SYNACK, PICO_TCP_RST, PICO_TCP_RSTACK, PICO_TCP_SYNACK | PICO_TCP_PSH },
|
||||
{ /* PICO_SOCKET_STATE_TCP_SYN_RECV */ PICO_TCP_SYN, PICO_TCP_ACK, PICO_TCP_PSH, PICO_TCP_PSHACK, PICO_TCP_FINACK, PICO_TCP_FINPSHACK, PICO_TCP_RST},
|
||||
{ /* PICO_SOCKET_STATE_TCP_ESTABLISHED*/ PICO_TCP_SYN, PICO_TCP_SYNACK, PICO_TCP_ACK, PICO_TCP_PSH, PICO_TCP_PSHACK, PICO_TCP_FIN, PICO_TCP_FINACK, PICO_TCP_FINPSHACK, PICO_TCP_RST, PICO_TCP_RSTACK},
|
||||
{ /* PICO_SOCKET_STATE_TCP_CLOSE_WAIT */ PICO_TCP_SYNACK, PICO_TCP_ACK, PICO_TCP_PSH, PICO_TCP_PSHACK, PICO_TCP_FIN, PICO_TCP_FINACK, PICO_TCP_FINPSHACK, PICO_TCP_RST},
|
||||
@@ -2864,6 +2874,11 @@ int pico_tcp_input(struct pico_socket *s, struct pico_frame *f)
|
||||
// tcp_dbg("[sam] TCP> s->state >> 8 = %u\n", s->state >> 8);
|
||||
tcp_dbg("[tcp input] socket: %p state: %d <-- local port:%u remote port: %u seq: 0x%08x ack: 0x%08x flags: 0x%02x t_len: %u, hdr: %u payload: %d\n", s, s->state >> 8, short_be(hdr->trans.dport), short_be(hdr->trans.sport), SEQN(f), ACKN(f), hdr->flags, f->transport_len, (hdr->len & 0xf0) >> 2, f->payload_len );
|
||||
|
||||
if ((f->payload + f->payload_len) > (f->buffer + f->buffer_len)) {
|
||||
tcp_dbg("TCP> Invalid payload len %04x\n", f->payload_len);
|
||||
pico_frame_discard(f);
|
||||
return -1;
|
||||
}
|
||||
/* This copy of the frame has the current socket as owner */
|
||||
f->sock = s;
|
||||
s->timestamp = TCP_TIME;
|
||||
@@ -2874,7 +2889,9 @@ int pico_tcp_input(struct pico_socket *s, struct pico_frame *f)
|
||||
}
|
||||
else if (flags == PICO_TCP_SYN || flags == (PICO_TCP_SYN | PICO_TCP_PSH)) {
|
||||
tcp_action_call(action->syn, s, f);
|
||||
} else if (flags == (PICO_TCP_SYN | PICO_TCP_ACK)) {
|
||||
} else if (flags == (PICO_TCP_SYN | PICO_TCP_ACK)
|
||||
// Windows CE / DirectPlay sets the PSH flag on SYN|ACK packets, which is normally invalid
|
||||
|| flags == (PICO_TCP_SYN | PICO_TCP_ACK | PICO_TCP_PSH)) {
|
||||
tcp_action_call(action->synack, s, f);
|
||||
} else {
|
||||
ret = tcp_action_by_flags(action, s, f, flags);
|
||||
|
||||
@@ -451,6 +451,7 @@ int32_t pico_device_broadcast(struct pico_frame *f)
|
||||
{
|
||||
struct pico_tree_node *index;
|
||||
int32_t ret = -1;
|
||||
int sent = 0;
|
||||
|
||||
pico_tree_foreach(index, &Device_tree)
|
||||
{
|
||||
@@ -463,14 +464,28 @@ int32_t pico_device_broadcast(struct pico_frame *f)
|
||||
break;
|
||||
|
||||
copy->dev = dev;
|
||||
copy->dev->send(copy->dev, copy->start, (int)copy->len);
|
||||
ret = copy->dev->send(copy->dev, copy->start, (int)copy->len);
|
||||
/* FIXME: If a device driver returns zero (which means the device
|
||||
* driver is currently busy) there is no means to retry the
|
||||
* broadcast operation later. */
|
||||
pico_frame_discard(copy);
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = f->dev->send(f->dev, f->start, (int)f->len);
|
||||
/* FIXME: If a device driver returns zero (which means the device
|
||||
* driver is currently busy) there is no means to retry the
|
||||
* broadcast operation later. */
|
||||
}
|
||||
|
||||
/* FIXME: If at least one device driver was able to sent the frame on
|
||||
* the wire, the broadcast operation will be considered successful. */
|
||||
if (ret > 0) {
|
||||
sent = 1;
|
||||
}
|
||||
}
|
||||
ret = sent ? f->len : -1;
|
||||
pico_frame_discard(f);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
@@ -473,6 +473,8 @@ static void socket_garbage_collect(pico_time now, void *arg)
|
||||
struct pico_socket *s = (struct pico_socket *) arg;
|
||||
IGNORE_PARAMETER(now);
|
||||
|
||||
if (s->wakeup)
|
||||
s->wakeup(PICO_SOCK_EV_DEL, s);
|
||||
socket_clean_queues(s);
|
||||
PICO_FREE(s);
|
||||
}
|
||||
|
||||
+1
-1
Submodule core/deps/rcheevos updated: 563230b1c2...3106e6d3d2.
Submodule
+1
Submodule core/deps/websocketpp added at 1b11fd3015.
@@ -1,6 +1,21 @@
|
||||
===========
|
||||
|Changelog|
|
||||
===========
|
||||
xBRZ 1.8 [2019-11-28]
|
||||
---------------------
|
||||
Consider ARGB outside area as transparent
|
||||
Fixed ARGB scaling issue on image borders
|
||||
|
||||
|
||||
xBRZ 1.7 [2019-07-04]
|
||||
---------------------
|
||||
Fixed asymmetric color distance
|
||||
New parameter: "Center direction bias"
|
||||
|
||||
|
||||
xBRZ 1.6 [2018-02-27]
|
||||
---------------------
|
||||
Added bilinear scaling
|
||||
Option to skip color buffer creation
|
||||
Updated license info
|
||||
|
||||
|
||||
xBRZ 1.5 [2017-08-07]
|
||||
---------------------
|
||||
|
||||
+439
-204
@@ -1,24 +1,25 @@
|
||||
// ****************************************************************************
|
||||
// * This file is part of the HqMAME project. It is distributed under *
|
||||
// * This file is part of the xBRZ project. It is distributed under *
|
||||
// * GNU General Public License: https://www.gnu.org/licenses/gpl-3.0 *
|
||||
// * Copyright (C) Zenju (zenju AT gmx DOT de) - All Rights Reserved *
|
||||
// * *
|
||||
// * Additionally and as a special exception, the author gives permission *
|
||||
// * to link the code of this program with the MAME library (or with modified *
|
||||
// * versions of MAME that use the same license as MAME), and distribute *
|
||||
// * linked combinations including the two. You must obey the GNU General *
|
||||
// * Public License in all respects for all of the code used other than MAME. *
|
||||
// * to link the code of this program with the following libraries *
|
||||
// * (or with modified versions that use the same licenses), and distribute *
|
||||
// * linked combinations including the two: MAME, FreeFileSync, Snes9x, ePSXe *
|
||||
// * You must obey the GNU General Public License in all respects for all of *
|
||||
// * the code used other than MAME, FreeFileSync, Snes9x, ePSXe. *
|
||||
// * If you modify this file, you may extend this exception to your version *
|
||||
// * of the file, but you are not obligated to do so. If you do not wish to *
|
||||
// * do so, delete this exception statement from your version. *
|
||||
// ****************************************************************************
|
||||
|
||||
#include "xbrz.h"
|
||||
#include "xbrz_tools.h"
|
||||
#include <cassert>
|
||||
#include <algorithm>
|
||||
#include <vector>
|
||||
#include <cmath>
|
||||
#include <algorithm>
|
||||
#include <cmath> //std::sqrt
|
||||
#include "xbrz_tools.h"
|
||||
|
||||
using namespace xbrz;
|
||||
|
||||
@@ -26,9 +27,9 @@ using namespace xbrz;
|
||||
namespace
|
||||
{
|
||||
template <unsigned int M, unsigned int N> inline
|
||||
uint32_t gradientRGB(uint32_t pixFront, uint32_t pixBack) //blend front color with opacity M / N over opaque background: http://en.wikipedia.org/wiki/Alpha_compositing#Alpha_blending
|
||||
uint32_t gradientRGB(uint32_t pixFront, uint32_t pixBack) //blend front color with opacity M / N over opaque background: https://en.wikipedia.org/wiki/Alpha_compositing#Alpha_blending
|
||||
{
|
||||
static_assert(0 < M && M < N && N <= 1000, "");
|
||||
static_assert(0 < M && M < N && N <= 1000);
|
||||
|
||||
auto calcColor = [](unsigned char colFront, unsigned char colBack) -> unsigned char { return (colFront * M + colBack * (N - M)) / N; };
|
||||
|
||||
@@ -41,7 +42,7 @@ uint32_t gradientRGB(uint32_t pixFront, uint32_t pixBack) //blend front color wi
|
||||
template <unsigned int M, unsigned int N> inline
|
||||
uint32_t gradientARGB(uint32_t pixFront, uint32_t pixBack) //find intermediate color between two colors with alpha channels (=> NO alpha blending!!!)
|
||||
{
|
||||
static_assert(0 < M && M < N && N <= 1000, "");
|
||||
static_assert(0 < M && M < N && N <= 1000);
|
||||
|
||||
const unsigned int weightFront = getAlpha(pixFront) * M;
|
||||
const unsigned int weightBack = getAlpha(pixBack) * (N - M);
|
||||
@@ -135,7 +136,7 @@ template <class T> inline
|
||||
T square(T value) { return value * value; }
|
||||
|
||||
|
||||
|
||||
#if 0
|
||||
inline
|
||||
double distRGB(uint32_t pix1, uint32_t pix2)
|
||||
{
|
||||
@@ -146,12 +147,13 @@ double distRGB(uint32_t pix1, uint32_t pix2)
|
||||
//euklidean RGB distance
|
||||
return std::sqrt(square(r_diff) + square(g_diff) + square(b_diff));
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
inline
|
||||
double distYCbCr(uint32_t pix1, uint32_t pix2, double lumaWeight)
|
||||
{
|
||||
//http://en.wikipedia.org/wiki/YCbCr#ITU-R_BT.601_conversion
|
||||
//https://en.wikipedia.org/wiki/YCbCr#ITU-R_BT.601_conversion
|
||||
//YCbCr conversion is a matrix multiplication => take advantage of linearity by subtracting first!
|
||||
const int r_diff = static_cast<int>(getRed (pix1)) - getRed (pix2); //we may delay division by 255 to after matrix multiplication
|
||||
const int g_diff = static_cast<int>(getGreen(pix1)) - getGreen(pix2); //
|
||||
@@ -186,9 +188,9 @@ double distYCbCrBuffered(uint32_t pix1, uint32_t pix2)
|
||||
|
||||
for (uint32_t i = 0; i < 256 * 256 * 256; ++i) //startup time: 114 ms on Intel Core i5 (four cores)
|
||||
{
|
||||
const int r_diff = getByte<2>(i) * 2 - 0xFF;
|
||||
const int g_diff = getByte<1>(i) * 2 - 0xFF;
|
||||
const int b_diff = getByte<0>(i) * 2 - 0xFF;
|
||||
const int r_diff = static_cast<signed char>(getByte<2>(i)) * 2;
|
||||
const int g_diff = static_cast<signed char>(getByte<1>(i)) * 2;
|
||||
const int b_diff = static_cast<signed char>(getByte<0>(i)) * 2;
|
||||
|
||||
const double k_b = 0.0593; //ITU-R BT.2020 conversion
|
||||
const double k_r = 0.2627; //
|
||||
@@ -210,24 +212,32 @@ double distYCbCrBuffered(uint32_t pix1, uint32_t pix2)
|
||||
// return 0;
|
||||
//if (pix1 < pix2)
|
||||
// std::swap(pix1, pix2); -> 30% perf degradation!!!
|
||||
#if 1
|
||||
|
||||
const int r_diff = static_cast<int>(getRed (pix1)) - getRed (pix2);
|
||||
const int g_diff = static_cast<int>(getGreen(pix1)) - getGreen(pix2);
|
||||
const int b_diff = static_cast<int>(getBlue (pix1)) - getBlue (pix2);
|
||||
|
||||
return diffToDist[(((r_diff + 0xFF) / 2) << 16) | //slightly reduce precision (division by 2) to squeeze value into single byte
|
||||
(((g_diff + 0xFF) / 2) << 8) |
|
||||
(( b_diff + 0xFF) / 2)];
|
||||
#else //not noticeably faster:
|
||||
const int r_diff_tmp = ((pix1 & 0xFF0000) + 0xFF0000 - (pix2 & 0xFF0000)) / 2;
|
||||
const int g_diff_tmp = ((pix1 & 0x00FF00) + 0x00FF00 - (pix2 & 0x00FF00)) / 2; //slightly reduce precision (division by 2) to squeeze value into single byte
|
||||
const int b_diff_tmp = ((pix1 & 0x0000FF) + 0x0000FF - (pix2 & 0x0000FF)) / 2;
|
||||
const size_t index = (static_cast<unsigned char>(r_diff / 2) << 16) | //slightly reduce precision (division by 2) to squeeze value into single byte
|
||||
(static_cast<unsigned char>(g_diff / 2) << 8) |
|
||||
(static_cast<unsigned char>(b_diff / 2));
|
||||
|
||||
return diffToDist[(r_diff_tmp & 0xFF0000) | (g_diff_tmp & 0x00FF00) | (b_diff_tmp & 0x0000FF)];
|
||||
#if 0 //attention: the following calculation creates an asymmetric color distance!!! (e.g. r_diff=46 will be unpacked as 45, but r_diff=-46 unpacks to -47
|
||||
const size_t index = (((r_diff + 0xFF) / 2) << 16) | //slightly reduce precision (division by 2) to squeeze value into single byte
|
||||
(((g_diff + 0xFF) / 2) << 8) |
|
||||
(( b_diff + 0xFF) / 2);
|
||||
#endif
|
||||
return diffToDist[index];
|
||||
}
|
||||
|
||||
|
||||
#if defined _MSC_VER && !defined NDEBUG
|
||||
const int debugPixelX = -1;
|
||||
const int debugPixelY = 58;
|
||||
|
||||
thread_local bool breakIntoDebugger = false;
|
||||
#endif
|
||||
|
||||
|
||||
enum BlendType
|
||||
{
|
||||
BLEND_NONE = 0,
|
||||
@@ -244,24 +254,32 @@ struct BlendResult
|
||||
};
|
||||
|
||||
|
||||
struct Kernel_3x3
|
||||
{
|
||||
uint32_t
|
||||
a, b, c,
|
||||
d, e, f,
|
||||
g, h, i;
|
||||
};
|
||||
|
||||
struct Kernel_4x4 //kernel for preprocessing step
|
||||
{
|
||||
uint32_t
|
||||
/**/a, b, c, d,
|
||||
/**/e, f, g, h,
|
||||
/**/i, j, k, l,
|
||||
/**/m, n, o, p;
|
||||
a, b, c, //
|
||||
e, f, g, // support reinterpret_cast from Kernel_4x4 => Kernel_3x3
|
||||
i, j, k, //
|
||||
m, n, o,
|
||||
d, h, l, p;
|
||||
};
|
||||
|
||||
/*
|
||||
input kernel area naming convention:
|
||||
/* input kernel area naming convention:
|
||||
-----------------
|
||||
| A | B | C | D |
|
||||
----|---|---|---|
|
||||
| E | F | G | H | //evaluate the four corners between F, G, J, K
|
||||
----|---|---|---| //input pixel is at position F
|
||||
|---|---|---|---|
|
||||
| E | F | G | H | evaluate the four corners between F, G, J, K
|
||||
|---|---|---|---| input pixel is at position F
|
||||
| I | J | K | L |
|
||||
----|---|---|---|
|
||||
|---|---|---|---|
|
||||
| M | N | O | P |
|
||||
-----------------
|
||||
*/
|
||||
@@ -269,6 +287,11 @@ template <class ColorDistance>
|
||||
FORCE_INLINE //detect blend direction
|
||||
BlendResult preProcessCorners(const Kernel_4x4& ker, const xbrz::ScalerCfg& cfg) //result: F, G, J, K corners of "GradientType"
|
||||
{
|
||||
#if defined _MSC_VER && !defined NDEBUG
|
||||
if (breakIntoDebugger)
|
||||
__debugbreak(); //__asm int 3;
|
||||
#endif
|
||||
|
||||
BlendResult result = {};
|
||||
|
||||
if ((ker.f == ker.g &&
|
||||
@@ -279,9 +302,8 @@ BlendResult preProcessCorners(const Kernel_4x4& ker, const xbrz::ScalerCfg& cfg)
|
||||
|
||||
auto dist = [&](uint32_t pix1, uint32_t pix2) { return ColorDistance::dist(pix1, pix2, cfg.luminanceWeight); };
|
||||
|
||||
const int weight = 4;
|
||||
double jg = dist(ker.i, ker.f) + dist(ker.f, ker.c) + dist(ker.n, ker.k) + dist(ker.k, ker.h) + weight * dist(ker.j, ker.g);
|
||||
double fk = dist(ker.e, ker.j) + dist(ker.j, ker.o) + dist(ker.b, ker.g) + dist(ker.g, ker.l) + weight * dist(ker.f, ker.k);
|
||||
double jg = dist(ker.i, ker.f) + dist(ker.f, ker.c) + dist(ker.n, ker.k) + dist(ker.k, ker.h) + cfg.centerDirectionBias * dist(ker.j, ker.g);
|
||||
double fk = dist(ker.e, ker.j) + dist(ker.j, ker.o) + dist(ker.b, ker.g) + dist(ker.g, ker.l) + cfg.centerDirectionBias * dist(ker.f, ker.k);
|
||||
|
||||
if (jg < fk) //test sample: 70% of values max(jg, fk) / min(jg, fk) are between 1.1 and 3.7 with median being 1.8
|
||||
{
|
||||
@@ -304,14 +326,6 @@ BlendResult preProcessCorners(const Kernel_4x4& ker, const xbrz::ScalerCfg& cfg)
|
||||
return result;
|
||||
}
|
||||
|
||||
struct Kernel_3x3
|
||||
{
|
||||
uint32_t
|
||||
/**/a, b, c,
|
||||
/**/d, e, f,
|
||||
/**/g, h, i;
|
||||
};
|
||||
|
||||
#define DEF_GETTER(x) template <RotationDegree rotDeg> uint32_t inline get_##x(const Kernel_3x3& ker) { return ker.x; }
|
||||
//we cannot and NEED NOT write "ker.##x" since ## concatenates preprocessor tokens but "." is not a token
|
||||
DEF_GETTER(a) DEF_GETTER(b) DEF_GETTER(c)
|
||||
@@ -339,17 +353,21 @@ DEF_GETTER(g, a) DEF_GETTER(h, d) DEF_GETTER(i, g)
|
||||
|
||||
|
||||
//compress four blend types into a single byte
|
||||
inline BlendType getTopL (unsigned char b) { return static_cast<BlendType>(0x3 & b); }
|
||||
//inline BlendType getTopL (unsigned char b) { return static_cast<BlendType>(0x3 & b); }
|
||||
inline BlendType getTopR (unsigned char b) { return static_cast<BlendType>(0x3 & (b >> 2)); }
|
||||
inline BlendType getBottomR(unsigned char b) { return static_cast<BlendType>(0x3 & (b >> 4)); }
|
||||
inline BlendType getBottomL(unsigned char b) { return static_cast<BlendType>(0x3 & (b >> 6)); }
|
||||
|
||||
inline void setTopL (unsigned char& b, BlendType bt) { b |= bt; } //buffer is assumed to be initialized before preprocessing!
|
||||
inline void setTopR (unsigned char& b, BlendType bt) { b |= (bt << 2); }
|
||||
inline void setBottomR(unsigned char& b, BlendType bt) { b |= (bt << 4); }
|
||||
inline void setBottomL(unsigned char& b, BlendType bt) { b |= (bt << 6); }
|
||||
inline void clearAddTopL(unsigned char& b, BlendType bt) { b = static_cast<unsigned char>(bt); }
|
||||
inline void addTopR (unsigned char& b, BlendType bt) { b |= (bt << 2); } //buffer is assumed to be initialized before preprocessing!
|
||||
inline void addBottomR (unsigned char& b, BlendType bt) { b |= (bt << 4); } //e.g. via clearAddTopL()
|
||||
inline void addBottomL (unsigned char& b, BlendType bt) { b |= (bt << 6); } //
|
||||
|
||||
inline bool blendingNeeded(unsigned char b) { return b != 0; }
|
||||
inline bool blendingNeeded(unsigned char b)
|
||||
{
|
||||
static_assert(BLEND_NONE == 0);
|
||||
return b != 0;
|
||||
}
|
||||
|
||||
template <RotationDegree rotDeg> inline
|
||||
unsigned char rotateBlendInfo(unsigned char b) { return b; }
|
||||
@@ -358,20 +376,12 @@ template <> inline unsigned char rotateBlendInfo<ROT_180>(unsigned char b) { ret
|
||||
template <> inline unsigned char rotateBlendInfo<ROT_270>(unsigned char b) { return ((b << 6) | (b >> 2)) & 0xff; }
|
||||
|
||||
|
||||
#if defined _MSC_VER && !defined NDEBUG
|
||||
int debugPixelX = -1;
|
||||
int debugPixelY = 12;
|
||||
__declspec(thread) bool breakIntoDebugger = false;
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
input kernel area naming convention:
|
||||
/* input kernel area naming convention:
|
||||
-------------
|
||||
| A | B | C |
|
||||
----|---|---|
|
||||
| D | E | F | //input pixel is at position E
|
||||
----|---|---|
|
||||
|---|---|---|
|
||||
| D | E | F | input pixel is at position E
|
||||
|---|---|---|
|
||||
| G | H | I |
|
||||
-------------
|
||||
*/
|
||||
@@ -382,7 +392,7 @@ void blendPixel(const Kernel_3x3& ker,
|
||||
unsigned char blendInfo, //result of preprocessing all four corners of pixel "e"
|
||||
const xbrz::ScalerCfg& cfg)
|
||||
{
|
||||
#define a get_a<rotDeg>(ker)
|
||||
//#define a get_a<rotDeg>(ker)
|
||||
#define b get_b<rotDeg>(ker)
|
||||
#define c get_c<rotDeg>(ker)
|
||||
#define d get_d<rotDeg>(ker)
|
||||
@@ -410,7 +420,7 @@ void blendPixel(const Kernel_3x3& ker,
|
||||
return true;
|
||||
|
||||
//make sure there is no second blending in an adjacent rotation for this pixel: handles insular pixels, mario eyes
|
||||
if (getTopR(blend) != BLEND_NONE && !eq(e, g)) //but support double-blending for 90� corners
|
||||
if (getTopR(blend) != BLEND_NONE && !eq(e, g)) //but support double-blending for 90° corners
|
||||
return false;
|
||||
if (getBottomL(blend) != BLEND_NONE && !eq(e, c))
|
||||
return false;
|
||||
@@ -453,7 +463,7 @@ void blendPixel(const Kernel_3x3& ker,
|
||||
Scaler::blendCorner(px, out);
|
||||
}
|
||||
|
||||
#undef a
|
||||
//#undef a
|
||||
#undef b
|
||||
#undef c
|
||||
#undef d
|
||||
@@ -465,7 +475,72 @@ void blendPixel(const Kernel_3x3& ker,
|
||||
}
|
||||
|
||||
|
||||
template <class Scaler, class ColorDistance> //scaler policy: see "Scaler2x" reference implementation
|
||||
class OobReaderTransparent
|
||||
{
|
||||
public:
|
||||
OobReaderTransparent(const uint32_t* src, int srcWidth, int srcHeight, int y) :
|
||||
s_m1(0 <= y - 1 && y - 1 < srcHeight ? src + srcWidth * (y - 1) : nullptr),
|
||||
s_0 (0 <= y && y < srcHeight ? src + srcWidth * y : nullptr),
|
||||
s_p1(0 <= y + 1 && y + 1 < srcHeight ? src + srcWidth * (y + 1) : nullptr),
|
||||
s_p2(0 <= y + 2 && y + 2 < srcHeight ? src + srcWidth * (y + 2) : nullptr),
|
||||
srcWidth_(srcWidth) {}
|
||||
|
||||
void readDhlp(Kernel_4x4& ker, int x) const //(x, y) is at kernel position F
|
||||
{
|
||||
[[likely]] if (const int x_p2 = x + 2; 0 <= x_p2 && x_p2 < srcWidth_)
|
||||
{
|
||||
ker.d = s_m1 ? s_m1[x_p2] : 0;
|
||||
ker.h = s_0 ? s_0 [x_p2] : 0;
|
||||
ker.l = s_p1 ? s_p1[x_p2] : 0;
|
||||
ker.p = s_p2 ? s_p2[x_p2] : 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
ker.d = 0;
|
||||
ker.h = 0;
|
||||
ker.l = 0;
|
||||
ker.p = 0;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
const uint32_t* const s_m1;
|
||||
const uint32_t* const s_0;
|
||||
const uint32_t* const s_p1;
|
||||
const uint32_t* const s_p2;
|
||||
const int srcWidth_;
|
||||
};
|
||||
|
||||
|
||||
class OobReaderDuplicate
|
||||
{
|
||||
public:
|
||||
OobReaderDuplicate(const uint32_t* src, int srcWidth, int srcHeight, int y) :
|
||||
s_m1(src + srcWidth * std::clamp(y - 1, 0, srcHeight - 1)),
|
||||
s_0 (src + srcWidth * std::clamp(y, 0, srcHeight - 1)),
|
||||
s_p1(src + srcWidth * std::clamp(y + 1, 0, srcHeight - 1)),
|
||||
s_p2(src + srcWidth * std::clamp(y + 2, 0, srcHeight - 1)),
|
||||
srcWidth_(srcWidth) {}
|
||||
|
||||
void readDhlp(Kernel_4x4& ker, int x) const //(x, y) is at kernel position F
|
||||
{
|
||||
const int x_p2 = std::clamp(x + 2, 0, srcWidth_ - 1);
|
||||
ker.d = s_m1[x_p2];
|
||||
ker.h = s_0 [x_p2];
|
||||
ker.l = s_p1[x_p2];
|
||||
ker.p = s_p2[x_p2];
|
||||
}
|
||||
|
||||
private:
|
||||
const uint32_t* const s_m1;
|
||||
const uint32_t* const s_0;
|
||||
const uint32_t* const s_p1;
|
||||
const uint32_t* const s_p2;
|
||||
const int srcWidth_;
|
||||
};
|
||||
|
||||
|
||||
template <class Scaler, class ColorDistance, class OobReader> //scaler policy: see "Scaler2x" reference implementation
|
||||
void scaleImage(const uint32_t* src, uint32_t* trg, int srcWidth, int srcHeight, const xbrz::ScalerCfg& cfg, int yFirst, int yLast)
|
||||
{
|
||||
yFirst = std::max(yFirst, 0);
|
||||
@@ -475,64 +550,72 @@ void scaleImage(const uint32_t* src, uint32_t* trg, int srcWidth, int srcHeight,
|
||||
|
||||
const int trgWidth = srcWidth * Scaler::scale;
|
||||
|
||||
//"use" space at the end of the image as temporary buffer for "on the fly preprocessing": we even could use larger area of
|
||||
//"sizeof(uint32_t) * srcWidth * (yLast - yFirst)" bytes without risk of accidental overwriting before accessing
|
||||
const int bufferSize = srcWidth;
|
||||
unsigned char* preProcBuffer = reinterpret_cast<unsigned char*>(trg + yLast * Scaler::scale * trgWidth) - bufferSize;
|
||||
std::fill(preProcBuffer, preProcBuffer + bufferSize, '\0');
|
||||
static_assert(BLEND_NONE == 0, "");
|
||||
//(ab)use space of "sizeof(uint32_t) * srcWidth * Scaler::scale" at the end of the image as temporary
|
||||
//buffer for "on the fly preprocessing" without risk of accidental overwriting before accessing
|
||||
unsigned char* const preProcBuf = reinterpret_cast<unsigned char*>(trg + yLast * Scaler::scale * trgWidth) - srcWidth;
|
||||
|
||||
//initialize preprocessing buffer for first row of current stripe: detect upper left and right corner blending
|
||||
//this cannot be optimized for adjacent processing stripes; we must not allow for a memory race condition!
|
||||
if (yFirst > 0)
|
||||
{
|
||||
const int y = yFirst - 1;
|
||||
const OobReader oobReader(src, srcWidth, srcHeight, yFirst - 1);
|
||||
|
||||
const uint32_t* s_m1 = src + srcWidth * std::max(y - 1, 0);
|
||||
const uint32_t* s_0 = src + srcWidth * y; //center line
|
||||
const uint32_t* s_p1 = src + srcWidth * std::min(y + 1, srcHeight - 1);
|
||||
const uint32_t* s_p2 = src + srcWidth * std::min(y + 2, srcHeight - 1);
|
||||
//initialize at position x = -1
|
||||
Kernel_4x4 ker4 = {};
|
||||
oobReader.readDhlp(ker4, -4); //hack: read a, e, i, m at x = -1
|
||||
ker4.a = ker4.d;
|
||||
ker4.e = ker4.h;
|
||||
ker4.i = ker4.l;
|
||||
ker4.m = ker4.p;
|
||||
|
||||
oobReader.readDhlp(ker4, -3);
|
||||
ker4.b = ker4.d;
|
||||
ker4.f = ker4.h;
|
||||
ker4.j = ker4.l;
|
||||
ker4.n = ker4.p;
|
||||
|
||||
oobReader.readDhlp(ker4, -2);
|
||||
ker4.c = ker4.d;
|
||||
ker4.g = ker4.h;
|
||||
ker4.k = ker4.l;
|
||||
ker4.o = ker4.p;
|
||||
|
||||
oobReader.readDhlp(ker4, -1);
|
||||
|
||||
{
|
||||
const BlendResult res = preProcessCorners<ColorDistance>(ker4, cfg);
|
||||
clearAddTopL(preProcBuf[0], res.blend_k); //set 1st known corner for (0, yFirst)
|
||||
}
|
||||
|
||||
for (int x = 0; x < srcWidth; ++x)
|
||||
{
|
||||
const int x_m1 = std::max(x - 1, 0);
|
||||
const int x_p1 = std::min(x + 1, srcWidth - 1);
|
||||
const int x_p2 = std::min(x + 2, srcWidth - 1);
|
||||
ker4.a = ker4.b; //shift previous kernel to the left
|
||||
ker4.e = ker4.f; // -----------------
|
||||
ker4.i = ker4.j; // | A | B | C | D |
|
||||
ker4.m = ker4.n; // |---|---|---|---|
|
||||
/**/ // | E | F | G | H | (x, yFirst - 1) is at position F
|
||||
ker4.b = ker4.c; // |---|---|---|---|
|
||||
ker4.f = ker4.g; // | I | J | K | L |
|
||||
ker4.j = ker4.k; // |---|---|---|---|
|
||||
ker4.n = ker4.o; // | M | N | O | P |
|
||||
/**/ // -----------------
|
||||
ker4.c = ker4.d;
|
||||
ker4.g = ker4.h;
|
||||
ker4.k = ker4.l;
|
||||
ker4.o = ker4.p;
|
||||
|
||||
Kernel_4x4 ker = {}; //perf: initialization is negligible
|
||||
ker.a = s_m1[x_m1]; //read sequentially from memory as far as possible
|
||||
ker.b = s_m1[x];
|
||||
ker.c = s_m1[x_p1];
|
||||
ker.d = s_m1[x_p2];
|
||||
oobReader.readDhlp(ker4, x);
|
||||
|
||||
ker.e = s_0[x_m1];
|
||||
ker.f = s_0[x];
|
||||
ker.g = s_0[x_p1];
|
||||
ker.h = s_0[x_p2];
|
||||
/* preprocessing blend result:
|
||||
---------
|
||||
| F | G | evaluate corner between F, G, J, K
|
||||
|---+---| current input pixel is at position F
|
||||
| J | K |
|
||||
--------- */
|
||||
const BlendResult res = preProcessCorners<ColorDistance>(ker4, cfg);
|
||||
addTopR(preProcBuf[x], res.blend_j); //set 2nd known corner for (x, yFirst)
|
||||
|
||||
ker.i = s_p1[x_m1];
|
||||
ker.j = s_p1[x];
|
||||
ker.k = s_p1[x_p1];
|
||||
ker.l = s_p1[x_p2];
|
||||
|
||||
ker.m = s_p2[x_m1];
|
||||
ker.n = s_p2[x];
|
||||
ker.o = s_p2[x_p1];
|
||||
ker.p = s_p2[x_p2];
|
||||
|
||||
const BlendResult res = preProcessCorners<ColorDistance>(ker, cfg);
|
||||
/*
|
||||
preprocessing blend result:
|
||||
---------
|
||||
| F | G | //evalute corner between F, G, J, K
|
||||
----|---| //input pixel is at position F
|
||||
| J | K |
|
||||
---------
|
||||
*/
|
||||
setTopR(preProcBuffer[x], res.blend_j);
|
||||
|
||||
if (x + 1 < bufferSize)
|
||||
setTopL(preProcBuffer[x + 1], res.blend_k);
|
||||
if (x + 1 < srcWidth)
|
||||
clearAddTopL(preProcBuf[x + 1], res.blend_k); //set 1st known corner for (x + 1, yFirst)
|
||||
}
|
||||
}
|
||||
//------------------------------------------------------------------------------------
|
||||
@@ -541,91 +624,92 @@ void scaleImage(const uint32_t* src, uint32_t* trg, int srcWidth, int srcHeight,
|
||||
{
|
||||
uint32_t* out = trg + Scaler::scale * y * trgWidth; //consider MT "striped" access
|
||||
|
||||
const uint32_t* s_m1 = src + srcWidth * std::max(y - 1, 0);
|
||||
const uint32_t* s_0 = src + srcWidth * y; //center line
|
||||
const uint32_t* s_p1 = src + srcWidth * std::min(y + 1, srcHeight - 1);
|
||||
const uint32_t* s_p2 = src + srcWidth * std::min(y + 2, srcHeight - 1);
|
||||
const OobReader oobReader(src, srcWidth, srcHeight, y);
|
||||
|
||||
//initialize at position x = -1
|
||||
Kernel_4x4 ker4 = {};
|
||||
oobReader.readDhlp(ker4, -4); //hack: read a, e, i, m at x = -1
|
||||
ker4.a = ker4.d;
|
||||
ker4.e = ker4.h;
|
||||
ker4.i = ker4.l;
|
||||
ker4.m = ker4.p;
|
||||
|
||||
oobReader.readDhlp(ker4, -3);
|
||||
ker4.b = ker4.d;
|
||||
ker4.f = ker4.h;
|
||||
ker4.j = ker4.l;
|
||||
ker4.n = ker4.p;
|
||||
|
||||
oobReader.readDhlp(ker4, -2);
|
||||
ker4.c = ker4.d;
|
||||
ker4.g = ker4.h;
|
||||
ker4.k = ker4.l;
|
||||
ker4.o = ker4.p;
|
||||
|
||||
oobReader.readDhlp(ker4, -1);
|
||||
|
||||
unsigned char blend_xy1 = 0; //corner blending for current (x, y + 1) position
|
||||
{
|
||||
const BlendResult res = preProcessCorners<ColorDistance>(ker4, cfg);
|
||||
clearAddTopL(blend_xy1, res.blend_k); //set 1st known corner for (0, y + 1) and buffer for use on next column
|
||||
|
||||
addBottomL(preProcBuf[0], res.blend_g); //set 3rd known corner for (0, y)
|
||||
}
|
||||
|
||||
for (int x = 0; x < srcWidth; ++x, out += Scaler::scale)
|
||||
{
|
||||
#if defined _MSC_VER && !defined NDEBUG
|
||||
breakIntoDebugger = debugPixelX == x && debugPixelY == y;
|
||||
#endif
|
||||
//all those bounds checks have only insignificant impact on performance!
|
||||
const int x_m1 = std::max(x - 1, 0); //perf: prefer array indexing to additional pointers!
|
||||
const int x_p1 = std::min(x + 1, srcWidth - 1);
|
||||
const int x_p2 = std::min(x + 2, srcWidth - 1);
|
||||
ker4.a = ker4.b; //shift previous kernel to the left
|
||||
ker4.e = ker4.f; // -----------------
|
||||
ker4.i = ker4.j; // | A | B | C | D |
|
||||
ker4.m = ker4.n; // |---|---|---|---|
|
||||
/**/ // | E | F | G | H | (x, y) is at position F
|
||||
ker4.b = ker4.c; // |---|---|---|---|
|
||||
ker4.f = ker4.g; // | I | J | K | L |
|
||||
ker4.j = ker4.k; // |---|---|---|---|
|
||||
ker4.n = ker4.o; // | M | N | O | P |
|
||||
/**/ // -----------------
|
||||
ker4.c = ker4.d;
|
||||
ker4.g = ker4.h;
|
||||
ker4.k = ker4.l;
|
||||
ker4.o = ker4.p;
|
||||
|
||||
Kernel_4x4 ker4 = {}; //perf: initialization is negligible
|
||||
|
||||
ker4.a = s_m1[x_m1]; //read sequentially from memory as far as possible
|
||||
ker4.b = s_m1[x];
|
||||
ker4.c = s_m1[x_p1];
|
||||
ker4.d = s_m1[x_p2];
|
||||
|
||||
ker4.e = s_0[x_m1];
|
||||
ker4.f = s_0[x];
|
||||
ker4.g = s_0[x_p1];
|
||||
ker4.h = s_0[x_p2];
|
||||
|
||||
ker4.i = s_p1[x_m1];
|
||||
ker4.j = s_p1[x];
|
||||
ker4.k = s_p1[x_p1];
|
||||
ker4.l = s_p1[x_p2];
|
||||
|
||||
ker4.m = s_p2[x_m1];
|
||||
ker4.n = s_p2[x];
|
||||
ker4.o = s_p2[x_p1];
|
||||
ker4.p = s_p2[x_p2];
|
||||
oobReader.readDhlp(ker4, x);
|
||||
|
||||
//evaluate the four corners on bottom-right of current pixel
|
||||
unsigned char blend_xy = 0; //for current (x, y) position
|
||||
unsigned char blend_xy = preProcBuf[x]; //for current (x, y) position
|
||||
{
|
||||
/* preprocessing blend result:
|
||||
---------
|
||||
| F | G | evaluate corner between F, G, J, K
|
||||
|---+---| current input pixel is at position F
|
||||
| J | K |
|
||||
--------- */
|
||||
const BlendResult res = preProcessCorners<ColorDistance>(ker4, cfg);
|
||||
/*
|
||||
preprocessing blend result:
|
||||
---------
|
||||
| F | G | //evalute corner between F, G, J, K
|
||||
----|---| //current input pixel is at position F
|
||||
| J | K |
|
||||
---------
|
||||
*/
|
||||
blend_xy = preProcBuffer[x];
|
||||
setBottomR(blend_xy, res.blend_f); //all four corners of (x, y) have been determined at this point due to processing sequence!
|
||||
addBottomR(blend_xy, res.blend_f); //all four corners of (x, y) have been determined at this point due to processing sequence!
|
||||
|
||||
setTopR(blend_xy1, res.blend_j); //set 2nd known corner for (x, y + 1)
|
||||
preProcBuffer[x] = blend_xy1; //store on current buffer position for use on next row
|
||||
addTopR(blend_xy1, res.blend_j); //set 2nd known corner for (x, y + 1)
|
||||
preProcBuf[x] = blend_xy1; //store on current buffer position for use on next row
|
||||
|
||||
blend_xy1 = 0;
|
||||
setTopL(blend_xy1, res.blend_k); //set 1st known corner for (x + 1, y + 1) and buffer for use on next column
|
||||
[[likely]] if (x + 1 < srcWidth)
|
||||
{
|
||||
//blend_xy1 -> blend_x1y1
|
||||
clearAddTopL(blend_xy1, res.blend_k); //set 1st known corner for (x + 1, y + 1) and buffer for use on next column
|
||||
|
||||
if (x + 1 < bufferSize) //set 3rd known corner for (x + 1, y)
|
||||
setBottomL(preProcBuffer[x + 1], res.blend_g);
|
||||
addBottomL(preProcBuf[x + 1], res.blend_g); //set 3rd known corner for (x + 1, y)
|
||||
}
|
||||
}
|
||||
|
||||
//fill block of size scale * scale with the given color
|
||||
fillBlock(out, trgWidth * sizeof(uint32_t), ker4.f, Scaler::scale, Scaler::scale);
|
||||
//place *after* preprocessing step, to not overwrite the results while processing the the last pixel!
|
||||
//place *after* preprocessing step, to not overwrite the results while processing the last pixel!
|
||||
|
||||
//blend four corners of current pixel
|
||||
if (blendingNeeded(blend_xy)) //good 5% perf-improvement
|
||||
//blend all four corners of current pixel
|
||||
if (blendingNeeded(blend_xy))
|
||||
{
|
||||
Kernel_3x3 ker3 = {}; //perf: initialization is negligible
|
||||
|
||||
ker3.a = ker4.a;
|
||||
ker3.b = ker4.b;
|
||||
ker3.c = ker4.c;
|
||||
|
||||
ker3.d = ker4.e;
|
||||
ker3.e = ker4.f;
|
||||
ker3.f = ker4.g;
|
||||
|
||||
ker3.g = ker4.i;
|
||||
ker3.h = ker4.j;
|
||||
ker3.i = ker4.k;
|
||||
|
||||
const auto& ker3 = reinterpret_cast<const Kernel_3x3&>(ker4); //"The Things We Do for Perf"
|
||||
blendPixel<Scaler, ColorDistance, ROT_0 >(ker3, out, trgWidth, blend_xy, cfg);
|
||||
blendPixel<Scaler, ColorDistance, ROT_90 >(ker3, out, trgWidth, blend_xy, cfg);
|
||||
blendPixel<Scaler, ColorDistance, ROT_180>(ker3, out, trgWidth, blend_xy, cfg);
|
||||
@@ -1037,6 +1121,22 @@ struct ColorDistanceARGB
|
||||
};
|
||||
|
||||
|
||||
struct ColorDistanceUnbufferedARGB
|
||||
{
|
||||
static double dist(uint32_t pix1, uint32_t pix2, double luminanceWeight)
|
||||
{
|
||||
const double a1 = getAlpha(pix1) / 255.0 ;
|
||||
const double a2 = getAlpha(pix2) / 255.0 ;
|
||||
|
||||
const double d = distYCbCr(pix1, pix2, luminanceWeight);
|
||||
if (a1 < a2)
|
||||
return a1 * d + 255 * (a2 - a1);
|
||||
else
|
||||
return a2 * d + 255 * (a1 - a2);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
struct ColorGradientRGB
|
||||
{
|
||||
template <unsigned int M, unsigned int N>
|
||||
@@ -1059,37 +1159,60 @@ struct ColorGradientARGB
|
||||
|
||||
void xbrz::scale(size_t factor, const uint32_t* src, uint32_t* trg, int srcWidth, int srcHeight, ColorFormat colFmt, const xbrz::ScalerCfg& cfg, int yFirst, int yLast)
|
||||
{
|
||||
if (factor == 1)
|
||||
{
|
||||
std::copy(src + yFirst * srcWidth, src + yLast * srcWidth, trg);
|
||||
return;
|
||||
}
|
||||
|
||||
static_assert(SCALE_FACTOR_MAX == 6);
|
||||
switch (colFmt)
|
||||
{
|
||||
case ColorFormat::ARGB:
|
||||
switch (factor)
|
||||
{
|
||||
case 2:
|
||||
return scaleImage<Scaler2x<ColorGradientARGB>, ColorDistanceARGB>(src, trg, srcWidth, srcHeight, cfg, yFirst, yLast);
|
||||
case 3:
|
||||
return scaleImage<Scaler3x<ColorGradientARGB>, ColorDistanceARGB>(src, trg, srcWidth, srcHeight, cfg, yFirst, yLast);
|
||||
case 4:
|
||||
return scaleImage<Scaler4x<ColorGradientARGB>, ColorDistanceARGB>(src, trg, srcWidth, srcHeight, cfg, yFirst, yLast);
|
||||
case 5:
|
||||
return scaleImage<Scaler5x<ColorGradientARGB>, ColorDistanceARGB>(src, trg, srcWidth, srcHeight, cfg, yFirst, yLast);
|
||||
case 6:
|
||||
return scaleImage<Scaler6x<ColorGradientARGB>, ColorDistanceARGB>(src, trg, srcWidth, srcHeight, cfg, yFirst, yLast);
|
||||
}
|
||||
break;
|
||||
|
||||
case ColorFormat::RGB:
|
||||
switch (factor)
|
||||
{
|
||||
case 2:
|
||||
return scaleImage<Scaler2x<ColorGradientRGB>, ColorDistanceRGB>(src, trg, srcWidth, srcHeight, cfg, yFirst, yLast);
|
||||
return scaleImage<Scaler2x<ColorGradientRGB>, ColorDistanceRGB, OobReaderDuplicate>(src, trg, srcWidth, srcHeight, cfg, yFirst, yLast);
|
||||
case 3:
|
||||
return scaleImage<Scaler3x<ColorGradientRGB>, ColorDistanceRGB>(src, trg, srcWidth, srcHeight, cfg, yFirst, yLast);
|
||||
return scaleImage<Scaler3x<ColorGradientRGB>, ColorDistanceRGB, OobReaderDuplicate>(src, trg, srcWidth, srcHeight, cfg, yFirst, yLast);
|
||||
case 4:
|
||||
return scaleImage<Scaler4x<ColorGradientRGB>, ColorDistanceRGB>(src, trg, srcWidth, srcHeight, cfg, yFirst, yLast);
|
||||
return scaleImage<Scaler4x<ColorGradientRGB>, ColorDistanceRGB, OobReaderDuplicate>(src, trg, srcWidth, srcHeight, cfg, yFirst, yLast);
|
||||
case 5:
|
||||
return scaleImage<Scaler5x<ColorGradientRGB>, ColorDistanceRGB>(src, trg, srcWidth, srcHeight, cfg, yFirst, yLast);
|
||||
return scaleImage<Scaler5x<ColorGradientRGB>, ColorDistanceRGB, OobReaderDuplicate>(src, trg, srcWidth, srcHeight, cfg, yFirst, yLast);
|
||||
case 6:
|
||||
return scaleImage<Scaler6x<ColorGradientRGB>, ColorDistanceRGB>(src, trg, srcWidth, srcHeight, cfg, yFirst, yLast);
|
||||
return scaleImage<Scaler6x<ColorGradientRGB>, ColorDistanceRGB, OobReaderDuplicate>(src, trg, srcWidth, srcHeight, cfg, yFirst, yLast);
|
||||
}
|
||||
break;
|
||||
|
||||
case ColorFormat::ARGB:
|
||||
switch (factor)
|
||||
{
|
||||
case 2:
|
||||
return scaleImage<Scaler2x<ColorGradientARGB>, ColorDistanceARGB, OobReaderTransparent>(src, trg, srcWidth, srcHeight, cfg, yFirst, yLast);
|
||||
case 3:
|
||||
return scaleImage<Scaler3x<ColorGradientARGB>, ColorDistanceARGB, OobReaderTransparent>(src, trg, srcWidth, srcHeight, cfg, yFirst, yLast);
|
||||
case 4:
|
||||
return scaleImage<Scaler4x<ColorGradientARGB>, ColorDistanceARGB, OobReaderTransparent>(src, trg, srcWidth, srcHeight, cfg, yFirst, yLast);
|
||||
case 5:
|
||||
return scaleImage<Scaler5x<ColorGradientARGB>, ColorDistanceARGB, OobReaderTransparent>(src, trg, srcWidth, srcHeight, cfg, yFirst, yLast);
|
||||
case 6:
|
||||
return scaleImage<Scaler6x<ColorGradientARGB>, ColorDistanceARGB, OobReaderTransparent>(src, trg, srcWidth, srcHeight, cfg, yFirst, yLast);
|
||||
}
|
||||
break;
|
||||
|
||||
case ColorFormat::ARGB_UNBUFFERED:
|
||||
switch (factor)
|
||||
{
|
||||
case 2:
|
||||
return scaleImage<Scaler2x<ColorGradientARGB>, ColorDistanceUnbufferedARGB, OobReaderTransparent>(src, trg, srcWidth, srcHeight, cfg, yFirst, yLast);
|
||||
case 3:
|
||||
return scaleImage<Scaler3x<ColorGradientARGB>, ColorDistanceUnbufferedARGB, OobReaderTransparent>(src, trg, srcWidth, srcHeight, cfg, yFirst, yLast);
|
||||
case 4:
|
||||
return scaleImage<Scaler4x<ColorGradientARGB>, ColorDistanceUnbufferedARGB, OobReaderTransparent>(src, trg, srcWidth, srcHeight, cfg, yFirst, yLast);
|
||||
case 5:
|
||||
return scaleImage<Scaler5x<ColorGradientARGB>, ColorDistanceUnbufferedARGB, OobReaderTransparent>(src, trg, srcWidth, srcHeight, cfg, yFirst, yLast);
|
||||
case 6:
|
||||
return scaleImage<Scaler6x<ColorGradientARGB>, ColorDistanceUnbufferedARGB, OobReaderTransparent>(src, trg, srcWidth, srcHeight, cfg, yFirst, yLast);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -1101,21 +1224,133 @@ bool xbrz::equalColorTest(uint32_t col1, uint32_t col2, ColorFormat colFmt, doub
|
||||
{
|
||||
switch (colFmt)
|
||||
{
|
||||
case ColorFormat::ARGB:
|
||||
return ColorDistanceARGB::dist(col1, col2, luminanceWeight) < equalColorTolerance;
|
||||
|
||||
case ColorFormat::RGB:
|
||||
return ColorDistanceRGB::dist(col1, col2, luminanceWeight) < equalColorTolerance;
|
||||
case ColorFormat::ARGB:
|
||||
return ColorDistanceARGB::dist(col1, col2, luminanceWeight) < equalColorTolerance;
|
||||
case ColorFormat::ARGB_UNBUFFERED:
|
||||
return ColorDistanceUnbufferedARGB::dist(col1, col2, luminanceWeight) < equalColorTolerance;
|
||||
}
|
||||
assert(false);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
void xbrz::bilinearScale(const uint32_t* src, int srcWidth, int srcHeight,
|
||||
/**/ uint32_t* trg, int trgWidth, int trgHeight)
|
||||
{
|
||||
bilinearScale(src, srcWidth, srcHeight, srcWidth * sizeof(uint32_t),
|
||||
trg, trgWidth, trgHeight, trgWidth * sizeof(uint32_t),
|
||||
0, trgHeight, [](uint32_t pix) { return pix; });
|
||||
}
|
||||
|
||||
|
||||
void xbrz::nearestNeighborScale(const uint32_t* src, int srcWidth, int srcHeight,
|
||||
uint32_t* trg, int trgWidth, int trgHeight)
|
||||
/**/ uint32_t* trg, int trgWidth, int trgHeight)
|
||||
{
|
||||
nearestNeighborScale(src, srcWidth, srcHeight, srcWidth * sizeof(uint32_t),
|
||||
trg, trgWidth, trgHeight, trgWidth * sizeof(uint32_t),
|
||||
SliceType::TARGET, 0, trgHeight, [](uint32_t pix) { return pix; });
|
||||
0, trgHeight, [](uint32_t pix) { return pix; });
|
||||
}
|
||||
|
||||
|
||||
#if 0
|
||||
//#include <ppl.h>
|
||||
void bilinearScaleCpu(const uint32_t* src, int srcWidth, int srcHeight,
|
||||
/**/ uint32_t* trg, int trgWidth, int trgHeight)
|
||||
{
|
||||
const int TASK_GRANULARITY = 16;
|
||||
|
||||
concurrency::task_group tg;
|
||||
|
||||
for (int i = 0; i < trgHeight; i += TASK_GRANULARITY)
|
||||
tg.run([=]
|
||||
{
|
||||
const int iLast = std::min(i + TASK_GRANULARITY, trgHeight);
|
||||
xbrz::bilinearScale(src, srcWidth, srcHeight, srcWidth * sizeof(uint32_t),
|
||||
trg, trgWidth, trgHeight, trgWidth * sizeof(uint32_t),
|
||||
i, iLast, [](uint32_t pix) { return pix; });
|
||||
});
|
||||
tg.wait();
|
||||
}
|
||||
|
||||
|
||||
//Perf: AMP vs CPU: merely ~10% shorter runtime (scaling 1280x800 -> 1920x1080)
|
||||
//#include <amp.h>
|
||||
void bilinearScaleAmp(const uint32_t* src, int srcWidth, int srcHeight, //throw concurrency::runtime_exception
|
||||
/**/ uint32_t* trg, int trgWidth, int trgHeight)
|
||||
{
|
||||
//C++ AMP reference: https://msdn.microsoft.com/en-us/library/hh289390.aspx
|
||||
//introduction to C++ AMP: https://msdn.microsoft.com/en-us/magazine/hh882446.aspx
|
||||
using namespace concurrency;
|
||||
//TODO: pitch
|
||||
|
||||
if (srcHeight <= 0 || srcWidth <= 0) return;
|
||||
|
||||
const float scaleX = static_cast<float>(trgWidth ) / srcWidth;
|
||||
const float scaleY = static_cast<float>(trgHeight) / srcHeight;
|
||||
|
||||
array_view<const uint32_t, 2> srcView(srcHeight, srcWidth, src);
|
||||
array_view< uint32_t, 2> trgView(trgHeight, trgWidth, trg);
|
||||
trgView.discard_data();
|
||||
|
||||
parallel_for_each(trgView.extent, [=](index<2> idx) restrict(amp) //throw ?
|
||||
{
|
||||
const int y = idx[0];
|
||||
const int x = idx[1];
|
||||
//Perf notes:
|
||||
// -> float-based calculation is (almost) 2x as fas as double!
|
||||
// -> no noticeable improvement via tiling: https://msdn.microsoft.com/en-us/magazine/hh882447.aspx
|
||||
// -> no noticeable improvement with restrict(amp,cpu)
|
||||
// -> iterating over y-axis only is significantly slower!
|
||||
// -> pre-calculating x,y-dependent variables in a buffer + array_view<> is ~ 20 % slower!
|
||||
const int y1 = srcHeight * y / trgHeight;
|
||||
int y2 = y1 + 1;
|
||||
if (y2 == srcHeight) --y2;
|
||||
|
||||
const float yy1 = y / scaleY - y1;
|
||||
const float y2y = 1 - yy1;
|
||||
//-------------------------------------
|
||||
const int x1 = srcWidth * x / trgWidth;
|
||||
int x2 = x1 + 1;
|
||||
if (x2 == srcWidth) --x2;
|
||||
|
||||
const float xx1 = x / scaleX - x1;
|
||||
const float x2x = 1 - xx1;
|
||||
//-------------------------------------
|
||||
const float x2xy2y = x2x * y2y;
|
||||
const float xx1y2y = xx1 * y2y;
|
||||
const float x2xyy1 = x2x * yy1;
|
||||
const float xx1yy1 = xx1 * yy1;
|
||||
|
||||
auto interpolate = [=](int offset)
|
||||
{
|
||||
/*
|
||||
https://en.wikipedia.org/wiki/Bilinear_interpolation
|
||||
(c11(x2 - x) + c21(x - x1)) * (y2 - y ) +
|
||||
(c12(x2 - x) + c22(x - x1)) * (y - y1)
|
||||
*/
|
||||
const auto c11 = (srcView(y1, x1) >> (8 * offset)) & 0xff;
|
||||
const auto c21 = (srcView(y1, x2) >> (8 * offset)) & 0xff;
|
||||
const auto c12 = (srcView(y2, x1) >> (8 * offset)) & 0xff;
|
||||
const auto c22 = (srcView(y2, x2) >> (8 * offset)) & 0xff;
|
||||
|
||||
return c11 * x2xy2y + c21 * xx1y2y +
|
||||
c12 * x2xyy1 + c22 * xx1yy1;
|
||||
};
|
||||
|
||||
const float bi = interpolate(0);
|
||||
const float gi = interpolate(1);
|
||||
const float ri = interpolate(2);
|
||||
const float ai = interpolate(3);
|
||||
|
||||
const auto b = static_cast<uint32_t>(bi + 0.5f);
|
||||
const auto g = static_cast<uint32_t>(gi + 0.5f);
|
||||
const auto r = static_cast<uint32_t>(ri + 0.5f);
|
||||
const auto a = static_cast<uint32_t>(ai + 0.5f);
|
||||
|
||||
trgView(y, x) = (a << 24) | (r << 16) | (g << 8) | b;
|
||||
});
|
||||
trgView.synchronize(); //throw ?
|
||||
}
|
||||
#endif
|
||||
+13
-11
@@ -1,13 +1,14 @@
|
||||
// ****************************************************************************
|
||||
// * This file is part of the HqMAME project. It is distributed under *
|
||||
// * This file is part of the xBRZ project. It is distributed under *
|
||||
// * GNU General Public License: https://www.gnu.org/licenses/gpl-3.0 *
|
||||
// * Copyright (C) Zenju (zenju AT gmx DOT de) - All Rights Reserved *
|
||||
// * *
|
||||
// * Additionally and as a special exception, the author gives permission *
|
||||
// * to link the code of this program with the MAME library (or with modified *
|
||||
// * versions of MAME that use the same license as MAME), and distribute *
|
||||
// * linked combinations including the two. You must obey the GNU General *
|
||||
// * Public License in all respects for all of the code used other than MAME. *
|
||||
// * to link the code of this program with the following libraries *
|
||||
// * (or with modified versions that use the same licenses), and distribute *
|
||||
// * linked combinations including the two: MAME, FreeFileSync, Snes9x, ePSXe *
|
||||
// * You must obey the GNU General Public License in all respects for all of *
|
||||
// * the code used other than MAME, FreeFileSync, Snes9x, ePSXe. *
|
||||
// * If you modify this file, you may extend this exception to your version *
|
||||
// * of the file, but you are not obligated to do so. If you do not wish to *
|
||||
// * do so, delete this exception statement from your version. *
|
||||
@@ -21,10 +22,6 @@
|
||||
#include <limits>
|
||||
#include "xbrz_config.h"
|
||||
|
||||
// Guard against msvc stupidity
|
||||
#ifdef max
|
||||
#undef max
|
||||
#endif
|
||||
|
||||
namespace xbrz
|
||||
{
|
||||
@@ -47,11 +44,13 @@ enum class ColorFormat //from high bits -> low bits, 8 bit per channel
|
||||
{
|
||||
RGB, //8 bit for each red, green, blue, upper 8 bits unused
|
||||
ARGB, //including alpha channel, BGRA byte order on little-endian machines
|
||||
ARGB_UNBUFFERED, //like ARGB, but without the one-time buffer creation overhead (ca. 100 - 300 ms) at the expense of a slightly slower scaling time
|
||||
};
|
||||
|
||||
const int SCALE_FACTOR_MAX = 6;
|
||||
|
||||
/*
|
||||
-> map source (srcWidth * srcHeight) to target (scale * width x scale * height) image, optionally processing a half-open slice of rows [yFirst, yLast) only
|
||||
-> support for source/target pitch in bytes!
|
||||
-> if your emulator changes only a few image slices during each cycle (e.g. DOSBox) then there's no need to run xBRZ on the complete image:
|
||||
Just make sure you enlarge the source image slice by 2 rows on top and 2 on bottom (this is the additional range the xBRZ algorithm is using during analysis)
|
||||
CAVEAT: If there are multiple changed slices, make sure they do not overlap after adding these additional rows in order to avoid a memory race condition
|
||||
@@ -60,12 +59,15 @@ enum class ColorFormat //from high bits -> low bits, 8 bit per channel
|
||||
THREAD-SAFETY: - parts of the same image may be scaled by multiple threads as long as the [yFirst, yLast) ranges do not overlap!
|
||||
- there is a minor inefficiency for the first row of a slice, so avoid processing single rows only; suggestion: process at least 8-16 rows
|
||||
*/
|
||||
void scale(size_t factor, //valid range: 2 - 6
|
||||
void scale(size_t factor, //valid range: 2 - SCALE_FACTOR_MAX
|
||||
const uint32_t* src, uint32_t* trg, int srcWidth, int srcHeight,
|
||||
ColorFormat colFmt,
|
||||
const ScalerCfg& cfg = ScalerCfg(),
|
||||
int yFirst = 0, int yLast = std::numeric_limits<int>::max()); //slice of source image
|
||||
|
||||
void bilinearScale(const uint32_t* src, int srcWidth, int srcHeight,
|
||||
/**/ uint32_t* trg, int trgWidth, int trgHeight);
|
||||
|
||||
void nearestNeighborScale(const uint32_t* src, int srcWidth, int srcHeight,
|
||||
/**/ uint32_t* trg, int trgWidth, int trgHeight);
|
||||
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
// ****************************************************************************
|
||||
// * This file is part of the HqMAME project. It is distributed under *
|
||||
// * This file is part of the xBRZ project. It is distributed under *
|
||||
// * GNU General Public License: https://www.gnu.org/licenses/gpl-3.0 *
|
||||
// * Copyright (C) Zenju (zenju AT gmx DOT de) - All Rights Reserved *
|
||||
// * *
|
||||
// * Additionally and as a special exception, the author gives permission *
|
||||
// * to link the code of this program with the MAME library (or with modified *
|
||||
// * versions of MAME that use the same license as MAME), and distribute *
|
||||
// * linked combinations including the two. You must obey the GNU General *
|
||||
// * Public License in all respects for all of the code used other than MAME. *
|
||||
// * to link the code of this program with the following libraries *
|
||||
// * (or with modified versions that use the same licenses), and distribute *
|
||||
// * linked combinations including the two: MAME, FreeFileSync, Snes9x, ePSXe *
|
||||
// * You must obey the GNU General Public License in all respects for all of *
|
||||
// * the code used other than MAME, FreeFileSync, Snes9x, ePSXe. *
|
||||
// * If you modify this file, you may extend this exception to your version *
|
||||
// * of the file, but you are not obligated to do so. If you do not wish to *
|
||||
// * do so, delete this exception statement from your version. *
|
||||
@@ -24,6 +25,7 @@ struct ScalerCfg
|
||||
{
|
||||
double luminanceWeight = 1;
|
||||
double equalColorTolerance = 30;
|
||||
double centerDirectionBias = 4;
|
||||
double dominantDirectionThreshold = 3.6;
|
||||
double steepDirectionThreshold = 2.2;
|
||||
double newTestAttribute = 0; //unused; test new parameters
|
||||
|
||||
+182
-71
@@ -1,13 +1,14 @@
|
||||
// ****************************************************************************
|
||||
// * This file is part of the HqMAME project. It is distributed under *
|
||||
// * This file is part of the xBRZ project. It is distributed under *
|
||||
// * GNU General Public License: https://www.gnu.org/licenses/gpl-3.0 *
|
||||
// * Copyright (C) Zenju (zenju AT gmx DOT de) - All Rights Reserved *
|
||||
// * *
|
||||
// * Additionally and as a special exception, the author gives permission *
|
||||
// * to link the code of this program with the MAME library (or with modified *
|
||||
// * versions of MAME that use the same license as MAME), and distribute *
|
||||
// * linked combinations including the two. You must obey the GNU General *
|
||||
// * Public License in all respects for all of the code used other than MAME. *
|
||||
// * to link the code of this program with the following libraries *
|
||||
// * (or with modified versions that use the same licenses), and distribute *
|
||||
// * linked combinations including the two: MAME, FreeFileSync, Snes9x, ePSXe *
|
||||
// * You must obey the GNU General Public License in all respects for all of *
|
||||
// * the code used other than MAME, FreeFileSync, Snes9x, ePSXe. *
|
||||
// * If you modify this file, you may extend this exception to your version *
|
||||
// * of the file, but you are not obligated to do so. If you do not wish to *
|
||||
// * do so, delete this exception statement from your version. *
|
||||
@@ -25,14 +26,14 @@ namespace xbrz
|
||||
{
|
||||
template <uint32_t N> inline
|
||||
unsigned char getByte(uint32_t val) { return static_cast<unsigned char>((val >> (8 * N)) & 0xff); }
|
||||
// Note that we use RGBA, not ARGB
|
||||
inline unsigned char getAlpha(uint32_t pix) { return getByte<3>(pix); }
|
||||
inline unsigned char getRed (uint32_t pix) { return getByte<0>(pix); }
|
||||
inline unsigned char getGreen(uint32_t pix) { return getByte<1>(pix); }
|
||||
inline unsigned char getBlue (uint32_t pix) { return getByte<2>(pix); }
|
||||
|
||||
inline uint32_t makePixel(unsigned char a, unsigned char r, unsigned char g, unsigned char b) { return (a << 24) | (b << 16) | (g << 8) | r; }
|
||||
inline uint32_t makePixel( unsigned char r, unsigned char g, unsigned char b) { return 0xFF000000 | (b << 16) | (g << 8) | r; }
|
||||
inline unsigned char getAlpha(uint32_t pix) { return getByte<3>(pix); }
|
||||
inline unsigned char getRed (uint32_t pix) { return getByte<2>(pix); }
|
||||
inline unsigned char getGreen(uint32_t pix) { return getByte<1>(pix); }
|
||||
inline unsigned char getBlue (uint32_t pix) { return getByte<0>(pix); }
|
||||
|
||||
inline uint32_t makePixel(unsigned char a, unsigned char r, unsigned char g, unsigned char b) { return (a << 24) | (r << 16) | (g << 8) | b; }
|
||||
inline uint32_t makePixel( unsigned char r, unsigned char g, unsigned char b) { return (r << 16) | (g << 8) | b; }
|
||||
|
||||
inline uint32_t rgb555to888(uint16_t pix) { return ((pix & 0x7C00) << 9) | ((pix & 0x03E0) << 6) | ((pix & 0x001F) << 3); }
|
||||
inline uint32_t rgb565to888(uint16_t pix) { return ((pix & 0xF800) << 8) | ((pix & 0x07E0) << 5) | ((pix & 0x001F) << 3); }
|
||||
@@ -55,7 +56,7 @@ Pix* byteAdvance(Pix* ptr, int bytes)
|
||||
|
||||
//fill block with the given color
|
||||
template <class Pix> inline
|
||||
void fillBlock(Pix* trg, int pitch, Pix col, int blockWidth, int blockHeight)
|
||||
void fillBlock(Pix* trg, int pitch /*[bytes]*/, Pix col, int blockWidth, int blockHeight)
|
||||
{
|
||||
//for (int y = 0; y < blockHeight; ++y, trg = byteAdvance(trg, pitch))
|
||||
// std::fill(trg, trg + blockWidth, col);
|
||||
@@ -66,16 +67,11 @@ void fillBlock(Pix* trg, int pitch, Pix col, int blockWidth, int blockHeight)
|
||||
}
|
||||
|
||||
|
||||
enum class SliceType
|
||||
{
|
||||
SOURCE,
|
||||
TARGET,
|
||||
};
|
||||
|
||||
//nearest-neighbor (going over target image - slow for upscaling, since source is read multiple times missing out on cache! Fast for similar image sizes!)
|
||||
template <class PixSrc, class PixTrg, class PixConverter>
|
||||
void nearestNeighborScale(const PixSrc* src, int srcWidth, int srcHeight, int srcPitch,
|
||||
/**/ PixTrg* trg, int trgWidth, int trgHeight, int trgPitch,
|
||||
SliceType st, int yFirst, int yLast, PixConverter pixCvrt /*convert PixSrc to PixTrg*/)
|
||||
void nearestNeighborScale(const PixSrc* src, int srcWidth, int srcHeight, int srcPitch /*[bytes]*/,
|
||||
/**/ PixTrg* trg, int trgWidth, int trgHeight, int trgPitch /*[bytes]*/,
|
||||
int yFirst, int yLast, PixConverter pixCvrt /*convert PixSrc to PixTrg*/)
|
||||
{
|
||||
static_assert(std::is_integral<PixSrc>::value, "PixSrc* is expected to be cast-able to char*");
|
||||
static_assert(std::is_integral<PixTrg>::value, "PixTrg* is expected to be cast-able to char*");
|
||||
@@ -89,65 +85,180 @@ void nearestNeighborScale(const PixSrc* src, int srcWidth, int srcHeight, int sr
|
||||
return;
|
||||
}
|
||||
|
||||
switch (st)
|
||||
yFirst = std::max(yFirst, 0);
|
||||
yLast = std::min(yLast, trgHeight);
|
||||
if (yFirst >= yLast || srcHeight <= 0 || srcWidth <= 0) return;
|
||||
|
||||
for (int y = yFirst; y < yLast; ++y)
|
||||
{
|
||||
case SliceType::SOURCE:
|
||||
//nearest-neighbor (going over source image - fast for upscaling, since source is read only once
|
||||
yFirst = std::max(yFirst, 0);
|
||||
yLast = std::min(yLast, srcHeight);
|
||||
if (yFirst >= yLast || trgWidth <= 0 || trgHeight <= 0) return;
|
||||
const int ySrc = srcHeight * y / trgHeight;
|
||||
const PixSrc* const srcLine = byteAdvance(src, ySrc * srcPitch);
|
||||
PixTrg* const trgLine = byteAdvance(trg, y * trgPitch);
|
||||
|
||||
for (int y = yFirst; y < yLast; ++y)
|
||||
for (int x = 0; x < trgWidth; ++x)
|
||||
{
|
||||
const int xSrc = srcWidth * x / trgWidth;
|
||||
trgLine[x] = pixCvrt(srcLine[xSrc]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//nearest-neighbor (going over source image - fast for upscaling, since source is read only once
|
||||
template <class PixSrc, class PixTrg, class PixConverter>
|
||||
void nearestNeighborScaleOverSource(const PixSrc* src, int srcWidth, int srcHeight, int srcPitch /*[bytes]*/,
|
||||
/**/ PixTrg* trg, int trgWidth, int trgHeight, int trgPitch /*[bytes]*/,
|
||||
int yFirst, int yLast, PixConverter pixCvrt /*convert PixSrc to PixTrg*/)
|
||||
{
|
||||
static_assert(std::is_integral<PixSrc>::value, "PixSrc* is expected to be cast-able to char*");
|
||||
static_assert(std::is_integral<PixTrg>::value, "PixTrg* is expected to be cast-able to char*");
|
||||
|
||||
static_assert(std::is_same<decltype(pixCvrt(PixSrc())), PixTrg>::value, "PixConverter returning wrong pixel format");
|
||||
|
||||
if (srcPitch < srcWidth * static_cast<int>(sizeof(PixSrc)) ||
|
||||
trgPitch < trgWidth * static_cast<int>(sizeof(PixTrg)))
|
||||
{
|
||||
assert(false);
|
||||
return;
|
||||
}
|
||||
|
||||
yFirst = std::max(yFirst, 0);
|
||||
yLast = std::min(yLast, srcHeight);
|
||||
if (yFirst >= yLast || trgWidth <= 0 || trgHeight <= 0) return;
|
||||
|
||||
for (int y = yFirst; y < yLast; ++y)
|
||||
{
|
||||
//mathematically: ySrc = floor(srcHeight * yTrg / trgHeight)
|
||||
// => search for integers in: [ySrc, ySrc + 1) * trgHeight / srcHeight
|
||||
|
||||
//keep within for loop to support MT input slices!
|
||||
const int yTrgFirst = ( y * trgHeight + srcHeight - 1) / srcHeight; //=ceil(y * trgHeight / srcHeight)
|
||||
const int yTrgLast = ((y + 1) * trgHeight + srcHeight - 1) / srcHeight; //=ceil(((y + 1) * trgHeight) / srcHeight)
|
||||
const int blockHeight = yTrgLast - yTrgFirst;
|
||||
|
||||
if (blockHeight > 0)
|
||||
{
|
||||
const PixSrc* srcLine = byteAdvance(src, y * srcPitch);
|
||||
/**/ PixTrg* trgLine = byteAdvance(trg, yTrgFirst * trgPitch);
|
||||
int xTrgFirst = 0;
|
||||
|
||||
for (int x = 0; x < srcWidth; ++x)
|
||||
{
|
||||
//mathematically: ySrc = floor(srcHeight * yTrg / trgHeight)
|
||||
// => search for integers in: [ySrc, ySrc + 1) * trgHeight / srcHeight
|
||||
|
||||
//keep within for loop to support MT input slices!
|
||||
const int yTrg_first = ( y * trgHeight + srcHeight - 1) / srcHeight; //=ceil(y * trgHeight / srcHeight)
|
||||
const int yTrg_last = ((y + 1) * trgHeight + srcHeight - 1) / srcHeight; //=ceil(((y + 1) * trgHeight) / srcHeight)
|
||||
const int blockHeight = yTrg_last - yTrg_first;
|
||||
|
||||
if (blockHeight > 0)
|
||||
const int xTrgLast = ((x + 1) * trgWidth + srcWidth - 1) / srcWidth;
|
||||
const int blockWidth = xTrgLast - xTrgFirst;
|
||||
if (blockWidth > 0)
|
||||
{
|
||||
const PixSrc* srcLine = byteAdvance(src, y * srcPitch);
|
||||
/**/ PixTrg* trgLine = byteAdvance(trg, yTrg_first * trgPitch);
|
||||
int xTrg_first = 0;
|
||||
xTrgFirst = xTrgLast;
|
||||
|
||||
for (int x = 0; x < srcWidth; ++x)
|
||||
{
|
||||
const int xTrg_last = ((x + 1) * trgWidth + srcWidth - 1) / srcWidth;
|
||||
const int blockWidth = xTrg_last - xTrg_first;
|
||||
if (blockWidth > 0)
|
||||
{
|
||||
xTrg_first = xTrg_last;
|
||||
|
||||
const auto trgPix = pixCvrt(srcLine[x]);
|
||||
fillBlock(trgLine, trgPitch, trgPix, blockWidth, blockHeight);
|
||||
trgLine += blockWidth;
|
||||
}
|
||||
}
|
||||
const auto trgPix = pixCvrt(srcLine[x]);
|
||||
fillBlock(trgLine, trgPitch, trgPix, blockWidth, blockHeight);
|
||||
trgLine += blockWidth;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
case SliceType::TARGET:
|
||||
//nearest-neighbor (going over target image - slow for upscaling, since source is read multiple times missing out on cache! Fast for similar image sizes!)
|
||||
yFirst = std::max(yFirst, 0);
|
||||
yLast = std::min(yLast, trgHeight);
|
||||
if (yFirst >= yLast || srcHeight <= 0 || srcWidth <= 0) return;
|
||||
|
||||
for (int y = yFirst; y < yLast; ++y)
|
||||
template <class PixTrg, class PixConverter>
|
||||
void bilinearScale(const uint32_t* src, int srcWidth, int srcHeight, int srcPitch,
|
||||
/**/ PixTrg* trg, int trgWidth, int trgHeight, int trgPitch,
|
||||
int yFirst, int yLast, PixConverter pixCvrt /*convert uint32_t to PixTrg*/)
|
||||
{
|
||||
static_assert(std::is_integral<PixTrg>::value, "PixTrg* is expected to be cast-able to char*");
|
||||
static_assert(std::is_same<decltype(pixCvrt(uint32_t())), PixTrg>::value, "PixConverter returning wrong pixel format");
|
||||
|
||||
if (srcPitch < srcWidth * static_cast<int>(sizeof(uint32_t)) ||
|
||||
trgPitch < trgWidth * static_cast<int>(sizeof(PixTrg)))
|
||||
{
|
||||
assert(false);
|
||||
return;
|
||||
}
|
||||
|
||||
yFirst = std::max(yFirst, 0);
|
||||
yLast = std::min(yLast, trgHeight);
|
||||
if (yFirst >= yLast || srcHeight <= 0 || srcWidth <= 0) return;
|
||||
|
||||
const double scaleX = static_cast<double>(trgWidth ) / srcWidth;
|
||||
const double scaleY = static_cast<double>(trgHeight) / srcHeight;
|
||||
|
||||
//perf notes:
|
||||
// -> double-based calculation is (slightly) faster than float
|
||||
// -> pre-calculation gives significant boost; std::vector<> memory allocation is negligible!
|
||||
struct CoeffsX
|
||||
{
|
||||
int x1 = 0;
|
||||
int x2 = 0;
|
||||
double xx1 = 0;
|
||||
double x2x = 0;
|
||||
};
|
||||
std::vector<CoeffsX> buf(trgWidth);
|
||||
for (int x = 0; x < trgWidth; ++x)
|
||||
{
|
||||
const int x1 = srcWidth * x / trgWidth;
|
||||
int x2 = x1 + 1;
|
||||
if (x2 == srcWidth) --x2;
|
||||
|
||||
const double xx1 = x / scaleX - x1;
|
||||
const double x2x = 1 - xx1;
|
||||
|
||||
buf[x] = { x1, x2, xx1, x2x };
|
||||
}
|
||||
|
||||
for (int y = yFirst; y < yLast; ++y)
|
||||
{
|
||||
const int y1 = srcHeight * y / trgHeight;
|
||||
int y2 = y1 + 1;
|
||||
if (y2 == srcHeight) --y2;
|
||||
|
||||
const double yy1 = y / scaleY - y1;
|
||||
const double y2y = 1 - yy1;
|
||||
|
||||
const uint32_t* const srcLine = byteAdvance(src, y1 * srcPitch);
|
||||
const uint32_t* const srcLineNext = byteAdvance(src, y2 * srcPitch);
|
||||
PixTrg* const trgLine = byteAdvance(trg, y * trgPitch);
|
||||
|
||||
for (int x = 0; x < trgWidth; ++x)
|
||||
{
|
||||
//perf: do NOT "simplify" the variable layout without measurement!
|
||||
const int x1 = buf[x].x1;
|
||||
const int x2 = buf[x].x2;
|
||||
const double xx1 = buf[x].xx1;
|
||||
const double x2x = buf[x].x2x;
|
||||
|
||||
const double x2xy2y = x2x * y2y;
|
||||
const double xx1y2y = xx1 * y2y;
|
||||
const double x2xyy1 = x2x * yy1;
|
||||
const double xx1yy1 = xx1 * yy1;
|
||||
|
||||
auto interpolate = [=](int offset)
|
||||
{
|
||||
PixTrg* trgLine = byteAdvance(trg, y * trgPitch);
|
||||
const int ySrc = srcHeight * y / trgHeight;
|
||||
const PixSrc* srcLine = byteAdvance(src, ySrc * srcPitch);
|
||||
for (int x = 0; x < trgWidth; ++x)
|
||||
{
|
||||
const int xSrc = srcWidth * x / trgWidth;
|
||||
trgLine[x] = pixCvrt(srcLine[xSrc]);
|
||||
}
|
||||
}
|
||||
break;
|
||||
/* https://en.wikipedia.org/wiki/Bilinear_interpolation
|
||||
(c11(x2 - x) + c21(x - x1)) * (y2 - y ) +
|
||||
(c12(x2 - x) + c22(x - x1)) * (y - y1) */
|
||||
const auto c11 = (srcLine [x1] >> (8 * offset)) & 0xff;
|
||||
const auto c21 = (srcLine [x2] >> (8 * offset)) & 0xff;
|
||||
const auto c12 = (srcLineNext[x1] >> (8 * offset)) & 0xff;
|
||||
const auto c22 = (srcLineNext[x2] >> (8 * offset)) & 0xff;
|
||||
|
||||
return c11 * x2xy2y + c21 * xx1y2y +
|
||||
c12 * x2xyy1 + c22 * xx1yy1;
|
||||
};
|
||||
|
||||
const double bi = interpolate(0);
|
||||
const double gi = interpolate(1);
|
||||
const double ri = interpolate(2);
|
||||
const double ai = interpolate(3);
|
||||
|
||||
const auto b = static_cast<uint32_t>(bi + 0.5);
|
||||
const auto g = static_cast<uint32_t>(gi + 0.5);
|
||||
const auto r = static_cast<uint32_t>(ri + 0.5);
|
||||
const auto a = static_cast<uint32_t>(ai + 0.5);
|
||||
|
||||
const uint32_t trgPix = (a << 24) | (r << 16) | (g << 8) | b;
|
||||
|
||||
trgLine[x] = pixCvrt(trgPix);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Submodule
+1
Submodule core/deps/xbyak added at 0d67fd1530.
-11
@@ -1,11 +0,0 @@
|
||||
name: test
|
||||
on: [push]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: test
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- run: sudo apt install nasm yasm g++-multilib tcsh
|
||||
- run: make test
|
||||
@@ -1 +0,0 @@
|
||||
/build* # cmake
|
||||
@@ -1,46 +0,0 @@
|
||||
cmake_minimum_required(VERSION 2.6...3.0.2)
|
||||
|
||||
project(xbyak CXX)
|
||||
|
||||
file(GLOB headers xbyak/*.h)
|
||||
|
||||
if (DEFINED CMAKE_VERSION AND CMAKE_VERSION VERSION_GREATER_EQUAL 3.0.2)
|
||||
include(GNUInstallDirs)
|
||||
add_library(${PROJECT_NAME} INTERFACE)
|
||||
add_library(${PROJECT_NAME}::${PROJECT_NAME} ALIAS ${PROJECT_NAME})
|
||||
|
||||
target_include_directories(
|
||||
${PROJECT_NAME} INTERFACE
|
||||
"$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>"
|
||||
"$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>"
|
||||
)
|
||||
|
||||
install(
|
||||
TARGETS ${PROJECT_NAME}
|
||||
EXPORT ${PROJECT_NAME}-targets
|
||||
)
|
||||
|
||||
configure_file(
|
||||
cmake/config.cmake.in
|
||||
${PROJECT_NAME}Config.cmake
|
||||
@ONLY
|
||||
)
|
||||
|
||||
install(
|
||||
FILES ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake
|
||||
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}
|
||||
)
|
||||
|
||||
install(
|
||||
EXPORT ${PROJECT_NAME}-targets
|
||||
NAMESPACE ${PROJECT_NAME}::
|
||||
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}
|
||||
)
|
||||
elseif(NOT DEFINED CMAKE_INSTALL_INCLUDEDIR)
|
||||
set(CMAKE_INSTALL_INCLUDEDIR "include")
|
||||
endif()
|
||||
|
||||
install(
|
||||
FILES ${headers}
|
||||
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/xbyak
|
||||
)
|
||||
@@ -1,47 +0,0 @@
|
||||
|
||||
Copyright (c) 2007 MITSUNARI Shigeo
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
Neither the name of the copyright owner nor the names of its contributors may
|
||||
be used to endorse or promote products derived from this software without
|
||||
specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
THE POSSIBILITY OF SUCH DAMAGE.
|
||||
-----------------------------------------------------------------------------
|
||||
ソースコード形式かバイナリ形式か、変更するかしないかを問わず、以下の条件を満た
|
||||
す場合に限り、再頒布および使用が許可されます。
|
||||
|
||||
ソースコードを再頒布する場合、上記の著作権表示、本条件一覧、および下記免責条項
|
||||
を含めること。
|
||||
バイナリ形式で再頒布する場合、頒布物に付属のドキュメント等の資料に、上記の著作
|
||||
権表示、本条件一覧、および下記免責条項を含めること。
|
||||
書面による特別の許可なしに、本ソフトウェアから派生した製品の宣伝または販売促進
|
||||
に、著作権者の名前またはコントリビューターの名前を使用してはならない。
|
||||
本ソフトウェアは、著作権者およびコントリビューターによって「現状のまま」提供さ
|
||||
れており、明示黙示を問わず、商業的な使用可能性、および特定の目的に対する適合性
|
||||
に関する暗黙の保証も含め、またそれに限定されない、いかなる保証もありません。
|
||||
著作権者もコントリビューターも、事由のいかんを問わず、 損害発生の原因いかんを
|
||||
問わず、かつ責任の根拠が契約であるか厳格責任であるか(過失その他の)不法行為で
|
||||
あるかを問わず、仮にそのような損害が発生する可能性を知らされていたとしても、
|
||||
本ソフトウェアの使用によって発生した(代替品または代用サービスの調達、使用の
|
||||
喪失、データの喪失、利益の喪失、業務の中断も含め、またそれに限定されない)直接
|
||||
損害、間接損害、偶発的な損害、特別損害、懲罰的損害、または結果損害について、
|
||||
一切責任を負わないものとします。
|
||||
@@ -1,24 +0,0 @@
|
||||
PREFIX?=/usr/local
|
||||
INSTALL_DIR=$(PREFIX)/include/xbyak
|
||||
|
||||
all:
|
||||
$(MAKE) -C sample
|
||||
|
||||
clean:
|
||||
$(MAKE) -C sample clean
|
||||
|
||||
install:
|
||||
mkdir -p $(INSTALL_DIR)
|
||||
cp -pR xbyak/*.h $(INSTALL_DIR)
|
||||
|
||||
uninstall:
|
||||
rm -i $(INSTALL_DIR)/*.h
|
||||
rmdir $(INSTALL_DIR)
|
||||
|
||||
update:
|
||||
$(MAKE) -C gen
|
||||
|
||||
test:
|
||||
$(MAKE) -C test test
|
||||
|
||||
.PHONY: test update
|
||||
@@ -1 +0,0 @@
|
||||
include("${CMAKE_CURRENT_LIST_DIR}/@[email protected]")
|
||||
@@ -1,26 +0,0 @@
|
||||
TARGET=../xbyak/xbyak_mnemonic.h
|
||||
BIN=sortline gen_code gen_avx512
|
||||
CFLAGS=-I../ -O2 -DXBYAK_NO_OP_NAMES -Wall -Wextra -Wno-missing-field-initializers
|
||||
all: $(TARGET)
|
||||
sortline: sortline.cpp
|
||||
$(CXX) $(CFLAGS) $< -o $@
|
||||
gen_code: gen_code.cpp ../xbyak/xbyak.h avx_type.hpp
|
||||
$(CXX) $(CFLAGS) $< -o $@
|
||||
gen_avx512: gen_avx512.cpp ../xbyak/xbyak.h avx_type.hpp
|
||||
$(CXX) $(CFLAGS) $< -o $@
|
||||
|
||||
$(TARGET): $(BIN)
|
||||
./gen_code | ./sortline > $@
|
||||
echo "#ifdef XBYAK_ENABLE_OMITTED_OPERAND" >> $@
|
||||
./gen_code omit | ./sortline >> $@
|
||||
echo "#endif" >>$@
|
||||
./gen_code fixed >> $@
|
||||
echo "#ifndef XBYAK_DISABLE_AVX512" >> $@
|
||||
./gen_avx512 | ./sortline >> $@
|
||||
echo "#ifdef XBYAK64" >> $@
|
||||
./gen_avx512 64 | ./sortline >> $@
|
||||
echo "#endif" >> $@
|
||||
echo "#endif" >> $@
|
||||
|
||||
clean:
|
||||
$(RM) $(BIN) $(TARGET)
|
||||
@@ -1,170 +0,0 @@
|
||||
#include <assert.h>
|
||||
// copy CodeGenerator::AVXtype
|
||||
enum AVXtype {
|
||||
// low 3 bit
|
||||
T_N1 = 1,
|
||||
T_N2 = 2,
|
||||
T_N4 = 3,
|
||||
T_N8 = 4,
|
||||
T_N16 = 5,
|
||||
T_N32 = 6,
|
||||
T_NX_MASK = 7,
|
||||
//
|
||||
T_N_VL = 1 << 3, // N * (1, 2, 4) for VL
|
||||
T_DUP = 1 << 4, // N = (8, 32, 64)
|
||||
T_66 = 1 << 5,
|
||||
T_F3 = 1 << 6,
|
||||
T_F2 = 1 << 7,
|
||||
T_0F = 1 << 8,
|
||||
T_0F38 = 1 << 9,
|
||||
T_0F3A = 1 << 10,
|
||||
T_L0 = 1 << 11,
|
||||
T_L1 = 1 << 12,
|
||||
T_W0 = 1 << 13,
|
||||
T_W1 = 1 << 14,
|
||||
T_EW0 = 1 << 15,
|
||||
T_EW1 = 1 << 16,
|
||||
T_YMM = 1 << 17, // support YMM, ZMM
|
||||
T_EVEX = 1 << 18,
|
||||
T_ER_X = 1 << 19, // xmm{er}
|
||||
T_ER_Y = 1 << 20, // ymm{er}
|
||||
T_ER_Z = 1 << 21, // zmm{er}
|
||||
T_SAE_X = 1 << 22, // xmm{sae}
|
||||
T_SAE_Y = 1 << 23, // ymm{sae}
|
||||
T_SAE_Z = 1 << 24, // zmm{sae}
|
||||
T_MUST_EVEX = 1 << 25, // contains T_EVEX
|
||||
T_B32 = 1 << 26, // m32bcst
|
||||
T_B64 = 1 << 27, // m64bcst
|
||||
T_M_K = 1 << 28, // mem{k}
|
||||
T_VSIB = 1 << 29,
|
||||
T_MEM_EVEX = 1 << 30, // use evex if mem
|
||||
T_XXX
|
||||
};
|
||||
|
||||
const int NONE = 256; // same as Xbyak::CodeGenerator::NONE
|
||||
|
||||
std::string type2String(int type)
|
||||
{
|
||||
std::string str;
|
||||
int low = type & T_NX_MASK;
|
||||
if (0 < low) {
|
||||
const char *tbl[8] = {
|
||||
"T_N1", "T_N2", "T_N4", "T_N8", "T_N16", "T_N32"
|
||||
};
|
||||
assert(low < int(sizeof(tbl) / sizeof(tbl[0])));
|
||||
str = tbl[low - 1];
|
||||
}
|
||||
if (type & T_N_VL) {
|
||||
if (!str.empty()) str += " | ";
|
||||
str += "T_N_VL";
|
||||
}
|
||||
if (type & T_DUP) {
|
||||
if (!str.empty()) str += " | ";
|
||||
str += "T_DUP";
|
||||
}
|
||||
if (type & T_66) {
|
||||
if (!str.empty()) str += " | ";
|
||||
str += "T_66";
|
||||
}
|
||||
if (type & T_F3) {
|
||||
if (!str.empty()) str += " | ";
|
||||
str += "T_F3";
|
||||
}
|
||||
if (type & T_F2) {
|
||||
if (!str.empty()) str += " | ";
|
||||
str += "T_F2";
|
||||
}
|
||||
if (type & T_0F) {
|
||||
if (!str.empty()) str += " | ";
|
||||
str += "T_0F";
|
||||
}
|
||||
if (type & T_0F38) {
|
||||
if (!str.empty()) str += " | ";
|
||||
str += "T_0F38";
|
||||
}
|
||||
if (type & T_0F3A) {
|
||||
if (!str.empty()) str += " | ";
|
||||
str += "T_0F3A";
|
||||
}
|
||||
if (type & T_L0) {
|
||||
if (!str.empty()) str += " | ";
|
||||
str += "VEZ_L0";
|
||||
}
|
||||
if (type & T_L1) {
|
||||
if (!str.empty()) str += " | ";
|
||||
str += "VEZ_L1";
|
||||
}
|
||||
if (type & T_W0) {
|
||||
if (!str.empty()) str += " | ";
|
||||
str += "T_W0";
|
||||
}
|
||||
if (type & T_W1) {
|
||||
if (!str.empty()) str += " | ";
|
||||
str += "T_W1";
|
||||
}
|
||||
if (type & T_EW0) {
|
||||
if (!str.empty()) str += " | ";
|
||||
str += "T_EW0";
|
||||
}
|
||||
if (type & T_EW1) {
|
||||
if (!str.empty()) str += " | ";
|
||||
str += "T_EW1";
|
||||
}
|
||||
if (type & T_YMM) {
|
||||
if (!str.empty()) str += " | ";
|
||||
str += "T_YMM";
|
||||
}
|
||||
if (type & T_EVEX) {
|
||||
if (!str.empty()) str += " | ";
|
||||
str += "T_EVEX";
|
||||
}
|
||||
if (type & T_ER_X) {
|
||||
if (!str.empty()) str += " | ";
|
||||
str += "T_ER_X";
|
||||
}
|
||||
if (type & T_ER_Y) {
|
||||
if (!str.empty()) str += " | ";
|
||||
str += "T_ER_Y";
|
||||
}
|
||||
if (type & T_ER_Z) {
|
||||
if (!str.empty()) str += " | ";
|
||||
str += "T_ER_Z";
|
||||
}
|
||||
if (type & T_SAE_X) {
|
||||
if (!str.empty()) str += " | ";
|
||||
str += "T_SAE_X";
|
||||
}
|
||||
if (type & T_SAE_Y) {
|
||||
if (!str.empty()) str += " | ";
|
||||
str += "T_SAE_Y";
|
||||
}
|
||||
if (type & T_SAE_Z) {
|
||||
if (!str.empty()) str += " | ";
|
||||
str += "T_SAE_Z";
|
||||
}
|
||||
if (type & T_MUST_EVEX) {
|
||||
if (!str.empty()) str += " | ";
|
||||
str += "T_MUST_EVEX";
|
||||
}
|
||||
if (type & T_B32) {
|
||||
if (!str.empty()) str += " | ";
|
||||
str += "T_B32";
|
||||
}
|
||||
if (type & T_B64) {
|
||||
if (!str.empty()) str += " | ";
|
||||
str += "T_B64";
|
||||
}
|
||||
if (type & T_M_K) {
|
||||
if (!str.empty()) str += " | ";
|
||||
str += "T_M_K";
|
||||
}
|
||||
if (type & T_VSIB) {
|
||||
if (!str.empty()) str += " | ";
|
||||
str += "T_VSIB";
|
||||
}
|
||||
if (type & T_MEM_EVEX) {
|
||||
if (!str.empty()) str += " | ";
|
||||
str += "T_MEM_EVEX";
|
||||
}
|
||||
return str;
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
#include <stdio.h>
|
||||
|
||||
int main()
|
||||
{
|
||||
puts("enum {");
|
||||
for (int i = 0; i < 256; i++) {
|
||||
printf(" B");
|
||||
for (int j = 0; j < 8; j++) {
|
||||
putchar(i & (1 << (7 - j)) ? '1' : '0');
|
||||
}
|
||||
printf("= %d", i);
|
||||
if (i < 255) putchar(',');
|
||||
putchar('\n');
|
||||
}
|
||||
puts("};");
|
||||
return 0;
|
||||
}
|
||||
@@ -1,750 +0,0 @@
|
||||
#define XBYAK_DONT_READ_LIST
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "../xbyak/xbyak.h"
|
||||
#define NUM_OF_ARRAY(x) (sizeof(x) / sizeof(x[0]))
|
||||
|
||||
using namespace Xbyak;
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(disable : 4996) // scanf
|
||||
#define snprintf _snprintf_s
|
||||
#endif
|
||||
|
||||
#include "avx_type.hpp"
|
||||
|
||||
void putOpmask(bool only64bit)
|
||||
{
|
||||
if (only64bit) {
|
||||
puts("void kmovq(const Opmask& k, const Reg64& r) { opVex(k, 0, r, T_L0 | T_0F | T_F2 | T_W1, 0x92); }");
|
||||
puts("void kmovq(const Reg64& r, const Opmask& k) { opVex(r, 0, k, T_L0 | T_0F | T_F2 | T_W1, 0x93); }");
|
||||
return;
|
||||
}
|
||||
|
||||
{
|
||||
const struct Tbl {
|
||||
const char *name;
|
||||
uint8_t code;
|
||||
} tbl[] = {
|
||||
{ "kadd", 0x4A },
|
||||
{ "kand", 0x41 },
|
||||
{ "kandn", 0x42 },
|
||||
{ "kor", 0x45 },
|
||||
{ "kxnor", 0x46 },
|
||||
{ "kxor", 0x47 },
|
||||
};
|
||||
for (size_t i = 0; i < NUM_OF_ARRAY(tbl); i++) {
|
||||
const Tbl& p = tbl[i];
|
||||
printf("void %sw(const Opmask& r1, const Opmask& r2, const Opmask& r3) { opVex(r1, &r2, r3, T_L1 | T_0F | T_W0, 0x%02X); }\n", p.name, p.code);
|
||||
printf("void %sq(const Opmask& r1, const Opmask& r2, const Opmask& r3) { opVex(r1, &r2, r3, T_L1 | T_0F | T_W1, 0x%02X); }\n", p.name, p.code);
|
||||
printf("void %sb(const Opmask& r1, const Opmask& r2, const Opmask& r3) { opVex(r1, &r2, r3, T_L1 | T_0F | T_66 | T_W0, 0x%02X); }\n", p.name, p.code);
|
||||
printf("void %sd(const Opmask& r1, const Opmask& r2, const Opmask& r3) { opVex(r1, &r2, r3, T_L1 | T_0F | T_66 | T_W1, 0x%02X); }\n", p.name, p.code);
|
||||
}
|
||||
printf("void kunpckbw(const Opmask& r1, const Opmask& r2, const Opmask& r3) { opVex(r1, &r2, r3, T_L1 | T_0F | T_66 | T_W0, 0x4B); }\n");
|
||||
printf("void kunpckwd(const Opmask& r1, const Opmask& r2, const Opmask& r3) { opVex(r1, &r2, r3, T_L1 | T_0F | T_W0, 0x4B); }\n");
|
||||
printf("void kunpckdq(const Opmask& r1, const Opmask& r2, const Opmask& r3) { opVex(r1, &r2, r3, T_L1 | T_0F | T_W1, 0x4B); }\n");
|
||||
}
|
||||
{
|
||||
const struct Tbl {
|
||||
const char *name;
|
||||
uint8_t code;
|
||||
} tbl[] = {
|
||||
{ "knot", 0x44 },
|
||||
{ "kortest", 0x98 },
|
||||
{ "ktest", 0x99 },
|
||||
};
|
||||
for (size_t i = 0; i < NUM_OF_ARRAY(tbl); i++) {
|
||||
const Tbl& p = tbl[i];
|
||||
printf("void %sw(const Opmask& r1, const Opmask& r2) { opVex(r1, 0, r2, T_0F | T_W0, 0x%02X); }\n", p.name, p.code);
|
||||
printf("void %sq(const Opmask& r1, const Opmask& r2) { opVex(r1, 0, r2, T_0F | T_W1, 0x%02X); }\n", p.name, p.code);
|
||||
printf("void %sb(const Opmask& r1, const Opmask& r2) { opVex(r1, 0, r2, T_0F | T_66 | T_W0, 0x%02X); }\n", p.name, p.code);
|
||||
printf("void %sd(const Opmask& r1, const Opmask& r2) { opVex(r1, 0, r2, T_0F | T_66 | T_W1, 0x%02X); }\n", p.name, p.code);
|
||||
}
|
||||
}
|
||||
{
|
||||
const struct Tbl {
|
||||
const char *name;
|
||||
uint8_t code;
|
||||
} tbl[] = {
|
||||
{ "kshiftl", 0x32 },
|
||||
{ "kshiftr", 0x30 },
|
||||
};
|
||||
for (size_t i = 0; i < NUM_OF_ARRAY(tbl); i++) {
|
||||
const Tbl& p = tbl[i];
|
||||
printf("void %sw(const Opmask& r1, const Opmask& r2, uint8_t imm) { opVex(r1, 0, r2, T_66 | T_0F3A | T_W1, 0x%02X, imm); }\n", p.name, p.code);
|
||||
printf("void %sq(const Opmask& r1, const Opmask& r2, uint8_t imm) { opVex(r1, 0, r2, T_66 | T_0F3A | T_W1, 0x%02X, imm); }\n", p.name, p.code + 1);
|
||||
printf("void %sb(const Opmask& r1, const Opmask& r2, uint8_t imm) { opVex(r1, 0, r2, T_66 | T_0F3A | T_W0, 0x%02X, imm); }\n", p.name, p.code);
|
||||
printf("void %sd(const Opmask& r1, const Opmask& r2, uint8_t imm) { opVex(r1, 0, r2, T_66 | T_0F3A | T_W0, 0x%02X, imm); }\n", p.name, p.code + 1);
|
||||
}
|
||||
}
|
||||
puts("void kmovw(const Opmask& k, const Operand& op) { if (!op.isMEM() && !op.isOPMASK()) XBYAK_THROW(ERR_BAD_COMBINATION) opVex(k, 0, op, T_L0 | T_0F | T_W0, 0x90); }");
|
||||
puts("void kmovq(const Opmask& k, const Operand& op) { if (!op.isMEM() && !op.isOPMASK()) XBYAK_THROW(ERR_BAD_COMBINATION) opVex(k, 0, op, T_L0 | T_0F | T_W1, 0x90); }");
|
||||
puts("void kmovb(const Opmask& k, const Operand& op) { if (!op.isMEM() && !op.isOPMASK()) XBYAK_THROW(ERR_BAD_COMBINATION) opVex(k, 0, op, T_L0 | T_0F | T_66 | T_W0, 0x90); }");
|
||||
puts("void kmovd(const Opmask& k, const Operand& op) { if (!op.isMEM() && !op.isOPMASK()) XBYAK_THROW(ERR_BAD_COMBINATION) opVex(k, 0, op, T_L0 | T_0F | T_66 | T_W1, 0x90); }");
|
||||
|
||||
puts("void kmovw(const Address& addr, const Opmask& k) { opVex(k, 0, addr, T_L0 | T_0F | T_W0, 0x91); }");
|
||||
puts("void kmovq(const Address& addr, const Opmask& k) { opVex(k, 0, addr, T_L0 | T_0F | T_W1, 0x91); }");
|
||||
puts("void kmovb(const Address& addr, const Opmask& k) { opVex(k, 0, addr, T_L0 | T_0F | T_66 | T_W0, 0x91); }");
|
||||
puts("void kmovd(const Address& addr, const Opmask& k) { opVex(k, 0, addr, T_L0 | T_0F | T_66 | T_W1, 0x91); }");
|
||||
|
||||
puts("void kmovw(const Opmask& k, const Reg32& r) { opVex(k, 0, r, T_L0 | T_0F | T_W0, 0x92); }");
|
||||
puts("void kmovw(const Reg32& r, const Opmask& k) { opVex(r, 0, k, T_L0 | T_0F | T_W0, 0x93); }");
|
||||
puts("void kmovb(const Opmask& k, const Reg32& r) { opVex(k, 0, r, T_L0 | T_0F | T_66 | T_W0, 0x92); }");
|
||||
puts("void kmovb(const Reg32& r, const Opmask& k) { opVex(r, 0, k, T_L0 | T_0F | T_66 | T_W0, 0x93); }");
|
||||
puts("void kmovd(const Opmask& k, const Reg32& r) { opVex(k, 0, r, T_L0 | T_0F | T_F2 | T_W0, 0x92); }");
|
||||
puts("void kmovd(const Reg32& r, const Opmask& k) { opVex(r, 0, k, T_L0 | T_0F | T_F2 | T_W0, 0x93); }");
|
||||
}
|
||||
|
||||
// vcmppd(k, x, op)
|
||||
void putVcmp()
|
||||
{
|
||||
const struct Tbl {
|
||||
uint8_t code;
|
||||
const char *name;
|
||||
int type;
|
||||
bool hasIMM;
|
||||
} tbl[] = {
|
||||
{ 0xC2, "vcmppd", T_0F | T_MUST_EVEX | T_EW1 | T_SAE_Z | T_YMM | T_66 | T_B64, true },
|
||||
{ 0xC2, "vcmpps", T_0F | T_MUST_EVEX | T_EW0 | T_SAE_Z | T_YMM | T_B32, true },
|
||||
{ 0xC2, "vcmpsd", T_0F | T_MUST_EVEX | T_EW1 | T_SAE_Z | T_F2 | T_N8, true },
|
||||
{ 0xC2, "vcmpss", T_0F | T_MUST_EVEX | T_EW0 | T_SAE_Z | T_F3 | T_N4, true },
|
||||
|
||||
{ 0x74, "vpcmpeqb", T_66 | T_0F | T_MUST_EVEX | T_YMM, false },
|
||||
{ 0x75, "vpcmpeqw", T_66 | T_0F | T_MUST_EVEX | T_YMM, false },
|
||||
{ 0x76, "vpcmpeqd", T_66 | T_0F | T_MUST_EVEX | T_YMM | T_B32, false },
|
||||
{ 0x29, "vpcmpeqq", T_66 | T_0F38 | T_MUST_EVEX | T_YMM | T_EW1 | T_B64, false },
|
||||
|
||||
{ 0x64, "vpcmpgtb", T_66 | T_0F | T_MUST_EVEX | T_YMM, false },
|
||||
{ 0x65, "vpcmpgtw", T_66 | T_0F | T_MUST_EVEX | T_YMM, false },
|
||||
{ 0x66, "vpcmpgtd", T_66 | T_0F | T_MUST_EVEX | T_YMM | T_EW0 | T_B32, false },
|
||||
{ 0x37, "vpcmpgtq", T_66 | T_0F38 | T_MUST_EVEX | T_YMM | T_EW1 | T_B64, false },
|
||||
|
||||
{ 0x3F, "vpcmpb", T_66 | T_0F3A | T_MUST_EVEX | T_YMM | T_EW0, true },
|
||||
{ 0x3E, "vpcmpub", T_66 | T_0F3A | T_MUST_EVEX | T_YMM | T_EW0, true },
|
||||
|
||||
{ 0x3F, "vpcmpw", T_66 | T_0F3A | T_MUST_EVEX | T_YMM | T_EW1, true },
|
||||
{ 0x3E, "vpcmpuw", T_66 | T_0F3A | T_MUST_EVEX | T_YMM | T_EW1, true },
|
||||
{ 0x1F, "vpcmpd", T_66 | T_0F3A | T_MUST_EVEX | T_YMM | T_EW0 | T_B32, true },
|
||||
{ 0x1E, "vpcmpud", T_66 | T_0F3A | T_MUST_EVEX | T_YMM | T_EW0 | T_B32, true },
|
||||
{ 0x1F, "vpcmpq", T_66 | T_0F3A | T_MUST_EVEX | T_YMM | T_EW1 | T_B64, true },
|
||||
{ 0x1E, "vpcmpuq", T_66 | T_0F3A | T_MUST_EVEX | T_YMM | T_EW1 | T_B64, true },
|
||||
|
||||
{ 0x26, "vptestmb", T_66 | T_0F38 | T_MUST_EVEX | T_YMM | T_EW0, false },
|
||||
{ 0x26, "vptestmw", T_66 | T_0F38 | T_MUST_EVEX | T_YMM | T_EW1, false },
|
||||
{ 0x27, "vptestmd", T_66 | T_0F38 | T_MUST_EVEX | T_YMM | T_EW0 | T_B32, false },
|
||||
{ 0x27, "vptestmq", T_66 | T_0F38 | T_MUST_EVEX | T_YMM | T_EW1 | T_B64, false },
|
||||
|
||||
{ 0x26, "vptestnmb", T_F3 | T_0F38 | T_MUST_EVEX | T_YMM | T_EW0, false },
|
||||
{ 0x26, "vptestnmw", T_F3 | T_0F38 | T_MUST_EVEX | T_YMM | T_EW1, false },
|
||||
{ 0x27, "vptestnmd", T_F3 | T_0F38 | T_MUST_EVEX | T_YMM | T_EW0 | T_B32, false },
|
||||
{ 0x27, "vptestnmq", T_F3 | T_0F38 | T_MUST_EVEX | T_YMM | T_EW1 | T_B64, false },
|
||||
};
|
||||
for (size_t i = 0; i < NUM_OF_ARRAY(tbl); i++) {
|
||||
const Tbl *p = &tbl[i];
|
||||
std::string type = type2String(p->type);
|
||||
printf("void %s(const Opmask& k, const Xmm& x, const Operand& op%s) { opAVX_K_X_XM(k, x, op, %s, 0x%02X%s); }\n"
|
||||
, p->name, p->hasIMM ? ", uint8_t imm" : "", type.c_str(), p->code, p->hasIMM ? ", imm" : "");
|
||||
}
|
||||
}
|
||||
|
||||
// XM_X
|
||||
void putX_XM()
|
||||
{
|
||||
const struct Tbl {
|
||||
uint8_t code;
|
||||
const char *name;
|
||||
int type;
|
||||
} tbl[] = {
|
||||
{ 0x6F, "vmovdqa32", T_66 | T_0F | T_MUST_EVEX | T_YMM | T_EW0 | T_ER_X | T_ER_Y | T_ER_Z },
|
||||
{ 0x6F, "vmovdqa64", T_66 | T_0F | T_MUST_EVEX | T_YMM | T_EW1 | T_ER_X | T_ER_Y | T_ER_Z },
|
||||
{ 0x6F, "vmovdqu8", T_F2 | T_0F | T_MUST_EVEX | T_YMM | T_EW0 | T_ER_X | T_ER_Y | T_ER_Z },
|
||||
{ 0x6F, "vmovdqu16", T_F2 | T_0F | T_MUST_EVEX | T_YMM | T_EW1 | T_ER_X | T_ER_Y | T_ER_Z },
|
||||
{ 0x6F, "vmovdqu32", T_F3 | T_0F | T_MUST_EVEX | T_YMM | T_EW0 | T_ER_X | T_ER_Y | T_ER_Z },
|
||||
{ 0x6F, "vmovdqu64", T_F3 | T_0F | T_MUST_EVEX | T_YMM | T_EW1 | T_ER_X | T_ER_Y | T_ER_Z },
|
||||
{ 0x7B, "vcvtpd2qq", T_66 | T_0F | T_MUST_EVEX | T_YMM | T_EW1 | T_B64 | T_ER_Z },
|
||||
// putCvt
|
||||
{ 0x79, "vcvtpd2uqq", T_66 | T_0F | T_MUST_EVEX | T_YMM | T_EW1 | T_B64 | T_ER_Z },
|
||||
{ 0x79, "vcvtps2udq", T_0F | T_MUST_EVEX | T_YMM | T_EW0 | T_B32 | T_ER_Z },
|
||||
{ 0xE6, "vcvtqq2pd", T_F3 | T_0F | T_MUST_EVEX | T_YMM | T_EW1 | T_B64 | T_ER_Z },
|
||||
{ 0x7A, "vcvttpd2qq", T_66 | T_0F | T_MUST_EVEX | T_YMM | T_EW1 | T_B64 | T_SAE_Z },
|
||||
{ 0x78, "vcvttpd2uqq", T_66 | T_0F | T_MUST_EVEX | T_YMM | T_EW1 | T_B64 | T_SAE_Z },
|
||||
{ 0x78, "vcvttps2udq", T_0F | T_MUST_EVEX | T_YMM | T_EW0 | T_B32 | T_SAE_Z },
|
||||
{ 0x7A, "vcvtudq2ps", T_F2 | T_0F | T_YMM | T_MUST_EVEX | T_EW0 | T_B32 | T_ER_Z },
|
||||
{ 0x7A, "vcvtuqq2pd", T_F3 | T_0F | T_YMM | T_MUST_EVEX | T_EW1 | T_B64 | T_ER_Z },
|
||||
|
||||
{ 0x88, "vexpandpd", T_66 | T_0F38 | T_MUST_EVEX | T_YMM | T_EW1 | T_N8 },
|
||||
{ 0x88, "vexpandps", T_66 | T_0F38 | T_MUST_EVEX | T_YMM | T_EW0 | T_N4 },
|
||||
|
||||
{ 0x89, "vpexpandd", T_66 | T_0F38 | T_MUST_EVEX | T_YMM | T_EW0 | T_N4 },
|
||||
{ 0x89, "vpexpandq", T_66 | T_0F38 | T_MUST_EVEX | T_YMM | T_EW1 | T_N8 },
|
||||
{ 0x42, "vgetexppd", T_66 | T_0F38 | T_MUST_EVEX | T_YMM | T_EW1 | T_B64 | T_SAE_Z },
|
||||
{ 0x42, "vgetexpps", T_66 | T_0F38 | T_MUST_EVEX | T_YMM | T_EW0 | T_B32 | T_SAE_Z },
|
||||
};
|
||||
for (size_t i = 0; i < NUM_OF_ARRAY(tbl); i++) {
|
||||
const Tbl *p = &tbl[i];
|
||||
std::string type = type2String(p->type);
|
||||
printf("void %s(const Xmm& x, const Operand& op) { opAVX_X_XM_IMM(x, op, %s, 0x%02X); }\n", p->name, type.c_str(), p->code);
|
||||
}
|
||||
puts("void vpabsq(const Xmm& x, const Operand& op) { opAVX_X_XM_IMM(x, op, T_66 | T_0F38 | T_MUST_EVEX | T_EW1 | T_B64 | T_YMM, 0x1F); }");
|
||||
|
||||
puts("void vexp2pd(const Zmm& z, const Operand& op) { opAVX_X_XM_IMM(z, op, T_66 | T_0F38 | T_MUST_EVEX | T_YMM | T_EW1 | T_B64 | T_SAE_Z, 0xC8); }");
|
||||
puts("void vexp2ps(const Zmm& z, const Operand& op) { opAVX_X_XM_IMM(z, op, T_66 | T_0F38 | T_MUST_EVEX | T_YMM | T_EW0 | T_B32 | T_SAE_Z, 0xC8); }");
|
||||
puts("void vrcp28pd(const Zmm& z, const Operand& op) { opAVX_X_XM_IMM(z, op, T_66 | T_0F38 | T_MUST_EVEX | T_YMM | T_EW1 | T_B64 | T_SAE_Z, 0xCA); }");
|
||||
puts("void vrcp28ps(const Zmm& z, const Operand& op) { opAVX_X_XM_IMM(z, op, T_66 | T_0F38 | T_MUST_EVEX | T_YMM | T_EW0 | T_B32 | T_SAE_Z, 0xCA); }");
|
||||
|
||||
puts("void vrsqrt28pd(const Zmm& z, const Operand& op) { opAVX_X_XM_IMM(z, op, T_66 | T_0F38 | T_MUST_EVEX | T_YMM | T_EW1 | T_B64 | T_SAE_Z, 0xCC); }");
|
||||
puts("void vrsqrt28ps(const Zmm& z, const Operand& op) { opAVX_X_XM_IMM(z, op, T_66 | T_0F38 | T_MUST_EVEX | T_YMM | T_EW0 | T_B32 | T_SAE_Z, 0xCC); }");
|
||||
}
|
||||
|
||||
void putM_X()
|
||||
{
|
||||
const struct Tbl {
|
||||
uint8_t code;
|
||||
const char *name;
|
||||
int type;
|
||||
} tbl[] = {
|
||||
{ 0x7F, "vmovdqa32", T_66 | T_0F | T_MUST_EVEX | T_YMM | T_EW0 | T_ER_X | T_ER_Y | T_ER_Z | T_M_K },
|
||||
{ 0x7F, "vmovdqa64", T_66 | T_0F | T_MUST_EVEX | T_YMM | T_EW1 | T_ER_X | T_ER_Y | T_ER_Z | T_M_K },
|
||||
{ 0x7F, "vmovdqu8", T_F2 | T_0F | T_MUST_EVEX | T_YMM | T_EW0 | T_ER_X | T_ER_Y | T_ER_Z | T_M_K },
|
||||
{ 0x7F, "vmovdqu16", T_F2 | T_0F | T_MUST_EVEX | T_YMM | T_EW1 | T_ER_X | T_ER_Y | T_ER_Z | T_M_K },
|
||||
{ 0x7F, "vmovdqu32", T_F3 | T_0F | T_MUST_EVEX | T_YMM | T_EW0 | T_ER_X | T_ER_Y | T_ER_Z | T_M_K },
|
||||
{ 0x7F, "vmovdqu64", T_F3 | T_0F | T_MUST_EVEX | T_YMM | T_EW1 | T_ER_X | T_ER_Y | T_ER_Z | T_M_K },
|
||||
};
|
||||
for (size_t i = 0; i < NUM_OF_ARRAY(tbl); i++) {
|
||||
const Tbl *p = &tbl[i];
|
||||
std::string type = type2String(p->type);
|
||||
printf("void %s(const Address& addr, const Xmm& x) { opAVX_X_XM_IMM(x, addr, %s, 0x%02X); }\n", p->name, type.c_str(), p->code);
|
||||
}
|
||||
}
|
||||
|
||||
void putXM_X()
|
||||
{
|
||||
const struct Tbl {
|
||||
uint8_t code;
|
||||
const char *name;
|
||||
int type;
|
||||
} tbl[] = {
|
||||
{ 0x8A, "vcompresspd", T_66 | T_0F38 | T_MUST_EVEX | T_YMM | T_EW1 | T_N8 },
|
||||
{ 0x8A, "vcompressps", T_66 | T_0F38 | T_MUST_EVEX | T_YMM | T_EW0 | T_N4 },
|
||||
|
||||
{ 0x8B, "vpcompressd", T_66 | T_0F38 | T_MUST_EVEX | T_YMM | T_EW0 | T_N4 },
|
||||
{ 0x8B, "vpcompressq", T_66 | T_0F38 | T_MUST_EVEX | T_YMM | T_EW1 | T_N8 },
|
||||
|
||||
{ 0x63, "vcompressb", T_66 | T_0F38 | T_MUST_EVEX | T_YMM | T_EW0 | T_N1 },
|
||||
{ 0x63, "vcompressw", T_66 | T_0F38 | T_MUST_EVEX | T_YMM | T_EW1 | T_N2 },
|
||||
};
|
||||
for (size_t i = 0; i < NUM_OF_ARRAY(tbl); i++) {
|
||||
const Tbl *p = &tbl[i];
|
||||
std::string type = type2String(p->type);
|
||||
printf("void %s(const Operand& op, const Xmm& x) { opAVX_X_XM_IMM(x, op, %s, 0x%02X); }\n", p->name, type.c_str(), p->code);
|
||||
}
|
||||
}
|
||||
|
||||
void putX_X_XM_IMM()
|
||||
{
|
||||
const struct Tbl {
|
||||
uint8_t code;
|
||||
const char *name;
|
||||
int type;
|
||||
bool hasIMM;
|
||||
} tbl[] = {
|
||||
{ 0x03, "valignd", T_MUST_EVEX | T_66 | T_0F3A | T_EW0 | T_YMM, true },
|
||||
{ 0x03, "valignq", T_MUST_EVEX | T_66 | T_0F3A | T_EW1 | T_YMM, true },
|
||||
{ 0xDB, "vpandd", T_MUST_EVEX | T_YMM | T_66 | T_0F | T_EW0 | T_B32, false },
|
||||
{ 0xDB, "vpandq", T_MUST_EVEX | T_YMM | T_66 | T_0F | T_EW1 | T_B64, false },
|
||||
{ 0xDF, "vpandnd", T_MUST_EVEX | T_YMM | T_66 | T_0F | T_EW0 | T_B32, false },
|
||||
{ 0xDF, "vpandnq", T_MUST_EVEX | T_YMM | T_66 | T_0F | T_EW1 | T_B64, false },
|
||||
{ 0x3D, "vpmaxsq", T_66 | T_0F38 | T_MUST_EVEX | T_YMM | T_EW1 | T_B64, false },
|
||||
{ 0x3F, "vpmaxuq", T_66 | T_0F38 | T_MUST_EVEX | T_YMM | T_EW1 | T_B64, false },
|
||||
{ 0x39, "vpminsq", T_66 | T_0F38 | T_MUST_EVEX | T_YMM | T_EW1 | T_B64, false },
|
||||
{ 0x3B, "vpminuq", T_66 | T_0F38 | T_MUST_EVEX | T_YMM | T_EW1 | T_B64, false },
|
||||
{ 0xE2, "vpsraq", T_66 | T_0F | T_MUST_EVEX | T_YMM | T_EW1 | T_N16, false },
|
||||
{ 0x46, "vpsravq", T_66 | T_0F38 | T_MUST_EVEX | T_YMM | T_EW1 | T_B64, false },
|
||||
{ 0x11, "vpsravw", T_66 | T_0F38 | T_MUST_EVEX | T_YMM | T_EW1, false },
|
||||
{ 0x12, "vpsllvw", T_66 | T_0F38 | T_MUST_EVEX | T_YMM | T_EW1, false },
|
||||
{ 0x10, "vpsrlvw", T_66 | T_0F38 | T_MUST_EVEX | T_YMM | T_EW1, false },
|
||||
{ 0xEB, "vpord", T_66 | T_0F | T_MUST_EVEX | T_YMM | T_EW0 | T_B32, false },
|
||||
{ 0xEB, "vporq", T_66 | T_0F | T_MUST_EVEX | T_YMM | T_EW1 | T_B64, false },
|
||||
|
||||
{ 0xEF, "vpxord", T_66 | T_0F | T_MUST_EVEX | T_YMM | T_EW0 | T_B32, false },
|
||||
{ 0xEF, "vpxorq", T_66 | T_0F | T_MUST_EVEX | T_YMM | T_EW1 | T_B64, false },
|
||||
|
||||
{ 0x40, "vpmullq", T_66 | T_0F38 | T_MUST_EVEX | T_YMM | T_EW1 | T_B64, false },
|
||||
|
||||
{ 0x8D, "vpermb", T_66 | T_0F38 | T_MUST_EVEX | T_YMM | T_EW0, false },
|
||||
{ 0x8D, "vpermw", T_66 | T_0F38 | T_MUST_EVEX | T_YMM | T_EW1, false },
|
||||
|
||||
{ 0x65, "vblendmpd", T_66 | T_0F38 | T_YMM | T_MUST_EVEX | T_EW1 | T_B64, false },
|
||||
{ 0x65, "vblendmps", T_66 | T_0F38 | T_YMM | T_MUST_EVEX | T_EW0 | T_B32, false },
|
||||
{ 0x66, "vpblendmb", T_66 | T_0F38 | T_YMM | T_MUST_EVEX | T_EW0, false },
|
||||
{ 0x66, "vpblendmw", T_66 | T_0F38 | T_YMM | T_MUST_EVEX | T_EW1, false },
|
||||
{ 0x64, "vpblendmd", T_66 | T_0F38 | T_YMM | T_MUST_EVEX | T_EW0 | T_B32, false },
|
||||
{ 0x64, "vpblendmq", T_66 | T_0F38 | T_YMM | T_MUST_EVEX | T_EW1 | T_B64, false },
|
||||
|
||||
{ 0x7D, "vpermt2b", T_66 | T_0F38 | T_YMM | T_MUST_EVEX | T_EW0, false },
|
||||
{ 0x7D, "vpermt2w", T_66 | T_0F38 | T_YMM | T_MUST_EVEX | T_EW1, false },
|
||||
{ 0x7E, "vpermt2d", T_66 | T_0F38 | T_YMM | T_MUST_EVEX | T_EW0 | T_B32, false },
|
||||
{ 0x7E, "vpermt2q", T_66 | T_0F38 | T_YMM | T_MUST_EVEX | T_EW1 | T_B64, false },
|
||||
{ 0x7F, "vpermt2ps", T_66 | T_0F38 | T_YMM | T_MUST_EVEX | T_EW0 | T_B32, false },
|
||||
{ 0x7F, "vpermt2pd", T_66 | T_0F38 | T_YMM | T_MUST_EVEX | T_EW1 | T_B64, false },
|
||||
|
||||
{ 0x75, "vpermi2b", T_66 | T_0F38 | T_YMM | T_MUST_EVEX | T_EW0, false },
|
||||
{ 0x75, "vpermi2w", T_66 | T_0F38 | T_YMM | T_MUST_EVEX | T_EW1, false },
|
||||
{ 0x76, "vpermi2d", T_66 | T_0F38 | T_YMM | T_MUST_EVEX | T_EW0 | T_B32, false },
|
||||
{ 0x76, "vpermi2q", T_66 | T_0F38 | T_YMM | T_MUST_EVEX | T_EW1 | T_B64, false },
|
||||
{ 0x77, "vpermi2ps", T_66 | T_0F38 | T_YMM | T_MUST_EVEX | T_EW0 | T_B32, false },
|
||||
{ 0x77, "vpermi2pd", T_66 | T_0F38 | T_YMM | T_MUST_EVEX | T_EW1 | T_B64, false },
|
||||
|
||||
{ 0x25, "vpternlogd", T_66 | T_0F3A | T_YMM | T_MUST_EVEX | T_EW0 | T_B32, true },
|
||||
{ 0x25, "vpternlogq", T_66 | T_0F3A | T_YMM | T_MUST_EVEX | T_EW1 | T_B64, true },
|
||||
|
||||
{ 0x43, "vgetexpsd", T_66 | T_0F38 | T_MUST_EVEX | T_EW1 | T_SAE_X | T_N8, false },
|
||||
{ 0x43, "vgetexpss", T_66 | T_0F38 | T_MUST_EVEX | T_EW0 | T_SAE_X | T_N4, false },
|
||||
{ 0x27, "vgetmantsd", T_66 | T_0F3A | T_MUST_EVEX | T_EW1 | T_SAE_X | T_N8, true },
|
||||
{ 0x27, "vgetmantss", T_66 | T_0F3A | T_MUST_EVEX | T_EW0 | T_SAE_X | T_N4, true },
|
||||
|
||||
{ 0x54, "vfixupimmpd", T_66 | T_0F3A | T_MUST_EVEX | T_YMM | T_EW1 | T_B64 | T_SAE_Z, true },
|
||||
{ 0x54, "vfixupimmps", T_66 | T_0F3A | T_MUST_EVEX | T_YMM | T_EW0 | T_B32 | T_SAE_Z, true },
|
||||
{ 0x55, "vfixupimmsd", T_66 | T_0F3A | T_MUST_EVEX | T_EW1 | T_SAE_Z | T_N8, true },
|
||||
{ 0x55, "vfixupimmss", T_66 | T_0F3A | T_MUST_EVEX | T_EW0 | T_SAE_Z | T_N4, true },
|
||||
|
||||
{ 0x4D, "vrcp14sd", T_66 | T_0F38 | T_MUST_EVEX | T_EW1 | T_N8, false },
|
||||
{ 0x4D, "vrcp14ss", T_66 | T_0F38 | T_MUST_EVEX | T_EW0 | T_N4, false },
|
||||
|
||||
{ 0x4F, "vrsqrt14sd", T_66 | T_0F38 | T_YMM | T_MUST_EVEX | T_EW1 | T_N8, false },
|
||||
{ 0x4F, "vrsqrt14ss", T_66 | T_0F38 | T_YMM | T_MUST_EVEX | T_EW0 | T_N4, false },
|
||||
|
||||
{ 0x0B, "vrndscalesd", T_66 | T_0F3A | T_MUST_EVEX | T_EW1 | T_N8, true },
|
||||
{ 0x0A, "vrndscaless", T_66 | T_0F3A | T_MUST_EVEX | T_EW0 | T_N4, true },
|
||||
|
||||
{ 0x2C, "vscalefpd", T_66 | T_0F38 | T_YMM | T_MUST_EVEX | T_EW1 | T_B64 | T_ER_Z, false },
|
||||
{ 0x2C, "vscalefps", T_66 | T_0F38 | T_YMM | T_MUST_EVEX | T_EW0 | T_B32 | T_ER_Z, false },
|
||||
{ 0x2D, "vscalefsd", T_66 | T_0F38 | T_MUST_EVEX | T_EW1 | T_ER_X | T_N8, false },
|
||||
{ 0x2D, "vscalefss", T_66 | T_0F38 | T_MUST_EVEX | T_EW0 | T_ER_X | T_N4, false },
|
||||
|
||||
{ 0x42, "vdbpsadbw", T_66 | T_0F3A | T_YMM | T_MUST_EVEX | T_EW0, true },
|
||||
{ 0x83, "vpmultishiftqb", T_66 | T_0F38 | T_YMM | T_MUST_EVEX | T_EW1 | T_B64, false },
|
||||
|
||||
{ 0x15, "vprolvd", T_66 | T_0F38 | T_YMM | T_MUST_EVEX | T_EW0 | T_B32, false },
|
||||
{ 0x15, "vprolvq", T_66 | T_0F38 | T_YMM | T_MUST_EVEX | T_EW1 | T_B64, false },
|
||||
|
||||
{ 0x14, "vprorvd", T_66 | T_0F38 | T_YMM | T_MUST_EVEX | T_EW0 | T_B32, false },
|
||||
{ 0x14, "vprorvq", T_66 | T_0F38 | T_YMM | T_MUST_EVEX | T_EW1 | T_B64, false },
|
||||
|
||||
{ 0xCB, "vrcp28sd", T_66 | T_0F38 | T_MUST_EVEX | T_EW1 | T_N8 | T_SAE_X, false },
|
||||
{ 0xCB, "vrcp28ss", T_66 | T_0F38 | T_MUST_EVEX | T_EW0 | T_N4 | T_SAE_X, false },
|
||||
|
||||
{ 0xCD, "vrsqrt28sd", T_66 | T_0F38 | T_MUST_EVEX | T_EW1 | T_N8 | T_SAE_X, false },
|
||||
{ 0xCD, "vrsqrt28ss", T_66 | T_0F38 | T_MUST_EVEX | T_EW0 | T_N4 | T_SAE_X, false },
|
||||
|
||||
{ 0x50, "vrangepd", T_66 | T_0F3A | T_YMM | T_MUST_EVEX | T_EW1 | T_B64 | T_SAE_Z, true },
|
||||
{ 0x50, "vrangeps", T_66 | T_0F3A | T_YMM | T_MUST_EVEX | T_EW0 | T_B32 | T_SAE_Z, true },
|
||||
{ 0x51, "vrangesd", T_66 | T_0F3A | T_MUST_EVEX | T_EW1 | T_SAE_X | T_N8, true },
|
||||
{ 0x51, "vrangess", T_66 | T_0F3A | T_MUST_EVEX | T_EW0 | T_SAE_X | T_N4, true },
|
||||
|
||||
{ 0x57, "vreducesd", T_66 | T_0F3A | T_MUST_EVEX | T_EW1 | T_SAE_X | T_N8, true },
|
||||
{ 0x57, "vreducess", T_66 | T_0F3A | T_MUST_EVEX | T_EW0 | T_SAE_X | T_N4, true },
|
||||
|
||||
{ 0xB4, "vpmadd52luq", T_66 | T_0F38 | T_YMM | T_MUST_EVEX | T_EW1 | T_B64, false },
|
||||
{ 0xB5, "vpmadd52huq", T_66 | T_0F38 | T_YMM | T_MUST_EVEX | T_EW1 | T_B64, false },
|
||||
|
||||
{ 0x70, "vpshldw", T_66 | T_0F3A | T_YMM | T_MUST_EVEX | T_EW1 | T_SAE_Z, true },
|
||||
{ 0x71, "vpshldd", T_66 | T_0F3A | T_YMM | T_MUST_EVEX | T_EW0 | T_SAE_Z | T_B32, true },
|
||||
{ 0x71, "vpshldq", T_66 | T_0F3A | T_YMM | T_MUST_EVEX | T_EW1 | T_SAE_Z | T_B64, true },
|
||||
|
||||
{ 0x70, "vpshldvw", T_66 | T_0F38 | T_YMM | T_MUST_EVEX | T_EW1 | T_SAE_Z, false },
|
||||
{ 0x71, "vpshldvd", T_66 | T_0F38 | T_YMM | T_MUST_EVEX | T_EW0 | T_SAE_Z | T_B32, false },
|
||||
{ 0x71, "vpshldvq", T_66 | T_0F38 | T_YMM | T_MUST_EVEX | T_EW1 | T_SAE_Z | T_B64, false },
|
||||
|
||||
{ 0x72, "vpshrdw", T_66 | T_0F3A | T_YMM | T_MUST_EVEX | T_EW1 | T_SAE_Z, true },
|
||||
{ 0x73, "vpshrdd", T_66 | T_0F3A | T_YMM | T_MUST_EVEX | T_EW0 | T_SAE_Z | T_B32, true },
|
||||
{ 0x73, "vpshrdq", T_66 | T_0F3A | T_YMM | T_MUST_EVEX | T_EW1 | T_SAE_Z | T_B64, true },
|
||||
|
||||
{ 0x72, "vpshrdvw", T_66 | T_0F38 | T_YMM | T_MUST_EVEX | T_EW1 | T_SAE_Z, false },
|
||||
{ 0x73, "vpshrdvd", T_66 | T_0F38 | T_YMM | T_MUST_EVEX | T_EW0 | T_SAE_Z | T_B32, false },
|
||||
{ 0x73, "vpshrdvq", T_66 | T_0F38 | T_YMM | T_MUST_EVEX | T_EW1 | T_SAE_Z | T_B64, false },
|
||||
|
||||
{ 0x72, "vcvtne2ps2bf16", T_F2 | T_0F38 | T_YMM | T_MUST_EVEX | T_EW0 | T_SAE_Z | T_B32, false },
|
||||
{ 0x52, "vdpbf16ps", T_F3 | T_0F38 | T_YMM | T_MUST_EVEX | T_EW0 | T_SAE_Z | T_B32, false },
|
||||
};
|
||||
for (size_t i = 0; i < NUM_OF_ARRAY(tbl); i++) {
|
||||
const Tbl *p = &tbl[i];
|
||||
std::string type = type2String(p->type);
|
||||
printf("void %s(const Xmm& x1, const Xmm& x2, const Operand& op%s) { opAVX_X_X_XM(x1, x2, op, %s, 0x%02X%s); }\n"
|
||||
, p->name, p->hasIMM ? ", uint8_t imm" : "", type.c_str(), p->code, p->hasIMM ? ", imm" : "");
|
||||
}
|
||||
}
|
||||
|
||||
void putShift()
|
||||
{
|
||||
const struct Tbl {
|
||||
const char *name;
|
||||
uint8_t code;
|
||||
int idx;
|
||||
int type;
|
||||
} tbl[] = {
|
||||
{ "vpsraq", 0x72, 4, T_0F | T_66 | T_YMM | T_MUST_EVEX |T_EW1 | T_B64 },
|
||||
{ "vprold", 0x72, 1, T_66 | T_0F | T_YMM | T_MUST_EVEX | T_EW0 | T_B32 },
|
||||
{ "vprolq", 0x72, 1, T_66 | T_0F | T_YMM | T_MUST_EVEX | T_EW1 | T_B64 },
|
||||
{ "vprord", 0x72, 0, T_66 | T_0F | T_YMM | T_MUST_EVEX | T_EW0 | T_B32 },
|
||||
{ "vprorq", 0x72, 0, T_66 | T_0F | T_YMM | T_MUST_EVEX | T_EW1 | T_B64 },
|
||||
};
|
||||
for (size_t i = 0; i < NUM_OF_ARRAY(tbl); i++) {
|
||||
const Tbl& p = tbl[i];
|
||||
std::string type = type2String(p.type);
|
||||
printf("void %s(const Xmm& x, const Operand& op, uint8_t imm) { opAVX_X_X_XM(Xmm(x.getKind(), %d), x, op, %s, 0x%02X, imm); }\n", p.name, p.idx, type.c_str(), p.code);
|
||||
}
|
||||
}
|
||||
|
||||
void putExtractInsert()
|
||||
{
|
||||
{
|
||||
const struct Tbl {
|
||||
const char *name;
|
||||
uint8_t code;
|
||||
int type;
|
||||
bool isZMM;
|
||||
} tbl[] = {
|
||||
{ "vextractf32x4", 0x19, T_66 | T_0F3A | T_MUST_EVEX | T_EW0 | T_YMM | T_N16, false },
|
||||
{ "vextractf64x2", 0x19, T_66 | T_0F3A | T_MUST_EVEX | T_EW1 | T_YMM | T_N16, false },
|
||||
{ "vextractf32x8", 0x1B, T_66 | T_0F3A | T_MUST_EVEX | T_EW0 | T_YMM | T_N32, true },
|
||||
{ "vextractf64x4", 0x1B, T_66 | T_0F3A | T_MUST_EVEX | T_EW1 | T_YMM | T_N32, true },
|
||||
|
||||
{ "vextracti32x4", 0x39, T_66 | T_0F3A | T_MUST_EVEX | T_EW0 | T_YMM | T_N16, false },
|
||||
{ "vextracti64x2", 0x39, T_66 | T_0F3A | T_MUST_EVEX | T_EW1 | T_YMM | T_N16, false },
|
||||
{ "vextracti32x8", 0x3B, T_66 | T_0F3A | T_MUST_EVEX | T_EW0 | T_YMM | T_N32, true },
|
||||
{ "vextracti64x4", 0x3B, T_66 | T_0F3A | T_MUST_EVEX | T_EW1 | T_YMM | T_N32, true },
|
||||
};
|
||||
for (size_t i = 0; i < NUM_OF_ARRAY(tbl); i++) {
|
||||
const Tbl& p = tbl[i];
|
||||
std::string type = type2String(p.type);
|
||||
const char *kind = p.isZMM ? "Operand::MEM | Operand::YMM" : "Operand::MEM | Operand::XMM";
|
||||
printf("void %s(const Operand& op, const %s& r, uint8_t imm) { if (!op.is(%s)) XBYAK_THROW(ERR_BAD_COMBINATION) opVex(r, 0, op, %s, 0x%2X, imm); }\n", p.name, p.isZMM ? "Zmm" : "Ymm", kind, type.c_str(), p.code);
|
||||
}
|
||||
}
|
||||
{
|
||||
const struct Tbl {
|
||||
const char *name;
|
||||
uint8_t code;
|
||||
int type;
|
||||
bool isZMM;
|
||||
} tbl[] = {
|
||||
{ "vinsertf32x4", 0x18, T_66 | T_0F3A | T_MUST_EVEX | T_EW0 | T_YMM | T_N16, false },
|
||||
{ "vinsertf64x2", 0x18, T_66 | T_0F3A | T_MUST_EVEX | T_EW1 | T_YMM | T_N16, false },
|
||||
{ "vinsertf32x8", 0x1A, T_66 | T_0F3A | T_MUST_EVEX | T_EW0 | T_YMM | T_N32, true },
|
||||
{ "vinsertf64x4", 0x1A, T_66 | T_0F3A | T_MUST_EVEX | T_EW1 | T_YMM | T_N32, true },
|
||||
|
||||
{ "vinserti32x4", 0x38, T_66 | T_0F3A | T_MUST_EVEX | T_EW0 | T_YMM | T_N16, false },
|
||||
{ "vinserti64x2", 0x38, T_66 | T_0F3A | T_MUST_EVEX | T_EW1 | T_YMM | T_N16, false },
|
||||
{ "vinserti32x8", 0x3A, T_66 | T_0F3A | T_MUST_EVEX | T_EW0 | T_YMM | T_N32, true },
|
||||
{ "vinserti64x4", 0x3A, T_66 | T_0F3A | T_MUST_EVEX | T_EW1 | T_YMM | T_N32, true },
|
||||
};
|
||||
for (size_t i = 0; i < NUM_OF_ARRAY(tbl); i++) {
|
||||
const Tbl& p = tbl[i];
|
||||
std::string type = type2String(p.type);
|
||||
const char *x = p.isZMM ? "Zmm" : "Ymm";
|
||||
const char *cond = p.isZMM ? "op.is(Operand::MEM | Operand::YMM)" : "(r1.getKind() == r2.getKind() && op.is(Operand::MEM | Operand::XMM))";
|
||||
printf("void %s(const %s& r1, const %s& r2, const Operand& op, uint8_t imm) {"
|
||||
"if (!%s) XBYAK_THROW(ERR_BAD_COMBINATION) "
|
||||
"opVex(r1, &r2, op, %s, 0x%2X, imm); }\n", p.name, x, x, cond, type.c_str(), p.code);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void putBroadcast(bool only64bit)
|
||||
{
|
||||
{
|
||||
const struct Tbl {
|
||||
uint8_t code;
|
||||
const char *name;
|
||||
int type;
|
||||
int reg;
|
||||
} tbl[] = {
|
||||
{ 0x7A, "vpbroadcastb", T_66 | T_0F38 | T_YMM | T_MUST_EVEX | T_EW0, 8 },
|
||||
{ 0x7B, "vpbroadcastw", T_66 | T_0F38 | T_YMM | T_MUST_EVEX | T_EW0, 16 },
|
||||
{ 0x7C, "vpbroadcastd", T_66 | T_0F38 | T_YMM | T_MUST_EVEX | T_EW0, 32 },
|
||||
{ 0x7C, "vpbroadcastq", T_66 | T_0F38 | T_YMM | T_MUST_EVEX | T_EW1, 64},
|
||||
};
|
||||
for (size_t i = 0; i < NUM_OF_ARRAY(tbl); i++) {
|
||||
const Tbl& p = tbl[i];
|
||||
std::string type = type2String(p.type);
|
||||
if ((only64bit && p.reg == 64) || (!only64bit && p.reg != 64)) {
|
||||
printf("void %s(const Xmm& x, const Reg%d& r) { opVex(x, 0, r, %s, 0x%02X); }\n", p.name, p.reg, type.c_str(), p.code);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (only64bit) return;
|
||||
puts("void vbroadcastf32x2(const Ymm& y, const Operand& op) { opAVX_X_XM_IMM(y, op, T_66 | T_0F38 | T_YMM | T_MUST_EVEX | T_EW0 | T_N8, 0x19); }");
|
||||
puts("void vbroadcastf32x4(const Ymm& y, const Address& addr) { opAVX_X_XM_IMM(y, addr, T_66 | T_0F38 | T_YMM | T_MUST_EVEX | T_EW0 | T_N16, 0x1A); }");
|
||||
puts("void vbroadcastf64x2(const Ymm& y, const Address& addr) { opAVX_X_XM_IMM(y, addr, T_66 | T_0F38 | T_YMM | T_MUST_EVEX | T_EW1 | T_N16, 0x1A); }");
|
||||
puts("void vbroadcastf64x4(const Zmm& y, const Address& addr) { opAVX_X_XM_IMM(y, addr, T_66 | T_0F38 | T_YMM | T_MUST_EVEX | T_EW1 | T_N32, 0x1B); }");
|
||||
puts("void vbroadcastf32x8(const Zmm& y, const Address& addr) { opAVX_X_XM_IMM(y, addr, T_66 | T_0F38 | T_YMM | T_MUST_EVEX | T_EW0 | T_N32, 0x1B); }");
|
||||
|
||||
puts("void vbroadcasti32x2(const Xmm& x, const Operand& op) { opAVX_X_XM_IMM(x, op, T_66 | T_0F38 | T_YMM | T_MUST_EVEX | T_EW0 | T_N8, 0x59); }");
|
||||
puts("void vbroadcasti32x4(const Ymm& y, const Operand& op) { opAVX_X_XM_IMM(y, op, T_66 | T_0F38 | T_YMM | T_MUST_EVEX | T_EW0 | T_N16, 0x5A); }");
|
||||
puts("void vbroadcasti64x2(const Ymm& y, const Operand& op) { opAVX_X_XM_IMM(y, op, T_66 | T_0F38 | T_YMM | T_MUST_EVEX | T_EW1 | T_N16, 0x5A); }");
|
||||
puts("void vbroadcasti32x8(const Zmm& z, const Operand& op) { opAVX_X_XM_IMM(z, op, T_66 | T_0F38 | T_YMM | T_MUST_EVEX | T_EW0 | T_N32, 0x5B); }");
|
||||
puts("void vbroadcasti64x4(const Zmm& z, const Operand& op) { opAVX_X_XM_IMM(z, op, T_66 | T_0F38 | T_YMM | T_MUST_EVEX | T_EW1 | T_N32, 0x5B); }");
|
||||
}
|
||||
|
||||
void putCvt()
|
||||
{
|
||||
puts("void vcvtpd2udq(const Xmm& x, const Operand& op) { opCvt2(x, op, T_0F | T_YMM | T_MUST_EVEX | T_EW1 | T_B64 | T_ER_Z, 0x79); }");
|
||||
puts("void vcvtps2qq(const Xmm& x, const Operand& op) { checkCvt1(x, op); opVex(x, 0, op, T_66 | T_0F | T_YMM | T_MUST_EVEX | T_EW0 | T_B32 | T_N8 | T_N_VL | T_ER_Y, 0x7B); }");
|
||||
puts("void vcvtps2uqq(const Xmm& x, const Operand& op) { checkCvt1(x, op); opVex(x, 0, op, T_66 | T_0F | T_YMM | T_MUST_EVEX | T_EW0 | T_B32 | T_N8 | T_N_VL | T_ER_Y, 0x79); }");
|
||||
puts("void vcvtqq2ps(const Xmm& x, const Operand& op) { opCvt2(x, op, T_0F | T_YMM | T_MUST_EVEX | T_EW1 | T_B64 | T_ER_Z, 0x5B); }");
|
||||
puts("void vcvttpd2udq(const Xmm& x, const Operand& op) { opCvt2(x, op, T_0F | T_YMM | T_MUST_EVEX | T_EW1 | T_B64 | T_SAE_Z, 0x78); }");
|
||||
puts("void vcvttps2qq(const Xmm& x, const Operand& op) { checkCvt1(x, op); opVex(x, 0, op, T_66 | T_0F | T_YMM | T_MUST_EVEX | T_EW0 | T_B32 | T_N8 | T_N_VL | T_SAE_Y, 0x7A); }");
|
||||
puts("void vcvttps2uqq(const Xmm& x, const Operand& op) { checkCvt1(x, op); opVex(x, 0, op, T_66 | T_0F | T_YMM | T_MUST_EVEX | T_EW0 | T_B32 | T_N8 | T_N_VL | T_SAE_Y, 0x78); }");
|
||||
puts("void vcvtudq2pd(const Xmm& x, const Operand& op) { checkCvt1(x, op); opVex(x, 0, op, T_F3 | T_0F | T_YMM | T_MUST_EVEX | T_EW0 | T_B32 | T_N8 | T_N_VL, 0x7A); }");
|
||||
|
||||
puts("void vcvtsd2usi(const Reg32e& r, const Operand& op) { int type = (T_F2 | T_0F | T_MUST_EVEX | T_N8 | T_ER_X) | (r.isREG(64) ? T_EW1 : T_EW0); opAVX_X_X_XM(Xmm(r.getIdx()), xm0, op, type, 0x79); }");
|
||||
puts("void vcvtss2usi(const Reg32e& r, const Operand& op) { int type = (T_F3 | T_0F | T_MUST_EVEX | T_N4 | T_ER_X) | (r.isREG(64) ? T_EW1 : T_EW0); opAVX_X_X_XM(Xmm(r.getIdx()), xm0, op, type, 0x79); }");
|
||||
puts("void vcvttsd2usi(const Reg32e& r, const Operand& op) { int type = (T_F2 | T_0F | T_MUST_EVEX | T_N8 | T_SAE_X) | (r.isREG(64) ? T_EW1 : T_EW0); opAVX_X_X_XM(Xmm(r.getIdx()), xm0, op, type, 0x78); }");
|
||||
puts("void vcvttss2usi(const Reg32e& r, const Operand& op) { int type = (T_F3 | T_0F | T_MUST_EVEX | T_N4 | T_SAE_X) | (r.isREG(64) ? T_EW1 : T_EW0); opAVX_X_X_XM(Xmm(r.getIdx()), xm0, op, type, 0x78); }");
|
||||
puts("void vcvtuqq2ps(const Xmm& x, const Operand& op) { opCvt2(x, op, T_F2 | T_0F | T_YMM | T_MUST_EVEX | T_EW1 | T_B64 | T_ER_Z, 0x7A); }");
|
||||
puts("void vcvtusi2sd(const Xmm& x1, const Xmm& x2, const Operand& op) { opCvt3(x1, x2, op, T_F2 | T_0F | T_MUST_EVEX, T_W1 | T_EW1 | T_ER_X | T_N8, T_W0 | T_EW0 | T_N4, 0x7B); }");
|
||||
puts("void vcvtusi2ss(const Xmm& x1, const Xmm& x2, const Operand& op) { opCvt3(x1, x2, op, T_F3 | T_0F | T_MUST_EVEX | T_ER_X, T_W1 | T_EW1 | T_N8, T_W0 | T_EW0 | T_N4, 0x7B); }");
|
||||
}
|
||||
|
||||
enum { // same as xbyak.h
|
||||
xx_yy_zz = 0,
|
||||
xx_yx_zy = 1,
|
||||
xx_xy_yz = 2,
|
||||
};
|
||||
void putGather()
|
||||
{
|
||||
const struct Tbl {
|
||||
const char *name;
|
||||
int type;
|
||||
uint8_t code;
|
||||
int mode;
|
||||
} tbl[] = {
|
||||
{ "vpgatherdd", T_66 | T_0F38 | T_YMM | T_MUST_EVEX | T_EW0 | T_N4, 0x90, xx_yy_zz },
|
||||
{ "vpgatherdq", T_66 | T_0F38 | T_YMM | T_MUST_EVEX | T_EW1 | T_N8, 0x90, xx_yx_zy },
|
||||
{ "vpgatherqd", T_66 | T_0F38 | T_YMM | T_MUST_EVEX | T_EW0 | T_N4, 0x91, xx_xy_yz },
|
||||
{ "vpgatherqq", T_66 | T_0F38 | T_YMM | T_MUST_EVEX | T_EW1 | T_N8, 0x91, xx_yy_zz },
|
||||
{ "vgatherdps", T_66 | T_0F38 | T_YMM | T_MUST_EVEX | T_EW0 | T_N4, 0x92, xx_yy_zz },
|
||||
{ "vgatherdpd", T_66 | T_0F38 | T_YMM | T_MUST_EVEX | T_EW1 | T_N8, 0x92, xx_yx_zy },
|
||||
{ "vgatherqps", T_66 | T_0F38 | T_YMM | T_MUST_EVEX | T_EW0 | T_N4, 0x93, xx_xy_yz },
|
||||
{ "vgatherqpd", T_66 | T_0F38 | T_YMM | T_MUST_EVEX | T_EW1 | T_N8, 0x93, xx_yy_zz },
|
||||
};
|
||||
for (size_t i = 0; i < NUM_OF_ARRAY(tbl); i++) {
|
||||
const Tbl& p = tbl[i];
|
||||
std::string type = type2String(p.type | T_VSIB);
|
||||
printf("void %s(const Xmm& x, const Address& addr) { opGather2(x, addr, %s, 0x%02X, %d); }\n", p.name, type.c_str(), p.code, p.mode);
|
||||
}
|
||||
}
|
||||
void putScatter()
|
||||
{
|
||||
const struct Tbl {
|
||||
const char *name;
|
||||
int type;
|
||||
uint8_t code;
|
||||
int mode; // reverse of gather
|
||||
} tbl[] = {
|
||||
{ "vpscatterdd", T_66 | T_0F38 | T_YMM | T_MUST_EVEX | T_EW0 | T_N4 | T_M_K, 0xA0, xx_yy_zz },
|
||||
{ "vpscatterdq", T_66 | T_0F38 | T_YMM | T_MUST_EVEX | T_EW1 | T_N8 | T_M_K, 0xA0, xx_yx_zy },
|
||||
{ "vpscatterqd", T_66 | T_0F38 | T_YMM | T_MUST_EVEX | T_EW0 | T_N4 | T_M_K, 0xA1, xx_xy_yz },
|
||||
{ "vpscatterqq", T_66 | T_0F38 | T_YMM | T_MUST_EVEX | T_EW1 | T_N8 | T_M_K, 0xA1, xx_yy_zz },
|
||||
|
||||
{ "vscatterdps", T_66 | T_0F38 | T_YMM | T_MUST_EVEX | T_EW0 | T_N4 | T_M_K, 0xA2, xx_yy_zz },
|
||||
{ "vscatterdpd", T_66 | T_0F38 | T_YMM | T_MUST_EVEX | T_EW1 | T_N8 | T_M_K, 0xA2, xx_yx_zy },
|
||||
{ "vscatterqps", T_66 | T_0F38 | T_YMM | T_MUST_EVEX | T_EW0 | T_N4 | T_M_K, 0xA3, xx_xy_yz },
|
||||
{ "vscatterqpd", T_66 | T_0F38 | T_YMM | T_MUST_EVEX | T_EW1 | T_N8 | T_M_K, 0xA3, xx_yy_zz },
|
||||
};
|
||||
for (size_t i = 0; i < NUM_OF_ARRAY(tbl); i++) {
|
||||
const Tbl& p = tbl[i];
|
||||
std::string type = type2String(p.type | T_VSIB);
|
||||
printf("void %s(const Address& addr, const Xmm& x) { opGather2(x, addr, %s, 0x%02X, %d); }\n", p.name, type.c_str(), p.code, p.mode);
|
||||
}
|
||||
}
|
||||
|
||||
void putShuff()
|
||||
{
|
||||
puts("void vshuff32x4(const Ymm& y1, const Ymm& y2, const Operand& op, uint8_t imm) { opAVX_X_X_XM(y1, y2, op, T_66 | T_0F3A | T_YMM | T_MUST_EVEX | T_EW0 | T_B32, 0x23, imm); }");
|
||||
puts("void vshuff64x2(const Ymm& y1, const Ymm& y2, const Operand& op, uint8_t imm) { opAVX_X_X_XM(y1, y2, op, T_66 | T_0F3A | T_YMM | T_MUST_EVEX | T_EW1 | T_B64, 0x23, imm); }");
|
||||
puts("void vshufi32x4(const Ymm& y1, const Ymm& y2, const Operand& op, uint8_t imm) { opAVX_X_X_XM(y1, y2, op, T_66 | T_0F3A | T_YMM | T_MUST_EVEX | T_EW0 | T_B32, 0x43, imm); }");
|
||||
puts("void vshufi64x2(const Ymm& y1, const Ymm& y2, const Operand& op, uint8_t imm) { opAVX_X_X_XM(y1, y2, op, T_66 | T_0F3A | T_YMM | T_MUST_EVEX | T_EW1 | T_B64, 0x43, imm); }");
|
||||
}
|
||||
|
||||
void putMov()
|
||||
{
|
||||
puts("void vpmovm2b(const Xmm& x, const Opmask& k) { opVex(x, 0, k, T_F3 | T_0F38 | T_MUST_EVEX | T_YMM | T_EW0, 0x28); }");
|
||||
puts("void vpmovm2w(const Xmm& x, const Opmask& k) { opVex(x, 0, k, T_F3 | T_0F38 | T_MUST_EVEX | T_YMM | T_EW1, 0x28); }");
|
||||
puts("void vpmovm2d(const Xmm& x, const Opmask& k) { opVex(x, 0, k, T_F3 | T_0F38 | T_MUST_EVEX | T_YMM | T_EW0, 0x38); }");
|
||||
puts("void vpmovm2q(const Xmm& x, const Opmask& k) { opVex(x, 0, k, T_F3 | T_0F38 | T_MUST_EVEX | T_YMM | T_EW1, 0x38); }");
|
||||
|
||||
puts("void vpmovb2m(const Opmask& k, const Xmm& x) { opVex(k, 0, x, T_F3 | T_0F38 | T_MUST_EVEX | T_YMM | T_EW0, 0x29); }");
|
||||
puts("void vpmovw2m(const Opmask& k, const Xmm& x) { opVex(k, 0, x, T_F3 | T_0F38 | T_MUST_EVEX | T_YMM | T_EW1, 0x29); }");
|
||||
puts("void vpmovd2m(const Opmask& k, const Xmm& x) { opVex(k, 0, x, T_F3 | T_0F38 | T_MUST_EVEX | T_YMM | T_EW0, 0x39); }");
|
||||
puts("void vpmovq2m(const Opmask& k, const Xmm& x) { opVex(k, 0, x, T_F3 | T_0F38 | T_MUST_EVEX | T_YMM | T_EW1, 0x39); }");
|
||||
|
||||
{
|
||||
const struct Tbl {
|
||||
uint8_t code;
|
||||
const char *name;
|
||||
int type;
|
||||
int mode;
|
||||
} tbl[] = {
|
||||
{ 0x32, "vpmovqb", T_F3 | T_0F38 | T_MUST_EVEX | T_YMM | T_EW0 | T_N2 | T_N_VL, false },
|
||||
{ 0x22, "vpmovsqb", T_F3 | T_0F38 | T_MUST_EVEX | T_YMM | T_EW0 | T_N2 | T_N_VL, false },
|
||||
{ 0x12, "vpmovusqb", T_F3 | T_0F38 | T_MUST_EVEX | T_YMM | T_EW0 | T_N2 | T_N_VL, false },
|
||||
|
||||
{ 0x34, "vpmovqw", T_F3 | T_0F38 | T_MUST_EVEX | T_YMM | T_EW0 | T_N4 | T_N_VL, false },
|
||||
{ 0x24, "vpmovsqw", T_F3 | T_0F38 | T_MUST_EVEX | T_YMM | T_EW0 | T_N4 | T_N_VL, false },
|
||||
{ 0x14, "vpmovusqw", T_F3 | T_0F38 | T_MUST_EVEX | T_YMM | T_EW0 | T_N4 | T_N_VL, false },
|
||||
|
||||
{ 0x35, "vpmovqd", T_F3 | T_0F38 | T_MUST_EVEX | T_YMM | T_EW0 | T_N8 | T_N_VL, true },
|
||||
{ 0x25, "vpmovsqd", T_F3 | T_0F38 | T_MUST_EVEX | T_YMM | T_EW0 | T_N8 | T_N_VL, true },
|
||||
{ 0x15, "vpmovusqd", T_F3 | T_0F38 | T_MUST_EVEX | T_YMM | T_EW0 | T_N8 | T_N_VL, true },
|
||||
|
||||
{ 0x31, "vpmovdb", T_F3 | T_0F38 | T_MUST_EVEX | T_YMM | T_EW0 | T_N4 | T_N_VL, false },
|
||||
{ 0x21, "vpmovsdb", T_F3 | T_0F38 | T_MUST_EVEX | T_YMM | T_EW0 | T_N4 | T_N_VL, false },
|
||||
{ 0x11, "vpmovusdb", T_F3 | T_0F38 | T_MUST_EVEX | T_YMM | T_EW0 | T_N4 | T_N_VL, false },
|
||||
|
||||
{ 0x33, "vpmovdw", T_F3 | T_0F38 | T_MUST_EVEX | T_YMM | T_EW0 | T_N8 | T_N_VL, true },
|
||||
{ 0x23, "vpmovsdw", T_F3 | T_0F38 | T_MUST_EVEX | T_YMM | T_EW0 | T_N8 | T_N_VL, true },
|
||||
{ 0x13, "vpmovusdw", T_F3 | T_0F38 | T_MUST_EVEX | T_YMM | T_EW0 | T_N8 | T_N_VL, true },
|
||||
|
||||
{ 0x30, "vpmovwb", T_F3 | T_0F38 | T_MUST_EVEX | T_YMM | T_EW0 | T_N8 | T_N_VL, true },
|
||||
{ 0x20, "vpmovswb", T_F3 | T_0F38 | T_MUST_EVEX | T_YMM | T_EW0 | T_N8 | T_N_VL, true },
|
||||
{ 0x10, "vpmovuswb", T_F3 | T_0F38 | T_MUST_EVEX | T_YMM | T_EW0 | T_N8 | T_N_VL, true },
|
||||
};
|
||||
for (size_t i = 0; i < NUM_OF_ARRAY(tbl); i++) {
|
||||
const Tbl& p = tbl[i];
|
||||
std::string type = type2String(p.type);
|
||||
printf("void %s(const Operand& op, const Xmm& x) { opVmov(op, x, %s, 0x%02X, %s); }\n", p.name, type.c_str(), p.code, p.mode ? "true" : "false");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void putX_XM_IMM()
|
||||
{
|
||||
const struct Tbl {
|
||||
uint8_t code;
|
||||
const char *name;
|
||||
int type;
|
||||
bool hasIMM;
|
||||
} tbl[] = {
|
||||
{ 0x26, "vgetmantpd", T_66 | T_0F3A | T_YMM | T_MUST_EVEX | T_EW1 | T_B64 | T_SAE_Z, true },
|
||||
{ 0x26, "vgetmantps", T_66 | T_0F3A | T_YMM | T_MUST_EVEX | T_EW0 | T_B32 | T_SAE_Z, true },
|
||||
{ 0x4C, "vrcp14pd", T_66 | T_0F38 | T_YMM | T_MUST_EVEX | T_EW1 | T_B64, false },
|
||||
{ 0x4C, "vrcp14ps", T_66 | T_0F38 | T_YMM | T_MUST_EVEX | T_EW0 | T_B32, false },
|
||||
|
||||
{ 0x4E, "vrsqrt14pd", T_66 | T_0F38 | T_YMM | T_MUST_EVEX | T_EW1 | T_B64, false },
|
||||
{ 0x4E, "vrsqrt14ps", T_66 | T_0F38 | T_YMM | T_MUST_EVEX | T_EW0 | T_B32, false },
|
||||
|
||||
{ 0x09, "vrndscalepd", T_66 | T_0F3A | T_YMM | T_MUST_EVEX | T_EW1 | T_B64, true },
|
||||
{ 0x08, "vrndscaleps", T_66 | T_0F3A | T_YMM | T_MUST_EVEX | T_EW0 | T_B32, true },
|
||||
|
||||
{ 0xC4, "vpconflictd", T_66 | T_0F38 | T_YMM | T_MUST_EVEX | T_EW0 | T_B32, false },
|
||||
{ 0xC4, "vpconflictq", T_66 | T_0F38 | T_YMM | T_MUST_EVEX | T_EW1 | T_B64, false },
|
||||
|
||||
{ 0x44, "vplzcntd", T_66 | T_0F38 | T_YMM | T_MUST_EVEX | T_EW0 | T_B32, false },
|
||||
{ 0x44, "vplzcntq", T_66 | T_0F38 | T_YMM | T_MUST_EVEX | T_EW1 | T_B64, false },
|
||||
|
||||
{ 0x56, "vreducepd", T_66 | T_0F3A | T_YMM | T_MUST_EVEX | T_EW1 | T_B64 | T_SAE_Z, true },
|
||||
{ 0x56, "vreduceps", T_66 | T_0F3A | T_YMM | T_MUST_EVEX | T_EW0 | T_B32 | T_SAE_Z, true },
|
||||
|
||||
{ 0x54, "vpopcntb", T_66 | T_0F38 | T_YMM | T_MUST_EVEX | T_EW0 | T_SAE_Z, false },
|
||||
{ 0x54, "vpopcntw", T_66 | T_0F38 | T_YMM | T_MUST_EVEX | T_EW1 | T_SAE_Z, false },
|
||||
{ 0x55, "vpopcntd", T_66 | T_0F38 | T_YMM | T_MUST_EVEX | T_EW0 | T_SAE_Z | T_B32, false },
|
||||
{ 0x55, "vpopcntq", T_66 | T_0F38 | T_YMM | T_MUST_EVEX | T_EW1 | T_SAE_Z | T_B64, false },
|
||||
|
||||
{ 0x62, "vpexpandb", T_66 | T_0F38 | T_YMM | T_MUST_EVEX | T_EW0 | T_SAE_Z | T_N1, false },
|
||||
{ 0x62, "vpexpandw", T_66 | T_0F38 | T_YMM | T_MUST_EVEX | T_EW1 | T_SAE_Z | T_N2, false },
|
||||
};
|
||||
for (size_t i = 0; i < NUM_OF_ARRAY(tbl); i++) {
|
||||
const Tbl *p = &tbl[i];
|
||||
std::string type = type2String(p->type);
|
||||
printf("void %s(const Xmm& x, const Operand& op%s) { opAVX_X_XM_IMM(x, op, %s, 0x%02X%s); }\n"
|
||||
, p->name, p->hasIMM ? ", uint8_t imm" : "", type.c_str(), p->code, p->hasIMM ? ", imm" : "");
|
||||
}
|
||||
}
|
||||
|
||||
void putMisc()
|
||||
{
|
||||
puts("void vpbroadcastmb2q(const Xmm& x, const Opmask& k) { opVex(x, 0, k, T_F3 | T_0F38 | T_YMM | T_MUST_EVEX | T_EW1, 0x2A); }");
|
||||
puts("void vpbroadcastmw2d(const Xmm& x, const Opmask& k) { opVex(x, 0, k, T_F3 | T_0F38 | T_YMM | T_MUST_EVEX | T_EW0, 0x3A); }");
|
||||
{
|
||||
const struct Tbl {
|
||||
const char *name;
|
||||
int zm;
|
||||
int type;
|
||||
uint8_t code;
|
||||
bool isZmm;
|
||||
} tbl[] = {
|
||||
{ "vgatherpf0dps", 1, T_EW0 | T_N4, 0xC6, true },
|
||||
{ "vgatherpf0qps", 1, T_EW0 | T_N4, 0xC7, true },
|
||||
{ "vgatherpf0dpd", 1, T_EW1 | T_N8, 0xC6, false },
|
||||
{ "vgatherpf0qpd", 1, T_EW1 | T_N8, 0xC7, true },
|
||||
|
||||
{ "vgatherpf1dps", 2, T_EW0 | T_N4, 0xC6, true },
|
||||
{ "vgatherpf1qps", 2, T_EW0 | T_N4, 0xC7, true },
|
||||
{ "vgatherpf1dpd", 2, T_EW1 | T_N8, 0xC6, false },
|
||||
{ "vgatherpf1qpd", 2, T_EW1 | T_N8, 0xC7, true },
|
||||
|
||||
{ "vscatterpf0dps", 5, T_EW0 | T_N4, 0xC6, true },
|
||||
{ "vscatterpf0qps", 5, T_EW0 | T_N4, 0xC7, true },
|
||||
{ "vscatterpf0dpd", 5, T_EW1 | T_N8, 0xC6, false },
|
||||
{ "vscatterpf0qpd", 5, T_EW1 | T_N8, 0xC7, true },
|
||||
|
||||
{ "vscatterpf1dps", 6, T_EW0 | T_N4, 0xC6, true },
|
||||
{ "vscatterpf1qps", 6, T_EW0 | T_N4, 0xC7, true },
|
||||
{ "vscatterpf1dpd", 6, T_EW1 | T_N8, 0xC6, false },
|
||||
{ "vscatterpf1qpd", 6, T_EW1 | T_N8, 0xC7, true },
|
||||
};
|
||||
for (size_t i = 0; i < NUM_OF_ARRAY(tbl); i++) {
|
||||
const Tbl& p = tbl[i];
|
||||
std::string type = type2String(p.type | T_66 | T_0F38 | T_MUST_EVEX | T_M_K | T_VSIB);
|
||||
printf("void %s(const Address& addr) { opGatherFetch(addr, zm%d, %s, 0x%2X, Operand::%s); }\n"
|
||||
, p.name, p.zm, type.c_str(), p.code, p.isZmm ? "ZMM" : "YMM");
|
||||
}
|
||||
}
|
||||
|
||||
puts("void vfpclasspd(const Opmask& k, const Operand& op, uint8_t imm) { if (!op.isBit(128|256|512)) XBYAK_THROW(ERR_BAD_MEM_SIZE) opVex(k.changeBit(op.getBit()), 0, op, T_66 | T_0F3A | T_MUST_EVEX | T_YMM | T_EW1 | T_B64, 0x66, imm); }");
|
||||
puts("void vfpclassps(const Opmask& k, const Operand& op, uint8_t imm) { if (!op.isBit(128|256|512)) XBYAK_THROW(ERR_BAD_MEM_SIZE) opVex(k.changeBit(op.getBit()), 0, op, T_66 | T_0F3A | T_MUST_EVEX | T_YMM | T_EW0 | T_B32, 0x66, imm); }");
|
||||
puts("void vfpclasssd(const Opmask& k, const Operand& op, uint8_t imm) { if (!op.isXMEM()) XBYAK_THROW(ERR_BAD_MEM_SIZE) opVex(k, 0, op, T_66 | T_0F3A | T_MUST_EVEX | T_EW1 | T_N8, 0x67, imm); }");
|
||||
puts("void vfpclassss(const Opmask& k, const Operand& op, uint8_t imm) { if (!op.isXMEM()) XBYAK_THROW(ERR_BAD_MEM_SIZE) opVex(k, 0, op, T_66 | T_0F3A | T_MUST_EVEX | T_EW0 | T_N4, 0x67, imm); }");
|
||||
|
||||
puts("void vpshufbitqmb(const Opmask& k, const Xmm& x, const Operand& op) { opVex(k, &x, op, T_66 | T_0F38 | T_EW0 | T_YMM | T_MUST_EVEX, 0x8F); }");
|
||||
puts("void vcvtneps2bf16(const Xmm& x, const Operand& op) { opCvt2(x, op, T_F3 | T_0F38 | T_EW0 | T_YMM | T_SAE_Z | T_MUST_EVEX | T_B32, 0x72); }");
|
||||
|
||||
puts("void vp2intersectd(const Opmask& k, const Xmm& x, const Operand& op) { if (k.getOpmaskIdx() != 0) XBYAK_THROW(ERR_OPMASK_IS_ALREADY_SET) opAVX_K_X_XM(k, x, op, T_F2 | T_0F38 | T_YMM | T_EVEX | T_EW0 | T_B32, 0x68); }");
|
||||
puts("void vp2intersectq(const Opmask& k, const Xmm& x, const Operand& op) { if (k.getOpmaskIdx() != 0) XBYAK_THROW(ERR_OPMASK_IS_ALREADY_SET) opAVX_K_X_XM(k, x, op, T_F2 | T_0F38 | T_YMM | T_EVEX | T_EW1 | T_B64, 0x68); }");
|
||||
}
|
||||
|
||||
void putV4FMA()
|
||||
{
|
||||
puts("void v4fmaddps(const Zmm& z1, const Zmm& z2, const Address& addr) { opAVX_X_X_XM(z1, z2, addr, T_0F38 | T_F2 | T_EW0 | T_YMM | T_MUST_EVEX | T_N16, 0x9A); }");
|
||||
puts("void v4fnmaddps(const Zmm& z1, const Zmm& z2, const Address& addr) { opAVX_X_X_XM(z1, z2, addr, T_0F38 | T_F2 | T_EW0 | T_YMM | T_MUST_EVEX | T_N16, 0xAA); }");
|
||||
puts("void v4fmaddss(const Xmm& x1, const Xmm& x2, const Address& addr) { opAVX_X_X_XM(x1, x2, addr, T_0F38 | T_F2 | T_EW0 | T_MUST_EVEX | T_N16, 0x9B); }");
|
||||
puts("void v4fnmaddss(const Xmm& x1, const Xmm& x2, const Address& addr) { opAVX_X_X_XM(x1, x2, addr, T_0F38 | T_F2 | T_EW0 | T_MUST_EVEX | T_N16, 0xAB); }");
|
||||
puts("void vp4dpwssd(const Zmm& z1, const Zmm& z2, const Address& addr) { opAVX_X_X_XM(z1, z2, addr, T_0F38 | T_F2 | T_EW0 | T_YMM | T_MUST_EVEX | T_N16, 0x52); }");
|
||||
puts("void vp4dpwssds(const Zmm& z1, const Zmm& z2, const Address& addr) { opAVX_X_X_XM(z1, z2, addr, T_0F38 | T_F2 | T_EW0 | T_YMM | T_MUST_EVEX | T_N16, 0x53); }");
|
||||
}
|
||||
|
||||
int main(int argc, char *[])
|
||||
{
|
||||
bool only64bit = argc == 2;
|
||||
putOpmask(only64bit);
|
||||
putBroadcast(only64bit);
|
||||
if (only64bit) {
|
||||
return 0;
|
||||
}
|
||||
putVcmp();
|
||||
putX_XM();
|
||||
putM_X();
|
||||
putXM_X();
|
||||
putX_X_XM_IMM();
|
||||
putShift();
|
||||
putExtractInsert();
|
||||
putCvt();
|
||||
putGather();
|
||||
putShuff();
|
||||
putMov();
|
||||
putX_XM_IMM();
|
||||
putMisc();
|
||||
putScatter();
|
||||
putV4FMA();
|
||||
}
|
||||
File diff suppressed because it is too large.
Load diff
@@ -1,23 +0,0 @@
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <string>
|
||||
#include <set>
|
||||
|
||||
typedef std::set<std::string> StrSet;
|
||||
|
||||
int main()
|
||||
{
|
||||
StrSet ss;
|
||||
std::string line;
|
||||
while (std::getline(std::cin, line)) {
|
||||
if (!line.empty() && line[line.size() - 1] == '\n') {
|
||||
line.resize(line.size() - 1);
|
||||
}
|
||||
if (!line.empty()) {
|
||||
ss.insert(line);
|
||||
}
|
||||
}
|
||||
for (StrSet::const_iterator i = ss.begin(), ie = ss.end(); i != ie; ++i) {
|
||||
std::cout << *i << std::endl;
|
||||
}
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
@echo off
|
||||
set OPT=/EHsc -I../ /W4 -D_CRT_SECURE_NO_WARNINGS
|
||||
set TARGET=..\\xbyak\\xbyak_mnemonic.h
|
||||
set SORT=sortline
|
||||
cl gen_code.cpp %OPT%
|
||||
gen_code | %SORT% > %TARGET%
|
||||
echo #ifdef XBYAK_ENABLE_OMITTED_OPERAND>> %TARGET%
|
||||
gen_code omit | %SORT% >> %TARGET%
|
||||
echo #endif>>%TARGET%
|
||||
gen_code fixed >> %TARGET%
|
||||
cl gen_avx512.cpp %OPT%
|
||||
echo #ifndef XBYAK_DISABLE_AVX512>> %TARGET%
|
||||
gen_avx512 | %SORT% >> %TARGET%
|
||||
echo #ifdef XBYAK64>> %TARGET%
|
||||
gen_avx512 64 | %SORT% >> %TARGET%
|
||||
echo #endif>> %TARGET%
|
||||
echo #endif>> %TARGET%
|
||||
@@ -1,617 +0,0 @@
|
||||
[](https://github.com/herumi/xbyak/actions/workflows/main.yml)
|
||||
|
||||
# Xbyak 5.992 ; JIT assembler for x86(IA32), x64(AMD64, x86-64) by C++
|
||||
|
||||
## Abstract
|
||||
|
||||
Xbyak is a C++ header library that enables dynamically to assemble x86(IA32), x64(AMD64, x86-64) mnemonic.
|
||||
|
||||
The pronunciation of Xbyak is `kəi-bja-k`.
|
||||
It is named from a Japanese word [開闢](https://translate.google.com/?hl=ja&sl=ja&tl=en&text=%E9%96%8B%E9%97%A2&op=translate), which means the beginning of the world.
|
||||
|
||||
## Feature
|
||||
* header file only
|
||||
* Intel/MASM like syntax
|
||||
* fully support AVX-512
|
||||
|
||||
**Note**:
|
||||
Use `and_()`, `or_()`, ... instead of `and()`, `or()`.
|
||||
If you want to use them, then specify `-fno-operator-names` option to gcc/clang.
|
||||
|
||||
### News
|
||||
- vnni instructions such as vpdpbusd supports vex encoding.
|
||||
- (break backward compatibility) `push(byte, imm)` (resp. `push(word, imm)`) forces to cast `imm` to 8(resp. 16) bit.
|
||||
- (Windows) `#include <winsock2.h>` has been removed from xbyak.h, so add it explicitly if you need it.
|
||||
- support exception-less mode see. [Exception-less mode](#exception-less-mode)
|
||||
- `XBYAK_USE_MMAP_ALLOCATOR` will be defined on Linux/macOS unless `XBYAK_DONT_USE_MMAP_ALLOCATOR` is defined.
|
||||
|
||||
### Supported OS
|
||||
|
||||
* Windows Xp, Vista, Windows 7, Windows 10(32bit, 64bit)
|
||||
* Linux(32bit, 64bit)
|
||||
* Intel macOS
|
||||
|
||||
### Supported Compilers
|
||||
|
||||
Almost C++03 or later compilers for x86/x64 such as Visual Studio, g++, clang++, Intel C++ compiler and g++ on mingw/cygwin.
|
||||
|
||||
## Install
|
||||
|
||||
The following files are necessary. Please add the path to your compile directory.
|
||||
|
||||
* xbyak.h
|
||||
* xbyak_mnemonic.h
|
||||
* xbyak_util.h
|
||||
|
||||
Linux:
|
||||
```
|
||||
make install
|
||||
```
|
||||
|
||||
These files are copied into `/usr/local/include/xbyak`.
|
||||
|
||||
## How to use it
|
||||
|
||||
Inherit `Xbyak::CodeGenerator` class and make the class method.
|
||||
```
|
||||
#include <xbyak/xbyak.h>
|
||||
|
||||
struct Code : Xbyak::CodeGenerator {
|
||||
Code(int x)
|
||||
{
|
||||
mov(eax, x);
|
||||
ret();
|
||||
}
|
||||
};
|
||||
```
|
||||
Or you can pass the instance of CodeGenerator without inheriting.
|
||||
```
|
||||
void genCode(Xbyak::CodeGenerator& code, int x) {
|
||||
using namespace Xbyak::util;
|
||||
code.mov(eax, x);
|
||||
code.ret();
|
||||
}
|
||||
```
|
||||
|
||||
Make an instance of the class and get the function
|
||||
pointer by calling `getCode()` and call it.
|
||||
```
|
||||
Code c(5);
|
||||
int (*f)() = c.getCode<int (*)()>();
|
||||
printf("ret=%d\n", f()); // ret = 5
|
||||
```
|
||||
|
||||
## Syntax
|
||||
Similar to MASM/NASM syntax with parentheses.
|
||||
|
||||
```
|
||||
NASM Xbyak
|
||||
mov eax, ebx --> mov(eax, ebx);
|
||||
inc ecx inc(ecx);
|
||||
ret --> ret();
|
||||
```
|
||||
|
||||
## Addressing
|
||||
Use `qword`, `dword`, `word` and `byte` if it is necessary to specify the size of memory,
|
||||
otherwise use `ptr`.
|
||||
|
||||
```
|
||||
(ptr|qword|dword|word|byte) [base + index * (1|2|4|8) + displacement]
|
||||
[rip + 32bit disp] ; x64 only
|
||||
|
||||
NASM Xbyak
|
||||
mov eax, [ebx+ecx] --> mov(eax, ptr [ebx+ecx]);
|
||||
mov al, [ebx+ecx] --> mov(al, ptr [ebx + ecx]);
|
||||
test byte [esp], 4 --> test(byte [esp], 4);
|
||||
inc qword [rax] --> inc(qword [rax]);
|
||||
```
|
||||
**Note**: `qword`, ... are member variables, then don't use `dword` as unsigned int type.
|
||||
|
||||
### How to use Selector (Segment Register)
|
||||
```
|
||||
mov eax, [fs:eax] --> putSeg(fs);
|
||||
mov(eax, ptr [eax]);
|
||||
mov ax, cs --> mov(ax, cs);
|
||||
```
|
||||
**Note**: Segment class is not derived from `Operand`.
|
||||
|
||||
## AVX
|
||||
|
||||
```
|
||||
vaddps(xmm1, xmm2, xmm3); // xmm1 <- xmm2 + xmm3
|
||||
vaddps(xmm2, xmm3, ptr [rax]); // use ptr to access memory
|
||||
vgatherdpd(xmm1, ptr [ebp + 256 + xmm2*4], xmm3);
|
||||
```
|
||||
|
||||
**Note**:
|
||||
If `XBYAK_ENABLE_OMITTED_OPERAND` is defined, then you can use two operand version for backward compatibility.
|
||||
But the newer version will not support it.
|
||||
```
|
||||
vaddps(xmm2, xmm3); // xmm2 <- xmm2 + xmm3
|
||||
```
|
||||
|
||||
## AVX-512
|
||||
|
||||
```
|
||||
vaddpd zmm2, zmm5, zmm30 --> vaddpd(zmm2, zmm5, zmm30);
|
||||
vaddpd xmm30, xmm20, [rax] --> vaddpd(xmm30, xmm20, ptr [rax]);
|
||||
vaddps xmm30, xmm20, [rax] --> vaddps(xmm30, xmm20, ptr [rax]);
|
||||
vaddpd zmm2{k5}, zmm4, zmm2 --> vaddpd(zmm2 | k5, zmm4, zmm2);
|
||||
vaddpd zmm2{k5}{z}, zmm4, zmm2 --> vaddpd(zmm2 | k5 | T_z, zmm4, zmm2);
|
||||
vaddpd zmm2{k5}{z}, zmm4, zmm2,{rd-sae} --> vaddpd(zmm2 | k5 | T_z, zmm4, zmm2 | T_rd_sae);
|
||||
vaddpd(zmm2 | k5 | T_z | T_rd_sae, zmm4, zmm2); // the position of `|` is arbitrary.
|
||||
vcmppd k4{k3}, zmm1, zmm2, {sae}, 5 --> vcmppd(k4 | k3, zmm1, zmm2 | T_sae, 5);
|
||||
|
||||
vaddpd xmm1, xmm2, [rax+256] --> vaddpd(xmm1, xmm2, ptr [rax+256]);
|
||||
vaddpd xmm1, xmm2, [rax+256]{1to2} --> vaddpd(xmm1, xmm2, ptr_b [rax+256]);
|
||||
vaddpd ymm1, ymm2, [rax+256]{1to4} --> vaddpd(ymm1, ymm2, ptr_b [rax+256]);
|
||||
vaddpd zmm1, zmm2, [rax+256]{1to8} --> vaddpd(zmm1, zmm2, ptr_b [rax+256]);
|
||||
vaddps zmm1, zmm2, [rax+rcx*8+8]{1to16} --> vaddps(zmm1, zmm2, ptr_b [rax+rcx*8+8]);
|
||||
vmovsd [rax]{k1}, xmm4 --> vmovsd(ptr [rax] | k1, xmm4);
|
||||
|
||||
vcvtpd2dq xmm16, oword [eax+33] --> vcvtpd2dq(xmm16, xword [eax+33]); // use xword for m128 instead of oword
|
||||
vcvtpd2dq(xmm16, ptr [eax+33]); // default xword
|
||||
vcvtpd2dq xmm21, [eax+32]{1to2} --> vcvtpd2dq(xmm21, ptr_b [eax+32]);
|
||||
vcvtpd2dq xmm0, yword [eax+33] --> vcvtpd2dq(xmm0, yword [eax+33]); // use yword for m256
|
||||
vcvtpd2dq xmm19, [eax+32]{1to4} --> vcvtpd2dq(xmm19, yword_b [eax+32]); // use yword_b to broadcast
|
||||
|
||||
vfpclassps k5{k3}, zword [rax+64], 5 --> vfpclassps(k5|k3, zword [rax+64], 5); // specify m512
|
||||
vfpclasspd k5{k3}, [rax+64]{1to2}, 5 --> vfpclasspd(k5|k3, xword_b [rax+64], 5); // broadcast 64-bit to 128-bit
|
||||
vfpclassps k5{k3}, [rax+64]{1to4}, 5 --> vfpclassps(k5|k3, yword_b [rax+64], 5); // broadcast 64-bit to 256-bit
|
||||
|
||||
vpdpbusd(xm0, xm1, xm2); // default encoding is EVEX
|
||||
vpdpbusd(xm0, xm1, xm2, EvexEncoding); // same as the above
|
||||
vpdpbusd(xm0, xm1, xm2, VexEncoding); // VEX encoding
|
||||
```
|
||||
### Remark
|
||||
* `k1`, ..., `k7` are opmask registers.
|
||||
- `k0` is dealt as no mask.
|
||||
- e.g. `vmovaps(zmm0|k0, ptr[rax]);` and `vmovaps(zmm0|T_z, ptr[rax]);` are same to `vmovaps(zmm0, ptr[rax]);`.
|
||||
* use `| T_z`, `| T_sae`, `| T_rn_sae`, `| T_rd_sae`, `| T_ru_sae`, `| T_rz_sae` instead of `,{z}`, `,{sae}`, `,{rn-sae}`, `,{rd-sae}`, `,{ru-sae}`, `,{rz-sae}` respectively.
|
||||
* `k4 | k3` is different from `k3 | k4`.
|
||||
* use `ptr_b` for broadcast `{1toX}`. X is automatically determined.
|
||||
* specify `xword`/`yword`/`zword(_b)` for m128/m256/m512 if necessary.
|
||||
|
||||
## Label
|
||||
Two kinds of Label are supported. (String literal and Label class).
|
||||
|
||||
### String literal
|
||||
```
|
||||
L("L1");
|
||||
jmp("L1");
|
||||
|
||||
jmp("L2");
|
||||
...
|
||||
a few mnemonics (8-bit displacement jmp)
|
||||
...
|
||||
L("L2");
|
||||
|
||||
jmp("L3", T_NEAR);
|
||||
...
|
||||
a lot of mnemonics (32-bit displacement jmp)
|
||||
...
|
||||
L("L3");
|
||||
```
|
||||
|
||||
* Call `hasUndefinedLabel()` to verify your code has no undefined label.
|
||||
* you can use a label for immediate value of mov like as `mov(eax, "L2")`.
|
||||
|
||||
### Support `@@`, `@f`, `@b` like MASM
|
||||
|
||||
```
|
||||
L("@@"); // <A>
|
||||
jmp("@b"); // jmp to <A>
|
||||
jmp("@f"); // jmp to <B>
|
||||
L("@@"); // <B>
|
||||
jmp("@b"); // jmp to <B>
|
||||
mov(eax, "@b");
|
||||
jmp(eax); // jmp to <B>
|
||||
```
|
||||
|
||||
### Local label
|
||||
|
||||
Label symbols beginning with a period between `inLocalLabel()` and `outLocalLabel()`
|
||||
are treated as a local label.
|
||||
`inLocalLabel()` and `outLocalLabel()` can be nested.
|
||||
|
||||
```
|
||||
void func1()
|
||||
{
|
||||
inLocalLabel();
|
||||
L(".lp"); // <A> ; local label
|
||||
...
|
||||
jmp(".lp"); // jmp to <A>
|
||||
L("aaa"); // global label <C>
|
||||
outLocalLabel();
|
||||
|
||||
inLocalLabel();
|
||||
L(".lp"); // <B> ; local label
|
||||
func1();
|
||||
jmp(".lp"); // jmp to <B>
|
||||
inLocalLabel();
|
||||
jmp("aaa"); // jmp to <C>
|
||||
}
|
||||
```
|
||||
|
||||
### short and long jump
|
||||
Xbyak deals with jump mnemonics of an undefined label as short jump if no type is specified.
|
||||
So if the size between jmp and label is larger than 127 byte, then xbyak will cause an error.
|
||||
|
||||
```
|
||||
jmp("short-jmp"); // short jmp
|
||||
// small code
|
||||
L("short-jmp");
|
||||
|
||||
jmp("long-jmp");
|
||||
// long code
|
||||
L("long-jmp"); // throw exception
|
||||
```
|
||||
Then specify T_NEAR for jmp.
|
||||
```
|
||||
jmp("long-jmp", T_NEAR); // long jmp
|
||||
// long code
|
||||
L("long-jmp");
|
||||
```
|
||||
Or call `setDefaultJmpNEAR(true);` once, then the default type is set to T_NEAR.
|
||||
```
|
||||
jmp("long-jmp"); // long jmp
|
||||
// long code
|
||||
L("long-jmp");
|
||||
```
|
||||
|
||||
### Label class
|
||||
|
||||
`L()` and `jxx()` support Label class.
|
||||
|
||||
```
|
||||
Xbyak::Label label1, label2;
|
||||
L(label1);
|
||||
...
|
||||
jmp(label1);
|
||||
...
|
||||
jmp(label2);
|
||||
...
|
||||
L(label2);
|
||||
```
|
||||
|
||||
Use `putL` for jmp table
|
||||
```
|
||||
Label labelTbl, L0, L1, L2;
|
||||
mov(rax, labelTbl);
|
||||
// rdx is an index of jump table
|
||||
jmp(ptr [rax + rdx * sizeof(void*)]);
|
||||
L(labelTbl);
|
||||
putL(L0);
|
||||
putL(L1);
|
||||
putL(L2);
|
||||
L(L0);
|
||||
....
|
||||
L(L1);
|
||||
....
|
||||
```
|
||||
|
||||
`assignL(dstLabel, srcLabel)` binds dstLabel with srcLabel.
|
||||
|
||||
```
|
||||
Label label2;
|
||||
Label label1 = L(); // make label1 ; same to Label label1; L(label1);
|
||||
...
|
||||
jmp(label2); // label2 is not determined here
|
||||
...
|
||||
assignL(label2, label1); // label2 <- label1
|
||||
```
|
||||
The `jmp` in the above code jumps to label1 assigned by `assignL`.
|
||||
|
||||
**Note**:
|
||||
* srcLabel must be used in `L()`.
|
||||
* dstLabel must not be used in `L()`.
|
||||
|
||||
`Label::getAddress()` returns the address specified by the label instance and 0 if not specified.
|
||||
```
|
||||
// not AutoGrow mode
|
||||
Label label;
|
||||
assert(label.getAddress() == 0);
|
||||
L(label);
|
||||
assert(label.getAddress() == getCurr());
|
||||
```
|
||||
|
||||
### Rip ; relative addressing
|
||||
```
|
||||
Label label;
|
||||
mov(eax, ptr [rip + label]); // eax = 4
|
||||
...
|
||||
|
||||
L(label);
|
||||
dd(4);
|
||||
```
|
||||
```
|
||||
int x;
|
||||
...
|
||||
mov(eax, ptr[rip + &x]); // throw exception if the difference between &x and current position is larger than 2GiB
|
||||
```
|
||||
|
||||
## Code size
|
||||
The default max code size is 4096 bytes.
|
||||
Specify the size in constructor of `CodeGenerator()` if necessary.
|
||||
|
||||
```
|
||||
class Quantize : public Xbyak::CodeGenerator {
|
||||
public:
|
||||
Quantize()
|
||||
: CodeGenerator(8192)
|
||||
{
|
||||
}
|
||||
...
|
||||
};
|
||||
```
|
||||
|
||||
## User allocated memory
|
||||
|
||||
You can make jit code on prepared memory.
|
||||
|
||||
Call `setProtectModeRE` yourself to change memory mode if using the prepared memory.
|
||||
|
||||
```
|
||||
uint8_t alignas(4096) buf[8192]; // C++11 or later
|
||||
|
||||
struct Code : Xbyak::CodeGenerator {
|
||||
Code() : Xbyak::CodeGenerator(sizeof(buf), buf)
|
||||
{
|
||||
mov(rax, 123);
|
||||
ret();
|
||||
}
|
||||
};
|
||||
|
||||
int main()
|
||||
{
|
||||
Code c;
|
||||
c.setProtectModeRE(); // set memory to Read/Exec
|
||||
printf("%d\n", c.getCode<int(*)()>()());
|
||||
}
|
||||
```
|
||||
|
||||
**Note**: See [sample/test0.cpp](sample/test0.cpp).
|
||||
|
||||
### AutoGrow
|
||||
|
||||
The memory region for jit is automatically extended if necessary when `AutoGrow` is specified in a constructor of `CodeGenerator`.
|
||||
|
||||
Call `ready()` or `readyRE()` before calling `getCode()` to fix jump address.
|
||||
```
|
||||
struct Code : Xbyak::CodeGenerator {
|
||||
Code()
|
||||
: Xbyak::CodeGenerator(<default memory size>, Xbyak::AutoGrow)
|
||||
{
|
||||
...
|
||||
}
|
||||
};
|
||||
Code c;
|
||||
// generate code for jit
|
||||
c.ready(); // mode = Read/Write/Exec
|
||||
```
|
||||
|
||||
**Note**:
|
||||
* Don't use the address returned by `getCurr()` before calling `ready()` because it may be invalid address.
|
||||
|
||||
### Read/Exec mode
|
||||
Xbyak set Read/Write/Exec mode to memory to run jit code.
|
||||
If you want to use Read/Exec mode for security, then specify `DontSetProtectRWE` for `CodeGenerator` and
|
||||
call `setProtectModeRE()` after generating jit code.
|
||||
|
||||
```
|
||||
struct Code : Xbyak::CodeGenerator {
|
||||
Code()
|
||||
: Xbyak::CodeGenerator(4096, Xbyak::DontSetProtectRWE)
|
||||
{
|
||||
mov(eax, 123);
|
||||
ret();
|
||||
}
|
||||
};
|
||||
|
||||
Code c;
|
||||
c.setProtectModeRE();
|
||||
...
|
||||
|
||||
```
|
||||
Call `readyRE()` instead of `ready()` when using `AutoGrow` mode.
|
||||
See [protect-re.cpp](sample/protect-re.cpp).
|
||||
|
||||
## Exception-less mode
|
||||
If `XBYAK_NO_EXCEPTION` is defined, then gcc/clang can compile xbyak with `-fno-exceptions`.
|
||||
In stead of throwing an exception, `Xbyak::GetError()` returns non-zero value (e.g. `ERR_BAD_ADDRESSING`) if there is something wrong.
|
||||
The status will not be changed automatically, then you should reset it by `Xbyak::ClearError()`.
|
||||
`CodeGenerator::reset()` calls `ClearError()`.
|
||||
|
||||
## Macro
|
||||
|
||||
* **XBYAK32** is defined on 32bit.
|
||||
* **XBYAK64** is defined on 64bit.
|
||||
* **XBYAK64_WIN** is defined on 64bit Windows(VC).
|
||||
* **XBYAK64_GCC** is defined on 64bit gcc, cygwin.
|
||||
* define **XBYAK_USE_OP_NAMES** on gcc with `-fno-operator-names` if you want to use `and()`, ....
|
||||
* define **XBYAK_ENABLE_OMITTED_OPERAND** if you use omitted destination such as `vaddps(xmm2, xmm3);`(deprecated in the future).
|
||||
* define **XBYAK_UNDEF_JNL** if Bessel function jnl is defined as macro.
|
||||
* define **XBYAK_NO_EXCEPTION** for a compiler option `-fno-exceptions`.
|
||||
|
||||
## Sample
|
||||
|
||||
* [test0.cpp](sample/test0.cpp) ; tiny sample (x86, x64)
|
||||
* [quantize.cpp](sample/quantize.cpp) ; JIT optimized quantization by fast division (x86 only)
|
||||
* [calc.cpp](sample/calc.cpp) ; assemble and estimate a given polynomial (x86, x64)
|
||||
* [bf.cpp](sample/bf.cpp) ; JIT brainfuck (x86, x64)
|
||||
|
||||
## License
|
||||
|
||||
modified new BSD License
|
||||
http://opensource.org/licenses/BSD-3-Clause
|
||||
|
||||
## History
|
||||
* 2021/May/09 ver 5.992 support endbr32 and endbr64
|
||||
* 2020/Nov/16 ver 5.991 disable constexpr for gcc-5 with -std=c++-14
|
||||
* 2020/Oct/19 ver 5.99 support VNNI instructions(Thanks to akharito)
|
||||
* 2020/Oct/17 ver 5.98 support the form of [scale * reg]
|
||||
* 2020/Sep/08 ver 5.97 replace uint32 with uint32_t etc.
|
||||
* 2020/Aug/28 ver 5.95 some constructors of register classes support constexpr if C++14 or later
|
||||
* 2020/Aug/04 ver 5.941 `CodeGenerator::reset()` calls `ClearError()`.
|
||||
* 2020/Jul/28 ver 5.94 remove #include <winsock2.h> (only windows)
|
||||
* 2020/Jul/21 ver 5.93 support exception-less mode
|
||||
* 2020/Jun/30 ver 5.92 support Intel AMX instruction set (Thanks to nshustrov)
|
||||
* 2020/Jun/22 ver 5.913 fix mov(r64, imm64) on 32-bit env with XBYAK64
|
||||
* 2020/Jun/19 ver 5.912 define MAP_JIT on macOS regardless of Xcode version (Thanks to rsdubtso)
|
||||
* 2020/May/10 ver 5.911 XBYAK_USE_MMAP_ALLOCATOR is defined unless XBYAK_DONT_USE_MMAP_ALLOCATOR is defined.
|
||||
* 2020/Apr/20 ver 5.91 accept mask register k0 (it means no mask)
|
||||
* 2020/Apr/09 ver 5.90 kmov{b,d,w,q} throws exception for an unsupported register
|
||||
* 2020/Feb/26 ver 5.891 fix typo of type
|
||||
* 2020/Jan/03 ver 5.89 fix error of vfpclasspd
|
||||
* 2019/Dec/20 ver 5.88 fix compile error on Windows
|
||||
* 2019/Dec/19 ver 5.87 add setDefaultJmpNEAR(), which deals with `jmp` of an undefined label as T_NEAR if no type is specified.
|
||||
* 2019/Dec/13 ver 5.86 [changed] revert to the behavior before v5.84 if -fno-operator-names is defined (and() is available)
|
||||
* 2019/Dec/07 ver 5.85 append MAP_JIT flag to mmap for macOS mojave or later
|
||||
* 2019/Nov/29 ver 5.84 [changed] XBYAK_NO_OP_NAMES is defined unless XBYAK_USE_OP_NAMES is defined
|
||||
* 2019/Oct/12 ver 5.83 exit(1) was removed
|
||||
* 2019/Sep/23 ver 5.82 support monitorx, mwaitx, clzero (thanks to @MagurosanTeam)
|
||||
* 2019/Sep/14 ver 5.81 support some generic mnemonics.
|
||||
* 2019/Aug/01 ver 5.802 fix detection of AVX512_BF16 (thanks to vpirogov)
|
||||
* 2019/May/27 support vp2intersectd, vp2intersectq (not tested)
|
||||
* 2019/May/26 ver 5.80 support vcvtne2ps2bf16, vcvtneps2bf16, vdpbf16ps
|
||||
* 2019/Apr/27 ver 5.79 vcmppd/vcmpps supports ptr_b(thanks to jkopinsky)
|
||||
* 2019/Apr/15 ver 5.78 rewrite Reg::changeBit() (thanks to MerryMage)
|
||||
* 2019/Mar/06 ver 5.77 fix number of cores that share LLC cache by densamoilov
|
||||
* 2019/Jan/17 ver 5.76 add Cpu::getNumCores() by shelleygoel
|
||||
* 2018/Oct/31 ver 5.751 recover Xbyak::CastTo for compatibility
|
||||
* 2018/Oct/29 ver 5.75 unlink LabelManager from Label when msg is destroyed
|
||||
* 2018/Oct/21 ver 5.74 support RegRip +/- int. Xbyak::CastTo is removed
|
||||
* 2018/Oct/15 util::AddressFrame uses push/pop instead of mov
|
||||
* 2018/Sep/19 ver 5.73 fix evex encoding of vpslld, vpslldq, vpsllw, etc for (reg, mem, imm8)
|
||||
* 2018/Sep/19 ver 5.72 fix the encoding of vinsertps for disp8N(Thanks to petercaday)
|
||||
* 2018/Sep/04 ver 5.71 L() returns a new label instance
|
||||
* 2018/Aug/27 ver 5.70 support setProtectMode() and DontUseProtect for read/exec setting
|
||||
* 2018/Aug/24 ver 5.68 fix wrong VSIB encoding with vector index >= 16(thanks to petercaday)
|
||||
* 2018/Aug/14 ver 5.67 remove mutable in Address ; fix setCacheHierarchy for cloud vm
|
||||
* 2018/Jul/26 ver 5.661 support mingw64
|
||||
* 2018/Jul/24 ver 5.66 add CodeArray::PROTECT_RE to mode of protect()
|
||||
* 2018/Jun/26 ver 5.65 fix push(qword [mem])
|
||||
* 2018/Mar/07 ver 5.64 fix zero division in Cpu() on some cpu
|
||||
* 2018/Feb/14 ver 5.63 fix Cpu::setCacheHierarchy() and fix EvexModifierZero for clang<3.9(thanks to mgouicem)
|
||||
* 2018/Feb/13 ver 5.62 Cpu::setCacheHierarchy() by mgouicem and rsdubtso
|
||||
* 2018/Feb/07 ver 5.61 vmov* supports mem{k}{z}(I forgot it)
|
||||
* 2018/Jan/24 ver 5.601 add xword, yword, etc. into Xbyak::util namespace
|
||||
* 2018/Jan/05 ver 5.60 support AVX-512 for Ice lake(319433-030.pdf)
|
||||
* 2017/Aug/22 ver 5.53 fix mpx encoding, add bnd() prefix
|
||||
* 2017/Aug/18 ver 5.52 fix align (thanks to MerryMage)
|
||||
* 2017/Aug/17 ver 5.51 add multi-byte nop and align() uses it(thanks to inolen)
|
||||
* 2017/Aug/08 ver 5.50 add mpx(thanks to magurosan)
|
||||
* 2017/Aug/08 ver 5.45 add sha(thanks to magurosan)
|
||||
* 2017/Aug/08 ver 5.44 add prefetchw(thanks to rsdubtso)
|
||||
* 2017/Jul/12 ver 5.432 reduce warnings of PVS studio
|
||||
* 2017/Jul/09 ver 5.431 fix hasRex() (no affect) (thanks to drillsar)
|
||||
* 2017/May/14 ver 5.43 fix CodeGenerator::resetSize() (thanks to gibbed)
|
||||
* 2017/May/13 ver 5.42 add movs{b,w,d,q}
|
||||
* 2017/Jan/26 ver 5.41 add prefetchwt1 and support for scale == 0(thanks to rsdubtso)
|
||||
* 2016/Dec/14 ver 5.40 add Label::getAddress() method to get the pointer specified by the label
|
||||
* 2016/Dec/09 ver 5.34 fix handling of negative offsets when encoding disp8N(thanks to rsdubtso)
|
||||
* 2016/Dec/08 ver 5.33 fix encoding of vpbroadcast{b,w,d,q}, vpinsr{b,w}, vpextr{b,w} for disp8N
|
||||
* 2016/Dec/01 ver 5.32 rename __xgetbv() to _xgetbv() to support clang for Visual Studio(thanks to freiro)
|
||||
* 2016/Nov/27 ver 5.31 rename AVX512_4VNNI to AVX512_4VNNIW
|
||||
* 2016/Nov/27 ver 5.30 add AVX512_4VNNI, AVX512_4FMAPS instructions(thanks to rsdubtso)
|
||||
* 2016/Nov/26 ver 5.20 add detection of AVX512_4VNNI and AVX512_4FMAPS(thanks to rsdubtso)
|
||||
* 2016/Nov/20 ver 5.11 lost vptest for ymm(thanks to gregory38)
|
||||
* 2016/Nov/20 ver 5.10 add addressing [rip+&var]
|
||||
* 2016/Sep/29 ver 5.03 fix detection ERR_INVALID_OPMASK_WITH_MEMORY(thanks to PVS-Studio)
|
||||
* 2016/Aug/15 ver 5.02 xbyak does not include xbyak_bin2hex.h
|
||||
* 2016/Aug/15 ver 5.011 fix detection of version of gcc 5.4
|
||||
* 2016/Aug/03 ver 5.01 disable omitted operand
|
||||
* 2016/Jun/24 ver 5.00 support avx-512 instruction set
|
||||
* 2016/Jun/13 avx-512 add mask instructions
|
||||
* 2016/May/05 ver 4.91 add detection of AVX-512 to Xbyak::util::Cpu
|
||||
* 2016/Mar/14 ver 4.901 comment to ready() function(thanks to skmp)
|
||||
* 2016/Feb/04 ver 4.90 add jcc(const void *addr);
|
||||
* 2016/Jan/30 ver 4.89 vpblendvb supports ymm reg(thanks to John Funnell)
|
||||
* 2016/Jan/24 ver 4.88 lea, cmov supports 16-bit register(thanks to whyisthisfieldhere)
|
||||
* 2015/Oct/05 ver 4.87 support segment selectors
|
||||
* 2015/Aug/18 ver 4.86 fix [rip + label] addressing with immediate value(thanks to whyisthisfieldhere)
|
||||
* 2015/Aug/10 ver 4.85 Address::operator==() is not correct(thanks to inolen)
|
||||
* 2015/Jun/22 ver 4.84 call() support variadic template if available(thanks to randomstuff)
|
||||
* 2015/Jun/16 ver 4.83 support movbe(thanks to benvanik)
|
||||
* 2015/May/24 ver 4.82 support detection of F16C
|
||||
* 2015/Apr/25 ver 4.81 fix the condition to throw exception for setSize(thanks to whyisthisfieldhere)
|
||||
* 2015/Apr/22 ver 4.80 rip supports label(thanks to whyisthisfieldhere)
|
||||
* 2015/Jar/28 ver 4.71 support adcx, adox, cmpxchg, rdseed, stac
|
||||
* 2014/Oct/14 ver 4.70 support MmapAllocator
|
||||
* 2014/Jun/13 ver 4.62 disable warning of VC2014
|
||||
* 2014/May/30 ver 4.61 support bt, bts, btr, btc
|
||||
* 2014/May/28 ver 4.60 support vcvtph2ps, vcvtps2ph
|
||||
* 2014/Apr/11 ver 4.52 add detection of rdrand
|
||||
* 2014/Mar/25 ver 4.51 remove state information of unreferenced labels
|
||||
* 2014/Mar/16 ver 4.50 support new Label
|
||||
* 2014/Mar/05 ver 4.40 fix wrong detection of BMI/enhanced rep on VirtualBox
|
||||
* 2013/Dec/03 ver 4.30 support Reg::cvt8(), cvt16(), cvt32(), cvt64()
|
||||
* 2013/Oct/16 ver 4.21 label support std::string
|
||||
* 2013/Jul/30 ver 4.20 [break backward compatibility] split Reg32e class into RegExp(base+index*scale+disp) and Reg32e(means Reg32 or Reg64)
|
||||
* 2013/Jul/04 ver 4.10 [break backward compatibility] change the type of Xbyak::Error from enum to a class
|
||||
* 2013/Jun/21 ver 4.02 add putL(LABEL) function to put the address of the label
|
||||
* 2013/Jun/21 ver 4.01 vpsllw, vpslld, vpsllq, vpsraw, vpsrad, vpsrlw, vpsrld, vpsrlq support (ymm, ymm, xmm). support vpbroadcastb, vpbroadcastw, vpbroadcastd, vpbroadcastq(thanks to Gabest).
|
||||
* 2013/May/30 ver 4.00 support AVX2, VEX-encoded GPR-instructions
|
||||
* 2013/Mar/27 ver 3.80 support mov(reg, "label");
|
||||
* 2013/Mar/13 ver 3.76 add cqo(), jcxz(), jecxz(), jrcxz()
|
||||
* 2013/Jan/15 ver 3.75 add setSize() to modify generated code
|
||||
* 2013/Jan/12 ver 3.74 add CodeGenerator::reset() ; add Allocator::useProtect()
|
||||
* 2013/Jan/06 ver 3.73 use unordered_map if possible
|
||||
* 2012/Dec/04 ver 3.72 eax, ebx, ... are member variables of CodeGenerator(revert), Xbyak::util::eax, ... are static const.
|
||||
* 2012/Nov/17 ver 3.71 and_(), or_(), xor_(), not_() are available if XBYAK_NO_OP_NAMES is not defined.
|
||||
* 2012/Nov/17 change eax, ebx, ptr and so on in CodeGenerator as static member and alias of them are defined in Xbyak::util.
|
||||
* 2012/Nov/09 ver 3.70 XBYAK_NO_OP_NAMES macro is added to use and_() instead of and() (thanks to Mattias)
|
||||
* 2012/Nov/01 ver 3.62 add fwait/fnwait/finit/fninit
|
||||
* 2012/Nov/01 ver 3.61 add fldcw/fstcw
|
||||
* 2012/May/03 ver 3.60 change interface of Allocator
|
||||
* 2012/Mar/23 ver 3.51 fix userPtr mode
|
||||
* 2012/Mar/19 ver 3.50 support AutoGrow mode
|
||||
* 2011/Nov/09 ver 3.05 fix bit property of rip addresing / support movsxd
|
||||
* 2011/Aug/15 ver 3.04 fix dealing with imm8 such as add(dword [ebp-8], 0xda); (thanks to lolcat)
|
||||
* 2011/Jun/16 ver 3.03 fix __GNUC_PREREQ macro for Mac gcc(thanks to t_teruya)
|
||||
* 2011/Apr/28 ver 3.02 do not use xgetbv on Mac gcc
|
||||
* 2011/May/24 ver 3.01 fix typo of OSXSAVE
|
||||
* 2011/May/23 ver 3.00 add vcmpeqps and so on
|
||||
* 2011/Feb/16 ver 2.994 beta add vmovq for 32-bit mode(I forgot it)
|
||||
* 2011/Feb/16 ver 2.993 beta remove cvtReg to avoid thread unsafe
|
||||
* 2011/Feb/10 ver 2.992 beta support one argument syntax for fadd like nasm
|
||||
* 2011/Feb/07 ver 2.991 beta fix pextrw reg, xmm, imm(Thanks to Gabest)
|
||||
* 2011/Feb/04 ver 2.99 beta support AVX
|
||||
* 2010/Dec/08 ver 2.31 fix ptr [rip + 32bit offset], support rdtscp
|
||||
* 2010/Oct/19 ver 2.30 support pclmulqdq, aesdec, aesdeclast, aesenc, aesenclast, aesimc, aeskeygenassist
|
||||
* 2010/Jun/07 ver 2.29 fix call(<label>)
|
||||
* 2010/Jun/17 ver 2.28 move some member functions to public
|
||||
* 2010/Jun/01 ver 2.27 support encoding of mov(reg64, imm) like yasm(not nasm)
|
||||
* 2010/May/24 ver 2.26 fix sub(rsp, 1000)
|
||||
* 2010/Apr/26 ver 2.25 add jc/jnc(I forgot to implement them...)
|
||||
* 2010/Apr/16 ver 2.24 change the prototype of rewrite() method
|
||||
* 2010/Apr/15 ver 2.23 fix align() and xbyak_util.h for Mac
|
||||
* 2010/Feb/16 ver 2.22 fix inLocalLabel()/outLocalLabel()
|
||||
* 2009/Dec/09 ver 2.21 support cygwin(gcc 4.3.2)
|
||||
* 2009/Nov/28 support a part of FPU
|
||||
* 2009/Jun/25 fix mov(qword[rax], imm); (thanks to Martin)
|
||||
* 2009/Mar/10 fix redundant REX.W prefix on jmp/call reg64
|
||||
* 2009/Feb/24 add movq reg64, mmx/xmm; movq mmx/xmm, reg64
|
||||
* 2009/Feb/13 movd(xmm7, dword[eax]) drops 0x66 prefix (thanks to Gabest)
|
||||
* 2008/Dec/30 fix call in short relative address(thanks to kato san)
|
||||
* 2008/Sep/18 support @@, @f, @b and localization of label(thanks to nobu-q san)
|
||||
* 2008/Sep/18 support (ptr[rip + 32bit offset]) (thanks to Dango-Chu san)
|
||||
* 2008/Jun/03 fix align(). mov(ptr[eax],1) throws ERR_MEM_SIZE_IS_NOT_SPECIFIED.
|
||||
* 2008/Jun/02 support memory interface allocated by user
|
||||
* 2008/May/26 fix protect() to avoid invalid setting(thanks to shinichiro_h san)
|
||||
* 2008/Apr/30 add cmpxchg16b, cdqe
|
||||
* 2008/Apr/29 support x64
|
||||
* 2008/Apr/14 code refactoring
|
||||
* 2008/Mar/12 add bsr/bsf
|
||||
* 2008/Feb/14 fix output of sub eax, 1234 (thanks to Robert)
|
||||
* 2007/Nov/5 support lock, xadd, xchg
|
||||
* 2007/Nov/2 support SSSE3/SSE4 (thanks to Dango-Chu san)
|
||||
* 2007/Feb/4 fix the bug that exception doesn't occur under the condition which the offset of jmp mnemonic without T_NEAR is over 127.
|
||||
* 2007/Jan/21 fix the bug to create address like [disp] select smaller representation for mov (eax|ax|al, [disp])
|
||||
* 2007/Jan/4 first version
|
||||
|
||||
## Author
|
||||
MITSUNARI Shigeo(herumi@nifty.com)
|
||||
|
||||
## Sponsors welcome
|
||||
[GitHub Sponsor](https://github.com/sponsors/herumi)
|
||||
@@ -1,560 +0,0 @@
|
||||
|
||||
C++用x86(IA-32), x64(AMD64, x86-64) JITアセンブラ Xbyak 5.992
|
||||
|
||||
-----------------------------------------------------------------------------
|
||||
◎概要
|
||||
|
||||
これはx86, x64(AMD64, x86-64)のマシン語命令を生成するC++のクラスライブラリです。
|
||||
プログラム実行時に動的にアセンブルすることが可能です。
|
||||
|
||||
-----------------------------------------------------------------------------
|
||||
◎特徴
|
||||
|
||||
・ヘッダファイルオンリー
|
||||
xbyak.hをインクルードするだけですぐ利用することができます。
|
||||
C++の枠組み内で閉じているため、外部アセンブラは不要です。
|
||||
32bit/64bit両対応です。
|
||||
対応ニーモニック:特権命令除くx86, MMX/MMX2/SSE/SSE2/SSE3/SSSE3/SSE4/FPU(一部)/AVX/AVX2/FMA/VEX-encoded GPR
|
||||
|
||||
・Windows Xp(32bit, 64bit), Windows 7/Linux(32bit, 64bit)/Intel Mac対応
|
||||
Windows Xp, Windows 7上ではVC2008, VC2010, VC2012
|
||||
Linux (kernel 3.8)上ではgcc 4.7.3, clang 3.3
|
||||
Intel Mac
|
||||
などで動作確認をしています。
|
||||
|
||||
※ and, orなどの代わりにand_, or_を使用してください。
|
||||
and, orなどを使いたい場合は-fno-operator-namesをgcc/clangに指定してください。
|
||||
|
||||
-----------------------------------------------------------------------------
|
||||
◎準備
|
||||
xbyak.h
|
||||
xbyak_bin2hex.h
|
||||
これらを同一のパスに入れてインクルードパスに追加してください。
|
||||
|
||||
Linuxではmake installで/usr/local/include/xbyakにコピーされます。
|
||||
-----------------------------------------------------------------------------
|
||||
◎下位互換性の破れ
|
||||
* push byte, immまたはpush word, immが下位8bit, 16bitにキャストした値を使うように変更。
|
||||
* (Windows) `<winsock2.h>`をincludeしなくなったので必要なら明示的にincludeしてください。
|
||||
* XBYAK_USE_MMAP_ALLOCATORがデフォルトで有効になりました。従来の方式にする場合はXBYAK_DONT_USE_MMAP_ALLOCATORを定義してください。
|
||||
* Xbyak::Errorの型をenumからclassに変更
|
||||
** 従来のenumの値をとるにはintにキャストしてください。
|
||||
* (古い)Reg32eクラスを(新しい)Reg32eとRegExpに分ける。
|
||||
** (新しい)Reg32eはReg32かReg64
|
||||
** (新しい)RegExpは'Reg32e + (Reg32e|Xmm|Ymm) * scale + disp'の型
|
||||
|
||||
-----------------------------------------------------------------------------
|
||||
◎新機能
|
||||
|
||||
例外なしモード追加
|
||||
XBYAK_NO_EXCEPTIONを定義してコンパイルするとgcc/clangで-fno-exceptionsオプションでコンパイルできます。
|
||||
エラーは例外の代わりに`Xbyak::GetError()`で通達されます。
|
||||
この値が0でなければ何か問題が発生しています。
|
||||
この値は自動的に変更されないので`Xbyak::ClearError()`でリセットしてください。
|
||||
`CodeGenerator::reset()`は`ClearError()`を呼びます。
|
||||
|
||||
MmapAllocator追加
|
||||
これはUnix系OSでのみの仕様です。XBYAK_USE_MMAP_ALLOCATORを使うと利用できます。
|
||||
デフォルトのAllocatorはメモリ確保時にposix_memalignを使います。
|
||||
この領域に対するmprotectはmap countを減らします。
|
||||
map countの最大値は/proc/sys/vm/max_map_countに書かれています。
|
||||
デフォルトでは3万個ほどのXbyak::CodeGeneratorインスタンスを生成するとエラーになります。
|
||||
test/mprotect_test.cppで確認できます。
|
||||
これを避けるためにはmmapを使うMmapAllocatorを使ってください。
|
||||
|
||||
|
||||
AutoGrowモード追加
|
||||
これはメモリ伸長を動的に行うモードです。
|
||||
今まではXbyak::CodeGenerator()に渡したメモリサイズを超えると例外が発生して
|
||||
いましたが、このモードでは内部でメモリを再確保して伸長します。
|
||||
ただし、getCode()を呼び出す前にジャンプ命令のアドレス解決をするためにready()
|
||||
関数を呼ぶ必要があります。
|
||||
|
||||
次のように使います。
|
||||
|
||||
struct Code : Xbyak::CodeGenerator {
|
||||
Code()
|
||||
: Xbyak::CodeGenerator(<default memory size>, Xbyak::AutoGrow)
|
||||
{
|
||||
...
|
||||
}
|
||||
};
|
||||
Code c;
|
||||
c.ready(); // この呼び出しを忘れてはいけない
|
||||
|
||||
注意1. ready()を呼んで確定するまではgetCurr()で得たポインタは無効化されている
|
||||
可能性があります。getSize()でoffsetを保持しておきready()のあとにgetCode()を
|
||||
呼び出してからgetCode() + offsetで新しいポインタを取得してください。
|
||||
|
||||
注意2. AutoGrowモードでは64bitモードの相対アドレッシング[rip]は非サポートです。
|
||||
|
||||
-----------------------------------------------------------------------------
|
||||
◎文法
|
||||
|
||||
Xbyak::CodeGeneratorクラスを継承し、そのクラスメソッド内でx86, x64アセンブラを
|
||||
記述します。そのメソッドを呼び出した後、getCode()メソッドを呼び出し、その戻
|
||||
り値を自分が使いたい関数ポインタに変換して利用します。アセンブルエラーは例外
|
||||
により通知されます(cf. main.cpp)。
|
||||
|
||||
・基本的にnasmの命令で括弧をつければよいです。
|
||||
|
||||
mov eax, ebx --> mov(eax, ebx);
|
||||
inc ecx inc(ecx);
|
||||
ret --> ret();
|
||||
|
||||
・アドレッシング
|
||||
|
||||
(ptr|dword|word|byte) [base + index * (1|2|4|8) + displacement]
|
||||
[rip + 32bit disp] ; x64 only
|
||||
という形で指定します。サイズを指定する必要がない限りptrを使えばよいです。
|
||||
|
||||
セレクター(セグメントレジスタ)をサポートしました。
|
||||
(注意)セグメントレジスタはOperandを継承していません。
|
||||
|
||||
mov eax, [fs:eax] --> putSeg(fs); mov(eax, ptr [eax]);
|
||||
mov ax, cs --> mov(ax, cs);
|
||||
|
||||
mov eax, [ebx+ecx] --> mov (eax, ptr[ebx+ecx]);
|
||||
test byte [esp], 4 --> test (byte [esp], 4);
|
||||
|
||||
(注意) dword, word, byteはメンバ変数です。従ってたとえばunsigned intの
|
||||
つもりでdwordをtypedefしないでください。
|
||||
|
||||
・AVX
|
||||
|
||||
FMAについては簡略表記を導入するか検討中です(アイデア募集中)。
|
||||
|
||||
vaddps(xmm1, xmm2, xmm3); // xmm1 <- xmm2 + xmm3
|
||||
vaddps(xmm2, xmm3, ptr [rax]); // メモリアクセスはptrで
|
||||
|
||||
vfmadd231pd(xmm1, xmm2, xmm3); // xmm1 <- (xmm2 * xmm3) + xmm1
|
||||
|
||||
*注意*
|
||||
デスティネーションの省略形はサポートされなくなりました。
|
||||
|
||||
vaddps(xmm2, xmm3); // xmm2 <- xmm2 + xmm3
|
||||
|
||||
XBYAK_ENABLE_OMITTED_OPERANDを定義すると使えますが、将来はそれも非サポートになるでしょう。
|
||||
|
||||
・AVX-512
|
||||
|
||||
vaddpd zmm2, zmm5, zmm30 --> vaddpd(zmm2, zmm5, zmm30);
|
||||
vaddpd xmm30, xmm20, [rax] --> vaddpd(xmm30, xmm20, ptr [rax]);
|
||||
vaddps xmm30, xmm20, [rax] --> vaddps(xmm30, xmm20, ptr [rax]);
|
||||
vaddpd zmm2{k5}, zmm4, zmm2 --> vaddpd(zmm2 | k5, zmm4, zmm2);
|
||||
vaddpd zmm2{k5}{z}, zmm4, zmm2 --> vaddpd(zmm2 | k5 | T_z, zmm4, zmm2);
|
||||
vaddpd zmm2{k5}{z}, zmm4, zmm2,{rd-sae} --> vaddpd(zmm2 | k5 | T_z, zmm4, zmm2 | T_rd_sae);
|
||||
vaddpd(zmm2 | k5 | T_z | T_rd_sae, zmm4, zmm2); // the position of `|` is arbitrary.
|
||||
vcmppd k4{k3}, zmm1, zmm2, {sae}, 5 --> vcmppd(k4 | k3, zmm1, zmm2 | T_sae, 5);
|
||||
|
||||
vaddpd xmm1, xmm2, [rax+256]{1to2} --> vaddpd(xmm1, xmm2, ptr_b [rax+256]);
|
||||
vaddpd ymm1, ymm2, [rax+256]{1to4} --> vaddpd(ymm1, ymm2, ptr_b [rax+256]);
|
||||
vaddpd zmm1, zmm2, [rax+256]{1to8} --> vaddpd(zmm1, zmm2, ptr_b [rax+256]);
|
||||
vaddps zmm1, zmm2, [rax+rcx*8+8]{1to16} --> vaddps(zmm1, zmm2, ptr_b [rax+rcx*8+8]);
|
||||
vmovsd [rax]{k1}, xmm4 --> vmovsd(ptr [rax] | k1, xmm4);
|
||||
|
||||
vcvtpd2dq xmm16, oword [eax+33] --> vcvtpd2dq(xmm16, xword [eax+33]); // use xword for m128 instead of oword
|
||||
vcvtpd2dq(xmm16, ptr [eax+33]); // default xword
|
||||
vcvtpd2dq xmm21, [eax+32]{1to2} --> vcvtpd2dq(xmm21, ptr_b [eax+32]);
|
||||
vcvtpd2dq xmm0, yword [eax+33] --> vcvtpd2dq(xmm0, yword [eax+33]); // use yword for m256
|
||||
vcvtpd2dq xmm19, [eax+32]{1to4} --> vcvtpd2dq(xmm19, yword_b [eax+32]); // use yword_b to broadcast
|
||||
|
||||
vfpclassps k5{k3}, zword [rax+64], 5 --> vfpclassps(k5|k3, zword [rax+64], 5); // specify m512
|
||||
vfpclasspd k5{k3}, [rax+64]{1to2}, 5 --> vfpclasspd(k5|k3, xword_b [rax+64], 5); // broadcast 64-bit to 128-bit
|
||||
vfpclassps k5{k3}, [rax+64]{1to4}, 5 --> vfpclassps(k5|k3, xword_b [rax+64], 5); // broadcast 64-bit to 256-bit
|
||||
|
||||
vpdpbusd(xm0, xm1, xm2); // default encoding is EVEX
|
||||
vpdpbusd(xm0, xm1, xm2, EvexEncoding); // same as the above
|
||||
vpdpbusd(xm0, xm1, xm2, VexEncoding); // VEX encoding
|
||||
|
||||
注意
|
||||
* k1, ..., k7 は新しいopmaskレジスタです。
|
||||
* z, sae, rn-sae, rd-sae, ru-sae, rz-saeの代わりにT_z, T_sae, T_rn_sae, T_rd_sae, T_ru_sae, T_rz_saeを使ってください。
|
||||
* `k4 | k3`と`k3 | k4`は意味が異なります。
|
||||
* {1toX}の代わりにptr_bを使ってください。Xは自動的に決まります。
|
||||
* 一部の命令はメモリサイズを指定するためにxword/yword/zword(_b)を使ってください。
|
||||
|
||||
・ラベル
|
||||
|
||||
L(文字列);
|
||||
で定義します。ジャンプするときはその文字列を指定します。後方参照も可能ですが、
|
||||
相対アドレスが8ビットに収まらない場合はT_NEARをつけないと実行時に例外が発生
|
||||
します。
|
||||
mov(eax, "L2");の様にラベルが表すアドレスをmovの即値として使えます。
|
||||
|
||||
・hasUndefinedLabel()を呼び出して真ならジャンプ先が存在しないことを示します。
|
||||
コードを見直してください。
|
||||
|
||||
L("L1");
|
||||
jmp ("L1");
|
||||
|
||||
jmp ("L2");
|
||||
...
|
||||
少しの命令の場合。
|
||||
...
|
||||
L("L2");
|
||||
|
||||
jmp ("L3", T_NEAR);
|
||||
...
|
||||
沢山の命令がある場合
|
||||
...
|
||||
L("L3");
|
||||
|
||||
<応用編>
|
||||
|
||||
1. MASMライクな@@, @f, @bをサポート
|
||||
|
||||
L("@@"); // <A>
|
||||
jmp("@b"); // jmp to <A>
|
||||
jmp("@f"); // jmp to <B>
|
||||
L("@@"); // <B>
|
||||
jmp("@b"); // jmp to <B>
|
||||
mov(eax, "@b");
|
||||
jmp(eax); // jmp to <B>
|
||||
|
||||
2. ラベルの局所化
|
||||
|
||||
ピリオドで始まるラベルをinLocalLabel(), outLocalLabel()で挟むことで局所化できます。
|
||||
inLocalLabel(), outLocalLabel()は入れ子にすることができます。
|
||||
|
||||
void func1()
|
||||
{
|
||||
inLocalLabel();
|
||||
L(".lp"); // <A> ; ローカルラベル
|
||||
...
|
||||
jmp(".lp"); // jmpt to <A>
|
||||
L("aaa"); // グローバルラベル
|
||||
outLocalLabel();
|
||||
}
|
||||
|
||||
void func2()
|
||||
{
|
||||
inLocalLabel();
|
||||
L(".lp"); // <B> ; ローカルラベル
|
||||
func1();
|
||||
jmp(".lp"); // jmp to <B>
|
||||
outLocalLabel();
|
||||
}
|
||||
|
||||
上記サンプルではinLocalLabel(), outLocalLabel()が無いと、
|
||||
".lp"ラベルの二重定義エラーになります。
|
||||
|
||||
3. 新しいLabelクラスによるジャンプ命令
|
||||
|
||||
ジャンプ先を文字列による指定だけでなくラベルクラスを使えるようになりました。
|
||||
|
||||
Label label1, label2;
|
||||
L(label1);
|
||||
...
|
||||
jmp(label1);
|
||||
...
|
||||
jmp(label2);
|
||||
...
|
||||
L(label2);
|
||||
|
||||
更にラベルの割り当てを行うassignL(dstLabel, srcLabel)という命令も追加されました。
|
||||
|
||||
Label label2;
|
||||
Label label1 = L(); // Label label1; L(label1);と同じ意味
|
||||
...
|
||||
jmp(label2);
|
||||
...
|
||||
assignL(label2, label1);
|
||||
|
||||
上記jmp命令はlabel1にジャンプします。
|
||||
|
||||
制限
|
||||
* srcLabelはL()により飛び先が確定していないといけません。
|
||||
* dstLabelはL()により飛び先が確定していてはいけません。
|
||||
|
||||
ラベルは`getAddress()`によりそのアドレスを取得できます。
|
||||
未定義のときは0が返ります。
|
||||
```
|
||||
// not AutoGrow mode
|
||||
Label label;
|
||||
assert(label.getAddress(), 0);
|
||||
L(label);
|
||||
assert(label.getAddress(), getCurr());
|
||||
```
|
||||
|
||||
・Xbyak::CodeGenerator()コンストラクタインタフェース
|
||||
|
||||
@param maxSize [in] コード生成最大サイズ(デフォルト4096byte)
|
||||
@param userPtr [in] ユーザ指定メモリ
|
||||
|
||||
CodeGenerator(size_t maxSize = DEFAULT_MAX_CODE_SIZE, void *userPtr = 0);
|
||||
|
||||
デフォルトコードサイズは4096(=DEFAULT_MAX_CODE_SIZE)バイトです。
|
||||
それより大きなコードを生成する場合はCodeGenerator()のコンストラクタに指定してください。
|
||||
|
||||
class Quantize : public Xbyak::CodeGenerator {
|
||||
public:
|
||||
Quantize()
|
||||
: CodeGenerator(8192)
|
||||
{
|
||||
}
|
||||
...
|
||||
};
|
||||
|
||||
またユーザ指定メモリをコード生成最大サイズと共に指定すると、CodeGeneratorは
|
||||
指定されたメモリ上にバイト列を生成します。
|
||||
|
||||
補助関数として指定されたアドレスの実行属性を変更するCodeArray::protect()と
|
||||
与えられたポインタからアライメントされたポインタを取得するCodeArray::getAlignedAddress()
|
||||
も用意しました。詳細はsample/test0.cppのuse memory allocated by userを参考に
|
||||
してください。
|
||||
|
||||
/**
|
||||
change exec permission of memory
|
||||
@param addr [in] buffer address
|
||||
@param size [in] buffer size
|
||||
@param canExec [in] true(enable to exec), false(disable to exec)
|
||||
@return true(success), false(failure)
|
||||
*/
|
||||
bool CodeArray::protect(const void *addr, size_t size, bool canExec);
|
||||
|
||||
/**
|
||||
get aligned memory pointer
|
||||
*/
|
||||
uint8 *CodeArray::getAlignedAddress(uint8 *addr, size_t alignedSize = ALIGN_SIZE);
|
||||
|
||||
・read/execモード
|
||||
デフォルトのCodeGeneratorはコンストラクト時にJIT用の領域をread/write/execモードに設定して利用します。
|
||||
コード生成時はread/writeでコード実行時にはread/execにしたい場合、次のようにしてください。
|
||||
|
||||
struct Code : Xbyak::CodeGenerator {
|
||||
Code()
|
||||
: Xbyak::CodeGenerator(4096, Xbyak::DontUseProtect) // JIT領域をread/writeのままコード生成
|
||||
{
|
||||
mov(eax, 123);
|
||||
ret();
|
||||
}
|
||||
};
|
||||
|
||||
Code c;
|
||||
c.setProtectModeRE(); // read/execモードに変更
|
||||
// JIT領域を実行
|
||||
|
||||
AutoGrowの場合はreadyの代わりにreadyRE()を読んでください。
|
||||
|
||||
struct Code : Xbyak::CodeGenerator {
|
||||
Code()
|
||||
: Xbyak::CodeGenerator(4096, Xbyak::AutoGrow) // JIT領域をread/writeのままコード生成
|
||||
{
|
||||
mov(eax, 123);
|
||||
ret();
|
||||
}
|
||||
};
|
||||
|
||||
Code c;
|
||||
c.readyRE(); // read/exeモードに変更
|
||||
// JIT領域を実行
|
||||
|
||||
setProtectModeRW()を呼ぶと領域が元のread/execモードに戻ります。
|
||||
|
||||
|
||||
その他詳細は各種サンプルを参照してください。
|
||||
-----------------------------------------------------------------------------
|
||||
◎マクロ
|
||||
|
||||
32bit環境上でコンパイルするとXBYAK32が、64bit環境上でコンパイルするとXBYAK64が
|
||||
定義されます。さらに64bit環境上ではWindows(VC)ならXBYAK64_WIN、cygwin, gcc上では
|
||||
XBYAK64_GCCが定義されます。
|
||||
|
||||
-----------------------------------------------------------------------------
|
||||
◎使用例
|
||||
|
||||
test0.cpp ; 簡単な例(x86, x64)
|
||||
quantize.cpp ; 割り算のJITアセンブルによる量子化の高速化(x86)
|
||||
calc.cpp ; 与えられた多項式をアセンブルして実行(x86, x64)
|
||||
boost(http://www.boost.org/)が必要
|
||||
bf.cpp ; JIT Brainfuck(x86, x64)
|
||||
|
||||
-----------------------------------------------------------------------------
|
||||
◎ライセンス
|
||||
|
||||
修正された新しいBSDライセンスに従います。
|
||||
http://opensource.org/licenses/BSD-3-Clause
|
||||
|
||||
sample/{echo,hello}.bfは http://www.kmonos.net/alang/etc/brainfuck.php から
|
||||
いただきました。
|
||||
|
||||
-----------------------------------------------------------------------------
|
||||
◎履歴
|
||||
|
||||
2021/05/09 ver 5.992 endbr32とendbr64のサポート
|
||||
2020/11/16 ver 5.991 g++-5のC++14でconstexpr機能の抑制
|
||||
2020/10/19 ver 5.99 VNNI命令サポート(Thanks to akharito)
|
||||
2020/10/17 ver 5.98 [scale * reg]のサポート
|
||||
2020/09/08 ver 5.97 uint32などをuint32_tに置換
|
||||
2020/08/28 ver 5.95 レジスタクラスのコンストラクタがconstexprに対応(C++14以降)
|
||||
2020/08/04 ver 5.941 `CodeGenerator::reset()`が`ClearError()`を呼ぶように変更
|
||||
2020/07/28 ver 5.94 #include <winsock2.h>の削除 (only windows)
|
||||
2020/07/21 ver 5.93 例外なしモード追加
|
||||
2020/06/30 ver 5.92 Intel AMX命令サポート (Thanks to nshustrov)
|
||||
2020/06/19 ver 5.913 32ビット環境でXBYAK64を定義したときのmov(r64, imm64)を修正
|
||||
2020/06/19 ver 5.912 macOSの古いXcodeでもMAP_JITを有効にする(Thanks to rsdubtso)
|
||||
2020/05/10 ver 5.911 Linux/macOSでXBYAK_USE_MMAP_ALLOCATORがデフォルト有効になる
|
||||
2020/04/20 ver 5.91 マスクレジスタk0を受け入れる(マスクをしない)
|
||||
2020/04/09 ver 5.90 kmov{b,w,d,q}がサポートされないレジスタを受けると例外を投げる
|
||||
2020/02/26 ver 5.891 zm0のtype修正
|
||||
2020/01/03 ver 5.89 vfpclasspdの処理エラー修正
|
||||
2019/12/20 ver 5.88 Windowsでのコンパイルエラー修正
|
||||
2019/12/19 ver 5.87 未定義ラベルへのjmp命令のデフォルト挙動をT_NEARにするsetDefaultJmpNEAR()を追加
|
||||
2019/12/13 ver 5.86 [変更] -fno-operator-namesが指定されたときは5.84以前の挙動に戻す
|
||||
2019/12/07 ver 5.85 mmapにMAP_JITフラグを追加(macOS mojave以上)
|
||||
2019/11/29 ver 5.84 [変更] XBYAK_USE_OP_NAMESが定義されていない限りXBYAK_NO_OP_NAMESが定義されるように変更
|
||||
2019/10/12 ver 5.83 exit(1)の除去
|
||||
2019/09/23 ver 5.82 monitorx, mwaitx, clzero対応 (thanks to MagurosanTeam)
|
||||
2019/09/14 ver 5.81 いくつかの一般命令をサポート
|
||||
2019/08/01 ver 5.802 AVX512_BF16判定修正 (thanks to vpirogov)
|
||||
2019/05/27 support vp2intersectd, vp2intersectq (not tested)
|
||||
2019/05/26 ver 5.80 support vcvtne2ps2bf16, vcvtneps2bf16, vdpbf16ps
|
||||
2019/04/27 ver 5.79 vcmppd/vcmppsのptr_b対応忘れ(thanks to jkopinsky)
|
||||
2019/04/15 ver 5.78 Reg::changeBit()のリファクタリング(thanks to MerryMage)
|
||||
2019/03/06 ver 5.77 LLCキャッシュを共有数CPU数の修整(by densamoilov)
|
||||
2019/01/17 ver 5.76 Cpu::getNumCores()追加(by shelleygoel)
|
||||
2018/10/31 ver 5.751 互換性のためにXbyak::CastToの復元
|
||||
2018/10/29 ver 5.75 LabelManagerのデストラクタでLabelから参照を切り離す
|
||||
2018/10/21 ver 5.74 RegRip +/intの形をサポート Xbyak::CastToを削除
|
||||
2018/10/15 util::StackFrameでmovの代わりにpush/popを使う
|
||||
2018/09/19 ver 5.73 vpslld, vpslldq, vpsllwなどの(reg, mem, imm8)に対するevexエンコーディング修整
|
||||
2018/09/19 ver 5.72 fix the encoding of vinsertps for disp8N(Thanks to petercaday)
|
||||
2018/08/27 ver 5.71 新しいlabelインスタンスを返すL()を追加
|
||||
2018/08/27 ver 5.70 read/exec設定のためのsetProtectMode()とDontUseProtectの追加
|
||||
2018/08/24 ver 5.68 indexが16以上のVSIBエンコーディングのバグ修正(thanks to petercaday)
|
||||
2018/08/14 ver 5.67 Addressクラス内のmutableを削除 ; fix setCacheHierarchy for cloud vm
|
||||
2018/07/26 ver 5.661 mingw64対応
|
||||
2018/07/24 ver 5.66 protect()のmodeにCodeArray::PROTECT_REを追加
|
||||
2018/06/26 ver 5.65 fix push(qword [mem])
|
||||
2018/03/07 ver 5.64 Cpu()の中でzero divisionが出ることがあるのを修正
|
||||
2018/02/14 ver 5.63 Cpu::setCacheHierarchy()の修正とclang<3.9のためのEvexModifierZero修正(thanks to mgouicem)
|
||||
2018/02/13 ver 5.62 Cpu::setCacheHierarchy() by mgouicem and rsdubtso
|
||||
2018/02/07 ver 5.61 vmov*がmem{k}{z}形式対応(忘れてた)
|
||||
2018/01/24 ver 5.601 xword, ywordなどをXbyak::util名前空間に追加
|
||||
2018/01/05 ver 5.60 Ice lake系命令対応(319433-030.pdf)
|
||||
2017/08/22 ver 5.53 mpxエンコーディングバグ修正, bnd()プレフィクス追加
|
||||
2017/08/18 ver 5.52 align修正(thanks to MerryMage)
|
||||
2017/08/17 ver 5.51 multi-byte nop追加 align()はそれを使用する(thanks to inolen)
|
||||
2017/08/08 ver 5.50 mpx追加(thanks to magurosan)
|
||||
2017/08/08 ver 5.45 sha追加(thanks to magurosan)
|
||||
2017/08/08 ver 5.44 prefetchw追加(thanks to rsdubtso)
|
||||
2017/07/12 ver 5.432 PVS-studioの警告を減らす
|
||||
2017/07/09 ver 5.431 hasRex()修正 (影響なし) (thanks to drillsar)
|
||||
2017/05/14 ver 5.43 CodeGenerator::resetSize()修正(thanks to gibbed)
|
||||
2017/05/13 ver 5.42 movs{b,w,d,q}追加
|
||||
2017/01/26 ver 5.41 prefetcwt1追加とscale == 0対応(thanks to rsdubtso)
|
||||
2016/12/14 ver 5.40 Labelが示すアドレスを取得するLabel::getAddress()追加
|
||||
2016/12/07 ver 5.34 disp8N時の負のオフセット処理の修正(thanks to rsdubtso)
|
||||
2016/12/06 ver 5.33 disp8N時のvpbroadcast{b,w,d,q}, vpinsr{b,w}, vpextr{b,w}のバグ修正
|
||||
2016/12/01 ver 5.32 clang for Visual Studioサポートのために__xgetbv()を_xgetbv()に変更(thanks to freiro)
|
||||
2016/11/27 ver 5.31 AVX512_4VNNIをAVX512_4VNNIWに変更
|
||||
2016/11/27 ver 5.30 AVX512_4VNNI, AVX512_4FMAPS命令の追加(thanks to rsdubtso)
|
||||
2016/11/26 ver 5.20 AVX512_4VNNIとAVX512_4FMAPSの判定追加(thanks to rsdubtso)
|
||||
2016/11/20 ver 5.11 何故か消えていたvptest for ymm追加(thanks to gregory38)
|
||||
2016/11/20 ver 5.10 [rip+&var]の形のアドレッシング追加
|
||||
2016/09/29 ver 5.03 ERR_INVALID_OPMASK_WITH_MEMORYの判定ミス修正(thanks to PVS-Studio)
|
||||
2016/08/15 ver 5.02 xbyak_bin2hex.hをincludeしない
|
||||
2016/08/15 ver 5.011 gcc 5.4のバージョン取得ミスの修正
|
||||
2016/08/03 ver 5.01 AVXの省略表記非サポート
|
||||
2016/07/24 ver 5.00 avx-512フルサポート
|
||||
2016/06/13 avx-512 opmask命令サポート
|
||||
2016/05/05 ver 4.91 AVX-512命令の検出サポート
|
||||
2016/03/14 ver 4.901 ready()関数にコメント加筆(thanks to skmp)
|
||||
2016/02/04 ver 4.90 条件分岐命令にjcc(const void *addr);のタイプを追加
|
||||
2016/01/30 ver 4.89 vpblendvbがymmレジスタをサポートしていなかった(thanks to John Funnell)
|
||||
2016/01/24 ver 4.88 lea, cmovの16bitレジスタ対応(thanks to whyisthisfieldhere)
|
||||
2015/08/16 ver 4.87 セグメントセレクタに対応
|
||||
2015/08/16 ver 4.86 [rip + label]アドレッシングで即値を使うと壊れる(thanks to whyisthisfieldhere)
|
||||
2015/08/10 ver 4.85 Address::operator==()が間違っている(thanks to inolen)
|
||||
2015/07/22 ver 4.84 call()がvariadic template対応
|
||||
2015/05/24 ver 4.83 mobveサポート(thanks to benvanik)
|
||||
2015/05/24 ver 4.82 F16Cが使えるかどうかの判定追加
|
||||
2015/04/25 ver 4.81 setSizeが例外を投げる条件を修正(thanks to whyisthisfieldhere)
|
||||
2015/04/22 ver 4.80 rip相対でLabelのサポート(thanks to whyisthisfieldhere)
|
||||
2015/01/28 ver 4.71 adcx, adox, cmpxchg, rdseed, stacのサポート
|
||||
2014/10/14 ver 4.70 MmapAllocatorのサポート
|
||||
2014/06/13 ver 4.62 VC2014で警告抑制
|
||||
2014/05/30 ver 4.61 bt, bts, btr, btcのサポート
|
||||
2014/05/28 ver 4.60 vcvtph2ps, vcvtps2phのサポート
|
||||
2014/04/11 ver 4.52 rdrandの判定追加
|
||||
2014/03/25 ver 4.51 参照されなくなったラベルの状態を削除する
|
||||
2014/03/16 ver 4.50 新しいラベルクラスのサポート
|
||||
2014/03/05 ver 4.40 VirtualBox上でBMI/enhanced repのサポート判定を間違うことがあるのを修正
|
||||
2013/12/03 ver 4.30 Reg::cvt8(), cvt16(), cvt32()のサポート
|
||||
2013/10/16 ver 4.21 ラベルでstd::stringを受け付ける。
|
||||
2013/07/30 ver 4.20 [break backward compatibility] 従来のReg32eクラスをアドレッシング用のRegExpとReg32, Reg64を表すReg32eに分離
|
||||
2013/07/04 ver 4.10 [break backward compatibility] Xbyak::Errorの型をenumからclassに変更
|
||||
2013/06/21 ver 4.02 LABELの指すアドレスを書き込むputL(LABEL)関数の追加。
|
||||
2013/06/21 ver 4.01 vpsllw, vpslld, vpsllq, vpsraw, vpsrad, vpsrlw, vpsrld, vpsrlq support (ymm, ymm, xmm)
|
||||
support vpbroadcastb, vpbroadcastw, vpbroadcastd, vpbroadcastq(thanks to Gabest)
|
||||
2013/05/30 ver 4.00 AVX2, VEX-encoded GPR-instructionをサポート
|
||||
2013/03/27 ver 3.80 mov(reg, "label");をサポート
|
||||
2013/03/13 ver 3.76 cqo, jcxz, jecxz, jrcxz追加
|
||||
2013/01/15 ver 3.75 生成されたコードを修正するためにsetSize()を追加
|
||||
2013/01/12 ver 3.74 CodeGenerator::reset()とAllocator::useProtect()を追加
|
||||
2013/01/06 ver 3.73 可能ならunordered_mapを使う
|
||||
2012/12/04 ver 3.72 eaxなどをCodeGeneratorのメンバ変数に戻す. Xbyak::util::eaxはstatic const変数
|
||||
2012/11/17 ver 3.71 and_(), or_(), xor_(), not_()をXBYAK_NO_OP_NAMESが定義されていないときでも使えるようにした
|
||||
2012/11/17 CodeGeneratorのeax, ecx, ptrなどのメンバ変数をstaticにし、const参照をXbyak::utilにも定義
|
||||
2012/11/09 ver 3.70 and()をand_()にするためのマクロXBYAK_NO_OP_NAMESを追加(thanks to Mattias)
|
||||
2012/11/01 ver 3.62 add fwait/fnwait/finit/fninit
|
||||
2012/11/01 ver 3.61 add fldcw/fstcw
|
||||
2012/05/03 ver 3.60 Allocatorクラスのインタフェースを変更
|
||||
2012/03/23 ver 3.51 userPtrモードがバグったのを修正
|
||||
2012/03/19 ver 3.50 AutoGrowモードサポート
|
||||
2011/11/09 ver 3.05 rip相対の64bitサイズ以外の扱いのバグ修正 / movsxdサポート
|
||||
2011/08/15 ver 3.04 add(dword [ebp-8], 0xda);などにおけるimm8の扱いのバグ修正(thanks to lolcat)
|
||||
2011/06/16 ver 3.03 Macのgcc上での__GNUC_PREREQがミスってたのを修正(thanks to t_teruya)
|
||||
2011/04/28 ver 3.02 Macのgcc上ではxgetbvをdisable
|
||||
2011/03/24 ver 3.01 fix typo of OSXSAVE
|
||||
2011/03/23 ver 3.00 vcmpeqpsなどを追加
|
||||
2011/02/16 ver 2.994 beta add vmovq for 32-bit mode(I forgot it)
|
||||
2011/02/16 ver 2.993 beta remove cvtReg to avoid thread unsafe
|
||||
2011/02/10 ver 2.992 beta support one argument syntax for fadd like nasm
|
||||
2011/02/07 ver 2.991 beta fix pextrw reg, xmm, imm(Thanks to Gabest)
|
||||
2011/02/04 ver 2.99 beta support AVX
|
||||
2010/12/08 ver 2.31 fix ptr [rip + 32bit offset], support rtdscp
|
||||
2010/10/19 ver 2.30 support pclmulqdq, aesdec, aesdeclast, aesenc, aesenclast, aesimc, aeskeygenassist
|
||||
2010/07/07 ver 2.29 fix call(<label>)
|
||||
2010/06/17 ver 2.28 move some member functions to public
|
||||
2010/06/01 ver 2.27 support encoding of mov(reg64, imm) like yasm(not nasm)
|
||||
2010/05/24 ver 2.26 fix sub(rsp, 1000)
|
||||
2010/04/26 ver 2.25 add jc/jnc(I forgot to implement them...)
|
||||
2010/04/16 ver 2.24 change the prototype of rewrite() method
|
||||
2010/04/15 ver 2.23 fix align() and xbyak_util.h for Mac
|
||||
2010/02/16 ver 2.22 fix inLocalLabel()/outLocalLabel()
|
||||
2009/12/09 ver 2.21 support cygwin(gcc 4.3.2)
|
||||
2009/11/28 ver 2.20 FPUの一部命令サポート
|
||||
2009/06/25 ver 2.11 64bitモードでの mov(qword[rax], imm); 修正(thanks to Martinさん)
|
||||
2009/03/10 ver 2.10 jmp/call reg64の冗長なREG.W削除
|
||||
2009/02/24 ver 2.09 movq reg64, mmx/xmm; movq mmx/xmm, reg64追加
|
||||
2009/02/13 ver 2.08 movd(xmm7, dword[eax])が0x66を落とすバグ修正(thanks to Gabestさん)
|
||||
2008/12/30 ver 2.07 call()の相対アドレスが8bit以下のときのバグ修正(thanks to katoさん)
|
||||
2008/09/18 ver 2.06 @@, @f, @bとラベルの局所化機能追加(thanks to nobu-qさん)
|
||||
2008/09/18 ver 2.05 ptr [rip + 32bit offset]サポート(thanks to 団子厨(Dango-Chu)さん)
|
||||
2008/06/03 ver 2.04 align()のポカミス修正。mov(ptr[eax],1);などをエラーに
|
||||
2008/06/02 ver 2.03 ユーザ定義メモリインタフェースサポート
|
||||
2008/05/26 ver 2.02 protect()(on Linux)で不正な設定になることがあるのを修正(thanks to sinichiro_hさん)
|
||||
2008/04/30 ver 2.01 cmpxchg16b, cdqe追加
|
||||
2008/04/29 ver 2.00 x86/x64-64版公開
|
||||
2008/04/25 ver 1.90 x64版β公開
|
||||
2008/04/18 ver 1.12 コード整理
|
||||
2008/04/14 ver 1.11 コード整理
|
||||
2008/03/12 ver 1.10 bsf/bsr追加(忘れていた)
|
||||
2008/02/14 ver 1.09 sub eax, 1234が16bitモードで出力されていたのを修正(thanks to Robertさん)
|
||||
2007/11/05 ver 1.08 lock, xadd, xchg追加
|
||||
2007/11/02 ver 1.07 SSSE3/SSE4対応(thanks to 団子厨(Dango-Chu)さん)
|
||||
2007/09/25 ver 1.06 call((int)関数ポインタ); jmp((int)関数ポインタ);のサポート
|
||||
2007/08/04 ver 1.05 細かい修正
|
||||
2007/02/04 後方へのジャンプでT_NEARをつけないときに8bit相対アドレスに入らない
|
||||
場合に例外が発生しないバグの修正
|
||||
2007/01/21 [disp]の形のアドレス生成のバグ修正
|
||||
mov (eax|ax|al, [disp]); mov([disp], eax|ax|al);の短い表現選択
|
||||
2007/01/17 webページ作成
|
||||
2007/01/04 公開開始
|
||||
|
||||
-----------------------------------------------------------------------------
|
||||
◎著作権者
|
||||
|
||||
光成滋生(MITSUNARI Shigeo, [email protected])
|
||||
@@ -1,123 +0,0 @@
|
||||
XBYAK_INC=../xbyak/xbyak.h
|
||||
|
||||
BOOST_EXIST=$(shell echo "\#include <boost/spirit/core.hpp>" | (gcc -E - 2>/dev/null) | grep "boost/spirit/core.hpp" >/dev/null && echo "1")
|
||||
UNAME_M=$(shell uname -m)
|
||||
|
||||
ONLY_64BIT=0
|
||||
ifeq ($(shell uname -s),Darwin)
|
||||
ONLY_64BIT=1
|
||||
OS=mac
|
||||
ifeq ($(UNAME_M),x86_64)
|
||||
BIT=64
|
||||
endif
|
||||
ifeq ($(UNAME_M),i386)
|
||||
BIT=32
|
||||
endif
|
||||
ifeq ($(shell sw_vers -productVersion | cut -c1-4 | sed 's/\.//'),105)
|
||||
ifeq ($(shell sysctl -n hw.cpu64bit_capable),1)
|
||||
BIT=64
|
||||
endif
|
||||
endif
|
||||
else
|
||||
BIT=32
|
||||
ifeq ($(UNAME_M),x86_64)
|
||||
BIT=64
|
||||
endif
|
||||
ifeq ($(UNAME_M),amd64)
|
||||
BIT=64
|
||||
endif
|
||||
endif
|
||||
|
||||
ifeq ($(BIT),64)
|
||||
TARGET += test64 bf64 memfunc64 test_util64 jmp_table64
|
||||
ifeq ($(BOOST_EXIST),1)
|
||||
TARGET += calc64 #calc2_64
|
||||
endif
|
||||
endif
|
||||
|
||||
ifneq ($(OS),mac)
|
||||
TARGET += static_buf64
|
||||
endif
|
||||
|
||||
|
||||
ifneq ($(ONLY_64BIT),1)
|
||||
TARGET += test quantize bf toyvm test_util memfunc static_buf jmp_table
|
||||
ifeq ($(BOOST_EXIST),1)
|
||||
TARGET += calc #calc2
|
||||
endif
|
||||
endif
|
||||
|
||||
all: $(TARGET)
|
||||
|
||||
CFLAGS_WARN=-Wall -Wextra -Wformat=2 -Wcast-qual -Wcast-align -Wwrite-strings -Wfloat-equal -Wpointer-arith #-pedantic
|
||||
|
||||
CFLAGS=-g -O2 -fomit-frame-pointer -Wall -I../ $(CFLAGS_WARN)
|
||||
|
||||
test:
|
||||
$(CXX) $(CFLAGS) test0.cpp -o $@ -m32
|
||||
|
||||
quantize:
|
||||
$(CXX) $(CFLAGS) quantize.cpp -o $@ -m32
|
||||
|
||||
calc:
|
||||
$(CXX) $(CFLAGS) calc.cpp -o $@ -m32
|
||||
calc64:
|
||||
$(CXX) $(CFLAGS) calc.cpp -o $@ -m64
|
||||
calc2:
|
||||
$(CXX) $(CFLAGS) calc2.cpp -o $@ -m32
|
||||
calc2_64:
|
||||
$(CXX) $(CFLAGS) calc2.cpp -o $@ -m64
|
||||
|
||||
bf:
|
||||
$(CXX) $(CFLAGS) bf.cpp -o $@ -m32
|
||||
bf64:
|
||||
$(CXX) $(CFLAGS) bf.cpp -o $@ -m64
|
||||
|
||||
memfunc:
|
||||
$(CXX) $(CFLAGS) memfunc.cpp -o $@ -m32
|
||||
memfunc64:
|
||||
$(CXX) $(CFLAGS) memfunc.cpp -o $@ -m64
|
||||
|
||||
toyvm:
|
||||
$(CXX) $(CFLAGS) toyvm.cpp -o $@ -m32
|
||||
|
||||
test64:
|
||||
$(CXX) $(CFLAGS) test0.cpp -o $@ -m64
|
||||
test_util:
|
||||
$(CXX) $(CFLAGS) test_util.cpp -o $@ -m32
|
||||
test_util64:
|
||||
$(CXX) $(CFLAGS) test_util.cpp -o $@ -m64
|
||||
static_buf:
|
||||
$(CXX) $(CFLAGS) static_buf.cpp -o $@ -m32
|
||||
static_buf64:
|
||||
$(CXX) $(CFLAGS) static_buf.cpp -o $@ -m64
|
||||
jmp_table:
|
||||
$(CXX) $(CFLAGS) jmp_table.cpp -o $@ -m32
|
||||
jmp_table64:
|
||||
$(CXX) $(CFLAGS) jmp_table.cpp -o $@ -m64
|
||||
profiler: profiler.cpp ../xbyak/xbyak_util.h
|
||||
$(CXX) $(CFLAGS) profiler.cpp -o $@
|
||||
profiler-vtune: profiler.cpp ../xbyak/xbyak_util.h
|
||||
$(CXX) $(CFLAGS) profiler.cpp -o $@ -DXBYAK_USE_VTUNE -I /opt/intel/vtune_amplifier/include/ -L /opt/intel/vtune_amplifier/lib64 -ljitprofiling -ldl
|
||||
|
||||
clean:
|
||||
rm -rf *.o $(TARGET) *.exe profiler profiler-vtune
|
||||
|
||||
test : test0.cpp $(XBYAK_INC)
|
||||
test64: test0.cpp $(XBYAK_INC)
|
||||
quantize : quantize.cpp $(XBYAK_INC)
|
||||
calc : calc.cpp $(XBYAK_INC)
|
||||
calc64 : calc.cpp $(XBYAK_INC)
|
||||
calc2 : calc2.cpp $(XBYAK_INC)
|
||||
calc2_64 : calc2.cpp $(XBYAK_INC)
|
||||
bf : bf.cpp $(XBYAK_INC)
|
||||
bf64 : bf.cpp $(XBYAK_INC)
|
||||
memfunc : memfunc.cpp $(XBYAK_INC)
|
||||
memfunc64 : memfunc.cpp $(XBYAK_INC)
|
||||
toyvm : toyvm.cpp $(XBYAK_INC)
|
||||
static_buf: static_buf.cpp $(XBYAK_INC)
|
||||
static_buf64: static_buf.cpp $(XBYAK_INC)
|
||||
test_util : test_util.cpp $(XBYAK_INC) ../xbyak/xbyak_util.h
|
||||
test_util2 : test_util.cpp $(XBYAK_INC) ../xbyak/xbyak_util.h
|
||||
jmp_table: jmp_table.cpp $(XBYAK_INC)
|
||||
jmp_table64: jmp_table.cpp $(XBYAK_INC)
|
||||
@@ -1,211 +0,0 @@
|
||||
#define XBYAK_NO_OP_NAMES
|
||||
#include "xbyak/xbyak.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stack>
|
||||
#include <fstream>
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(disable : 4996) // scanf
|
||||
#define snprintf _snprintf_s
|
||||
#endif
|
||||
|
||||
class Brainfuck : public Xbyak::CodeGenerator {
|
||||
public:
|
||||
int getContinuousChar(std::istream& is, char c)
|
||||
{
|
||||
int count = 1;
|
||||
char p;
|
||||
while (is >> p) {
|
||||
if (p != c) break;
|
||||
count++;
|
||||
}
|
||||
is.unget();
|
||||
return count;
|
||||
}
|
||||
Brainfuck(std::istream& is) : CodeGenerator(100000)
|
||||
{
|
||||
// void (*)(void* putchar, void* getchar, int *stack)
|
||||
using namespace Xbyak;
|
||||
#ifdef XBYAK32
|
||||
const Reg32& pPutchar(esi);
|
||||
const Reg32& pGetchar(edi);
|
||||
const Reg32& stack(ebp);
|
||||
const Address cur = dword [stack];
|
||||
push(ebp); // stack
|
||||
push(esi);
|
||||
push(edi);
|
||||
const int P_ = 4 * 3;
|
||||
mov(pPutchar, ptr[esp + P_ + 4]); // putchar
|
||||
mov(pGetchar, ptr[esp + P_ + 8]); // getchar
|
||||
mov(stack, ptr[esp + P_ + 12]); // stack
|
||||
#elif defined(XBYAK64_WIN)
|
||||
const Reg64& pPutchar(rsi);
|
||||
const Reg64& pGetchar(rdi);
|
||||
const Reg64& stack(rbp); // stack
|
||||
const Address cur = dword [stack];
|
||||
push(rsi);
|
||||
push(rdi);
|
||||
push(rbp);
|
||||
mov(pPutchar, rcx); // putchar
|
||||
mov(pGetchar, rdx); // getchar
|
||||
mov(stack, r8); // stack
|
||||
#else
|
||||
const Reg64& pPutchar(rbx);
|
||||
const Reg64& pGetchar(rbp);
|
||||
const Reg64& stack(r12); // stack
|
||||
const Address cur = dword [stack];
|
||||
push(rbx);
|
||||
push(rbp);
|
||||
push(r12);
|
||||
mov(pPutchar, rdi); // putchar
|
||||
mov(pGetchar, rsi); // getchar
|
||||
mov(stack, rdx); // stack
|
||||
#endif
|
||||
std::stack<Label> labelF, labelB;
|
||||
char c;
|
||||
while (is >> c) {
|
||||
switch (c) {
|
||||
case '+':
|
||||
case '-':
|
||||
{
|
||||
int count = getContinuousChar(is, c);
|
||||
if (count == 1) {
|
||||
c == '+' ? inc(cur) : dec(cur);
|
||||
} else {
|
||||
add(cur, (c == '+' ? count : -count));
|
||||
}
|
||||
}
|
||||
break;
|
||||
case '>':
|
||||
case '<':
|
||||
{
|
||||
int count = getContinuousChar(is, c);
|
||||
add(stack, 4 * (c == '>' ? count : -count));
|
||||
}
|
||||
break;
|
||||
case '.':
|
||||
#ifdef XBYAK32
|
||||
push(cur);
|
||||
call(pPutchar);
|
||||
pop(eax);
|
||||
#elif defined(XBYAK64_WIN)
|
||||
mov(ecx, cur);
|
||||
sub(rsp, 32);
|
||||
call(pPutchar);
|
||||
add(rsp, 32);
|
||||
#else
|
||||
mov(edi, cur);
|
||||
call(pPutchar);
|
||||
#endif
|
||||
break;
|
||||
case ',':
|
||||
#if defined(XBYAK32) || defined(XBYAK64_GCC)
|
||||
call(pGetchar);
|
||||
#elif defined(XBYAK64_WIN)
|
||||
sub(rsp, 32);
|
||||
call(pGetchar);
|
||||
add(rsp, 32);
|
||||
#endif
|
||||
mov(cur, eax);
|
||||
break;
|
||||
case '[':
|
||||
{
|
||||
Label B = L();
|
||||
labelB.push(B);
|
||||
mov(eax, cur);
|
||||
test(eax, eax);
|
||||
Label F;
|
||||
jz(F, T_NEAR);
|
||||
labelF.push(F);
|
||||
}
|
||||
break;
|
||||
case ']':
|
||||
{
|
||||
Label B = labelB.top(); labelB.pop();
|
||||
jmp(B);
|
||||
Label F = labelF.top(); labelF.pop();
|
||||
L(F);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
#ifdef XBYAK32
|
||||
pop(edi);
|
||||
pop(esi);
|
||||
pop(ebp);
|
||||
#elif defined(XBYAK64_WIN)
|
||||
pop(rbp);
|
||||
pop(rdi);
|
||||
pop(rsi);
|
||||
#else
|
||||
pop(r12);
|
||||
pop(rbp);
|
||||
pop(rbx);
|
||||
#endif
|
||||
ret();
|
||||
}
|
||||
};
|
||||
|
||||
void dump(const uint8_t *code, size_t size)
|
||||
{
|
||||
puts("#include <stdio.h>\nstatic int stack[128 * 1024];");
|
||||
#ifdef _MSC_VER
|
||||
printf("static __declspec(align(4096)) ");
|
||||
#else
|
||||
printf("static __attribute__((aligned(4096)))");
|
||||
#endif
|
||||
puts("const unsigned char code[] = {");
|
||||
for (size_t i = 0; i < size; i++) {
|
||||
printf("0x%02x,", code[i]); if ((i % 16) == 15) putchar('\n');
|
||||
}
|
||||
puts("\n};");
|
||||
#ifdef _MSC_VER
|
||||
puts("#include <windows.h>");
|
||||
#else
|
||||
puts("#include <unistd.h>");
|
||||
puts("#include <sys/mman.h>");
|
||||
#endif
|
||||
puts("int main()\n{");
|
||||
#ifdef _MSC_VER
|
||||
puts("\tDWORD oldProtect;");
|
||||
puts("\tVirtualProtect((void*)code, sizeof(code), PAGE_EXECUTE_READWRITE, &oldProtect);");
|
||||
#else
|
||||
puts("\tlong pageSize = sysconf(_SC_PAGESIZE) - 1;");
|
||||
puts("\tmprotect((void*)code, (sizeof(code) + pageSize) & ~pageSize, PROT_READ | PROT_EXEC);");
|
||||
#endif
|
||||
puts(
|
||||
"\t((void (*)(void*, void*, int *))code)((void*)putchar, (void*)getchar, stack);\n"
|
||||
"}"
|
||||
);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
#ifdef XBYAK32
|
||||
fprintf(stderr, "32bit mode\n");
|
||||
#else
|
||||
fprintf(stderr, "64bit mode\n");
|
||||
#endif
|
||||
if (argc == 1) {
|
||||
fprintf(stderr, "bf filename.bf [0|1]\n");
|
||||
return 1;
|
||||
}
|
||||
std::ifstream ifs(argv[1]);
|
||||
int mode = argc == 3 ? atoi(argv[2]) : 0;
|
||||
try {
|
||||
Brainfuck bf(ifs);
|
||||
if (mode == 0) {
|
||||
static int stack[128 * 1024];
|
||||
bf.getCode<void (*)(const void*, const void*, int *)>()(reinterpret_cast<const void*>(putchar), reinterpret_cast<const void*>(getchar), stack);
|
||||
} else {
|
||||
dump(bf.getCode(), bf.getSize());
|
||||
}
|
||||
} catch (std::exception& e) {
|
||||
printf("ERR:%s\n", e.what());
|
||||
} catch (...) {
|
||||
printf("unknown error\n");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,228 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Debug|x64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|Win32">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|x64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>{654BD79B-59D3-4B10-BBAA-158BAB272828}</ProjectGuid>
|
||||
<WindowsTargetPlatformVersion>10.0.17763.0</WindowsTargetPlatformVersion>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
<UseOfMfc>false</UseOfMfc>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
<UseOfMfc>false</UseOfMfc>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
<UseOfMfc>false</UseOfMfc>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
<UseOfMfc>false</UseOfMfc>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
<Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC60.props" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
<Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC60.props" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
<Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC60.props" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
<Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC60.props" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup>
|
||||
<_ProjectFileVersion>15.0.27924.0</_ProjectFileVersion>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
<IntDir>$(ProjectName)\$(Configuration)\</IntDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
<IntDir>$(ProjectName)\$(Configuration)\</IntDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
<IntDir>$(ProjectName)\$(Platform)\$(Configuration)\</IntDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
<IntDir>$(ProjectName)\$(Platform)\$(Configuration)\</IntDir>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<Midl>
|
||||
<TypeLibraryName>.\Release/bf.tlb</TypeLibraryName>
|
||||
<HeaderFileName />
|
||||
</Midl>
|
||||
<ClCompile>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
|
||||
<AdditionalIncludeDirectories>../;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<StringPooling>true</StringPooling>
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<PrecompiledHeaderOutputFile>.\Release/bf.pch</PrecompiledHeaderOutputFile>
|
||||
<WarningLevel>Level4</WarningLevel>
|
||||
<SuppressStartupBanner>true</SuppressStartupBanner>
|
||||
</ClCompile>
|
||||
<ResourceCompile>
|
||||
<PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<Culture>0x0411</Culture>
|
||||
</ResourceCompile>
|
||||
<Link>
|
||||
<SuppressStartupBanner>true</SuppressStartupBanner>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<RandomizedBaseAddress>false</RandomizedBaseAddress>
|
||||
<DataExecutionPrevention />
|
||||
<TargetMachine>MachineX86</TargetMachine>
|
||||
</Link>
|
||||
<Bscmake>
|
||||
<SuppressStartupBanner>true</SuppressStartupBanner>
|
||||
</Bscmake>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<Midl>
|
||||
<TypeLibraryName>.\Debug/bf.tlb</TypeLibraryName>
|
||||
<HeaderFileName />
|
||||
</Midl>
|
||||
<ClCompile>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<AdditionalIncludeDirectories>../;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<MinimalRebuild>true</MinimalRebuild>
|
||||
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
|
||||
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
|
||||
<PrecompiledHeaderOutputFile>.\Debug/bf.pch</PrecompiledHeaderOutputFile>
|
||||
<WarningLevel>Level4</WarningLevel>
|
||||
<SuppressStartupBanner>true</SuppressStartupBanner>
|
||||
</ClCompile>
|
||||
<ResourceCompile>
|
||||
<PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<Culture>0x0411</Culture>
|
||||
</ResourceCompile>
|
||||
<Link>
|
||||
<SuppressStartupBanner>true</SuppressStartupBanner>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<ProgramDatabaseFile>.\Debug/bf.pdb</ProgramDatabaseFile>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<RandomizedBaseAddress>false</RandomizedBaseAddress>
|
||||
<DataExecutionPrevention />
|
||||
<TargetMachine>MachineX86</TargetMachine>
|
||||
</Link>
|
||||
<Bscmake>
|
||||
<SuppressStartupBanner>true</SuppressStartupBanner>
|
||||
</Bscmake>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<Midl>
|
||||
<TargetEnvironment>X64</TargetEnvironment>
|
||||
<TypeLibraryName>.\Release/bf.tlb</TypeLibraryName>
|
||||
<HeaderFileName />
|
||||
</Midl>
|
||||
<ClCompile>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
|
||||
<AdditionalIncludeDirectories>../;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<StringPooling>true</StringPooling>
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<PrecompiledHeaderOutputFile>.\Release/bf.pch</PrecompiledHeaderOutputFile>
|
||||
<WarningLevel>Level4</WarningLevel>
|
||||
<SuppressStartupBanner>true</SuppressStartupBanner>
|
||||
</ClCompile>
|
||||
<ResourceCompile>
|
||||
<PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<Culture>0x0411</Culture>
|
||||
</ResourceCompile>
|
||||
<Link>
|
||||
<SuppressStartupBanner>true</SuppressStartupBanner>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<RandomizedBaseAddress>false</RandomizedBaseAddress>
|
||||
<DataExecutionPrevention />
|
||||
<TargetMachine>MachineX64</TargetMachine>
|
||||
</Link>
|
||||
<Bscmake>
|
||||
<SuppressStartupBanner>true</SuppressStartupBanner>
|
||||
</Bscmake>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<Midl>
|
||||
<TargetEnvironment>X64</TargetEnvironment>
|
||||
<TypeLibraryName>.\Debug/bf.tlb</TypeLibraryName>
|
||||
<HeaderFileName />
|
||||
</Midl>
|
||||
<ClCompile>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<AdditionalIncludeDirectories>../;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<MinimalRebuild>true</MinimalRebuild>
|
||||
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
|
||||
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
|
||||
<PrecompiledHeaderOutputFile>.\Debug/bf.pch</PrecompiledHeaderOutputFile>
|
||||
<WarningLevel>Level4</WarningLevel>
|
||||
<SuppressStartupBanner>true</SuppressStartupBanner>
|
||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||
</ClCompile>
|
||||
<ResourceCompile>
|
||||
<PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<Culture>0x0411</Culture>
|
||||
</ResourceCompile>
|
||||
<Link>
|
||||
<SuppressStartupBanner>true</SuppressStartupBanner>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<ProgramDatabaseFile>.\Debug/bf.pdb</ProgramDatabaseFile>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<RandomizedBaseAddress>false</RandomizedBaseAddress>
|
||||
<DataExecutionPrevention />
|
||||
<TargetMachine>MachineX64</TargetMachine>
|
||||
</Link>
|
||||
<Bscmake>
|
||||
<SuppressStartupBanner>true</SuppressStartupBanner>
|
||||
</Bscmake>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="bf.cpp" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
||||
@@ -1,229 +0,0 @@
|
||||
/*
|
||||
@author herumi
|
||||
|
||||
tiny calculator
|
||||
This program generates a function to calc the value of
|
||||
polynomial given by user in run-time.
|
||||
use boost::spirit::classic
|
||||
see calc2.cpp for new version of boost::spirit
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <sstream>
|
||||
#include <map>
|
||||
#define XBYAK_NO_OP_NAMES
|
||||
#include "xbyak/xbyak.h"
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(disable : 4127) // for boost(constant condition)
|
||||
#pragma warning(disable : 4512) // for boost
|
||||
#endif
|
||||
#include <boost/spirit/include/classic_file_iterator.hpp>
|
||||
#include <boost/spirit/include/classic_core.hpp>
|
||||
#include <boost/bind.hpp>
|
||||
|
||||
enum Error {
|
||||
UNDEFINED_VARIABLE = 1
|
||||
};
|
||||
|
||||
/*
|
||||
JIT assemble of given polynomial for VC or gcc
|
||||
*/
|
||||
class FuncGen : public Xbyak::CodeGenerator {
|
||||
public:
|
||||
typedef std::map<std::string, int> Map;
|
||||
private:
|
||||
enum {
|
||||
MAX_CONST_NUM = 32
|
||||
};
|
||||
double constTbl_[MAX_CONST_NUM];
|
||||
size_t constTblPos_;
|
||||
int regIdx_;
|
||||
Map varMap_; // map var name to index
|
||||
#ifdef XBYAK32
|
||||
const Xbyak::Reg32& valTbl_;
|
||||
const Xbyak::Reg32& tbl_;
|
||||
#else
|
||||
const Xbyak::Reg64& valTbl_;
|
||||
const Xbyak::Reg64& tbl_;
|
||||
#endif
|
||||
public:
|
||||
/*
|
||||
@param y [out] the value of f(var)
|
||||
@param var [in] table of input variables
|
||||
func(double *y, const double var[]);
|
||||
@note func does not return double to avoid difference of compiler
|
||||
*/
|
||||
FuncGen(const std::vector<std::string>& varTbl)
|
||||
: constTblPos_(0)
|
||||
, regIdx_(-1)
|
||||
#ifdef XBYAK32
|
||||
, valTbl_(eax)
|
||||
, tbl_(edx)
|
||||
#elif defined(XBYAK64_WIN)
|
||||
, valTbl_(rcx)
|
||||
, tbl_(rdx)
|
||||
#else
|
||||
, valTbl_(rdi)
|
||||
, tbl_(rsi)
|
||||
#endif
|
||||
{
|
||||
#ifdef XBYAK32
|
||||
mov(valTbl_, ptr[esp+8]); // eax == varTbl
|
||||
mov(tbl_, (size_t)constTbl_);
|
||||
#else
|
||||
#ifdef XBYAK64_WIN
|
||||
movaps(ptr [rsp + 8], xm6); // save xm6, xm7
|
||||
movaps(ptr [rsp + 8 + 16], xm7);
|
||||
#endif
|
||||
mov(tbl_, (size_t)constTbl_);
|
||||
#endif
|
||||
for (int i = 0, n = static_cast<int>(varTbl.size()); i < n; i++) {
|
||||
varMap_[varTbl[i]] = i;
|
||||
}
|
||||
}
|
||||
// use edx
|
||||
void genPush(double n)
|
||||
{
|
||||
if (constTblPos_ >= MAX_CONST_NUM) throw;
|
||||
constTbl_[constTblPos_] = n;
|
||||
if (regIdx_ == 7) throw;
|
||||
movsd(Xbyak::Xmm(++regIdx_), ptr[tbl_ + (int)(constTblPos_ * sizeof(double))]);
|
||||
constTblPos_++;
|
||||
}
|
||||
// use eax
|
||||
void genVal(const char *begin, const char *end)
|
||||
{
|
||||
std::string var(begin, end);
|
||||
if (varMap_.find(var) == varMap_.end()) throw UNDEFINED_VARIABLE;
|
||||
if (regIdx_ == 7) throw;
|
||||
movsd(Xbyak::Xmm(++regIdx_), ptr[valTbl_ + varMap_[var] * sizeof(double)]);
|
||||
}
|
||||
void genAdd(const char*, const char*)
|
||||
{
|
||||
addsd(Xbyak::Xmm(regIdx_ - 1), Xbyak::Xmm(regIdx_)); regIdx_--;
|
||||
}
|
||||
void genSub(const char*, const char*)
|
||||
{
|
||||
subsd(Xbyak::Xmm(regIdx_ - 1), Xbyak::Xmm(regIdx_)); regIdx_--;
|
||||
}
|
||||
void genMul(const char*, const char*)
|
||||
{
|
||||
mulsd(Xbyak::Xmm(regIdx_ - 1), Xbyak::Xmm(regIdx_)); regIdx_--;
|
||||
}
|
||||
void genDiv(const char*, const char*)
|
||||
{
|
||||
divsd(Xbyak::Xmm(regIdx_ - 1), Xbyak::Xmm(regIdx_)); regIdx_--;
|
||||
}
|
||||
void complete()
|
||||
{
|
||||
#ifdef XBYAK32
|
||||
mov(eax, ptr [esp + 4]); // eax = valTbl
|
||||
movsd(ptr [eax], xm0);
|
||||
#else
|
||||
#ifdef XBYAK64_WIN
|
||||
movaps(xm6, ptr [rsp + 8]);
|
||||
movaps(xm7, ptr [rsp + 8 + 16]);
|
||||
#endif
|
||||
#endif
|
||||
ret();
|
||||
}
|
||||
};
|
||||
|
||||
struct Grammar : public boost::spirit::classic::grammar<Grammar> {
|
||||
FuncGen& f_;
|
||||
Grammar(FuncGen& f) : f_(f) { }
|
||||
template<typename ScannerT>
|
||||
struct definition {
|
||||
boost::spirit::classic::rule<ScannerT> poly0, poly1, poly2, var;
|
||||
|
||||
definition(const Grammar& self)
|
||||
{
|
||||
using namespace boost;
|
||||
using namespace boost::spirit::classic;
|
||||
|
||||
poly0 = poly1 >> *(('+' >> poly1)[bind(&FuncGen::genAdd, ref(self.f_), _1, _2)]
|
||||
| ('-' >> poly1)[bind(&FuncGen::genSub, ref(self.f_), _1, _2)]);
|
||||
poly1 = poly2 >> *(('*' >> poly2)[bind(&FuncGen::genMul, ref(self.f_), _1, _2)]
|
||||
| ('/' >> poly2)[bind(&FuncGen::genDiv, ref(self.f_), _1, _2)]);
|
||||
var = (+alpha_p)[bind(&FuncGen::genVal, ref(self.f_), _1, _2)];
|
||||
poly2 = real_p[bind(&FuncGen::genPush, ref(self.f_), _1)]
|
||||
| var
|
||||
| '(' >> poly0 >> ')';
|
||||
}
|
||||
const boost::spirit::classic::rule<ScannerT>& start() const { return poly0; }
|
||||
};
|
||||
};
|
||||
|
||||
void put(const std::vector<double>& x)
|
||||
{
|
||||
for (size_t i = 0, n = x.size(); i < n; i++) {
|
||||
if (i > 0) printf(", ");
|
||||
printf("%f", x[i]);
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
if (argc <= 2) {
|
||||
fprintf(stderr, "calc \"var1 var2 ...\" \"function of var\"\n");
|
||||
fprintf(stderr, "eg. calc x \"x*x\"\n");
|
||||
fprintf(stderr, "eg. calc \"x y z\" \"x*x + y - z\"\n");
|
||||
return 1;
|
||||
}
|
||||
const char *poly = argv[2];
|
||||
try {
|
||||
std::vector<std::string> varTbl;
|
||||
|
||||
// get varTbl from argv[1]
|
||||
{
|
||||
std::istringstream is(argv[1]);
|
||||
int i = 0;
|
||||
printf("varTbl = { ");
|
||||
while (is) {
|
||||
std::string var;
|
||||
is >> var;
|
||||
if (var.empty()) break;
|
||||
printf("%s:%d, ", var.c_str(), i);
|
||||
varTbl.push_back(var);
|
||||
i++;
|
||||
}
|
||||
printf("}\n");
|
||||
}
|
||||
FuncGen funcGen(varTbl);
|
||||
Grammar calc(funcGen);
|
||||
boost::spirit::classic::parse_info<> r = parse(poly, calc, boost::spirit::classic::space_p);
|
||||
if (!r.full) {
|
||||
printf("err poly=%s\n", poly);
|
||||
return 1;
|
||||
}
|
||||
funcGen.complete();
|
||||
std::vector<double> valTbl;
|
||||
valTbl.resize(varTbl.size());
|
||||
#ifdef XBYAK32
|
||||
puts("32bit mode");
|
||||
void (*func)(double *ret, const double *valTbl) = funcGen.getCode<void (*)(double *, const double*)>();
|
||||
#else
|
||||
puts("64bit mode");
|
||||
double (*func)(const double *valTbl) = funcGen.getCode<double (*)(const double*)>();
|
||||
#endif
|
||||
for (int i = 0; i < 10; i++) {
|
||||
for (size_t j = 0, n = valTbl.size(); j < n; j++) {
|
||||
valTbl[j] = rand() % 7;
|
||||
}
|
||||
double y;
|
||||
#ifdef XBYAK32
|
||||
func(&y, &valTbl[0]);
|
||||
#else
|
||||
y = func(&valTbl[0]);
|
||||
#endif
|
||||
printf("f("); put(valTbl); printf(")=%f\n", y);
|
||||
}
|
||||
} catch (std::exception& e) {
|
||||
printf("ERR:%s\n", e.what());
|
||||
} catch (Error err) {
|
||||
printf("ERR:%d\n", err);
|
||||
} catch (...) {
|
||||
printf("unknown error\n");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
Loaded 100 of 696 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user