mirror of
https://github.com/flyinghead/flycast.git
synced 2026-11-08 01:48:31 -10:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8ea12443d3 | ||
|
|
6679cb2f31 | ||
|
|
f1fd8b12e2 | ||
|
|
aafa9f0bf0 | ||
|
|
dae3676979 | ||
|
|
09ab139407 | ||
|
|
138adc28d7 | ||
|
|
9fd80b952a | ||
|
|
a058481e36 | ||
|
|
33d1dafdb7 | ||
|
|
8b2c1bc5dc | ||
|
|
2b83df86cd | ||
|
|
72d9ad34dc | ||
|
|
e72a867363 | ||
|
|
a01edd22c7 | ||
|
|
c1f5f2e8f9 | ||
|
|
f6c1503887 | ||
|
|
71982eda7a | ||
|
|
fefdb6c661 | ||
|
|
4dd490034a | ||
|
|
719fd70860 | ||
|
|
49ad2b6864 | ||
|
|
7d645541f8 | ||
|
|
f50d6204dd | ||
|
|
e270621a03 | ||
|
|
07172416c1 | ||
|
|
f9dcd08cf3 | ||
|
|
83a27b9125 | ||
|
|
9976fe10fb | ||
|
|
af7edadedb | ||
|
|
d882c48b4f | ||
|
|
d92790e69f | ||
|
|
5eef0309bf | ||
|
|
5f88293fbd | ||
|
|
245b9043c5 | ||
|
|
e3a1440e25 | ||
|
|
0a9eaa6cb8 | ||
|
|
e4ca99afba | ||
|
|
e5ccf98693 | ||
|
|
e832509175 | ||
|
|
977d6c6f95 | ||
|
|
2103dd5a7a | ||
|
|
9df12f950b | ||
|
|
272f25ceb3 | ||
|
|
46340e7e77 | ||
|
|
aed4d21a4f | ||
|
|
9b4667cb38 | ||
|
|
ec3ad9b328 | ||
|
|
ca613db70d | ||
|
|
9fd48e7de3 | ||
|
|
1277a8ff13 | ||
|
|
8adec3f20b | ||
|
|
9aa7371d82 | ||
|
|
0bf1877d96 | ||
|
|
4cd6278104 | ||
|
|
14b8d4e915 | ||
|
|
ddb012bbd2 | ||
|
|
bfe09667f4 | ||
|
|
4e3d1caf3f | ||
|
|
6777aa39cb | ||
|
|
9bdaa6c40b | ||
|
|
021249c321 | ||
|
|
e7a4e64a6b | ||
|
|
b840a4f477 | ||
|
|
bad55204f2 | ||
|
|
70fe47dacf | ||
|
|
24e579ed99 | ||
|
|
8ddbe9212a | ||
|
|
adeba60ba9 | ||
|
|
95de83431b | ||
|
|
112e05ed5d | ||
|
|
90896368b8 | ||
|
|
ce46d1a383 | ||
|
|
c1abadb6cd | ||
|
|
e85fa82101 | ||
|
|
0a0d30309b | ||
|
|
30e5466d90 | ||
|
|
48dfab7397 | ||
|
|
4747252187 | ||
|
|
a5608f4f22 | ||
|
|
20652516e7 | ||
|
|
f05e5f3582 | ||
|
|
72e892a77e | ||
|
|
0fa3e9a37b | ||
|
|
1256680a99 | ||
|
|
81bebdb900 | ||
|
|
6cc64c18dd | ||
|
|
6b18ad7e3e | ||
|
|
2797cca5ff | ||
|
|
b7a2e605f9 | ||
|
|
ec82c7b9ed | ||
|
|
88f23958ac | ||
|
|
4f834610b3 | ||
|
|
e2e9a54e0e | ||
|
|
cc56b0fbae | ||
|
|
5755c5b3c6 | ||
|
|
34216f77af | ||
|
|
21c77adc4d | ||
|
|
35acb7e62c | ||
|
|
b5f49d6c3a | ||
|
|
de403a6203 | ||
|
|
6f0581032b | ||
|
|
f13d7ad2dc | ||
|
|
90b06a688b | ||
|
|
1b6b61d253 | ||
|
|
83493cc14b | ||
|
|
9bf60dde3c | ||
|
|
24954ec599 | ||
|
|
c53a1c42c6 | ||
|
|
13302b87c8 | ||
|
|
f76d05a3d5 | ||
|
|
763d9ce06a | ||
|
|
6ab43096a2 | ||
|
|
ceec01ac2e | ||
|
|
7327e52e71 | ||
|
|
f04e9d4a65 | ||
|
|
c386f64faa | ||
|
|
ff33ff2b88 | ||
|
|
17db07703e | ||
|
|
75f64efe93 | ||
|
|
ab8b4f0e54 | ||
|
|
43ba8953a2 | ||
|
|
6de2f160a1 | ||
|
|
ccc9931de8 | ||
|
|
0517a4600c | ||
|
|
fe17d459a5 | ||
|
|
2d4684a462 | ||
|
|
300cf0d437 | ||
|
|
c96e828c63 | ||
|
|
4666ea2fdb | ||
|
|
8f5f2caae6 | ||
|
|
8fdd1dde3d | ||
|
|
8e96590065 | ||
|
|
d46b181084 | ||
|
|
e46815d070 | ||
|
|
3c38fc1f16 | ||
|
|
47b6a90bec | ||
|
|
de6a43bd21 | ||
|
|
7438094d7c | ||
|
|
336706e728 | ||
|
|
8f486e71cb | ||
|
|
b378161837 | ||
|
|
a136583189 | ||
|
|
06a6e26588 | ||
|
|
5541d34a9e | ||
|
|
108c8a4b5d | ||
|
|
9e916ca1c9 | ||
|
|
42e98e86d0 | ||
|
|
010fba15a8 | ||
|
|
bf249061cf | ||
|
|
24db1422b8 | ||
|
|
da6c34b2fd | ||
|
|
a6c4530e22 | ||
|
|
e8340bfa5e | ||
|
|
eaa22a49d1 | ||
|
|
4f87a3556e | ||
|
|
41d418ed25 | ||
|
|
9d6eab74e1 | ||
|
|
a0c81d2f2a | ||
|
|
d6efbc513c | ||
|
|
ed78eb4d50 | ||
|
|
236b747db8 | ||
|
|
c9fafa0ed1 | ||
|
|
4bd8866164 | ||
|
|
f346bcd68b | ||
|
|
187991d71f | ||
|
|
40cdef6c1c | ||
|
|
8252a28e48 | ||
|
|
c7ee42f0ba | ||
|
|
e27b5dc1aa | ||
|
|
966ff3767d | ||
|
|
056a02357d | ||
|
|
6115a918b2 | ||
|
|
3ffb09ec72 | ||
|
|
de89d8cfed | ||
|
|
c7d6525c51 | ||
|
|
5ce1f92e5c | ||
|
|
464defe0d7 | ||
|
|
d323490d1f | ||
|
|
d8c15de030 | ||
|
|
b55054249f | ||
|
|
0aa8910742 | ||
|
|
43bb7c83f7 | ||
|
|
391da7023f | ||
|
|
b0a268b89e | ||
|
|
960b8134c1 | ||
|
|
5a51749daa | ||
|
|
d2dc60ec00 | ||
|
|
33bcf4443f | ||
|
|
62d00578af | ||
|
|
dac5c008ab | ||
|
|
588035d9eb | ||
|
|
f63a82afc4 | ||
|
|
c052822fd4 | ||
|
|
2846b3002b | ||
|
|
19a240503d | ||
|
|
c9d3096e41 | ||
|
|
d6ae47d0f7 | ||
|
|
40a7c08d14 | ||
|
|
6f8a588794 | ||
|
|
156aafe95b | ||
|
|
1017d3eb95 | ||
|
|
3059b43121 | ||
|
|
93789e2a63 | ||
|
|
6639d6b167 | ||
|
|
daef33cea5 | ||
|
|
a7c89701fe | ||
|
|
9a119e7646 | ||
|
|
c8462e1f78 | ||
|
|
50944772b7 | ||
|
|
952a785bf0 | ||
|
|
f9eed1ed3f | ||
|
|
b7df183c7c | ||
|
|
13edf858e3 | ||
|
|
d45de9e8a9 | ||
|
|
81cbf45bdb | ||
|
|
d340b620c3 | ||
|
|
443d5a2ba6 | ||
|
|
894a38fb71 | ||
|
|
aea37b3bd8 | ||
|
|
b5eecb79b8 | ||
|
|
f629c352e1 | ||
|
|
ff91d1101a | ||
|
|
4f1512d369 | ||
|
|
2dde1d5e7b | ||
|
|
3c8769cb5c | ||
|
|
ba12c01ab8 | ||
|
|
713739bbc7 | ||
|
|
4667d17d78 | ||
|
|
bc51aefa9c | ||
|
|
67c4e62c51 | ||
|
|
b71541f8dd | ||
|
|
56cad843c9 | ||
|
|
1b0781c680 | ||
|
|
0c5e79d618 | ||
|
|
5c8d7021f6 | ||
|
|
8d2bcdf35e | ||
|
|
eb2826f6d3 | ||
|
|
6cb929953c | ||
|
|
232924d88a | ||
|
|
90b13a40ab | ||
|
|
a50f5765da | ||
|
|
44fa364f36 | ||
|
|
7029e1615a | ||
|
|
3469b7fca7 | ||
|
|
434083c716 | ||
|
|
d9d91381b5 | ||
|
|
531c6f94d5 | ||
|
|
9aa9b5bebc | ||
|
|
e592650afc | ||
|
|
c146a92f83 | ||
|
|
d4fa3c441e | ||
|
|
47eeab9985 | ||
|
|
be8c559b2f | ||
|
|
51d25bb49b | ||
|
|
6d69598800 | ||
|
|
36684bf82c | ||
|
|
cdaaeb5b27 | ||
|
|
4220c0d64f | ||
|
|
e286f98f72 | ||
|
|
e714e94510 | ||
|
|
8715e5a5e9 | ||
|
|
1153238e2c | ||
|
|
617d82f5a2 | ||
|
|
471e0a7786 | ||
|
|
887e616f76 | ||
|
|
aa2fa1f611 | ||
|
|
57c88e07c4 | ||
|
|
593b3205bd | ||
|
|
ecce9157bd | ||
|
|
b2d96d77d7 | ||
|
|
e1537ddbda | ||
|
|
4c7e57ebd6 | ||
|
|
116dc0e1ed | ||
|
|
10d3ffdf09 | ||
|
|
cbd01fba38 | ||
|
|
88fd2641d9 | ||
|
|
70a69cf48d | ||
|
|
f8d5517b8e | ||
|
|
16b2f59a47 | ||
|
|
07d6ca6c84 | ||
|
|
c9c015976a | ||
|
|
2615cc13f1 | ||
|
|
599dc92d11 | ||
|
|
e26302ef03 | ||
|
|
fd3e74e224 | ||
|
|
5b5d7b01eb | ||
|
|
f6b01aba0c | ||
|
|
19bb4a6e5d | ||
|
|
bc70d9118d | ||
|
|
393c3dbfd9 | ||
|
|
8fd6fefda7 | ||
|
|
a620a432c9 | ||
|
|
9e37d1e726 | ||
|
|
c1b087df83 | ||
|
|
2add951f70 | ||
|
|
070ac717d3 | ||
|
|
cfb7ff3054 | ||
|
|
e03c37b013 | ||
|
|
0b0904cdc5 | ||
|
|
195f401044 | ||
|
|
552e5b7d7a | ||
|
|
2a48049216 | ||
|
|
c001240797 | ||
|
|
e7d0a5f2f9 | ||
|
|
032cc17659 | ||
|
|
c0c6f206bf | ||
|
|
6aa59c54a5 | ||
|
|
9c964ac955 | ||
|
|
5734556440 | ||
|
|
e76b76dcc4 | ||
|
|
cab19ad54b | ||
|
|
a7702c622a | ||
|
|
9f9b29b833 | ||
|
|
06529b63f7 | ||
|
|
0d36154618 | ||
|
|
c7b6f22e10 | ||
|
|
d069b45bff | ||
|
|
4a0ace5de2 | ||
|
|
57c2dcd961 | ||
|
|
790f5b1ad2 | ||
|
|
54ac9c6361 | ||
|
|
449b871e0c | ||
|
|
e057370e97 | ||
|
|
c938f7b0df | ||
|
|
99dc278ad2 | ||
|
|
bccdc6600a | ||
|
|
ba1a68a69f | ||
|
|
363c2c4c3f | ||
|
|
fe429ec01e | ||
|
|
192838b9c1 | ||
|
|
2a19ccf945 | ||
|
|
00954f1b60 | ||
|
|
bf4346c849 | ||
|
|
32502e7459 | ||
|
|
99031e23d3 | ||
|
|
f4f087a6ea | ||
|
|
0433fd824c | ||
|
|
9137ff998f | ||
|
|
7cc77b10ed | ||
|
|
07f208d2a2 | ||
|
|
05cd7ee8d3 | ||
|
|
d8e61520af | ||
|
|
e9beea484d | ||
|
|
4aecdbbb25 | ||
|
|
d7c28a4805 | ||
|
|
939e2bc68f | ||
|
|
ce4a3a7147 | ||
|
|
5fde889d7c | ||
|
|
fd2a87fca2 | ||
|
|
153dbb0c56 | ||
|
|
e53433e6f5 | ||
|
|
db7895cea5 | ||
|
|
f3a774ab4e | ||
|
|
bd25c14cfd | ||
|
|
035ea0b0c0 | ||
|
|
d6593b9c6e | ||
|
|
105ab95efa | ||
|
|
2c711e46fe | ||
|
|
923be3899d | ||
|
|
cb518b5481 | ||
|
|
a18e3701c6 | ||
|
|
2ed4b4a984 | ||
|
|
f11a5981fe | ||
|
|
ea83b08f89 | ||
|
|
b785944560 | ||
|
|
8f3124d14e | ||
|
|
14f3507b86 | ||
|
|
4efacd7d71 | ||
|
|
a9d5b77053 | ||
|
|
bc28c7ccb3 | ||
|
|
f14c29fd04 | ||
|
|
3303ecbbd1 | ||
|
|
c4c4c2fde0 | ||
|
|
78a874d20e | ||
|
|
ef321d81a4 | ||
|
|
df83ca436c | ||
|
|
665ef86cf0 | ||
|
|
b9601d26e3 | ||
|
|
038df0d923 | ||
|
|
73cbd7a183 | ||
|
|
ab25cc73a9 | ||
|
|
a0014bc810 | ||
|
|
6de5879cb4 | ||
|
|
32ecb141df | ||
|
|
4cd90d8ebb | ||
|
|
46eab502e4 | ||
|
|
535fbe29f8 | ||
|
|
41723a831f | ||
|
|
abe1d4fd27 | ||
|
|
dda04e63fa | ||
|
|
e60f30b357 | ||
|
|
f0f27558af | ||
|
|
0f6a92caad | ||
|
|
9a60cd7ded | ||
|
|
926877397c | ||
|
|
b92277ac58 | ||
|
|
9a7bf75e4e | ||
|
|
1253e1199d | ||
|
|
51508dcdc6 | ||
|
|
f6b3577de5 | ||
|
|
a4ec706c79 | ||
|
|
cb890c7b6f | ||
|
|
dbfead6a15 | ||
|
|
fd3f207e45 | ||
|
|
594b403997 | ||
|
|
bafe07de85 | ||
|
|
3e047a6e03 | ||
|
|
29c0dca0ce | ||
|
|
5cfd3f0ba3 | ||
|
|
923dcf10a7 | ||
|
|
7b71bd319c | ||
|
|
51089c5e0a | ||
|
|
24944e00a7 | ||
|
|
66faf0d330 | ||
|
|
c0de126b2b | ||
|
|
c1f0a5a15f | ||
|
|
f640b32cc9 | ||
|
|
93e47dd410 | ||
|
|
8fb3def2d5 | ||
|
|
98a0f2b821 | ||
|
|
4fafa91506 | ||
|
|
09a1fea40f | ||
|
|
e55d70c0e6 | ||
|
|
ca45ff3834 | ||
|
|
35c71ebcfd | ||
|
|
33edcca348 | ||
|
|
dac5b991e0 | ||
|
|
8ba5e05421 | ||
|
|
35b7be3905 | ||
|
|
b7d923e02b | ||
|
|
eaf2c0064c | ||
|
|
a65cd9e5f9 | ||
|
|
e94b26f1df | ||
|
|
e96b38ff5c | ||
|
|
e894d4df5c | ||
|
|
c58ae4daac | ||
|
|
cb9af7d742 | ||
|
|
2a364dee67 | ||
|
|
56107b3667 | ||
|
|
31aab32d95 | ||
|
|
0b66409ed2 | ||
|
|
8ae288d2ca | ||
|
|
4419ff310a | ||
|
|
2f524923da | ||
|
|
07d761a880 | ||
|
|
f6f6637973 | ||
|
|
2cd3ffb33f | ||
|
|
abd9219347 | ||
|
|
417a42ae10 | ||
|
|
0e12153c45 | ||
|
|
cb33387ed6 | ||
|
|
38d4689b63 | ||
|
|
23d1db9c75 | ||
|
|
4e079b5d0b | ||
|
|
3fcbdd3fc5 | ||
|
|
78b44919c5 | ||
|
|
13a8d49c90 | ||
|
|
7308f9a704 | ||
|
|
18f9b84af6 | ||
|
|
56517b027a | ||
|
|
d4a02e3c2b | ||
|
|
33131e1395 | ||
|
|
73ac46f421 | ||
|
|
7fc70ee1f4 | ||
|
|
d9b5f27311 | ||
|
|
252838d896 | ||
|
|
cb91ad3ae0 | ||
|
|
60f3d718ac | ||
|
|
e8e382372a | ||
|
|
205c365b1b | ||
|
|
09857008bd | ||
|
|
5eddc26850 | ||
|
|
496429d6f4 | ||
|
|
a915f185f8 | ||
|
|
0f6e1752e3 | ||
|
|
e57ccde532 | ||
|
|
f75a16f40c | ||
|
|
a869e183db | ||
|
|
c60edb0090 | ||
|
|
84d82f360b | ||
|
|
b002bdff39 | ||
|
|
5ffcdb5f1e | ||
|
|
79bbd86c2f | ||
|
|
39a212140a | ||
|
|
dddd712f08 | ||
|
|
a7dbbbe578 | ||
|
|
2445739c0e | ||
|
|
403f1f635b | ||
|
|
879372cb79 | ||
|
|
6b05c0ab01 | ||
|
|
289f264371 | ||
|
|
869ddb643d | ||
|
|
c63f1a9997 | ||
|
|
0fc0dc5101 | ||
|
|
213bc70e2d | ||
|
|
c839bc89eb | ||
|
|
84f2871650 | ||
|
|
e1b4d4d703 | ||
|
|
b564b0bf91 | ||
|
|
7e1dcf9003 | ||
|
|
0f4c903fed | ||
|
|
0ac483acfc | ||
|
|
f4835a89d3 | ||
|
|
139f248572 | ||
|
|
b23d37f76f | ||
|
|
56358be542 | ||
|
|
1377e61d03 | ||
|
|
ce694ba8b5 | ||
|
|
8eae6b97fc | ||
|
|
d29645cc49 | ||
|
|
f870ccc23c | ||
|
|
3aa2f922e7 | ||
|
|
129fff1c2a | ||
|
|
10b13dfe9c | ||
|
|
d506cc40a2 | ||
|
|
358a54152b | ||
|
|
06e2c455e8 | ||
|
|
a1838eee30 | ||
|
|
56b082def7 | ||
|
|
92a10ba0f0 | ||
|
|
c637ae8281 | ||
|
|
40953b17c4 | ||
|
|
a473154250 | ||
|
|
13f3c3e228 | ||
|
|
817cc87c8c | ||
|
|
ab09efa762 | ||
|
|
7061c043d9 | ||
|
|
92a19e9250 | ||
|
|
4f5fd31d81 | ||
|
|
1b565f9879 | ||
|
|
d2b475ae41 | ||
|
|
9c61006941 | ||
|
|
4db26bc092 | ||
|
|
8c0f543bc8 | ||
|
|
8e3a48eb6f | ||
|
|
7a22318b0f | ||
|
|
a0bf24f7cc | ||
|
|
3c6eaa4d34 | ||
|
|
3bf817aea1 | ||
|
|
a3ebe02f85 | ||
|
|
4eda9ebffc | ||
|
|
278f26aadd | ||
|
|
17b82ab5d3 | ||
|
|
30e66d1c17 | ||
|
|
2089015221 | ||
|
|
e19a62aa07 | ||
|
|
42d003597e | ||
|
|
f9da57d87f | ||
|
|
daf8230cca | ||
|
|
f02265b662 | ||
|
|
5eb893a995 | ||
|
|
dfd517706a | ||
|
|
b47f4f56ef | ||
|
|
a870fb7f6c | ||
|
|
7cd308fcae | ||
|
|
6e6f75386b | ||
|
|
aad4921e09 | ||
|
|
8b8113b482 | ||
|
|
98acd1178d | ||
|
|
0070f9abad | ||
|
|
dca048981f | ||
|
|
74b98d85ed | ||
|
|
67a7637b9f | ||
|
|
2511a19d2d | ||
|
|
f04ddad94f | ||
|
|
b4e5af6346 | ||
|
|
f679fd9ba9 | ||
|
|
b6930a2a9e | ||
|
|
4db7137dbf | ||
|
|
bee534922b | ||
|
|
d6fe46649c | ||
|
|
236539c881 | ||
|
|
2644c2ef47 | ||
|
|
f590766421 | ||
|
|
fa1c62d11a | ||
|
|
ffc0a42c18 | ||
|
|
bc3c1ab628 | ||
|
|
6c249ee4d2 | ||
|
|
3330f01267 | ||
|
|
bd946bfbea | ||
|
|
bb92e9f7a4 | ||
|
|
63686eeee1 | ||
|
|
c0a286532a | ||
|
|
ce0354f294 | ||
|
|
231a1b624f | ||
|
|
9b8fd39d12 | ||
|
|
90c4e42c11 | ||
|
|
ee806bc035 | ||
|
|
d76611730e | ||
|
|
bdd677d66a | ||
|
|
2299c9fade | ||
|
|
885714e883 | ||
|
|
f95c7212bf | ||
|
|
bb0da9488f | ||
|
|
1aeacb0297 | ||
|
|
b92b7a3ece | ||
|
|
0a1fe0135f | ||
|
|
4391058563 | ||
|
|
ea9bdd03e4 | ||
|
|
ed99c96232 | ||
|
|
755e17dc97 | ||
|
|
76af42ae6e | ||
|
|
e94babe57e | ||
|
|
416e4c5366 | ||
|
|
6b9840268f | ||
|
|
415d8c2ea3 | ||
|
|
3f456c6738 | ||
|
|
59480ea5a6 | ||
|
|
920666bc70 | ||
|
|
eebcb322cf | ||
|
|
04b0489ff3 | ||
|
|
dd5f44ff91 | ||
|
|
a7b89ba06a | ||
|
|
e5344d37d0 | ||
|
|
c07f862ef2 | ||
|
|
8b0add47a2 | ||
|
|
fe9ce46ab1 | ||
|
|
01c5c98396 | ||
|
|
d00f07acb8 | ||
|
|
83bfa9158d | ||
|
|
ac2637286b | ||
|
|
541544292a | ||
|
|
97bd3fc082 | ||
|
|
71ce2a2415 | ||
|
|
4b0d377e66 | ||
|
|
ae2bc8182f | ||
|
|
d9ec14e048 | ||
|
|
c0f0a758df | ||
|
|
06270e66c8 | ||
|
|
75fe707de3 | ||
|
|
1a5a2f64d4 | ||
|
|
220fd51b27 | ||
|
|
29cdc77817 | ||
|
|
483c59f2e4 | ||
|
|
1fdab613fd | ||
|
|
539b9e7746 | ||
|
|
045f693eef | ||
|
|
3192f84576 | ||
|
|
27038d4cf9 | ||
|
|
4acb670b88 | ||
|
|
79b9b49218 | ||
|
|
5f161df06b | ||
|
|
fc3b9046d8 | ||
|
|
754d2a53a0 | ||
|
|
e913bae9e3 | ||
|
|
22d228c1b0 | ||
|
|
d3a3cab425 | ||
|
|
1fe7352ed0 | ||
|
|
9d1a5cf0d3 | ||
|
|
c8a45d95a7 | ||
|
|
92a1c1891b | ||
|
|
858174791f | ||
|
|
fb4e653269 | ||
|
|
210100a108 | ||
|
|
edd1487378 | ||
|
|
68f4ce1ec5 | ||
|
|
c3c355a8c5 | ||
|
|
70d3e221a9 | ||
|
|
b556617e1d | ||
|
|
e327172fd0 | ||
|
|
c5f82483e6 | ||
|
|
a418b05272 | ||
|
|
5c3f66fe05 | ||
|
|
81ce3f7d10 | ||
|
|
64cfba735e | ||
|
|
8828b4fe52 | ||
|
|
87fdd203b5 | ||
|
|
187674ddac | ||
|
|
f94a08f12f | ||
|
|
252ad711f1 | ||
|
|
9d6bfd4786 | ||
|
|
d3690b12c6 | ||
|
|
32e08ca165 | ||
|
|
bc4f8fbe60 | ||
|
|
fd3deeb318 | ||
|
|
7108358ebd | ||
|
|
98daea0e97 | ||
|
|
48acb03b81 | ||
|
|
08ac485eac | ||
|
|
c033a81eca | ||
|
|
5df9127add | ||
|
|
b9e9cc534c | ||
|
|
79be464326 | ||
|
|
f67aad0b2d | ||
|
|
55b36fe719 | ||
|
|
7cce77cccd | ||
|
|
170f794c3a | ||
|
|
ae4bd79ca1 | ||
|
|
d76982bbeb | ||
|
|
fb4229c4ae | ||
|
|
caec338d25 | ||
|
|
b94200233d | ||
|
|
eb3ebe24e8 | ||
|
|
4514a4bfcc | ||
|
|
5e4e48fffe | ||
|
|
47a33f97f9 | ||
|
|
b36ef9da1e | ||
|
|
068861d0cc | ||
|
|
f2f8f3ccd2 | ||
|
|
2d7a1ce71a | ||
|
|
74d72eb257 | ||
|
|
9512ee657a | ||
|
|
78f80eb7dc | ||
|
|
fa525b4488 | ||
|
|
ee3e83e09c | ||
|
|
ea4354ba2e | ||
|
|
5c5c872afc | ||
|
|
9f2ffd102c | ||
|
|
34f8941868 | ||
|
|
07b217d9f8 | ||
|
|
cb83d319b9 | ||
|
|
23daa3efdf | ||
|
|
3a1ffceb58 | ||
|
|
f3431bd95d | ||
|
|
01c7250be2 | ||
|
|
e6bc36e110 | ||
|
|
afc1f5f4e1 | ||
|
|
4a2ad8b145 | ||
|
|
17ab0aba26 | ||
|
|
cc1b45b7cc | ||
|
|
4d990947de | ||
|
|
5542d6db21 | ||
|
|
8ca89ead0e | ||
|
|
ebf5f24487 | ||
|
|
90269d5204 | ||
|
|
e4332f6275 | ||
|
|
cd7168772d | ||
|
|
77ded80450 | ||
|
|
fbc69b6ae1 | ||
|
|
ea7dd699b9 | ||
|
|
018a852995 | ||
|
|
8a28ddbfe6 | ||
|
|
f186046c98 | ||
|
|
5644e834fa | ||
|
|
0b1f69bfd2 | ||
|
|
4eb5cd928e | ||
|
|
b8d47fe0a8 | ||
|
|
abcd9d77d4 | ||
|
|
095e5ede81 | ||
|
|
52754cbbbb | ||
|
|
ea9d048bc9 | ||
|
|
942224c685 | ||
|
|
670a25b039 | ||
|
|
cab02c86bc | ||
|
|
b4a67460e0 | ||
|
|
b56750df30 | ||
|
|
aa5fd64777 | ||
|
|
5a13b4df28 | ||
|
|
67bba95dd1 | ||
|
|
cd6152b193 | ||
|
|
67c070c20f | ||
|
|
2355bb8bb5 | ||
|
|
c4d24254db | ||
|
|
27b6bafd0f | ||
|
|
9cbdcc6260 | ||
|
|
192bbb715e | ||
|
|
014da3a225 | ||
|
|
803f4cd298 | ||
|
|
885a0508c0 | ||
|
|
a1472fb190 | ||
|
|
b86df7217c | ||
|
|
26815d042a | ||
|
|
026f21eddf | ||
|
|
30501aebb1 | ||
|
|
4014b1b574 | ||
|
|
8d54382b10 | ||
|
|
47dd8241b6 | ||
|
|
195da2adcc | ||
|
|
2b430eec6f | ||
|
|
d51e36998b | ||
|
|
a970a1263c | ||
|
|
cf9ccea70b | ||
|
|
f885cbb4ea | ||
|
|
97dfabc416 | ||
|
|
8d2b0749a0 | ||
|
|
a3acf4a8cc | ||
|
|
e505ab6019 | ||
|
|
9b24984b07 | ||
|
|
7ce08ea860 | ||
|
|
a156edbd73 | ||
|
|
9dae5827cc | ||
|
|
5da799244f | ||
|
|
bf79183bd6 | ||
|
|
afcb3b7ad8 | ||
|
|
5bfbcb210c | ||
|
|
4f65d45e55 | ||
|
|
3f8ecfedbb | ||
|
|
d8137a967c | ||
|
|
ffec935e2f | ||
|
|
253301ba4f | ||
|
|
a21b79cfbe | ||
|
|
3f4c24d350 | ||
|
|
645f413523 | ||
|
|
08478aa757 | ||
|
|
4aef8667b7 | ||
|
|
9d08da1fc9 | ||
|
|
4408aa7dbe | ||
|
|
d2e8c9465b | ||
|
|
04df0da7cb | ||
|
|
5eeddecb40 | ||
|
|
71aea45811 | ||
|
|
cf690fbb61 | ||
|
|
85b286ec47 | ||
|
|
07d0cf6839 | ||
|
|
5e43b603ac | ||
|
|
69d2cfd56d | ||
|
|
0f90293252 | ||
|
|
0d166e1403 | ||
|
|
b5879e6e1d | ||
|
|
5b169b7f9d | ||
|
|
099a758c94 | ||
|
|
638e5d233a | ||
|
|
a23362cee0 | ||
|
|
040db856f8 | ||
|
|
8d0654c323 | ||
|
|
cacfdbad90 | ||
|
|
811bf6f449 | ||
|
|
43f8f3e4ad | ||
|
|
a045c52146 | ||
|
|
98531e07ea | ||
|
|
5020a267af | ||
|
|
debe21de7b | ||
|
|
084066bde7 | ||
|
|
46d7dfc750 | ||
|
|
37c17e4300 | ||
|
|
3a21f545d8 | ||
|
|
f35167a0de | ||
|
|
0b6c09da02 | ||
|
|
d9c08bd081 | ||
|
|
927db7f189 | ||
|
|
badf36899e | ||
|
|
d3aed076a6 | ||
|
|
962b0bb65c | ||
|
|
6e940e4d08 | ||
|
|
90e9f70a1a | ||
|
|
bfdab4db20 | ||
|
|
f0e4574132 | ||
|
|
c461624a67 | ||
|
|
e6060aff6b | ||
|
|
d1e6ee9cd7 | ||
|
|
6480a6e4e5 | ||
|
|
6cfbdf6586 | ||
|
|
6b2063b06f | ||
|
|
301a7c5dcd | ||
|
|
e70a0dcf3d | ||
|
|
d1ab3461a6 | ||
|
|
b81a6762bc | ||
|
|
5875eda4d0 | ||
|
|
04c418d02a | ||
|
|
02a002d55b | ||
|
|
0305904873 | ||
|
|
ee84567c17 | ||
|
|
528235ce9d | ||
|
|
27ea6ca092 | ||
|
|
cb94354099 | ||
|
|
53dab29ddb | ||
|
|
b1479e6e34 | ||
|
|
ea3262f7b0 | ||
|
|
143073b61d | ||
|
|
c472d60f80 | ||
|
|
0c01075ba8 | ||
|
|
1149d499a8 | ||
|
|
85a941d6c6 | ||
|
|
0a27b63584 | ||
|
|
6f5f91245b | ||
|
|
234955ac01 | ||
|
|
99d5266aa0 | ||
|
|
a5967a283f | ||
|
|
21a4935ec4 | ||
|
|
610e3cf968 | ||
|
|
45c9d6185b | ||
|
|
e18a4afcbb | ||
|
|
499f86b065 | ||
|
|
80cf4406a7 | ||
|
|
cc4e3875f3 | ||
|
|
1c4871acb3 | ||
|
|
3b683648fa | ||
|
|
3923f10277 | ||
|
|
1a681746b5 | ||
|
|
5703ef26cf | ||
|
|
5096d50d37 | ||
|
|
f7e227a4aa | ||
|
|
bbff377ceb | ||
|
|
f8372c51a7 | ||
|
|
31debefbe1 | ||
|
|
c7d214e55a | ||
|
|
e3e2c3a0d2 | ||
|
|
f96ce85365 | ||
|
|
aa79196d38 | ||
|
|
2b14c3e605 | ||
|
|
41ba110ef4 | ||
|
|
ad42a32260 | ||
|
|
cc408f9688 | ||
|
|
520e96a039 | ||
|
|
db9fbbaebf | ||
|
|
88384ad7d1 | ||
|
|
464b459073 | ||
|
|
aea228c3df | ||
|
|
8cdd171ab7 | ||
|
|
9473c235f2 | ||
|
|
b443467770 | ||
|
|
a6bf9dd39c | ||
|
|
8fdcea2e20 | ||
|
|
31bd943d67 | ||
|
|
ba78a3aa5b | ||
|
|
1948c66c11 | ||
|
|
3cf7cf0a7f | ||
|
|
a593cddf52 | ||
|
|
cecf16e65e | ||
|
|
458b233e16 | ||
|
|
cca7ed6bf7 | ||
|
|
f63cf7406a | ||
|
|
e21d666328 | ||
|
|
ab3f5dbc4c | ||
|
|
528f15f117 | ||
|
|
7c72aa8a80 | ||
|
|
2420c05930 | ||
|
|
3a312f3814 | ||
|
|
bac67bd91a | ||
|
|
36e67203a4 | ||
|
|
a52d1c97ec | ||
|
|
9d3125c546 | ||
|
|
86a6d7a4f5 | ||
|
|
0f214b1441 | ||
|
|
a0b50cd41d | ||
|
|
1d1754dc98 | ||
|
|
b8464ef6c5 | ||
|
|
692ca52182 | ||
|
|
b4ecaecd45 | ||
|
|
9954768636 | ||
|
|
cbffc5cade | ||
|
|
4bbf5c562e | ||
|
|
329e5ed467 | ||
|
|
19a160695c | ||
|
|
1e195b7237 | ||
|
|
2b37a5dc08 | ||
|
|
8aadf5b097 | ||
|
|
13428ba696 | ||
|
|
52f2ca7ff6 | ||
|
|
174ce8786b | ||
|
|
fc118f295d | ||
|
|
18cfe2f92f | ||
|
|
0d4a7dbac9 | ||
|
|
a370851494 | ||
|
|
7b49cc73ee | ||
|
|
a8c5af8425 | ||
|
|
3441a9ccf0 | ||
|
|
659d21680b | ||
|
|
2da833883b | ||
|
|
c301bf0827 | ||
|
|
1c4303b76d | ||
|
|
170a6ac36e | ||
|
|
92fa4c041d | ||
|
|
f34a9f6eac | ||
|
|
9fb69af355 | ||
|
|
59606d8935 | ||
|
|
bd7f5ec4c1 | ||
|
|
d082993a7a | ||
|
|
640d4162b6 | ||
|
|
66eb08f2d1 | ||
|
|
93fbd67a85 | ||
|
|
cf031717dd | ||
|
|
075ec1cf98 | ||
|
|
8f3b6a2371 | ||
|
|
ac24d9be5b | ||
|
|
a0e800f102 | ||
|
|
7e4572a86a | ||
|
|
4f0d3a958d | ||
|
|
06c5ba7f0e | ||
|
|
673fb26d6e | ||
|
|
5fa98da17e | ||
|
|
9b2f33f7bd | ||
|
|
2b70c73f80 | ||
|
|
1aec64cbae | ||
|
|
611946559c | ||
|
|
2997c6396f | ||
|
|
859d5df056 | ||
|
|
8a1902e5a8 | ||
|
|
285655f52d | ||
|
|
fceb170a2a | ||
|
|
4376e89149 | ||
|
|
cbd1d3134e | ||
|
|
fc479dbcc0 | ||
|
|
ae47ac19b8 | ||
|
|
84f6bd3fef | ||
|
|
d3b2da8e3b | ||
|
|
493ccc27d1 | ||
|
|
b37e6dc28d | ||
|
|
8cd6a94e26 | ||
|
|
13df32ba3f | ||
|
|
262a39cafb | ||
|
|
480f2e31b0 | ||
|
|
d0bb0aea97 | ||
|
|
bf3f927a99 | ||
|
|
19818e717f | ||
|
|
b6491a3842 | ||
|
|
c04c696ba6 | ||
|
|
17474bf005 | ||
|
|
756ec0e672 | ||
|
|
3dfdb60139 | ||
|
|
5a409dbe2c | ||
|
|
9ef37d9776 | ||
|
|
ba0a357d48 | ||
|
|
659ffa4406 | ||
|
|
12bba31270 | ||
|
|
dd66e44871 | ||
|
|
c5c87522ca | ||
|
|
5ef80f0a17 | ||
|
|
7372df3aff | ||
|
|
cf514b0d6b | ||
|
|
b232a10167 | ||
|
|
2a465d2f03 | ||
|
|
802f70fedd | ||
|
|
5acfa7d3d6 | ||
|
|
85188bf137 | ||
|
|
bfc44f2b4e | ||
|
|
96aaa8b14a | ||
|
|
53ed006a54 | ||
|
|
171c41df12 | ||
|
|
4b53edb3bd | ||
|
|
62085539a7 | ||
|
|
1c8e558e25 | ||
|
|
568145c247 | ||
|
|
5703bc7df2 | ||
|
|
95a00a165a | ||
|
|
599bc8a823 | ||
|
|
9578841480 | ||
|
|
5387a6b534 | ||
|
|
bf09e96e04 | ||
|
|
b5d8cecd91 | ||
|
|
6d913f42c8 | ||
|
|
1e0a875fa3 | ||
|
|
4d77ce5a66 | ||
|
|
f3a6fb7d8b | ||
|
|
b6f73d96ca | ||
|
|
13f3c8281f | ||
|
|
0107435a73 | ||
|
|
ce674a872a | ||
|
|
51758b965e | ||
|
|
7fec511463 | ||
|
|
1dd006d846 | ||
|
|
2800927fa1 | ||
|
|
f133e3cccb | ||
|
|
b0a520fe18 | ||
|
|
3f30dd01ad | ||
|
|
0c081a9597 | ||
|
|
7176460de3 | ||
|
|
733a1fa73d | ||
|
|
e3809ba058 | ||
|
|
4d3de39c64 | ||
|
|
1765e50703 | ||
|
|
f9feaa313b | ||
|
|
9781d8971a | ||
|
|
a0a9b5bbc5 | ||
|
|
c684faf423 | ||
|
|
cdca559d99 | ||
|
|
d76dff8594 | ||
|
|
223504a206 | ||
|
|
1ab4eb00c0 | ||
|
|
32e3e7d9c5 | ||
|
|
98123b9215 | ||
|
|
9069a49145 | ||
|
|
d417237e64 | ||
|
|
648f33473f | ||
|
|
446619ce85 | ||
|
|
f5fa1f6210 | ||
|
|
976fb99aa3 | ||
|
|
a0529d1cfc | ||
|
|
8001af9743 | ||
|
|
e48b72a859 | ||
|
|
71ba018782 | ||
|
|
59ff44132b | ||
|
|
8a0323ec08 | ||
|
|
4c7df6c7f4 | ||
|
|
676cd3104b | ||
|
|
a40210c55c | ||
|
|
034f90c1e0 | ||
|
|
64223927b8 | ||
|
|
e2c03255bb | ||
|
|
63495d3a6a | ||
|
|
88466ec352 | ||
|
|
1995eb935b | ||
|
|
f6532ca27a | ||
|
|
75dd5305c4 | ||
|
|
76cf989455 | ||
|
|
5b8e932509 | ||
|
|
993b705d8b | ||
|
|
19204882c4 | ||
|
|
605dc59f8d | ||
|
|
2332884d8b | ||
|
|
94f3d80a75 | ||
|
|
0b0e64304e | ||
|
|
5a1a766bd4 | ||
|
|
c15f446ffc | ||
|
|
c88cdde9ec | ||
|
|
40dbf53792 | ||
|
|
0cbf6f6601 | ||
|
|
c8fc873cf9 | ||
|
|
b935bef906 | ||
|
|
c1f0dd81d2 | ||
|
|
5722dc90f0 | ||
|
|
e3c260f4ca | ||
|
|
d1e48c657e | ||
|
|
decf70c87c | ||
|
|
4de9076b49 | ||
|
|
922df88cdd | ||
|
|
f25aeee756 | ||
|
|
2b36953fdc | ||
|
|
1dcf302665 | ||
|
|
1fd95c2886 | ||
|
|
93e1d7fcee | ||
|
|
b2b860bb8e | ||
|
|
0bd88fc9d9 | ||
|
|
20f9450218 | ||
|
|
401c402afc | ||
|
|
77a105d888 | ||
|
|
257c6b729f | ||
|
|
c5c941e928 | ||
|
|
092006fbbe | ||
|
|
6add19fb04 | ||
|
|
02d4b821d7 | ||
|
|
3d00ac338b | ||
|
|
387b9778f3 | ||
|
|
582876b99e | ||
|
|
3b3391c0d1 | ||
|
|
df61b1046a | ||
|
|
8426bcad27 | ||
|
|
d22fa54f7b | ||
|
|
2d56dddf7a | ||
|
|
7da0549b8c | ||
|
|
b821ece052 | ||
|
|
b240da41e0 | ||
|
|
d85baba1d3 | ||
|
|
8a44b909a4 | ||
|
|
5362264b18 | ||
|
|
1858cf3b33 | ||
|
|
1f876cde39 | ||
|
|
7288c7b541 | ||
|
|
2b8f5a7b9d | ||
|
|
c2e1425209 | ||
|
|
c9c1218234 | ||
|
|
11d776aea1 | ||
|
|
1386744fe0 | ||
|
|
da0d012328 | ||
|
|
f88abf9987 | ||
|
|
4a4fa7792f | ||
|
|
73adbc660b | ||
|
|
e0d87eb093 | ||
|
|
85b8c599c4 | ||
|
|
71e9420929 | ||
|
|
a6ac753c64 | ||
|
|
55600c40a9 | ||
|
|
9070c246d4 | ||
|
|
19ccc6a38d | ||
|
|
ad8b41adb0 | ||
|
|
807b8dea91 | ||
|
|
8e8935b9c4 | ||
|
|
9d17fc15a3 | ||
|
|
1cadd4e923 | ||
|
|
ab791d1b9c | ||
|
|
4f206d2773 | ||
|
|
7f9d9b81aa | ||
|
|
19112aecb2 | ||
|
|
b5b0875203 | ||
|
|
9a557978c4 | ||
|
|
7f28b767e4 | ||
|
|
5f5a748031 | ||
|
|
7bcd8c819a | ||
|
|
7209a61583 | ||
|
|
1523fafce0 | ||
|
|
3915c55251 | ||
|
|
5259aa20e6 | ||
|
|
11ecb473b6 | ||
|
|
7982fdac1c | ||
|
|
54d92a11e8 | ||
|
|
5eb302898f | ||
|
|
5b3a414987 | ||
|
|
658e111e3c | ||
|
|
d08f0e6599 | ||
|
|
77a11d2a2e |
No files matched your search
-14
@@ -1,14 +0,0 @@
|
||||
freebsd_instance:
|
||||
image_family: freebsd-13-0
|
||||
|
||||
env:
|
||||
CCACHE_DIR: /tmp/ccache
|
||||
CIRRUS_CLONE_SUBMODULES: true
|
||||
|
||||
task:
|
||||
install_script: pkg install -y alsa-lib ccache cmake evdev-proto git libao libevdev libudev-devd libzip mesa-libs miniupnpc ninja pkgconf png pulseaudio sdl2
|
||||
ccache_cache:
|
||||
folder: /tmp/ccache
|
||||
script:
|
||||
- cmake -B build -DCMAKE_BUILD_TYPE=Release -G Ninja
|
||||
- cmake --build build --config Release
|
||||
+2
-1
@@ -1 +1,2 @@
|
||||
custom: ['https://utip.io/flyinghead', 'https://www.paypal.com/paypalme/FlycastEmu']
|
||||
buy_me_a_coffee: hhwtpernwq
|
||||
custom: ['https://www.paypal.com/paypalme/FlycastEmu']
|
||||
@@ -12,33 +12,44 @@ jobs:
|
||||
sudo apt-get update
|
||||
sudo apt-get -y install ccache libcurl4-openssl-dev ninja-build
|
||||
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
submodules: true
|
||||
submodules: recursive
|
||||
|
||||
- uses: actions/setup-java@v4
|
||||
with:
|
||||
java-version: '17'
|
||||
distribution: 'temurin'
|
||||
cache: 'gradle'
|
||||
|
||||
- uses: actions/cache@v3
|
||||
- uses: actions/cache@v4
|
||||
with:
|
||||
path: ~/.ccache
|
||||
key: android-ccache-${{ github.sha }}
|
||||
restore-keys: android-ccache-
|
||||
|
||||
- uses: actions/cache@v3
|
||||
- name: Bump version code
|
||||
uses: chkfung/[email protected]
|
||||
with:
|
||||
path: |
|
||||
~/.gradle/caches
|
||||
~/.gradle/wrapper
|
||||
key: android-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
|
||||
restore-keys: android-gradle-
|
||||
gradlePath: shell/android-studio/flycast/build.gradle
|
||||
versionCode: ${{ github.run_number }}
|
||||
|
||||
- name: Gradle
|
||||
working-directory: shell/android-studio
|
||||
run: ./gradlew assembleRelease --parallel
|
||||
run: ./gradlew bundleRelease --parallel
|
||||
env:
|
||||
SENTRY_UPLOAD_URL: ${{ secrets.SENTRY_UPLOAD_URL }}
|
||||
ANDROID_KEYSTORE_PASSWORD: ${{ secrets.ANDROID_KEYSTORE_PASSWORD }}
|
||||
|
||||
- uses: actions/upload-artifact@v3
|
||||
- name: Upload to Google Play
|
||||
uses: r0adkll/[email protected]
|
||||
with:
|
||||
name: flycast-release.apk
|
||||
path: shell/android-studio/flycast/build/outputs/apk/release/flycast-release.apk
|
||||
serviceAccountJsonPlainText: ${{ secrets.PLAY_SERVICE_ACCOUNT_JSON }}
|
||||
packageName: com.flycast.emulator
|
||||
releaseFiles: shell/android-studio/flycast/build/outputs/bundle/release/flycast-release.aab
|
||||
track: internal
|
||||
status: draft
|
||||
|
||||
- name: Build dump_syms
|
||||
working-directory: core/deps/breakpad
|
||||
@@ -50,7 +61,7 @@ jobs:
|
||||
- name: Extract symbols
|
||||
run: |
|
||||
DUMP_SYMS=./core/deps/breakpad/bin/dump_syms
|
||||
SO_DIR=shell/android-studio/flycast/build/intermediates/cmake/release/obj
|
||||
SO_DIR=shell/android-studio/flycast/build/intermediates/merged_native_libs/release/mergeReleaseNativeLibs/out/lib
|
||||
for arch in arm64-v8a armeabi-v7a x86 x86_64 ; do
|
||||
$DUMP_SYMS $SO_DIR/$arch/libflycast.so > libflycast.so.sym
|
||||
BUILD_ID=`head -1 libflycast.so.sym | awk '{ print $4 }'`
|
||||
@@ -58,19 +69,25 @@ jobs:
|
||||
mv libflycast.so.sym symbols/libflycast.so/$BUILD_ID
|
||||
done
|
||||
|
||||
- name: Configure AWS Credentials
|
||||
id: aws-credentials
|
||||
uses: aws-actions/configure-aws-credentials@v1
|
||||
- name: Setup Sentry CLI
|
||||
uses: mathieu-bour/setup-sentry-cli@v2
|
||||
env:
|
||||
SENTRY_TOKEN: ${{ secrets.SENTRY_TOKEN }}
|
||||
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'
|
||||
|
||||
- name: Upload to S3
|
||||
run: 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 != '' }}
|
||||
|
||||
- name: Upload to S3 (symbols)
|
||||
run: aws s3 sync symbols s3://flycast-symbols/android --follow-symlinks
|
||||
if: ${{ steps.aws-credentials.outputs.aws-account-id != '' }}
|
||||
url: https://sentry.io
|
||||
token: ${{ env.SENTRY_TOKEN }}
|
||||
organization: flycast
|
||||
project: minidump
|
||||
version: 2.21.2
|
||||
if: ${{ env.SENTRY_TOKEN != '' }}
|
||||
|
||||
- name: Upload symbols to Sentry
|
||||
run: |
|
||||
VERSION=$(git describe --tags --always)
|
||||
sentry-cli releases new "$VERSION"
|
||||
sentry-cli releases set-commits "$VERSION" --auto
|
||||
sentry-cli debug-files upload symbols
|
||||
shell: bash
|
||||
env:
|
||||
SENTRY_TOKEN: ${{ secrets.SENTRY_TOKEN }}
|
||||
if: ${{ env.SENTRY_TOKEN != '' }}
|
||||
@@ -1,136 +0,0 @@
|
||||
name: C/C++ CI
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: ${{ matrix.config.name }}
|
||||
runs-on: ${{ matrix.config.os }}
|
||||
|
||||
defaults:
|
||||
run:
|
||||
shell: ${{ matrix.config.shell }}
|
||||
|
||||
env:
|
||||
CCACHE_DIR: ${{ github.workspace }}/.ccache
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
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 -DAPPLE_BREAKPAD=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-latest, shell: sh, cmakeArgs: -G Ninja, buildType: Release}
|
||||
- {name: x86_64-pc-windows-msvc, os: windows-latest, shell: cmd, arch: x64, cmakeArgs: -G Ninja, buildType: Release}
|
||||
- {name: x86_64-w64-mingw32, os: windows-latest, shell: 'msys2 {0}', cmakeArgs: -G Ninja, 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}
|
||||
|
||||
steps:
|
||||
- name: Set up build environment (macOS)
|
||||
run: |
|
||||
brew update
|
||||
brew install libao ldid ninja pulseaudio
|
||||
VULKAN_VER=1.3.211.0 && aria2c --parameterized-uri=true https://{sdk.lunarg.com/sdk/download/$VULKAN_VER/mac,distfiles.macports.org/MoltenVK}/vulkansdk-macos-$VULKAN_VER.dmg
|
||||
hdiutil attach ./vulkansdk-macos-*.dmg
|
||||
sudo /Volumes/vulkansdk-macos-*/InstallVulkan.app/Contents/MacOS/InstallVulkan --root $HOME/VulkanSDK --accept-licenses --default-answer --confirm-command install
|
||||
hdiutil detach /Volumes/vulkansdk-macos-*
|
||||
echo "VULKAN_SDK=$HOME/VulkanSDK/macOS" >> $GITHUB_ENV
|
||||
if: runner.os == 'macOS'
|
||||
|
||||
- name: Set up build environment (Linux)
|
||||
run: |
|
||||
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
|
||||
if: runner.os == 'Linux'
|
||||
|
||||
- name: Set up build environment (Windows, MinGW)
|
||||
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
|
||||
if: matrix.config.shell == 'msys2 {0}'
|
||||
|
||||
- name: Set up build environment (Windows, Visual Studio)
|
||||
run: |
|
||||
choco install ccache directx-sdk ninja
|
||||
echo DXSDK_DIR=C:\Program Files (x86)\Microsoft DirectX SDK (June 2010)>> %GITHUB_ENV%
|
||||
if: matrix.config.shell == 'cmd'
|
||||
|
||||
- uses: ilammy/msvc-dev-cmd@v1
|
||||
with:
|
||||
arch: ${{ matrix.config.arch }}
|
||||
if: matrix.config.shell == 'cmd'
|
||||
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
submodules: true
|
||||
|
||||
- name: Compile a universal OpenMP (macOS)
|
||||
run: export HOMEBREW_NO_INSTALLED_DEPENDENTS_CHECK=1; brew reinstall --build-from-source --formula ./shell/apple/libomp.rb
|
||||
if: runner.os == 'macOS'
|
||||
|
||||
- uses: actions/cache@v3
|
||||
with:
|
||||
path: ${{ env.CCACHE_DIR }}
|
||||
key: ccache-${{ matrix.config.name }}-${{ github.sha }}
|
||||
restore-keys: ccache-${{ matrix.config.name }}-
|
||||
if: runner.os != 'macOS'
|
||||
|
||||
- name: CMake
|
||||
run: |
|
||||
cmake -B build -DCMAKE_BUILD_TYPE=${{ matrix.config.buildType }} -DCMAKE_INSTALL_PREFIX=artifact ${{ matrix.config.cmakeArgs }}
|
||||
cmake --build build --config ${{ matrix.config.buildType }} --target install
|
||||
|
||||
- name: Unit Tests
|
||||
run: |
|
||||
cmake -B build -DCMAKE_BUILD_TYPE=${{ matrix.config.buildType }} -DCMAKE_INSTALL_PREFIX=artifact -DENABLE_CTEST=ON ${{ matrix.config.cmakeArgs }}
|
||||
cmake --build build --config ${{ matrix.config.buildType }}
|
||||
./build/flycast
|
||||
if: matrix.config.name == 'x86_64-pc-linux-gnu'
|
||||
|
||||
- name: Dump symbols
|
||||
run: |
|
||||
core/deps/breakpad/bin/dump_syms artifact/bin/flycast.exe > flycast.exe.sym 2>/dev/null
|
||||
BUILD_ID=`head -1 flycast.exe.sym | awk '{ print $4 }'`
|
||||
mkdir -p symbols/flycast.exe/$BUILD_ID
|
||||
mv flycast.exe.sym symbols/flycast.exe/$BUILD_ID
|
||||
strip artifact/bin/flycast.exe
|
||||
if: matrix.config.name == 'x86_64-w64-mingw32'
|
||||
|
||||
- uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: flycast-${{ matrix.config.name }}
|
||||
path: artifact/bin
|
||||
|
||||
- name: Package app (macos)
|
||||
run: |
|
||||
cd artifact/bin
|
||||
zip -rm flycast.app.zip Flycast.app
|
||||
if: matrix.config.name == 'apple-darwin'
|
||||
|
||||
- name: Package app (windows)
|
||||
run: |
|
||||
powershell Compress-Archive artifact/bin/flycast.exe artifact/bin/flycast.zip
|
||||
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@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 != ''
|
||||
|
||||
- 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
|
||||
shell: bash
|
||||
if: ${{ steps.aws-credentials.outputs.aws-account-id != '' }}
|
||||
|
||||
- name: Upload symbols to S3 (Windows-MinGW, macOS)
|
||||
run: aws s3 sync symbols s3://flycast-symbols/${{ matrix.config.destDir }} --follow-symlinks
|
||||
shell: bash
|
||||
if: ${{ steps.aws-credentials.outputs.aws-account-id != '' && (matrix.config.name == 'x86_64-w64-mingw32' || matrix.config.name == 'apple-darwin') }}
|
||||
@@ -1,34 +0,0 @@
|
||||
# Prepare source texts & upload them to Crowdin
|
||||
|
||||
name: Crowdin Source Texts Upload
|
||||
|
||||
# on change to the English texts
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
paths:
|
||||
- 'shell/libretro/libretro_core_options.h'
|
||||
|
||||
jobs:
|
||||
upload_source_file:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Setup Java JDK
|
||||
uses: actions/setup-java@v3
|
||||
with:
|
||||
distribution: 'temurin'
|
||||
java-version: 8
|
||||
|
||||
- name: Setup Python
|
||||
uses: actions/setup-python@v3
|
||||
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Upload Source
|
||||
shell: bash
|
||||
env:
|
||||
CROWDIN_API_KEY: ${{ secrets.CROWDIN_API_KEY }}
|
||||
run: |
|
||||
python3 intl/upload_workflow.py $CROWDIN_API_KEY "flyinghead-flycast" "shell/libretro/libretro_core_options.h"
|
||||
@@ -1,47 +0,0 @@
|
||||
# Download translations form Crowdin & Recreate libretro_core_options_intl.h
|
||||
|
||||
name: Crowdin Translation Integration
|
||||
|
||||
on:
|
||||
schedule:
|
||||
# please choose a random time & weekday to avoid all repos synching at the same time
|
||||
- cron: '15 22 * * 5' # Fridays at 10:15 PM, UTC
|
||||
|
||||
jobs:
|
||||
create_intl_file:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Setup Java JDK
|
||||
uses: actions/setup-java@v3
|
||||
with:
|
||||
distribution: 'temurin'
|
||||
java-version: 8
|
||||
|
||||
- name: Setup Python
|
||||
uses: actions/setup-python@v3
|
||||
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
persist-credentials: false # otherwise, the token used is the GITHUB_TOKEN, instead of your personal access token.
|
||||
fetch-depth: 0 # otherwise, there would be errors pushing refs to the destination repository.
|
||||
|
||||
- name: Create intl file
|
||||
shell: bash
|
||||
env:
|
||||
CROWDIN_API_KEY: ${{ secrets.CROWDIN_API_KEY }}
|
||||
run: |
|
||||
python3 intl/download_workflow.py $CROWDIN_API_KEY "flyinghead-flycast" "shell/libretro/libretro_core_options_intl.h"
|
||||
|
||||
- name: Commit files
|
||||
run: |
|
||||
git config --local user.email "[email protected]"
|
||||
git config --local user.name "github-actions[bot]"
|
||||
git add intl/*_workflow.py "shell/libretro/libretro_core_options_intl.h"
|
||||
git commit -m "Fetch translations & Recreate libretro_core_options_intl.h"
|
||||
|
||||
- name: GitHub Push
|
||||
uses: ad-m/[email protected]
|
||||
with:
|
||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
branch: ${{ github.ref }}
|
||||
@@ -1,59 +0,0 @@
|
||||
name: Nintendo Switch CI
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: ${{ matrix.config.name }}
|
||||
runs-on: ubuntu-latest
|
||||
container: devkitpro/devkita64:20220128
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
config:
|
||||
- {name: standalone, destDir: switch}
|
||||
- {name: libretro, cmakeArgs: -DLIBRETRO=ON}
|
||||
|
||||
steps:
|
||||
- name: Set up build environment
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get -y install awscli ccache ninja-build
|
||||
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
submodules: true
|
||||
|
||||
- uses: actions/cache@v3
|
||||
with:
|
||||
path: ~/.ccache
|
||||
key: ccache-switch-${{ matrix.config.name }}-${{ github.sha }}
|
||||
restore-keys: ccache-switch-${{ matrix.config.name }}-
|
||||
|
||||
- name: CMake
|
||||
run: |
|
||||
$DEVKITPRO/portlibs/switch/bin/aarch64-none-elf-cmake -B build -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=artifact -G Ninja ${{ matrix.config.cmakeArgs }}
|
||||
cmake --build build --config Release --target install
|
||||
|
||||
- uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: flycast-switch-${{ matrix.config.name }}
|
||||
path: artifact/bin
|
||||
|
||||
- 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@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 != ''
|
||||
|
||||
- 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 != '' }}
|
||||
@@ -1,69 +0,0 @@
|
||||
name: Windows UWP CI
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: windows-latest
|
||||
|
||||
env:
|
||||
VCPKG_ROOT: ${{ github.workspace }}/vcpkg
|
||||
VCPKG_DEFAULT_BINARY_CACHE: ${{ github.workspace }}/vcpkg/bincache
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
submodules: true
|
||||
|
||||
- name: bootstrap vcpkg
|
||||
run: |
|
||||
git clone https://github.com/microsoft/vcpkg
|
||||
mkdir vcpkg\bincache
|
||||
vcpkg\bootstrap-vcpkg.bat
|
||||
|
||||
- uses: actions/cache@v3
|
||||
with:
|
||||
path: ${{ env.VCPKG_DEFAULT_BINARY_CACHE }}
|
||||
key: vcpkg-${{ hashFiles( 'vcpkg.json' ) }}
|
||||
|
||||
- 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 -DCMAKE_SYSTEM_PROCESSOR=AMD64 -DCMAKE_CROSSCOMPILING=OFF -DCMAKE_TOOLCHAIN_FILE=%VCPKG_ROOT%\scripts\buildsystems\vcpkg.cmake
|
||||
cmake --build build --config Release --parallel 2
|
||||
shell: cmd
|
||||
|
||||
- uses: ilammy/msvc-dev-cmd@v1
|
||||
|
||||
- name: Package app
|
||||
run: |
|
||||
mkdir build\artifact
|
||||
cd build\AppPackages\flycast\flycast_*_x64_Test
|
||||
mkdir tmp
|
||||
ren *.msix flycast.msix
|
||||
makeappx.exe unpack /p .\flycast.msix /d tmp
|
||||
copy ..\..\..\Release\*.dll tmp
|
||||
makeappx pack /d tmp /p ..\..\..\artifact\flycast.appx
|
||||
|
||||
- name: Sign app
|
||||
run: signtool sign /f shell\uwp\sign_cert.pfx /p '${{ secrets.SIGN_CERT_PWD }}' /v /fd SHA256 build\artifact\flycast.appx
|
||||
if: github.repository == 'flyinghead/flycast' && github.event_name == 'push'
|
||||
|
||||
- uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: flycast-uwp
|
||||
path: build/artifact
|
||||
|
||||
- name: Configure AWS Credentials
|
||||
id: aws-credentials
|
||||
uses: aws-actions/configure-aws-credentials@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'
|
||||
|
||||
- name: Upload to S3
|
||||
run: aws s3 sync build/artifact s3://flycast-builds/xbox/${GITHUB_REF#refs/}-$GITHUB_SHA --acl public-read --follow-symlinks
|
||||
shell: bash
|
||||
if: ${{ steps.aws-credentials.outputs.aws-account-id != '' }}
|
||||
@@ -1,12 +1,19 @@
|
||||
build/
|
||||
artifact/
|
||||
|
||||
# macOS
|
||||
.DS_Store
|
||||
shell/apple/emulator-ios/OpenMP/OpenMP.xcframework
|
||||
|
||||
# Visual Studio
|
||||
.vs/
|
||||
.vscode/
|
||||
out/
|
||||
|
||||
# JetBrains IDES
|
||||
.idea/
|
||||
cmake-build-*/
|
||||
|
||||
# Dependencies from .gitmodules
|
||||
core/deps/breakpad/
|
||||
core/deps/glslang/
|
||||
@@ -17,11 +17,22 @@
|
||||
CORE_ARGS: -DLIBRETRO=ON -DCMAKE_POSITION_INDEPENDENT_CODE=TRUE -DCMAKE_BUILD_TYPE=Release
|
||||
|
||||
.core-defs-osx-x64:
|
||||
extends: .core-defs
|
||||
variables:
|
||||
CORE_ARGS: -DLIBRETRO=ON -G Xcode -DCMAKE_BUILD_TYPE=Release -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
|
||||
EXTRA_PATH: Release
|
||||
|
||||
.core-defs-ios-arm64:
|
||||
extends: .core-defs
|
||||
variables:
|
||||
CORE_ARGS: -DLIBRETRO=ON -DCMAKE_BUILD_TYPE=Release
|
||||
|
||||
.core-defs-android:
|
||||
extends: .core-defs
|
||||
script:
|
||||
@@ -43,6 +54,10 @@ include:
|
||||
- project: 'libretro-infrastructure/ci-templates'
|
||||
file: 'osx-cmake-x86.yml'
|
||||
|
||||
# MacOS arm64
|
||||
- project: 'libretro-infrastructure/ci-templates'
|
||||
file: 'osx-cmake-arm64.yml'
|
||||
|
||||
# Linux
|
||||
- project: 'libretro-infrastructure/ci-templates'
|
||||
file: '/linux-cmake.yml'
|
||||
@@ -52,11 +67,19 @@ include:
|
||||
- project: 'libretro-infrastructure/ci-templates'
|
||||
file: '/android-cmake.yml'
|
||||
|
||||
# iOS arm64
|
||||
- project: 'libretro-infrastructure/ci-templates'
|
||||
file: '/ios-cmake.yml'
|
||||
|
||||
################################## CONSOLES ################################
|
||||
# Nintendo Switch
|
||||
# - project: 'libretro-infrastructure/ci-templates'
|
||||
# file: '/libnx-static.yml'
|
||||
|
||||
# tvOS arm64
|
||||
- project: 'libretro-infrastructure/ci-templates'
|
||||
file: '/tvos-cmake.yml'
|
||||
|
||||
# Stages for building
|
||||
stages:
|
||||
- build-prepare
|
||||
@@ -98,6 +121,12 @@ libretro-build-osx-x64:
|
||||
- .libretro-osx-cmake-x86
|
||||
- .core-defs-osx-x64
|
||||
|
||||
# MacOS arm 64-bit
|
||||
libretro-build-osx-arm64:
|
||||
extends:
|
||||
- .libretro-osx-cmake-arm64
|
||||
- .core-defs-osx-arm64
|
||||
|
||||
################################### CELLULAR #################################
|
||||
# Android ARMv7a
|
||||
android-armeabi-v7a:
|
||||
@@ -123,9 +152,20 @@ android-x86:
|
||||
- .libretro-android-cmake-x86
|
||||
- .core-defs-android
|
||||
|
||||
libretro-build-ios-arm64:
|
||||
extends:
|
||||
- .libretro-ios-cmake-arm64
|
||||
- .core-defs-ios-arm64
|
||||
|
||||
################################### CONSOLES #################################
|
||||
# Nintendo Switch
|
||||
#libretro-build-libnx-aarch64:
|
||||
# extends:
|
||||
# - .libretro-libnx-static-retroarch-master
|
||||
# - .core-defs
|
||||
|
||||
# tvOS arm64
|
||||
libretro-build-tvos-arm64:
|
||||
extends:
|
||||
- .libretro-tvos-cmake-arm64
|
||||
- .core-defs-ios-arm64
|
||||
+31
@@ -4,9 +4,40 @@
|
||||
[submodule "core/deps/libchdr"]
|
||||
path = core/deps/libchdr
|
||||
url = https://github.com/rtissera/libchdr.git
|
||||
ignore = dirty
|
||||
[submodule "core/deps/luabridge"]
|
||||
path = core/deps/luabridge
|
||||
url = https://github.com/vinniefalco/LuaBridge.git
|
||||
[submodule "core/deps/breakpad"]
|
||||
path = core/deps/breakpad
|
||||
url = https://github.com/flyinghead/mingw-breakpad
|
||||
[submodule "core/deps/Vulkan-Headers"]
|
||||
path = core/deps/Vulkan-Headers
|
||||
url = https://github.com/KhronosGroup/Vulkan-Headers.git
|
||||
[submodule "core/deps/VulkanMemoryAllocator"]
|
||||
path = core/deps/VulkanMemoryAllocator
|
||||
url = https://github.com/GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator.git
|
||||
[submodule "core/deps/glslang"]
|
||||
path = core/deps/glslang
|
||||
url = https://github.com/KhronosGroup/glslang.git
|
||||
[submodule "core/deps/oboe"]
|
||||
path = core/deps/oboe
|
||||
url = https://github.com/google/oboe.git
|
||||
[submodule "core/deps/Syphon"]
|
||||
path = core/deps/Syphon
|
||||
url = https://github.com/vkedwardli/Syphon-Framework.git
|
||||
[submodule "core/deps/Spout"]
|
||||
path = core/deps/Spout
|
||||
url = https://github.com/vkedwardli/Spout2.git
|
||||
[submodule "core/deps/discord-rpc"]
|
||||
path = core/deps/discord-rpc
|
||||
url = https://github.com/flyinghead/discord-rpc
|
||||
[submodule "core/deps/libadrenotools"]
|
||||
path = core/deps/libadrenotools
|
||||
url = https://github.com/bylaws/libadrenotools
|
||||
[submodule "core/deps/rcheevos"]
|
||||
path = core/deps/rcheevos
|
||||
url = https://github.com/RetroAchievements/rcheevos.git
|
||||
[submodule "core/deps/googletest"]
|
||||
path = core/deps/googletest
|
||||
url = https://github.com/google/googletest.git
|
||||
+1214
-872
File diff suppressed because it is too large.
Load diff
@@ -4,6 +4,7 @@
|
||||
[](https://github.com/flyinghead/flycast/actions/workflows/c-cpp.yml)
|
||||
[](https://github.com/flyinghead/flycast/actions/workflows/switch.yml)
|
||||
[](https://github.com/flyinghead/flycast/actions/workflows/uwp.yml)
|
||||
[](https://github.com/flyinghead/flycast/actions/workflows/bsd.yml)
|
||||
|
||||

|
||||
|
||||
@@ -15,7 +16,7 @@ Join us on our [**Discord server**](https://discord.gg/X8YWP8w) for a chat.
|
||||
|
||||
## Install
|
||||
|
||||
### Flatpak (Linux)
|
||||
### Flatpak (Linux )
|
||||
|
||||
1. [Set up Flatpak](https://www.flatpak.org/setup/).
|
||||
|
||||
@@ -27,7 +28,7 @@ Join us on our [**Discord server**](https://discord.gg/X8YWP8w) for a chat.
|
||||
|
||||
`flatpak run org.flycast.Flycast`
|
||||
|
||||
### Homebrew (MacOS)
|
||||
### Homebrew (MacOS )
|
||||
|
||||
1. [Set up Homebrew](https://brew.sh).
|
||||
|
||||
@@ -35,16 +36,21 @@ Join us on our [**Discord server**](https://discord.gg/X8YWP8w) for a chat.
|
||||
|
||||
`brew install --cask flycast`
|
||||
|
||||
### Xbox One/Series
|
||||
### Xbox One/Series 
|
||||
|
||||
#### Retail:
|
||||
Open [**gamr13's github page**](https://gamr13.github.io/) from your Xbox console.
|
||||
|
||||
#### Dev Mode:
|
||||
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**.
|
||||
|
||||
### Binaries
|
||||
### Binaries      
|
||||
|
||||
Get fresh builds for your system [**on the builds page**](https://flyinghead.github.io/flycast-builds/).
|
||||
|
||||
**New:** Now automated test results are available as well.
|
||||
|
||||
### Build instructions:
|
||||
```
|
||||
$ git clone --recursive https://github.com/flyinghead/flycast.git
|
||||
$ cd flycast
|
||||
$ mkdir build && cd build
|
||||
$ cmake ..
|
||||
$ make
|
||||
```
|
||||
+1
-2
@@ -7,11 +7,10 @@ Here lies the core of our codebase. Everything that's OS inspecific rests here.
|
||||
### Some rudimentary categories are:
|
||||
- hw -- DC Hardware Components Implementation
|
||||
- nullDC.cpp -- Main entry points
|
||||
- khronos -- OpenGL and Vulkan headers
|
||||
- oslib -- Audio drivers
|
||||
- cfg -- Configuration backend structure
|
||||
- reios -- (Our) Implementation of the DreamCast BIOS
|
||||
- deps -- External dependencies
|
||||
- imgread -- Content drivers
|
||||
- rec-* -- Recompilers
|
||||
- rend -- OpenGL and Vulkan renderers
|
||||
- rend -- Graphics renderers and UI
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
This file is part of Flycast.
|
||||
|
||||
Flycast is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Flycast is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Flycast. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include "types.h"
|
||||
#include <future>
|
||||
#include <vector>
|
||||
|
||||
namespace achievements
|
||||
{
|
||||
#ifdef USE_RACHIEVEMENTS
|
||||
|
||||
struct Game
|
||||
{
|
||||
std::string image;
|
||||
std::string title;
|
||||
u32 unlockedAchievements;
|
||||
u32 totalAchievements;
|
||||
u32 points;
|
||||
u32 totalPoints;
|
||||
};
|
||||
|
||||
struct Achievement
|
||||
{
|
||||
Achievement() = default;
|
||||
Achievement(const std::string& image, const std::string& title, const std::string& description, const std::string& category, const std::string& status)
|
||||
: image(image), title(title), description(description), category(category), status(status) {}
|
||||
std::string image;
|
||||
std::string title;
|
||||
std::string description;
|
||||
std::string category;
|
||||
std::string status;
|
||||
};
|
||||
|
||||
bool init();
|
||||
void term();
|
||||
std::future<void> login(const char *username, const char *password);
|
||||
void logout();
|
||||
bool isLoggedOn();
|
||||
bool isActive();
|
||||
Game getCurrentGame();
|
||||
std::vector<Achievement> getAchievementList();
|
||||
bool canPause();
|
||||
|
||||
#else
|
||||
|
||||
static inline bool isActive() {
|
||||
return false;
|
||||
}
|
||||
static inline bool canPause() {
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void serialize(Serializer& ser);
|
||||
void deserialize(Deserializer& deser);
|
||||
|
||||
}
|
||||
@@ -23,19 +23,19 @@
|
||||
#include "deps/lzma/7zCrc.h"
|
||||
#include "deps/lzma/Alloc.h"
|
||||
|
||||
#include <cstring>
|
||||
|
||||
#define kInputBufSize ((size_t)1 << 18)
|
||||
|
||||
static bool crc_tables_generated;
|
||||
|
||||
bool SzArchive::Open(const char* path)
|
||||
bool SzArchive::Open(FILE *file)
|
||||
{
|
||||
SzArEx_Init(&szarchive);
|
||||
|
||||
File_Close(&archiveStream.file);
|
||||
File_Construct(&archiveStream.file);
|
||||
archiveStream.file.file = nowide::fopen(path, "rb");
|
||||
if (archiveStream.file.file == nullptr)
|
||||
return false;
|
||||
archiveStream.file.file = file;
|
||||
|
||||
FileInStream_CreateVTable(&archiveStream);
|
||||
LookToRead2_CreateVTable(&lookStream, 0);
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
#include "deps/lzma/7zFile.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstring>
|
||||
|
||||
class SzArchive : public Archive
|
||||
{
|
||||
@@ -38,9 +39,10 @@ public:
|
||||
ArchiveFile* OpenFile(const char* name) override;
|
||||
ArchiveFile *OpenFileByCrc(u32 crc) override;
|
||||
|
||||
private:
|
||||
bool Open(const char* path) override;
|
||||
protected:
|
||||
bool Open(FILE *file) override;
|
||||
|
||||
private:
|
||||
CSzArEx szarchive;
|
||||
UInt32 block_idx; /* it can have any value before first call (if outBuffer = 0) */
|
||||
Byte *out_buffer; /* it must be 0 before first call for each new archive. */
|
||||
@@ -53,16 +55,21 @@ private:
|
||||
class SzArchiveFile : public ArchiveFile
|
||||
{
|
||||
public:
|
||||
SzArchiveFile(u8 *data, u32 offset, u32 length) : data(data), offset(offset), length(length) {}
|
||||
SzArchiveFile(u8 *data, u32 offset, u32 length)
|
||||
: data(data), offset(offset), _length(length) {}
|
||||
u32 Read(void *buffer, u32 length) override
|
||||
{
|
||||
length = std::min(length, this->length);
|
||||
length = std::min(length, this->_length);
|
||||
memcpy(buffer, data + offset, length);
|
||||
return length;
|
||||
}
|
||||
|
||||
size_t length() override {
|
||||
return _length;
|
||||
}
|
||||
|
||||
private:
|
||||
u8 *data;
|
||||
u32 offset;
|
||||
u32 length;
|
||||
u32 _length;
|
||||
};
|
||||
+60
-32
@@ -25,11 +25,8 @@ ZipArchive::~ZipArchive()
|
||||
zip_close(zip);
|
||||
}
|
||||
|
||||
bool ZipArchive::Open(const char* path)
|
||||
bool ZipArchive::Open(FILE *file)
|
||||
{
|
||||
FILE *file = nowide::fopen(path, "rb");
|
||||
if (file == nullptr)
|
||||
return false;
|
||||
zip_error_t error;
|
||||
zip_source_t *source = zip_source_filep_create(file, 0, -1, &error);
|
||||
if (source == nullptr)
|
||||
@@ -37,7 +34,7 @@ bool ZipArchive::Open(const char* path)
|
||||
std::fclose(file);
|
||||
return false;
|
||||
}
|
||||
zip = zip_open_from_source(source, 0, NULL);
|
||||
zip = zip_open_from_source(source, 0, nullptr);
|
||||
if (zip == nullptr)
|
||||
zip_source_free(source);
|
||||
return zip != nullptr;
|
||||
@@ -45,46 +42,77 @@ bool ZipArchive::Open(const char* path)
|
||||
|
||||
ArchiveFile* ZipArchive::OpenFile(const char* name)
|
||||
{
|
||||
zip_file *zip_file = zip_fopen(zip, name, 0);
|
||||
if (zip_file == NULL)
|
||||
return NULL;
|
||||
|
||||
return new ZipArchiveFile(zip_file);
|
||||
zip_file_t *zip_file = zip_fopen(zip, name, 0);
|
||||
if (zip_file == nullptr)
|
||||
return nullptr;
|
||||
zip_stat_t stat;
|
||||
zip_stat(zip, name, 0, &stat);
|
||||
return new ZipArchiveFile(zip_file, stat.size, stat.name);
|
||||
}
|
||||
|
||||
struct zip_file *zip_fopen_by_crc(struct zip *za, u32 crc, int flags)
|
||||
static zip_file *zip_fopen_by_crc(zip_t *za, u32 crc, int flags, zip_uint64_t& index)
|
||||
{
|
||||
int i, n;
|
||||
struct zip_stat stat;
|
||||
if (crc == 0)
|
||||
return nullptr;
|
||||
|
||||
if (crc == 0) {
|
||||
return NULL;
|
||||
}
|
||||
zip_int64_t n = zip_get_num_entries(za, 0);
|
||||
for (index = 0; index < (zip_uint64_t)n; index++)
|
||||
{
|
||||
zip_stat_t stat;
|
||||
if (zip_stat_index(za, index, flags, &stat) < -1)
|
||||
return nullptr;
|
||||
if (stat.crc == crc)
|
||||
return zip_fopen_index(za, index, flags);
|
||||
}
|
||||
|
||||
n = zip_get_num_files(za);
|
||||
for (i = 0; i < n; i++) {
|
||||
if (zip_stat_index(za, i, flags, &stat) < -1) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (stat.crc == crc) {
|
||||
return zip_fopen_index(za, i, flags);
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ArchiveFile* ZipArchive::OpenFileByCrc(u32 crc)
|
||||
{
|
||||
zip_file *zip_file = zip_fopen_by_crc(zip, crc, 0);
|
||||
if (zip_file == NULL)
|
||||
return NULL;
|
||||
zip_uint64_t index;
|
||||
zip_file_t *zip_file = zip_fopen_by_crc(zip, crc, 0, index);
|
||||
if (zip_file == nullptr)
|
||||
return nullptr;
|
||||
zip_stat_t stat;
|
||||
zip_stat_index(zip, index, 0, &stat);
|
||||
|
||||
return new ZipArchiveFile(zip_file);
|
||||
return new ZipArchiveFile(zip_file, stat.size, stat.name);
|
||||
}
|
||||
|
||||
u32 ZipArchiveFile::Read(void* buffer, u32 length)
|
||||
{
|
||||
return zip_fread(zip_file, buffer, length);
|
||||
}
|
||||
|
||||
bool ZipArchive::Open(const void *data, size_t size)
|
||||
{
|
||||
zip_error_t error;
|
||||
zip_source_t *source = zip_source_buffer_create(data, size, 0, &error);
|
||||
if (source == nullptr)
|
||||
return false;
|
||||
zip = zip_open_from_source(source, 0, nullptr);
|
||||
if (zip == nullptr)
|
||||
zip_source_free(source);
|
||||
return zip != nullptr;
|
||||
}
|
||||
|
||||
ArchiveFile *ZipArchive::OpenFirstFile()
|
||||
{
|
||||
zip_file_t *zipFile = zip_fopen_index(zip, 0, 0);
|
||||
if (zipFile == nullptr)
|
||||
return nullptr;
|
||||
zip_stat_t stat;
|
||||
zip_stat_index(zip, 0, 0, &stat);
|
||||
return new ZipArchiveFile(zipFile, stat.size, stat.name);
|
||||
}
|
||||
|
||||
ArchiveFile *ZipArchive::OpenFileByIndex(size_t index)
|
||||
{
|
||||
zip_file_t *zipFile = zip_fopen_index(zip, index, 0);
|
||||
if (zipFile == nullptr)
|
||||
return nullptr;
|
||||
zip_stat_t stat;
|
||||
zip_stat_index(zip, index, 0, &stat);
|
||||
return new ZipArchiveFile(zipFile, stat.size, stat.name);
|
||||
}
|
||||
@@ -26,25 +26,39 @@
|
||||
class ZipArchive : public Archive
|
||||
{
|
||||
public:
|
||||
ZipArchive() : zip(NULL) {}
|
||||
~ZipArchive() override;
|
||||
|
||||
ArchiveFile* OpenFile(const char* name) override;
|
||||
ArchiveFile* OpenFileByCrc(u32 crc) override;
|
||||
|
||||
private:
|
||||
bool Open(const char* path) override;
|
||||
bool Open(FILE *file) override;
|
||||
bool Open(const void *data, size_t size);
|
||||
|
||||
struct zip *zip;
|
||||
ArchiveFile *OpenFirstFile();
|
||||
ArchiveFile *OpenFileByIndex(size_t index);
|
||||
|
||||
private:
|
||||
zip_t *zip = nullptr;
|
||||
};
|
||||
|
||||
class ZipArchiveFile : public ArchiveFile
|
||||
{
|
||||
public:
|
||||
ZipArchiveFile(struct zip_file *zip_file) : zip_file(zip_file) {}
|
||||
~ZipArchiveFile() override { zip_fclose(zip_file); }
|
||||
ZipArchiveFile(zip_file_t *zip_file, size_t length, const char *name)
|
||||
: zip_file(zip_file), _length(length), name(name) {}
|
||||
~ZipArchiveFile() override {
|
||||
zip_fclose(zip_file);
|
||||
}
|
||||
u32 Read(void* buffer, u32 length) override;
|
||||
size_t length() override {
|
||||
return _length;
|
||||
}
|
||||
const char *getName() override {
|
||||
return name;
|
||||
}
|
||||
|
||||
private:
|
||||
struct zip_file *zip_file;
|
||||
zip_file_t *zip_file;
|
||||
size_t _length;
|
||||
const char *name;
|
||||
};
|
||||
+49
-12
@@ -22,24 +22,61 @@
|
||||
#include "archive.h"
|
||||
#include "7zArchive.h"
|
||||
#include "ZipArchive.h"
|
||||
#include "oslib/storage.h"
|
||||
|
||||
Archive *OpenArchive(const char *path)
|
||||
Archive *OpenArchive(const std::string& path)
|
||||
{
|
||||
std::string base_path(path);
|
||||
|
||||
Archive *sz_archive = new SzArchive();
|
||||
if (sz_archive->Open(base_path.c_str()) || sz_archive->Open((base_path + ".7z").c_str()) || sz_archive->Open((base_path + ".7Z").c_str()))
|
||||
return sz_archive;
|
||||
delete sz_archive;
|
||||
|
||||
FILE *file = nullptr;
|
||||
hostfs::FileInfo fileInfo;
|
||||
try {
|
||||
fileInfo = hostfs::storage().getFileInfo(path);
|
||||
if (!fileInfo.isDirectory)
|
||||
file = hostfs::storage().openFile(path, "rb");
|
||||
} catch (const hostfs::StorageException& e) {
|
||||
}
|
||||
if (file == nullptr)
|
||||
{
|
||||
file = hostfs::storage().openFile(path + ".7z", "rb");
|
||||
if (file == nullptr)
|
||||
file = hostfs::storage().openFile(path + ".7Z", "rb");
|
||||
}
|
||||
if (file != nullptr)
|
||||
{
|
||||
Archive *sz_archive = new SzArchive();
|
||||
if (sz_archive->Open(file))
|
||||
return sz_archive;
|
||||
delete sz_archive;
|
||||
file = nullptr;
|
||||
}
|
||||
// Retry as a zip file
|
||||
try {
|
||||
if (!fileInfo.isDirectory)
|
||||
file = hostfs::storage().openFile(path, "rb");
|
||||
} catch (const hostfs::StorageException& e) {
|
||||
}
|
||||
if (file == nullptr)
|
||||
{
|
||||
file = hostfs::storage().openFile(path + ".zip", "rb");
|
||||
if (file == nullptr)
|
||||
{
|
||||
file = hostfs::storage().openFile(path + ".ZIP", "rb");
|
||||
if (file == nullptr)
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
Archive *zip_archive = new ZipArchive();
|
||||
if (zip_archive->Open(base_path.c_str()) || zip_archive->Open((base_path + ".zip").c_str()) || zip_archive->Open((base_path + ".ZIP").c_str()))
|
||||
if (zip_archive->Open(file))
|
||||
return zip_archive;
|
||||
delete zip_archive;
|
||||
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool Archive::Open(const char* path)
|
||||
{
|
||||
FILE *file = nowide::fopen(path, "rb");
|
||||
if (file == nullptr)
|
||||
return false;
|
||||
return Open(file);
|
||||
}
|
||||
|
||||
@@ -27,6 +27,8 @@ class ArchiveFile
|
||||
public:
|
||||
virtual ~ArchiveFile() = default;
|
||||
virtual u32 Read(void *buffer, u32 length) = 0;
|
||||
virtual size_t length() = 0;
|
||||
virtual const char *getName() { return nullptr; }
|
||||
};
|
||||
|
||||
class Archive
|
||||
@@ -36,10 +38,13 @@ public:
|
||||
virtual ArchiveFile *OpenFile(const char *name) = 0;
|
||||
virtual ArchiveFile *OpenFileByCrc(u32 crc) = 0;
|
||||
|
||||
friend Archive *OpenArchive(const char *path);
|
||||
protected:
|
||||
virtual bool Open(FILE *file) = 0;
|
||||
|
||||
private:
|
||||
virtual bool Open(const char *name) = 0;
|
||||
bool Open(const char *name);
|
||||
|
||||
friend Archive *OpenArchive(const std::string& path);
|
||||
};
|
||||
|
||||
Archive *OpenArchive(const char *path);
|
||||
Archive *OpenArchive(const std::string& path);
|
||||
+40
-15
@@ -19,15 +19,15 @@
|
||||
#include "rzip.h"
|
||||
#include <zlib.h>
|
||||
|
||||
#include <cstring>
|
||||
|
||||
const u8 RZipHeader[8] = { '#', 'R', 'Z', 'I', 'P', 'v', 1, '#' };
|
||||
|
||||
bool RZipFile::Open(const std::string& path, bool write)
|
||||
bool RZipFile::Open(FILE *file, bool write)
|
||||
{
|
||||
verify(file == nullptr);
|
||||
|
||||
file = nowide::fopen(path.c_str(), write ? "wb" : "rb");
|
||||
if (file == nullptr)
|
||||
return false;
|
||||
verify(this->file == nullptr);
|
||||
verify(file != nullptr);
|
||||
startOffset = std::ftell(file);
|
||||
if (!write)
|
||||
{
|
||||
u8 header[sizeof(RZipHeader)];
|
||||
@@ -36,7 +36,7 @@ bool RZipFile::Open(const std::string& path, bool write)
|
||||
|| std::fread(&maxChunkSize, sizeof(maxChunkSize), 1, file) != 1
|
||||
|| std::fread(&size, sizeof(size), 1, file) != 1)
|
||||
{
|
||||
Close();
|
||||
std::fseek(file, startOffset, SEEK_SET);
|
||||
return false;
|
||||
}
|
||||
// savestates created on 32-bit platforms used to have a 32-bit size
|
||||
@@ -49,7 +49,31 @@ bool RZipFile::Open(const std::string& path, bool write)
|
||||
chunkIndex = 0;
|
||||
chunkSize = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
maxChunkSize = 1_MB;
|
||||
if (std::fwrite(RZipHeader, sizeof(RZipHeader), 1, file) != 1
|
||||
|| std::fwrite(&maxChunkSize, sizeof(maxChunkSize), 1, file) != 1
|
||||
|| std::fwrite(&size, sizeof(size), 1, file) != 1)
|
||||
{
|
||||
std::fseek(file, startOffset, SEEK_SET);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
this->write = write;
|
||||
this->file = file;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RZipFile::Open(const std::string& path, bool write)
|
||||
{
|
||||
FILE *f = nowide::fopen(path.c_str(), write ? "wb" : "rb");
|
||||
if (f == nullptr)
|
||||
return false;
|
||||
if (!Open(f, write)) {
|
||||
Close();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -57,6 +81,11 @@ void RZipFile::Close()
|
||||
{
|
||||
if (file != nullptr)
|
||||
{
|
||||
if (write)
|
||||
{
|
||||
std::fseek(file, startOffset + sizeof(RZipHeader) + sizeof(maxChunkSize), SEEK_SET);
|
||||
std::fwrite(&size, sizeof(size), 1, file);
|
||||
}
|
||||
std::fclose(file);
|
||||
file = nullptr;
|
||||
if (chunk != nullptr)
|
||||
@@ -70,6 +99,7 @@ void RZipFile::Close()
|
||||
size_t RZipFile::Read(void *data, size_t length)
|
||||
{
|
||||
verify(file != nullptr);
|
||||
verify(!write);
|
||||
|
||||
u8 *p = (u8 *)data;
|
||||
size_t rv = 0;
|
||||
@@ -99,7 +129,7 @@ size_t RZipFile::Read(void *data, size_t length)
|
||||
delete [] zipped;
|
||||
chunkSize = (u32)tl;
|
||||
}
|
||||
u32 l = std::min(chunkSize - chunkIndex, (u32)length);
|
||||
u32 l = std::min(chunkSize - chunkIndex, (u32)(length - rv));
|
||||
memcpy(p, chunk + chunkIndex, l);
|
||||
p += l;
|
||||
chunkIndex += l;
|
||||
@@ -112,14 +142,9 @@ size_t RZipFile::Read(void *data, size_t length)
|
||||
size_t RZipFile::Write(const void *data, size_t length)
|
||||
{
|
||||
verify(file != nullptr);
|
||||
verify(std::ftell(file) == 0);
|
||||
verify(write);
|
||||
|
||||
maxChunkSize = 1024 * 1024;
|
||||
size = length;
|
||||
if (std::fwrite(RZipHeader, sizeof(RZipHeader), 1, file) != 1
|
||||
|| std::fwrite(&maxChunkSize, sizeof(maxChunkSize), 1, file) != 1
|
||||
|| std::fwrite(&size, sizeof(size), 1, file) != 1)
|
||||
return 0;
|
||||
size += length;
|
||||
const u8 *p = (const u8 *)data;
|
||||
// compression output buffer must be 0.1% larger + 12 bytes
|
||||
uLongf maxZippedSize = maxChunkSize + maxChunkSize / 1000 + 12;
|
||||
|
||||
@@ -28,6 +28,7 @@ public:
|
||||
~RZipFile() { Close(); }
|
||||
|
||||
bool Open(const std::string& path, bool write);
|
||||
bool Open(FILE *file, bool write);
|
||||
void Close();
|
||||
size_t Size() const { return size; }
|
||||
size_t Read(void *data, size_t length);
|
||||
@@ -41,4 +42,6 @@ private:
|
||||
u8 *chunk = nullptr;
|
||||
u32 chunkSize = 0;
|
||||
u32 chunkIndex = 0;
|
||||
bool write = false;
|
||||
long startOffset = 0;
|
||||
};
|
||||
@@ -0,0 +1,358 @@
|
||||
#if USE_ALSA
|
||||
#include "audiostream.h"
|
||||
#include <alsa/asoundlib.h>
|
||||
#include "cfg/cfg.h"
|
||||
#include "cfg/option.h"
|
||||
|
||||
class AlsaAudioBackend : public AudioBackend
|
||||
{
|
||||
snd_pcm_t *handle = nullptr;
|
||||
bool pcm_blocking = true;
|
||||
snd_pcm_uframes_t buffer_size = 0;
|
||||
snd_pcm_uframes_t period_size = 0;
|
||||
snd_pcm_t *handle_record = nullptr;
|
||||
|
||||
public:
|
||||
AlsaAudioBackend()
|
||||
: AudioBackend("alsa", "Advanced Linux Sound Architecture") {}
|
||||
|
||||
bool init() override
|
||||
{
|
||||
snd_pcm_hw_params_t *params;
|
||||
|
||||
std::string device = cfgLoadStr("alsa", "device", "");
|
||||
|
||||
int rc = -1;
|
||||
if (!device.empty() && device != "auto") {
|
||||
rc = snd_pcm_open(&handle, device.c_str(), SND_PCM_STREAM_PLAYBACK, 0);
|
||||
if (rc < 0)
|
||||
WARN_LOG(AUDIO, "ALSA: Cannot open device %s. Trying auto", device.c_str());
|
||||
}
|
||||
if (rc < 0)
|
||||
{
|
||||
INFO_LOG(AUDIO, "ALSA: trying to determine audio device");
|
||||
|
||||
// trying default device
|
||||
device = "default";
|
||||
rc = snd_pcm_open(&handle, device.c_str(), SND_PCM_STREAM_PLAYBACK, 0);
|
||||
|
||||
// "default" didn't work, try first device
|
||||
if (rc < 0)
|
||||
{
|
||||
device = "plughw:0,0,0";
|
||||
rc = snd_pcm_open(&handle, device.c_str(), SND_PCM_STREAM_PLAYBACK, 0);
|
||||
|
||||
if (rc < 0)
|
||||
{
|
||||
device = "plughw:0,0";
|
||||
rc = snd_pcm_open(&handle, device.c_str(), SND_PCM_STREAM_PLAYBACK, 0);
|
||||
}
|
||||
}
|
||||
|
||||
// first didn't work, try second
|
||||
if (rc < 0)
|
||||
{
|
||||
device = "plughw:1,0";
|
||||
rc = snd_pcm_open(&handle, device.c_str(), SND_PCM_STREAM_PLAYBACK, 0);
|
||||
}
|
||||
|
||||
// try pulse audio backend
|
||||
if (rc < 0)
|
||||
{
|
||||
device = "pulse";
|
||||
rc = snd_pcm_open(&handle, device.c_str(), SND_PCM_STREAM_PLAYBACK, 0);
|
||||
}
|
||||
|
||||
if (rc < 0)
|
||||
INFO_LOG(AUDIO, "ALSA: unable to automatically determine audio device.");
|
||||
}
|
||||
|
||||
if (rc < 0)
|
||||
{
|
||||
ERROR_LOG(AUDIO, "ALSA: unable to open PCM device %s: %s", device.c_str(), snd_strerror(rc));
|
||||
return false;
|
||||
}
|
||||
|
||||
INFO_LOG(AUDIO, "ALSA: Successfully initialized \"%s\"", device.c_str());
|
||||
|
||||
/* Allocate a hardware parameters object. */
|
||||
snd_pcm_hw_params_alloca(¶ms);
|
||||
|
||||
/* Fill it in with default values. */
|
||||
rc=snd_pcm_hw_params_any(handle, params);
|
||||
if (rc < 0)
|
||||
{
|
||||
ERROR_LOG(AUDIO, "ALSA: Error:snd_pcm_hw_params_any %s", snd_strerror(rc));
|
||||
term();
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Set the desired hardware parameters. */
|
||||
|
||||
/* Interleaved mode */
|
||||
rc=snd_pcm_hw_params_set_access(handle, params, SND_PCM_ACCESS_RW_INTERLEAVED);
|
||||
if (rc < 0)
|
||||
{
|
||||
ERROR_LOG(AUDIO, "ALSA: Error:snd_pcm_hw_params_set_access %s", snd_strerror(rc));
|
||||
term();
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Signed 16-bit little-endian format */
|
||||
rc=snd_pcm_hw_params_set_format(handle, params, SND_PCM_FORMAT_S16_LE);
|
||||
if (rc < 0)
|
||||
{
|
||||
ERROR_LOG(AUDIO, "ALSA: Error:snd_pcm_hw_params_set_format %s", snd_strerror(rc));
|
||||
term();
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Two channels (stereo) */
|
||||
rc=snd_pcm_hw_params_set_channels(handle, params, 2);
|
||||
if (rc < 0)
|
||||
{
|
||||
ERROR_LOG(AUDIO, "ALSA: Error:snd_pcm_hw_params_set_channels %s", snd_strerror(rc));
|
||||
term();
|
||||
return false;
|
||||
}
|
||||
|
||||
// 44100 samples/second
|
||||
rc = snd_pcm_hw_params_set_rate(handle, params, 44100, 0);
|
||||
if (rc < 0)
|
||||
{
|
||||
ERROR_LOG(AUDIO, "ALSA: Error:snd_pcm_hw_params_set_rate %s", snd_strerror(rc));
|
||||
term();
|
||||
return false;
|
||||
}
|
||||
|
||||
// Period size (512)
|
||||
period_size = std::min(SAMPLE_COUNT, (u32)config::AudioBufferSize / 4);
|
||||
rc = snd_pcm_hw_params_set_period_size_near(handle, params, &period_size, nullptr);
|
||||
if (rc < 0)
|
||||
{
|
||||
ERROR_LOG(AUDIO, "ALSA: Error:snd_pcm_hw_params_set_periods_near %s", snd_strerror(rc));
|
||||
term();
|
||||
return false;
|
||||
}
|
||||
INFO_LOG(AUDIO, "ALSA: period size set to %zd", (size_t)period_size);
|
||||
|
||||
// Sample buffer size
|
||||
buffer_size = config::AudioBufferSize;
|
||||
rc = snd_pcm_hw_params_set_buffer_size_near(handle, params, &buffer_size);
|
||||
if (rc < 0)
|
||||
{
|
||||
ERROR_LOG(AUDIO, "ALSA: Error:snd_pcm_hw_params_set_buffer_size_near %s", snd_strerror(rc));
|
||||
term();
|
||||
return false;
|
||||
}
|
||||
INFO_LOG(AUDIO, "ALSA: buffer size set to %ld", buffer_size);
|
||||
|
||||
/* Write the parameters to the driver */
|
||||
rc = snd_pcm_hw_params(handle, params);
|
||||
if (rc < 0)
|
||||
{
|
||||
ERROR_LOG(AUDIO, "ALSA: Unable to set hw parameters: %s", snd_strerror(rc));
|
||||
term();
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool initRecord(u32 sampling_freq) override
|
||||
{
|
||||
int err;
|
||||
if ((err = snd_pcm_open(&handle_record, "default", SND_PCM_STREAM_CAPTURE, 0)) < 0)
|
||||
{
|
||||
ERROR_LOG(AUDIO, "ALSA: Cannot open default audio capture device: %s", snd_strerror(err));
|
||||
return false;
|
||||
}
|
||||
snd_pcm_hw_params_t *hw_params;
|
||||
if ((err = snd_pcm_hw_params_malloc(&hw_params)) < 0)
|
||||
{
|
||||
ERROR_LOG(AUDIO, "ALSA: Cannot allocate hardware parameter structure: %s", snd_strerror(err));
|
||||
snd_pcm_close(handle_record);
|
||||
return false;
|
||||
}
|
||||
if ((err = snd_pcm_hw_params_any(handle_record, hw_params)) < 0)
|
||||
{
|
||||
ERROR_LOG(AUDIO, "ALSA: Cannot initialize hardware parameter structure: %s", snd_strerror(err));
|
||||
snd_pcm_hw_params_free(hw_params);
|
||||
snd_pcm_close(handle_record);
|
||||
return false;
|
||||
}
|
||||
if ((err = snd_pcm_hw_params_set_access(handle_record, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0)
|
||||
{
|
||||
ERROR_LOG(AUDIO, "ALSA: Cannot set access type: %s\n", snd_strerror(err));
|
||||
snd_pcm_hw_params_free(hw_params);
|
||||
snd_pcm_close(handle_record);
|
||||
return false;
|
||||
}
|
||||
if ((err = snd_pcm_hw_params_set_format(handle_record, hw_params, SND_PCM_FORMAT_S16_LE)) < 0)
|
||||
{
|
||||
ERROR_LOG(AUDIO, "ALSA: Cannot set sample format: %s", snd_strerror(err));
|
||||
snd_pcm_hw_params_free(hw_params);
|
||||
snd_pcm_close(handle_record);
|
||||
return false;
|
||||
}
|
||||
if ((err = snd_pcm_hw_params_set_rate(handle_record, hw_params, sampling_freq, 0)) < 0)
|
||||
{
|
||||
ERROR_LOG(AUDIO, "ALSA: Cannot set sample rate to %d Hz: %s", sampling_freq, snd_strerror(err));
|
||||
snd_pcm_hw_params_free(hw_params);
|
||||
snd_pcm_close(handle_record);
|
||||
return false;
|
||||
}
|
||||
if ((err = snd_pcm_hw_params_set_channels(handle_record, hw_params, 1)) < 0)
|
||||
{
|
||||
ERROR_LOG(AUDIO, "ALSA: Cannot set channel count: %s", snd_strerror(err));
|
||||
snd_pcm_hw_params_free(hw_params);
|
||||
snd_pcm_close(handle_record);
|
||||
return false;
|
||||
}
|
||||
if ((err = snd_pcm_hw_params(handle_record, hw_params)) < 0)
|
||||
{
|
||||
ERROR_LOG(AUDIO, "ALSA: Cannot set parameters: %s", snd_strerror(err));
|
||||
snd_pcm_hw_params_free(hw_params);
|
||||
snd_pcm_close(handle_record);
|
||||
return false;
|
||||
}
|
||||
snd_pcm_hw_params_free(hw_params);
|
||||
snd_pcm_nonblock(handle_record, 1);
|
||||
if ((err = snd_pcm_prepare(handle_record)) < 0)
|
||||
{
|
||||
ERROR_LOG(AUDIO, "ALSA: Cannot prepare device: %s", snd_strerror(err));
|
||||
snd_pcm_close(handle_record);
|
||||
return false;
|
||||
}
|
||||
INFO_LOG(AUDIO, "ALSA: Successfully initialized capture device");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void termRecord() override
|
||||
{
|
||||
snd_pcm_close(handle_record);
|
||||
}
|
||||
|
||||
u32 record(void* frame, u32 samples) override
|
||||
{
|
||||
int err = snd_pcm_readi(handle_record, frame, samples);
|
||||
if (err < (int)samples)
|
||||
{
|
||||
if (err < 0)
|
||||
{
|
||||
DEBUG_LOG(AUDIO, "ALSA: Recording error: %s", snd_strerror(err));
|
||||
err = 0;
|
||||
err = snd_pcm_prepare(handle_record);
|
||||
}
|
||||
u8 *buffer = (u8 *)frame + err;
|
||||
memset(buffer, 0, (samples - err) * 2);
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
u32 push(const void* frame, u32 samples, bool wait) override
|
||||
{
|
||||
if (wait != pcm_blocking) {
|
||||
snd_pcm_nonblock(handle, wait ? 0 : 1);
|
||||
pcm_blocking = wait;
|
||||
}
|
||||
|
||||
int rc = snd_pcm_writei(handle, frame, samples);
|
||||
if (rc < 0)
|
||||
{
|
||||
snd_pcm_recover(handle, rc, 1);
|
||||
if (rc == -EPIPE)
|
||||
{
|
||||
// EPIPE means underrun
|
||||
// Write some silence then our samples
|
||||
const size_t silence_size = buffer_size - samples;
|
||||
void *silence = alloca(silence_size * 4);
|
||||
memset(silence, 0, silence_size * 4);
|
||||
snd_pcm_writei(handle, silence, silence_size);
|
||||
snd_pcm_writei(handle, frame, samples);
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
void term() override
|
||||
{
|
||||
snd_pcm_drop(handle);
|
||||
snd_pcm_close(handle);
|
||||
}
|
||||
|
||||
std::vector<std::string> getDeviceList()
|
||||
{
|
||||
std::vector<std::string> result;
|
||||
|
||||
char **hints;
|
||||
int err = snd_device_name_hint(-1, "pcm", (void***)&hints);
|
||||
|
||||
// Error initializing ALSA
|
||||
if (err != 0)
|
||||
return result;
|
||||
|
||||
// special value to automatically detect on initialization
|
||||
result.emplace_back("auto");
|
||||
|
||||
char** n = hints;
|
||||
while (*n != NULL)
|
||||
{
|
||||
// Get the type (NULL/Input/Output)
|
||||
char *type = snd_device_name_get_hint(*n, "IOID");
|
||||
char *name = snd_device_name_get_hint(*n, "NAME");
|
||||
|
||||
if (name != NULL)
|
||||
{
|
||||
// We only want output or special devices (like "default" or "pulse")
|
||||
// TODO Only those with type == NULL?
|
||||
if (type == NULL || strcmp(type, "Output") == 0)
|
||||
{
|
||||
// TODO Check if device works (however we need to hash the resulting list then)
|
||||
/*snd_pcm_t *handle;
|
||||
int rc = snd_pcm_open(&handle, name, SND_PCM_STREAM_PLAYBACK, 0);
|
||||
|
||||
if (rc == 0)
|
||||
{
|
||||
result.push_back(name);
|
||||
snd_pcm_close(handle);
|
||||
}
|
||||
*/
|
||||
|
||||
result.emplace_back(name);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (type != NULL)
|
||||
free(type);
|
||||
|
||||
if (name != NULL)
|
||||
free(name);
|
||||
|
||||
n++;
|
||||
}
|
||||
|
||||
snd_device_name_free_hint((void**)hints);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
Option* getOptions(int *count) override
|
||||
{
|
||||
*count = 1;
|
||||
static Option result;
|
||||
|
||||
result.name = "device";
|
||||
result.caption = "Device";
|
||||
result.type = Option::list;
|
||||
result.values = getDeviceList();
|
||||
|
||||
return &result;
|
||||
}
|
||||
};
|
||||
static AlsaAudioBackend alsaBackend;
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,308 @@
|
||||
/*
|
||||
Simple Core Audio backend for osx (and maybe ios?)
|
||||
Based off various audio core samples and dolphin's code
|
||||
|
||||
This is part of the Reicast project, please consult the
|
||||
LICENSE file for licensing & related information
|
||||
|
||||
This could do with some locking logic to avoid
|
||||
race conditions, and some variable length buffer
|
||||
logic to support chunk sizes other than 512 bytes
|
||||
|
||||
It does work on my macmini though
|
||||
*/
|
||||
#if defined(__APPLE__)
|
||||
#include "audiostream.h"
|
||||
#include "cfg/option.h"
|
||||
#include "stdclass.h"
|
||||
|
||||
#include <atomic>
|
||||
|
||||
#include <AudioUnit/AudioUnit.h>
|
||||
#include <AudioToolbox/AudioQueue.h>
|
||||
|
||||
class CoreAudioBackend : public AudioBackend
|
||||
{
|
||||
AudioUnit audioUnit;
|
||||
|
||||
u32 BUFSIZE = 0;
|
||||
u8 *samples_temp = nullptr;
|
||||
|
||||
std::atomic<int> samples_wptr;
|
||||
std::atomic<int> samples_rptr;
|
||||
cResetEvent bufferEmpty;
|
||||
|
||||
// input buffer and indexes
|
||||
u8 samples_input[2400];
|
||||
static constexpr size_t InputBufSize = sizeof(samples_input);
|
||||
std::atomic<int> input_wptr;
|
||||
std::atomic<int> input_rptr;
|
||||
AudioQueueRef recordQueue;
|
||||
|
||||
static OSStatus renderCallback(void* ctx, AudioUnitRenderActionFlags* flags, const AudioTimeStamp* ts,
|
||||
UInt32 bus, UInt32 frames, AudioBufferList* abl)
|
||||
{
|
||||
CoreAudioBackend *backend = (CoreAudioBackend *)ctx;
|
||||
for (int i = 0; i < abl->mNumberBuffers; i++)
|
||||
{
|
||||
int size = abl->mBuffers[i].mDataByteSize;
|
||||
u8 *outBuffer = (u8 *)abl->mBuffers[i].mData;
|
||||
while (size != 0)
|
||||
{
|
||||
int avail = (backend->samples_wptr - backend->samples_rptr + backend->BUFSIZE) % backend->BUFSIZE;
|
||||
if (avail == 0)
|
||||
{
|
||||
//printf("Core Audio: buffer underrun %d bytes (%d)", size, abl->mBuffers[i].mDataByteSize);
|
||||
memset(outBuffer, '\0', size);
|
||||
return noErr;
|
||||
}
|
||||
avail = std::min(avail, size);
|
||||
avail = std::min(avail, (int)backend->BUFSIZE - backend->samples_rptr);
|
||||
memcpy(outBuffer, backend->samples_temp + backend->samples_rptr, avail);
|
||||
backend->samples_rptr = (backend->samples_rptr + avail) % backend->BUFSIZE;
|
||||
size -= avail;
|
||||
outBuffer += avail;
|
||||
// Set the mutex to allow writing
|
||||
backend->bufferEmpty.Set();
|
||||
}
|
||||
}
|
||||
|
||||
return noErr;
|
||||
}
|
||||
|
||||
public:
|
||||
CoreAudioBackend()
|
||||
: AudioBackend("coreaudio", "Core Audio") {}
|
||||
|
||||
bool init() override
|
||||
{
|
||||
OSStatus err;
|
||||
AURenderCallbackStruct callback_struct;
|
||||
AudioStreamBasicDescription format;
|
||||
AudioComponentDescription desc;
|
||||
AudioComponent component;
|
||||
|
||||
desc.componentType = kAudioUnitType_Output;
|
||||
#if !defined(TARGET_IPHONE)
|
||||
desc.componentSubType = kAudioUnitSubType_DefaultOutput;
|
||||
#else
|
||||
desc.componentSubType = kAudioUnitSubType_RemoteIO;
|
||||
#endif
|
||||
desc.componentFlags = 0;
|
||||
desc.componentFlagsMask = 0;
|
||||
desc.componentManufacturer = kAudioUnitManufacturer_Apple;
|
||||
component = AudioComponentFindNext(nullptr, &desc);
|
||||
|
||||
if (component == nullptr) {
|
||||
ERROR_LOG(AUDIO, "coreaudio: AudioComponentFindNext failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
err = AudioComponentInstanceNew(component, &audioUnit);
|
||||
if (err != noErr) {
|
||||
ERROR_LOG(AUDIO, "coreaudio: AudioComponentInstanceNew failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
FillOutASBDForLPCM(format, 44100,
|
||||
2, 16, 16, false, false, false);
|
||||
err = AudioUnitSetProperty(audioUnit,
|
||||
kAudioUnitProperty_StreamFormat,
|
||||
kAudioUnitScope_Input, 0, &format,
|
||||
sizeof(AudioStreamBasicDescription));
|
||||
if (err != noErr)
|
||||
{
|
||||
ERROR_LOG(AUDIO, "coreaudio: AudioUnitSetProperty(kAudioUnitProperty_StreamFormat) failed");
|
||||
AudioComponentInstanceDispose(audioUnit);
|
||||
return false;
|
||||
}
|
||||
|
||||
callback_struct.inputProc = renderCallback;
|
||||
callback_struct.inputProcRefCon = this;
|
||||
err = AudioUnitSetProperty(audioUnit,
|
||||
kAudioUnitProperty_SetRenderCallback,
|
||||
kAudioUnitScope_Input, 0, &callback_struct,
|
||||
sizeof callback_struct);
|
||||
if (err != noErr)
|
||||
{
|
||||
ERROR_LOG(AUDIO, "coreaudio: AudioUnitSetProperty(kAudioUnitProperty_SetRenderCallback) failed");
|
||||
AudioComponentInstanceDispose(audioUnit);
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
err = AudioUnitSetParameter(audioUnit,
|
||||
kHALOutputParam_Volume,
|
||||
kAudioUnitParameterFlag_Output, 0,
|
||||
1, 0);
|
||||
verify(err == noErr);
|
||||
*/
|
||||
|
||||
err = AudioUnitInitialize(audioUnit);
|
||||
if (err != noErr)
|
||||
{
|
||||
ERROR_LOG(AUDIO, "coreaudio: AudioUnitInitialize failed");
|
||||
AudioComponentInstanceDispose(audioUnit);
|
||||
return false;
|
||||
}
|
||||
|
||||
BUFSIZE = config::AudioBufferSize * 4;
|
||||
samples_temp = new u8[BUFSIZE]();
|
||||
samples_rptr = 0;
|
||||
samples_wptr = 0;
|
||||
|
||||
err = AudioOutputUnitStart(audioUnit);
|
||||
if (err != noErr)
|
||||
{
|
||||
ERROR_LOG(AUDIO, "coreaudio: AudioOutputUnitStart failed");
|
||||
AudioUnitUninitialize(audioUnit);
|
||||
AudioComponentInstanceDispose(audioUnit);
|
||||
return false;
|
||||
}
|
||||
|
||||
bufferEmpty.Set();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
u32 push(const void* frame, u32 samples, bool wait) override
|
||||
{
|
||||
int size = samples * 4;
|
||||
while (size != 0)
|
||||
{
|
||||
int avail = (samples_rptr - samples_wptr - 4 + BUFSIZE) % BUFSIZE;
|
||||
if (avail == 0)
|
||||
{
|
||||
if (!wait)
|
||||
break;
|
||||
bufferEmpty.Wait();
|
||||
continue;
|
||||
}
|
||||
avail = std::min(avail, size);
|
||||
avail = std::min(avail, (int)BUFSIZE - samples_wptr);
|
||||
memcpy(&samples_temp[samples_wptr], frame, avail);
|
||||
samples_wptr = (samples_wptr + avail) % BUFSIZE;
|
||||
frame = (u8 *)frame + avail;
|
||||
size -= avail;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void term() override
|
||||
{
|
||||
AudioOutputUnitStop(audioUnit);
|
||||
AudioUnitUninitialize(audioUnit);
|
||||
AudioComponentInstanceDispose(audioUnit);
|
||||
bufferEmpty.Set();
|
||||
delete [] samples_temp;
|
||||
samples_temp = nullptr;
|
||||
}
|
||||
|
||||
static void recordCallback(void *inUserData, AudioQueueRef inAQ, AudioQueueBufferRef inBuffer,
|
||||
const AudioTimeStamp *inStartTime, UInt32 frameSize, const AudioStreamPacketDescription *dataFormat)
|
||||
{
|
||||
//DEBUG_LOG(AUDIO, "AudioQueue callback: wptr %d rptr %d bytes %d", (int)input_wptr, (int)input_rptr, inBuffer->mAudioDataByteSize);
|
||||
CoreAudioBackend *backend = (CoreAudioBackend *)inUserData;
|
||||
UInt32 size = inBuffer->mAudioDataByteSize;
|
||||
UInt32 freeSpace = (backend->input_rptr - backend->input_wptr - 2 + InputBufSize) % InputBufSize;
|
||||
if (size > freeSpace)
|
||||
{
|
||||
DEBUG_LOG(AUDIO, "coreaudio: record overrun %d bytes", size - freeSpace);
|
||||
size = freeSpace;
|
||||
}
|
||||
while (size != 0)
|
||||
{
|
||||
UInt32 chunk = std::min(size, (UInt32)(InputBufSize - backend->input_wptr));
|
||||
memcpy(backend->samples_input + backend->input_wptr, inBuffer->mAudioData, chunk);
|
||||
backend->input_wptr = (backend->input_wptr + chunk) % InputBufSize;
|
||||
size -= chunk;
|
||||
}
|
||||
AudioQueueEnqueueBuffer(backend->recordQueue, inBuffer, 0, nullptr);
|
||||
}
|
||||
|
||||
void termRecord() override
|
||||
{
|
||||
if (recordQueue != nullptr)
|
||||
{
|
||||
AudioQueueStop(recordQueue, true);
|
||||
AudioQueueDispose(recordQueue, true);
|
||||
recordQueue = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
bool initRecord(u32 sampling_freq) override
|
||||
{
|
||||
AudioStreamBasicDescription desc{};
|
||||
desc.mFormatID = kAudioFormatLinearPCM;
|
||||
desc.mSampleRate = (double)sampling_freq;
|
||||
desc.mChannelsPerFrame = 1;
|
||||
desc.mBitsPerChannel = 16;
|
||||
desc.mBytesPerPacket = desc.mBytesPerFrame = 2;
|
||||
desc.mFramesPerPacket = 1;
|
||||
desc.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger | kLinearPCMFormatFlagIsPacked;
|
||||
desc.mReserved = 0;
|
||||
|
||||
OSStatus err = AudioQueueNewInput(&desc,
|
||||
recordCallback,
|
||||
this,
|
||||
nullptr,
|
||||
kCFRunLoopCommonModes,
|
||||
0,
|
||||
&recordQueue);
|
||||
if (err != noErr)
|
||||
{
|
||||
ERROR_LOG(AUDIO, "AudioQueueNewInput failed: %d", err);
|
||||
return false;
|
||||
}
|
||||
|
||||
AudioQueueBufferRef buffers[2];
|
||||
for (UInt32 i = 0; i < std::size(buffers) && err == noErr; i++)
|
||||
{
|
||||
err = AudioQueueAllocateBuffer(recordQueue, 480, &buffers[i]);
|
||||
if (err == noErr)
|
||||
err = AudioQueueEnqueueBuffer(recordQueue, buffers[i], 0, nullptr);
|
||||
}
|
||||
input_wptr = 0;
|
||||
input_rptr = 0;
|
||||
if (err == noErr)
|
||||
err = AudioQueueStart(recordQueue, nullptr);
|
||||
if (err != noErr)
|
||||
{
|
||||
ERROR_LOG(AUDIO, "AudioQueue init failed: %d", err);
|
||||
termRecord();
|
||||
return false;
|
||||
}
|
||||
INFO_LOG(AUDIO, "AudioQueue initialized - sample rate %f", desc.mSampleRate);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
u32 record(void* frame, u32 samples) override
|
||||
{
|
||||
// DEBUG_LOG(AUDIO, "coreaudio_record: wptr %d rptr %d", (int)input_wptr, (int)input_rptr);
|
||||
u32 size = samples * 2;
|
||||
while (size != 0)
|
||||
{
|
||||
u32 avail = (input_wptr - input_rptr + InputBufSize) % InputBufSize;
|
||||
if (avail == 0)
|
||||
{
|
||||
DEBUG_LOG(AUDIO, "coreaudio: record underrun %d bytes", size);
|
||||
break;
|
||||
}
|
||||
avail = std::min(avail, size);
|
||||
avail = std::min(avail, (u32)(InputBufSize - input_rptr));
|
||||
|
||||
memcpy(frame, &samples_input[input_rptr], avail);
|
||||
frame = (u8 *)frame + avail;
|
||||
input_rptr = (input_rptr + avail) % InputBufSize;
|
||||
size -= avail;
|
||||
}
|
||||
|
||||
return samples - size / 2;
|
||||
}
|
||||
};
|
||||
static CoreAudioBackend coreAudioBackend;
|
||||
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,242 @@
|
||||
#include "build.h"
|
||||
#if defined(_WIN32) && !defined(TARGET_UWP)
|
||||
#include "audiostream.h"
|
||||
#include "cfg/option.h"
|
||||
#include <initguid.h>
|
||||
#include <dsound.h>
|
||||
#include <vector>
|
||||
#include <atomic>
|
||||
#include <thread>
|
||||
#include "stdclass.h"
|
||||
#include "windows/comptr.h"
|
||||
#include "oslib/oslib.h"
|
||||
|
||||
HWND getNativeHwnd();
|
||||
#define verifyc(x) verify(!FAILED(x))
|
||||
|
||||
#ifdef __CRT_UUID_DECL
|
||||
__CRT_UUID_DECL(IDirectSoundBuffer8, 0x6825A449,0x7524,0x4D82,0x92,0x0F,0x50,0xE3,0x6A,0xB3,0xAB,0x1E);
|
||||
__CRT_UUID_DECL(IDirectSoundNotify, 0xB0210783,0x89cd,0x11d0,0xAF,0x08,0x00,0xA0,0xC9,0x25,0xCD,0x16);
|
||||
__CRT_UUID_DECL(IDirectSoundCaptureBuffer8, 0x00990DF4,0x0DBB,0x4872,0x83,0x3E,0x6D,0x30,0x3E,0x80,0xAE,0xB6);
|
||||
#else
|
||||
struct __declspec(uuid("{6825A449-7524-4D82-920F-50E36AB3AB1E}")) IDirectSoundBuffer8;
|
||||
struct __declspec(uuid("{B0210783-89cd-11d0-AF08-00A0C925CD16}")) IDirectSoundNotify;
|
||||
struct __declspec(uuid("{00990DF4-0DBB-4872-833E-6D303E80AEB6}")) IDirectSoundCaptureBuffer8;
|
||||
#endif
|
||||
|
||||
class DirectSoundBackend : public AudioBackend
|
||||
{
|
||||
ComPtr<IDirectSound8> dsound;
|
||||
ComPtr<IDirectSoundBuffer8> buffer;
|
||||
std::vector<HANDLE> notificationEvents;
|
||||
|
||||
ComPtr<IDirectSoundCapture8> dcapture;
|
||||
ComPtr<IDirectSoundCaptureBuffer8> capture_buffer;
|
||||
|
||||
std::atomic_bool audioThreadRunning;
|
||||
std::thread audioThread;
|
||||
cResetEvent pushWait;
|
||||
|
||||
static constexpr u32 SAMPLE_BYTES = SAMPLE_COUNT * 4;
|
||||
|
||||
RingBuffer ringBuffer;
|
||||
|
||||
u32 notificationOffset(int index) {
|
||||
return index * SAMPLE_BYTES;
|
||||
}
|
||||
|
||||
void audioThreadMain()
|
||||
{
|
||||
ThreadName _("FlyDirectSound");
|
||||
audioThreadRunning = true;
|
||||
while (true)
|
||||
{
|
||||
u32 rv = WaitForMultipleObjects(notificationEvents.size(), ¬ificationEvents[0], false, 100);
|
||||
|
||||
if (!audioThreadRunning)
|
||||
break;
|
||||
if (rv == WAIT_TIMEOUT || rv == WAIT_FAILED)
|
||||
continue;
|
||||
rv -= WAIT_OBJECT_0;
|
||||
|
||||
void *p1, *p2;
|
||||
DWORD sz1, sz2;
|
||||
|
||||
if (SUCCEEDED(buffer->Lock(notificationOffset(rv), SAMPLE_BYTES, &p1, &sz1, &p2, &sz2, 0)))
|
||||
{
|
||||
if (!ringBuffer.read((u8*)p1, sz1))
|
||||
memset(p1, 0, sz1);
|
||||
if (sz2 != 0)
|
||||
{
|
||||
if (!ringBuffer.read((u8*)p2, sz2))
|
||||
memset(p2, 0, sz2);
|
||||
}
|
||||
buffer->Unlock(p1, sz1, p2, sz2);
|
||||
pushWait.Set();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
DirectSoundBackend()
|
||||
: AudioBackend("directsound", "Microsoft DirectSound") {}
|
||||
|
||||
bool init() override
|
||||
{
|
||||
if (FAILED(DirectSoundCreate8(NULL, &dsound.get(), NULL))) {
|
||||
ERROR_LOG(AUDIO, "DirectSound8 initialization failed");
|
||||
return false;
|
||||
}
|
||||
if (FAILED(dsound->SetCooperativeLevel(getNativeHwnd(), DSSCL_PRIORITY))) {
|
||||
ERROR_LOG(AUDIO, "DirectSound8 SetCooperativeLevel failed");
|
||||
dsound.reset();
|
||||
return false;
|
||||
}
|
||||
|
||||
// Set up WAV format structure.
|
||||
WAVEFORMATEX wfx;
|
||||
memset(&wfx, 0, sizeof(WAVEFORMATEX));
|
||||
wfx.wFormatTag = WAVE_FORMAT_PCM;
|
||||
wfx.nChannels = 2;
|
||||
wfx.nSamplesPerSec = 44100;
|
||||
wfx.nBlockAlign = 4;
|
||||
wfx.nAvgBytesPerSec = wfx.nSamplesPerSec * wfx.nBlockAlign;
|
||||
wfx.wBitsPerSample = 16;
|
||||
|
||||
// Set up DSBUFFERDESC structure.
|
||||
DSBUFFERDESC desc;
|
||||
memset(&desc, 0, sizeof(DSBUFFERDESC));
|
||||
desc.dwSize = sizeof(DSBUFFERDESC);
|
||||
desc.dwFlags = DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_CTRLPOSITIONNOTIFY | DSBCAPS_GLOBALFOCUS;
|
||||
desc.dwBufferBytes = SAMPLE_BYTES * 2;
|
||||
desc.lpwfxFormat = &wfx;
|
||||
|
||||
// Create the buffer
|
||||
ComPtr<IDirectSoundBuffer> buffer_;
|
||||
if (FAILED(dsound->CreateSoundBuffer(&desc, &buffer_.get(), 0))
|
||||
|| FAILED(buffer_.as(buffer)))
|
||||
{
|
||||
ERROR_LOG(AUDIO, "DirectSound8 CreateSoundBuffer failed");
|
||||
dsound.reset();
|
||||
return false;
|
||||
}
|
||||
|
||||
// Set up notifications
|
||||
ComPtr<IDirectSoundNotify> bufferNotify;
|
||||
verifyc(buffer.as(bufferNotify));
|
||||
notificationEvents.clear();
|
||||
std::vector<DSBPOSITIONNOTIFY> posNotify;
|
||||
for (int i = 0; notificationOffset(i) < desc.dwBufferBytes; i++)
|
||||
{
|
||||
notificationEvents.push_back(CreateEvent(nullptr, false, false, nullptr));
|
||||
posNotify.push_back({ notificationOffset(i), notificationEvents.back() });
|
||||
}
|
||||
bufferNotify->SetNotificationPositions(posNotify.size(), &posNotify[0]);
|
||||
|
||||
// Clear the buffers
|
||||
void *p1, *p2;
|
||||
DWORD sz1, sz2;
|
||||
verifyc(buffer->Lock(0, desc.dwBufferBytes, &p1, &sz1, &p2, &sz2, 0));
|
||||
verify(p2 == nullptr);
|
||||
memset(p1, 0, sz1);
|
||||
verifyc(buffer->Unlock(p1, sz1, p2, sz2));
|
||||
ringBuffer.setCapacity(config::AudioBufferSize * 4);
|
||||
|
||||
// Start the thread
|
||||
audioThread = std::thread(&DirectSoundBackend::audioThreadMain, this);
|
||||
|
||||
// Play the buffer !
|
||||
if (FAILED(buffer->Play(0, 0, DSBPLAY_LOOPING)))
|
||||
{
|
||||
ERROR_LOG(AUDIO, "DirectSound8 Play failed");
|
||||
term();
|
||||
return false;
|
||||
}
|
||||
INFO_LOG(AUDIO, "DirectSound playback started");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
u32 push(const void* frame, u32 samples, bool wait) override
|
||||
{
|
||||
while (!ringBuffer.write((const u8 *)frame, samples * 4) && wait)
|
||||
pushWait.Wait();
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void term() override
|
||||
{
|
||||
audioThreadRunning = false;
|
||||
audioThread.join();
|
||||
buffer->Stop();
|
||||
|
||||
for (HANDLE event : notificationEvents)
|
||||
CloseHandle(event);
|
||||
buffer.reset();
|
||||
dsound.reset();
|
||||
INFO_LOG(AUDIO, "DirectSound playback stopped");
|
||||
}
|
||||
|
||||
bool initRecord(u32 sampling_freq) override
|
||||
{
|
||||
if (FAILED(DirectSoundCaptureCreate8(&DSDEVID_DefaultVoiceCapture, &dcapture.get(), NULL)))
|
||||
{
|
||||
ERROR_LOG(AUDIO, "DirectSound capture device creation failed");
|
||||
return false;
|
||||
}
|
||||
HRESULT hr;
|
||||
WAVEFORMATEX wfx =
|
||||
{ WAVE_FORMAT_PCM, 1, sampling_freq, sampling_freq * 2, 2, 16, 0 };
|
||||
// wFormatTag, nChannels, nSamplesPerSec, nAvgBytesPerSec,
|
||||
// nBlockAlign, wBitsPerSample, cbSize
|
||||
|
||||
DSCBUFFERDESC dscbd;
|
||||
dscbd.dwSize = sizeof(DSCBUFFERDESC);
|
||||
dscbd.dwFlags = 0;
|
||||
dscbd.dwBufferBytes = 480 * 2;
|
||||
dscbd.dwReserved = 0;
|
||||
dscbd.lpwfxFormat = &wfx;
|
||||
dscbd.dwFXCount = 0;
|
||||
dscbd.lpDSCFXDesc = NULL;
|
||||
|
||||
ComPtr<IDirectSoundCaptureBuffer> pDSCB;
|
||||
if (FAILED(hr = dcapture->CreateCaptureBuffer(&dscbd, &pDSCB.get(), NULL)))
|
||||
{
|
||||
ERROR_LOG(AUDIO, "DirectSound capture buffer creation failed");
|
||||
dcapture.reset();
|
||||
return false;
|
||||
}
|
||||
pDSCB.as(capture_buffer);
|
||||
capture_buffer->Start(DSCBSTART_LOOPING);
|
||||
INFO_LOG(AUDIO, "DirectSound capture device and buffer created");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
u32 record(void *buffer, u32 samples) override
|
||||
{
|
||||
DWORD readPos;
|
||||
capture_buffer->GetCurrentPosition(NULL, &readPos);
|
||||
void *p1, *p2;
|
||||
DWORD p1bytes, p2bytes;
|
||||
capture_buffer->Lock(readPos, samples * 2, &p1, &p1bytes, &p2, &p2bytes, 0);
|
||||
memcpy(buffer, p1, p1bytes);
|
||||
if (p2bytes > 0)
|
||||
memcpy((u8 *)buffer + p1bytes, p2, p2bytes);
|
||||
capture_buffer->Unlock(p1, p1bytes, p2, p2bytes);
|
||||
return (p1bytes + p2bytes) / 2;
|
||||
}
|
||||
|
||||
void termRecord() override
|
||||
{
|
||||
if (!dcapture)
|
||||
return;
|
||||
capture_buffer->Stop();
|
||||
capture_buffer.reset();
|
||||
dcapture.reset();
|
||||
}
|
||||
};
|
||||
static DirectSoundBackend directSoundBackend;
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,54 @@
|
||||
#ifdef USE_LIBAO
|
||||
#include "audiostream.h"
|
||||
#include <ao/ao.h>
|
||||
|
||||
class LibAOBackend : public AudioBackend
|
||||
{
|
||||
ao_device *aodevice = nullptr;
|
||||
|
||||
public:
|
||||
LibAOBackend()
|
||||
: AudioBackend("libao", "libao") {}
|
||||
|
||||
bool init() override
|
||||
{
|
||||
ao_initialize();
|
||||
|
||||
ao_sample_format aoformat {};
|
||||
aoformat.bits = 16;
|
||||
aoformat.channels = 2;
|
||||
aoformat.rate = 44100;
|
||||
aoformat.byte_format = AO_FMT_LITTLE;
|
||||
|
||||
aodevice = ao_open_live(ao_default_driver_id(), &aoformat, NULL); // Live output
|
||||
if (aodevice == nullptr)
|
||||
aodevice = ao_open_live(ao_driver_id("null"), &aoformat, NULL);
|
||||
if (aodevice == nullptr) {
|
||||
ERROR_LOG(AUDIO, "Cannot open libao driver");
|
||||
ao_shutdown();
|
||||
}
|
||||
|
||||
return aodevice != nullptr;
|
||||
}
|
||||
|
||||
u32 push(const void* frame, u32 samples, bool wait) override
|
||||
{
|
||||
if (aodevice != nullptr)
|
||||
ao_play(aodevice, (char*)frame, samples * 4);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void term() override
|
||||
{
|
||||
if (aodevice != nullptr)
|
||||
{
|
||||
ao_close(aodevice);
|
||||
aodevice = nullptr;
|
||||
ao_shutdown();
|
||||
}
|
||||
}
|
||||
};
|
||||
static LibAOBackend libAOBackend;
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,51 @@
|
||||
#include "audiostream.h"
|
||||
|
||||
#include <chrono>
|
||||
#include <thread>
|
||||
|
||||
class NullAudioBackend : public AudioBackend
|
||||
{
|
||||
using the_clock = std::chrono::high_resolution_clock;
|
||||
|
||||
public:
|
||||
NullAudioBackend()
|
||||
: AudioBackend("null", "No Audio") {}
|
||||
|
||||
bool init() override
|
||||
{
|
||||
last_time = the_clock::time_point();
|
||||
return true;
|
||||
}
|
||||
|
||||
u32 push(const void* frame, u32 samples, bool wait) override
|
||||
{
|
||||
if (wait)
|
||||
{
|
||||
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);
|
||||
std::this_thread::sleep_for(duration);
|
||||
last_time += fduration;
|
||||
}
|
||||
else
|
||||
last_time = the_clock::now();
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
bool initRecord(u32 sampling_freq) override
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
u32 record(void *buffer, u32 samples) override
|
||||
{
|
||||
memset(buffer, 0, samples * 2);
|
||||
return samples;
|
||||
}
|
||||
|
||||
private:
|
||||
the_clock::time_point last_time;
|
||||
};
|
||||
static NullAudioBackend nullBackend;
|
||||
@@ -0,0 +1,201 @@
|
||||
/*
|
||||
Copyright 2021 flyinghead
|
||||
|
||||
This file is part of Flycast.
|
||||
|
||||
Flycast is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Flycast is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Flycast. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifdef USE_OBOE
|
||||
#include "audiostream.h"
|
||||
#include "cfg/option.h"
|
||||
#include <oboe/Oboe.h>
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
#include <atomic>
|
||||
#include <memory>
|
||||
#include "stdclass.h"
|
||||
|
||||
class OboeBackend : AudioBackend
|
||||
{
|
||||
RingBuffer ringBuffer;
|
||||
cResetEvent pushWait;
|
||||
|
||||
std::shared_ptr<oboe::AudioStream> stream;
|
||||
std::shared_ptr<oboe::AudioStream> recordStream;
|
||||
|
||||
class AudioCallback : public oboe::AudioStreamDataCallback
|
||||
{
|
||||
public:
|
||||
AudioCallback(OboeBackend *backend) : backend(backend) {}
|
||||
|
||||
oboe::DataCallbackResult onAudioReady(oboe::AudioStream *audioStream, void *audioData, int32_t numFrames) override
|
||||
{
|
||||
if (!backend->ringBuffer.read((u8 *)audioData, numFrames * 4))
|
||||
// underrun
|
||||
memset(audioData, 0, numFrames * 4);
|
||||
backend->pushWait.Set();
|
||||
|
||||
return oboe::DataCallbackResult::Continue;
|
||||
}
|
||||
|
||||
OboeBackend *backend;
|
||||
};
|
||||
AudioCallback audioCallback;
|
||||
|
||||
class AudioErrorCallback : public oboe::AudioStreamErrorCallback
|
||||
{
|
||||
public:
|
||||
AudioErrorCallback(OboeBackend *backend) : backend(backend) {}
|
||||
|
||||
void onErrorAfterClose(oboe::AudioStream *stream, oboe::Result error) override
|
||||
{
|
||||
// Only attempt to recover if init was successful
|
||||
if (backend->stream != nullptr)
|
||||
{
|
||||
WARN_LOG(AUDIO, "Audio device lost. Attempting to reopen the audio stream");
|
||||
// the oboe stream is already closed so make sure we don't close it twice
|
||||
backend->stream.reset();
|
||||
backend->term();
|
||||
backend->init();
|
||||
}
|
||||
}
|
||||
|
||||
OboeBackend *backend;
|
||||
};
|
||||
AudioErrorCallback errorCallback;
|
||||
|
||||
public:
|
||||
OboeBackend()
|
||||
: AudioBackend("Oboe", "Automatic AAudio / OpenSL selection"), audioCallback(this), errorCallback(this) {}
|
||||
|
||||
bool init() override
|
||||
{
|
||||
// Actual capacity is size-1 to avoid overrun so add one buffer
|
||||
ringBuffer.setCapacity((config::AudioBufferSize + SAMPLE_COUNT) * 4);
|
||||
|
||||
oboe::AudioStreamBuilder builder;
|
||||
oboe::Result result = builder.setDirection(oboe::Direction::Output)
|
||||
->setPerformanceMode(oboe::PerformanceMode::LowLatency)
|
||||
->setSharingMode(oboe::SharingMode::Exclusive)
|
||||
->setFormat(oboe::AudioFormat::I16)
|
||||
->setChannelCount(oboe::ChannelCount::Stereo)
|
||||
->setSampleRate(44100)
|
||||
->setSampleRateConversionQuality(oboe::SampleRateConversionQuality::High)
|
||||
->setFramesPerCallback(SAMPLE_COUNT)
|
||||
->setDataCallback(&audioCallback)
|
||||
->setErrorCallback(&errorCallback)
|
||||
->setUsage(oboe::Usage::Game)
|
||||
->openStream(stream);
|
||||
if (result != oboe::Result::OK)
|
||||
{
|
||||
ERROR_LOG(AUDIO, "Oboe open stream failed: %s", oboe::convertToText(result));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (stream->getAudioApi() == oboe::AudioApi::AAudio && config::AudioBufferSize < 1764)
|
||||
{
|
||||
// Reduce internal buffer for low latency (< 40 ms)
|
||||
int bufSize = stream->getBufferSizeInFrames();
|
||||
int burst = stream->getFramesPerBurst();
|
||||
if (bufSize - burst > SAMPLE_COUNT)
|
||||
{
|
||||
while (bufSize - burst > SAMPLE_COUNT)
|
||||
bufSize -= burst;
|
||||
stream->setBufferSizeInFrames(bufSize);
|
||||
}
|
||||
}
|
||||
|
||||
stream->requestStart();
|
||||
NOTICE_LOG(AUDIO, "Oboe driver started. stream capacity: %d frames, size: %d frames, frames/callback: %d, frames/burst: %d",
|
||||
stream->getBufferCapacityInFrames(), stream->getBufferSizeInFrames(),
|
||||
stream->getFramesPerCallback(), stream->getFramesPerBurst());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void term() override
|
||||
{
|
||||
NOTICE_LOG(AUDIO, "Oboe driver stopping");
|
||||
if (stream != nullptr)
|
||||
{
|
||||
// Don't let the AudioErrorCallback term/reinit while we are stopping
|
||||
// This won't prevent shit to hit the fan if it's already in the process
|
||||
// of doing so but this is a pretty rare event and happens on devices
|
||||
// that have audio issues already.
|
||||
auto localStream = stream;
|
||||
stream.reset();
|
||||
localStream->stop();
|
||||
localStream->close();
|
||||
}
|
||||
}
|
||||
|
||||
u32 push(const void* frame, u32 samples, bool wait) override
|
||||
{
|
||||
while (!ringBuffer.write((const u8 *)frame, samples * 4) && wait)
|
||||
pushWait.Wait();
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void termRecord() override
|
||||
{
|
||||
if (recordStream != nullptr)
|
||||
{
|
||||
recordStream->stop();
|
||||
recordStream->close();
|
||||
recordStream.reset();
|
||||
}
|
||||
NOTICE_LOG(AUDIO, "Oboe recorder stopped");
|
||||
}
|
||||
|
||||
bool initRecord(u32 sampling_freq) override
|
||||
{
|
||||
oboe::AudioStreamBuilder builder;
|
||||
oboe::Result result = builder.setDirection(oboe::Direction::Input)
|
||||
->setPerformanceMode(oboe::PerformanceMode::None)
|
||||
->setSharingMode(oboe::SharingMode::Exclusive)
|
||||
->setFormat(oboe::AudioFormat::I16)
|
||||
->setChannelCount(oboe::ChannelCount::Mono)
|
||||
->setSampleRate(sampling_freq)
|
||||
->openStream(recordStream);
|
||||
if (result != oboe::Result::OK)
|
||||
{
|
||||
ERROR_LOG(AUDIO, "Oboe open record stream failed: %s", oboe::convertToText(result));
|
||||
return false;
|
||||
}
|
||||
recordStream->requestStart();
|
||||
NOTICE_LOG(AUDIO, "Oboe recorder started. stream capacity: %d frames",
|
||||
recordStream->getBufferCapacityInFrames());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
u32 record(void *data, u32 samples) override
|
||||
{
|
||||
if (recordStream == nullptr)
|
||||
return 0;
|
||||
oboe::ResultWithValue<int32_t> result = recordStream->read(data, samples, 0);
|
||||
if (result == oboe::Result::ErrorDisconnected)
|
||||
{
|
||||
WARN_LOG(AUDIO, "Recording device lost. Attempting to reopen the audio stream");
|
||||
u32 sampleRate = recordStream->getSampleRate();
|
||||
termRecord();
|
||||
initRecord(sampleRate);
|
||||
}
|
||||
return std::max(0, result.value());
|
||||
}
|
||||
};
|
||||
static OboeBackend oboeBackend;
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,337 @@
|
||||
#if USE_OMX
|
||||
#include "audiostream.h"
|
||||
#include "cfg/option.h"
|
||||
#include <IL/OMX_Broadcom.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#define PORT_INDEX 100
|
||||
#define OUTPUT_FREQ 44100
|
||||
|
||||
class OMXAudioBackend : public AudioBackend
|
||||
{
|
||||
OMX_HANDLETYPE omx_handle = nullptr;
|
||||
OMX_STATETYPE omx_state = OMX_StateInvalid;
|
||||
size_t audio_buffer_idx = 0;
|
||||
OMX_BUFFERHEADERTYPE** audio_buffers = nullptr;
|
||||
u32 latency_max = 0;
|
||||
u32 buffer_count = 0;
|
||||
u32 buffer_size = 0;
|
||||
u32 buffer_length = 0;
|
||||
pthread_mutex_t audio_lock;
|
||||
pthread_cond_t omx_state_cond;
|
||||
|
||||
static OMX_ERRORTYPE eventHandler(
|
||||
OMX_IN OMX_HANDLETYPE hComponent,
|
||||
OMX_IN OMX_PTR pAppData,
|
||||
OMX_IN OMX_EVENTTYPE eEvent,
|
||||
OMX_IN OMX_U32 nData1,
|
||||
OMX_IN OMX_U32 nData2,
|
||||
OMX_IN OMX_PTR pEventData)
|
||||
{
|
||||
OMXAudioBackend *backend = (OMXAudioBackend *)pAddData;
|
||||
pthread_mutex_lock(&backend->audio_lock);
|
||||
if(eEvent == OMX_EventCmdComplete && nData1 == OMX_CommandStateSet)
|
||||
{
|
||||
backend->omx_state = (OMX_STATETYPE)nData2;
|
||||
pthread_cond_signal(&backend->omx_state_cond);
|
||||
}
|
||||
pthread_mutex_unlock(&backend->audio_lock);
|
||||
return OMX_ErrorNone;
|
||||
}
|
||||
|
||||
static OMX_ERRORTYPE emptyBufferDone(
|
||||
OMX_IN OMX_HANDLETYPE hComponent,
|
||||
OMX_IN OMX_PTR pAppData,
|
||||
OMX_IN OMX_BUFFERHEADERTYPE* pBuffer)
|
||||
{
|
||||
return OMX_ErrorNone;
|
||||
}
|
||||
|
||||
static OMX_ERRORTYPE fillBufferDone(
|
||||
OMX_OUT OMX_HANDLETYPE hComponent,
|
||||
OMX_OUT OMX_PTR pAppData,
|
||||
OMX_OUT OMX_BUFFERHEADERTYPE* pBuffer)
|
||||
{
|
||||
return OMX_ErrorNone;
|
||||
}
|
||||
|
||||
void waitForState(OMX_STATETYPE state)
|
||||
{
|
||||
pthread_mutex_lock(&audio_lock);
|
||||
while(omx_state != state)
|
||||
pthread_cond_wait(&omx_state_cond, &audio_lock);
|
||||
pthread_mutex_unlock(&audio_lock);
|
||||
}
|
||||
|
||||
u32 getLatency()
|
||||
{
|
||||
OMX_PARAM_U32TYPE param;
|
||||
memset(¶m, 0, sizeof(OMX_PARAM_U32TYPE));
|
||||
param.nSize = sizeof(OMX_PARAM_U32TYPE);
|
||||
param.nVersion.nVersion = OMX_VERSION;
|
||||
param.nPortIndex = PORT_INDEX;
|
||||
|
||||
OMX_ERRORTYPE error = OMX_GetConfig(omx_handle, OMX_IndexConfigAudioRenderingLatency, ¶m);
|
||||
if(error != OMX_ErrorNone)
|
||||
WARN_LOG(AUDIO, "OMX: failed to get OMX configuration (OMX_IndexConfigAudioRenderingLatency). Error 0x%X", error);
|
||||
|
||||
return param.nU32 * 1000 / OUTPUT_FREQ;
|
||||
}
|
||||
|
||||
public:
|
||||
OMXAudioBackend()
|
||||
: AudioBackend("omx", "OpenMAX IL") {}
|
||||
|
||||
bool init() override
|
||||
{
|
||||
OMX_ERRORTYPE error;
|
||||
|
||||
error = OMX_Init();
|
||||
if (error != OMX_ErrorNone)
|
||||
{
|
||||
WARN_LOG(AUDIO, "OMX: OMX_Init() failed. Error 0x%X", error);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Initialize settings
|
||||
latency_max = config::OmxAudioLatency;
|
||||
buffer_size = config::AudioBufferSize * 4;
|
||||
buffer_count = 2 + OUTPUT_FREQ * latency_max / (buffer_size * 1000);
|
||||
|
||||
OMX_CALLBACKTYPE callbacks;
|
||||
callbacks.EventHandler = eventHandler;
|
||||
callbacks.EmptyBufferDone = emptyBufferDone;
|
||||
callbacks.FillBufferDone = fillBufferDone;
|
||||
|
||||
error = OMX_GetHandle(&omx_handle, (OMX_STRING)"OMX.broadcom.audio_render", this, &callbacks);
|
||||
if (error != OMX_ErrorNone)
|
||||
{
|
||||
WARN_LOG(AUDIO, "OMX: OMX_GetHandle() failed. Error 0x%X", error);
|
||||
OMX_Deinit();
|
||||
return false;
|
||||
}
|
||||
|
||||
OMX_PARAM_PORTDEFINITIONTYPE param;
|
||||
memset(¶m, 0, sizeof(OMX_PARAM_PORTDEFINITIONTYPE));
|
||||
param.nSize = sizeof(OMX_PARAM_PORTDEFINITIONTYPE);
|
||||
param.nVersion.nVersion = OMX_VERSION;
|
||||
param.nPortIndex = PORT_INDEX;
|
||||
param.nBufferSize = buffer_size;
|
||||
param.nBufferCountActual = buffer_count;
|
||||
param.format.audio.eEncoding = OMX_AUDIO_CodingPCM;
|
||||
|
||||
error = OMX_SetParameter(omx_handle, OMX_IndexParamPortDefinition, ¶m);
|
||||
if (error != OMX_ErrorNone)
|
||||
{
|
||||
WARN_LOG(AUDIO, "OMX: failed to set OMX_IndexParamPortDefinition. Error 0x%X", error);
|
||||
OMX_Deinit();
|
||||
return false;
|
||||
}
|
||||
|
||||
OMX_AUDIO_PARAM_PCMMODETYPE pcm;
|
||||
memset(&pcm, 0, sizeof(OMX_AUDIO_PARAM_PCMMODETYPE));
|
||||
pcm.nSize = sizeof(OMX_AUDIO_PARAM_PCMMODETYPE);
|
||||
pcm.nVersion.nVersion = OMX_VERSION;
|
||||
pcm.nPortIndex = PORT_INDEX;
|
||||
pcm.nChannels = 2;
|
||||
pcm.eNumData = OMX_NumericalDataSigned;
|
||||
pcm.eEndian = OMX_EndianLittle;
|
||||
pcm.nSamplingRate = OUTPUT_FREQ;
|
||||
pcm.bInterleaved = OMX_TRUE;
|
||||
pcm.nBitPerSample = 16;
|
||||
pcm.ePCMMode = OMX_AUDIO_PCMModeLinear;
|
||||
pcm.eChannelMapping[1] = OMX_AUDIO_ChannelRF;
|
||||
pcm.eChannelMapping[0] = OMX_AUDIO_ChannelLF;
|
||||
|
||||
error = OMX_SetParameter(omx_handle, OMX_IndexParamAudioPcm, &pcm);
|
||||
if (error != OMX_ErrorNone)
|
||||
{
|
||||
WARN_LOG(AUDIO, "OMX: failed to set OMX_IndexParamAudioPcm. Error 0x%X", error);
|
||||
OMX_Deinit();
|
||||
return false;
|
||||
}
|
||||
|
||||
// Disable all ports
|
||||
error = OMX_SendCommand(omx_handle, OMX_CommandPortDisable, PORT_INDEX, NULL);
|
||||
if (error != OMX_ErrorNone)
|
||||
WARN_LOG(AUDIO, "OMX: failed to do OMX_CommandPortDisable. Error 0x%X", error);
|
||||
|
||||
OMX_PORT_PARAM_TYPE param2;
|
||||
memset(¶m2, 0, sizeof(OMX_PORT_PARAM_TYPE));
|
||||
param2.nSize = sizeof(OMX_PORT_PARAM_TYPE);
|
||||
param2.nVersion.nVersion = OMX_VERSION;
|
||||
error = OMX_GetParameter(omx_handle, OMX_IndexParamOtherInit, ¶m2);
|
||||
if (error != OMX_ErrorNone)
|
||||
{
|
||||
WARN_LOG(AUDIO, "OMX: failed to get OMX_IndexParamOtherInit. Error 0x%X", error);
|
||||
}
|
||||
else
|
||||
{
|
||||
for(u32 i = 0; i < param2.nPorts; i++)
|
||||
{
|
||||
u32 port = param2.nStartPortNumber + i;
|
||||
error = OMX_SendCommand(omx_handle, OMX_CommandPortDisable, port, NULL);
|
||||
if(error != OMX_ErrorNone)
|
||||
WARN_LOG(AUDIO, "OMX: failed to do OMX_CommandPortDisable on port %u. Error 0x%X", port, error);
|
||||
}
|
||||
}
|
||||
|
||||
// Go into idle state
|
||||
error = OMX_SendCommand(omx_handle, OMX_CommandStateSet, OMX_StateIdle, NULL);
|
||||
if (error != OMX_ErrorNone)
|
||||
{
|
||||
WARN_LOG(AUDIO, "OMX: failed to set OMX_CommandStateSet. Error 0x%X", error);
|
||||
OMX_Deinit();
|
||||
return false;
|
||||
}
|
||||
waitForState(OMX_StateIdle);
|
||||
|
||||
// Check if we're in a state able to recieve buffers
|
||||
OMX_STATETYPE state;
|
||||
error = OMX_GetState(omx_handle, &state);
|
||||
if (error != OMX_ErrorNone || !(state == OMX_StateIdle || state == OMX_StateExecuting || state == OMX_StatePause))
|
||||
{
|
||||
WARN_LOG(AUDIO, "OMX: state is incorrect. State 0x%X; Error 0x%X", state, error);
|
||||
OMX_Deinit();
|
||||
return false;
|
||||
}
|
||||
|
||||
// Create audio buffers
|
||||
INFO_LOG(AUDIO, "OMX: creating %u buffers", buffer_count);
|
||||
|
||||
// Enable port
|
||||
error = OMX_SendCommand(omx_handle, OMX_CommandPortEnable, PORT_INDEX, NULL);
|
||||
if (error != OMX_ErrorNone)
|
||||
WARN_LOG(AUDIO, "OMX: failed to do OMX_CommandPortEnable. Error 0x%X", error);
|
||||
|
||||
// Free audio buffers if they're allocated
|
||||
if (audio_buffers != NULL)
|
||||
delete[] audio_buffers;
|
||||
|
||||
// Allocate buffers
|
||||
audio_buffers = new OMX_BUFFERHEADERTYPE*[buffer_count];
|
||||
for (size_t i = 0; i < buffer_count; i++)
|
||||
{
|
||||
error = OMX_AllocateBuffer(omx_handle, &audio_buffers[i], PORT_INDEX, NULL, buffer_size);
|
||||
if (error != OMX_ErrorNone)
|
||||
{
|
||||
WARN_LOG(AUDIO, "OMX: failed to allocate buffer[%u]. Error 0x%X", i, error);
|
||||
OMX_Deinit();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Set state to executing
|
||||
error = OMX_SendCommand(omx_handle, OMX_CommandStateSet, OMX_StateExecuting, NULL);
|
||||
if (error != OMX_ErrorNone)
|
||||
{
|
||||
WARN_LOG(AUDIO, "OMX: failed to do OMX_CommandStateSet. Error 0x%X", error);
|
||||
OMX_Deinit();
|
||||
return false;
|
||||
}
|
||||
waitForState(OMX_StateExecuting);
|
||||
|
||||
// Empty buffers
|
||||
for (size_t i = 0; i < buffer_count; i++)
|
||||
{
|
||||
memset(audio_buffers[i]->pBuffer, 0, buffer_size);
|
||||
audio_buffers[i]->nOffset = 0;
|
||||
audio_buffers[i]->nFilledLen = buffer_size;
|
||||
|
||||
error = OMX_EmptyThisBuffer(omx_handle, audio_buffers[i]);
|
||||
if(error != OMX_ErrorNone)
|
||||
WARN_LOG(AUDIO, "OMX: failed to empty buffer[%u]. Error 0x%X", i, error);
|
||||
}
|
||||
|
||||
const char* output_device = "local";
|
||||
if (config::OmxAudioHdmi)
|
||||
output_device = (const char*)"hdmi";
|
||||
|
||||
// Set audio destination
|
||||
OMX_CONFIG_BRCMAUDIODESTINATIONTYPE ar_dest;
|
||||
memset(&ar_dest, 0, sizeof(ar_dest));
|
||||
ar_dest.nSize = sizeof(OMX_CONFIG_BRCMAUDIODESTINATIONTYPE);
|
||||
ar_dest.nVersion.nVersion = OMX_VERSION;
|
||||
strcpy((char *)ar_dest.sName, output_device);
|
||||
error = OMX_SetConfig(omx_handle, OMX_IndexConfigBrcmAudioDestination, &ar_dest);
|
||||
if (error != OMX_ErrorNone)
|
||||
{
|
||||
WARN_LOG(AUDIO, "OMX: failed to set OMX configuration (OMX_IndexConfigBrcmAudioDestination). Error 0x%X", error);
|
||||
OMX_Deinit();
|
||||
return false;
|
||||
}
|
||||
|
||||
audio_buffer_idx = 0;
|
||||
buffer_length = 0;
|
||||
|
||||
INFO_LOG(AUDIO, "OMX: audio output to '%s'", ar_dest.sName);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
u32 push(const void* frame, u32 samples, bool wait) override
|
||||
{
|
||||
if(audio_buffers == NULL)
|
||||
return 1;
|
||||
|
||||
size_t data_size = samples * 4;
|
||||
|
||||
while(data_size > 0)
|
||||
{
|
||||
size_t copy_size = std::min(buffer_size - buffer_length, data_size);
|
||||
|
||||
// Don't have more than maximum audio latency
|
||||
u32 latency = getLatency();
|
||||
if(latency > latency_max)
|
||||
{
|
||||
usleep((latency - latency_max) * 1000);
|
||||
}
|
||||
else if(latency == 0)
|
||||
{
|
||||
INFO_LOG(AUDIO, "OMX: underrun occurred");
|
||||
}
|
||||
|
||||
memcpy(audio_buffers[audio_buffer_idx]->pBuffer + buffer_length, frame, copy_size);
|
||||
buffer_length += copy_size;
|
||||
frame = (char *)frame + copy_size;
|
||||
|
||||
// Flush buffer and swap
|
||||
if(buffer_length >= buffer_size)
|
||||
{
|
||||
audio_buffers[audio_buffer_idx]->nOffset = 0;
|
||||
audio_buffers[audio_buffer_idx]->nFilledLen = buffer_size;
|
||||
|
||||
OMX_ERRORTYPE error = OMX_EmptyThisBuffer(omx_handle, audio_buffers[audio_buffer_idx]);
|
||||
if(error != OMX_ErrorNone)
|
||||
INFO_LOG(AUDIO, "OMX: failed to empty buffer[%u]. Error 0x%X", audio_buffer_idx, error);
|
||||
|
||||
audio_buffer_idx = (audio_buffer_idx + 1) % buffer_count;
|
||||
buffer_length = 0;
|
||||
}
|
||||
|
||||
data_size -= copy_size;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void term() override
|
||||
{
|
||||
OMX_ERRORTYPE error;
|
||||
|
||||
// Is there anything else that needs to be done for omx?
|
||||
|
||||
error = OMX_Deinit();
|
||||
if(error != OMX_ErrorNone)
|
||||
WARN_LOG(AUDIO, "OMX: OMX_Deinit() failed. Error 0x%X", error);
|
||||
|
||||
if(audio_buffers != NULL)
|
||||
{
|
||||
delete[] audio_buffers;
|
||||
audio_buffers = NULL;
|
||||
}
|
||||
}
|
||||
};
|
||||
static OMXAudioBackend omxAudioBackend;
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,116 @@
|
||||
#ifdef USE_OSS
|
||||
#include "audiostream.h"
|
||||
#include <fcntl.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/soundcard.h>
|
||||
#include <unistd.h>
|
||||
|
||||
class OSSAudioBackend : public AudioBackend
|
||||
{
|
||||
int audioFD = -1;
|
||||
int recordFD = -1;
|
||||
|
||||
public:
|
||||
OSSAudioBackend()
|
||||
: AudioBackend("oss", "Open Sound System") {}
|
||||
|
||||
bool init() override
|
||||
{
|
||||
audioFD = open("/dev/dsp", O_WRONLY);
|
||||
if (audioFD < 0)
|
||||
{
|
||||
WARN_LOG(AUDIO, "Couldn't open /dev/dsp.");
|
||||
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;
|
||||
}
|
||||
|
||||
u32 push(const void* frame, u32 samples, bool wait) override
|
||||
{
|
||||
write(audioFD, frame, samples * 4);
|
||||
return 1;
|
||||
}
|
||||
|
||||
void term() override
|
||||
{
|
||||
if (audioFD >= 0)
|
||||
close(audioFD);
|
||||
audioFD = -1;
|
||||
}
|
||||
|
||||
// recording untested
|
||||
|
||||
bool initRecord(u32 sampling_freq) override
|
||||
{
|
||||
recordFD = open("/dev/dsp", O_RDONLY);
|
||||
if (recordFD < 0)
|
||||
{
|
||||
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;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void termRecord() override
|
||||
{
|
||||
if (recordFD >= 0)
|
||||
close(recordFD);
|
||||
recordFD = -1;
|
||||
}
|
||||
|
||||
u32 record(void *buffer, u32 samples) override
|
||||
{
|
||||
samples *= 2;
|
||||
int l = read(recordFD, buffer, samples);
|
||||
if (l < (int)samples)
|
||||
{
|
||||
if (l < 0)
|
||||
{
|
||||
INFO_LOG(AUDIO, "OSS: Recording error");
|
||||
l = 0;
|
||||
}
|
||||
memset((u8 *)buffer + l, 0, samples - l);
|
||||
}
|
||||
return l / 2;
|
||||
}
|
||||
};
|
||||
static OSSAudioBackend ossAudioBackend;
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,252 @@
|
||||
#ifdef USE_PULSEAUDIO
|
||||
#include "audiostream.h"
|
||||
#include "cfg/option.h"
|
||||
#include <pulse/pulseaudio.h>
|
||||
|
||||
class PulseAudioBackend : public AudioBackend
|
||||
{
|
||||
pa_threaded_mainloop *mainloop = nullptr;
|
||||
pa_context *context = nullptr;
|
||||
pa_stream *stream = nullptr;
|
||||
pa_stream *record_stream = nullptr;
|
||||
|
||||
static void context_state_cb(pa_context *c, void *userdata)
|
||||
{
|
||||
PulseAudioBackend *backend = (PulseAudioBackend *)userdata;
|
||||
switch (pa_context_get_state(c))
|
||||
{
|
||||
case PA_CONTEXT_READY:
|
||||
case PA_CONTEXT_TERMINATED:
|
||||
case PA_CONTEXT_FAILED:
|
||||
pa_threaded_mainloop_signal(backend->mainloop, 0);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void stream_request_cb(pa_stream *s, size_t length, void *userdata)
|
||||
{
|
||||
PulseAudioBackend *backend = (PulseAudioBackend *)userdata;
|
||||
pa_threaded_mainloop_signal(backend->mainloop, 0);
|
||||
}
|
||||
|
||||
public:
|
||||
PulseAudioBackend()
|
||||
: AudioBackend("pulse", "PulseAudio") {}
|
||||
|
||||
bool init() override
|
||||
{
|
||||
mainloop = pa_threaded_mainloop_new();
|
||||
if (!mainloop)
|
||||
{
|
||||
WARN_LOG(AUDIO, "PulseAudio: pa_threaded_mainloop_new failed");
|
||||
return false;
|
||||
}
|
||||
context = pa_context_new(pa_threaded_mainloop_get_api(mainloop), "flycast");
|
||||
if (!context)
|
||||
{
|
||||
WARN_LOG(AUDIO, "PulseAudio: pa_context_new failed");
|
||||
term();
|
||||
return false;
|
||||
}
|
||||
pa_context_set_state_callback(context, context_state_cb, this);
|
||||
|
||||
if (pa_context_connect(context, nullptr, PA_CONTEXT_NOFLAGS, nullptr) < 0)
|
||||
{
|
||||
WARN_LOG(AUDIO, "PulseAudio: pa_context_connect failed");
|
||||
term();
|
||||
return false;
|
||||
}
|
||||
|
||||
pa_threaded_mainloop_lock(mainloop);
|
||||
if (pa_threaded_mainloop_start(mainloop) < 0)
|
||||
{
|
||||
WARN_LOG(AUDIO, "PulseAudio: pa_threaded_mainloop_start failed");
|
||||
pa_threaded_mainloop_unlock(mainloop);
|
||||
term();
|
||||
return false;
|
||||
}
|
||||
pa_threaded_mainloop_wait(mainloop);
|
||||
|
||||
if (pa_context_get_state(context) != PA_CONTEXT_READY)
|
||||
{
|
||||
WARN_LOG(AUDIO, "PulseAudio: context isn't ready");
|
||||
pa_threaded_mainloop_unlock(mainloop);
|
||||
term();
|
||||
return false;
|
||||
}
|
||||
pa_sample_spec spec{ PA_SAMPLE_S16LE, 44100, 2 };
|
||||
|
||||
stream = pa_stream_new(context, "audio", &spec, NULL);
|
||||
if (!stream)
|
||||
{
|
||||
WARN_LOG(AUDIO, "PulseAudio: pa_stream_new failed");
|
||||
pa_threaded_mainloop_unlock(mainloop);
|
||||
term();
|
||||
return false;
|
||||
}
|
||||
|
||||
//pa_stream_set_state_callback(stream, stream_state_cb, this);
|
||||
pa_stream_set_write_callback(stream, stream_request_cb, this);
|
||||
//pa_stream_set_latency_update_callback(stream, stream_latency_update_cb, this);
|
||||
//pa_stream_set_underflow_callback(stream, underrun_update_cb, this);
|
||||
//pa_stream_set_buffer_attr_callback(stream, buffer_attr_cb, this);
|
||||
|
||||
pa_buffer_attr buffer_attr;
|
||||
buffer_attr.maxlength = -1;
|
||||
buffer_attr.tlength = pa_usec_to_bytes(config::AudioBufferSize * PA_USEC_PER_SEC / 44100, &spec);
|
||||
buffer_attr.prebuf = -1;
|
||||
buffer_attr.minreq = -1;
|
||||
buffer_attr.fragsize = -1;
|
||||
|
||||
if (pa_stream_connect_playback(stream, nullptr, &buffer_attr, PA_STREAM_ADJUST_LATENCY, nullptr, nullptr) < 0)
|
||||
{
|
||||
WARN_LOG(AUDIO, "PulseAudio: pa_stream_connect_playback failed");
|
||||
pa_threaded_mainloop_unlock(mainloop);
|
||||
term();
|
||||
return false;
|
||||
}
|
||||
|
||||
pa_threaded_mainloop_wait(mainloop);
|
||||
|
||||
if (pa_stream_get_state(stream) != PA_STREAM_READY)
|
||||
{
|
||||
WARN_LOG(AUDIO, "PulseAudio: stream isn't ready");
|
||||
pa_threaded_mainloop_unlock(mainloop);
|
||||
term();
|
||||
return false;
|
||||
}
|
||||
|
||||
const pa_buffer_attr *server_attr = pa_stream_get_buffer_attr(stream);
|
||||
if (server_attr)
|
||||
DEBUG_LOG(AUDIO, "PulseAudio: requested %d samples buffer, got %d", buffer_attr.tlength / 4, server_attr->tlength / 4);
|
||||
|
||||
pa_threaded_mainloop_unlock(mainloop);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
u32 push(const void* frame, u32 samples, bool wait) override
|
||||
{
|
||||
const u8 *buf = (const u8 *)frame;
|
||||
size_t size = samples * 4;
|
||||
|
||||
pa_threaded_mainloop_lock(mainloop);
|
||||
while (size)
|
||||
{
|
||||
size_t writable = std::min(size, pa_stream_writable_size(stream));
|
||||
|
||||
if (writable)
|
||||
{
|
||||
pa_stream_write(stream, buf, writable, NULL, 0, PA_SEEK_RELATIVE);
|
||||
buf += writable;
|
||||
size -= writable;
|
||||
}
|
||||
else if (wait)
|
||||
pa_threaded_mainloop_wait(mainloop);
|
||||
else
|
||||
break;
|
||||
}
|
||||
pa_threaded_mainloop_unlock(mainloop);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void term() override
|
||||
{
|
||||
if (mainloop)
|
||||
pa_threaded_mainloop_stop(mainloop);
|
||||
|
||||
if (stream)
|
||||
{
|
||||
pa_stream_disconnect(stream);
|
||||
pa_stream_unref(stream);
|
||||
stream = nullptr;
|
||||
}
|
||||
if (context)
|
||||
{
|
||||
pa_context_disconnect(context);
|
||||
pa_context_unref(context);
|
||||
context = nullptr;
|
||||
}
|
||||
|
||||
if (mainloop)
|
||||
pa_threaded_mainloop_free(mainloop);
|
||||
mainloop = nullptr;
|
||||
}
|
||||
|
||||
bool initRecord(u32 sampling_freq) override
|
||||
{
|
||||
pa_sample_spec spec{ PA_SAMPLE_S16LE, sampling_freq, 1 };
|
||||
|
||||
record_stream = pa_stream_new(context, "record", &spec, NULL);
|
||||
if (!record_stream)
|
||||
{
|
||||
INFO_LOG(AUDIO, "PulseAudio: pa_stream_new failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
pa_threaded_mainloop_lock(mainloop);
|
||||
|
||||
pa_buffer_attr buffer_attr;
|
||||
buffer_attr.fragsize = 240 * 2;
|
||||
buffer_attr.maxlength = buffer_attr.fragsize * 2;
|
||||
|
||||
if (pa_stream_connect_record(record_stream, nullptr, &buffer_attr, PA_STREAM_NOFLAGS) < 0)
|
||||
{
|
||||
INFO_LOG(AUDIO, "PulseAudio: pa_stream_connect_record failed");
|
||||
pa_stream_unref(record_stream);
|
||||
record_stream = nullptr;
|
||||
return false;
|
||||
}
|
||||
pa_threaded_mainloop_unlock(mainloop);
|
||||
INFO_LOG(AUDIO, "PulseAudio: Successfully initialized capture device");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void termRecord() override
|
||||
{
|
||||
if (record_stream != nullptr)
|
||||
{
|
||||
pa_threaded_mainloop_lock(mainloop);
|
||||
pa_stream_disconnect(record_stream);
|
||||
pa_stream_unref(record_stream);
|
||||
record_stream = nullptr;
|
||||
pa_threaded_mainloop_unlock(mainloop);
|
||||
}
|
||||
}
|
||||
|
||||
u32 record(void *buffer, u32 samples) override
|
||||
{
|
||||
if (record_stream == nullptr)
|
||||
return 0;
|
||||
pa_threaded_mainloop_lock(mainloop);
|
||||
const void *data;
|
||||
size_t size;
|
||||
if (pa_stream_peek(record_stream, &data, &size) < 0)
|
||||
{
|
||||
pa_threaded_mainloop_unlock(mainloop);
|
||||
DEBUG_LOG(AUDIO, "PulseAudio: pa_stream_peek error");
|
||||
return 0;
|
||||
}
|
||||
if (size == 0)
|
||||
{
|
||||
pa_threaded_mainloop_unlock(mainloop);
|
||||
return 0;
|
||||
}
|
||||
size = std::min((size_t)samples * 2, size);
|
||||
if (data != nullptr)
|
||||
memcpy(buffer, data, size);
|
||||
else
|
||||
memset(buffer, 0, size);
|
||||
pa_stream_drop(record_stream);
|
||||
pa_threaded_mainloop_unlock(mainloop);
|
||||
|
||||
return size / 2;
|
||||
}
|
||||
};
|
||||
static PulseAudioBackend pulseAudioBackend;
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,243 @@
|
||||
#if defined(USE_SDL_AUDIO)
|
||||
|
||||
#include <SDL.h>
|
||||
#include "audiostream.h"
|
||||
#include "cfg/option.h"
|
||||
#include "stdclass.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <atomic>
|
||||
#include <mutex>
|
||||
|
||||
class SDLAudioBackend : AudioBackend
|
||||
{
|
||||
SDL_AudioDeviceID audiodev {};
|
||||
bool needs_resampling = false;
|
||||
cResetEvent read_wait;
|
||||
std::mutex stream_mutex;
|
||||
uint32_t *sample_buffer;
|
||||
unsigned sample_buffer_size = 0;
|
||||
unsigned sample_count = 0;
|
||||
SDL_AudioCVT audioCvt;
|
||||
|
||||
SDL_AudioDeviceID recorddev {};
|
||||
u8 recordbuf[480 * 4];
|
||||
std::atomic<size_t> rec_read;
|
||||
std::atomic<size_t> rec_write;
|
||||
|
||||
static void audioCallback(void* userdata, Uint8* stream, int len)
|
||||
{
|
||||
SDLAudioBackend *backend = (SDLAudioBackend *)userdata;
|
||||
|
||||
backend->stream_mutex.lock();
|
||||
// Wait until there's enough samples to feed the kraken
|
||||
unsigned oslen = len / sizeof(uint32_t);
|
||||
unsigned islen = backend->needs_resampling ? std::ceil(oslen / backend->audioCvt.len_ratio) : oslen;
|
||||
|
||||
if (backend->sample_count < islen)
|
||||
{
|
||||
// No data, just output a bit of silence for the underrun
|
||||
memset(stream, 0, len);
|
||||
backend->stream_mutex.unlock();
|
||||
backend->read_wait.Set();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!backend->needs_resampling) {
|
||||
// Just copy bytes for this case.
|
||||
memcpy(stream, &backend->sample_buffer[0], len);
|
||||
}
|
||||
else
|
||||
{
|
||||
SDL_AudioCVT& cvt = backend->audioCvt;
|
||||
cvt.len = islen * sizeof(uint32_t);
|
||||
memcpy(cvt.buf, &backend->sample_buffer[0], cvt.len);
|
||||
SDL_ConvertAudio(&cvt);
|
||||
memcpy(stream, cvt.buf, cvt.len_cvt);
|
||||
}
|
||||
|
||||
// Move samples in the buffer and consume them
|
||||
memmove(&backend->sample_buffer[0], &backend->sample_buffer[islen], (backend->sample_count - islen) * sizeof(uint32_t));
|
||||
backend->sample_count -= islen;
|
||||
|
||||
backend->stream_mutex.unlock();
|
||||
backend->read_wait.Set();
|
||||
}
|
||||
|
||||
public:
|
||||
SDLAudioBackend()
|
||||
: AudioBackend("sdl2", "Simple DirectMedia Layer 2 Audio") {}
|
||||
|
||||
bool init() override
|
||||
{
|
||||
if (!SDL_WasInit(SDL_INIT_AUDIO))
|
||||
{
|
||||
if (SDL_InitSubSystem(SDL_INIT_AUDIO)) {
|
||||
ERROR_LOG(AUDIO, "SDL2 error initializing audio subsystem: %s", SDL_GetError());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
sample_buffer_size = std::max<u32>(SAMPLE_COUNT * 2, config::AudioBufferSize);
|
||||
sample_buffer = new uint32_t[sample_buffer_size]();
|
||||
sample_count = 0;
|
||||
|
||||
// Support 44.1KHz (native) but also upsampling to 48KHz
|
||||
SDL_AudioSpec wav_spec, out_spec;
|
||||
memset(&wav_spec, 0, sizeof(wav_spec));
|
||||
wav_spec.freq = 44100;
|
||||
wav_spec.format = AUDIO_S16;
|
||||
wav_spec.channels = 2;
|
||||
wav_spec.samples = SAMPLE_COUNT * 2; // Must be power of two
|
||||
wav_spec.callback = audioCallback;
|
||||
wav_spec.userdata = this;
|
||||
needs_resampling = false;
|
||||
|
||||
// Try 44.1KHz which should be faster since it's native.
|
||||
audiodev = SDL_OpenAudioDevice(NULL, 0, &wav_spec, &out_spec, 0);
|
||||
if (audiodev == 0)
|
||||
{
|
||||
INFO_LOG(AUDIO, "SDL2: SDL_OpenAudioDevice failed: %s", SDL_GetError());
|
||||
needs_resampling = true;
|
||||
wav_spec.freq = 48000;
|
||||
audiodev = SDL_OpenAudioDevice(NULL, 0, &wav_spec, &out_spec, 0);
|
||||
if (audiodev == 0)
|
||||
ERROR_LOG(AUDIO, "SDL2: SDL_OpenAudioDevice failed: %s", SDL_GetError());
|
||||
else
|
||||
{
|
||||
INFO_LOG(AUDIO, "SDL2: Using resampling to 48 KHz");
|
||||
int ret = SDL_BuildAudioCVT(&audioCvt, AUDIO_S16, 2, 44100, AUDIO_S16, 2, 48000);
|
||||
if (ret != 1 || audioCvt.needed == 0)
|
||||
{
|
||||
ERROR_LOG(AUDIO, "SDL2: can't build audio converter: %s", SDL_GetError());
|
||||
SDL_CloseAudioDevice(audiodev);
|
||||
audiodev = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
audioCvt.buf = new u8[SAMPLE_COUNT * 2 * sizeof(uint32_t) * audioCvt.len_mult];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return audiodev != 0;
|
||||
}
|
||||
|
||||
u32 push(const void* frame, u32 samples, bool wait) override
|
||||
{
|
||||
// Unpause the device shall it be paused.
|
||||
if (SDL_GetAudioDeviceStatus(audiodev) != SDL_AUDIO_PLAYING)
|
||||
SDL_PauseAudioDevice(audiodev, 0);
|
||||
|
||||
// If wait, then wait for the buffer to be smaller than a certain size.
|
||||
stream_mutex.lock();
|
||||
if (wait) {
|
||||
while (sample_count + samples > sample_buffer_size) {
|
||||
stream_mutex.unlock();
|
||||
read_wait.Wait();
|
||||
stream_mutex.lock();
|
||||
}
|
||||
}
|
||||
|
||||
// Copy as many samples as possible, drop any remaining (this should not happen usually)
|
||||
unsigned free_samples = sample_buffer_size - sample_count;
|
||||
unsigned tocopy = samples < free_samples ? samples : free_samples;
|
||||
memcpy(&sample_buffer[sample_count], frame, tocopy * sizeof(uint32_t));
|
||||
sample_count += tocopy;
|
||||
stream_mutex.unlock();
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void term() override
|
||||
{
|
||||
if (audiodev)
|
||||
{
|
||||
// Stop audio playback.
|
||||
SDL_PauseAudioDevice(audiodev, 1);
|
||||
read_wait.Set();
|
||||
SDL_CloseAudioDevice(audiodev);
|
||||
audiodev = SDL_AudioDeviceID();
|
||||
}
|
||||
delete [] sample_buffer;
|
||||
sample_buffer = nullptr;
|
||||
if (needs_resampling)
|
||||
{
|
||||
delete [] audioCvt.buf;
|
||||
audioCvt.buf = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
static void recordCallback(void *userdata, u8 *stream, int len)
|
||||
{
|
||||
SDLAudioBackend *backend = (SDLAudioBackend *)userdata;
|
||||
DEBUG_LOG(AUDIO, "SDL2: sdl2_record_cb len %d write %zd read %zd", len, (size_t)backend->rec_write, (size_t)backend->rec_read);
|
||||
while (len > 0)
|
||||
{
|
||||
size_t plen = std::min((size_t)len, sizeof(backend->recordbuf) - backend->rec_write);
|
||||
memcpy(&backend->recordbuf[backend->rec_write], stream, plen);
|
||||
len -= plen;
|
||||
backend->rec_write = (backend->rec_write + plen) % sizeof(backend->recordbuf);
|
||||
stream += plen;
|
||||
}
|
||||
}
|
||||
|
||||
bool initRecord(u32 sampling_freq) override
|
||||
{
|
||||
rec_write = 0;
|
||||
rec_read = 0;
|
||||
|
||||
SDL_AudioSpec wav_spec, out_spec;
|
||||
memset(&wav_spec, 0, sizeof(wav_spec));
|
||||
wav_spec.freq = sampling_freq;
|
||||
wav_spec.format = AUDIO_S16;
|
||||
wav_spec.channels = 1;
|
||||
wav_spec.samples = 256; // Must be power of two
|
||||
wav_spec.callback = recordCallback;
|
||||
wav_spec.userdata = this;
|
||||
recorddev = SDL_OpenAudioDevice(NULL, 1, &wav_spec, &out_spec, 0);
|
||||
if (recorddev == 0)
|
||||
{
|
||||
ERROR_LOG(AUDIO, "SDL2: Cannot open audio capture device: %s", SDL_GetError());
|
||||
return false;
|
||||
}
|
||||
SDL_PauseAudioDevice(recorddev, 0);
|
||||
INFO_LOG(AUDIO, "SDL2: opened audio capture device");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void termRecord() override
|
||||
{
|
||||
if (recorddev != 0)
|
||||
{
|
||||
SDL_PauseAudioDevice(recorddev, 1);
|
||||
SDL_CloseAudioDevice(recorddev);
|
||||
recorddev = 0;
|
||||
}
|
||||
}
|
||||
|
||||
u32 record(void* frame, u32 samples) override
|
||||
{
|
||||
u32 count = 0;
|
||||
samples *= 2;
|
||||
while (samples > 0)
|
||||
{
|
||||
u32 avail = std::min(rec_write - rec_read, sizeof(recordbuf) - rec_read);
|
||||
if (avail == 0)
|
||||
break;
|
||||
avail = std::min(avail, samples);
|
||||
memcpy((u8 *)frame + count, &recordbuf[rec_read], avail);
|
||||
rec_read = (rec_read + avail) % sizeof(recordbuf);
|
||||
samples -= avail;
|
||||
count += avail;
|
||||
}
|
||||
DEBUG_LOG(AUDIO, "SDL2: sdl2_record len %d ret %d write %zd read %zd", samples * 2, count, (size_t)rec_write, (size_t)rec_read);
|
||||
|
||||
return count / 2;
|
||||
}
|
||||
};
|
||||
static SDLAudioBackend sdlAudioBackend;
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,140 @@
|
||||
#include "audiostream.h"
|
||||
#include "cfg/option.h"
|
||||
|
||||
struct SoundFrame { s16 l; s16 r; };
|
||||
|
||||
static SoundFrame Buffer[SAMPLE_COUNT];
|
||||
static u32 writePtr; // next sample index
|
||||
|
||||
static AudioBackend *currentBackend;
|
||||
std::vector<AudioBackend *> *AudioBackend::backends;
|
||||
|
||||
static bool audio_recording_started;
|
||||
static bool eight_khz;
|
||||
|
||||
AudioBackend *AudioBackend::getBackend(const std::string& slug)
|
||||
{
|
||||
if (backends == nullptr)
|
||||
return nullptr;
|
||||
if (slug == "auto")
|
||||
{
|
||||
// Prefer sdl2 if available and avoid the null driver
|
||||
AudioBackend *sdlBackend = nullptr;
|
||||
AudioBackend *autoBackend = nullptr;
|
||||
for (auto backend : *backends)
|
||||
{
|
||||
if (backend->slug == "sdl2")
|
||||
sdlBackend = backend;
|
||||
if (backend->slug != "null" && autoBackend == nullptr)
|
||||
autoBackend = backend;
|
||||
}
|
||||
if (sdlBackend != nullptr)
|
||||
autoBackend = sdlBackend;
|
||||
if (autoBackend == nullptr)
|
||||
autoBackend = backends->front();
|
||||
INFO_LOG(AUDIO, "Auto-selected audio backend \"%s\" (%s).", autoBackend->slug.c_str(), autoBackend->name.c_str());
|
||||
|
||||
return autoBackend;
|
||||
}
|
||||
for (auto backend : *backends)
|
||||
{
|
||||
if (backend->slug == slug)
|
||||
return backend;
|
||||
}
|
||||
WARN_LOG(AUDIO, "WARNING: Audio backend \"%s\" not found!", slug.c_str());
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void WriteSample(s16 r, s16 l)
|
||||
{
|
||||
Buffer[writePtr].r = r * config::AudioVolume.dbPower();
|
||||
Buffer[writePtr].l = l * config::AudioVolume.dbPower();
|
||||
|
||||
if (++writePtr == SAMPLE_COUNT)
|
||||
{
|
||||
if (currentBackend != nullptr)
|
||||
currentBackend->push(Buffer, SAMPLE_COUNT, config::LimitFPS);
|
||||
writePtr = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void InitAudio()
|
||||
{
|
||||
TermAudio();
|
||||
|
||||
std::string slug = config::AudioBackend;
|
||||
currentBackend = AudioBackend::getBackend(slug);
|
||||
if (currentBackend == nullptr && slug != "auto")
|
||||
{
|
||||
slug = "auto";
|
||||
currentBackend = AudioBackend::getBackend(slug);
|
||||
}
|
||||
if (currentBackend != nullptr)
|
||||
{
|
||||
INFO_LOG(AUDIO, "Initializing audio backend \"%s\" (%s)...", currentBackend->slug.c_str(), currentBackend->name.c_str());
|
||||
if (!currentBackend->init())
|
||||
{
|
||||
currentBackend = nullptr;
|
||||
if (slug != "auto")
|
||||
{
|
||||
WARN_LOG(AUDIO, "Audio driver %s failed to initialize. Defaulting to 'auto'", slug.c_str());
|
||||
slug = "auto";
|
||||
currentBackend = AudioBackend::getBackend(slug);
|
||||
if (!currentBackend->init())
|
||||
currentBackend = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (currentBackend == nullptr)
|
||||
{
|
||||
WARN_LOG(AUDIO, "Running without audio!");
|
||||
return;
|
||||
}
|
||||
|
||||
if (audio_recording_started)
|
||||
{
|
||||
// Restart recording
|
||||
audio_recording_started = false;
|
||||
StartAudioRecording(eight_khz);
|
||||
}
|
||||
}
|
||||
|
||||
void TermAudio()
|
||||
{
|
||||
if (currentBackend == nullptr)
|
||||
return;
|
||||
|
||||
// Save recording state before stopping
|
||||
bool rec_started = audio_recording_started;
|
||||
StopAudioRecording();
|
||||
audio_recording_started = rec_started;
|
||||
currentBackend->term();
|
||||
INFO_LOG(AUDIO, "Terminating audio backend \"%s\" (%s)...", currentBackend->slug.c_str(), currentBackend->name.c_str());
|
||||
currentBackend = nullptr;
|
||||
}
|
||||
|
||||
void StartAudioRecording(bool eight_khz)
|
||||
{
|
||||
::eight_khz = eight_khz;
|
||||
if (currentBackend != nullptr)
|
||||
audio_recording_started = currentBackend->initRecord(eight_khz ? 8000 : 11025);
|
||||
else
|
||||
// might be called between TermAudio/InitAudio
|
||||
audio_recording_started = true;
|
||||
}
|
||||
|
||||
u32 RecordAudio(void *buffer, u32 samples)
|
||||
{
|
||||
if (!audio_recording_started || currentBackend == nullptr)
|
||||
return 0;
|
||||
return currentBackend->record(buffer, samples);
|
||||
}
|
||||
|
||||
void StopAudioRecording()
|
||||
{
|
||||
// might be called between TermAudio/InitAudio
|
||||
if (audio_recording_started && currentBackend != nullptr)
|
||||
currentBackend->termRecord();
|
||||
audio_recording_started = false;
|
||||
}
|
||||
@@ -0,0 +1,131 @@
|
||||
#pragma once
|
||||
#include "types.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <atomic>
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
class AudioBackend
|
||||
{
|
||||
public:
|
||||
virtual ~AudioBackend() = default;
|
||||
|
||||
virtual bool init() = 0;
|
||||
virtual u32 push(const void *data, u32 frames, bool wait) = 0;
|
||||
virtual void term() {}
|
||||
|
||||
struct Option {
|
||||
std::string name;
|
||||
std::string caption;
|
||||
enum { integer, checkbox, list } type;
|
||||
|
||||
int minValue;
|
||||
int maxValue;
|
||||
std::vector<std::string> values;
|
||||
};
|
||||
virtual const Option *getOptions(int *count) {
|
||||
*count = 0;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
virtual bool initRecord(u32 sampling_freq) { return false; }
|
||||
virtual u32 record(void *, u32) { return 0; }
|
||||
virtual void termRecord() {}
|
||||
|
||||
std::string slug;
|
||||
std::string name;
|
||||
|
||||
static size_t getCount() { return backends == nullptr ? 0 : backends->size(); }
|
||||
static AudioBackend *getBackend(size_t index) { return backends == nullptr ? nullptr : (*backends)[index]; }
|
||||
static AudioBackend *getBackend(const std::string& slug);
|
||||
|
||||
protected:
|
||||
AudioBackend(const std::string& slug, const std::string& name)
|
||||
: slug(slug), name(name) {
|
||||
registerAudioBackend(this);
|
||||
}
|
||||
|
||||
private:
|
||||
static void registerAudioBackend(AudioBackend *backend)
|
||||
{
|
||||
if (backends == nullptr)
|
||||
backends = new std::vector<AudioBackend *>();
|
||||
backends->push_back(backend);
|
||||
std::sort(backends->begin(), backends->end(), [](AudioBackend *b1, AudioBackend *b2) { return b1->slug < b2->slug; });
|
||||
}
|
||||
|
||||
static std::vector<AudioBackend *> *backends;
|
||||
};
|
||||
|
||||
void InitAudio();
|
||||
void TermAudio();
|
||||
void WriteSample(s16 right, s16 left);
|
||||
|
||||
void StartAudioRecording(bool eight_khz);
|
||||
u32 RecordAudio(void *buffer, u32 samples);
|
||||
void StopAudioRecording();
|
||||
|
||||
constexpr u32 SAMPLE_COUNT = 512; // AudioBackend::push() is always called with that many frames
|
||||
|
||||
class RingBuffer
|
||||
{
|
||||
std::vector<u8> buffer;
|
||||
std::atomic_int readCursor { 0 };
|
||||
std::atomic_int writeCursor { 0 };
|
||||
|
||||
u32 readSize() {
|
||||
return (u32)((writeCursor - readCursor + buffer.size()) % buffer.size());
|
||||
}
|
||||
u32 writeSize() {
|
||||
return (u32)((readCursor - writeCursor + buffer.size() - 1) % buffer.size());
|
||||
}
|
||||
|
||||
public:
|
||||
bool write(const u8 *data, u32 size)
|
||||
{
|
||||
if (size > writeSize())
|
||||
return false;
|
||||
u32 wc = writeCursor;
|
||||
u32 chunkSize = std::min<u32>(size, (u32)buffer.size() - wc);
|
||||
memcpy(&buffer[wc], data, chunkSize);
|
||||
wc = (wc + chunkSize) % buffer.size();
|
||||
size -= chunkSize;
|
||||
if (size > 0)
|
||||
{
|
||||
data += chunkSize;
|
||||
memcpy(&buffer[wc], data, size);
|
||||
wc = (wc + size) % buffer.size();
|
||||
}
|
||||
writeCursor = wc;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool read(u8 *data, u32 size)
|
||||
{
|
||||
if (size > readSize())
|
||||
return false;
|
||||
u32 rc = readCursor;
|
||||
u32 chunkSize = std::min<u32>(size, (u32)buffer.size() - rc);
|
||||
memcpy(data, &buffer[rc], chunkSize);
|
||||
rc = (rc + chunkSize) % buffer.size();
|
||||
size -= chunkSize;
|
||||
if (size > 0)
|
||||
{
|
||||
data += chunkSize;
|
||||
memcpy(data, &buffer[rc], size);
|
||||
rc = (rc + size) % buffer.size();
|
||||
}
|
||||
readCursor = rc;
|
||||
return true;
|
||||
}
|
||||
|
||||
void setCapacity(size_t size)
|
||||
{
|
||||
std::fill(buffer.begin(), buffer.end(), 0);
|
||||
buffer.resize(size);
|
||||
readCursor = 0;
|
||||
writeCursor = 0;
|
||||
}
|
||||
};
|
||||
+19
-151
@@ -1,134 +1,16 @@
|
||||
/*
|
||||
reicast build options
|
||||
|
||||
Reicast can support a lot of stuff, and this is an attempt
|
||||
to organize the build time options
|
||||
|
||||
Option categories
|
||||
|
||||
BUILD_* - BUILD_COMPILER, etc...
|
||||
definitions about the build machine
|
||||
|
||||
HOST_*
|
||||
definitions about the host machine
|
||||
|
||||
FEAT_*
|
||||
definitions about the features that this build targets
|
||||
This is higly related to HOST_*, but it's for options that might
|
||||
or might not be avaiable depending on the target host, or that
|
||||
features that are irrelevant of the host
|
||||
|
||||
Eg, Alsa, Pulse Audio and OSS might sense as HOST dedinitions
|
||||
but it usually makes more sense to detect them as runtime. In
|
||||
that context, HOST_ALSA makes no sense because the host might
|
||||
or might not have alsa installed/ running
|
||||
|
||||
MMU makes no sense as a HOST definition at all, so it should
|
||||
be FEAT_HAS_MMU
|
||||
|
||||
TARGET_*
|
||||
A preconfigured default. Eg TARGET_WIN86.
|
||||
|
||||
Naming of options, option values, and how to use them
|
||||
|
||||
for options that makes sense to have a list of values
|
||||
{CATEGORY}_{OPTION}
|
||||
{OPTION}_{VALUE}
|
||||
|
||||
eg.
|
||||
BUILD_COMPILER == COMPILER_GCC, HOST_CPU != CPU_X64, ...
|
||||
|
||||
for options that are boolean
|
||||
{CATEGORY}_IS_{OPTION} or {CATEGORY}_HAS_{OPTION}
|
||||
|
||||
Evaluates to 0 or 1
|
||||
|
||||
If an configuration cannot be neatly split into a set of
|
||||
of orthogonal options, then it makes sense to break things
|
||||
to "sets" or have a hierarchy of options.
|
||||
|
||||
Example
|
||||
-------
|
||||
|
||||
In the beggining it made sense to have an audio backend
|
||||
per operating system. It made sense to have it depend
|
||||
on HOST_OS and seleect DirectSound or alsa.
|
||||
|
||||
// no option needed
|
||||
|
||||
Then, as android was introduced, which also uses OS_LINUX
|
||||
atm, the audio could have been made an option. It could be
|
||||
a HOST_* option, or FEAT_* one. I'd prefer FEAT_*.
|
||||
FEAT_* makes more sense as future wise we might want
|
||||
to support multiple backends.
|
||||
|
||||
FEAT_AUDIO_BACKEND
|
||||
AUDIO_BACKEND_NONE
|
||||
AUDIO_BACKEND_DS
|
||||
AUDIO_BACKEND_ALSA
|
||||
AUDIO_BACKEND_ANDROID
|
||||
|
||||
Used like
|
||||
#if FEAT_AUDIO_BACKEND == AUDIO_BACKEND_DS ....
|
||||
|
||||
At some point, we might have multiple audio backends that
|
||||
can be compiled in and autodetected/selected at runtime.
|
||||
In that case, it might make sense to have the options like
|
||||
|
||||
FEAT_HAS_ALSA
|
||||
FEAT_HAS_DIRECTSOUND
|
||||
FEAT_HAS_ANDROID_AUDIO
|
||||
|
||||
or
|
||||
FEAT_HAS_AUDIO_ALSA
|
||||
FEAT_HAS_AUDIO_DS
|
||||
FEAT_HAS_AUDIO_ANDROID
|
||||
|
||||
The none option might or might not make sense. In this
|
||||
case it can be removed, as it should always be avaiable.
|
||||
|
||||
Guidelines
|
||||
----------
|
||||
|
||||
General rule of thumb, don't overcomplicate things. Start
|
||||
with a simple option, and then make it more complicated
|
||||
as new uses apply (see the example above)
|
||||
|
||||
Don't use too long names, don't use too cryptic names.
|
||||
Most team developers should be able to understand or
|
||||
figure out most of the acronyms used.
|
||||
|
||||
Try to be consistent on the acronyms across all definitions
|
||||
|
||||
Code shouldn't depend on build level options whenever possible
|
||||
|
||||
Generally, the file should compile even if the option/module is
|
||||
disabled. This makes makefiles etc much easier to write
|
||||
|
||||
TARGET_* options should generally only be used in this file
|
||||
|
||||
The current source is *not* good example of these guidelines
|
||||
|
||||
We'll try to be smart and figure out some options/defaults on this file
|
||||
but this shouldn't get too complicated
|
||||
|
||||
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
//#define STRICT_MODE
|
||||
#ifndef STRICT_MODE
|
||||
#define FAST_MMU
|
||||
#define USE_WINCE_HACK
|
||||
#endif
|
||||
|
||||
#define DC_PLATFORM_MASK 7
|
||||
#define DC_PLATFORM_DREAMCAST 0 /* Works, for the most part */
|
||||
#define DC_PLATFORM_DEV_UNIT 1 /* This is missing hardware */
|
||||
#define DC_PLATFORM_NAOMI 2 /* Works, for the most part */
|
||||
#define DC_PLATFORM_NAOMI2 3 /* Needs to be done, 2xsh4 + 2xpvr + custom TNL */
|
||||
#define DC_PLATFORM_ATOMISWAVE 4 /* Works, for the most part */
|
||||
#define DC_PLATFORM_HIKARU 5 /* Needs to be done, 2xsh4, 2x aica , custom vpu */
|
||||
#define DC_PLATFORM_AURORA 6 /* Needs to be done, Uses newer 300 mhz sh4 + 150 mhz pvr mbx SoC */
|
||||
#define DC_PLATFORM_DREAMCAST 0
|
||||
#define DC_PLATFORM_DEV_UNIT 1
|
||||
#define DC_PLATFORM_NAOMI 2
|
||||
#define DC_PLATFORM_NAOMI2 3
|
||||
#define DC_PLATFORM_ATOMISWAVE 4
|
||||
#define DC_PLATFORM_SYSTEMSP 5
|
||||
|
||||
//HOST_CPU
|
||||
#define CPU_X86 0x20000001
|
||||
@@ -139,13 +21,10 @@
|
||||
#define CPU_PPC 0x20000006
|
||||
#define CPU_PPC64 0x20000007
|
||||
#define CPU_ARM64 0x20000008
|
||||
#define CPU_MIPS64 0x20000009
|
||||
|
||||
//FEAT_SHREC, FEAT_AREC, FEAT_DSPREC
|
||||
#define DYNAREC_NONE 0x40000001
|
||||
#define DYNAREC_JIT 0x40000002
|
||||
#define DYNAREC_CPP 0x40000003
|
||||
|
||||
|
||||
//automatic
|
||||
|
||||
@@ -175,12 +54,6 @@
|
||||
#define FEAT_DSPREC DYNAREC_NONE
|
||||
#endif
|
||||
|
||||
#if defined(TARGET_NO_JIT)
|
||||
#define FEAT_SHREC DYNAREC_CPP
|
||||
#define FEAT_AREC DYNAREC_NONE
|
||||
#define FEAT_DSPREC DYNAREC_NONE
|
||||
#endif
|
||||
|
||||
#ifdef __SWITCH__
|
||||
#define FEAT_NO_RWX_PAGES
|
||||
#endif
|
||||
@@ -222,31 +95,26 @@
|
||||
#if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_APP)
|
||||
#define TARGET_UWP
|
||||
#endif
|
||||
#if !defined(LIBRETRO) && !defined(TARGET_UWP)
|
||||
#define USE_DX9
|
||||
#ifdef HAVE_D3D11
|
||||
#define USE_DX11
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
#if !defined(LIBRETRO) && !defined(TARGET_NO_EXCEPTIONS)
|
||||
#define USE_GGPO
|
||||
#endif
|
||||
|
||||
#if !defined(__ANDROID__) && !defined(TARGET_IPHONE) && !defined(TARGET_UWP) \
|
||||
&& !defined(__SWITCH__) && !defined(LIBRETRO) && !defined(__NetBSD__) && !defined(__OpenBSD__)
|
||||
#define NAOMI_MULTIBOARD
|
||||
#endif
|
||||
|
||||
// TARGET PLATFORM
|
||||
|
||||
#define RAM_SIZE_MAX (32*1024*1024)
|
||||
#define VRAM_SIZE_MAX (16*1024*1024)
|
||||
#define ARAM_SIZE_MAX (8*1024*1024)
|
||||
|
||||
#define GD_CLOCK 33868800 //GDROM XTAL -- 768fs
|
||||
|
||||
#define AICA_CORE_CLOCK (GD_CLOCK*4/3) //[45158400] GD->PLL 3:4 -> AICA CORE -- 1024fs
|
||||
#define ADAC_CLOCK (AICA_CORE_CLOCK/4) //[11289600] 44100*256, AICA CORE -> PLL 4:1 -> ADAC -- 256fs
|
||||
#define AICA_ARM_CLOCK (AICA_CORE_CLOCK/2) //[22579200] AICA CORE -> PLL 2:1 -> ARM
|
||||
#define AICA_SDRAM_CLOCK (GD_CLOCK*2) //[67737600] GD-> PLL 2 -> SDRAM
|
||||
#define SH4_MAIN_CLOCK (200*1000*1000) //[200000000] XTal(13.5) -> PLL (33.3) -> PLL 1:6 (200)
|
||||
#define SH4_RAM_CLOCK (100*1000*1000) //[100000000] XTal(13.5) -> PLL (33.3) -> PLL 1:3 (100) , also suplied to HOLLY chip
|
||||
#define G2_BUS_CLOCK (25*1000*1000) //[25000000] from Holly, from SH4_RAM_CLOCK w/ 2 2:1 plls
|
||||
#define GD_CLOCK 33868800 //GDROM XTAL -- 768fs
|
||||
#define AICA_CORE_CLOCK (GD_CLOCK * 4 / 3) //[45158400] GD->PLL 3:4 -> AICA CORE -- 1024fs
|
||||
#define AICA_ARM_CLOCK (AICA_CORE_CLOCK / 2) //[22579200] AICA CORE -> PLL 2:1 -> ARM
|
||||
#define SH4_MAIN_CLOCK (200 * 1000 * 1000) //[200000000] XTal(13.5) -> PLL (33.3) -> PLL 1:6 (200)
|
||||
#define G2_BUS_CLOCK (25 * 1000 * 1000) //[25000000] from Holly, from SH4_RAM_CLOCK w/ 2 2:1 plls
|
||||
|
||||
#if defined(GLES) && !defined(GLES3) && !defined(GLES2)
|
||||
// Only use GL ES 2.0 API functions
|
||||
|
||||
+1
-1
@@ -14,7 +14,7 @@ bool cfgLoadBool(const std::string& section, const std::string& key, bool 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);
|
||||
|
||||
bool ParseCommandLine(int argc, char *argv[]);
|
||||
void ParseCommandLine(int argc, char *argv[]);
|
||||
|
||||
void cfgSetAutoSave(bool autoSave);
|
||||
bool cfgHasSection(const std::string& section);
|
||||
|
||||
+27
-16
@@ -3,7 +3,6 @@
|
||||
*/
|
||||
|
||||
#include <cstdio>
|
||||
#include <cctype>
|
||||
#include <cstring>
|
||||
|
||||
#include "cfg/cfg.h"
|
||||
@@ -12,43 +11,56 @@
|
||||
static int setconfig(char *arg[], int cl)
|
||||
{
|
||||
int rv=0;
|
||||
for(;;)
|
||||
|
||||
if (cl < 1)
|
||||
{
|
||||
if (cl<1)
|
||||
{
|
||||
WARN_LOG(COMMON, "-config : invalid number of parameters, format is section:key=value");
|
||||
break;
|
||||
}
|
||||
std::string value(arg[1]);
|
||||
WARN_LOG(COMMON, "-config : invalid number of parameters, format is section:key=value,section:key=value,...");
|
||||
return rv;
|
||||
}
|
||||
|
||||
std::string value(arg[1]);
|
||||
for(;;)
|
||||
{
|
||||
auto seppos = value.find(':');
|
||||
if (seppos == std::string::npos)
|
||||
{
|
||||
WARN_LOG(COMMON, "-config : invalid parameter %s, format is section:key=value", value.c_str());
|
||||
WARN_LOG(COMMON, "-config : invalid parameter %s, format is section:key=value,section:key=value,...", value.c_str());
|
||||
break;
|
||||
}
|
||||
auto eqpos = value.find('=', seppos);
|
||||
if (eqpos == std::string::npos)
|
||||
{
|
||||
WARN_LOG(COMMON, "-config : invalid parameter %s, format is section:key=value", value.c_str());
|
||||
WARN_LOG(COMMON, "-config : invalid parameter %s, format is section:key=value,section:key=value,...", value.c_str());
|
||||
break;
|
||||
}
|
||||
|
||||
auto commapos = value.find(',', eqpos);
|
||||
|
||||
std::string sect = trim_ws(value.substr(0, seppos));
|
||||
std::string key = trim_ws(value.substr(seppos + 1, eqpos - seppos - 1));
|
||||
value = trim_ws(value.substr(eqpos + 1));
|
||||
auto endofcurrent = (commapos == std::string::npos) ? value.size() : commapos;
|
||||
std::string next = (commapos == std::string::npos) ? "" : trim_ws(value.substr(endofcurrent + 1, value.size() - endofcurrent));
|
||||
value = trim_ws(value.substr(eqpos + 1, endofcurrent - eqpos - 1));
|
||||
|
||||
if (sect.empty() || key.empty())
|
||||
{
|
||||
WARN_LOG(COMMON, "-config : invalid parameter, format is section:key=value");
|
||||
WARN_LOG(COMMON, "-config : invalid parameter, format is section:key=value,section:key=value,...");
|
||||
break;
|
||||
}
|
||||
|
||||
INFO_LOG(COMMON, "Virtual cfg %s:%s=%s", sect.c_str(), key.c_str(), value.c_str());
|
||||
|
||||
cfgSetVirtual(sect, key, value);
|
||||
rv++;
|
||||
|
||||
if (cl>=3 && strcmp(arg[2],",")==0)
|
||||
if (commapos == std::string::npos)
|
||||
rv++;
|
||||
|
||||
if (commapos != std::string::npos)
|
||||
{
|
||||
value = next;
|
||||
continue;
|
||||
}
|
||||
else if (cl>=3 && strcmp(arg[2],",")==0)
|
||||
{
|
||||
cl-=2;
|
||||
arg+=2;
|
||||
@@ -74,7 +86,7 @@ static int showhelp()
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool ParseCommandLine(int argc,char* argv[])
|
||||
void ParseCommandLine(int argc,char* argv[])
|
||||
{
|
||||
settings.content.path.clear();
|
||||
int cl=argc-2;
|
||||
@@ -128,5 +140,4 @@ bool ParseCommandLine(int argc,char* argv[])
|
||||
arg++;
|
||||
cl--;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
+2
-7
@@ -260,18 +260,13 @@ void ConfigFile::parse(FILE* file)
|
||||
|
||||
void ConfigFile::save(FILE* file)
|
||||
{
|
||||
for (const auto& section_it : this->sections)
|
||||
for (const auto& [section_name, section] : this->sections)
|
||||
{
|
||||
const std::string& section_name = section_it.first;
|
||||
const ConfigSection& section = section_it.second;
|
||||
|
||||
if (!section_name.empty())
|
||||
std::fprintf(file, "[%s]\n", section_name.c_str());
|
||||
|
||||
for (const auto& entry_it : section.entries)
|
||||
for (const auto& [entry_name, entry] : section.entries)
|
||||
{
|
||||
const std::string& entry_name = entry_it.first;
|
||||
const ConfigEntry& entry = entry_it.second;
|
||||
std::fprintf(file, "%s = %s\n", entry_name.c_str(), entry.get_string().c_str());
|
||||
}
|
||||
if (!section_name.empty())
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#include <cstdio>
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <cstdint>
|
||||
|
||||
namespace emucfg {
|
||||
|
||||
|
||||
+42
-11
@@ -18,13 +18,14 @@
|
||||
*/
|
||||
#include "option.h"
|
||||
#include "network/naomi_network.h"
|
||||
#include "debug/gdb_server.h"
|
||||
|
||||
namespace config {
|
||||
|
||||
// Dynarec
|
||||
|
||||
Option<bool> DynarecEnabled("Dynarec.Enabled", true);
|
||||
Option<bool> DynarecIdleSkip("Dynarec.idleskip", true);
|
||||
Option<int> Sh4Clock("Sh4Clock", 200);
|
||||
|
||||
// General
|
||||
|
||||
@@ -32,12 +33,13 @@ Option<int> Cable("Dreamcast.Cable", 3); // TV Composite
|
||||
Option<int> Region("Dreamcast.Region", 1); // USA
|
||||
Option<int> Broadcast("Dreamcast.Broadcast", 0); // NTSC
|
||||
Option<int> Language("Dreamcast.Language", 1); // English
|
||||
Option<bool> FullMMU("Dreamcast.FullMMU");
|
||||
Option<bool> ForceWindowsCE("Dreamcast.ForceWindowsCE");
|
||||
Option<bool> AutoLoadState("Dreamcast.AutoLoadState");
|
||||
Option<bool> AutoSaveState("Dreamcast.AutoSaveState");
|
||||
Option<int> SavestateSlot("Dreamcast.SavestateSlot");
|
||||
Option<int, false> SavestateSlot("Dreamcast.SavestateSlot");
|
||||
Option<bool> ForceFreePlay("ForceFreePlay", true);
|
||||
Option<bool, false> FetchBoxart("FetchBoxart", true);
|
||||
Option<bool, false> BoxartDisplayMode("BoxartDisplayMode", true);
|
||||
Option<int, false> UIScaling("UIScaling", 100);
|
||||
|
||||
// Sound
|
||||
|
||||
@@ -57,6 +59,7 @@ Option<bool> AutoLatency("aica.AutoLatency",
|
||||
|
||||
OptionString AudioBackend("backend", "auto", "audio");
|
||||
AudioVolumeOption AudioVolume;
|
||||
Option<bool> VmuSound("VmuSound", false, "audio");
|
||||
|
||||
// Rendering
|
||||
|
||||
@@ -90,30 +93,51 @@ std::array<Option<int>, 4> CrosshairColor {
|
||||
Option<int>("rend.CrossHairColor3"),
|
||||
Option<int>("rend.CrossHairColor4"),
|
||||
};
|
||||
Option<int> CrosshairSize("rend.CrosshairSize", 40);
|
||||
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> VSync("rend.vsync", true);
|
||||
Option<int64_t> PixelBufferSize("rend.PixelBufferSize", 512 * 1024 * 1024);
|
||||
Option<int64_t> PixelBufferSize("rend.PixelBufferSize", 512_MB);
|
||||
Option<int> AnisotropicFiltering("rend.AnisotropicFiltering", 1);
|
||||
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);
|
||||
Option<bool> NativeDepthInterpolation("rend.NativeDepthInterpolation", false);
|
||||
Option<bool> EmulateFramebuffer("rend.EmulateFramebuffer", false);
|
||||
Option<bool> FixUpscaleBleedingEdge("rend.FixUpscaleBleedingEdge", true);
|
||||
Option<bool> CustomGpuDriver("rend.CustomGpuDriver", false);
|
||||
#ifdef VIDEO_ROUTING
|
||||
Option<bool, false> VideoRouting("rend.VideoRouting", false);
|
||||
Option<bool, false> VideoRoutingScale("rend.VideoRoutingScale", false);
|
||||
Option<int, false> VideoRoutingVRes("rend.VideoRoutingVRes", 720);
|
||||
#endif
|
||||
|
||||
// Misc
|
||||
|
||||
Option<bool> SerialConsole("Debug.SerialConsoleEnabled");
|
||||
Option<bool> SerialPTY("Debug.SerialPTY");
|
||||
Option<bool> GDB("Debug.GDBEnabled");
|
||||
Option<int> GDBPort("Debug.GDBPort", debugger::DEFAULT_PORT);
|
||||
Option<bool> GDBWaitForConnection("Debug.GDBWaitForConnection");
|
||||
Option<bool> UseReios("UseReios");
|
||||
Option<bool> FastGDRomLoad("FastGDRomLoad", false);
|
||||
Option<bool> RamMod32MB("Dreamcast.RamMod32MB", false);
|
||||
|
||||
Option<bool> OpenGlChecks("OpenGlChecks", false, "validate");
|
||||
|
||||
Option<std::vector<std::string>, false> ContentPath("Dreamcast.ContentPath");
|
||||
Option<bool, false> HideLegacyNaomiRoms("Dreamcast.HideLegacyNaomiRoms", true);
|
||||
Option<bool, false> UploadCrashLogs("UploadCrashLogs", true);
|
||||
Option<bool, false> DiscordPresence("DiscordPresence", true);
|
||||
|
||||
// Profiler
|
||||
Option<bool> ProfilerEnabled("Profiler.Enabled");
|
||||
Option<bool> ProfilerDrawToGUI("Profiler.DrawGUI");
|
||||
Option<bool> ProfilerOutputTTY("Profiler.OutputTTY");
|
||||
Option<float> ProfilerFrameWarningTime("Profiler.FrameWarningTime", 1.0f / 55.0f);
|
||||
|
||||
// Network
|
||||
|
||||
@@ -131,10 +155,9 @@ Option<int> GGPOAnalogAxes("GGPOAnalogAxes", 0, "network");
|
||||
Option<bool> GGPOChat("GGPOChat", true, "network");
|
||||
Option<bool> GGPOChatTimeoutToggle("GGPOChatTimeoutToggle", true, "network");
|
||||
Option<int> GGPOChatTimeout("GGPOChatTimeout", 10, "network");
|
||||
|
||||
#ifdef SUPPORT_DISPMANX
|
||||
Option<bool> DispmanxMaintainAspect("maintain_aspect", true, "dispmanx");
|
||||
#endif
|
||||
Option<bool> NetworkOutput("NetworkOutput", false, "network");
|
||||
Option<int> MultiboardSlaves("MultiboardSlaves", 1, "network");
|
||||
Option<bool> BattleCableEnable("BattleCable", false, "network");
|
||||
|
||||
#ifdef USE_OMX
|
||||
Option<int> OmxAudioLatency("audio_latency", 100, "omx");
|
||||
@@ -165,12 +188,20 @@ std::array<std::array<Option<MapleDeviceType>, 2>, 4> MapleExpansionDevices {
|
||||
Option<MapleDeviceType>("device4.1", MDT_None, "input"),
|
||||
Option<MapleDeviceType>("device4.2", MDT_None, "input"),
|
||||
};
|
||||
Option<bool> PerGameVmu("PerGameVmu", false, "config");
|
||||
#ifdef _WIN32
|
||||
Option<bool> UseRawInput("RawInput", false, "input");
|
||||
Option<bool, false> UseRawInput("RawInput", false, "input");
|
||||
#endif
|
||||
|
||||
#ifdef USE_LUA
|
||||
OptionString LuaFileName("LuaFileName", "flycast.lua");
|
||||
Option<std::string, false> LuaFileName("LuaFileName", "flycast.lua");
|
||||
#endif
|
||||
|
||||
// RetroAchievements
|
||||
|
||||
Option<bool> EnableAchievements("Enabled", false, "achievements");
|
||||
Option<bool> AchievementsHardcoreMode("HardcoreMode", false, "achievements");
|
||||
OptionString AchievementsUserName("UserName", "", "achievements");
|
||||
OptionString AchievementsToken("Token", "", "achievements");
|
||||
|
||||
} // namespace config
|
||||
+72
-37
@@ -21,6 +21,7 @@
|
||||
#include <vector>
|
||||
#include <array>
|
||||
#include <cmath>
|
||||
#include <type_traits>
|
||||
#include "cfg.h"
|
||||
#include "hw/maple/maple_cfg.h"
|
||||
#ifdef LIBRETRO
|
||||
@@ -100,10 +101,6 @@ private:
|
||||
friend class Option;
|
||||
};
|
||||
|
||||
// Missing in C++11
|
||||
template <bool B, typename T = void>
|
||||
using enable_if_t = typename std::enable_if<B, T>::type;
|
||||
|
||||
template<typename T, bool PerGameOption = true>
|
||||
class Option : public BaseOption {
|
||||
public:
|
||||
@@ -157,8 +154,8 @@ public:
|
||||
T& get() { return value; }
|
||||
void set(T v) { value = v; }
|
||||
|
||||
void override(T v) {
|
||||
verify(PerGameOption);
|
||||
void override(T v)
|
||||
{
|
||||
overriddenDefault = v;
|
||||
overridden = true;
|
||||
value = v;
|
||||
@@ -173,36 +170,36 @@ public:
|
||||
|
||||
protected:
|
||||
template <typename U = T>
|
||||
enable_if_t<std::is_same<U, bool>::value, T>
|
||||
std::enable_if_t<std::is_same_v<U, bool>, T>
|
||||
doLoad(const std::string& section, const std::string& name) const
|
||||
{
|
||||
return cfgLoadBool(section, name, value);
|
||||
}
|
||||
|
||||
template <typename U = T>
|
||||
enable_if_t<std::is_same<U, int64_t>::value, T>
|
||||
std::enable_if_t<std::is_same<U, int64_t>::value, T>
|
||||
doLoad(const std::string& section, const std::string& name) const
|
||||
{
|
||||
return cfgLoadInt64(section, name, value);
|
||||
}
|
||||
|
||||
template <typename U = T>
|
||||
enable_if_t<(std::is_integral<U>::value || std::is_enum<U>::value)
|
||||
&& !std::is_same<U, bool>::value && !std::is_same<U, int64_t>::value, T>
|
||||
std::enable_if_t<(std::is_integral_v<U> || std::is_enum_v<U>)
|
||||
&& !std::is_same_v<U, bool> && !std::is_same_v<U, int64_t>, T>
|
||||
doLoad(const std::string& section, const std::string& name) const
|
||||
{
|
||||
return (T)cfgLoadInt(section, name, (int)value);
|
||||
}
|
||||
|
||||
template <typename U = T>
|
||||
enable_if_t<std::is_same<U, std::string>::value, T>
|
||||
std::enable_if_t<std::is_same_v<U, std::string>, T>
|
||||
doLoad(const std::string& section, const std::string& name) const
|
||||
{
|
||||
return cfgLoadStr(section, name, value);
|
||||
}
|
||||
|
||||
template <typename U = T>
|
||||
enable_if_t<std::is_same<float, U>::value, T>
|
||||
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, "");
|
||||
@@ -213,7 +210,7 @@ protected:
|
||||
}
|
||||
|
||||
template <typename U = T>
|
||||
enable_if_t<std::is_same<std::vector<std::string>, U>::value, T>
|
||||
std::enable_if_t<std::is_same_v<std::vector<std::string>, U>, T>
|
||||
doLoad(const std::string& section, const std::string& name) const
|
||||
{
|
||||
std::string paths = cfgLoadStr(section, name, "");
|
||||
@@ -272,36 +269,36 @@ protected:
|
||||
}
|
||||
|
||||
template <typename U = T>
|
||||
enable_if_t<std::is_same<U, bool>::value>
|
||||
std::enable_if_t<std::is_same_v<U, bool>>
|
||||
doSave(const std::string& section, const std::string& name) const
|
||||
{
|
||||
cfgSaveBool(section, name, value);
|
||||
}
|
||||
|
||||
template <typename U = T>
|
||||
enable_if_t<std::is_same<U, int64_t>::value>
|
||||
std::enable_if_t<std::is_same<U, int64_t>::value>
|
||||
doSave(const std::string& section, const std::string& name) const
|
||||
{
|
||||
cfgSaveInt64(section, name, value);
|
||||
}
|
||||
|
||||
template <typename U = T>
|
||||
enable_if_t<(std::is_integral<U>::value || std::is_enum<U>::value)
|
||||
&& !std::is_same<U, bool>::value && !std::is_same<U, int64_t>::value>
|
||||
std::enable_if_t<(std::is_integral_v<U> || std::is_enum_v<U>)
|
||||
&& !std::is_same_v<U, bool> && !std::is_same_v<U, int64_t>>
|
||||
doSave(const std::string& section, const std::string& name) const
|
||||
{
|
||||
cfgSaveInt(section, name, (int)value);
|
||||
}
|
||||
|
||||
template <typename U = T>
|
||||
enable_if_t<std::is_same<U, std::string>::value>
|
||||
std::enable_if_t<std::is_same_v<U, std::string>>
|
||||
doSave(const std::string& section, const std::string& name) const
|
||||
{
|
||||
cfgSaveStr(section, name, value);
|
||||
}
|
||||
|
||||
template <typename U = T>
|
||||
enable_if_t<std::is_same<float, U>::value>
|
||||
std::enable_if_t<std::is_same_v<float, U>>
|
||||
doSave(const std::string& section, const std::string& name) const
|
||||
{
|
||||
char buf[64];
|
||||
@@ -310,7 +307,7 @@ protected:
|
||||
}
|
||||
|
||||
template <typename U = T>
|
||||
enable_if_t<std::is_same<std::vector<std::string>, U>::value>
|
||||
std::enable_if_t<std::is_same_v<std::vector<std::string>, U>>
|
||||
doSave(const std::string& section, const std::string& name) const
|
||||
{
|
||||
std::string s;
|
||||
@@ -359,8 +356,9 @@ using OptionString = Option<std::string>;
|
||||
// Dynarec
|
||||
|
||||
extern Option<bool> DynarecEnabled;
|
||||
extern Option<bool> DynarecIdleSkip;
|
||||
constexpr bool DynarecSafeMode = false;
|
||||
#ifndef LIBRETRO
|
||||
extern Option<int> Sh4Clock;
|
||||
#endif
|
||||
|
||||
// General
|
||||
|
||||
@@ -368,12 +366,13 @@ extern Option<int> Cable; // 0 -> VGA, 1 -> VGA, 2 -> RGB, 3 -> TV Composite
|
||||
extern Option<int> Region; // 0 -> JP, 1 -> USA, 2 -> EU, 3 -> default
|
||||
extern Option<int> Broadcast; // 0 -> NTSC, 1 -> PAL, 2 -> PAL/M, 3 -> PAL/N, 4 -> default
|
||||
extern Option<int> Language; // 0 -> JP, 1 -> EN, 2 -> DE, 3 -> FR, 4 -> SP, 5 -> IT, 6 -> default
|
||||
extern Option<bool> FullMMU;
|
||||
extern Option<bool> ForceWindowsCE;
|
||||
extern Option<bool> AutoLoadState;
|
||||
extern Option<bool> AutoSaveState;
|
||||
extern Option<int> SavestateSlot;
|
||||
extern Option<int, false> SavestateSlot;
|
||||
extern Option<bool> ForceFreePlay;
|
||||
extern Option<bool, false> FetchBoxart;
|
||||
extern Option<bool, false> BoxartDisplayMode;
|
||||
extern Option<int, false> UIScaling;
|
||||
|
||||
// Sound
|
||||
|
||||
@@ -407,19 +406,27 @@ public:
|
||||
}
|
||||
};
|
||||
extern AudioVolumeOption AudioVolume;
|
||||
extern Option<bool> VmuSound;
|
||||
|
||||
// Rendering
|
||||
|
||||
class RendererOption : public Option<RenderType> {
|
||||
public:
|
||||
RendererOption()
|
||||
#ifdef USE_DX9
|
||||
: Option<RenderType>("pvr.rend", RenderType::DirectX9) {}
|
||||
#elif defined(TARGET_UWP)
|
||||
: Option<RenderType>("pvr.rend", RenderType::DirectX11) {}
|
||||
#ifdef LIBRETRO
|
||||
RendererOption() : Option<RenderType>("",
|
||||
#else
|
||||
: Option<RenderType>("pvr.rend", RenderType::OpenGL) {}
|
||||
RendererOption() : Option<RenderType>("pvr.rend",
|
||||
#endif
|
||||
#if defined(USE_DX11)
|
||||
RenderType::DirectX11
|
||||
#elif defined(USE_DX9)
|
||||
RenderType::DirectX9
|
||||
#elif !defined(USE_OPENGL)
|
||||
RenderType::Vulkan
|
||||
#else
|
||||
RenderType::OpenGL
|
||||
#endif
|
||||
) {}
|
||||
|
||||
RenderType& operator=(const RenderType& v) { set(v); return value; }
|
||||
|
||||
@@ -453,6 +460,7 @@ extern Option<bool> PerStripSorting;
|
||||
extern Option<bool> DelayFrameSwapping; // Delay swapping frame until FB_R_SOF matches FB_W_SOF
|
||||
extern Option<bool> WidescreenGameHacks;
|
||||
extern std::array<Option<int>, 4> CrosshairColor;
|
||||
extern Option<int> CrosshairSize;
|
||||
extern Option<int> SkipFrame;
|
||||
extern Option<int> MaxThreads;
|
||||
extern Option<int> AutoSkipFrame; // 0: none, 1: some, 2: more
|
||||
@@ -464,18 +472,38 @@ extern Option<int> TextureFiltering; // 0: default, 1: force nearest, 2: force l
|
||||
extern Option<bool> ThreadedRendering;
|
||||
extern Option<bool> DupeFrames;
|
||||
extern Option<bool> NativeDepthInterpolation;
|
||||
extern Option<bool> EmulateFramebuffer;
|
||||
extern Option<bool> FixUpscaleBleedingEdge;
|
||||
extern Option<bool> CustomGpuDriver;
|
||||
#ifdef VIDEO_ROUTING
|
||||
extern Option<bool, false> VideoRouting;
|
||||
extern Option<bool, false> VideoRoutingScale;
|
||||
extern Option<int, false> VideoRoutingVRes;
|
||||
#endif
|
||||
|
||||
// Misc
|
||||
|
||||
extern Option<bool> SerialConsole;
|
||||
extern Option<bool> SerialPTY;
|
||||
extern Option<bool> GDB;
|
||||
extern Option<int> GDBPort;
|
||||
extern Option<bool> GDBWaitForConnection;
|
||||
extern Option<bool> UseReios;
|
||||
extern Option<bool> FastGDRomLoad;
|
||||
extern Option<bool> RamMod32MB;
|
||||
|
||||
extern Option<bool> OpenGlChecks;
|
||||
|
||||
extern Option<std::vector<std::string>, false> ContentPath;
|
||||
extern Option<bool, false> HideLegacyNaomiRoms;
|
||||
extern Option<bool, false> UploadCrashLogs;
|
||||
extern Option<bool, false> DiscordPresence;
|
||||
|
||||
// Profiling
|
||||
extern Option<bool> ProfilerEnabled;
|
||||
extern Option<bool> ProfilerDrawToGUI;
|
||||
extern Option<bool> ProfilerOutputTTY;
|
||||
extern Option<float> ProfilerFrameWarningTime;
|
||||
|
||||
// Network
|
||||
|
||||
@@ -493,10 +521,9 @@ extern Option<int> GGPOAnalogAxes;
|
||||
extern Option<bool> GGPOChat;
|
||||
extern Option<bool> GGPOChatTimeoutToggle;
|
||||
extern Option<int> GGPOChatTimeout;
|
||||
|
||||
#ifdef SUPPORT_DISPMANX
|
||||
extern Option<bool> DispmanxMaintainAspect;
|
||||
#endif
|
||||
extern Option<bool> NetworkOutput;
|
||||
extern Option<int> MultiboardSlaves;
|
||||
extern Option<bool> BattleCableEnable;
|
||||
|
||||
#ifdef USE_OMX
|
||||
extern Option<int> OmxAudioLatency;
|
||||
@@ -509,14 +536,22 @@ extern Option<int> MouseSensitivity;
|
||||
extern Option<int> VirtualGamepadVibration;
|
||||
extern std::array<Option<MapleDeviceType>, 4> MapleMainDevices;
|
||||
extern std::array<std::array<Option<MapleDeviceType>, 2>, 4> MapleExpansionDevices;
|
||||
extern Option<bool> PerGameVmu;
|
||||
#ifdef _WIN32
|
||||
extern Option<bool> UseRawInput;
|
||||
extern Option<bool, false> UseRawInput;
|
||||
#else
|
||||
constexpr bool UseRawInput = false;
|
||||
#endif
|
||||
|
||||
#ifdef USE_LUA
|
||||
extern OptionString LuaFileName;
|
||||
extern Option<std::string, false> LuaFileName;
|
||||
#endif
|
||||
|
||||
// RetroAchievements
|
||||
|
||||
extern Option<bool> EnableAchievements;
|
||||
extern Option<bool> AchievementsHardcoreMode;
|
||||
extern OptionString AchievementsUserName;
|
||||
extern OptionString AchievementsToken;
|
||||
|
||||
} // namespace config
|
||||
+302
-205
@@ -25,10 +25,14 @@
|
||||
#include "reios/reios.h"
|
||||
#include "cfg/cfg.h"
|
||||
#include "cfg/ini.h"
|
||||
#include "cfg/option.h"
|
||||
#include "emulator.h"
|
||||
#include "oslib/storage.h"
|
||||
|
||||
const WidescreenCheat CheatManager::widescreen_cheats[] =
|
||||
{
|
||||
{ "T36803N", nullptr, { 0xBC2CC }, { 0xC00 } }, // 102 Dalmatians (USA)
|
||||
{ "T36813D 50", nullptr, { 0xBDE8C }, { 0xC00 } }, // 102 Dalmatians (PAL)
|
||||
{ "MK-51064", nullptr, { 0x39EFF4 }, { 0x43700000 } }, // 18 wheeler (USA)
|
||||
{ "MK-5106450", nullptr, { 0x39EFF4 }, { 0x43700000 } }, // 18 wheeler (PAL)
|
||||
{ "HDR-0080", nullptr, { 0x6625C0 }, { 0x43700000 } }, // 18 wheeler (JP)
|
||||
@@ -48,6 +52,7 @@ const WidescreenCheat CheatManager::widescreen_cheats[] =
|
||||
{ "T6801M", nullptr, { 0x042F3C }, { 0x4384BC09 } }, // Buggy Heat (JP)
|
||||
{ "T46601D 05", nullptr, { 0xBB3D14 }, { 0x440A7C9A } }, // Cannon Spike (PAL)
|
||||
{ "T1215N", nullptr, { 0xBB3C74 }, { 0x440A7C9A } }, // Cannon Spike (USA)
|
||||
{ "HDR-0115", nullptr, { 0x10ACFC }, { 0x3F400000 } }, // Cardcaptor Sakura: Tomoyo no Video Daisakusen (JPN)
|
||||
{ "T44901D 50", nullptr, { 0xB0109C, 0xB010CC }, { 0x43F00000, 0x3F400000 } }, // Carrier (PAL)
|
||||
{ "T5701N", nullptr, { 0xAFD93C, 0xAFD96C }, { 0x43F00000, 0x3F400000 } }, // Carrier (USA)
|
||||
// Capcom vs. SNK Pro (JP)
|
||||
@@ -105,7 +110,8 @@ const WidescreenCheat CheatManager::widescreen_cheats[] =
|
||||
{ "HDR-0100", nullptr, { 0x3235D4 }, { 0x00004000 } }, // Ferrari F355 Challenge (JP) vga mode only
|
||||
{ "MK-5115450", nullptr, { 0x3D3B10 }, { 0x43700000 } }, // Fighting Vipers 2 (PAL)
|
||||
{ "HDR-0133", nullptr, { 0x3D3AF0 }, { 0x43700000 } }, // Fighting Vipers 2 (JP)
|
||||
{ "MK-51114", nullptr, { 0x132DD8, 0xA26CA8, 0xA26738, 0xA275B8, 0xA26AD8, 0xA26908 },
|
||||
{ "T18805M", nullptr, { 0x1A39C0 }, { 0x3F400000 } }, // Fire Pro Wrestling D (JP)
|
||||
{ "MK-51114", " E ", { 0x132DD8, 0xA26CA8, 0xA26738, 0xA275B8, 0xA26AD8, 0xA26908 },
|
||||
{ 0x3F400000, 0x3F400000, 0x3F400000, 0x3F400000, 0x3F400000, 0x3F400000 } }, // Floigan Bros. Ep. 1 (PAL)
|
||||
{ "T34201M", nullptr, { 0x586290, 0x586260 }, { 0x3F400000, 0x43F00000 } }, // Frame Gride (JP)
|
||||
{ "T-8113D-50", nullptr, { 0x55A354 }, { 0x3FAAAAAB } }, // Fur Fighters (PAL)
|
||||
@@ -120,9 +126,10 @@ const WidescreenCheat CheatManager::widescreen_cheats[] =
|
||||
// { "T11001N", nullptr, { 0xC3D6BC, 0xD204A8, 0xD32FC8, 0xC7CF84, 0xD20548 },
|
||||
// { 0x00363031, 0x00000356, 0x00000280, 0x00000280, 0x00000280 } }, // Half-Life. Not working
|
||||
{ "MK-5104150", nullptr, { 0x23FCC4 }, { 0x44558000 } }, // Headhunter (PAL)
|
||||
{ "MK-5100250", nullptr, { 0x4C6708 }, { 0x43700000 } }, // House of the Dead 2, The (PAL)
|
||||
{ "MK-51002", nullptr, { 0x4C6088 }, { 0x43700000 } }, // House of the Dead 2, The (USA)
|
||||
{ "T38706M", nullptr, { 0xC0CFA0 }, { 0x3F400000 } }, // Ikaruga (JP)
|
||||
// gun coords issue
|
||||
//{ "MK-5100250", nullptr, { 0x4C6708 }, { 0x43700000 } }, // House of the Dead 2, The (PAL)
|
||||
//{ "MK-51002", nullptr, { 0x4C6088 }, { 0x43700000 } }, // House of the Dead 2, The (USA)
|
||||
//not working { "T38706M", nullptr, { 0xC0CFA0 }, { 0x3F400000 } }, // Ikaruga (JP)
|
||||
{ "T46001N", nullptr, { 0x1C8A98 }, { 0x3F400000 } }, // Illbleed (USA)
|
||||
{ "T44904D 50", nullptr, { 0x18C15C, 0x18C18C }, { 0x43F00000, 0x3F400000 } }, // Iron Aces (PAL)
|
||||
{ "MK-51058", nullptr, { 0x32E0FC, 0x32E12C }, { 0x43F00000, 0x3F400000 } }, // Jet Grind Radio (USA)
|
||||
@@ -145,7 +152,8 @@ const WidescreenCheat CheatManager::widescreen_cheats[] =
|
||||
{ "MK-5102250", "V1.001", { 0x107FDC, 0x11253C }, { 0x3F99999A, 0x3F900000 } }, // Metropolis Street Racer (v1.001) (PAL)
|
||||
{ "MK-5102250", "V1.009", { 0x106B5C, 0x1111F4 }, { 0x3F99999A, 0x3F900000 } }, // Metropolis Street Racer (v1.009) (PAL)
|
||||
{ "MK-51012", nullptr, { 0x10A01C, 0x1146FC }, { 0x3F99999A, 0x3F900000 } }, // Metropolis Street Racer (USA)
|
||||
{ "T0000M", nullptr, { 0x1CAEAC, 0x1CAEDC }, { 0x43F00000, 0x3F400000 } }, // Millenium Racer Y2K Fighters
|
||||
{ "T0000M", "MILLENNIUM RACER - Y2K FIGHTERS ",
|
||||
{ 0x1CAEAC, 0x1CAEDC }, { 0x43F00000, 0x3F400000 } }, // Millenium Racer Y2K Fighters
|
||||
{ "T1221M", nullptr, { 0x426B74 }, { 0x43F00000 } }, // Moero! Justice Gauken (JP)
|
||||
{ "T9701D", nullptr, { 0x31290C }, { 0x3F400000 } }, // Mortal Kombat Gold (PAL)
|
||||
{ "T-9701N", nullptr, { 0x337B8C }, { 0x3FA66666 } }, // Mortal Kombat Gold (USA)
|
||||
@@ -198,9 +206,15 @@ const WidescreenCheat CheatManager::widescreen_cheats[] =
|
||||
{ 0x3F400000, 0x43F00000, 0, 0x43F00000, 0 } },
|
||||
// Resident Evil: Code Veronica (USA)
|
||||
// Code 1-4 removes the black bars on top and bottom in FMV
|
||||
{ "T1204N", "RESIDENT EVIL CODE VERONICA ",
|
||||
{ "T1204N", "RESIDENT EVIL CODE VERONICA ",
|
||||
{ 0x329E40, 0x3838D8, 0x3838F8, 0x383918, 0x383938 },
|
||||
{ 0x3F400000, 0x43F00000, 0, 0x43F00000, 0 } },
|
||||
// Biohazard: Code Veronica: Kanzenban (JP)
|
||||
{ "T1240M", "BIOHAZARD CODE VERONICA PLUS ",
|
||||
{ 0x344AE1 }, { 0x003F6000 } },
|
||||
// Resident Evil: Code Veronica X Kanzenban (Eng. translation)
|
||||
{ "T1204N", "RESIDENT EVIL CODE VERONICA X ",
|
||||
{ 0x344AE1 }, { 0x003F6000 } },
|
||||
{ "T8107D 50", nullptr, { 0x0464FC, 0x046210 }, { 0x3A888889, 0x44200000 } }, // Re-Volt (PAL) Code 1 is a render fix
|
||||
{ "MK-5119250", nullptr, { 0x0C5EB4 }, { 0x3A888889 } }, // Rez (PAL)
|
||||
{ "T15122N", nullptr, { 0x8E7A80, 0x8E7AB4 }, { 0x43E10000, 0x3FAAAAAB } }, // Ring, The - Terror's Realm (USA)
|
||||
@@ -211,6 +225,7 @@ const WidescreenCheat CheatManager::widescreen_cheats[] =
|
||||
{ "T8104D 58", nullptr, { 0x2C03F8 }, { 0x44558000 } }, // Shadow Man (PAL)
|
||||
{ "T-8106N", nullptr, { 0x2C03F4 }, { 0x3F400000 } }, // Shadow Man (USA)
|
||||
{ "MK-51048", nullptr, { 0x4AA4DC, 0x2B4E30 }, { 0x3F400000, 0x3F400000 } }, // Seaman (USA)
|
||||
{ "MK-51053", nullptr, { 0x5630CC }, { 0x3F400000 } }, // Sega GT (USA)
|
||||
{ "MK-5105350", nullptr, { 0x5D613C }, { 0x3F400000 } }, // Sega GT (PAL)
|
||||
{ "MK-51096", nullptr, { 0x495050 }, { 0x43700000 } }, // Sega Marine Fishing (USA)
|
||||
// { "MK-51019", nullptr, { 0xB83A48 }, { 0x3F400000 } }, // Sega Rally 2 (USA) not working?
|
||||
@@ -251,20 +266,23 @@ const WidescreenCheat CheatManager::widescreen_cheats[] =
|
||||
{ "T40206N", nullptr, { 0x43296C }, { 0x3F400000 } }, // Super Magnetic Neo (US)
|
||||
{ "T40206D 50", nullptr, { 0x43E34C }, { 0x3F400000 } }, // Super Magnetic Neo (EU)
|
||||
// { "T7014D 50", nullptr, { 0xE2B234 }, { 0x3F800000 } }, // Super Runabout (PAL) doesn't work?
|
||||
{ "T40216N", nullptr, { 0x45CE54 }, { 0x3F400000 } }, // Surf Rocket Racers (US)
|
||||
{ "T17721D 50", nullptr, { 0x45CED4 }, { 0x3F400000 } }, // Surf Rocket Racers (PAL) alt: 021EBF40 3F400000
|
||||
{ "T17703D 50", nullptr, { 0xCD8950 }, { 0x3F111111 } }, // Suzuki Alstare Extreme Racing
|
||||
{ "T36807D 05", nullptr, { 0x140F74, 0x140FA4 }, { 0x43FA0000, 0x3F400000 } }, // Sword of Bersek (PAL)
|
||||
{ "T-36805N", nullptr, { 0x13F1C4, 0x13F194 }, { 0x3F400000, 0x43F00000 } }, // Sword of Bersek (USA)
|
||||
{ "MK-51186", nullptr, { 0x4A19B0 }, { 0x43700000 } }, // Tennis 2K2 (USA)
|
||||
{ "T15123N", nullptr, { 0x29B7BC }, { 0x3F400000 } }, // Test Drive Le Mans (USA) doesn't work?
|
||||
{ "T15123N", nullptr, { 0x29B7BC }, { 0x3F400000 } }, // Test Drive Le Mans (USA)
|
||||
{ "T20801M", nullptr, { 0x1AAC80, 0x1AACB0 }, { 0x43F00000, 0x3F400000 } }, // Tetris 4D (JP)
|
||||
{ "MK-5101153", nullptr, { 0x14EFA8, 0x14EFD8 }, { 0x43F00000, 0x3F400000 } }, // Timestalkers (PAL)
|
||||
{ "T7009D50", nullptr, { 0x39173C }, { 0x3F400000 } }, // Tech Romancer (PAL)
|
||||
{ "T35402M", nullptr, { 0x315370, 0x3153A0 }, { 0x43F00000, 0x3F400000 } }, // Tokyo Bus Guide (JP) doesn't work?
|
||||
{ "T40201D 50", nullptr, { 0x1D9F10 }, { 0x3F400000 } }, // Tokyo Highway Challenge (PAL)
|
||||
{ "T40210D 50", nullptr, { 0x21E4F8 }, { 0x43700000 } }, // Tokyo Highway Challenge 2 (PAL)
|
||||
{ "xxxxxxxxxx", nullptr, { 0x21DEF8 }, { 0x3F400000 } }, // Tokyo Street Racer 2 (USA)
|
||||
{ "T40202N", nullptr, { 0x1D9EB0 }, { 0x3F400000 } }, // Tokyo Xtreme Racer (USA)
|
||||
{ "T40211N", nullptr, { 0x21DEF8 }, { 0x43700000 } }, // Tokyo Xtreme Racer 2 (USA)
|
||||
// { "T36804D05", nullptr, { 0xB75E28 }, { 0x3EC00000 } }, // Tomb Raider: The Last Revelation (UK) (PAL) clipping, use hex patch instead
|
||||
// { "T40205N", nullptr, { 0x160D80, 0x160D7C }, { 0xA, 0xA } }, // Tony Hawk's Pro Skater (USA) -> missing character on selection screen
|
||||
{ "T13008D 05", nullptr, { 0x1D7C20 }, { 0x3FA66666 } }, // Tony Hawk's Pro Skater 2 (PAL)
|
||||
{ "T13006N", nullptr, { 0x1D77A0 }, { 0x3FA66666 } }, // Tony Hawk's Pro Skater 2 (USA)
|
||||
{ "MK-5102050", nullptr, { 0x0D592C }, { 0x3FD00000 } }, // Toy Commander (PAL)
|
||||
@@ -275,6 +293,7 @@ const WidescreenCheat CheatManager::widescreen_cheats[] =
|
||||
{ "T-8110D-50", nullptr, { 0x0C6B90, 0x0C6B94 }, { 0x43F00000, 0x43870000 } }, // Vanishing Point (PAL)
|
||||
// { "MK-5109450", nullptr, { 0x244134, 0x7A73B8, 0x7830D8, 0x7A74B8, 0x783138, 0x7A85A0, 0x6C7928, 0x6C7930, 0x6C7948, 0x6C7950 },
|
||||
//crash { 0x43F00000, 0x3F9C932E, 0x3F9C932E, 0x3F9C932E, 0x3F9C932E, 0x3F400000, 0, 0, 0, 0 } }, // Virtua Athlete 2K (PAL)
|
||||
{ "MK-51001", nullptr, { 0x19D518 }, { 0x43700000 } }, // Virtua Fighter 3 TB (NTSC)
|
||||
{ "MK-5100150", nullptr, { 0x19D718 }, { 0x43700000 } }, // Virtua Fighter 3 TB (PAL)
|
||||
{ "HDR-0002", nullptr, { 0x199FB0 }, { 0x43700000 } }, // Virtua Fighter 3 TB (JP)
|
||||
{ "MK-5105450", nullptr, { 0x456378 }, { 0x43700000 } }, // Virtua Tennis (v1.001) (PAL)
|
||||
@@ -283,7 +302,7 @@ const WidescreenCheat CheatManager::widescreen_cheats[] =
|
||||
// { "T0000", nullptr, { 0x3A514C, 0x3A6170 }, { 0x3F400000, 0x00000356 } }, // Volgarr the Viking. Not working
|
||||
{ "xxxxxxxxxx", nullptr, { 0x20BB68, 0x1ACBD0, 0x1B9ADC }, // Code 1 reduces clipping. Code 2 fixes the clock.
|
||||
{ 0x43700000, 0x7C1ACC60, 0x3F400000 } }, // What's Shenmue (JP)
|
||||
{ "T40504D 50", nullptr, { 0x75281C }, { 0x3F400000 } }, // Wetrix+ (PAL) not working?
|
||||
{ "T40504D 50", nullptr, { 0x75281C }, { 0x3F400000 } }, // Wetrix+ (PAL)
|
||||
{ "MK-51152", nullptr, { 0x014E90 }, { 0x43700000 } }, // World Series Baseball 2K2 (USA)
|
||||
{ "T20401M", nullptr, { 0x323CB0, 0x1ACBD0, 0x1B9ADC }, // Code 1 reduces clipping. Code 2 fixes the HUD.
|
||||
{ 0x43700000, 0x1ACC60, 0x3F400000 } }, // Zero Gunner 2 (JP)
|
||||
@@ -299,6 +318,7 @@ const WidescreenCheat CheatManager::naomi_widescreen_cheats[] =
|
||||
{ "KNIGHTS OF VALOUR THE 7 SPIRITS", nullptr, { 0x475B70, 0x475B40 }, { 0x3F400000, 0x43F00000 } },
|
||||
{ "Dolphin Blue", nullptr, { 0x3F2E2C, 0x3F2190, 0x3F2E6C, 0x3F215C },
|
||||
{ 0x43B90000, 0x3FAA9FBE, 0x43B90000, 0x43F00000 } },
|
||||
{ "FASTER THAN SPEED", nullptr, { 0x3488E0 }, { 0x3F400000 } }, // ftspeed
|
||||
{ "METAL SLUG 6", nullptr, { 0xE93478, 0xE9347C }, { 0x3F400000, 0x3F8872B0 } },
|
||||
{ "TOY FIGHTER", nullptr, { 0x133E58 }, { 0x43700000 } },
|
||||
{ "LUPIN THE THIRD -THE SHOOTING-", nullptr, { 0x045490 }, { 0x3F400000 } },
|
||||
@@ -310,11 +330,31 @@ const WidescreenCheat CheatManager::naomi_widescreen_cheats[] =
|
||||
{ " 18WHEELER", "18wheelr", { 0x5C64A8 }, { 0x43700000 } },
|
||||
{ "BEACH SPIKERS JAPAN", nullptr, { 0x065A7C }, { 0x44558000 } },
|
||||
{ "GUN SPIKE", nullptr, { 0x21A94 }, { 0x3FE38E39 } },
|
||||
{ "INITIAL D", "initd", { 0x155434 }, { 0x3FE38E39 } },
|
||||
{ "INITIAL D", "initdexp", { 0x159674 }, { 0x3FE38E39 } },
|
||||
{ "INITIAL D", "initdexpo", { 0x159634 }, { 0x3FE38E39 } },
|
||||
{ "INITIAL D", "initdo", { 0x14F5F4 }, { 0x3FE38E39 } },
|
||||
{ "INITIAL D Ver.2", "initdv2e", { 0x1B4F74 }, { 0x3FE38E39 } },
|
||||
{ "INITIAL D Ver.2", "initdv2j", { 0x1B4F34 }, { 0x3FE38E39 } },
|
||||
{ "INITIAL D Ver.2", "initdv2jo", { 0x1AD1F4 }, { 0x3FE38E39 } },
|
||||
{ "INITIAL D Ver.3", "initdv3e", { 0x1D0B34 }, { 0x3FE38E39 } },
|
||||
{ "INITIAL D Ver.3", "initdv3j", { 0x1D7C74 }, { 0x3FE38E39 } },
|
||||
{ "INITIAL D Ver.3", "initdv3jb", { 0x1D7774 }, { 0x3FE38E39 } },
|
||||
{ "AIRLINE PILOTS IN JAPAN", "alpilotj", { 0x1D62550 }, { 0x43700000 } },
|
||||
{ "MONKEY BALL JAPAN VERSION", nullptr, { 0x345B4, 0x45244, 0x454CC }, { 0x3FE38E39, 0x3FE38E39, 0x3FE38E39 } },
|
||||
{ "ZOMBIE REVENGE IN JAPAN", "zombrvn", { 0x7A4808 }, { 0x43700000 } },
|
||||
{ "ZOMBIE REVENGE IN JAPAN", "zombrvno", { 0x7A2E50 }, { 0x43700000 } },
|
||||
{ " BIOHAZARD GUN SURVIVOR2", "gunsur2", { 0x42EE80 }, { 0x3F400000 } },
|
||||
{ " BIOHAZARD GUN SURVIVOR2", "gunsur2j", { 0x42EBE0 }, { 0x3F400000 } },
|
||||
{ "SPAWN JAPAN", nullptr, { 0x02DEF8, 0x02E1C0 }, { 0x3A99999A, 0x3A99999A } },
|
||||
// gun coords problem with these 2 cheats
|
||||
// { " CONFIDENTIAL MISSION ---------", nullptr, { 0x24F798 }, { 0x43700000 } },
|
||||
// { "hotd2", nullptr, { 0x9C2AD8 }, { 0x43700000 } },
|
||||
{ "GUN SPIKE", nullptr, { 0xBACD7C }, { 0x440A7C9A } },
|
||||
{ " JAMBO SAFARI ------------", nullptr, { 0x2B1DE0 }, { 0x3FE38E39 } },
|
||||
{ "SOUL SURFER IN JAPAN", nullptr, { 0x8962C8 }, { 0x3FE38E39 } },
|
||||
{ "LOVE AND BERRY 3 EXP VER1.002", nullptr, { 0x3C16E4 }, { 0x3F400000 } }, // loveber3
|
||||
{ "LOVE AND BERRY USA VER2.000", nullptr, { 0x4E92D0 }, { 0x3F400000 } }, // lovebery
|
||||
|
||||
{ nullptr },
|
||||
};
|
||||
@@ -337,7 +377,7 @@ void CheatManager::setActive(bool active)
|
||||
void CheatManager::loadCheatFile(const std::string& filename)
|
||||
{
|
||||
#ifndef LIBRETRO
|
||||
FILE* cheatfile = nowide::fopen(filename.c_str(), "r");
|
||||
FILE* cheatfile = hostfs::storage().openFile(filename, "r");
|
||||
if (cheatfile == nullptr)
|
||||
{
|
||||
WARN_LOG(COMMON, "Cannot open cheat file '%s'", filename.c_str());
|
||||
@@ -394,18 +434,70 @@ void CheatManager::reset(const std::string& gameId)
|
||||
setActive(false);
|
||||
this->gameId = gameId;
|
||||
#ifndef LIBRETRO
|
||||
std::string cheatFile = cfgLoadStr("cheats", gameId, "");
|
||||
if (!cheatFile.empty())
|
||||
loadCheatFile(cheatFile);
|
||||
#endif
|
||||
if (gameId == "VF4 FINAL TUNED JAPAN")
|
||||
if (!settings.raHardcoreMode)
|
||||
{
|
||||
setActive(true);
|
||||
cheats.emplace_back(Cheat::Type::setValue, "Skip DIMM version check", true, 16, 0x0007f486, 0xe001); // mov #1, r0
|
||||
cheats.back().builtIn = true;
|
||||
std::string cheatFile = cfgLoadStr("cheats", gameId, "");
|
||||
if (!cheatFile.empty())
|
||||
loadCheatFile(cheatFile);
|
||||
}
|
||||
#endif
|
||||
size_t cheatCount = cheats.size();
|
||||
if (gameId == "Fixed BOOT strapper") // Extreme Hunting 2
|
||||
{
|
||||
cheats.emplace_back(Cheat::Type::runNextIfEq, "skip netbd check ifeq", true, 32, 0x00067b04, 0, true);
|
||||
cheats.emplace_back(Cheat::Type::setValue, "skip netbd check", true, 32, 0x00067b04, 1, true); // 1 skips initNetwork()
|
||||
cheats.emplace_back(Cheat::Type::setValue, "skip netbd check 2", true, 16, 0x0009acc8, 0x0009, true); // not acceptable by main board
|
||||
// ac010000 should be d202 9302, but is changed to 78c0 8c93
|
||||
cheats.emplace_back(Cheat::Type::runNextIfEq, "fix boot ifeq", true, 32, 0x00010000, 0x8c9378c0, true);
|
||||
cheats.emplace_back(Cheat::Type::setValue, "fix boot", true, 32, 0x00010000, 0x9302d202, true);
|
||||
}
|
||||
else if (gameId == "THE KING OF ROUTE66") {
|
||||
cheats.emplace_back(Cheat::Type::setValue, "ignore drive error", true, 32, 0x00023ee0, 0x0009000B, true); // rts, nop
|
||||
}
|
||||
else if (gameId.substr(0, 8) == "MKG TKOB")
|
||||
{
|
||||
const auto& setMushikingCheats = [this](u32 addr) {
|
||||
cheats.emplace_back(Cheat::Type::setValue, "ignore rfid1 error", true, 32, addr, 0, true); // rfid[0].error = 0
|
||||
cheats.emplace_back(Cheat::Type::setValue, "ignore rfid2 error", true, 32, addr + 0x48, 0, true); // rfid[1].error = 0
|
||||
cheats.emplace_back(Cheat::Type::setValue, "ignore rfid1 status", true, 32, addr + 8, 0, true); // rfid[0].data18 = 0
|
||||
cheats.emplace_back(Cheat::Type::setValue, "ignore rfid2 status", true, 32, addr + 0x50, 0, true); // rfid[1].data18 = 0
|
||||
};
|
||||
if (gameId == "MKG TKOB 2 EXP VER1.001-") // mushi2eo
|
||||
setMushikingCheats(0x6fe1bc);
|
||||
else if (gameId == "MKG TKOB 2 JPN VER2.001-") // mushik2e
|
||||
setMushikingCheats(0x6ffe54);
|
||||
else if (gameId == "MKG TKOB 2K3 2ND VER1.003-")// mushike
|
||||
setMushikingCheats(0x4ad7ec);
|
||||
else if (gameId == "MKG TKOB 4 JPN VER2.000-") // mushik4e
|
||||
setMushikingCheats(0xb0e538);
|
||||
else if (gameId == "MKG TKOB 2K3 2ND VER1.002-")// mushikeo
|
||||
setMushikingCheats(0x4ad56c);
|
||||
else if (gameId == "MKG TKOB 2K3 2ND KOR VER1.000-") // mushikk
|
||||
setMushikingCheats(0x4ac9b8);
|
||||
else if (gameId == "MKG TKOB 2K3 2ND CHN VER1.000-") // mushikc
|
||||
setMushikingCheats(0x4aa9b8);
|
||||
else if (gameId == "MKG TKOB 2 KOR VER1.000-") // mushik2k
|
||||
setMushikingCheats(0x706084);
|
||||
}
|
||||
else if (gameId == "T-8120N") { // Dave Mirra BMX (US)
|
||||
cheats.emplace_back(Cheat::Type::setValue, "fix main loop time", true, 32, 0x0030b8cc, 0x42040000, true); // 33.0 ms
|
||||
}
|
||||
else if (gameId == "T8120D 50") { // Dave Mirra BMX (EU)
|
||||
cheats.emplace_back(Cheat::Type::setValue, "fix main loop time", true, 32, 0x003011cc, 0x42200000, true); // 40.0 ms
|
||||
}
|
||||
else if (gameId == "MK-0100") { // F355 US
|
||||
cheats.emplace_back(Cheat::Type::setValue, "increase datapump timeout", true, 16, 0x00131668, 1000, true);
|
||||
}
|
||||
else if (gameId == "T8118D 50") { // F355 EU
|
||||
cheats.emplace_back(Cheat::Type::setValue, "increase datapump timeout", true, 16, 0x00135588, 1000, true);
|
||||
}
|
||||
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)
|
||||
}
|
||||
if (cheats.size() > cheatCount)
|
||||
setActive(true);
|
||||
}
|
||||
if (config::WidescreenGameHacks)
|
||||
if (config::WidescreenGameHacks && !settings.raHardcoreMode)
|
||||
{
|
||||
if (settings.platform.isConsole())
|
||||
{
|
||||
@@ -425,10 +517,7 @@ void CheatManager::reset(const std::string& gameId)
|
||||
}
|
||||
else
|
||||
{
|
||||
std::string romName = get_file_basename(settings.content.path);
|
||||
size_t folder_pos = get_last_slash_pos(romName);
|
||||
if (folder_pos != std::string::npos)
|
||||
romName = romName.substr(folder_pos + 1);
|
||||
std::string romName = get_file_basename(settings.content.fileName);
|
||||
|
||||
for (int i = 0; naomi_widescreen_cheats[i].game_id != nullptr; i++)
|
||||
{
|
||||
@@ -443,7 +532,7 @@ void CheatManager::reset(const std::string& gameId)
|
||||
}
|
||||
}
|
||||
if (widescreen_cheat != nullptr)
|
||||
for (size_t i = 0; i < ARRAY_SIZE(widescreen_cheat->addresses) && widescreen_cheat->addresses[i] != 0; i++)
|
||||
for (size_t i = 0; i < std::size(widescreen_cheat->addresses) && widescreen_cheat->addresses[i] != 0; i++)
|
||||
verify(widescreen_cheat->addresses[i] < RAM_SIZE);
|
||||
}
|
||||
setActive(active);
|
||||
@@ -484,7 +573,7 @@ void CheatManager::apply()
|
||||
{
|
||||
if (widescreen_cheat != nullptr)
|
||||
{
|
||||
for (size_t i = 0; i < ARRAY_SIZE(widescreen_cheat->addresses) && widescreen_cheat->addresses[i] != 0; i++)
|
||||
for (size_t i = 0; i < std::size(widescreen_cheat->addresses) && widescreen_cheat->addresses[i] != 0; i++)
|
||||
{
|
||||
u32 address = widescreen_cheat->addresses[i];
|
||||
u32 curVal = readRam(address, 32);
|
||||
@@ -492,11 +581,13 @@ void CheatManager::apply()
|
||||
writeRam(address, widescreen_cheat->values[i], 32);
|
||||
}
|
||||
}
|
||||
if (active && !settings.network.online)
|
||||
if (active)
|
||||
{
|
||||
bool skipCheat = false;
|
||||
for (const Cheat& cheat : cheats)
|
||||
{
|
||||
if (!cheat.builtIn && settings.network.online)
|
||||
continue;
|
||||
if (skipCheat) {
|
||||
skipCheat = false;
|
||||
continue;
|
||||
@@ -577,7 +668,7 @@ static std::vector<u32> parseCodes(const std::string& s)
|
||||
curCode += c;
|
||||
if (curCode.length() == 8)
|
||||
{
|
||||
codes.push_back(strtol(curCode.c_str(), nullptr, 16));
|
||||
codes.push_back(strtoul(curCode.c_str(), nullptr, 16));
|
||||
curCode.clear();
|
||||
}
|
||||
}
|
||||
@@ -588,7 +679,7 @@ static std::vector<u32> parseCodes(const std::string& s)
|
||||
{
|
||||
if (curCode.length() != 8)
|
||||
throw FlycastException("Invalid cheat code");
|
||||
codes.push_back(strtol(curCode.c_str(), nullptr, 16));
|
||||
codes.push_back(strtoul(curCode.c_str(), nullptr, 16));
|
||||
}
|
||||
|
||||
return codes;
|
||||
@@ -600,200 +691,206 @@ void CheatManager::addGameSharkCheat(const std::string& name, const std::string&
|
||||
Cheat conditionCheat;
|
||||
unsigned conditionLimit = 0;
|
||||
|
||||
for (unsigned i = 0; i < codes.size(); i++)
|
||||
{
|
||||
if (i < conditionLimit)
|
||||
cheats.push_back(conditionCheat);
|
||||
Cheat cheat{};
|
||||
cheat.description = name;
|
||||
u32 code = (codes[i] & 0xff000000) >> 24;
|
||||
switch (code)
|
||||
const size_t prevSize = cheats.size();
|
||||
try {
|
||||
for (unsigned i = 0; i < codes.size(); i++)
|
||||
{
|
||||
case 0:
|
||||
case 1:
|
||||
case 2:
|
||||
if (i < conditionLimit)
|
||||
cheats.push_back(conditionCheat);
|
||||
Cheat cheat{};
|
||||
cheat.description = name;
|
||||
u32 code = (codes[i] & 0xff000000) >> 24;
|
||||
switch (code)
|
||||
{
|
||||
// 8/16/32-bit write
|
||||
if (i + 1 >= codes.size())
|
||||
throw FlycastException("Missing value");
|
||||
cheat.type = Cheat::Type::setValue;
|
||||
cheat.size = code == 0 ? 8 : code == 1 ? 16 : 32;
|
||||
cheat.address = codes[i] & 0x00ffffff;
|
||||
cheat.value = codes[++i];
|
||||
cheats.push_back(cheat);
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
{
|
||||
u32 subcode = (codes[i] & 0x00ff0000) >> 16;
|
||||
switch (subcode)
|
||||
case 0:
|
||||
case 1:
|
||||
case 2:
|
||||
{
|
||||
case 0:
|
||||
// 8/16/32-bit write
|
||||
if (i + 1 >= codes.size())
|
||||
throw FlycastException("Missing value");
|
||||
cheat.type = Cheat::Type::setValue;
|
||||
cheat.size = code == 0 ? 8 : code == 1 ? 16 : 32;
|
||||
cheat.address = codes[i] & 0x00ffffff;
|
||||
cheat.value = codes[++i];
|
||||
cheats.push_back(cheat);
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
{
|
||||
u32 subcode = (codes[i] & 0x00ff0000) >> 16;
|
||||
switch (subcode)
|
||||
{
|
||||
// Group write
|
||||
int count = codes[i] & 0xffff;
|
||||
if (i + count + 1 >= codes.size())
|
||||
throw FlycastException("Missing values");
|
||||
cheat.type = Cheat::Type::setValue;
|
||||
cheat.size = 32;
|
||||
cheat.address = codes[++i] & 0x00ffffff;
|
||||
for (int j = 0; j < count; j++)
|
||||
case 0:
|
||||
{
|
||||
if (j == 1)
|
||||
cheat.description += " (cont'd)";
|
||||
// Group write
|
||||
int count = codes[i] & 0xffff;
|
||||
if (i + count + 1 >= codes.size())
|
||||
throw FlycastException("Missing values");
|
||||
cheat.type = Cheat::Type::setValue;
|
||||
cheat.size = 32;
|
||||
cheat.address = codes[++i] & 0x00ffffff;
|
||||
for (int j = 0; j < count; j++)
|
||||
{
|
||||
if (j == 1)
|
||||
cheat.description += " (cont'd)";
|
||||
cheat.value = codes[++i];
|
||||
cheats.push_back(cheat);
|
||||
cheat.address += 4;
|
||||
if (j < count - 1 && i < conditionLimit)
|
||||
cheats.push_back(conditionCheat);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
case 2:
|
||||
{
|
||||
// 8-bit inc/decrement
|
||||
if (i + 1 >= codes.size())
|
||||
throw FlycastException("Missing value");
|
||||
cheat.type = subcode == 1 ? Cheat::Type::increase : Cheat::Type::decrease;
|
||||
cheat.size = 8;
|
||||
cheat.value = codes[i] & 0xff;
|
||||
cheat.address = codes[++i] & 0x00ffffff;
|
||||
cheats.push_back(cheat);
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
case 4:
|
||||
{
|
||||
// 16-bit inc/decrement
|
||||
if (i + 1 >= codes.size())
|
||||
throw FlycastException("Missing value");
|
||||
cheat.type = subcode == 3 ? Cheat::Type::increase : Cheat::Type::decrease;
|
||||
cheat.size = 16;
|
||||
cheat.value = codes[i] & 0xffff;
|
||||
cheat.address = codes[++i] & 0x00ffffff;
|
||||
cheats.push_back(cheat);
|
||||
}
|
||||
break;
|
||||
case 5:
|
||||
case 6:
|
||||
{
|
||||
// 32-bit inc/decrement
|
||||
if (i + 2 >= codes.size())
|
||||
throw FlycastException("Missing address or value");
|
||||
cheat.type = subcode == 5 ? Cheat::Type::increase : Cheat::Type::decrease;
|
||||
cheat.size = 32;
|
||||
cheat.address = codes[++i] & 0x00ffffff;
|
||||
cheat.value = codes[++i];
|
||||
cheats.push_back(cheat);
|
||||
cheat.address += 4;
|
||||
if (j < count - 1 && i < conditionLimit)
|
||||
cheats.push_back(conditionCheat);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw FlycastException("Unsupported cheat type");
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
case 2:
|
||||
{
|
||||
// 8-bit inc/decrement
|
||||
if (i + 1 >= codes.size())
|
||||
throw FlycastException("Missing value");
|
||||
cheat.type = subcode == 1 ? Cheat::Type::increase : Cheat::Type::decrease;
|
||||
cheat.size = 8;
|
||||
cheat.value = codes[i] & 0xff;
|
||||
cheat.address = codes[++i] & 0x00ffffff;
|
||||
cheats.push_back(cheat);
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
case 4:
|
||||
{
|
||||
// 16-bit inc/decrement
|
||||
if (i + 1 >= codes.size())
|
||||
throw FlycastException("Missing value");
|
||||
cheat.type = subcode == 3 ? Cheat::Type::increase : Cheat::Type::decrease;
|
||||
cheat.size = 16;
|
||||
cheat.value = codes[i] & 0xffff;
|
||||
cheat.address = codes[++i] & 0x00ffffff;
|
||||
cheats.push_back(cheat);
|
||||
}
|
||||
break;
|
||||
case 5:
|
||||
case 6:
|
||||
{
|
||||
// 32-bit inc/decrement
|
||||
if (i + 2 >= codes.size())
|
||||
throw FlycastException("Missing address or value");
|
||||
cheat.type = subcode == 5 ? Cheat::Type::increase : Cheat::Type::decrease;
|
||||
cheat.size = 32;
|
||||
cheat.address = codes[++i] & 0x00ffffff;
|
||||
cheat.value = codes[++i];
|
||||
cheats.push_back(cheat);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw FlycastException("Unsupported cheat type");
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 4:
|
||||
{
|
||||
// 32-bit repeat write
|
||||
if (i + 2 >= codes.size())
|
||||
throw FlycastException("Missing count or value");
|
||||
cheat.type = Cheat::Type::setValue;
|
||||
cheat.size = 32;
|
||||
cheat.address = codes[i] & 0x00ffffff;
|
||||
cheat.repeatCount = codes[++i] >> 16;
|
||||
cheat.repeatAddressIncrement = codes[i] & 0xffff;
|
||||
cheat.value = codes[++i];
|
||||
cheats.push_back(cheat);
|
||||
}
|
||||
break;
|
||||
case 5:
|
||||
{
|
||||
// copy bytes
|
||||
if (i + 2 >= codes.size())
|
||||
throw FlycastException("Missing count or destination address");
|
||||
cheat.type = Cheat::Type::copy;
|
||||
cheat.size = 8;
|
||||
cheat.address = codes[i] & 0x00ffffff;
|
||||
cheat.destAddress = codes[++i] & 0x00ffffff;
|
||||
cheat.repeatCount = codes[++i];
|
||||
cheats.push_back(cheat);
|
||||
}
|
||||
break;
|
||||
// TODO 7 change decryption type
|
||||
// TODO 0xb delay applying codes
|
||||
// TODO 0xc global enable test
|
||||
case 0xd:
|
||||
{
|
||||
// enable next code if eq/neq/lt/gt
|
||||
if (i + 1 >= codes.size())
|
||||
throw FlycastException("Missing count or destination address");
|
||||
cheat.size = 16;
|
||||
cheat.address = codes[i] & 0x00ffffff;
|
||||
switch (codes[++i] >> 16)
|
||||
break;
|
||||
case 4:
|
||||
{
|
||||
case 0:
|
||||
cheat.type = Cheat::Type::runNextIfEq;
|
||||
break;
|
||||
case 1:
|
||||
cheat.type = Cheat::Type::runNextIfNeq;
|
||||
break;
|
||||
case 2:
|
||||
cheat.type = Cheat::Type::runNextIfLt;
|
||||
break;
|
||||
case 3:
|
||||
cheat.type = Cheat::Type::runNextIfGt;
|
||||
break;
|
||||
default:
|
||||
throw FlycastException("Unsupported conditional code");
|
||||
// 32-bit repeat write
|
||||
if (i + 2 >= codes.size())
|
||||
throw FlycastException("Missing count or value");
|
||||
cheat.type = Cheat::Type::setValue;
|
||||
cheat.size = 32;
|
||||
cheat.address = codes[i] & 0x00ffffff;
|
||||
cheat.repeatCount = codes[++i] >> 16;
|
||||
cheat.repeatAddressIncrement = codes[i] & 0xffff;
|
||||
cheat.value = codes[++i];
|
||||
cheats.push_back(cheat);
|
||||
}
|
||||
cheat.value = codes[i] & 0xffff;
|
||||
cheats.push_back(cheat);
|
||||
}
|
||||
break;
|
||||
case 0xe:
|
||||
{
|
||||
// multiline enable codes if eq/neq/lt/gt
|
||||
if (i + 1 >= codes.size())
|
||||
throw FlycastException("Missing test address");
|
||||
cheat.size = 16;
|
||||
cheat.value = codes[i] & 0xffff;
|
||||
conditionLimit = i + 1 + ((codes[i] >> 16) & 0xff);
|
||||
switch (codes[++i] >> 24)
|
||||
break;
|
||||
case 5:
|
||||
{
|
||||
case 0:
|
||||
cheat.type = Cheat::Type::runNextIfEq;
|
||||
break;
|
||||
case 1:
|
||||
cheat.type = Cheat::Type::runNextIfNeq;
|
||||
break;
|
||||
case 2:
|
||||
cheat.type = Cheat::Type::runNextIfLt;
|
||||
break;
|
||||
case 3:
|
||||
cheat.type = Cheat::Type::runNextIfGt;
|
||||
break;
|
||||
default:
|
||||
throw FlycastException("Unsupported conditional code");
|
||||
// copy bytes
|
||||
if (i + 2 >= codes.size())
|
||||
throw FlycastException("Missing count or destination address");
|
||||
cheat.type = Cheat::Type::copy;
|
||||
cheat.size = 8;
|
||||
cheat.address = codes[i] & 0x00ffffff;
|
||||
cheat.destAddress = codes[++i] & 0x00ffffff;
|
||||
cheat.repeatCount = codes[++i];
|
||||
cheats.push_back(cheat);
|
||||
}
|
||||
cheat.address = codes[i] & 0x00ffffff;
|
||||
conditionCheat = cheat;
|
||||
break;
|
||||
// TODO 7 change decryption type
|
||||
// TODO 0xb delay applying codes
|
||||
// TODO 0xc global enable test
|
||||
case 0xd:
|
||||
{
|
||||
// enable next code if eq/neq/lt/gt
|
||||
if (i + 1 >= codes.size())
|
||||
throw FlycastException("Missing count or destination address");
|
||||
cheat.size = 16;
|
||||
cheat.address = codes[i] & 0x00ffffff;
|
||||
switch (codes[++i] >> 16)
|
||||
{
|
||||
case 0:
|
||||
cheat.type = Cheat::Type::runNextIfEq;
|
||||
break;
|
||||
case 1:
|
||||
cheat.type = Cheat::Type::runNextIfNeq;
|
||||
break;
|
||||
case 2:
|
||||
cheat.type = Cheat::Type::runNextIfLt;
|
||||
break;
|
||||
case 3:
|
||||
cheat.type = Cheat::Type::runNextIfGt;
|
||||
break;
|
||||
default:
|
||||
throw FlycastException("Unsupported conditional code");
|
||||
}
|
||||
cheat.value = codes[i] & 0xffff;
|
||||
cheats.push_back(cheat);
|
||||
}
|
||||
break;
|
||||
case 0xe:
|
||||
{
|
||||
// multiline enable codes if eq/neq/lt/gt
|
||||
if (i + 1 >= codes.size())
|
||||
throw FlycastException("Missing test address");
|
||||
cheat.size = 16;
|
||||
cheat.value = codes[i] & 0xffff;
|
||||
conditionLimit = i + 1 + ((codes[i] >> 16) & 0xff);
|
||||
switch (codes[++i] >> 24)
|
||||
{
|
||||
case 0:
|
||||
cheat.type = Cheat::Type::runNextIfEq;
|
||||
break;
|
||||
case 1:
|
||||
cheat.type = Cheat::Type::runNextIfNeq;
|
||||
break;
|
||||
case 2:
|
||||
cheat.type = Cheat::Type::runNextIfLt;
|
||||
break;
|
||||
case 3:
|
||||
cheat.type = Cheat::Type::runNextIfGt;
|
||||
break;
|
||||
default:
|
||||
throw FlycastException("Unsupported conditional code");
|
||||
}
|
||||
cheat.address = codes[i] & 0x00ffffff;
|
||||
conditionCheat = cheat;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw FlycastException("Unsupported cheat type");
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw FlycastException("Unsupported cheat type");
|
||||
}
|
||||
}
|
||||
setActive(!cheats.empty());
|
||||
#ifndef LIBRETRO
|
||||
std::string path = cfgLoadStr("cheats", gameId, "");
|
||||
if (path == "")
|
||||
{
|
||||
path = get_game_save_prefix() + ".cht";
|
||||
cfgSaveStr("cheats", gameId, path);
|
||||
}
|
||||
saveCheatFile(path);
|
||||
std::string path = cfgLoadStr("cheats", gameId, "");
|
||||
if (path == "")
|
||||
{
|
||||
path = get_game_save_prefix() + ".cht";
|
||||
cfgSaveStr("cheats", gameId, path);
|
||||
}
|
||||
saveCheatFile(path);
|
||||
#endif
|
||||
setActive(!cheats.empty());
|
||||
} catch (...) {
|
||||
cheats.erase(cheats.begin() + prevSize, cheats.end());
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
void CheatManager::saveCheatFile(const std::string& filename)
|
||||
@@ -846,7 +943,7 @@ void CheatManager::saveCheatFile(const std::string& filename)
|
||||
i++;
|
||||
}
|
||||
cfg.set_int("", "cheats", i);
|
||||
FILE *fp = nowide::fopen(filename.c_str(), "w");
|
||||
FILE *fp = hostfs::storage().openFile(filename.c_str(), "w");
|
||||
if (fp == nullptr)
|
||||
throw FlycastException("Can't save cheat file");
|
||||
cfg.save(fp);
|
||||
|
||||
+11
-11
@@ -21,6 +21,8 @@
|
||||
#pragma once
|
||||
#include "types.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
struct WidescreenCheat
|
||||
{
|
||||
const char *game_id;
|
||||
@@ -49,19 +51,17 @@ struct Cheat
|
||||
u32 size;
|
||||
u32 address;
|
||||
u32 value;
|
||||
u8 valueMask;
|
||||
u32 repeatCount;
|
||||
u32 repeatValueIncrement;
|
||||
u32 repeatAddressIncrement;
|
||||
u32 destAddress;
|
||||
u8 valueMask = 0;
|
||||
u32 repeatCount = 1;
|
||||
u32 repeatValueIncrement = 0;
|
||||
u32 repeatAddressIncrement = 0;
|
||||
u32 destAddress = 0;
|
||||
bool builtIn;
|
||||
|
||||
Cheat(Type type = Type::disabled, const std::string& description = "", bool enabled = false, u32 size = 0, u32 address = 0,
|
||||
u32 value = 0, u8 valueMask = 0, u32 repeatCount = 1, u32 repeatValueIncrement = 0,
|
||||
u32 repeatAddressIncrement = 0, u32 destAddress = 0, bool builtIn = false)
|
||||
: type(type), description(description), enabled(enabled), size(size), address(address), value(value), valueMask(valueMask),
|
||||
repeatCount(repeatCount), repeatValueIncrement(repeatValueIncrement), repeatAddressIncrement(repeatAddressIncrement),
|
||||
destAddress(destAddress), builtIn(builtIn)
|
||||
Cheat(Type type = Type::disabled, const std::string& description = "", bool enabled = false,
|
||||
u32 size = 0, u32 address = 0, u32 value = 0, bool builtIn = false)
|
||||
: type(type), description(description), enabled(enabled),
|
||||
size(size), address(address), value(value), builtIn(builtIn)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
+44
-21
@@ -73,6 +73,24 @@ const std::array<Sh4RegType, 59> Sh4RegList {
|
||||
class DebugAgent
|
||||
{
|
||||
public:
|
||||
struct Breakpoint {
|
||||
enum Type
|
||||
{
|
||||
BP_TYPE_SOFTWARE_BREAK,
|
||||
BP_TYPE_HARDWARE_BREAK,
|
||||
BP_TYPE_WRITE_WATCHPOINT,
|
||||
BP_TYPE_READ_WATCHPOINT,
|
||||
BP_TYPE_ACCESS_WATCHPOINT,
|
||||
BP_TYPE_COUNT
|
||||
};
|
||||
|
||||
Breakpoint() = default;
|
||||
Breakpoint(u16 type, u32 addr) : addr(addr), type(type) { }
|
||||
u32 addr = 0;
|
||||
u16 type = 0;
|
||||
u16 savedOp = 0;
|
||||
};
|
||||
|
||||
void doContinue(u32 pc = 1)
|
||||
{
|
||||
if (pc != 1)
|
||||
@@ -82,11 +100,20 @@ public:
|
||||
|
||||
void step()
|
||||
{
|
||||
bool restoreBreakpoint = removeMatchpoint(0, Sh4cntx.pc, 2);
|
||||
bool restoreBreakpoint = removeMatchpoint(Breakpoint::BP_TYPE_SOFTWARE_BREAK, Sh4cntx.pc, 2);
|
||||
u32 savedPc = Sh4cntx.pc;
|
||||
emu.step();
|
||||
if (restoreBreakpoint)
|
||||
insertMatchpoint(0, savedPc, 2);
|
||||
insertMatchpoint(Breakpoint::BP_TYPE_SOFTWARE_BREAK, savedPc, 2);
|
||||
}
|
||||
|
||||
void stepRange(u32 from, u32 to)
|
||||
{
|
||||
bool restoreBreakpoint = removeMatchpoint(Breakpoint::BP_TYPE_SOFTWARE_BREAK, Sh4cntx.pc, 2);
|
||||
u32 savedPc = Sh4cntx.pc;
|
||||
emu.stepRange(from, to);
|
||||
if (restoreBreakpoint)
|
||||
insertMatchpoint(Breakpoint::BP_TYPE_SOFTWARE_BREAK, savedPc, 2);
|
||||
}
|
||||
|
||||
int readAllRegs(u32 **regs)
|
||||
@@ -190,31 +217,31 @@ public:
|
||||
}
|
||||
}
|
||||
}
|
||||
bool insertMatchpoint(char type, u32 addr, u32 len)
|
||||
bool insertMatchpoint(Breakpoint::Type type, u32 addr, u32 len)
|
||||
{
|
||||
if (type == 0 && len != 2) {
|
||||
if (type == Breakpoint::BP_TYPE_SOFTWARE_BREAK && len != 2) {
|
||||
WARN_LOG(COMMON, "insertMatchpoint: length != 2: %d", len);
|
||||
return false;
|
||||
}
|
||||
// TODO other matchpoint types
|
||||
if (breakpoints.find(addr) != breakpoints.end())
|
||||
if (breakpoints[type].find(addr) != breakpoints[type].end())
|
||||
return true;
|
||||
breakpoints[addr] = Breakpoint(type, addr);
|
||||
breakpoints[addr].savedOp = ReadMem16_nommu(addr);
|
||||
breakpoints[type][addr] = Breakpoint(type, addr);
|
||||
breakpoints[type][addr].savedOp = ReadMem16_nommu(addr);
|
||||
WriteMem16_nommu(addr, 0xC308); // trapa #0x20
|
||||
return true;
|
||||
}
|
||||
bool removeMatchpoint(char type, u32 addr, u32 len)
|
||||
bool removeMatchpoint(Breakpoint::Type type, u32 addr, u32 len)
|
||||
{
|
||||
if (type == 0 && len != 2) {
|
||||
if (type == Breakpoint::BP_TYPE_SOFTWARE_BREAK && len != 2) {
|
||||
WARN_LOG(COMMON, "removeMatchpoint: length != 2: %d", len);
|
||||
return false;
|
||||
}
|
||||
auto it = breakpoints.find(addr);
|
||||
if (it == breakpoints.end())
|
||||
auto it = breakpoints[type].find(addr);
|
||||
if (it == breakpoints[type].end())
|
||||
return false;
|
||||
WriteMem16_nommu(addr, it->second.savedOp);
|
||||
breakpoints.erase(it);
|
||||
breakpoints[type].erase(it);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -295,7 +322,10 @@ public:
|
||||
{
|
||||
verify(!Sh4cntx.CpuRunning);
|
||||
size = stack.size() * 8;
|
||||
return (const u32 *)&stack[0];
|
||||
if (!stack.empty())
|
||||
return (const u32 *)&stack[0];
|
||||
else
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void subroutineCall()
|
||||
@@ -312,13 +342,6 @@ public:
|
||||
|
||||
u32 exception = 0;
|
||||
|
||||
struct Breakpoint {
|
||||
Breakpoint() = default;
|
||||
Breakpoint(u16 type, u32 addr) : addr(addr), type(type) { }
|
||||
u32 addr = 0;
|
||||
u16 type = 0;
|
||||
u16 savedOp = 0;
|
||||
};
|
||||
std::map<u32, Breakpoint> breakpoints;
|
||||
std::map<u32, Breakpoint> breakpoints[Breakpoint::Type::BP_TYPE_COUNT];
|
||||
std::vector<std::pair<u32, u32>> stack;
|
||||
};
|
||||
+124
-33
@@ -22,12 +22,15 @@
|
||||
#include "gdb_server.h"
|
||||
#include "debug_agent.h"
|
||||
#include "network/net_platform.h"
|
||||
#include "cfg/option.h"
|
||||
#include "oslib/oslib.h"
|
||||
#include <stdexcept>
|
||||
#include <thread>
|
||||
#include <chrono>
|
||||
#include <mutex>
|
||||
#include <cassert>
|
||||
|
||||
#define SERVER_PORT 3263
|
||||
#define MAX_PACKET_LEN 4096
|
||||
|
||||
namespace debugger {
|
||||
|
||||
@@ -40,7 +43,7 @@ public:
|
||||
Error(const char *reason) : std::runtime_error(reason) {}
|
||||
};
|
||||
|
||||
void init()
|
||||
void init(int port)
|
||||
{
|
||||
if (VALID(serverSocket))
|
||||
return;
|
||||
@@ -55,7 +58,7 @@ public:
|
||||
struct sockaddr_in serveraddr;
|
||||
memset(&serveraddr, 0, sizeof(serveraddr));
|
||||
serveraddr.sin_family = AF_INET;
|
||||
serveraddr.sin_port = htons(SERVER_PORT);
|
||||
serveraddr.sin_port = htons(port);
|
||||
|
||||
if (::bind(serverSocket, (struct sockaddr *)&serveraddr, sizeof(serveraddr)) < 0)
|
||||
{
|
||||
@@ -69,10 +72,14 @@ public:
|
||||
}
|
||||
EventManager::listen(Event::Resume, emuEventCallback);
|
||||
EventManager::listen(Event::Terminate, emuEventCallback);
|
||||
|
||||
initialised = true;
|
||||
}
|
||||
|
||||
void term()
|
||||
{
|
||||
if (!initialised)
|
||||
return;
|
||||
EventManager::unlisten(Event::Resume, emuEventCallback);
|
||||
EventManager::unlisten(Event::Terminate, emuEventCallback);
|
||||
stop();
|
||||
@@ -90,12 +97,21 @@ public:
|
||||
|
||||
void run()
|
||||
{
|
||||
if (!initialised || thread.joinable())
|
||||
return;
|
||||
DEBUG_LOG(COMMON, "GdbServer starting");
|
||||
thread = std::thread(&GdbServer::serverThread, this);
|
||||
if (config::GDBWaitForConnection)
|
||||
{
|
||||
DEBUG_LOG(COMMON, "Waiting for GDB connection...");
|
||||
agentInterrupt();
|
||||
}
|
||||
}
|
||||
|
||||
void stop()
|
||||
{
|
||||
if (!initialised)
|
||||
return;
|
||||
if (thread.joinable())
|
||||
{
|
||||
DEBUG_LOG(COMMON, "GdbServer stopping");
|
||||
@@ -106,7 +122,7 @@ public:
|
||||
}
|
||||
|
||||
bool isRunning() const {
|
||||
return thread.joinable();
|
||||
return initialised && thread.joinable();
|
||||
}
|
||||
|
||||
// called on the emu thread
|
||||
@@ -125,6 +141,7 @@ private:
|
||||
|
||||
void serverThread()
|
||||
{
|
||||
ThreadName _("GdbServer");
|
||||
while (!stopRequested)
|
||||
{
|
||||
fd_set fds;
|
||||
@@ -183,18 +200,22 @@ private:
|
||||
{
|
||||
NOTICE_LOG(NETWORK, "gdb: client connection");
|
||||
attached = true;
|
||||
agent.interrupt();
|
||||
agentInterrupt();
|
||||
}
|
||||
}
|
||||
|
||||
void readCommand()
|
||||
{
|
||||
if (postDebugTrapNeeded)
|
||||
{
|
||||
postDebugTrapNeeded = false;
|
||||
agent.postDebugTrap();
|
||||
}
|
||||
try {
|
||||
try {
|
||||
if (postDebugTrapNeeded)
|
||||
{
|
||||
postDebugTrapNeeded = false;
|
||||
try {
|
||||
agent.postDebugTrap();
|
||||
} catch (const FlycastException& e) {
|
||||
throw Error(e.what());
|
||||
}
|
||||
}
|
||||
std::string packet = recvPacket();
|
||||
if (packet.empty())
|
||||
return;
|
||||
@@ -496,7 +517,12 @@ private:
|
||||
const u32 *data = agent.getStack(len);
|
||||
len /= 4;
|
||||
|
||||
#if _MSC_VER // Non-const array size is a GCC extension
|
||||
assert((len * 9 * 2 + 1) < MAX_PACKET_LEN);
|
||||
char reply[MAX_PACKET_LEN];
|
||||
#else
|
||||
char reply[len * 9 * 2 + 1];
|
||||
#endif
|
||||
char *r = reply;
|
||||
for (u32 i = 0; i < len; i++)
|
||||
{
|
||||
@@ -515,9 +541,13 @@ private:
|
||||
sendPacket("");
|
||||
}
|
||||
else if (pkt.rfind("qSupported", 0) == 0)
|
||||
{
|
||||
// Tell the remote stub about features supported by GDB,
|
||||
// and query the stub for features it supports
|
||||
sendPacket("PacketSize=10000");
|
||||
char qsupported[128];
|
||||
snprintf(qsupported, 128, "PacketSize=%i;vContSupported+", MAX_PACKET_LEN);
|
||||
sendPacket(qsupported);
|
||||
}
|
||||
else if (pkt.rfind("qSymbol:", 0) == 0)
|
||||
// Notify the target that GDB is prepared to serve symbol lookup requests
|
||||
sendPacket("OK");
|
||||
@@ -570,11 +600,41 @@ private:
|
||||
if (pkt.rfind("vAttach;", 0) == 0)
|
||||
sendPacket("S05");
|
||||
else if (pkt.rfind("vCont?", 0) == 0)
|
||||
// not supported
|
||||
sendPacket("vCont;s;c");
|
||||
// supported vCont actions - (c)ontinue, (C)ontinue with signal, (s)tep, (S)tep with signal, (r)ange-step
|
||||
sendPacket("vCont;c;C;s;S;t;r");
|
||||
else if (pkt.rfind("vCont", 0) == 0)
|
||||
// not supported
|
||||
WARN_LOG(COMMON, "vCont not supported %s", pkt.c_str());
|
||||
{
|
||||
std::string vContCmd = pkt.substr(strlen("vCont;"));
|
||||
switch (vContCmd[0])
|
||||
{
|
||||
case 'c':
|
||||
case 'C':
|
||||
sendContinue(vContCmd);
|
||||
break;
|
||||
case 's':
|
||||
step(EXCEPT_NONE);
|
||||
break;
|
||||
case 'S':
|
||||
step();
|
||||
case 'r':
|
||||
{
|
||||
u32 from, to;
|
||||
if (sscanf(vContCmd.c_str(), "r%x,%x", &from, &to) == 2)
|
||||
{
|
||||
stepRange(from, to);
|
||||
}
|
||||
else
|
||||
{
|
||||
WARN_LOG(COMMON, "Unsupported vCont:r format %s", pkt.c_str());
|
||||
sendContinue("c");
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
WARN_LOG(COMMON, "vCont action not supported %s", pkt.c_str());
|
||||
}
|
||||
}
|
||||
else if (pkt.rfind("vFile:", 0) == 0)
|
||||
// not supported
|
||||
sendPacket("");
|
||||
@@ -599,11 +659,11 @@ private:
|
||||
sendPacket("OK");
|
||||
agent.kill();
|
||||
}
|
||||
else if (pkt.rfind("vMustReplyEmpty", 0) == 0)
|
||||
// Reply empty packet
|
||||
sendPacket("");
|
||||
else
|
||||
{
|
||||
WARN_LOG(COMMON, "unknown v packet: %s", pkt.c_str());
|
||||
sendPacket("");
|
||||
}
|
||||
}
|
||||
|
||||
void restart()
|
||||
@@ -613,8 +673,23 @@ private:
|
||||
|
||||
void step(u32 what = 0)
|
||||
{
|
||||
agent.step();
|
||||
sendPacket("S05");
|
||||
try {
|
||||
agent.step();
|
||||
sendPacket("S05");
|
||||
} catch (const FlycastException& e) {
|
||||
throw Error(e.what());
|
||||
}
|
||||
}
|
||||
|
||||
void stepRange(u32 from, u32 to)
|
||||
{
|
||||
try {
|
||||
sendPacket("OK");
|
||||
agent.stepRange(from, to);
|
||||
sendPacket("S05");
|
||||
} catch (const FlycastException& e) {
|
||||
throw Error(e.what());
|
||||
}
|
||||
}
|
||||
|
||||
void insertMatchpoint(const std::string& pkt)
|
||||
@@ -627,22 +702,23 @@ private:
|
||||
sendPacket("E01");
|
||||
}
|
||||
switch (type) {
|
||||
case 0: // soft bp
|
||||
if (agent.insertMatchpoint(0, addr, len))
|
||||
case DebugAgent::Breakpoint::BP_TYPE_SOFTWARE_BREAK: // soft bp
|
||||
if (agent.insertMatchpoint(DebugAgent::Breakpoint::BP_TYPE_SOFTWARE_BREAK,
|
||||
addr, len))
|
||||
sendPacket("OK");
|
||||
else
|
||||
sendPacket("E01");
|
||||
break;
|
||||
case 1: // hardware bp
|
||||
case DebugAgent::Breakpoint::BP_TYPE_HARDWARE_BREAK: // hardware bp
|
||||
sendPacket("");
|
||||
break;
|
||||
case 2: // write watchpoint
|
||||
case DebugAgent::Breakpoint::BP_TYPE_WRITE_WATCHPOINT: // write watchpoint
|
||||
sendPacket("");
|
||||
break;
|
||||
case 3: // read watchpoint
|
||||
case DebugAgent::Breakpoint::BP_TYPE_READ_WATCHPOINT: // read watchpoint
|
||||
sendPacket("");
|
||||
break;
|
||||
case 4: // access watchpoint
|
||||
case DebugAgent::Breakpoint::BP_TYPE_ACCESS_WATCHPOINT: // access watchpoint
|
||||
sendPacket("");
|
||||
break;
|
||||
default:
|
||||
@@ -662,7 +738,8 @@ private:
|
||||
}
|
||||
switch (type) {
|
||||
case 0: // soft bp
|
||||
if (agent.removeMatchpoint(0, addr, len))
|
||||
if (agent.removeMatchpoint(DebugAgent::Breakpoint::BP_TYPE_SOFTWARE_BREAK,
|
||||
addr, len))
|
||||
sendPacket("OK");
|
||||
else
|
||||
sendPacket("E01");
|
||||
@@ -687,7 +764,7 @@ private:
|
||||
|
||||
void interrupt()
|
||||
{
|
||||
u32 signal = agent.interrupt();
|
||||
u32 signal = agentInterrupt();
|
||||
char s[10];
|
||||
sprintf(s, "S%02x", signal);
|
||||
sendPacket(s);
|
||||
@@ -827,6 +904,16 @@ private:
|
||||
throw Error("I/O error");
|
||||
}
|
||||
|
||||
u32 agentInterrupt()
|
||||
{
|
||||
try {
|
||||
return agent.interrupt();
|
||||
} catch (const FlycastException& e) {
|
||||
throw Error(e.what());
|
||||
}
|
||||
}
|
||||
|
||||
bool initialised = false;
|
||||
bool stopRequested = false;
|
||||
bool attached = false;
|
||||
bool postDebugTrapNeeded = false;
|
||||
@@ -840,9 +927,9 @@ public:
|
||||
|
||||
static GdbServer gdbServer;
|
||||
|
||||
void init()
|
||||
void init(int port)
|
||||
{
|
||||
gdbServer.init();
|
||||
gdbServer.init(port);
|
||||
}
|
||||
|
||||
void term()
|
||||
@@ -870,8 +957,12 @@ static void emuEventCallback(Event event, void *)
|
||||
switch (event)
|
||||
{
|
||||
case Event::Resume:
|
||||
if (!gdbServer.isRunning())
|
||||
gdbServer.run();
|
||||
try {
|
||||
if (!gdbServer.isRunning())
|
||||
gdbServer.run();
|
||||
} catch (const GdbServer::Error& e) {
|
||||
ERROR_LOG(COMMON, "%s", e.what());
|
||||
}
|
||||
break;
|
||||
case Event::Terminate:
|
||||
gdbServer.stop();
|
||||
|
||||
@@ -23,9 +23,11 @@ namespace debugger {
|
||||
// exception thrown in response to trap
|
||||
struct Stop { };
|
||||
|
||||
static const int DEFAULT_PORT = 3263;
|
||||
|
||||
#ifdef GDB_SERVER
|
||||
|
||||
void init();
|
||||
void init(int port);
|
||||
void term();
|
||||
void run();
|
||||
void debugTrap(u32 event);
|
||||
@@ -33,7 +35,7 @@ struct Stop { };
|
||||
void subroutineReturn();
|
||||
|
||||
#else
|
||||
static inline void init() {}
|
||||
static inline void init(int port) {}
|
||||
static inline void term() {}
|
||||
static inline void run() {}
|
||||
static inline void debugTrap(u32 event) {}
|
||||
|
||||
+1
-1
Submodule core/deps/SDL updated: 8c9beb0c87...92fe3b19c8.
Submodule
+1
Submodule core/deps/Spout added at 2110a918e7.
Submodule
+1
Submodule core/deps/Syphon added at 486dd8e4ef.
Submodule
+1
Submodule core/deps/Vulkan-Headers added at 85c2334e92.
Submodule
+1
Submodule core/deps/VulkanMemoryAllocator added at 6eb62e1515.
+1
-1
Submodule core/deps/breakpad updated: d2657e1267...1ab24bcc81.
Submodule
+1
Submodule core/deps/discord-rpc added at 6cae2bd07a.
@@ -579,26 +579,6 @@ GGPO_API GGPOErrorCode __cdecl ggpo_set_disconnect_timeout(GGPOSession *,
|
||||
GGPO_API GGPOErrorCode __cdecl ggpo_set_disconnect_notify_start(GGPOSession *,
|
||||
int timeout);
|
||||
|
||||
/*
|
||||
* ggpo_log --
|
||||
*
|
||||
* Used to write to the ggpo.net log. In the current versions of the
|
||||
* SDK, a log file is only generated if the "quark.log" environment
|
||||
* variable is set to 1. This will change in future versions of the
|
||||
* SDK.
|
||||
*/
|
||||
GGPO_API void __cdecl ggpo_log(GGPOSession *,
|
||||
const char *fmt, ...);
|
||||
/*
|
||||
* ggpo_logv --
|
||||
*
|
||||
* A varargs compatible version of ggpo_log. See ggpo_log for
|
||||
* more details.
|
||||
*/
|
||||
GGPO_API void __cdecl ggpo_logv(GGPOSession *,
|
||||
const char *fmt,
|
||||
va_list args);
|
||||
|
||||
/*
|
||||
* ggpo_send_message --
|
||||
*
|
||||
|
||||
@@ -20,7 +20,6 @@ struct GGPOSession {
|
||||
virtual GGPOErrorCode IncrementFrame(void) { return GGPO_OK; }
|
||||
virtual GGPOErrorCode DisconnectPlayer(GGPOPlayerHandle handle) { return GGPO_OK; }
|
||||
virtual GGPOErrorCode GetNetworkStats(GGPONetworkStats *stats, GGPOPlayerHandle handle) { return GGPO_OK; }
|
||||
virtual GGPOErrorCode Logv(const char *fmt, va_list list) { ::Logv(fmt, list); return GGPO_OK; }
|
||||
|
||||
virtual GGPOErrorCode SetFrameDelay(GGPOPlayerHandle player, int delay) { return GGPO_ERRORCODE_UNSUPPORTED; }
|
||||
virtual GGPOErrorCode SetDisconnectTimeout(int timeout) { return GGPO_ERRORCODE_UNSUPPORTED; }
|
||||
|
||||
@@ -130,12 +130,12 @@ Peer2PeerBackend::DoPoll(int timeout)
|
||||
total_min_confirmed = PollNPlayers(current_frame);
|
||||
}
|
||||
|
||||
Log("last confirmed frame in p2p backend is %d.\n", total_min_confirmed);
|
||||
Log("last confirmed frame in p2p backend is %d.", total_min_confirmed);
|
||||
if (total_min_confirmed >= 0) {
|
||||
ASSERT(total_min_confirmed != INT_MAX);
|
||||
if (_num_spectators > 0) {
|
||||
while (_next_spectator_frame <= total_min_confirmed) {
|
||||
Log("pushing frame %d to spectators.\n", _next_spectator_frame);
|
||||
Log("pushing frame %d to spectators.", _next_spectator_frame);
|
||||
|
||||
GameInput input;
|
||||
input.frame = _next_spectator_frame;
|
||||
@@ -147,7 +147,7 @@ Peer2PeerBackend::DoPoll(int timeout)
|
||||
_next_spectator_frame++;
|
||||
}
|
||||
}
|
||||
Log("setting confirmed frame in sync to %d.\n", total_min_confirmed);
|
||||
Log("setting confirmed frame in sync to %d.", total_min_confirmed);
|
||||
_sync.SetLastConfirmedFrame(total_min_confirmed);
|
||||
}
|
||||
|
||||
@@ -189,12 +189,12 @@ int Peer2PeerBackend::Poll2Players(int current_frame)
|
||||
if (!_local_connect_status[i].disconnected) {
|
||||
total_min_confirmed = MIN(_local_connect_status[i].last_frame, total_min_confirmed);
|
||||
}
|
||||
Log(" local endp: connected = %d, last_received = %d, total_min_confirmed = %d.\n", !_local_connect_status[i].disconnected, _local_connect_status[i].last_frame, total_min_confirmed);
|
||||
Log(" local endp: connected = %d, last_received = %d, total_min_confirmed = %d.", !_local_connect_status[i].disconnected, _local_connect_status[i].last_frame, total_min_confirmed);
|
||||
if (!queue_connected && !_local_connect_status[i].disconnected) {
|
||||
Log("disconnecting i %d by remote request.\n", i);
|
||||
Log("disconnecting i %d by remote request.", i);
|
||||
DisconnectPlayerQueue(i, total_min_confirmed);
|
||||
}
|
||||
Log(" total_min_confirmed = %d.\n", total_min_confirmed);
|
||||
Log(" total_min_confirmed = %d.", total_min_confirmed);
|
||||
}
|
||||
return total_min_confirmed;
|
||||
}
|
||||
@@ -208,7 +208,7 @@ int Peer2PeerBackend::PollNPlayers(int current_frame)
|
||||
for (queue = 0; queue < _num_players; queue++) {
|
||||
bool queue_connected = true;
|
||||
int queue_min_confirmed = MAX_INT;
|
||||
Log("considering queue %d.\n", queue);
|
||||
Log("considering queue %d.", queue);
|
||||
for (i = 0; i < _num_players; i++) {
|
||||
// we're going to do a lot of logic here in consideration of endpoint i.
|
||||
// keep accumulating the minimum confirmed point for all n*n packets and
|
||||
@@ -218,16 +218,16 @@ int Peer2PeerBackend::PollNPlayers(int current_frame)
|
||||
|
||||
queue_connected = queue_connected && connected;
|
||||
queue_min_confirmed = MIN(last_received, queue_min_confirmed);
|
||||
Log(" endpoint %d: connected = %d, last_received = %d, queue_min_confirmed = %d.\n", i, connected, last_received, queue_min_confirmed);
|
||||
Log(" endpoint %d: connected = %d, last_received = %d, queue_min_confirmed = %d.", i, connected, last_received, queue_min_confirmed);
|
||||
} else {
|
||||
Log(" endpoint %d: ignoring... not running.\n", i);
|
||||
Log(" endpoint %d: ignoring... not running.", i);
|
||||
}
|
||||
}
|
||||
// merge in our local status only if we're still connected!
|
||||
if (!_local_connect_status[queue].disconnected) {
|
||||
queue_min_confirmed = MIN(_local_connect_status[queue].last_frame, queue_min_confirmed);
|
||||
}
|
||||
Log(" local endp: connected = %d, last_received = %d, queue_min_confirmed = %d.\n", !_local_connect_status[queue].disconnected, _local_connect_status[queue].last_frame, queue_min_confirmed);
|
||||
Log(" local endp: connected = %d, last_received = %d, queue_min_confirmed = %d.", !_local_connect_status[queue].disconnected, _local_connect_status[queue].last_frame, queue_min_confirmed);
|
||||
|
||||
if (queue_connected) {
|
||||
total_min_confirmed = MIN(queue_min_confirmed, total_min_confirmed);
|
||||
@@ -236,11 +236,11 @@ int Peer2PeerBackend::PollNPlayers(int current_frame)
|
||||
// so, we need to re-adjust. This can happen when we detect our own disconnect at frame n
|
||||
// and later receive a disconnect notification for frame n-1.
|
||||
if (!_local_connect_status[queue].disconnected || _local_connect_status[queue].last_frame > queue_min_confirmed) {
|
||||
Log("disconnecting queue %d by remote request.\n", queue);
|
||||
Log("disconnecting queue %d by remote request.", queue);
|
||||
DisconnectPlayerQueue(queue, queue_min_confirmed);
|
||||
}
|
||||
}
|
||||
Log(" total_min_confirmed = %d.\n", total_min_confirmed);
|
||||
Log(" total_min_confirmed = %d.", total_min_confirmed);
|
||||
}
|
||||
return total_min_confirmed;
|
||||
}
|
||||
@@ -335,7 +335,7 @@ Peer2PeerBackend::SyncInput(void *values,
|
||||
GGPOErrorCode
|
||||
Peer2PeerBackend::IncrementFrame(void)
|
||||
{
|
||||
Log("End of frame (%d)...\n", _sync.GetFrameCount());
|
||||
Log("End of frame (%d)...", _sync.GetFrameCount());
|
||||
_sync.IncrementFrame();
|
||||
DoPoll(0);
|
||||
PollSyncEvents();
|
||||
@@ -383,7 +383,7 @@ Peer2PeerBackend::OnUdpProtocolPeerEvent(UdpProtocol::Event &evt, int queue)
|
||||
|
||||
_sync.AddRemoteInput(queue, evt.u.input.input);
|
||||
// Notify the other endpoints which frame we received from a peer
|
||||
Log("setting remote connect status for queue %d to %d\n", queue, evt.u.input.input.frame);
|
||||
Log("setting remote connect status for queue %d to %d", queue, evt.u.input.input.frame);
|
||||
_local_connect_status[queue].last_frame = evt.u.input.input.frame;
|
||||
}
|
||||
break;
|
||||
@@ -493,14 +493,14 @@ Peer2PeerBackend::DisconnectPlayer(GGPOPlayerHandle player)
|
||||
int current_frame = _sync.GetFrameCount();
|
||||
// xxx: we should be tracking who the local player is, but for now assume
|
||||
// that if the endpoint is not initalized, this must be the local player.
|
||||
Log("Disconnecting local player %d at frame %d by user request.\n", queue, _local_connect_status[queue].last_frame);
|
||||
Log("Disconnecting local player %d at frame %d by user request.", queue, _local_connect_status[queue].last_frame);
|
||||
for (int i = 0; i < _num_players; i++) {
|
||||
if (_endpoints[i].IsInitialized()) {
|
||||
DisconnectPlayerQueue(i, current_frame);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Log("Disconnecting queue %d at frame %d by user request.\n", queue, _local_connect_status[queue].last_frame);
|
||||
Log("Disconnecting queue %d at frame %d by user request.", queue, _local_connect_status[queue].last_frame);
|
||||
DisconnectPlayerQueue(queue, _local_connect_status[queue].last_frame);
|
||||
}
|
||||
return GGPO_OK;
|
||||
@@ -514,16 +514,16 @@ Peer2PeerBackend::DisconnectPlayerQueue(int queue, int syncto)
|
||||
|
||||
_endpoints[queue].Disconnect();
|
||||
|
||||
Log("Changing queue %d local connect status for last frame from %d to %d on disconnect request (current: %d).\n",
|
||||
Log("Changing queue %d local connect status for last frame from %d to %d on disconnect request (current: %d).",
|
||||
queue, _local_connect_status[queue].last_frame, syncto, framecount);
|
||||
|
||||
_local_connect_status[queue].disconnected = 1;
|
||||
_local_connect_status[queue].last_frame = syncto;
|
||||
|
||||
if (syncto != GameInput::NullFrame && syncto < framecount) {
|
||||
Log("adjusting simulation to account for the fact that %d disconnected @ %d.\n", queue, syncto);
|
||||
Log("adjusting simulation to account for the fact that %d disconnected @ %d.", queue, syncto);
|
||||
_sync.AdjustSimulation(syncto);
|
||||
Log("finished adjusting simulation.\n");
|
||||
Log("finished adjusting simulation.");
|
||||
}
|
||||
|
||||
info.code = GGPO_EVENTCODE_DISCONNECTED_FROM_PEER;
|
||||
|
||||
@@ -92,7 +92,7 @@ SpectatorBackend::SyncInput(void *values,
|
||||
GGPOErrorCode
|
||||
SpectatorBackend::IncrementFrame(void)
|
||||
{
|
||||
Log("End of frame (%d)...\n", _next_input_to_send - 1);
|
||||
Log("End of frame (%d)...", _next_input_to_send - 1);
|
||||
DoPoll(0);
|
||||
PollUdpProtocolEvents();
|
||||
|
||||
|
||||
@@ -83,7 +83,6 @@ SyncTestBackend::SyncInput(void *values,
|
||||
int size,
|
||||
int *disconnect_flags)
|
||||
{
|
||||
BeginLog(false);
|
||||
if (_rollingback) {
|
||||
_last_input = _saved_frames.front().input;
|
||||
} else {
|
||||
@@ -105,8 +104,7 @@ SyncTestBackend::IncrementFrame(void)
|
||||
_sync.IncrementFrame();
|
||||
_current_input.erase();
|
||||
|
||||
Log("End of frame(%d)...\n", _sync.GetFrameCount());
|
||||
EndLog();
|
||||
DEBUG_LOG(NETWORK, "End of frame(%d)...", _sync.GetFrameCount());
|
||||
|
||||
if (_rollingback) {
|
||||
return GGPO_OK;
|
||||
@@ -171,47 +169,9 @@ SyncTestBackend::RaiseSyncError(const char *fmt, ...)
|
||||
#ifdef _WIN32
|
||||
OutputDebugStringA(buf);
|
||||
#endif
|
||||
EndLog();
|
||||
// DebugBreak();
|
||||
}
|
||||
|
||||
GGPOErrorCode
|
||||
SyncTestBackend::Logv(char *fmt, va_list list)
|
||||
{
|
||||
if (_logfp) {
|
||||
vfprintf(_logfp, fmt, list);
|
||||
}
|
||||
return GGPO_OK;
|
||||
}
|
||||
|
||||
void
|
||||
SyncTestBackend::BeginLog(int saving)
|
||||
{
|
||||
EndLog();
|
||||
|
||||
char filename[MAX_PATH];
|
||||
#ifdef _WIN32
|
||||
CreateDirectoryA("synclogs", NULL);
|
||||
#else
|
||||
mkdir("synclogs", 0755);
|
||||
#endif
|
||||
snprintf(filename, ARRAY_SIZE(filename), "synclogs/%s-%04d-%s.log",
|
||||
saving ? "state" : "log",
|
||||
_sync.GetFrameCount(),
|
||||
_rollingback ? "replay" : "original");
|
||||
|
||||
_logfp = fopen(filename, "w");
|
||||
}
|
||||
|
||||
void
|
||||
SyncTestBackend::EndLog()
|
||||
{
|
||||
if (_logfp) {
|
||||
fprintf(_logfp, "Closing log file.\n");
|
||||
fclose(_logfp);
|
||||
_logfp = NULL;
|
||||
}
|
||||
}
|
||||
void
|
||||
SyncTestBackend::LogSaveStates(SavedInfo &info)
|
||||
{
|
||||
|
||||
@@ -24,7 +24,6 @@ public:
|
||||
virtual GGPOErrorCode AddLocalInput(GGPOPlayerHandle player, void *values, int size);
|
||||
virtual GGPOErrorCode SyncInput(void *values, int size, int *disconnect_flags);
|
||||
virtual GGPOErrorCode IncrementFrame(void);
|
||||
virtual GGPOErrorCode Logv(char *fmt, va_list list);
|
||||
|
||||
protected:
|
||||
struct SavedInfo {
|
||||
@@ -36,8 +35,6 @@ protected:
|
||||
};
|
||||
|
||||
void RaiseSyncError(const char *fmt, ...);
|
||||
void BeginLog(int saving);
|
||||
void EndLog();
|
||||
void LogSaveStates(SavedInfo &info);
|
||||
|
||||
protected:
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
#include "game_input.h"
|
||||
|
||||
#include "ggpo_types.h"
|
||||
#include "log.h"
|
||||
|
||||
void
|
||||
GameInput::init(int iframe, char *ibits, int isize, int offset)
|
||||
@@ -65,25 +64,23 @@ GameInput::log(char *prefix, bool show_frame) const
|
||||
size_t c = strlen(prefix);
|
||||
strcpy(buf, prefix);
|
||||
desc(buf + c, ARRAY_SIZE(buf) - c, show_frame);
|
||||
strcat(buf, "\n");
|
||||
Log(buf);
|
||||
Log("%s", buf);
|
||||
}
|
||||
|
||||
bool
|
||||
GameInput::equal(GameInput &other, bool bitsonly)
|
||||
{
|
||||
if (!bitsonly && frame != other.frame) {
|
||||
Log("frames don't match: %d, %d\n", frame, other.frame);
|
||||
Log("frames don't match: %d, %d", frame, other.frame);
|
||||
}
|
||||
if (size != other.size) {
|
||||
Log("sizes don't match: %d, %d\n", size, other.size);
|
||||
}
|
||||
if (memcmp(bits, other.bits, size)) {
|
||||
Log("bits don't match\n");
|
||||
Log("sizes don't match: %d, %d", size, other.size);
|
||||
}
|
||||
bool match = memcmp(bits, other.bits, size) == 0;
|
||||
if (!match)
|
||||
Log("bits don't match");
|
||||
ASSERT(size && other.size);
|
||||
return (bitsonly || frame == other.frame) &&
|
||||
size == other.size &&
|
||||
memcmp(bits, other.bits, size) == 0;
|
||||
size == other.size && match;
|
||||
}
|
||||
|
||||
@@ -40,6 +40,7 @@ typedef short int16;
|
||||
typedef int int32;
|
||||
|
||||
#include "ggponet.h"
|
||||
#include "log/Log.h"
|
||||
#include <stdexcept>
|
||||
|
||||
class GGPOException : public std::runtime_error {
|
||||
@@ -61,8 +62,6 @@ public:
|
||||
# error Unsupported platform
|
||||
#endif
|
||||
|
||||
#include "log.h"
|
||||
|
||||
/*
|
||||
* Macros
|
||||
*/
|
||||
@@ -70,16 +69,14 @@ public:
|
||||
do { \
|
||||
if (!(x)) { \
|
||||
char assert_buf[1024]; \
|
||||
snprintf(assert_buf, sizeof(assert_buf) - 1, "Assertion: %s @ %s:%d (pid:%ld)", #x, __FILE__, __LINE__, (long)GGPOPlatform::GetProcessID()); \
|
||||
Log("%s\n", assert_buf); \
|
||||
Log("\n"); \
|
||||
Log("\n"); \
|
||||
Log("\n"); \
|
||||
GGPOPlatform::AssertFailed(assert_buf); \
|
||||
exit(0); \
|
||||
snprintf(assert_buf, sizeof(assert_buf) - 1, "Assertion: %s @ %s:%d", #x, __FILE__, __LINE__); \
|
||||
GGPOPlatform::AssertFailed(assert_buf); \
|
||||
throw GGPOException(assert_buf, GGPO_ERRORCODE_GENERAL_FAILURE); \
|
||||
} \
|
||||
} while (false)
|
||||
|
||||
#define Log(...) DEBUG_LOG(NETWORK, __VA_ARGS__)
|
||||
|
||||
#ifndef ARRAY_SIZE
|
||||
# define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
|
||||
#endif
|
||||
|
||||
@@ -48,7 +48,7 @@ InputQueue::Init(int id, int input_size)
|
||||
int
|
||||
InputQueue::GetLastConfirmedFrame()
|
||||
{
|
||||
Log("returning last confirmed frame %d.\n", _last_added_frame);
|
||||
Log("input q%d | returning last confirmed frame %d.", _id, _last_added_frame);
|
||||
return _last_added_frame;
|
||||
}
|
||||
|
||||
@@ -67,21 +67,21 @@ InputQueue::DiscardConfirmedFrames(int frame)
|
||||
frame = MIN(frame, _last_frame_requested);
|
||||
}
|
||||
|
||||
Log("discarding confirmed frames up to %d (last_added:%d length:%d [head:%d tail:%d]).\n",
|
||||
Log("input q%d | discarding confirmed frames up to %d (last_added:%d length:%d [head:%d tail:%d]).", _id,
|
||||
frame, _last_added_frame, _length, _head, _tail);
|
||||
if (frame >= _last_added_frame) {
|
||||
_tail = _head;
|
||||
} else {
|
||||
int offset = frame - _inputs[_tail].frame + 1;
|
||||
|
||||
Log("difference of %d frames.\n", offset);
|
||||
Log("input q%d | difference of %d frames.", _id, offset);
|
||||
ASSERT(offset >= 0);
|
||||
|
||||
_tail = (_tail + offset) % INPUT_QUEUE_LENGTH;
|
||||
_length -= offset;
|
||||
}
|
||||
|
||||
Log("after discarding, new tail is %d (frame:%d).\n", _tail, _inputs[_tail].frame);
|
||||
Log("input q%d | after discarding, new tail is %d (frame:%d).", _id, _tail, _inputs[_tail].frame);
|
||||
ASSERT(_length >= 0);
|
||||
}
|
||||
|
||||
@@ -90,7 +90,7 @@ InputQueue::ResetPrediction(int frame)
|
||||
{
|
||||
ASSERT(_first_incorrect_frame == GameInput::NullFrame || frame <= _first_incorrect_frame);
|
||||
|
||||
Log("resetting all prediction errors back to frame %d.\n", frame);
|
||||
Log("input q%d | resetting all prediction errors back to frame %d.", _id, frame);
|
||||
|
||||
/*
|
||||
* There's nothing really to do other than reset our prediction
|
||||
@@ -116,7 +116,7 @@ InputQueue::GetConfirmedInput(int requested_frame, GameInput *input)
|
||||
bool
|
||||
InputQueue::GetInput(int requested_frame, GameInput *input)
|
||||
{
|
||||
Log("requesting input frame %d.\n", requested_frame);
|
||||
Log("input q%d | requesting input frame %d.", _id, requested_frame);
|
||||
|
||||
/*
|
||||
* No one should ever try to grab any input when we have a prediction
|
||||
@@ -144,7 +144,7 @@ InputQueue::GetInput(int requested_frame, GameInput *input)
|
||||
offset = (offset + _tail) % INPUT_QUEUE_LENGTH;
|
||||
ASSERT(_inputs[offset].frame == requested_frame);
|
||||
*input = _inputs[offset];
|
||||
Log("returning confirmed frame number %d.\n", input->frame);
|
||||
Log("input q%d | returning confirmed frame number %d.", _id, input->frame);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -154,13 +154,13 @@ InputQueue::GetInput(int requested_frame, GameInput *input)
|
||||
* same thing they did last time.
|
||||
*/
|
||||
if (requested_frame == 0) {
|
||||
Log("basing new prediction frame from nothing, you're client wants frame 0.\n");
|
||||
Log("input q%d | basing new prediction frame from nothing, you're client wants frame 0.", _id);
|
||||
_prediction.erase();
|
||||
} else if (_last_added_frame == GameInput::NullFrame) {
|
||||
Log("basing new prediction frame from nothing, since we have no frames yet.\n");
|
||||
Log("input q%d | basing new prediction frame from nothing, since we have no frames yet.", _id);
|
||||
_prediction.erase();
|
||||
} else {
|
||||
Log("basing new prediction frame from previously added frame (queue entry:%d, frame:%d).\n",
|
||||
Log("input q%d | basing new prediction frame from previously added frame (queue entry:%d, frame:%d).", _id,
|
||||
PREVIOUS_FRAME(_head), _inputs[PREVIOUS_FRAME(_head)].frame);
|
||||
_prediction = _inputs[PREVIOUS_FRAME(_head)];
|
||||
}
|
||||
@@ -176,7 +176,7 @@ InputQueue::GetInput(int requested_frame, GameInput *input)
|
||||
*/
|
||||
*input = _prediction;
|
||||
input->frame = requested_frame;
|
||||
Log("returning prediction frame number %d (%d).\n", input->frame, _prediction.frame);
|
||||
Log("input q%d | returning prediction frame number %d (%d).", _id, input->frame, _prediction.frame);
|
||||
|
||||
return false;
|
||||
}
|
||||
@@ -186,7 +186,7 @@ InputQueue::AddInput(GameInput &input)
|
||||
{
|
||||
int new_frame;
|
||||
|
||||
Log("adding input frame number %d to queue.\n", input.frame);
|
||||
Log("input q%d | adding input frame number %d to queue.", _id, input.frame);
|
||||
|
||||
/*
|
||||
* These next two lines simply verify that inputs are passed in
|
||||
@@ -216,7 +216,7 @@ InputQueue::AddInput(GameInput &input)
|
||||
void
|
||||
InputQueue::AddDelayedInputToQueue(GameInput &input, int frame_number)
|
||||
{
|
||||
Log("adding delayed input frame number %d to queue.\n", frame_number);
|
||||
Log("input q%d | adding delayed input frame number %d to queue.", _id, frame_number);
|
||||
|
||||
if (input.size != _prediction.size)
|
||||
throw GGPOException("Input size differs from peer", GGPO_ERRORCODE_INPUT_SIZE_DIFF);
|
||||
@@ -246,7 +246,7 @@ InputQueue::AddDelayedInputToQueue(GameInput &input, int frame_number)
|
||||
* in GetFirstIncorrectFrame()
|
||||
*/
|
||||
if (_first_incorrect_frame == GameInput::NullFrame && !_prediction.equal(input, true)) {
|
||||
Log("frame %d does not match prediction. marking error.\n", frame_number);
|
||||
Log("input q%d | frame %d does not match prediction. marking error.", _id, frame_number);
|
||||
_first_incorrect_frame = frame_number;
|
||||
}
|
||||
|
||||
@@ -257,7 +257,7 @@ InputQueue::AddDelayedInputToQueue(GameInput &input, int frame_number)
|
||||
* count up.
|
||||
*/
|
||||
if (_prediction.frame == _last_frame_requested && _first_incorrect_frame == GameInput::NullFrame) {
|
||||
Log("prediction is correct! dumping out of prediction mode.\n");
|
||||
Log("input q%d | prediction is correct! dumping out of prediction mode.", _id);
|
||||
_prediction.frame = GameInput::NullFrame;
|
||||
} else {
|
||||
_prediction.frame++;
|
||||
@@ -269,7 +269,7 @@ InputQueue::AddDelayedInputToQueue(GameInput &input, int frame_number)
|
||||
int
|
||||
InputQueue::AdvanceQueueHead(int frame)
|
||||
{
|
||||
Log("advancing queue head to frame %d.\n", frame);
|
||||
Log("input q%d | advancing queue head to frame %d.", _id, frame);
|
||||
|
||||
int expected_frame = _first_frame ? 0 : _inputs[PREVIOUS_FRAME(_head)].frame + 1;
|
||||
|
||||
@@ -281,7 +281,7 @@ InputQueue::AdvanceQueueHead(int frame)
|
||||
* time we shoved a frame into the system. In this case, there's
|
||||
* no room on the queue. Toss it.
|
||||
*/
|
||||
Log("Dropping input frame %d (expected next frame to be %d).\n",
|
||||
Log("input q%d | Dropping input frame %d (expected next frame to be %d).", _id,
|
||||
frame, expected_frame);
|
||||
return GameInput::NullFrame;
|
||||
}
|
||||
@@ -293,7 +293,7 @@ InputQueue::AdvanceQueueHead(int frame)
|
||||
* last frame in the queue several times in order to fill the space
|
||||
* left.
|
||||
*/
|
||||
Log("Adding padding frame %d to account for change in frame delay.\n",
|
||||
Log("input q%d | Adding padding frame %d to account for change in frame delay.", _id,
|
||||
expected_frame);
|
||||
GameInput &last_frame = _inputs[PREVIOUS_FRAME(_head)];
|
||||
AddDelayedInputToQueue(last_frame, expected_frame);
|
||||
@@ -303,19 +303,3 @@ InputQueue::AdvanceQueueHead(int frame)
|
||||
ASSERT(frame == 0 || frame == _inputs[PREVIOUS_FRAME(_head)].frame + 1);
|
||||
return frame;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
InputQueue::Log(const char *fmt, ...)
|
||||
{
|
||||
char buf[1024];
|
||||
size_t offset;
|
||||
va_list args;
|
||||
|
||||
offset = snprintf(buf, ARRAY_SIZE(buf), "input q%d | ", _id);
|
||||
va_start(args, fmt);
|
||||
vsnprintf(buf + offset, ARRAY_SIZE(buf) - offset - 1, fmt, args);
|
||||
buf[ARRAY_SIZE(buf)-1] = '\0';
|
||||
::Log(buf);
|
||||
va_end(args);
|
||||
}
|
||||
@@ -34,7 +34,6 @@ public:
|
||||
protected:
|
||||
int AdvanceQueueHead(int frame);
|
||||
void AddDelayedInputToQueue(GameInput &input, int i);
|
||||
void Log(const char *fmt, ...);
|
||||
|
||||
protected:
|
||||
int _id;
|
||||
|
||||
@@ -1,31 +0,0 @@
|
||||
/* -----------------------------------------------------------------------
|
||||
* GGPO.net (http://ggpo.net) - Copyright 2009 GroundStorm Studios, LLC.
|
||||
*
|
||||
* Use of this software is governed by the MIT license that can be found
|
||||
* in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include "ggpo_types.h"
|
||||
#include "log/Log.h"
|
||||
#include "log/LogManager.h"
|
||||
#include <string>
|
||||
|
||||
void Log(const char *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
Logv(fmt, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
void Logv(const char* fmt, va_list args)
|
||||
{
|
||||
std::string copy;
|
||||
if (fmt[strlen(fmt) - 1] == '\n') {
|
||||
copy = fmt;
|
||||
copy.pop_back();
|
||||
fmt = copy.c_str();
|
||||
}
|
||||
if (LogManager::GetInstance())
|
||||
LogManager::GetInstance()->Log(LogTypes::LDEBUG, LogTypes::NETWORK, __FILE__, __LINE__, fmt, args);
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
/* -----------------------------------------------------------------------
|
||||
* GGPO.net (http://ggpo.net) - Copyright 2009 GroundStorm Studios, LLC.
|
||||
*
|
||||
* Use of this software is governed by the MIT license that can be found
|
||||
* in the LICENSE file.
|
||||
*/
|
||||
|
||||
#ifndef _LOG_H
|
||||
#define _LOG_H
|
||||
|
||||
extern void Log(const char *fmt, ...);
|
||||
extern void Logv(const char *fmt, va_list list);
|
||||
|
||||
#endif
|
||||
@@ -23,22 +23,6 @@ struct Init
|
||||
};
|
||||
static Init init;
|
||||
|
||||
void
|
||||
ggpo_log(GGPOSession *ggpo, const char *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
ggpo_logv(ggpo, fmt, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
void
|
||||
ggpo_logv(GGPOSession *ggpo, const char *fmt, va_list args)
|
||||
{
|
||||
if (ggpo)
|
||||
ggpo->Logv(fmt, args);
|
||||
}
|
||||
|
||||
GGPOErrorCode
|
||||
ggpo_start_session(GGPOSession **session,
|
||||
GGPOSessionCallbacks *cb,
|
||||
@@ -59,7 +43,7 @@ ggpo_start_session(GGPOSession **session,
|
||||
verification_size);
|
||||
return GGPO_OK;
|
||||
} catch (const GGPOException& e) {
|
||||
Log("GGPOException in ggpo_start_session: %s", e.what());
|
||||
ERROR_LOG(NETWORK, "GGPOException in ggpo_start_session: %s", e.what());
|
||||
return e.ggpoError;
|
||||
}
|
||||
}
|
||||
@@ -74,7 +58,7 @@ ggpo_add_player(GGPOSession *ggpo,
|
||||
try {
|
||||
return ggpo->AddPlayer(player, handle);
|
||||
} catch (const GGPOException& e) {
|
||||
Log("GGPOException in ggpo_add_player: %s", e.what());
|
||||
ERROR_LOG(NETWORK, "GGPOException in ggpo_add_player: %s", e.what());
|
||||
return e.ggpoError;
|
||||
}
|
||||
}
|
||||
@@ -93,7 +77,7 @@ ggpo_start_synctest(GGPOSession **ggpo,
|
||||
*ggpo = (GGPOSession *)new SyncTestBackend(cb, game, frames, num_players);
|
||||
return GGPO_OK;
|
||||
} catch (const GGPOException& e) {
|
||||
Log("GGPOException in ggpo_start_synctest: %s", e.what());
|
||||
ERROR_LOG(NETWORK, "GGPOException in ggpo_start_synctest: %s", e.what());
|
||||
return e.ggpoError;
|
||||
}
|
||||
}
|
||||
@@ -108,7 +92,7 @@ ggpo_set_frame_delay(GGPOSession *ggpo,
|
||||
try {
|
||||
return ggpo->SetFrameDelay(player, frame_delay);
|
||||
} catch (const GGPOException& e) {
|
||||
Log("GGPOException in ggpo_set_frame_delay: %s", e.what());
|
||||
ERROR_LOG(NETWORK, "GGPOException in ggpo_set_frame_delay: %s", e.what());
|
||||
return e.ggpoError;
|
||||
}
|
||||
}
|
||||
@@ -121,7 +105,7 @@ ggpo_idle(GGPOSession *ggpo, int timeout)
|
||||
try {
|
||||
return ggpo->DoPoll(timeout);
|
||||
} catch (const GGPOException& e) {
|
||||
Log("GGPOException in ggpo_idle: %s", e.what());
|
||||
ERROR_LOG(NETWORK, "GGPOException in ggpo_idle: %s", e.what());
|
||||
return e.ggpoError;
|
||||
}
|
||||
}
|
||||
@@ -137,7 +121,7 @@ ggpo_add_local_input(GGPOSession *ggpo,
|
||||
try {
|
||||
return ggpo->AddLocalInput(player, values, size);
|
||||
} catch (const GGPOException& e) {
|
||||
Log("GGPOException in ggpo_add_local_input: %s", e.what());
|
||||
ERROR_LOG(NETWORK, "GGPOException in ggpo_add_local_input: %s", e.what());
|
||||
return e.ggpoError;
|
||||
}
|
||||
}
|
||||
@@ -153,7 +137,7 @@ ggpo_synchronize_input(GGPOSession *ggpo,
|
||||
try {
|
||||
return ggpo->SyncInput(values, size, disconnect_flags);
|
||||
} catch (const GGPOException& e) {
|
||||
Log("GGPOException in ggpo_synchronize_input: %s", e.what());
|
||||
ERROR_LOG(NETWORK, "GGPOException in ggpo_synchronize_input: %s", e.what());
|
||||
return e.ggpoError;
|
||||
}
|
||||
}
|
||||
@@ -166,7 +150,7 @@ GGPOErrorCode ggpo_disconnect_player(GGPOSession *ggpo,
|
||||
try {
|
||||
return ggpo->DisconnectPlayer(player);
|
||||
} catch (const GGPOException& e) {
|
||||
Log("GGPOException in ggpo_disconnect_player: %s", e.what());
|
||||
ERROR_LOG(NETWORK, "GGPOException in ggpo_disconnect_player: %s", e.what());
|
||||
return e.ggpoError;
|
||||
}
|
||||
}
|
||||
@@ -179,7 +163,7 @@ ggpo_advance_frame(GGPOSession *ggpo)
|
||||
try {
|
||||
return ggpo->IncrementFrame();
|
||||
} catch (const GGPOException& e) {
|
||||
Log("GGPOException in ggpo_advance_frame: %s", e.what());
|
||||
ERROR_LOG(NETWORK, "GGPOException in ggpo_advance_frame: %s", e.what());
|
||||
return e.ggpoError;
|
||||
}
|
||||
}
|
||||
@@ -194,7 +178,7 @@ ggpo_get_network_stats(GGPOSession *ggpo,
|
||||
try {
|
||||
return ggpo->GetNetworkStats(stats, player);
|
||||
} catch (const GGPOException& e) {
|
||||
Log("GGPOException in ggpo_get_network_stats: %s", e.what());
|
||||
ERROR_LOG(NETWORK, "GGPOException in ggpo_get_network_stats: %s", e.what());
|
||||
return e.ggpoError;
|
||||
}
|
||||
}
|
||||
@@ -218,7 +202,7 @@ ggpo_set_disconnect_timeout(GGPOSession *ggpo, int timeout)
|
||||
try {
|
||||
return ggpo->SetDisconnectTimeout(timeout);
|
||||
} catch (const GGPOException& e) {
|
||||
Log("GGPOException in ggpo_set_disconnect_timeout: %s", e.what());
|
||||
ERROR_LOG(NETWORK, "GGPOException in ggpo_set_disconnect_timeout: %s", e.what());
|
||||
return e.ggpoError;
|
||||
}
|
||||
}
|
||||
@@ -231,7 +215,7 @@ ggpo_set_disconnect_notify_start(GGPOSession *ggpo, int timeout)
|
||||
try {
|
||||
return ggpo->SetDisconnectNotifyStart(timeout);
|
||||
} catch (const GGPOException& e) {
|
||||
Log("GGPOException in ggpo_set_disconnect_notify_start: %s", e.what());
|
||||
ERROR_LOG(NETWORK, "GGPOException in ggpo_set_disconnect_notify_start: %s", e.what());
|
||||
return e.ggpoError;
|
||||
}
|
||||
}
|
||||
@@ -259,7 +243,7 @@ GGPOErrorCode ggpo_start_spectating(GGPOSession **session,
|
||||
verification_size);
|
||||
return GGPO_OK;
|
||||
} catch (const GGPOException& e) {
|
||||
Log("GGPOException in ggpo_start_spectating: %s", e.what());
|
||||
ERROR_LOG(NETWORK, "GGPOException in ggpo_start_spectating: %s", e.what());
|
||||
return e.ggpoError;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,7 +34,7 @@ CreateSocket(uint16 bind_port, int retries)
|
||||
for (port = bind_port; port <= bind_port + retries; port++) {
|
||||
sin.sin_port = htons(port);
|
||||
if (bind(s, (sockaddr *)&sin, sizeof sin) == 0) {
|
||||
Log("Udp bound to port: %d.\n", port);
|
||||
Log("Udp bound to port: %d.", port);
|
||||
return s;
|
||||
}
|
||||
}
|
||||
@@ -62,7 +62,7 @@ Udp::Init(uint16 port, Poll *poll, Callbacks *callbacks)
|
||||
_callbacks = callbacks;
|
||||
poll->RegisterLoop(this);
|
||||
|
||||
Log("binding udp socket to port %d.\n", port);
|
||||
Log("binding udp socket to port %d.", port);
|
||||
_socket = CreateSocket(port, 0);
|
||||
if (_socket == INVALID_SOCKET)
|
||||
throw GGPOException("Socket creation or bind failed", GGPO_ERRORCODE_NETWORK_ERROR);
|
||||
@@ -76,11 +76,11 @@ Udp::SendTo(char *buffer, int len, int flags, struct sockaddr *dst, int destlen)
|
||||
int res = sendto(_socket, buffer, len, flags, dst, destlen);
|
||||
if (res == SOCKET_ERROR) {
|
||||
int err = WSAGetLastError();
|
||||
Log("unknown error in sendto (erro: %d wsaerr: %d).\n", res, err);
|
||||
Log("unknown error in sendto (erro: %d wsaerr: %d).", res, err);
|
||||
ASSERT(false && "Unknown error in sendto");
|
||||
}
|
||||
char dst_ip[1024];
|
||||
Log("sent packet length %d to %s:%d (ret:%d).\n", len, inet_ntop(AF_INET, (void *)&to->sin_addr, dst_ip, ARRAY_SIZE(dst_ip)), ntohs(to->sin_port), res);
|
||||
Log("sent packet length %d to %s:%d (ret:%d).", len, inet_ntop(AF_INET, (void *)&to->sin_addr, dst_ip, ARRAY_SIZE(dst_ip)), ntohs(to->sin_port), res);
|
||||
}
|
||||
|
||||
bool
|
||||
@@ -99,32 +99,15 @@ Udp::OnLoopPoll(void *cookie)
|
||||
if (len == -1) {
|
||||
int error = WSAGetLastError();
|
||||
if (error != WSAEWOULDBLOCK) {
|
||||
Log("recvfrom WSAGetLastError returned %d (%x).\n", error, error);
|
||||
Log("recvfrom WSAGetLastError returned %d (%x).", error, error);
|
||||
}
|
||||
break;
|
||||
} else if (len > 0) {
|
||||
char src_ip[1024];
|
||||
Log("recvfrom returned (len:%d from:%s:%d).\n", len, inet_ntop(AF_INET, (void*)&recv_addr.sin_addr, src_ip, ARRAY_SIZE(src_ip)), ntohs(recv_addr.sin_port) );
|
||||
Log("recvfrom returned (len:%d from:%s:%d).", len, inet_ntop(AF_INET, (void*)&recv_addr.sin_addr, src_ip, ARRAY_SIZE(src_ip)), ntohs(recv_addr.sin_port) );
|
||||
UdpMsg *msg = (UdpMsg *)recv_buf;
|
||||
_callbacks->OnMsg(recv_addr, msg, len);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Udp::Log(const char *fmt, ...)
|
||||
{
|
||||
char buf[1024];
|
||||
size_t offset;
|
||||
va_list args;
|
||||
|
||||
strcpy(buf, "udp | ");
|
||||
offset = strlen(buf);
|
||||
va_start(args, fmt);
|
||||
vsnprintf(buf + offset, ARRAY_SIZE(buf) - offset - 1, fmt, args);
|
||||
buf[ARRAY_SIZE(buf)-1] = '\0';
|
||||
::Log(buf);
|
||||
va_end(args);
|
||||
}
|
||||
@@ -31,11 +31,6 @@ public:
|
||||
virtual void OnMsg(sockaddr_in &from, UdpMsg *msg, int len) = 0;
|
||||
};
|
||||
|
||||
|
||||
protected:
|
||||
void Log(const char *fmt, ...);
|
||||
|
||||
public:
|
||||
Udp();
|
||||
|
||||
void Init(uint16 port, Poll *p, Callbacks *callbacks);
|
||||
|
||||
@@ -197,7 +197,7 @@ UdpProtocol::OnLoopPoll(void *cookie)
|
||||
case Syncing:
|
||||
next_interval = (_state.sync.roundtrips_remaining == NUM_SYNC_PACKETS) ? SYNC_FIRST_RETRY_INTERVAL : SYNC_RETRY_INTERVAL;
|
||||
if (_last_send_time && _last_send_time + next_interval < now && _peer_addr.sin_addr.s_addr != 0) {
|
||||
Log("No luck syncing after %d ms... Re-queueing sync packet.\n", next_interval);
|
||||
Log("udpproto%d | No luck syncing after %d ms... Re-queueing sync packet.", _queue, next_interval);
|
||||
SendSyncRequest();
|
||||
}
|
||||
break;
|
||||
@@ -205,7 +205,7 @@ UdpProtocol::OnLoopPoll(void *cookie)
|
||||
case Running:
|
||||
// xxx: rig all this up with a timer wrapper
|
||||
if (!_state.running.last_input_packet_recv_time || _state.running.last_input_packet_recv_time + RUNNING_RETRY_INTERVAL < now) {
|
||||
Log("Haven't exchanged packets in a while (last received:%d last sent:%d). Resending.\n", _last_received_input.frame, _last_sent_input.frame);
|
||||
Log("udpproto%d | Haven't exchanged packets in a while (last received:%d last sent:%d). Resending.", _queue, _last_received_input.frame, _last_sent_input.frame);
|
||||
SendPendingOutput();
|
||||
_state.running.last_input_packet_recv_time = now;
|
||||
}
|
||||
@@ -224,13 +224,13 @@ UdpProtocol::OnLoopPoll(void *cookie)
|
||||
}
|
||||
|
||||
if (_last_send_time && _last_send_time + KEEP_ALIVE_INTERVAL < now) {
|
||||
Log("Sending keep alive packet\n");
|
||||
Log("udpproto%d | Sending keep alive packet", _queue);
|
||||
SendMsg(new UdpMsg(UdpMsg::KeepAlive));
|
||||
}
|
||||
|
||||
if (_disconnect_timeout && _disconnect_notify_start &&
|
||||
!_disconnect_notify_sent && (_last_recv_time + _disconnect_notify_start < now)) {
|
||||
Log("Endpoint has stopped receiving packets for %d ms. Sending notification.\n", _disconnect_notify_start);
|
||||
Log("udpproto%d | Endpoint has stopped receiving packets for %d ms. Sending notification.", _queue, _disconnect_notify_start);
|
||||
Event e(Event::NetworkInterrupted);
|
||||
e.u.network_interrupted.disconnect_timeout = _disconnect_timeout - _disconnect_notify_start;
|
||||
QueueEvent(e);
|
||||
@@ -239,7 +239,7 @@ UdpProtocol::OnLoopPoll(void *cookie)
|
||||
|
||||
if (_disconnect_timeout && (_last_recv_time + _disconnect_timeout < now)) {
|
||||
if (!_disconnect_event_sent) {
|
||||
Log("Endpoint has stopped receiving packets for %d ms. Disconnecting.\n", _disconnect_timeout);
|
||||
Log("udpproto%d | Endpoint has stopped receiving packets for %d ms. Disconnecting.", _queue, _disconnect_timeout);
|
||||
QueueEvent(Event(Event::Disconnected));
|
||||
_disconnect_event_sent = true;
|
||||
}
|
||||
@@ -248,7 +248,7 @@ UdpProtocol::OnLoopPoll(void *cookie)
|
||||
|
||||
case Disconnected:
|
||||
if (_shutdown_timeout < now) {
|
||||
Log("Shutting down udp connection.\n");
|
||||
Log("udpproto%d | Shutting down udp connection.", _queue);
|
||||
_udp = NULL;
|
||||
_shutdown_timeout = 0;
|
||||
}
|
||||
@@ -345,9 +345,9 @@ UdpProtocol::OnMsg(UdpMsg *msg, int len)
|
||||
|
||||
// filter out out-of-order packets
|
||||
uint16 skipped = (uint16)((int)seq - (int)_next_recv_seq);
|
||||
// Log("checking sequence number -> next - seq : %d - %d = %d\n", seq, _next_recv_seq, skipped);
|
||||
// Log("udpproto%d | checking sequence number -> next - seq : %d - %d = %d", _queue, seq, _next_recv_seq, skipped);
|
||||
if (skipped > MAX_SEQ_DISTANCE) {
|
||||
Log("dropping out of order packet (seq: %d, last seq:%d)\n", seq, _next_recv_seq);
|
||||
Log("udpproto%d | dropping out of order packet (seq: %d, last seq:%d)", _queue, seq, _next_recv_seq);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -384,9 +384,9 @@ UdpProtocol::UpdateNetworkStats(void)
|
||||
|
||||
_kbps_sent = int(Bps / 1024);
|
||||
|
||||
Log("Network Stats -- Bandwidth: %.2f KBps Packets Sent: %5d (%.2f pps) "
|
||||
"KB Sent: %.2f UDP Overhead: %.2f %%.\n",
|
||||
_kbps_sent,
|
||||
Log("udpproto%d | Network Stats -- Bandwidth: %.2f KBps Packets Sent: %5d (%.2f pps) "
|
||||
"KB Sent: %.2f UDP Overhead: %.2f %%.", _queue,
|
||||
(float)_kbps_sent,
|
||||
_packets_sent,
|
||||
(float)_packets_sent * 1000 / (now - _stats_start_time),
|
||||
total_bytes_sent / 1024.0,
|
||||
@@ -419,51 +419,35 @@ UdpProtocol::GetPeerConnectStatus(int id, int *frame)
|
||||
return !_peer_connect_status[id].disconnected;
|
||||
}
|
||||
|
||||
void
|
||||
UdpProtocol::Log(const char *fmt, ...)
|
||||
{
|
||||
char buf[1024];
|
||||
size_t offset;
|
||||
va_list args;
|
||||
|
||||
snprintf(buf, ARRAY_SIZE(buf), "udpproto%d | ", _queue);
|
||||
offset = strlen(buf);
|
||||
va_start(args, fmt);
|
||||
vsnprintf(buf + offset, ARRAY_SIZE(buf) - offset - 1, fmt, args);
|
||||
buf[ARRAY_SIZE(buf)-1] = '\0';
|
||||
::Log(buf);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
void
|
||||
UdpProtocol::LogMsg(const char *prefix, UdpMsg *msg)
|
||||
{
|
||||
switch (msg->hdr.type) {
|
||||
case UdpMsg::SyncRequest:
|
||||
Log("%s sync-request (%d).\n", prefix,
|
||||
Log("udpproto%d | %s sync-request (%d).", _queue, prefix,
|
||||
msg->u.sync_request.random_request);
|
||||
break;
|
||||
case UdpMsg::SyncReply:
|
||||
Log("%s sync-reply (%d).\n", prefix,
|
||||
Log("udpproto%d | %s sync-reply (%d).", _queue, prefix,
|
||||
msg->u.sync_reply.random_reply);
|
||||
break;
|
||||
case UdpMsg::QualityReport:
|
||||
Log("%s quality report.\n", prefix);
|
||||
Log("udpproto%d | %s quality report.", _queue, prefix);
|
||||
break;
|
||||
case UdpMsg::QualityReply:
|
||||
Log("%s quality reply.\n", prefix);
|
||||
Log("udpproto%d | %s quality reply.", _queue, prefix);
|
||||
break;
|
||||
case UdpMsg::KeepAlive:
|
||||
Log("%s keep alive.\n", prefix);
|
||||
Log("udpproto%d | %s keep alive.", _queue, prefix);
|
||||
break;
|
||||
case UdpMsg::Input:
|
||||
Log("%s game-compressed-input %d (+ %d bits).\n", prefix, msg->u.input.start_frame, msg->u.input.num_bits);
|
||||
Log("udpproto%d | %s game-compressed-input %d (+ %d bits).", _queue, prefix, msg->u.input.start_frame, msg->u.input.num_bits);
|
||||
break;
|
||||
case UdpMsg::InputAck:
|
||||
Log("%s input ack.\n", prefix);
|
||||
Log("udpproto%d | %s input ack.", _queue, prefix);
|
||||
break;
|
||||
case UdpMsg::AppData:
|
||||
Log("%s app data (%d bytes).\n", prefix, msg->u.app_data.size);
|
||||
Log("udpproto%d | %s app data (%d bytes).", _queue, prefix, msg->u.app_data.size);
|
||||
break;
|
||||
default:
|
||||
ASSERT(false && "Unknown UdpMsg type.");
|
||||
@@ -474,7 +458,7 @@ void
|
||||
UdpProtocol::LogEvent(const char *prefix, const UdpProtocol::Event &evt)
|
||||
{
|
||||
if (evt.type == UdpProtocol::Event::Synchronzied)
|
||||
Log("%s (event: Synchronzied).\n", prefix);
|
||||
Log("udpproto%d | %s (event: Synchronized).", _queue, prefix);
|
||||
}
|
||||
|
||||
bool
|
||||
@@ -488,7 +472,7 @@ bool
|
||||
UdpProtocol::OnSyncRequest(UdpMsg *msg, int len)
|
||||
{
|
||||
if (_remote_magic_number != 0 && msg->hdr.magic != _remote_magic_number) {
|
||||
Log("Ignoring sync request from unknown endpoint (%d != %d).\n",
|
||||
Log("udpproto%d | Ignoring sync request from unknown endpoint (%d != %d).", _queue,
|
||||
msg->hdr.magic, _remote_magic_number);
|
||||
return false;
|
||||
}
|
||||
@@ -500,14 +484,14 @@ UdpProtocol::OnSyncRequest(UdpMsg *msg, int len)
|
||||
if (msgVerifSize != (int)verification.size()
|
||||
|| (msgVerifSize != 0 && memcmp(&msg->u.sync_request.verification[0], &verification[0], msgVerifSize)))
|
||||
{
|
||||
Log("Verification mismatch: size received %d expected %d", msgVerifSize, (int)verification.size());
|
||||
Log("udpproto%d | Verification mismatch: size received %d expected %d", _queue, msgVerifSize, (int)verification.size());
|
||||
reply->u.sync_reply.verification_failure = 1;
|
||||
SendMsg(reply);
|
||||
throw GGPOException("Verification mismatch", GGPO_ERRORCODE_VERIFICATION_ERROR);
|
||||
}
|
||||
// FIXME
|
||||
if (_state.sync.roundtrips_remaining == NUM_SYNC_PACKETS && msg->hdr.sequence_number == 0) {
|
||||
Log("Sync request 0 received... Re-queueing sync packet.\n");
|
||||
Log("udpproto%d | Sync request 0 received... Re-queueing sync packet.", _queue);
|
||||
SendSyncRequest();
|
||||
}
|
||||
|
||||
@@ -521,12 +505,12 @@ bool
|
||||
UdpProtocol::OnSyncReply(UdpMsg *msg, int len)
|
||||
{
|
||||
if (_current_state != Syncing) {
|
||||
Log("Ignoring SyncReply while not synching.\n");
|
||||
Log("udpproto%d | Ignoring SyncReply while not synching.", _queue);
|
||||
return msg->hdr.magic == _remote_magic_number;
|
||||
}
|
||||
|
||||
if (msg->u.sync_reply.random_reply != _state.sync.random) {
|
||||
Log("sync reply %d != %d. Keep looking...\n",
|
||||
Log("udpproto%d | sync reply %d != %d. Keep looking...", _queue,
|
||||
msg->u.sync_reply.random_reply, _state.sync.random);
|
||||
return false;
|
||||
}
|
||||
@@ -538,9 +522,9 @@ UdpProtocol::OnSyncReply(UdpMsg *msg, int len)
|
||||
_connected = true;
|
||||
}
|
||||
|
||||
Log("Checking sync state (%d round trips remaining).\n", _state.sync.roundtrips_remaining);
|
||||
Log("udpproto%d | Checking sync state (%d round trips remaining).", _queue, _state.sync.roundtrips_remaining);
|
||||
if (--_state.sync.roundtrips_remaining == 0) {
|
||||
Log("Synchronized!\n");
|
||||
Log("udpproto%d | Synchronized!", _queue);
|
||||
QueueEvent(UdpProtocol::Event(UdpProtocol::Event::Synchronzied));
|
||||
_current_state = Running;
|
||||
_last_received_input.frame = -1;
|
||||
@@ -564,7 +548,7 @@ UdpProtocol::OnInput(UdpMsg *msg, int len)
|
||||
bool disconnect_requested = msg->u.input.disconnect_requested;
|
||||
if (disconnect_requested) {
|
||||
if (_current_state != Disconnected && !_disconnect_event_sent) {
|
||||
Log("Disconnecting endpoint on remote request.\n");
|
||||
Log("udpproto%d | Disconnecting endpoint on remote request.", _queue);
|
||||
QueueEvent(Event(Event::Disconnected));
|
||||
_disconnect_event_sent = true;
|
||||
}
|
||||
@@ -629,20 +613,21 @@ UdpProtocol::OnInput(UdpMsg *msg, int len)
|
||||
_last_received_input.frame = currentFrame;
|
||||
|
||||
/*
|
||||
* Send the event to the emualtor
|
||||
* Send the event to the emulator
|
||||
*/
|
||||
UdpProtocol::Event evt(UdpProtocol::Event::Input);
|
||||
evt.u.input.input = _last_received_input;
|
||||
|
||||
_last_received_input.desc(desc, ARRAY_SIZE(desc));
|
||||
if (LogTypes::LDEBUG <= MAX_LOGLEVEL)
|
||||
_last_received_input.desc(desc, ARRAY_SIZE(desc));
|
||||
|
||||
_state.running.last_input_packet_recv_time = GGPOPlatform::GetCurrentTimeMS();
|
||||
|
||||
Log("Sending frame %d to emu queue %d (%s).\n", _last_received_input.frame, _queue, desc);
|
||||
Log("udpproto%d | Sending frame %d to emu queue %d (%s).", _queue, _last_received_input.frame, _queue, desc);
|
||||
QueueEvent(evt);
|
||||
|
||||
} else {
|
||||
Log("Skipping past frame:(%d) current is %d.\n", currentFrame, _last_received_input.frame);
|
||||
Log("udpproto%d | Skipping past frame:(%d) current is %d.", _queue, currentFrame, _last_received_input.frame);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -657,7 +642,7 @@ UdpProtocol::OnInput(UdpMsg *msg, int len)
|
||||
* Get rid of our buffered input
|
||||
*/
|
||||
while (_pending_output.size() && _pending_output.front().frame < msg->u.input.ack_frame) {
|
||||
Log("Throwing away pending output frame %d\n", _pending_output.front().frame);
|
||||
Log("udpproto%d | Throwing away pending output frame %d", _queue, _pending_output.front().frame);
|
||||
_last_acked_input = _pending_output.front();
|
||||
_pending_output.pop();
|
||||
}
|
||||
@@ -672,7 +657,7 @@ UdpProtocol::OnInputAck(UdpMsg *msg, int len)
|
||||
* Get rid of our buffered input
|
||||
*/
|
||||
while (_pending_output.size() && _pending_output.front().frame < msg->u.input_ack.ack_frame) {
|
||||
Log("Throwing away pending output frame %d\n", _pending_output.front().frame);
|
||||
Log("udpproto%d | Throwing away pending output frame %d", _queue, _pending_output.front().frame);
|
||||
_last_acked_input = _pending_output.front();
|
||||
_pending_output.pop();
|
||||
}
|
||||
@@ -770,7 +755,7 @@ UdpProtocol::PumpSendQueue()
|
||||
}
|
||||
if (_oop_percent && !_oo_packet.msg && ((rand() % 100) < _oop_percent)) {
|
||||
int delay = rand() % (_send_latency * 10 + 1000);
|
||||
Log("creating rogue oop (seq: %d delay: %d)\n", entry.msg->hdr.sequence_number, delay);
|
||||
Log("udpproto%d | creating rogue oop (seq: %d delay: %d)", _queue, entry.msg->hdr.sequence_number, delay);
|
||||
_oo_packet.send_time = GGPOPlatform::GetCurrentTimeMS() + delay;
|
||||
_oo_packet.msg = entry.msg;
|
||||
_oo_packet.dest_addr = entry.dest_addr;
|
||||
@@ -785,7 +770,7 @@ UdpProtocol::PumpSendQueue()
|
||||
_send_queue.pop();
|
||||
}
|
||||
if (_oo_packet.msg && _oo_packet.send_time < (int)GGPOPlatform::GetCurrentTimeMS()) {
|
||||
Log("sending rogue oop!");
|
||||
Log("udpproto%d | sending rogue oop!", _queue);
|
||||
_udp->SendTo((char *)_oo_packet.msg, _oo_packet.msg->PacketSize(), 0,
|
||||
(struct sockaddr *)&_oo_packet.dest_addr, sizeof _oo_packet.dest_addr);
|
||||
|
||||
|
||||
@@ -119,7 +119,6 @@ protected:
|
||||
void UpdateNetworkStats(void);
|
||||
void QueueEvent(const UdpProtocol::Event &evt);
|
||||
void ClearSendQueue(void);
|
||||
void Log(const char *fmt, ...);
|
||||
void LogMsg(const char *prefix, UdpMsg *msg);
|
||||
void LogEvent(const char *prefix, const UdpProtocol::Event &evt);
|
||||
void SendSyncRequest();
|
||||
|
||||
@@ -59,7 +59,7 @@ Sync::AddLocalInput(int queue, GameInput &input)
|
||||
{
|
||||
int frames_behind = _framecount - _last_confirmed_frame;
|
||||
if (_framecount >= _max_prediction_frames && frames_behind >= _max_prediction_frames) {
|
||||
Log("Rejecting input from emulator: reached prediction barrier.\n");
|
||||
Log("Rejecting input from emulator: reached prediction barrier.");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -67,7 +67,7 @@ Sync::AddLocalInput(int queue, GameInput &input)
|
||||
SaveCurrentFrame();
|
||||
}
|
||||
|
||||
Log("Sending undelayed local frame %d to queue %d.\n", _framecount, queue);
|
||||
Log("Sending undelayed local frame %d to queue %d.", _framecount, queue);
|
||||
input.frame = _framecount;
|
||||
_input_queues[queue].AddInput(input);
|
||||
|
||||
@@ -146,7 +146,7 @@ Sync::AdjustSimulation(int seek_to)
|
||||
int framecount = _framecount;
|
||||
int count = _framecount - seek_to;
|
||||
|
||||
Log("Catching up\n");
|
||||
Log("Catching up");
|
||||
_rollingback = true;
|
||||
|
||||
/*
|
||||
@@ -167,7 +167,7 @@ Sync::AdjustSimulation(int seek_to)
|
||||
|
||||
_rollingback = false;
|
||||
|
||||
Log("---\n");
|
||||
Log("---");
|
||||
}
|
||||
|
||||
void
|
||||
@@ -175,7 +175,7 @@ Sync::LoadFrame(int frame)
|
||||
{
|
||||
// find the frame in question
|
||||
if (frame == _framecount) {
|
||||
Log("Skipping NOP.\n");
|
||||
Log("Skipping NOP.");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -183,7 +183,7 @@ Sync::LoadFrame(int frame)
|
||||
_savedstate.head = FindSavedFrameIndex(frame);
|
||||
SavedFrame *state = _savedstate.frames + _savedstate.head;
|
||||
|
||||
Log("=== Loading frame info %d (size: %d checksum: %08x).\n",
|
||||
Log("=== Loading frame info %d (size: %d checksum: %08x).",
|
||||
state->frame, state->cbuf, state->checksum);
|
||||
|
||||
ASSERT(state->buf && state->cbuf);
|
||||
@@ -210,7 +210,7 @@ Sync::SaveCurrentFrame()
|
||||
state->frame = _framecount;
|
||||
_callbacks.save_game_state(&state->buf, &state->cbuf, &state->checksum, state->frame);
|
||||
|
||||
Log("=== Saved frame info %d (size: %d checksum: %08x).\n", state->frame, state->cbuf, state->checksum);
|
||||
Log("=== Saved frame info %d (size: %d checksum: %08x).", state->frame, state->cbuf, state->checksum);
|
||||
_savedstate.head = (_savedstate.head + 1) % ARRAY_SIZE(_savedstate.frames);
|
||||
}
|
||||
|
||||
@@ -259,7 +259,7 @@ Sync::CheckSimulationConsistency(int *seekTo)
|
||||
int first_incorrect = GameInput::NullFrame;
|
||||
for (int i = 0; i < _config.num_players; i++) {
|
||||
int incorrect = _input_queues[i].GetFirstIncorrectFrame();
|
||||
Log("considering incorrect frame %d reported by queue %d.\n", incorrect, i);
|
||||
Log("considering incorrect frame %d reported by queue %d.", incorrect, i);
|
||||
|
||||
if (incorrect != GameInput::NullFrame && (first_incorrect == GameInput::NullFrame || incorrect < first_incorrect)) {
|
||||
first_incorrect = incorrect;
|
||||
@@ -267,7 +267,7 @@ Sync::CheckSimulationConsistency(int *seekTo)
|
||||
}
|
||||
|
||||
if (first_incorrect == GameInput::NullFrame) {
|
||||
Log("prediction ok. proceeding.\n");
|
||||
Log("prediction ok. proceeding.");
|
||||
return true;
|
||||
}
|
||||
*seekTo = first_incorrect;
|
||||
|
||||
@@ -59,7 +59,7 @@ TimeSync::recommend_frame_wait_duration(bool require_idle_input)
|
||||
// sleep for.
|
||||
int sleep_frames = (int)(((radvantage - advantage) / 2) + 0.5);
|
||||
|
||||
Log("iteration %d: sleep frames is %d\n", count, sleep_frames);
|
||||
Log("iteration %d: sleep frames is %d", count, sleep_frames);
|
||||
|
||||
// Some things just aren't worth correcting for. Make sure
|
||||
// the difference is relevant before proceeding.
|
||||
@@ -74,7 +74,7 @@ TimeSync::recommend_frame_wait_duration(bool require_idle_input)
|
||||
if (require_idle_input) {
|
||||
for (size_t i = 1; i < ARRAY_SIZE(_last_inputs); i++) {
|
||||
if (!_last_inputs[i].equal(_last_inputs[0], true)) {
|
||||
Log("iteration %d: rejecting due to input stuff at position %d...!!!\n", count, i);
|
||||
Log("iteration %d: rejecting due to input stuff at position %d...!!!", count, (int)i);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,175 @@
|
||||
#ifndef __eglplatform_h_
|
||||
#define __eglplatform_h_
|
||||
|
||||
/*
|
||||
** Copyright 2007-2020 The Khronos Group Inc.
|
||||
** SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/* Platform-specific types and definitions for egl.h
|
||||
*
|
||||
* Adopters may modify khrplatform.h and this file to suit their platform.
|
||||
* You are encouraged to submit all modifications to the Khronos group so that
|
||||
* they can be included in future versions of this file. Please submit changes
|
||||
* by filing an issue or pull request on the public Khronos EGL Registry, at
|
||||
* https://www.github.com/KhronosGroup/EGL-Registry/
|
||||
*/
|
||||
|
||||
#include <KHR/khrplatform.h>
|
||||
|
||||
/* Macros used in EGL function prototype declarations.
|
||||
*
|
||||
* EGL functions should be prototyped as:
|
||||
*
|
||||
* EGLAPI return-type EGLAPIENTRY eglFunction(arguments);
|
||||
* typedef return-type (EXPAPIENTRYP PFNEGLFUNCTIONPROC) (arguments);
|
||||
*
|
||||
* KHRONOS_APICALL and KHRONOS_APIENTRY are defined in KHR/khrplatform.h
|
||||
*/
|
||||
|
||||
#ifndef EGLAPI
|
||||
#define EGLAPI KHRONOS_APICALL
|
||||
#endif
|
||||
|
||||
#ifndef EGLAPIENTRY
|
||||
#define EGLAPIENTRY KHRONOS_APIENTRY
|
||||
#endif
|
||||
#define EGLAPIENTRYP EGLAPIENTRY*
|
||||
|
||||
/* The types NativeDisplayType, NativeWindowType, and NativePixmapType
|
||||
* are aliases of window-system-dependent types, such as X Display * or
|
||||
* Windows Device Context. They must be defined in platform-specific
|
||||
* code below. The EGL-prefixed versions of Native*Type are the same
|
||||
* types, renamed in EGL 1.3 so all types in the API start with "EGL".
|
||||
*
|
||||
* Khronos STRONGLY RECOMMENDS that you use the default definitions
|
||||
* provided below, since these changes affect both binary and source
|
||||
* portability of applications using EGL running on different EGL
|
||||
* implementations.
|
||||
*/
|
||||
|
||||
#if defined(EGL_NO_PLATFORM_SPECIFIC_TYPES)
|
||||
|
||||
typedef void *EGLNativeDisplayType;
|
||||
typedef void *EGLNativePixmapType;
|
||||
typedef void *EGLNativeWindowType;
|
||||
|
||||
#elif defined(_WIN32) || defined(__VC32__) && !defined(__CYGWIN__) && !defined(__SCITECH_SNAP__) /* Win32 and WinCE */
|
||||
#ifndef WIN32_LEAN_AND_MEAN
|
||||
#define WIN32_LEAN_AND_MEAN 1
|
||||
#endif
|
||||
#include <windows.h>
|
||||
|
||||
typedef HDC EGLNativeDisplayType;
|
||||
typedef HBITMAP EGLNativePixmapType;
|
||||
typedef HWND EGLNativeWindowType;
|
||||
|
||||
#elif defined(__QNX__)
|
||||
|
||||
typedef khronos_uintptr_t EGLNativeDisplayType;
|
||||
typedef struct _screen_pixmap* EGLNativePixmapType; /* screen_pixmap_t */
|
||||
typedef struct _screen_window* EGLNativeWindowType; /* screen_window_t */
|
||||
|
||||
#elif defined(__EMSCRIPTEN__)
|
||||
|
||||
typedef int EGLNativeDisplayType;
|
||||
typedef int EGLNativePixmapType;
|
||||
typedef int EGLNativeWindowType;
|
||||
|
||||
#elif defined(__WINSCW__) || defined(__SYMBIAN32__) /* Symbian */
|
||||
|
||||
typedef int EGLNativeDisplayType;
|
||||
typedef void *EGLNativePixmapType;
|
||||
typedef void *EGLNativeWindowType;
|
||||
|
||||
#elif defined(WL_EGL_PLATFORM)
|
||||
|
||||
typedef struct wl_display *EGLNativeDisplayType;
|
||||
typedef struct wl_egl_pixmap *EGLNativePixmapType;
|
||||
typedef struct wl_egl_window *EGLNativeWindowType;
|
||||
|
||||
#elif defined(__GBM__)
|
||||
|
||||
typedef struct gbm_device *EGLNativeDisplayType;
|
||||
typedef struct gbm_bo *EGLNativePixmapType;
|
||||
typedef void *EGLNativeWindowType;
|
||||
|
||||
#elif defined(__ANDROID__) || defined(ANDROID)
|
||||
|
||||
struct ANativeWindow;
|
||||
struct egl_native_pixmap_t;
|
||||
|
||||
typedef void* EGLNativeDisplayType;
|
||||
typedef struct egl_native_pixmap_t* EGLNativePixmapType;
|
||||
typedef struct ANativeWindow* EGLNativeWindowType;
|
||||
|
||||
#elif defined(USE_OZONE)
|
||||
|
||||
typedef intptr_t EGLNativeDisplayType;
|
||||
typedef intptr_t EGLNativePixmapType;
|
||||
typedef intptr_t EGLNativeWindowType;
|
||||
|
||||
#elif defined(USE_X11)
|
||||
|
||||
/* X11 (tentative) */
|
||||
#include <X11/Xlib.h>
|
||||
#include <X11/Xutil.h>
|
||||
|
||||
typedef Display *EGLNativeDisplayType;
|
||||
typedef Pixmap EGLNativePixmapType;
|
||||
typedef Window EGLNativeWindowType;
|
||||
|
||||
#elif defined(__unix__)
|
||||
|
||||
typedef void *EGLNativeDisplayType;
|
||||
typedef khronos_uintptr_t EGLNativePixmapType;
|
||||
typedef khronos_uintptr_t EGLNativeWindowType;
|
||||
|
||||
#elif defined(__APPLE__)
|
||||
|
||||
typedef int EGLNativeDisplayType;
|
||||
typedef void *EGLNativePixmapType;
|
||||
typedef void *EGLNativeWindowType;
|
||||
|
||||
#elif defined(__HAIKU__)
|
||||
|
||||
#include <kernel/image.h>
|
||||
|
||||
typedef void *EGLNativeDisplayType;
|
||||
typedef khronos_uintptr_t EGLNativePixmapType;
|
||||
typedef khronos_uintptr_t EGLNativeWindowType;
|
||||
|
||||
#elif defined(__Fuchsia__)
|
||||
|
||||
typedef void *EGLNativeDisplayType;
|
||||
typedef khronos_uintptr_t EGLNativePixmapType;
|
||||
typedef khronos_uintptr_t EGLNativeWindowType;
|
||||
|
||||
#else
|
||||
#error "Platform not recognized"
|
||||
#endif
|
||||
|
||||
/* EGL 1.2 types, renamed for consistency in EGL 1.3 */
|
||||
typedef EGLNativeDisplayType NativeDisplayType;
|
||||
typedef EGLNativePixmapType NativePixmapType;
|
||||
typedef EGLNativeWindowType NativeWindowType;
|
||||
|
||||
|
||||
/* Define EGLint. This must be a signed integral type large enough to contain
|
||||
* all legal attribute names and values passed into and out of EGL, whether
|
||||
* their type is boolean, bitmask, enumerant (symbolic constant), integer,
|
||||
* handle, or other. While in general a 32-bit integer will suffice, if
|
||||
* handles are 64 bit types, then EGLint should be defined as a signed 64-bit
|
||||
* integer type.
|
||||
*/
|
||||
typedef khronos_int32_t EGLint;
|
||||
|
||||
|
||||
/* C++ / C typecast macros for special EGL handle values */
|
||||
#if defined(__cplusplus)
|
||||
#define EGL_CAST(type, value) (static_cast<type>(value))
|
||||
#else
|
||||
#define EGL_CAST(type, value) ((type) (value))
|
||||
#endif
|
||||
|
||||
#endif /* __eglplatform_h */
|
||||
@@ -0,0 +1,311 @@
|
||||
#ifndef __khrplatform_h_
|
||||
#define __khrplatform_h_
|
||||
|
||||
/*
|
||||
** Copyright (c) 2008-2018 The Khronos Group Inc.
|
||||
**
|
||||
** Permission is hereby granted, free of charge, to any person obtaining a
|
||||
** copy of this software and/or associated documentation files (the
|
||||
** "Materials"), to deal in the Materials without restriction, including
|
||||
** without limitation the rights to use, copy, modify, merge, publish,
|
||||
** distribute, sublicense, and/or sell copies of the Materials, and to
|
||||
** permit persons to whom the Materials are furnished to do so, subject to
|
||||
** the following conditions:
|
||||
**
|
||||
** The above copyright notice and this permission notice shall be included
|
||||
** in all copies or substantial portions of the Materials.
|
||||
**
|
||||
** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
|
||||
*/
|
||||
|
||||
/* Khronos platform-specific types and definitions.
|
||||
*
|
||||
* The master copy of khrplatform.h is maintained in the Khronos EGL
|
||||
* Registry repository at https://github.com/KhronosGroup/EGL-Registry
|
||||
* The last semantic modification to khrplatform.h was at commit ID:
|
||||
* 67a3e0864c2d75ea5287b9f3d2eb74a745936692
|
||||
*
|
||||
* Adopters may modify this file to suit their platform. Adopters are
|
||||
* encouraged to submit platform specific modifications to the Khronos
|
||||
* group so that they can be included in future versions of this file.
|
||||
* Please submit changes by filing pull requests or issues on
|
||||
* the EGL Registry repository linked above.
|
||||
*
|
||||
*
|
||||
* See the Implementer's Guidelines for information about where this file
|
||||
* should be located on your system and for more details of its use:
|
||||
* http://www.khronos.org/registry/implementers_guide.pdf
|
||||
*
|
||||
* This file should be included as
|
||||
* #include <KHR/khrplatform.h>
|
||||
* by Khronos client API header files that use its types and defines.
|
||||
*
|
||||
* The types in khrplatform.h should only be used to define API-specific types.
|
||||
*
|
||||
* Types defined in khrplatform.h:
|
||||
* khronos_int8_t signed 8 bit
|
||||
* khronos_uint8_t unsigned 8 bit
|
||||
* khronos_int16_t signed 16 bit
|
||||
* khronos_uint16_t unsigned 16 bit
|
||||
* khronos_int32_t signed 32 bit
|
||||
* khronos_uint32_t unsigned 32 bit
|
||||
* khronos_int64_t signed 64 bit
|
||||
* khronos_uint64_t unsigned 64 bit
|
||||
* khronos_intptr_t signed same number of bits as a pointer
|
||||
* khronos_uintptr_t unsigned same number of bits as a pointer
|
||||
* khronos_ssize_t signed size
|
||||
* khronos_usize_t unsigned size
|
||||
* khronos_float_t signed 32 bit floating point
|
||||
* khronos_time_ns_t unsigned 64 bit time in nanoseconds
|
||||
* khronos_utime_nanoseconds_t unsigned time interval or absolute time in
|
||||
* nanoseconds
|
||||
* khronos_stime_nanoseconds_t signed time interval in nanoseconds
|
||||
* khronos_boolean_enum_t enumerated boolean type. This should
|
||||
* only be used as a base type when a client API's boolean type is
|
||||
* an enum. Client APIs which use an integer or other type for
|
||||
* booleans cannot use this as the base type for their boolean.
|
||||
*
|
||||
* Tokens defined in khrplatform.h:
|
||||
*
|
||||
* KHRONOS_FALSE, KHRONOS_TRUE Enumerated boolean false/true values.
|
||||
*
|
||||
* KHRONOS_SUPPORT_INT64 is 1 if 64 bit integers are supported; otherwise 0.
|
||||
* KHRONOS_SUPPORT_FLOAT is 1 if floats are supported; otherwise 0.
|
||||
*
|
||||
* Calling convention macros defined in this file:
|
||||
* KHRONOS_APICALL
|
||||
* KHRONOS_APIENTRY
|
||||
* KHRONOS_APIATTRIBUTES
|
||||
*
|
||||
* These may be used in function prototypes as:
|
||||
*
|
||||
* KHRONOS_APICALL void KHRONOS_APIENTRY funcname(
|
||||
* int arg1,
|
||||
* int arg2) KHRONOS_APIATTRIBUTES;
|
||||
*/
|
||||
|
||||
#if defined(__SCITECH_SNAP__) && !defined(KHRONOS_STATIC)
|
||||
# define KHRONOS_STATIC 1
|
||||
#endif
|
||||
|
||||
/*-------------------------------------------------------------------------
|
||||
* Definition of KHRONOS_APICALL
|
||||
*-------------------------------------------------------------------------
|
||||
* This precedes the return type of the function in the function prototype.
|
||||
*/
|
||||
#if defined(KHRONOS_STATIC)
|
||||
/* If the preprocessor constant KHRONOS_STATIC is defined, make the
|
||||
* header compatible with static linking. */
|
||||
# define KHRONOS_APICALL
|
||||
#elif defined(_WIN32)
|
||||
# define KHRONOS_APICALL __declspec(dllimport)
|
||||
#elif defined (__SYMBIAN32__)
|
||||
# define KHRONOS_APICALL IMPORT_C
|
||||
#elif defined(__ANDROID__)
|
||||
# define KHRONOS_APICALL __attribute__((visibility("default")))
|
||||
#else
|
||||
# define KHRONOS_APICALL
|
||||
#endif
|
||||
|
||||
/*-------------------------------------------------------------------------
|
||||
* Definition of KHRONOS_APIENTRY
|
||||
*-------------------------------------------------------------------------
|
||||
* This follows the return type of the function and precedes the function
|
||||
* name in the function prototype.
|
||||
*/
|
||||
#if defined(_WIN32) && !defined(_WIN32_WCE) && !defined(__SCITECH_SNAP__)
|
||||
/* Win32 but not WinCE */
|
||||
# define KHRONOS_APIENTRY __stdcall
|
||||
#else
|
||||
# define KHRONOS_APIENTRY
|
||||
#endif
|
||||
|
||||
/*-------------------------------------------------------------------------
|
||||
* Definition of KHRONOS_APIATTRIBUTES
|
||||
*-------------------------------------------------------------------------
|
||||
* This follows the closing parenthesis of the function prototype arguments.
|
||||
*/
|
||||
#if defined (__ARMCC_2__)
|
||||
#define KHRONOS_APIATTRIBUTES __softfp
|
||||
#else
|
||||
#define KHRONOS_APIATTRIBUTES
|
||||
#endif
|
||||
|
||||
/*-------------------------------------------------------------------------
|
||||
* basic type definitions
|
||||
*-----------------------------------------------------------------------*/
|
||||
#if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || defined(__GNUC__) || defined(__SCO__) || defined(__USLC__)
|
||||
|
||||
|
||||
/*
|
||||
* Using <stdint.h>
|
||||
*/
|
||||
#include <stdint.h>
|
||||
typedef int32_t khronos_int32_t;
|
||||
typedef uint32_t khronos_uint32_t;
|
||||
typedef int64_t khronos_int64_t;
|
||||
typedef uint64_t khronos_uint64_t;
|
||||
#define KHRONOS_SUPPORT_INT64 1
|
||||
#define KHRONOS_SUPPORT_FLOAT 1
|
||||
/*
|
||||
* To support platform where unsigned long cannot be used interchangeably with
|
||||
* inptr_t (e.g. CHERI-extended ISAs), we can use the stdint.h intptr_t.
|
||||
* Ideally, we could just use (u)intptr_t everywhere, but this could result in
|
||||
* ABI breakage if khronos_uintptr_t is changed from unsigned long to
|
||||
* unsigned long long or similar (this results in different C++ name mangling).
|
||||
* To avoid changes for existing platforms, we restrict usage of intptr_t to
|
||||
* platforms where the size of a pointer is larger than the size of long.
|
||||
*/
|
||||
#if defined(__SIZEOF_LONG__) && defined(__SIZEOF_POINTER__)
|
||||
#if __SIZEOF_POINTER__ > __SIZEOF_LONG__
|
||||
#define KHRONOS_USE_INTPTR_T
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#elif defined(__VMS ) || defined(__sgi)
|
||||
|
||||
/*
|
||||
* Using <inttypes.h>
|
||||
*/
|
||||
#include <inttypes.h>
|
||||
typedef int32_t khronos_int32_t;
|
||||
typedef uint32_t khronos_uint32_t;
|
||||
typedef int64_t khronos_int64_t;
|
||||
typedef uint64_t khronos_uint64_t;
|
||||
#define KHRONOS_SUPPORT_INT64 1
|
||||
#define KHRONOS_SUPPORT_FLOAT 1
|
||||
|
||||
#elif defined(_WIN32) && !defined(__SCITECH_SNAP__)
|
||||
|
||||
/*
|
||||
* Win32
|
||||
*/
|
||||
typedef __int32 khronos_int32_t;
|
||||
typedef unsigned __int32 khronos_uint32_t;
|
||||
typedef __int64 khronos_int64_t;
|
||||
typedef unsigned __int64 khronos_uint64_t;
|
||||
#define KHRONOS_SUPPORT_INT64 1
|
||||
#define KHRONOS_SUPPORT_FLOAT 1
|
||||
|
||||
#elif defined(__sun__) || defined(__digital__)
|
||||
|
||||
/*
|
||||
* Sun or Digital
|
||||
*/
|
||||
typedef int khronos_int32_t;
|
||||
typedef unsigned int khronos_uint32_t;
|
||||
#if defined(__arch64__) || defined(_LP64)
|
||||
typedef long int khronos_int64_t;
|
||||
typedef unsigned long int khronos_uint64_t;
|
||||
#else
|
||||
typedef long long int khronos_int64_t;
|
||||
typedef unsigned long long int khronos_uint64_t;
|
||||
#endif /* __arch64__ */
|
||||
#define KHRONOS_SUPPORT_INT64 1
|
||||
#define KHRONOS_SUPPORT_FLOAT 1
|
||||
|
||||
#elif 0
|
||||
|
||||
/*
|
||||
* Hypothetical platform with no float or int64 support
|
||||
*/
|
||||
typedef int khronos_int32_t;
|
||||
typedef unsigned int khronos_uint32_t;
|
||||
#define KHRONOS_SUPPORT_INT64 0
|
||||
#define KHRONOS_SUPPORT_FLOAT 0
|
||||
|
||||
#else
|
||||
|
||||
/*
|
||||
* Generic fallback
|
||||
*/
|
||||
#include <stdint.h>
|
||||
typedef int32_t khronos_int32_t;
|
||||
typedef uint32_t khronos_uint32_t;
|
||||
typedef int64_t khronos_int64_t;
|
||||
typedef uint64_t khronos_uint64_t;
|
||||
#define KHRONOS_SUPPORT_INT64 1
|
||||
#define KHRONOS_SUPPORT_FLOAT 1
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* Types that are (so far) the same on all platforms
|
||||
*/
|
||||
typedef signed char khronos_int8_t;
|
||||
typedef unsigned char khronos_uint8_t;
|
||||
typedef signed short int khronos_int16_t;
|
||||
typedef unsigned short int khronos_uint16_t;
|
||||
|
||||
/*
|
||||
* Types that differ between LLP64 and LP64 architectures - in LLP64,
|
||||
* pointers are 64 bits, but 'long' is still 32 bits. Win64 appears
|
||||
* to be the only LLP64 architecture in current use.
|
||||
*/
|
||||
#ifdef KHRONOS_USE_INTPTR_T
|
||||
typedef intptr_t khronos_intptr_t;
|
||||
typedef uintptr_t khronos_uintptr_t;
|
||||
#elif defined(_WIN64)
|
||||
typedef signed long long int khronos_intptr_t;
|
||||
typedef unsigned long long int khronos_uintptr_t;
|
||||
#else
|
||||
typedef signed long int khronos_intptr_t;
|
||||
typedef unsigned long int khronos_uintptr_t;
|
||||
#endif
|
||||
|
||||
#if defined(_WIN64)
|
||||
typedef signed long long int khronos_ssize_t;
|
||||
typedef unsigned long long int khronos_usize_t;
|
||||
#else
|
||||
typedef signed long int khronos_ssize_t;
|
||||
typedef unsigned long int khronos_usize_t;
|
||||
#endif
|
||||
|
||||
#if KHRONOS_SUPPORT_FLOAT
|
||||
/*
|
||||
* Float type
|
||||
*/
|
||||
typedef float khronos_float_t;
|
||||
#endif
|
||||
|
||||
#if KHRONOS_SUPPORT_INT64
|
||||
/* Time types
|
||||
*
|
||||
* These types can be used to represent a time interval in nanoseconds or
|
||||
* an absolute Unadjusted System Time. Unadjusted System Time is the number
|
||||
* of nanoseconds since some arbitrary system event (e.g. since the last
|
||||
* time the system booted). The Unadjusted System Time is an unsigned
|
||||
* 64 bit value that wraps back to 0 every 584 years. Time intervals
|
||||
* may be either signed or unsigned.
|
||||
*/
|
||||
typedef khronos_uint64_t khronos_utime_nanoseconds_t;
|
||||
typedef khronos_int64_t khronos_stime_nanoseconds_t;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Dummy value used to pad enum types to 32 bits.
|
||||
*/
|
||||
#ifndef KHRONOS_MAX_ENUM
|
||||
#define KHRONOS_MAX_ENUM 0x7FFFFFFF
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Enumerated boolean type
|
||||
*
|
||||
* Values other than zero should be considered to be true. Therefore
|
||||
* comparisons should not be made against KHRONOS_TRUE.
|
||||
*/
|
||||
typedef enum {
|
||||
KHRONOS_FALSE = 0,
|
||||
KHRONOS_TRUE = 1,
|
||||
KHRONOS_BOOLEAN_ENUM_FORCE_SIZE = KHRONOS_MAX_ENUM
|
||||
} khronos_boolean_enum_t;
|
||||
|
||||
#endif /* __khrplatform_h_ */
|
||||
@@ -0,0 +1,550 @@
|
||||
/**
|
||||
* Loader generated by glad 2.0.4 on Sat Jan 20 11:00:00 2024
|
||||
*
|
||||
* SPDX-License-Identifier: (WTFPL OR CC0-1.0) AND Apache-2.0
|
||||
*
|
||||
* Generator: C/C++
|
||||
* Specification: egl
|
||||
* Extensions: 0
|
||||
*
|
||||
* APIs:
|
||||
* - egl=1.5
|
||||
*
|
||||
* Options:
|
||||
* - ALIAS = False
|
||||
* - DEBUG = False
|
||||
* - HEADER_ONLY = False
|
||||
* - LOADER = True
|
||||
* - MX = False
|
||||
* - ON_DEMAND = False
|
||||
*
|
||||
* Commandline:
|
||||
* --api='egl=1.5' --extensions='' c --loader
|
||||
*
|
||||
* Online:
|
||||
* http://glad.sh/#api=egl%3D1.5&extensions=&generator=c&options=LOADER
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef GLAD_EGL_H_
|
||||
#define GLAD_EGL_H_
|
||||
|
||||
|
||||
#define GLAD_EGL
|
||||
#define GLAD_OPTION_EGL_LOADER
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifndef GLAD_PLATFORM_H_
|
||||
#define GLAD_PLATFORM_H_
|
||||
|
||||
#ifndef GLAD_PLATFORM_WIN32
|
||||
#if defined(_WIN32) || defined(__WIN32__) || defined(WIN32) || defined(__MINGW32__)
|
||||
#define GLAD_PLATFORM_WIN32 1
|
||||
#else
|
||||
#define GLAD_PLATFORM_WIN32 0
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef GLAD_PLATFORM_APPLE
|
||||
#ifdef __APPLE__
|
||||
#define GLAD_PLATFORM_APPLE 1
|
||||
#else
|
||||
#define GLAD_PLATFORM_APPLE 0
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef GLAD_PLATFORM_EMSCRIPTEN
|
||||
#ifdef __EMSCRIPTEN__
|
||||
#define GLAD_PLATFORM_EMSCRIPTEN 1
|
||||
#else
|
||||
#define GLAD_PLATFORM_EMSCRIPTEN 0
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef GLAD_PLATFORM_UWP
|
||||
#if defined(_MSC_VER) && !defined(GLAD_INTERNAL_HAVE_WINAPIFAMILY)
|
||||
#ifdef __has_include
|
||||
#if __has_include(<winapifamily.h>)
|
||||
#define GLAD_INTERNAL_HAVE_WINAPIFAMILY 1
|
||||
#endif
|
||||
#elif _MSC_VER >= 1700 && !_USING_V110_SDK71_
|
||||
#define GLAD_INTERNAL_HAVE_WINAPIFAMILY 1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef GLAD_INTERNAL_HAVE_WINAPIFAMILY
|
||||
#include <winapifamily.h>
|
||||
#if !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP)
|
||||
#define GLAD_PLATFORM_UWP 1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef GLAD_PLATFORM_UWP
|
||||
#define GLAD_PLATFORM_UWP 0
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef __GNUC__
|
||||
#define GLAD_GNUC_EXTENSION __extension__
|
||||
#else
|
||||
#define GLAD_GNUC_EXTENSION
|
||||
#endif
|
||||
|
||||
#define GLAD_UNUSED(x) (void)(x)
|
||||
|
||||
#ifndef GLAD_API_CALL
|
||||
#if defined(GLAD_API_CALL_EXPORT)
|
||||
#if GLAD_PLATFORM_WIN32 || defined(__CYGWIN__)
|
||||
#if defined(GLAD_API_CALL_EXPORT_BUILD)
|
||||
#if defined(__GNUC__)
|
||||
#define GLAD_API_CALL __attribute__ ((dllexport)) extern
|
||||
#else
|
||||
#define GLAD_API_CALL __declspec(dllexport) extern
|
||||
#endif
|
||||
#else
|
||||
#if defined(__GNUC__)
|
||||
#define GLAD_API_CALL __attribute__ ((dllimport)) extern
|
||||
#else
|
||||
#define GLAD_API_CALL __declspec(dllimport) extern
|
||||
#endif
|
||||
#endif
|
||||
#elif defined(__GNUC__) && defined(GLAD_API_CALL_EXPORT_BUILD)
|
||||
#define GLAD_API_CALL __attribute__ ((visibility ("default"))) extern
|
||||
#else
|
||||
#define GLAD_API_CALL extern
|
||||
#endif
|
||||
#else
|
||||
#define GLAD_API_CALL extern
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef APIENTRY
|
||||
#define GLAD_API_PTR APIENTRY
|
||||
#elif GLAD_PLATFORM_WIN32
|
||||
#define GLAD_API_PTR __stdcall
|
||||
#else
|
||||
#define GLAD_API_PTR
|
||||
#endif
|
||||
|
||||
#ifndef GLAPI
|
||||
#define GLAPI GLAD_API_CALL
|
||||
#endif
|
||||
|
||||
#ifndef GLAPIENTRY
|
||||
#define GLAPIENTRY GLAD_API_PTR
|
||||
#endif
|
||||
|
||||
#define GLAD_MAKE_VERSION(major, minor) (major * 10000 + minor)
|
||||
#define GLAD_VERSION_MAJOR(version) (version / 10000)
|
||||
#define GLAD_VERSION_MINOR(version) (version % 10000)
|
||||
|
||||
#define GLAD_GENERATOR_VERSION "2.0.4"
|
||||
|
||||
typedef void (*GLADapiproc)(void);
|
||||
|
||||
typedef GLADapiproc (*GLADloadfunc)(const char *name);
|
||||
typedef GLADapiproc (*GLADuserptrloadfunc)(void *userptr, const char *name);
|
||||
|
||||
typedef void (*GLADprecallback)(const char *name, GLADapiproc apiproc, int len_args, ...);
|
||||
typedef void (*GLADpostcallback)(void *ret, const char *name, GLADapiproc apiproc, int len_args, ...);
|
||||
|
||||
#endif /* GLAD_PLATFORM_H_ */
|
||||
|
||||
#define EGL_ALPHA_FORMAT 0x3088
|
||||
#define EGL_ALPHA_FORMAT_NONPRE 0x308B
|
||||
#define EGL_ALPHA_FORMAT_PRE 0x308C
|
||||
#define EGL_ALPHA_MASK_SIZE 0x303E
|
||||
#define EGL_ALPHA_SIZE 0x3021
|
||||
#define EGL_BACK_BUFFER 0x3084
|
||||
#define EGL_BAD_ACCESS 0x3002
|
||||
#define EGL_BAD_ALLOC 0x3003
|
||||
#define EGL_BAD_ATTRIBUTE 0x3004
|
||||
#define EGL_BAD_CONFIG 0x3005
|
||||
#define EGL_BAD_CONTEXT 0x3006
|
||||
#define EGL_BAD_CURRENT_SURFACE 0x3007
|
||||
#define EGL_BAD_DISPLAY 0x3008
|
||||
#define EGL_BAD_MATCH 0x3009
|
||||
#define EGL_BAD_NATIVE_PIXMAP 0x300A
|
||||
#define EGL_BAD_NATIVE_WINDOW 0x300B
|
||||
#define EGL_BAD_PARAMETER 0x300C
|
||||
#define EGL_BAD_SURFACE 0x300D
|
||||
#define EGL_BIND_TO_TEXTURE_RGB 0x3039
|
||||
#define EGL_BIND_TO_TEXTURE_RGBA 0x303A
|
||||
#define EGL_BLUE_SIZE 0x3022
|
||||
#define EGL_BUFFER_DESTROYED 0x3095
|
||||
#define EGL_BUFFER_PRESERVED 0x3094
|
||||
#define EGL_BUFFER_SIZE 0x3020
|
||||
#define EGL_CLIENT_APIS 0x308D
|
||||
#define EGL_CL_EVENT_HANDLE 0x309C
|
||||
#define EGL_COLORSPACE 0x3087
|
||||
#define EGL_COLORSPACE_LINEAR 0x308A
|
||||
#define EGL_COLORSPACE_sRGB 0x3089
|
||||
#define EGL_COLOR_BUFFER_TYPE 0x303F
|
||||
#define EGL_CONDITION_SATISFIED 0x30F6
|
||||
#define EGL_CONFIG_CAVEAT 0x3027
|
||||
#define EGL_CONFIG_ID 0x3028
|
||||
#define EGL_CONFORMANT 0x3042
|
||||
#define EGL_CONTEXT_CLIENT_TYPE 0x3097
|
||||
#define EGL_CONTEXT_CLIENT_VERSION 0x3098
|
||||
#define EGL_CONTEXT_LOST 0x300E
|
||||
#define EGL_CONTEXT_MAJOR_VERSION 0x3098
|
||||
#define EGL_CONTEXT_MINOR_VERSION 0x30FB
|
||||
#define EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT 0x00000002
|
||||
#define EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT 0x00000001
|
||||
#define EGL_CONTEXT_OPENGL_DEBUG 0x31B0
|
||||
#define EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE 0x31B1
|
||||
#define EGL_CONTEXT_OPENGL_PROFILE_MASK 0x30FD
|
||||
#define EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY 0x31BD
|
||||
#define EGL_CONTEXT_OPENGL_ROBUST_ACCESS 0x31B2
|
||||
#define EGL_CORE_NATIVE_ENGINE 0x305B
|
||||
#define EGL_DEFAULT_DISPLAY EGL_CAST(EGLNativeDisplayType,0)
|
||||
#define EGL_DEPTH_SIZE 0x3025
|
||||
#define EGL_DISPLAY_SCALING 10000
|
||||
#define EGL_DONT_CARE EGL_CAST(EGLint,-1)
|
||||
#define EGL_DRAW 0x3059
|
||||
#define EGL_EXTENSIONS 0x3055
|
||||
#define EGL_FALSE 0
|
||||
#define EGL_FOREVER 0xFFFFFFFFFFFFFFFF
|
||||
#define EGL_GL_COLORSPACE 0x309D
|
||||
#define EGL_GL_COLORSPACE_LINEAR 0x308A
|
||||
#define EGL_GL_COLORSPACE_SRGB 0x3089
|
||||
#define EGL_GL_RENDERBUFFER 0x30B9
|
||||
#define EGL_GL_TEXTURE_2D 0x30B1
|
||||
#define EGL_GL_TEXTURE_3D 0x30B2
|
||||
#define EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_X 0x30B4
|
||||
#define EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Y 0x30B6
|
||||
#define EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z 0x30B8
|
||||
#define EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_X 0x30B3
|
||||
#define EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_Y 0x30B5
|
||||
#define EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_Z 0x30B7
|
||||
#define EGL_GL_TEXTURE_LEVEL 0x30BC
|
||||
#define EGL_GL_TEXTURE_ZOFFSET 0x30BD
|
||||
#define EGL_GREEN_SIZE 0x3023
|
||||
#define EGL_HEIGHT 0x3056
|
||||
#define EGL_HORIZONTAL_RESOLUTION 0x3090
|
||||
#define EGL_IMAGE_PRESERVED 0x30D2
|
||||
#define EGL_LARGEST_PBUFFER 0x3058
|
||||
#define EGL_LEVEL 0x3029
|
||||
#define EGL_LOSE_CONTEXT_ON_RESET 0x31BF
|
||||
#define EGL_LUMINANCE_BUFFER 0x308F
|
||||
#define EGL_LUMINANCE_SIZE 0x303D
|
||||
#define EGL_MATCH_NATIVE_PIXMAP 0x3041
|
||||
#define EGL_MAX_PBUFFER_HEIGHT 0x302A
|
||||
#define EGL_MAX_PBUFFER_PIXELS 0x302B
|
||||
#define EGL_MAX_PBUFFER_WIDTH 0x302C
|
||||
#define EGL_MAX_SWAP_INTERVAL 0x303C
|
||||
#define EGL_MIN_SWAP_INTERVAL 0x303B
|
||||
#define EGL_MIPMAP_LEVEL 0x3083
|
||||
#define EGL_MIPMAP_TEXTURE 0x3082
|
||||
#define EGL_MULTISAMPLE_RESOLVE 0x3099
|
||||
#define EGL_MULTISAMPLE_RESOLVE_BOX 0x309B
|
||||
#define EGL_MULTISAMPLE_RESOLVE_BOX_BIT 0x0200
|
||||
#define EGL_MULTISAMPLE_RESOLVE_DEFAULT 0x309A
|
||||
#define EGL_NATIVE_RENDERABLE 0x302D
|
||||
#define EGL_NATIVE_VISUAL_ID 0x302E
|
||||
#define EGL_NATIVE_VISUAL_TYPE 0x302F
|
||||
#define EGL_NONE 0x3038
|
||||
#define EGL_NON_CONFORMANT_CONFIG 0x3051
|
||||
#define EGL_NOT_INITIALIZED 0x3001
|
||||
#define EGL_NO_CONTEXT EGL_CAST(EGLContext,0)
|
||||
#define EGL_NO_DISPLAY EGL_CAST(EGLDisplay,0)
|
||||
#define EGL_NO_IMAGE EGL_CAST(EGLImage,0)
|
||||
#define EGL_NO_RESET_NOTIFICATION 0x31BE
|
||||
#define EGL_NO_SURFACE EGL_CAST(EGLSurface,0)
|
||||
#define EGL_NO_SYNC EGL_CAST(EGLSync,0)
|
||||
#define EGL_NO_TEXTURE 0x305C
|
||||
#define EGL_OPENGL_API 0x30A2
|
||||
#define EGL_OPENGL_BIT 0x0008
|
||||
#define EGL_OPENGL_ES2_BIT 0x0004
|
||||
#define EGL_OPENGL_ES3_BIT 0x00000040
|
||||
#define EGL_OPENGL_ES_API 0x30A0
|
||||
#define EGL_OPENGL_ES_BIT 0x0001
|
||||
#define EGL_OPENVG_API 0x30A1
|
||||
#define EGL_OPENVG_BIT 0x0002
|
||||
#define EGL_OPENVG_IMAGE 0x3096
|
||||
#define EGL_PBUFFER_BIT 0x0001
|
||||
#define EGL_PIXEL_ASPECT_RATIO 0x3092
|
||||
#define EGL_PIXMAP_BIT 0x0002
|
||||
#define EGL_READ 0x305A
|
||||
#define EGL_RED_SIZE 0x3024
|
||||
#define EGL_RENDERABLE_TYPE 0x3040
|
||||
#define EGL_RENDER_BUFFER 0x3086
|
||||
#define EGL_RGB_BUFFER 0x308E
|
||||
#define EGL_SAMPLES 0x3031
|
||||
#define EGL_SAMPLE_BUFFERS 0x3032
|
||||
#define EGL_SIGNALED 0x30F2
|
||||
#define EGL_SINGLE_BUFFER 0x3085
|
||||
#define EGL_SLOW_CONFIG 0x3050
|
||||
#define EGL_STENCIL_SIZE 0x3026
|
||||
#define EGL_SUCCESS 0x3000
|
||||
#define EGL_SURFACE_TYPE 0x3033
|
||||
#define EGL_SWAP_BEHAVIOR 0x3093
|
||||
#define EGL_SWAP_BEHAVIOR_PRESERVED_BIT 0x0400
|
||||
#define EGL_SYNC_CL_EVENT 0x30FE
|
||||
#define EGL_SYNC_CL_EVENT_COMPLETE 0x30FF
|
||||
#define EGL_SYNC_CONDITION 0x30F8
|
||||
#define EGL_SYNC_FENCE 0x30F9
|
||||
#define EGL_SYNC_FLUSH_COMMANDS_BIT 0x0001
|
||||
#define EGL_SYNC_PRIOR_COMMANDS_COMPLETE 0x30F0
|
||||
#define EGL_SYNC_STATUS 0x30F1
|
||||
#define EGL_SYNC_TYPE 0x30F7
|
||||
#define EGL_TEXTURE_2D 0x305F
|
||||
#define EGL_TEXTURE_FORMAT 0x3080
|
||||
#define EGL_TEXTURE_RGB 0x305D
|
||||
#define EGL_TEXTURE_RGBA 0x305E
|
||||
#define EGL_TEXTURE_TARGET 0x3081
|
||||
#define EGL_TIMEOUT_EXPIRED 0x30F5
|
||||
#define EGL_TRANSPARENT_BLUE_VALUE 0x3035
|
||||
#define EGL_TRANSPARENT_GREEN_VALUE 0x3036
|
||||
#define EGL_TRANSPARENT_RED_VALUE 0x3037
|
||||
#define EGL_TRANSPARENT_RGB 0x3052
|
||||
#define EGL_TRANSPARENT_TYPE 0x3034
|
||||
#define EGL_TRUE 1
|
||||
#define EGL_UNKNOWN EGL_CAST(EGLint,-1)
|
||||
#define EGL_UNSIGNALED 0x30F3
|
||||
#define EGL_VENDOR 0x3053
|
||||
#define EGL_VERSION 0x3054
|
||||
#define EGL_VERTICAL_RESOLUTION 0x3091
|
||||
#define EGL_VG_ALPHA_FORMAT 0x3088
|
||||
#define EGL_VG_ALPHA_FORMAT_NONPRE 0x308B
|
||||
#define EGL_VG_ALPHA_FORMAT_PRE 0x308C
|
||||
#define EGL_VG_ALPHA_FORMAT_PRE_BIT 0x0040
|
||||
#define EGL_VG_COLORSPACE 0x3087
|
||||
#define EGL_VG_COLORSPACE_LINEAR 0x308A
|
||||
#define EGL_VG_COLORSPACE_LINEAR_BIT 0x0020
|
||||
#define EGL_VG_COLORSPACE_sRGB 0x3089
|
||||
#define EGL_WIDTH 0x3057
|
||||
#define EGL_WINDOW_BIT 0x0004
|
||||
|
||||
|
||||
#include <KHR/khrplatform.h>
|
||||
#include <EGL/eglplatform.h>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
struct AHardwareBuffer;
|
||||
struct wl_buffer;
|
||||
struct wl_display;
|
||||
struct wl_resource;
|
||||
|
||||
typedef unsigned int EGLBoolean;
|
||||
typedef unsigned int EGLenum;
|
||||
typedef intptr_t EGLAttribKHR;
|
||||
typedef intptr_t EGLAttrib;
|
||||
typedef void *EGLClientBuffer;
|
||||
typedef void *EGLConfig;
|
||||
typedef void *EGLContext;
|
||||
typedef void *EGLDeviceEXT;
|
||||
typedef void *EGLDisplay;
|
||||
typedef void *EGLImage;
|
||||
typedef void *EGLImageKHR;
|
||||
typedef void *EGLLabelKHR;
|
||||
typedef void *EGLObjectKHR;
|
||||
typedef void *EGLOutputLayerEXT;
|
||||
typedef void *EGLOutputPortEXT;
|
||||
typedef void *EGLStreamKHR;
|
||||
typedef void *EGLSurface;
|
||||
typedef void *EGLSync;
|
||||
typedef void *EGLSyncKHR;
|
||||
typedef void *EGLSyncNV;
|
||||
typedef void (*__eglMustCastToProperFunctionPointerType)(void);
|
||||
typedef khronos_utime_nanoseconds_t EGLTimeKHR;
|
||||
typedef khronos_utime_nanoseconds_t EGLTime;
|
||||
typedef khronos_utime_nanoseconds_t EGLTimeNV;
|
||||
typedef khronos_utime_nanoseconds_t EGLuint64NV;
|
||||
typedef khronos_uint64_t EGLuint64KHR;
|
||||
typedef khronos_stime_nanoseconds_t EGLnsecsANDROID;
|
||||
typedef int EGLNativeFileDescriptorKHR;
|
||||
typedef khronos_ssize_t EGLsizeiANDROID;
|
||||
typedef void (*EGLSetBlobFuncANDROID) (const void *key, EGLsizeiANDROID keySize, const void *value, EGLsizeiANDROID valueSize);
|
||||
typedef EGLsizeiANDROID (*EGLGetBlobFuncANDROID) (const void *key, EGLsizeiANDROID keySize, void *value, EGLsizeiANDROID valueSize);
|
||||
struct EGLClientPixmapHI {
|
||||
void *pData;
|
||||
EGLint iWidth;
|
||||
EGLint iHeight;
|
||||
EGLint iStride;
|
||||
};
|
||||
typedef void (GLAD_API_PTR *EGLDEBUGPROCKHR)(EGLenum error,const char *command,EGLint messageType,EGLLabelKHR threadLabel,EGLLabelKHR objectLabel,const char* message);
|
||||
#define PFNEGLBINDWAYLANDDISPLAYWL PFNEGLBINDWAYLANDDISPLAYWLPROC
|
||||
#define PFNEGLUNBINDWAYLANDDISPLAYWL PFNEGLUNBINDWAYLANDDISPLAYWLPROC
|
||||
#define PFNEGLQUERYWAYLANDBUFFERWL PFNEGLQUERYWAYLANDBUFFERWLPROC
|
||||
#define PFNEGLCREATEWAYLANDBUFFERFROMIMAGEWL PFNEGLCREATEWAYLANDBUFFERFROMIMAGEWLPROC
|
||||
|
||||
|
||||
#define EGL_VERSION_1_0 1
|
||||
GLAD_API_CALL int GLAD_EGL_VERSION_1_0;
|
||||
#define EGL_VERSION_1_1 1
|
||||
GLAD_API_CALL int GLAD_EGL_VERSION_1_1;
|
||||
#define EGL_VERSION_1_2 1
|
||||
GLAD_API_CALL int GLAD_EGL_VERSION_1_2;
|
||||
#define EGL_VERSION_1_3 1
|
||||
GLAD_API_CALL int GLAD_EGL_VERSION_1_3;
|
||||
#define EGL_VERSION_1_4 1
|
||||
GLAD_API_CALL int GLAD_EGL_VERSION_1_4;
|
||||
#define EGL_VERSION_1_5 1
|
||||
GLAD_API_CALL int GLAD_EGL_VERSION_1_5;
|
||||
|
||||
|
||||
typedef EGLBoolean (GLAD_API_PTR *PFNEGLBINDAPIPROC)(EGLenum api);
|
||||
typedef EGLBoolean (GLAD_API_PTR *PFNEGLBINDTEXIMAGEPROC)(EGLDisplay dpy, EGLSurface surface, EGLint buffer);
|
||||
typedef EGLBoolean (GLAD_API_PTR *PFNEGLCHOOSECONFIGPROC)(EGLDisplay dpy, const EGLint * attrib_list, EGLConfig * configs, EGLint config_size, EGLint * num_config);
|
||||
typedef EGLint (GLAD_API_PTR *PFNEGLCLIENTWAITSYNCPROC)(EGLDisplay dpy, EGLSync sync, EGLint flags, EGLTime timeout);
|
||||
typedef EGLBoolean (GLAD_API_PTR *PFNEGLCOPYBUFFERSPROC)(EGLDisplay dpy, EGLSurface surface, EGLNativePixmapType target);
|
||||
typedef EGLContext (GLAD_API_PTR *PFNEGLCREATECONTEXTPROC)(EGLDisplay dpy, EGLConfig config, EGLContext share_context, const EGLint * attrib_list);
|
||||
typedef EGLImage (GLAD_API_PTR *PFNEGLCREATEIMAGEPROC)(EGLDisplay dpy, EGLContext ctx, EGLenum target, EGLClientBuffer buffer, const EGLAttrib * attrib_list);
|
||||
typedef EGLSurface (GLAD_API_PTR *PFNEGLCREATEPBUFFERFROMCLIENTBUFFERPROC)(EGLDisplay dpy, EGLenum buftype, EGLClientBuffer buffer, EGLConfig config, const EGLint * attrib_list);
|
||||
typedef EGLSurface (GLAD_API_PTR *PFNEGLCREATEPBUFFERSURFACEPROC)(EGLDisplay dpy, EGLConfig config, const EGLint * attrib_list);
|
||||
typedef EGLSurface (GLAD_API_PTR *PFNEGLCREATEPIXMAPSURFACEPROC)(EGLDisplay dpy, EGLConfig config, EGLNativePixmapType pixmap, const EGLint * attrib_list);
|
||||
typedef EGLSurface (GLAD_API_PTR *PFNEGLCREATEPLATFORMPIXMAPSURFACEPROC)(EGLDisplay dpy, EGLConfig config, void * native_pixmap, const EGLAttrib * attrib_list);
|
||||
typedef EGLSurface (GLAD_API_PTR *PFNEGLCREATEPLATFORMWINDOWSURFACEPROC)(EGLDisplay dpy, EGLConfig config, void * native_window, const EGLAttrib * attrib_list);
|
||||
typedef EGLSync (GLAD_API_PTR *PFNEGLCREATESYNCPROC)(EGLDisplay dpy, EGLenum type, const EGLAttrib * attrib_list);
|
||||
typedef EGLSurface (GLAD_API_PTR *PFNEGLCREATEWINDOWSURFACEPROC)(EGLDisplay dpy, EGLConfig config, EGLNativeWindowType win, const EGLint * attrib_list);
|
||||
typedef EGLBoolean (GLAD_API_PTR *PFNEGLDESTROYCONTEXTPROC)(EGLDisplay dpy, EGLContext ctx);
|
||||
typedef EGLBoolean (GLAD_API_PTR *PFNEGLDESTROYIMAGEPROC)(EGLDisplay dpy, EGLImage image);
|
||||
typedef EGLBoolean (GLAD_API_PTR *PFNEGLDESTROYSURFACEPROC)(EGLDisplay dpy, EGLSurface surface);
|
||||
typedef EGLBoolean (GLAD_API_PTR *PFNEGLDESTROYSYNCPROC)(EGLDisplay dpy, EGLSync sync);
|
||||
typedef EGLBoolean (GLAD_API_PTR *PFNEGLGETCONFIGATTRIBPROC)(EGLDisplay dpy, EGLConfig config, EGLint attribute, EGLint * value);
|
||||
typedef EGLBoolean (GLAD_API_PTR *PFNEGLGETCONFIGSPROC)(EGLDisplay dpy, EGLConfig * configs, EGLint config_size, EGLint * num_config);
|
||||
typedef EGLContext (GLAD_API_PTR *PFNEGLGETCURRENTCONTEXTPROC)(void);
|
||||
typedef EGLDisplay (GLAD_API_PTR *PFNEGLGETCURRENTDISPLAYPROC)(void);
|
||||
typedef EGLSurface (GLAD_API_PTR *PFNEGLGETCURRENTSURFACEPROC)(EGLint readdraw);
|
||||
typedef EGLDisplay (GLAD_API_PTR *PFNEGLGETDISPLAYPROC)(EGLNativeDisplayType display_id);
|
||||
typedef EGLint (GLAD_API_PTR *PFNEGLGETERRORPROC)(void);
|
||||
typedef EGLDisplay (GLAD_API_PTR *PFNEGLGETPLATFORMDISPLAYPROC)(EGLenum platform, void * native_display, const EGLAttrib * attrib_list);
|
||||
typedef __eglMustCastToProperFunctionPointerType (GLAD_API_PTR *PFNEGLGETPROCADDRESSPROC)(const char * procname);
|
||||
typedef EGLBoolean (GLAD_API_PTR *PFNEGLGETSYNCATTRIBPROC)(EGLDisplay dpy, EGLSync sync, EGLint attribute, EGLAttrib * value);
|
||||
typedef EGLBoolean (GLAD_API_PTR *PFNEGLINITIALIZEPROC)(EGLDisplay dpy, EGLint * major, EGLint * minor);
|
||||
typedef EGLBoolean (GLAD_API_PTR *PFNEGLMAKECURRENTPROC)(EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLContext ctx);
|
||||
typedef EGLenum (GLAD_API_PTR *PFNEGLQUERYAPIPROC)(void);
|
||||
typedef EGLBoolean (GLAD_API_PTR *PFNEGLQUERYCONTEXTPROC)(EGLDisplay dpy, EGLContext ctx, EGLint attribute, EGLint * value);
|
||||
typedef const char * (GLAD_API_PTR *PFNEGLQUERYSTRINGPROC)(EGLDisplay dpy, EGLint name);
|
||||
typedef EGLBoolean (GLAD_API_PTR *PFNEGLQUERYSURFACEPROC)(EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint * value);
|
||||
typedef EGLBoolean (GLAD_API_PTR *PFNEGLRELEASETEXIMAGEPROC)(EGLDisplay dpy, EGLSurface surface, EGLint buffer);
|
||||
typedef EGLBoolean (GLAD_API_PTR *PFNEGLRELEASETHREADPROC)(void);
|
||||
typedef EGLBoolean (GLAD_API_PTR *PFNEGLSURFACEATTRIBPROC)(EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint value);
|
||||
typedef EGLBoolean (GLAD_API_PTR *PFNEGLSWAPBUFFERSPROC)(EGLDisplay dpy, EGLSurface surface);
|
||||
typedef EGLBoolean (GLAD_API_PTR *PFNEGLSWAPINTERVALPROC)(EGLDisplay dpy, EGLint interval);
|
||||
typedef EGLBoolean (GLAD_API_PTR *PFNEGLTERMINATEPROC)(EGLDisplay dpy);
|
||||
typedef EGLBoolean (GLAD_API_PTR *PFNEGLWAITCLIENTPROC)(void);
|
||||
typedef EGLBoolean (GLAD_API_PTR *PFNEGLWAITGLPROC)(void);
|
||||
typedef EGLBoolean (GLAD_API_PTR *PFNEGLWAITNATIVEPROC)(EGLint engine);
|
||||
typedef EGLBoolean (GLAD_API_PTR *PFNEGLWAITSYNCPROC)(EGLDisplay dpy, EGLSync sync, EGLint flags);
|
||||
|
||||
GLAD_API_CALL PFNEGLBINDAPIPROC glad_eglBindAPI;
|
||||
#define eglBindAPI glad_eglBindAPI
|
||||
GLAD_API_CALL PFNEGLBINDTEXIMAGEPROC glad_eglBindTexImage;
|
||||
#define eglBindTexImage glad_eglBindTexImage
|
||||
GLAD_API_CALL PFNEGLCHOOSECONFIGPROC glad_eglChooseConfig;
|
||||
#define eglChooseConfig glad_eglChooseConfig
|
||||
GLAD_API_CALL PFNEGLCLIENTWAITSYNCPROC glad_eglClientWaitSync;
|
||||
#define eglClientWaitSync glad_eglClientWaitSync
|
||||
GLAD_API_CALL PFNEGLCOPYBUFFERSPROC glad_eglCopyBuffers;
|
||||
#define eglCopyBuffers glad_eglCopyBuffers
|
||||
GLAD_API_CALL PFNEGLCREATECONTEXTPROC glad_eglCreateContext;
|
||||
#define eglCreateContext glad_eglCreateContext
|
||||
GLAD_API_CALL PFNEGLCREATEIMAGEPROC glad_eglCreateImage;
|
||||
#define eglCreateImage glad_eglCreateImage
|
||||
GLAD_API_CALL PFNEGLCREATEPBUFFERFROMCLIENTBUFFERPROC glad_eglCreatePbufferFromClientBuffer;
|
||||
#define eglCreatePbufferFromClientBuffer glad_eglCreatePbufferFromClientBuffer
|
||||
GLAD_API_CALL PFNEGLCREATEPBUFFERSURFACEPROC glad_eglCreatePbufferSurface;
|
||||
#define eglCreatePbufferSurface glad_eglCreatePbufferSurface
|
||||
GLAD_API_CALL PFNEGLCREATEPIXMAPSURFACEPROC glad_eglCreatePixmapSurface;
|
||||
#define eglCreatePixmapSurface glad_eglCreatePixmapSurface
|
||||
GLAD_API_CALL PFNEGLCREATEPLATFORMPIXMAPSURFACEPROC glad_eglCreatePlatformPixmapSurface;
|
||||
#define eglCreatePlatformPixmapSurface glad_eglCreatePlatformPixmapSurface
|
||||
GLAD_API_CALL PFNEGLCREATEPLATFORMWINDOWSURFACEPROC glad_eglCreatePlatformWindowSurface;
|
||||
#define eglCreatePlatformWindowSurface glad_eglCreatePlatformWindowSurface
|
||||
GLAD_API_CALL PFNEGLCREATESYNCPROC glad_eglCreateSync;
|
||||
#define eglCreateSync glad_eglCreateSync
|
||||
GLAD_API_CALL PFNEGLCREATEWINDOWSURFACEPROC glad_eglCreateWindowSurface;
|
||||
#define eglCreateWindowSurface glad_eglCreateWindowSurface
|
||||
GLAD_API_CALL PFNEGLDESTROYCONTEXTPROC glad_eglDestroyContext;
|
||||
#define eglDestroyContext glad_eglDestroyContext
|
||||
GLAD_API_CALL PFNEGLDESTROYIMAGEPROC glad_eglDestroyImage;
|
||||
#define eglDestroyImage glad_eglDestroyImage
|
||||
GLAD_API_CALL PFNEGLDESTROYSURFACEPROC glad_eglDestroySurface;
|
||||
#define eglDestroySurface glad_eglDestroySurface
|
||||
GLAD_API_CALL PFNEGLDESTROYSYNCPROC glad_eglDestroySync;
|
||||
#define eglDestroySync glad_eglDestroySync
|
||||
GLAD_API_CALL PFNEGLGETCONFIGATTRIBPROC glad_eglGetConfigAttrib;
|
||||
#define eglGetConfigAttrib glad_eglGetConfigAttrib
|
||||
GLAD_API_CALL PFNEGLGETCONFIGSPROC glad_eglGetConfigs;
|
||||
#define eglGetConfigs glad_eglGetConfigs
|
||||
GLAD_API_CALL PFNEGLGETCURRENTCONTEXTPROC glad_eglGetCurrentContext;
|
||||
#define eglGetCurrentContext glad_eglGetCurrentContext
|
||||
GLAD_API_CALL PFNEGLGETCURRENTDISPLAYPROC glad_eglGetCurrentDisplay;
|
||||
#define eglGetCurrentDisplay glad_eglGetCurrentDisplay
|
||||
GLAD_API_CALL PFNEGLGETCURRENTSURFACEPROC glad_eglGetCurrentSurface;
|
||||
#define eglGetCurrentSurface glad_eglGetCurrentSurface
|
||||
GLAD_API_CALL PFNEGLGETDISPLAYPROC glad_eglGetDisplay;
|
||||
#define eglGetDisplay glad_eglGetDisplay
|
||||
GLAD_API_CALL PFNEGLGETERRORPROC glad_eglGetError;
|
||||
#define eglGetError glad_eglGetError
|
||||
GLAD_API_CALL PFNEGLGETPLATFORMDISPLAYPROC glad_eglGetPlatformDisplay;
|
||||
#define eglGetPlatformDisplay glad_eglGetPlatformDisplay
|
||||
GLAD_API_CALL PFNEGLGETPROCADDRESSPROC glad_eglGetProcAddress;
|
||||
#define eglGetProcAddress glad_eglGetProcAddress
|
||||
GLAD_API_CALL PFNEGLGETSYNCATTRIBPROC glad_eglGetSyncAttrib;
|
||||
#define eglGetSyncAttrib glad_eglGetSyncAttrib
|
||||
GLAD_API_CALL PFNEGLINITIALIZEPROC glad_eglInitialize;
|
||||
#define eglInitialize glad_eglInitialize
|
||||
GLAD_API_CALL PFNEGLMAKECURRENTPROC glad_eglMakeCurrent;
|
||||
#define eglMakeCurrent glad_eglMakeCurrent
|
||||
GLAD_API_CALL PFNEGLQUERYAPIPROC glad_eglQueryAPI;
|
||||
#define eglQueryAPI glad_eglQueryAPI
|
||||
GLAD_API_CALL PFNEGLQUERYCONTEXTPROC glad_eglQueryContext;
|
||||
#define eglQueryContext glad_eglQueryContext
|
||||
GLAD_API_CALL PFNEGLQUERYSTRINGPROC glad_eglQueryString;
|
||||
#define eglQueryString glad_eglQueryString
|
||||
GLAD_API_CALL PFNEGLQUERYSURFACEPROC glad_eglQuerySurface;
|
||||
#define eglQuerySurface glad_eglQuerySurface
|
||||
GLAD_API_CALL PFNEGLRELEASETEXIMAGEPROC glad_eglReleaseTexImage;
|
||||
#define eglReleaseTexImage glad_eglReleaseTexImage
|
||||
GLAD_API_CALL PFNEGLRELEASETHREADPROC glad_eglReleaseThread;
|
||||
#define eglReleaseThread glad_eglReleaseThread
|
||||
GLAD_API_CALL PFNEGLSURFACEATTRIBPROC glad_eglSurfaceAttrib;
|
||||
#define eglSurfaceAttrib glad_eglSurfaceAttrib
|
||||
GLAD_API_CALL PFNEGLSWAPBUFFERSPROC glad_eglSwapBuffers;
|
||||
#define eglSwapBuffers glad_eglSwapBuffers
|
||||
GLAD_API_CALL PFNEGLSWAPINTERVALPROC glad_eglSwapInterval;
|
||||
#define eglSwapInterval glad_eglSwapInterval
|
||||
GLAD_API_CALL PFNEGLTERMINATEPROC glad_eglTerminate;
|
||||
#define eglTerminate glad_eglTerminate
|
||||
GLAD_API_CALL PFNEGLWAITCLIENTPROC glad_eglWaitClient;
|
||||
#define eglWaitClient glad_eglWaitClient
|
||||
GLAD_API_CALL PFNEGLWAITGLPROC glad_eglWaitGL;
|
||||
#define eglWaitGL glad_eglWaitGL
|
||||
GLAD_API_CALL PFNEGLWAITNATIVEPROC glad_eglWaitNative;
|
||||
#define eglWaitNative glad_eglWaitNative
|
||||
GLAD_API_CALL PFNEGLWAITSYNCPROC glad_eglWaitSync;
|
||||
#define eglWaitSync glad_eglWaitSync
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
GLAD_API_CALL int gladLoadEGLUserPtr(EGLDisplay display, GLADuserptrloadfunc load, void *userptr);
|
||||
GLAD_API_CALL int gladLoadEGL(EGLDisplay display, GLADloadfunc load);
|
||||
|
||||
#ifdef GLAD_EGL
|
||||
|
||||
GLAD_API_CALL int gladLoaderLoadEGL(EGLDisplay display);
|
||||
|
||||
GLAD_API_CALL void gladLoaderUnloadEGL(void);
|
||||
|
||||
#endif
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,397 @@
|
||||
/**
|
||||
* SPDX-License-Identifier: (WTFPL OR CC0-1.0) AND Apache-2.0
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <glad/egl.h>
|
||||
|
||||
#ifndef GLAD_IMPL_UTIL_C_
|
||||
#define GLAD_IMPL_UTIL_C_
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#define GLAD_IMPL_UTIL_SSCANF sscanf_s
|
||||
#else
|
||||
#define GLAD_IMPL_UTIL_SSCANF sscanf
|
||||
#endif
|
||||
|
||||
#endif /* GLAD_IMPL_UTIL_C_ */
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
int GLAD_EGL_VERSION_1_0 = 0;
|
||||
int GLAD_EGL_VERSION_1_1 = 0;
|
||||
int GLAD_EGL_VERSION_1_2 = 0;
|
||||
int GLAD_EGL_VERSION_1_3 = 0;
|
||||
int GLAD_EGL_VERSION_1_4 = 0;
|
||||
int GLAD_EGL_VERSION_1_5 = 0;
|
||||
|
||||
|
||||
|
||||
PFNEGLBINDAPIPROC glad_eglBindAPI = NULL;
|
||||
PFNEGLBINDTEXIMAGEPROC glad_eglBindTexImage = NULL;
|
||||
PFNEGLCHOOSECONFIGPROC glad_eglChooseConfig = NULL;
|
||||
PFNEGLCLIENTWAITSYNCPROC glad_eglClientWaitSync = NULL;
|
||||
PFNEGLCOPYBUFFERSPROC glad_eglCopyBuffers = NULL;
|
||||
PFNEGLCREATECONTEXTPROC glad_eglCreateContext = NULL;
|
||||
PFNEGLCREATEIMAGEPROC glad_eglCreateImage = NULL;
|
||||
PFNEGLCREATEPBUFFERFROMCLIENTBUFFERPROC glad_eglCreatePbufferFromClientBuffer = NULL;
|
||||
PFNEGLCREATEPBUFFERSURFACEPROC glad_eglCreatePbufferSurface = NULL;
|
||||
PFNEGLCREATEPIXMAPSURFACEPROC glad_eglCreatePixmapSurface = NULL;
|
||||
PFNEGLCREATEPLATFORMPIXMAPSURFACEPROC glad_eglCreatePlatformPixmapSurface = NULL;
|
||||
PFNEGLCREATEPLATFORMWINDOWSURFACEPROC glad_eglCreatePlatformWindowSurface = NULL;
|
||||
PFNEGLCREATESYNCPROC glad_eglCreateSync = NULL;
|
||||
PFNEGLCREATEWINDOWSURFACEPROC glad_eglCreateWindowSurface = NULL;
|
||||
PFNEGLDESTROYCONTEXTPROC glad_eglDestroyContext = NULL;
|
||||
PFNEGLDESTROYIMAGEPROC glad_eglDestroyImage = NULL;
|
||||
PFNEGLDESTROYSURFACEPROC glad_eglDestroySurface = NULL;
|
||||
PFNEGLDESTROYSYNCPROC glad_eglDestroySync = NULL;
|
||||
PFNEGLGETCONFIGATTRIBPROC glad_eglGetConfigAttrib = NULL;
|
||||
PFNEGLGETCONFIGSPROC glad_eglGetConfigs = NULL;
|
||||
PFNEGLGETCURRENTCONTEXTPROC glad_eglGetCurrentContext = NULL;
|
||||
PFNEGLGETCURRENTDISPLAYPROC glad_eglGetCurrentDisplay = NULL;
|
||||
PFNEGLGETCURRENTSURFACEPROC glad_eglGetCurrentSurface = NULL;
|
||||
PFNEGLGETDISPLAYPROC glad_eglGetDisplay = NULL;
|
||||
PFNEGLGETERRORPROC glad_eglGetError = NULL;
|
||||
PFNEGLGETPLATFORMDISPLAYPROC glad_eglGetPlatformDisplay = NULL;
|
||||
PFNEGLGETPROCADDRESSPROC glad_eglGetProcAddress = NULL;
|
||||
PFNEGLGETSYNCATTRIBPROC glad_eglGetSyncAttrib = NULL;
|
||||
PFNEGLINITIALIZEPROC glad_eglInitialize = NULL;
|
||||
PFNEGLMAKECURRENTPROC glad_eglMakeCurrent = NULL;
|
||||
PFNEGLQUERYAPIPROC glad_eglQueryAPI = NULL;
|
||||
PFNEGLQUERYCONTEXTPROC glad_eglQueryContext = NULL;
|
||||
PFNEGLQUERYSTRINGPROC glad_eglQueryString = NULL;
|
||||
PFNEGLQUERYSURFACEPROC glad_eglQuerySurface = NULL;
|
||||
PFNEGLRELEASETEXIMAGEPROC glad_eglReleaseTexImage = NULL;
|
||||
PFNEGLRELEASETHREADPROC glad_eglReleaseThread = NULL;
|
||||
PFNEGLSURFACEATTRIBPROC glad_eglSurfaceAttrib = NULL;
|
||||
PFNEGLSWAPBUFFERSPROC glad_eglSwapBuffers = NULL;
|
||||
PFNEGLSWAPINTERVALPROC glad_eglSwapInterval = NULL;
|
||||
PFNEGLTERMINATEPROC glad_eglTerminate = NULL;
|
||||
PFNEGLWAITCLIENTPROC glad_eglWaitClient = NULL;
|
||||
PFNEGLWAITGLPROC glad_eglWaitGL = NULL;
|
||||
PFNEGLWAITNATIVEPROC glad_eglWaitNative = NULL;
|
||||
PFNEGLWAITSYNCPROC glad_eglWaitSync = NULL;
|
||||
|
||||
|
||||
static void glad_egl_load_EGL_VERSION_1_0( GLADuserptrloadfunc load, void* userptr) {
|
||||
if(!GLAD_EGL_VERSION_1_0) return;
|
||||
glad_eglChooseConfig = (PFNEGLCHOOSECONFIGPROC) load(userptr, "eglChooseConfig");
|
||||
glad_eglCopyBuffers = (PFNEGLCOPYBUFFERSPROC) load(userptr, "eglCopyBuffers");
|
||||
glad_eglCreateContext = (PFNEGLCREATECONTEXTPROC) load(userptr, "eglCreateContext");
|
||||
glad_eglCreatePbufferSurface = (PFNEGLCREATEPBUFFERSURFACEPROC) load(userptr, "eglCreatePbufferSurface");
|
||||
glad_eglCreatePixmapSurface = (PFNEGLCREATEPIXMAPSURFACEPROC) load(userptr, "eglCreatePixmapSurface");
|
||||
glad_eglCreateWindowSurface = (PFNEGLCREATEWINDOWSURFACEPROC) load(userptr, "eglCreateWindowSurface");
|
||||
glad_eglDestroyContext = (PFNEGLDESTROYCONTEXTPROC) load(userptr, "eglDestroyContext");
|
||||
glad_eglDestroySurface = (PFNEGLDESTROYSURFACEPROC) load(userptr, "eglDestroySurface");
|
||||
glad_eglGetConfigAttrib = (PFNEGLGETCONFIGATTRIBPROC) load(userptr, "eglGetConfigAttrib");
|
||||
glad_eglGetConfigs = (PFNEGLGETCONFIGSPROC) load(userptr, "eglGetConfigs");
|
||||
glad_eglGetCurrentDisplay = (PFNEGLGETCURRENTDISPLAYPROC) load(userptr, "eglGetCurrentDisplay");
|
||||
glad_eglGetCurrentSurface = (PFNEGLGETCURRENTSURFACEPROC) load(userptr, "eglGetCurrentSurface");
|
||||
glad_eglGetDisplay = (PFNEGLGETDISPLAYPROC) load(userptr, "eglGetDisplay");
|
||||
glad_eglGetError = (PFNEGLGETERRORPROC) load(userptr, "eglGetError");
|
||||
glad_eglGetProcAddress = (PFNEGLGETPROCADDRESSPROC) load(userptr, "eglGetProcAddress");
|
||||
glad_eglInitialize = (PFNEGLINITIALIZEPROC) load(userptr, "eglInitialize");
|
||||
glad_eglMakeCurrent = (PFNEGLMAKECURRENTPROC) load(userptr, "eglMakeCurrent");
|
||||
glad_eglQueryContext = (PFNEGLQUERYCONTEXTPROC) load(userptr, "eglQueryContext");
|
||||
glad_eglQueryString = (PFNEGLQUERYSTRINGPROC) load(userptr, "eglQueryString");
|
||||
glad_eglQuerySurface = (PFNEGLQUERYSURFACEPROC) load(userptr, "eglQuerySurface");
|
||||
glad_eglSwapBuffers = (PFNEGLSWAPBUFFERSPROC) load(userptr, "eglSwapBuffers");
|
||||
glad_eglTerminate = (PFNEGLTERMINATEPROC) load(userptr, "eglTerminate");
|
||||
glad_eglWaitGL = (PFNEGLWAITGLPROC) load(userptr, "eglWaitGL");
|
||||
glad_eglWaitNative = (PFNEGLWAITNATIVEPROC) load(userptr, "eglWaitNative");
|
||||
}
|
||||
static void glad_egl_load_EGL_VERSION_1_1( GLADuserptrloadfunc load, void* userptr) {
|
||||
if(!GLAD_EGL_VERSION_1_1) return;
|
||||
glad_eglBindTexImage = (PFNEGLBINDTEXIMAGEPROC) load(userptr, "eglBindTexImage");
|
||||
glad_eglReleaseTexImage = (PFNEGLRELEASETEXIMAGEPROC) load(userptr, "eglReleaseTexImage");
|
||||
glad_eglSurfaceAttrib = (PFNEGLSURFACEATTRIBPROC) load(userptr, "eglSurfaceAttrib");
|
||||
glad_eglSwapInterval = (PFNEGLSWAPINTERVALPROC) load(userptr, "eglSwapInterval");
|
||||
}
|
||||
static void glad_egl_load_EGL_VERSION_1_2( GLADuserptrloadfunc load, void* userptr) {
|
||||
if(!GLAD_EGL_VERSION_1_2) return;
|
||||
glad_eglBindAPI = (PFNEGLBINDAPIPROC) load(userptr, "eglBindAPI");
|
||||
glad_eglCreatePbufferFromClientBuffer = (PFNEGLCREATEPBUFFERFROMCLIENTBUFFERPROC) load(userptr, "eglCreatePbufferFromClientBuffer");
|
||||
glad_eglQueryAPI = (PFNEGLQUERYAPIPROC) load(userptr, "eglQueryAPI");
|
||||
glad_eglReleaseThread = (PFNEGLRELEASETHREADPROC) load(userptr, "eglReleaseThread");
|
||||
glad_eglWaitClient = (PFNEGLWAITCLIENTPROC) load(userptr, "eglWaitClient");
|
||||
}
|
||||
static void glad_egl_load_EGL_VERSION_1_4( GLADuserptrloadfunc load, void* userptr) {
|
||||
if(!GLAD_EGL_VERSION_1_4) return;
|
||||
glad_eglGetCurrentContext = (PFNEGLGETCURRENTCONTEXTPROC) load(userptr, "eglGetCurrentContext");
|
||||
}
|
||||
static void glad_egl_load_EGL_VERSION_1_5( GLADuserptrloadfunc load, void* userptr) {
|
||||
if(!GLAD_EGL_VERSION_1_5) return;
|
||||
glad_eglClientWaitSync = (PFNEGLCLIENTWAITSYNCPROC) load(userptr, "eglClientWaitSync");
|
||||
glad_eglCreateImage = (PFNEGLCREATEIMAGEPROC) load(userptr, "eglCreateImage");
|
||||
glad_eglCreatePlatformPixmapSurface = (PFNEGLCREATEPLATFORMPIXMAPSURFACEPROC) load(userptr, "eglCreatePlatformPixmapSurface");
|
||||
glad_eglCreatePlatformWindowSurface = (PFNEGLCREATEPLATFORMWINDOWSURFACEPROC) load(userptr, "eglCreatePlatformWindowSurface");
|
||||
glad_eglCreateSync = (PFNEGLCREATESYNCPROC) load(userptr, "eglCreateSync");
|
||||
glad_eglDestroyImage = (PFNEGLDESTROYIMAGEPROC) load(userptr, "eglDestroyImage");
|
||||
glad_eglDestroySync = (PFNEGLDESTROYSYNCPROC) load(userptr, "eglDestroySync");
|
||||
glad_eglGetPlatformDisplay = (PFNEGLGETPLATFORMDISPLAYPROC) load(userptr, "eglGetPlatformDisplay");
|
||||
glad_eglGetSyncAttrib = (PFNEGLGETSYNCATTRIBPROC) load(userptr, "eglGetSyncAttrib");
|
||||
glad_eglWaitSync = (PFNEGLWAITSYNCPROC) load(userptr, "eglWaitSync");
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int glad_egl_get_extensions(EGLDisplay display, const char **extensions) {
|
||||
*extensions = eglQueryString(display, EGL_EXTENSIONS);
|
||||
|
||||
return extensions != NULL;
|
||||
}
|
||||
|
||||
static int glad_egl_has_extension(const char *extensions, const char *ext) {
|
||||
const char *loc;
|
||||
const char *terminator;
|
||||
if(extensions == NULL) {
|
||||
return 0;
|
||||
}
|
||||
while(1) {
|
||||
loc = strstr(extensions, ext);
|
||||
if(loc == NULL) {
|
||||
return 0;
|
||||
}
|
||||
terminator = loc + strlen(ext);
|
||||
if((loc == extensions || *(loc - 1) == ' ') &&
|
||||
(*terminator == ' ' || *terminator == '\0')) {
|
||||
return 1;
|
||||
}
|
||||
extensions = terminator;
|
||||
}
|
||||
}
|
||||
|
||||
static GLADapiproc glad_egl_get_proc_from_userptr(void *userptr, const char *name) {
|
||||
return (GLAD_GNUC_EXTENSION (GLADapiproc (*)(const char *name)) userptr)(name);
|
||||
}
|
||||
|
||||
static int glad_egl_find_extensions_egl(EGLDisplay display) {
|
||||
const char *extensions;
|
||||
if (!glad_egl_get_extensions(display, &extensions)) return 0;
|
||||
|
||||
GLAD_UNUSED(glad_egl_has_extension);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int glad_egl_find_core_egl(EGLDisplay display) {
|
||||
int major, minor;
|
||||
const char *version;
|
||||
|
||||
if (display == NULL) {
|
||||
display = EGL_NO_DISPLAY; /* this is usually NULL, better safe than sorry */
|
||||
}
|
||||
if (display == EGL_NO_DISPLAY) {
|
||||
display = eglGetCurrentDisplay();
|
||||
}
|
||||
#ifdef EGL_VERSION_1_4
|
||||
if (display == EGL_NO_DISPLAY) {
|
||||
display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
|
||||
}
|
||||
#endif
|
||||
#ifndef EGL_VERSION_1_5
|
||||
if (display == EGL_NO_DISPLAY) {
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
version = eglQueryString(display, EGL_VERSION);
|
||||
(void) eglGetError();
|
||||
|
||||
if (version == NULL) {
|
||||
major = 1;
|
||||
minor = 0;
|
||||
} else {
|
||||
GLAD_IMPL_UTIL_SSCANF(version, "%d.%d", &major, &minor);
|
||||
}
|
||||
|
||||
GLAD_EGL_VERSION_1_0 = (major == 1 && minor >= 0) || major > 1;
|
||||
GLAD_EGL_VERSION_1_1 = (major == 1 && minor >= 1) || major > 1;
|
||||
GLAD_EGL_VERSION_1_2 = (major == 1 && minor >= 2) || major > 1;
|
||||
GLAD_EGL_VERSION_1_3 = (major == 1 && minor >= 3) || major > 1;
|
||||
GLAD_EGL_VERSION_1_4 = (major == 1 && minor >= 4) || major > 1;
|
||||
GLAD_EGL_VERSION_1_5 = (major == 1 && minor >= 5) || major > 1;
|
||||
|
||||
return GLAD_MAKE_VERSION(major, minor);
|
||||
}
|
||||
|
||||
int gladLoadEGLUserPtr(EGLDisplay display, GLADuserptrloadfunc load, void* userptr) {
|
||||
int version;
|
||||
eglGetDisplay = (PFNEGLGETDISPLAYPROC) load(userptr, "eglGetDisplay");
|
||||
eglGetCurrentDisplay = (PFNEGLGETCURRENTDISPLAYPROC) load(userptr, "eglGetCurrentDisplay");
|
||||
eglQueryString = (PFNEGLQUERYSTRINGPROC) load(userptr, "eglQueryString");
|
||||
eglGetError = (PFNEGLGETERRORPROC) load(userptr, "eglGetError");
|
||||
if (eglGetDisplay == NULL || eglGetCurrentDisplay == NULL || eglQueryString == NULL || eglGetError == NULL) return 0;
|
||||
|
||||
version = glad_egl_find_core_egl(display);
|
||||
if (!version) return 0;
|
||||
glad_egl_load_EGL_VERSION_1_0(load, userptr);
|
||||
glad_egl_load_EGL_VERSION_1_1(load, userptr);
|
||||
glad_egl_load_EGL_VERSION_1_2(load, userptr);
|
||||
glad_egl_load_EGL_VERSION_1_4(load, userptr);
|
||||
glad_egl_load_EGL_VERSION_1_5(load, userptr);
|
||||
|
||||
if (!glad_egl_find_extensions_egl(display)) return 0;
|
||||
|
||||
|
||||
return version;
|
||||
}
|
||||
|
||||
int gladLoadEGL(EGLDisplay display, GLADloadfunc load) {
|
||||
return gladLoadEGLUserPtr(display, glad_egl_get_proc_from_userptr, GLAD_GNUC_EXTENSION (void*) load);
|
||||
}
|
||||
|
||||
|
||||
|
||||
#ifdef GLAD_EGL
|
||||
|
||||
#ifndef GLAD_LOADER_LIBRARY_C_
|
||||
#define GLAD_LOADER_LIBRARY_C_
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#if GLAD_PLATFORM_WIN32
|
||||
#include <windows.h>
|
||||
#else
|
||||
#include <dlfcn.h>
|
||||
#endif
|
||||
|
||||
|
||||
static void* glad_get_dlopen_handle(const char *lib_names[], int length) {
|
||||
void *handle = NULL;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < length; ++i) {
|
||||
#if GLAD_PLATFORM_WIN32
|
||||
#if GLAD_PLATFORM_UWP
|
||||
size_t buffer_size = (strlen(lib_names[i]) + 1) * sizeof(WCHAR);
|
||||
LPWSTR buffer = (LPWSTR) malloc(buffer_size);
|
||||
if (buffer != NULL) {
|
||||
int ret = MultiByteToWideChar(CP_ACP, 0, lib_names[i], -1, buffer, buffer_size);
|
||||
if (ret != 0) {
|
||||
handle = (void*) LoadPackagedLibrary(buffer, 0);
|
||||
}
|
||||
free((void*) buffer);
|
||||
}
|
||||
#else
|
||||
handle = (void*) LoadLibraryA(lib_names[i]);
|
||||
#endif
|
||||
#else
|
||||
handle = dlopen(lib_names[i], RTLD_LAZY | RTLD_LOCAL);
|
||||
#endif
|
||||
if (handle != NULL) {
|
||||
return handle;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void glad_close_dlopen_handle(void* handle) {
|
||||
if (handle != NULL) {
|
||||
#if GLAD_PLATFORM_WIN32
|
||||
FreeLibrary((HMODULE) handle);
|
||||
#else
|
||||
dlclose(handle);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
static GLADapiproc glad_dlsym_handle(void* handle, const char *name) {
|
||||
if (handle == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#if GLAD_PLATFORM_WIN32
|
||||
return (GLADapiproc) GetProcAddress((HMODULE) handle, name);
|
||||
#else
|
||||
return GLAD_GNUC_EXTENSION (GLADapiproc) dlsym(handle, name);
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif /* GLAD_LOADER_LIBRARY_C_ */
|
||||
|
||||
struct _glad_egl_userptr {
|
||||
void *handle;
|
||||
PFNEGLGETPROCADDRESSPROC get_proc_address_ptr;
|
||||
};
|
||||
|
||||
static GLADapiproc glad_egl_get_proc(void *vuserptr, const char* name) {
|
||||
struct _glad_egl_userptr userptr = *(struct _glad_egl_userptr*) vuserptr;
|
||||
GLADapiproc result = NULL;
|
||||
|
||||
result = glad_dlsym_handle(userptr.handle, name);
|
||||
if (result == NULL) {
|
||||
result = GLAD_GNUC_EXTENSION (GLADapiproc) userptr.get_proc_address_ptr(name);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static void* _egl_handle = NULL;
|
||||
|
||||
static void* glad_egl_dlopen_handle(void) {
|
||||
#if GLAD_PLATFORM_APPLE
|
||||
static const char *NAMES[] = {"libEGL.dylib"};
|
||||
#elif GLAD_PLATFORM_WIN32
|
||||
static const char *NAMES[] = {"libEGL.dll", "EGL.dll"};
|
||||
#else
|
||||
static const char *NAMES[] = {"libEGL.so.1", "libEGL.so"};
|
||||
#endif
|
||||
|
||||
if (_egl_handle == NULL) {
|
||||
_egl_handle = glad_get_dlopen_handle(NAMES, sizeof(NAMES) / sizeof(NAMES[0]));
|
||||
}
|
||||
|
||||
return _egl_handle;
|
||||
}
|
||||
|
||||
static struct _glad_egl_userptr glad_egl_build_userptr(void *handle) {
|
||||
struct _glad_egl_userptr userptr;
|
||||
userptr.handle = handle;
|
||||
userptr.get_proc_address_ptr = (PFNEGLGETPROCADDRESSPROC) glad_dlsym_handle(handle, "eglGetProcAddress");
|
||||
return userptr;
|
||||
}
|
||||
|
||||
int gladLoaderLoadEGL(EGLDisplay display) {
|
||||
int version = 0;
|
||||
void *handle = NULL;
|
||||
int did_load = 0;
|
||||
struct _glad_egl_userptr userptr;
|
||||
|
||||
did_load = _egl_handle == NULL;
|
||||
handle = glad_egl_dlopen_handle();
|
||||
if (handle != NULL) {
|
||||
userptr = glad_egl_build_userptr(handle);
|
||||
|
||||
if (userptr.get_proc_address_ptr != NULL) {
|
||||
version = gladLoadEGLUserPtr(display, glad_egl_get_proc, &userptr);
|
||||
}
|
||||
|
||||
if (!version && did_load) {
|
||||
gladLoaderUnloadEGL();
|
||||
}
|
||||
}
|
||||
|
||||
return version;
|
||||
}
|
||||
|
||||
|
||||
void gladLoaderUnloadEGL() {
|
||||
if (_egl_handle != NULL) {
|
||||
glad_close_dlopen_handle(_egl_handle);
|
||||
_egl_handle = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* GLAD_EGL */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
+11173
File diff suppressed because it is too large.
Load diff
Submodule
+1
Submodule core/deps/glslang added at 76b52ebf77.
@@ -1,108 +0,0 @@
|
||||
# Windows Build Configuration for AppVeyor
|
||||
# http://www.appveyor.com/docs/appveyor-yml
|
||||
|
||||
# build version format
|
||||
version: "{build}"
|
||||
|
||||
os: Visual Studio 2013
|
||||
|
||||
platform:
|
||||
- x64
|
||||
|
||||
configuration:
|
||||
- Debug
|
||||
- Release
|
||||
|
||||
branches:
|
||||
only:
|
||||
- master
|
||||
|
||||
# changes to these files don't need to trigger testing
|
||||
skip_commits:
|
||||
files:
|
||||
- README.md
|
||||
- README-spirv-remap.txt
|
||||
- LICENSE.txt
|
||||
- CODE_OF_CONDUCT.md
|
||||
- BUILD.*
|
||||
- WORKSPACE
|
||||
- kokoro/*
|
||||
- make-revision
|
||||
- Android.mk
|
||||
- _config.yml
|
||||
|
||||
# Travis advances the master-tot tag to current top of the tree after
|
||||
# each push into the master branch, because it relies on that tag to
|
||||
# upload build artifacts to the master-tot release. This will cause
|
||||
# double testing for each push on Appveyor: one for the push, one for
|
||||
# the tag advance. Disable testing tags.
|
||||
skip_tags: true
|
||||
|
||||
clone_depth: 5
|
||||
|
||||
matrix:
|
||||
fast_finish: true # Show final status immediately if a test fails.
|
||||
|
||||
# scripts that run after cloning repository
|
||||
install:
|
||||
- C:/Python27/python.exe update_glslang_sources.py
|
||||
- set PATH=C:\ninja;C:\Python36;%PATH%
|
||||
- git clone https://github.com/google/googletest.git External/googletest
|
||||
- cd External/googletest
|
||||
- git checkout 440527a61e1c91188195f7de212c63c77e8f0a45
|
||||
- cd ../..
|
||||
|
||||
build:
|
||||
parallel: true # enable MSBuild parallel builds
|
||||
verbosity: minimal
|
||||
|
||||
build_script:
|
||||
- mkdir build && cd build
|
||||
- cmake -G "Visual Studio 12 2013 Win64" -DCMAKE_INSTALL_PREFIX=install ..
|
||||
- cmake --build . --config %CONFIGURATION% --target install
|
||||
|
||||
test_script:
|
||||
- ctest -C %CONFIGURATION% --output-on-failure
|
||||
- cd ../Test && bash runtests
|
||||
- cd ../build
|
||||
|
||||
after_test:
|
||||
# For debug build, the generated dll has a postfix "d" in its name.
|
||||
- ps: >-
|
||||
If ($env:configuration -Match "Debug") {
|
||||
$env:SUFFIX="d"
|
||||
} Else {
|
||||
$env:SUFFIX=""
|
||||
}
|
||||
- cd install
|
||||
# Zip all glslang artifacts for uploading and deploying
|
||||
- 7z a glslang-master-windows-"%PLATFORM%"-"%CONFIGURATION%".zip
|
||||
bin\glslangValidator.exe
|
||||
bin\spirv-remap.exe
|
||||
include\glslang\*
|
||||
lib\glslang%SUFFIX%.lib
|
||||
lib\HLSL%SUFFIX%.lib
|
||||
lib\OGLCompiler%SUFFIX%.lib
|
||||
lib\OSDependent%SUFFIX%.lib
|
||||
lib\SPIRV%SUFFIX%.lib
|
||||
lib\SPVRemapper%SUFFIX%.lib
|
||||
lib\SPIRV-Tools%SUFFIX%.lib
|
||||
lib\SPIRV-Tools-opt%SUFFIX%.lib
|
||||
|
||||
artifacts:
|
||||
- path: build\install\*.zip
|
||||
name: artifacts-zip
|
||||
|
||||
deploy:
|
||||
- provider: GitHub
|
||||
auth_token:
|
||||
secure: YglcSYdl0TylEa59H4K6lylBEDr586NAt2EMgZquSo+iuPrwgZQuJLPCoihSm9y6
|
||||
release: master-tot
|
||||
description: "Continuous build of the latest master branch by Appveyor and Travis CI"
|
||||
artifact: artifacts-zip
|
||||
draft: false
|
||||
prerelease: false
|
||||
force_update: true
|
||||
on:
|
||||
branch: master
|
||||
APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2013
|
||||
@@ -1,13 +0,0 @@
|
||||
Language: Cpp
|
||||
IndentWidth: 4
|
||||
PointerAlignment: Left
|
||||
BreakBeforeBraces: Custom
|
||||
BraceWrapping: { AfterFunction: true, AfterControlStatement: false }
|
||||
IndentCaseLabels: false
|
||||
ReflowComments: false
|
||||
ColumnLimit: 120
|
||||
AccessModifierOffset: -4
|
||||
AlignTrailingComments: true
|
||||
AllowShortBlocksOnASingleLine: false
|
||||
AllowShortIfStatementsOnASingleLine: false
|
||||
AllowShortLoopsOnASingleLine: false
|
||||
@@ -1,17 +0,0 @@
|
||||
# test files have a mix of lf/crlf, and that's a good thing, for testing, don't mess with it
|
||||
# bash scripts need lines ending with lf, and that's correct for Windows too, e.g., under Cygwin
|
||||
# (scripts often don't have a suffix)
|
||||
* -text
|
||||
*.sh text eof=lf
|
||||
|
||||
# txt files should be native and normalized
|
||||
*.txt text
|
||||
|
||||
# source code can be native and normalized, but simpler if lf everywhere; will try that way
|
||||
*.h text eol=lf
|
||||
*.c text eol=lf
|
||||
*.cpp text eol=lf
|
||||
*.y text eol=lf
|
||||
*.out text eol=lf
|
||||
*.conf text eol=lf
|
||||
*.err text eol=lf
|
||||
@@ -1,10 +0,0 @@
|
||||
*.o
|
||||
*.a
|
||||
*.so
|
||||
*.exe
|
||||
tags
|
||||
TAGS
|
||||
build/
|
||||
Test/localResults/
|
||||
External/googletest
|
||||
External/spirv-tools
|
||||
@@ -1,128 +0,0 @@
|
||||
# Linux and Mac Build Configuration for Travis
|
||||
|
||||
language: cpp
|
||||
|
||||
os:
|
||||
- linux
|
||||
- osx
|
||||
|
||||
# Use Ubuntu 14.04 LTS (Trusty) as the Linux testing environment.
|
||||
sudo: false
|
||||
dist: trusty
|
||||
|
||||
env:
|
||||
global:
|
||||
- secure: aGFrgzyKp+84hKrGkxVWg8cHV61uqrKEHT38gfSQK6+WS4GfLOyH83p7WnsEBb7AMhzU7LMNFdvOFr6+NaMpVnqRvc40CEG1Q+lNg9Pq9mhIZLowvDrfqTL9kQ+8Nbw5Q6/dg6CTvY7fvRfpfCEmKIUZBRkoKUuHeuM1uy3IupFcdNuL5bSYn3Beo+apSJginh9DI4BLDXFUgBzTRSLLyCX5g3cpaeGGOCr8quJlYx75W6HRck5g9SZuLtUoH9GFEV3l+ZEWB8noErW+J56L03bwNwFuuAh321evw++oQk5KFa8rlDvar3SJ3b1RHB8u/eq5DBYMyaK/fS8+Q7QbGr8diF/wDe68bKO7U9IhpNfExXmczCpExjHomW5TQv4rYdGhygPMfW97aIsPRYyNKcl4fkmb7NDrM8w0Jscdq2g5c2Kz0ItyZoBri/NXLwFQQjaVCs7Pf97TjuMA7mK0GJmDTRzi6SrDYlWMt5BQL3y0CCojyfLIRcTh0CQjQI29s97bLfQrYAxt9GNNFR+HTXRLLrkaAlJkPGEPwUywlSfEThnvHLesNxYqemolAYpQT4ithoL4GehGIHmaxsW295aKVhuRf8K9eBODNqrfblvM42UHhjntT+92ZnQ/Gkq80GqaMxnxi4PO5FyPIxt0r981b54YBkWi8YA4P7w5pNI=
|
||||
matrix:
|
||||
- GLSLANG_BUILD_TYPE=Release
|
||||
- GLSLANG_BUILD_TYPE=Debug
|
||||
|
||||
compiler:
|
||||
- clang
|
||||
- gcc
|
||||
|
||||
matrix:
|
||||
fast_finish: true # Show final status immediately if a test fails.
|
||||
exclude:
|
||||
# Skip GCC builds on Mac OS X.
|
||||
- os: osx
|
||||
compiler: gcc
|
||||
include:
|
||||
# Additional build using Android NDK.
|
||||
- env: BUILD_NDK=ON
|
||||
|
||||
cache:
|
||||
apt: true
|
||||
|
||||
branches:
|
||||
only:
|
||||
- master
|
||||
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- clang-3.6
|
||||
|
||||
install:
|
||||
# Make sure that clang-3.6 is selected on Linux.
|
||||
- if [[ "$TRAVIS_OS_NAME" == "linux" && "$CC" == "clang" ]]; then
|
||||
export CC=clang-3.6 CXX=clang++-3.6;
|
||||
fi
|
||||
# Download a recent Android NDK and use its android.toolchain.cmake file.
|
||||
- if [[ "$BUILD_NDK" == "ON" ]]; then
|
||||
export ANDROID_NDK=$HOME/android-ndk;
|
||||
git init $ANDROID_NDK;
|
||||
pushd $ANDROID_NDK;
|
||||
git remote add dneto0 https://github.com/dneto0/android-ndk.git;
|
||||
git fetch --depth=1 dneto0 r17b-strip;
|
||||
git checkout FETCH_HEAD;
|
||||
popd;
|
||||
export TOOLCHAIN_PATH=$ANDROID_NDK/build/cmake/android.toolchain.cmake;
|
||||
fi
|
||||
|
||||
before_script:
|
||||
- git clone --depth=1 https://github.com/google/googletest.git External/googletest
|
||||
- ./update_glslang_sources.py
|
||||
|
||||
script:
|
||||
- mkdir build && cd build
|
||||
# For Android, do release building using NDK without testing.
|
||||
# Use android-14, the oldest native API level supporeted by NDK r17b.
|
||||
# We can use newer API levels if we want.
|
||||
# For Linux and macOS, do debug/release building with testing.
|
||||
- if [[ "$BUILD_NDK" == "ON" ]]; then
|
||||
cmake -DCMAKE_TOOLCHAIN_FILE=${TOOLCHAIN_PATH}
|
||||
-DANDROID_NATIVE_API_LEVEL=android-14
|
||||
-DCMAKE_BUILD_TYPE=Release
|
||||
-DANDROID_ABI="armeabi-v7a with NEON"
|
||||
-DBUILD_TESTING=OFF ..;
|
||||
make -j4;
|
||||
else
|
||||
cmake -DCMAKE_BUILD_TYPE=${GLSLANG_BUILD_TYPE}
|
||||
-DCMAKE_INSTALL_PREFIX=`pwd`/install ..;
|
||||
make -j4 install;
|
||||
ctest --output-on-failure &&
|
||||
cd ../Test && ./runtests;
|
||||
fi
|
||||
|
||||
after_success:
|
||||
# For debug build, the generated dll has a postfix "d" in its name.
|
||||
- if [[ "${GLSLANG_BUILD_TYPE}" == "Debug" ]]; then
|
||||
export SUFFIX="d";
|
||||
else
|
||||
export SUFFIX="";
|
||||
fi
|
||||
# Create tarball for deployment
|
||||
- if [[ ${CC} == clang* && "${BUILD_NDK}" != "ON" ]]; then
|
||||
cd ../build/install;
|
||||
export TARBALL=glslang-master-${TRAVIS_OS_NAME}-${GLSLANG_BUILD_TYPE}.zip;
|
||||
zip ${TARBALL}
|
||||
bin/glslangValidator
|
||||
include/glslang/*
|
||||
lib/libglslang${SUFFIX}.a
|
||||
lib/libHLSL${SUFFIX}.a
|
||||
lib/libOGLCompiler${SUFFIX}.a
|
||||
lib/libOSDependent${SUFFIX}.a
|
||||
lib/libSPIRV${SUFFIX}.a
|
||||
lib/libSPVRemapper${SUFFIX}.a
|
||||
lib/libSPIRV-Tools${SUFFIX}.a
|
||||
lib/libSPIRV-Tools-opt${SUFFIX}.a;
|
||||
fi
|
||||
|
||||
before_deploy:
|
||||
# Tag the current top of the tree as "master-tot".
|
||||
# Travis CI replies on the tag name to properly push to GitHub Releases.
|
||||
- git config --global user.name "Travis CI"
|
||||
- git config --global user.email "[email protected]"
|
||||
- git tag -f master-tot
|
||||
- git push -q -f https://${glslangtoken}@github.com/KhronosGroup/glslang --tags
|
||||
|
||||
deploy:
|
||||
provider: releases
|
||||
api_key: ${glslangtoken}
|
||||
on:
|
||||
branch: master
|
||||
condition: ${CC} == clang* && ${BUILD_NDK} != ON
|
||||
file: ${TARBALL}
|
||||
skip_cleanup: true
|
||||
overwrite: true
|
||||
@@ -1,100 +0,0 @@
|
||||
LOCAL_PATH := $(call my-dir)
|
||||
|
||||
GLSLANG_OS_FLAGS := -DGLSLANG_OSINCLUDE_UNIX
|
||||
# AMD and NV extensions are turned on by default in upstream Glslang.
|
||||
GLSLANG_DEFINES:= -DAMD_EXTENSIONS -DNV_EXTENSIONS -DENABLE_HLSL $(GLSLANG_OS_FLAGS)
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
LOCAL_MODULE:=OSDependent
|
||||
LOCAL_CXXFLAGS:=-std=c++11 -fno-exceptions -fno-rtti $(GLSLANG_DEFINES)
|
||||
LOCAL_EXPORT_C_INCLUDES:=$(LOCAL_PATH)
|
||||
LOCAL_SRC_FILES:=glslang/OSDependent/Unix/ossource.cpp
|
||||
LOCAL_C_INCLUDES:=$(LOCAL_PATH) $(LOCAL_PATH)/glslang/OSDependent/Unix/
|
||||
LOCAL_EXPORT_C_INCLUDES:=$(LOCAL_PATH)/glslang/OSDependent/Unix/
|
||||
include $(BUILD_STATIC_LIBRARY)
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
LOCAL_MODULE:=OGLCompiler
|
||||
LOCAL_CXXFLAGS:=-std=c++11 -fno-exceptions -fno-rtti $(GLSLANG_DEFINES)
|
||||
LOCAL_EXPORT_C_INCLUDES:=$(LOCAL_PATH)
|
||||
LOCAL_SRC_FILES:=OGLCompilersDLL/InitializeDll.cpp
|
||||
LOCAL_C_INCLUDES:=$(LOCAL_PATH)/OGLCompiler
|
||||
LOCAL_STATIC_LIBRARIES:=OSDependent
|
||||
include $(BUILD_STATIC_LIBRARY)
|
||||
|
||||
# Build Glslang's HLSL parser library.
|
||||
include $(CLEAR_VARS)
|
||||
LOCAL_MODULE:=HLSL
|
||||
LOCAL_CXXFLAGS:=-std=c++11 -fno-exceptions -fno-rtti $(GLSLANG_DEFINES)
|
||||
LOCAL_SRC_FILES:= \
|
||||
hlsl/hlslAttributes.cpp \
|
||||
hlsl/hlslGrammar.cpp \
|
||||
hlsl/hlslOpMap.cpp \
|
||||
hlsl/hlslParseables.cpp \
|
||||
hlsl/hlslParseHelper.cpp \
|
||||
hlsl/hlslScanContext.cpp \
|
||||
hlsl/hlslTokenStream.cpp
|
||||
LOCAL_C_INCLUDES:=$(LOCAL_PATH) \
|
||||
$(LOCAL_PATH)/hlsl
|
||||
include $(BUILD_STATIC_LIBRARY)
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
GLSLANG_OUT_PATH=$(if $(call host-path-is-absolute,$(TARGET_OUT)),$(TARGET_OUT),$(abspath $(TARGET_OUT)))
|
||||
|
||||
LOCAL_MODULE:=glslang
|
||||
LOCAL_CXXFLAGS:=-std=c++11 -fno-exceptions -fno-rtti $(GLSLANG_DEFINES)
|
||||
LOCAL_EXPORT_C_INCLUDES:=$(LOCAL_PATH)
|
||||
LOCAL_SRC_FILES:= \
|
||||
glslang/GenericCodeGen/CodeGen.cpp \
|
||||
glslang/GenericCodeGen/Link.cpp \
|
||||
glslang/MachineIndependent/attribute.cpp \
|
||||
glslang/MachineIndependent/Constant.cpp \
|
||||
glslang/MachineIndependent/glslang_tab.cpp \
|
||||
glslang/MachineIndependent/InfoSink.cpp \
|
||||
glslang/MachineIndependent/Initialize.cpp \
|
||||
glslang/MachineIndependent/Intermediate.cpp \
|
||||
glslang/MachineIndependent/intermOut.cpp \
|
||||
glslang/MachineIndependent/IntermTraverse.cpp \
|
||||
glslang/MachineIndependent/iomapper.cpp \
|
||||
glslang/MachineIndependent/limits.cpp \
|
||||
glslang/MachineIndependent/linkValidate.cpp \
|
||||
glslang/MachineIndependent/parseConst.cpp \
|
||||
glslang/MachineIndependent/ParseContextBase.cpp \
|
||||
glslang/MachineIndependent/ParseHelper.cpp \
|
||||
glslang/MachineIndependent/PoolAlloc.cpp \
|
||||
glslang/MachineIndependent/propagateNoContraction.cpp \
|
||||
glslang/MachineIndependent/reflection.cpp \
|
||||
glslang/MachineIndependent/RemoveTree.cpp \
|
||||
glslang/MachineIndependent/Scan.cpp \
|
||||
glslang/MachineIndependent/ShaderLang.cpp \
|
||||
glslang/MachineIndependent/SymbolTable.cpp \
|
||||
glslang/MachineIndependent/Versions.cpp \
|
||||
glslang/MachineIndependent/preprocessor/PpAtom.cpp \
|
||||
glslang/MachineIndependent/preprocessor/PpContext.cpp \
|
||||
glslang/MachineIndependent/preprocessor/Pp.cpp \
|
||||
glslang/MachineIndependent/preprocessor/PpScanner.cpp \
|
||||
glslang/MachineIndependent/preprocessor/PpTokens.cpp
|
||||
LOCAL_C_INCLUDES:=$(LOCAL_PATH) \
|
||||
$(LOCAL_PATH)/glslang/MachineIndependent \
|
||||
$(GLSLANG_OUT_PATH)
|
||||
LOCAL_STATIC_LIBRARIES:=OSDependent OGLCompiler HLSL
|
||||
include $(BUILD_STATIC_LIBRARY)
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
LOCAL_MODULE:=SPIRV
|
||||
LOCAL_CXXFLAGS:=-std=c++11 -fno-exceptions -fno-rtti -Werror $(GLSLANG_DEFINES)
|
||||
LOCAL_EXPORT_C_INCLUDES:=$(LOCAL_PATH)
|
||||
LOCAL_SRC_FILES:= \
|
||||
SPIRV/GlslangToSpv.cpp \
|
||||
SPIRV/InReadableOrder.cpp \
|
||||
SPIRV/Logger.cpp \
|
||||
SPIRV/SPVRemapper.cpp \
|
||||
SPIRV/SpvBuilder.cpp \
|
||||
SPIRV/SpvPostProcess.cpp \
|
||||
SPIRV/SpvTools.cpp \
|
||||
SPIRV/disassemble.cpp \
|
||||
SPIRV/doc.cpp
|
||||
LOCAL_C_INCLUDES:=$(LOCAL_PATH) $(LOCAL_PATH)/glslang/SPIRV
|
||||
LOCAL_EXPORT_C_INCLUDES:=$(LOCAL_PATH)/glslang/SPIRV
|
||||
LOCAL_STATIC_LIBRARIES:=glslang
|
||||
include $(BUILD_STATIC_LIBRARY)
|
||||
@@ -1,247 +0,0 @@
|
||||
package(
|
||||
default_visibility = ["//visibility:public"],
|
||||
)
|
||||
|
||||
# Description:
|
||||
#
|
||||
# Khronos reference front-end for GLSL and ESSL, and sample SPIR-V generator.
|
||||
|
||||
licenses(["notice"])
|
||||
|
||||
exports_files(["LICENSE"])
|
||||
|
||||
COMMON_COPTS = select({
|
||||
"@bazel_tools//src/conditions:windows": [""],
|
||||
"//conditions:default": [
|
||||
"-Wall",
|
||||
"-Wuninitialized",
|
||||
"-Wunused",
|
||||
"-Wunused-local-typedefs",
|
||||
"-Wunused-parameter",
|
||||
"-Wunused-value",
|
||||
"-Wunused-variable",
|
||||
"-Wno-reorder",
|
||||
"-std=c++11",
|
||||
"-fvisibility=hidden",
|
||||
"-fvisibility-inlines-hidden",
|
||||
"-fno-exceptions",
|
||||
"-fno-rtti",
|
||||
],
|
||||
})
|
||||
|
||||
cc_library(
|
||||
name = "glslang",
|
||||
srcs = glob(
|
||||
[
|
||||
"glslang/GenericCodeGen/*.cpp",
|
||||
"glslang/MachineIndependent/*.cpp",
|
||||
"glslang/MachineIndependent/preprocessor/*.cpp",
|
||||
"hlsl/*.cpp",
|
||||
],
|
||||
exclude = [
|
||||
"glslang/MachineIndependent/pch.cpp",
|
||||
"glslang/MachineIndependent/pch.h",
|
||||
"hlsl/pch.cpp",
|
||||
"hlsl/pch.h",
|
||||
],
|
||||
) + [
|
||||
"OGLCompilersDLL/InitializeDll.cpp",
|
||||
] + select({
|
||||
"@bazel_tools//src/conditions:windows":
|
||||
["glslang/OSDependent/Windows/ossource.cpp"],
|
||||
"//conditions:default":
|
||||
["glslang/OSDependent/Unix/ossource.cpp"],
|
||||
}),
|
||||
hdrs = glob([
|
||||
"glslang/Include/*.h",
|
||||
"glslang/MachineIndependent/*.h",
|
||||
"glslang/MachineIndependent/preprocessor/*.h",
|
||||
"hlsl/*.h",
|
||||
]) + [
|
||||
"OGLCompilersDLL/InitializeDll.h",
|
||||
"StandAlone/DirStackFileIncluder.h",
|
||||
"glslang/OSDependent/osinclude.h",
|
||||
"glslang/Public/ShaderLang.h",
|
||||
],
|
||||
copts = COMMON_COPTS,
|
||||
defines = [
|
||||
"AMD_EXTENSIONS",
|
||||
"ENABLE_HLSL=0",
|
||||
"ENABLE_OPT=0",
|
||||
"NV_EXTENSIONS",
|
||||
],
|
||||
linkopts = select({
|
||||
"@bazel_tools//src/conditions:windows": [""],
|
||||
"//conditions:default": ["-lm", "-lpthread"],
|
||||
}),
|
||||
linkstatic = 1,
|
||||
)
|
||||
|
||||
genrule(
|
||||
name = "export_spirv_headers",
|
||||
srcs = [
|
||||
"SPIRV/GLSL.ext.AMD.h",
|
||||
"SPIRV/GLSL.ext.EXT.h",
|
||||
"SPIRV/GLSL.ext.KHR.h",
|
||||
"SPIRV/GLSL.ext.NV.h",
|
||||
"SPIRV/GLSL.std.450.h",
|
||||
"SPIRV/NonSemanticDebugPrintf.h",
|
||||
"SPIRV/spirv.hpp",
|
||||
],
|
||||
outs = [
|
||||
"include/SPIRV/GLSL.ext.AMD.h",
|
||||
"include/SPIRV/GLSL.ext.EXT.h",
|
||||
"include/SPIRV/GLSL.ext.KHR.h",
|
||||
"include/SPIRV/GLSL.ext.NV.h",
|
||||
"include/SPIRV/GLSL.std.450.h",
|
||||
"include/SPIRV/NonSemanticDebugPrintf.h",
|
||||
"include/SPIRV/spirv.hpp",
|
||||
],
|
||||
cmd = "mkdir -p $(@D)/include/SPIRV && cp $(SRCS) $(@D)/include/SPIRV/",
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "SPIRV_headers",
|
||||
hdrs = [":export_spirv_headers"],
|
||||
copts = COMMON_COPTS,
|
||||
includes = [
|
||||
"include",
|
||||
"include/SPIRV",
|
||||
],
|
||||
linkstatic = 1,
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "SPIRV",
|
||||
srcs = glob(
|
||||
["SPIRV/*.cpp"],
|
||||
exclude = [
|
||||
"SPIRV/SpvTools.cpp",
|
||||
],
|
||||
),
|
||||
hdrs = [
|
||||
"SPIRV/GlslangToSpv.h",
|
||||
"SPIRV/Logger.h",
|
||||
"SPIRV/SPVRemapper.h",
|
||||
"SPIRV/SpvBuilder.h",
|
||||
"SPIRV/SpvTools.h",
|
||||
"SPIRV/bitutils.h",
|
||||
"SPIRV/disassemble.h",
|
||||
"SPIRV/doc.h",
|
||||
"SPIRV/hex_float.h",
|
||||
"SPIRV/spvIR.h",
|
||||
],
|
||||
copts = COMMON_COPTS,
|
||||
includes = ["SPIRV"],
|
||||
linkopts = select({
|
||||
"@bazel_tools//src/conditions:windows": [""],
|
||||
"//conditions:default": ["-lm"],
|
||||
}),
|
||||
linkstatic = 1,
|
||||
deps = [
|
||||
":SPIRV_headers",
|
||||
":glslang",
|
||||
],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "glslang-default-resource-limits",
|
||||
srcs = ["StandAlone/ResourceLimits.cpp"],
|
||||
hdrs = ["StandAlone/ResourceLimits.h"],
|
||||
copts = COMMON_COPTS,
|
||||
linkstatic = 1,
|
||||
deps = [":glslang"],
|
||||
)
|
||||
|
||||
cc_binary(
|
||||
name = "glslangValidator",
|
||||
srcs = [
|
||||
"StandAlone/StandAlone.cpp",
|
||||
"StandAlone/Worklist.h",
|
||||
],
|
||||
copts = COMMON_COPTS,
|
||||
deps = [
|
||||
":SPIRV",
|
||||
":glslang",
|
||||
":glslang-default-resource-limits",
|
||||
],
|
||||
)
|
||||
|
||||
cc_binary(
|
||||
name = "spirv-remap",
|
||||
srcs = ["StandAlone/spirv-remap.cpp"],
|
||||
copts = COMMON_COPTS,
|
||||
deps = [
|
||||
":SPIRV",
|
||||
":glslang",
|
||||
":glslang-default-resource-limits",
|
||||
],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "test_files",
|
||||
srcs = glob(
|
||||
["Test/**"],
|
||||
exclude = [
|
||||
"Test/bump",
|
||||
"Test/glslangValidator",
|
||||
"Test/runtests",
|
||||
],
|
||||
),
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "glslang_test_lib",
|
||||
testonly = 1,
|
||||
srcs = [
|
||||
"gtests/HexFloat.cpp",
|
||||
"gtests/Initializer.h",
|
||||
"gtests/Settings.cpp",
|
||||
"gtests/Settings.h",
|
||||
"gtests/TestFixture.cpp",
|
||||
"gtests/TestFixture.h",
|
||||
"gtests/main.cpp",
|
||||
],
|
||||
copts = COMMON_COPTS,
|
||||
data = [":test_files"],
|
||||
defines = select({
|
||||
# Unfortunately we can't use $(location) in cc_library at the moment.
|
||||
# See https://github.com/bazelbuild/bazel/issues/1023
|
||||
# So we'll specify the path manually.
|
||||
"@bazel_tools//src/conditions:windows":
|
||||
["GLSLANG_TEST_DIRECTORY='\"../../../../../Test\"'"],
|
||||
"//conditions:default":
|
||||
["GLSLANG_TEST_DIRECTORY='\"Test\"'"],
|
||||
}),
|
||||
linkstatic = 1,
|
||||
deps = [
|
||||
":SPIRV",
|
||||
":glslang",
|
||||
":glslang-default-resource-limits",
|
||||
"@com_google_googletest//:gtest",
|
||||
],
|
||||
)
|
||||
|
||||
GLSLANG_TESTS = glob(
|
||||
["gtests/*.FromFile.cpp"],
|
||||
# Since we are not building the SPIRV-Tools dependency, the following tests
|
||||
# cannot be performed.
|
||||
exclude = [
|
||||
"gtests/Hlsl.FromFile.cpp",
|
||||
"gtests/Spv.FromFile.cpp",
|
||||
],
|
||||
)
|
||||
|
||||
[cc_test(
|
||||
name = test_file.replace("gtests/", "").replace(".FromFile.cpp", "") + "_test",
|
||||
srcs = [test_file],
|
||||
copts = COMMON_COPTS,
|
||||
data = [
|
||||
":test_files",
|
||||
],
|
||||
deps = [
|
||||
":SPIRV",
|
||||
":glslang",
|
||||
":glslang_test_lib",
|
||||
],
|
||||
) for test_file in GLSLANG_TESTS]
|
||||
@@ -1,248 +0,0 @@
|
||||
# Copyright (C) 2018 Google, Inc.
|
||||
#
|
||||
# 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 Google Inc. 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 HOLDERS 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.
|
||||
|
||||
import("//build_overrides/glslang.gni")
|
||||
|
||||
# Both Chromium and Fuchsia use by default a set of warning errors
|
||||
# that is far too strict to compile this project. These are also
|
||||
# typically appended after |cflags|, overriding target-specific
|
||||
# definitions. To work around this, determine which configs to
|
||||
# add and remove in order to succesfully build the project.
|
||||
if (defined(is_fuchsia_tree) && is_fuchsia_tree) {
|
||||
_configs_to_remove = [ "//build/config:default_warnings" ]
|
||||
_configs_to_add = []
|
||||
} else {
|
||||
_configs_to_remove = [ "//build/config/compiler:chromium_code" ]
|
||||
_configs_to_add = [ "//build/config/compiler:no_chromium_code" ]
|
||||
}
|
||||
|
||||
spirv_tools_dir = glslang_spirv_tools_dir
|
||||
|
||||
config("glslang_public") {
|
||||
include_dirs = [ "." ]
|
||||
|
||||
defines = [ "ENABLE_HLSL=1" ]
|
||||
}
|
||||
|
||||
source_set("glslang_sources") {
|
||||
public_configs = [ ":glslang_public" ]
|
||||
|
||||
sources = [
|
||||
"OGLCompilersDLL/InitializeDll.cpp",
|
||||
"OGLCompilersDLL/InitializeDll.h",
|
||||
"SPIRV/GLSL.ext.AMD.h",
|
||||
"SPIRV/GLSL.ext.EXT.h",
|
||||
"SPIRV/GLSL.ext.KHR.h",
|
||||
"SPIRV/GLSL.ext.NV.h",
|
||||
"SPIRV/GLSL.std.450.h",
|
||||
"SPIRV/GlslangToSpv.cpp",
|
||||
"SPIRV/GlslangToSpv.h",
|
||||
"SPIRV/InReadableOrder.cpp",
|
||||
"SPIRV/Logger.cpp",
|
||||
"SPIRV/Logger.h",
|
||||
"SPIRV/NonSemanticDebugPrintf.h",
|
||||
"SPIRV/SPVRemapper.cpp",
|
||||
"SPIRV/SPVRemapper.h",
|
||||
"SPIRV/SpvBuilder.cpp",
|
||||
"SPIRV/SpvBuilder.h",
|
||||
"SPIRV/SpvPostProcess.cpp",
|
||||
"SPIRV/SpvTools.cpp",
|
||||
"SPIRV/SpvTools.h",
|
||||
"SPIRV/bitutils.h",
|
||||
"SPIRV/disassemble.cpp",
|
||||
"SPIRV/disassemble.h",
|
||||
"SPIRV/doc.cpp",
|
||||
"SPIRV/doc.h",
|
||||
"SPIRV/hex_float.h",
|
||||
"SPIRV/spirv.hpp",
|
||||
"SPIRV/spvIR.h",
|
||||
"glslang/GenericCodeGen/CodeGen.cpp",
|
||||
"glslang/GenericCodeGen/Link.cpp",
|
||||
"glslang/Include/BaseTypes.h",
|
||||
"glslang/Include/Common.h",
|
||||
"glslang/Include/ConstantUnion.h",
|
||||
"glslang/Include/InfoSink.h",
|
||||
"glslang/Include/InitializeGlobals.h",
|
||||
"glslang/Include/PoolAlloc.h",
|
||||
"glslang/Include/ResourceLimits.h",
|
||||
"glslang/Include/ShHandle.h",
|
||||
"glslang/Include/Types.h",
|
||||
"glslang/Include/arrays.h",
|
||||
"glslang/Include/intermediate.h",
|
||||
"glslang/Include/revision.h",
|
||||
"glslang/MachineIndependent/Constant.cpp",
|
||||
"glslang/MachineIndependent/InfoSink.cpp",
|
||||
"glslang/MachineIndependent/Initialize.cpp",
|
||||
"glslang/MachineIndependent/Initialize.h",
|
||||
"glslang/MachineIndependent/IntermTraverse.cpp",
|
||||
"glslang/MachineIndependent/Intermediate.cpp",
|
||||
"glslang/MachineIndependent/LiveTraverser.h",
|
||||
"glslang/MachineIndependent/ParseContextBase.cpp",
|
||||
"glslang/MachineIndependent/ParseHelper.cpp",
|
||||
"glslang/MachineIndependent/ParseHelper.h",
|
||||
"glslang/MachineIndependent/PoolAlloc.cpp",
|
||||
"glslang/MachineIndependent/RemoveTree.cpp",
|
||||
"glslang/MachineIndependent/RemoveTree.h",
|
||||
"glslang/MachineIndependent/Scan.cpp",
|
||||
"glslang/MachineIndependent/Scan.h",
|
||||
"glslang/MachineIndependent/ScanContext.h",
|
||||
"glslang/MachineIndependent/ShaderLang.cpp",
|
||||
"glslang/MachineIndependent/SymbolTable.cpp",
|
||||
"glslang/MachineIndependent/SymbolTable.h",
|
||||
"glslang/MachineIndependent/Versions.cpp",
|
||||
"glslang/MachineIndependent/Versions.h",
|
||||
"glslang/MachineIndependent/attribute.cpp",
|
||||
"glslang/MachineIndependent/attribute.h",
|
||||
"glslang/MachineIndependent/gl_types.h",
|
||||
"glslang/MachineIndependent/glslang_tab.cpp",
|
||||
"glslang/MachineIndependent/glslang_tab.cpp.h",
|
||||
"glslang/MachineIndependent/intermOut.cpp",
|
||||
"glslang/MachineIndependent/iomapper.cpp",
|
||||
"glslang/MachineIndependent/iomapper.h",
|
||||
"glslang/MachineIndependent/limits.cpp",
|
||||
"glslang/MachineIndependent/linkValidate.cpp",
|
||||
"glslang/MachineIndependent/localintermediate.h",
|
||||
"glslang/MachineIndependent/parseConst.cpp",
|
||||
"glslang/MachineIndependent/parseVersions.h",
|
||||
"glslang/MachineIndependent/preprocessor/Pp.cpp",
|
||||
"glslang/MachineIndependent/preprocessor/PpAtom.cpp",
|
||||
"glslang/MachineIndependent/preprocessor/PpContext.cpp",
|
||||
"glslang/MachineIndependent/preprocessor/PpContext.h",
|
||||
"glslang/MachineIndependent/preprocessor/PpScanner.cpp",
|
||||
"glslang/MachineIndependent/preprocessor/PpTokens.cpp",
|
||||
"glslang/MachineIndependent/preprocessor/PpTokens.h",
|
||||
"glslang/MachineIndependent/propagateNoContraction.cpp",
|
||||
"glslang/MachineIndependent/propagateNoContraction.h",
|
||||
"glslang/MachineIndependent/reflection.cpp",
|
||||
"glslang/MachineIndependent/reflection.h",
|
||||
"glslang/OSDependent/osinclude.h",
|
||||
"glslang/Public/ShaderLang.h",
|
||||
"hlsl/hlslAttributes.cpp",
|
||||
"hlsl/hlslAttributes.h",
|
||||
"hlsl/hlslGrammar.cpp",
|
||||
"hlsl/hlslGrammar.h",
|
||||
"hlsl/hlslOpMap.cpp",
|
||||
"hlsl/hlslOpMap.h",
|
||||
"hlsl/hlslParseHelper.cpp",
|
||||
"hlsl/hlslParseHelper.h",
|
||||
"hlsl/hlslParseables.cpp",
|
||||
"hlsl/hlslParseables.h",
|
||||
"hlsl/hlslScanContext.cpp",
|
||||
"hlsl/hlslScanContext.h",
|
||||
"hlsl/hlslTokenStream.cpp",
|
||||
"hlsl/hlslTokenStream.h",
|
||||
"hlsl/hlslTokens.h",
|
||||
]
|
||||
|
||||
defines = [ "ENABLE_OPT=1" ]
|
||||
|
||||
if (is_win) {
|
||||
sources += [ "glslang/OSDependent/Windows/ossource.cpp" ]
|
||||
defines += [ "GLSLANG_OSINCLUDE_WIN32" ]
|
||||
} else {
|
||||
sources += [ "glslang/OSDependent/Unix/ossource.cpp" ]
|
||||
defines += [ "GLSLANG_OSINCLUDE_UNIX" ]
|
||||
}
|
||||
|
||||
if (is_clang) {
|
||||
cflags = [
|
||||
"-Wno-extra-semi",
|
||||
"-Wno-ignored-qualifiers",
|
||||
"-Wno-implicit-fallthrough",
|
||||
"-Wno-inconsistent-missing-override",
|
||||
"-Wno-sign-compare",
|
||||
"-Wno-unused-variable",
|
||||
"-Wno-missing-field-initializers",
|
||||
"-Wno-newline-eof",
|
||||
]
|
||||
}
|
||||
if (is_win && !is_clang) {
|
||||
cflags = [
|
||||
"/wd4018", # signed/unsigned mismatch
|
||||
"/wd4189", # local variable is initialized but not referenced
|
||||
]
|
||||
}
|
||||
|
||||
deps = [
|
||||
"${spirv_tools_dir}:spvtools_opt",
|
||||
"${spirv_tools_dir}:spvtools_val",
|
||||
]
|
||||
|
||||
configs -= _configs_to_remove
|
||||
configs += _configs_to_add
|
||||
}
|
||||
|
||||
source_set("glslang_default_resource_limits_sources") {
|
||||
sources = [
|
||||
"StandAlone/ResourceLimits.cpp",
|
||||
"StandAlone/ResourceLimits.h",
|
||||
]
|
||||
deps = [
|
||||
":glslang_sources",
|
||||
]
|
||||
public_configs = [ ":glslang_public" ]
|
||||
|
||||
configs -= _configs_to_remove
|
||||
configs += _configs_to_add
|
||||
}
|
||||
|
||||
executable("glslang_validator") {
|
||||
sources = [
|
||||
"StandAlone/DirStackFileIncluder.h",
|
||||
"StandAlone/StandAlone.cpp",
|
||||
]
|
||||
if (!is_win) {
|
||||
cflags = [ "-Woverflow" ]
|
||||
}
|
||||
defines = [ "ENABLE_OPT=1" ]
|
||||
deps = [
|
||||
":glslang_default_resource_limits_sources",
|
||||
":glslang_sources",
|
||||
]
|
||||
|
||||
configs -= _configs_to_remove
|
||||
configs += _configs_to_add
|
||||
}
|
||||
|
||||
executable("spirv-remap") {
|
||||
sources = [
|
||||
"StandAlone/spirv-remap.cpp",
|
||||
]
|
||||
defines = [ "ENABLE_OPT=1" ]
|
||||
deps = [
|
||||
":glslang_sources",
|
||||
]
|
||||
|
||||
configs -= _configs_to_remove
|
||||
configs += _configs_to_add
|
||||
}
|
||||
@@ -1,229 +0,0 @@
|
||||
# increase to 3.1 once all major distributions
|
||||
# include a version of CMake >= 3.1
|
||||
cmake_minimum_required(VERSION 2.8.12)
|
||||
if (POLICY CMP0048)
|
||||
cmake_policy(SET CMP0048 NEW)
|
||||
endif()
|
||||
set_property(GLOBAL PROPERTY USE_FOLDERS ON)
|
||||
|
||||
# Enable compile commands database
|
||||
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
|
||||
|
||||
# Adhere to GNU filesystem layout conventions
|
||||
include(GNUInstallDirs)
|
||||
|
||||
# Needed for CMAKE_DEPENDENT_OPTION macro
|
||||
include(CMakeDependentOption)
|
||||
|
||||
option(BUILD_SHARED_LIBS "Build Shared Libraries" OFF)
|
||||
option(BUILD_EXTERNAL "Build external dependencies in /External" ON)
|
||||
|
||||
set(LIB_TYPE STATIC)
|
||||
|
||||
if(BUILD_SHARED_LIBS)
|
||||
set(LIB_TYPE SHARED)
|
||||
endif()
|
||||
|
||||
option(SKIP_GLSLANG_INSTALL "Skip installation" ${SKIP_GLSLANG_INSTALL})
|
||||
if(NOT ${SKIP_GLSLANG_INSTALL})
|
||||
set(ENABLE_GLSLANG_INSTALL ON)
|
||||
endif()
|
||||
option(ENABLE_SPVREMAPPER "Enables building of SPVRemapper" ON)
|
||||
|
||||
option(ENABLE_GLSLANG_BINARIES "Builds glslangValidator and spirv-remap" ON)
|
||||
|
||||
option(ENABLE_GLSLANG_JS
|
||||
"If using Emscripten, build glslang.js. Otherwise, builds a sample executable for binary-size testing." OFF)
|
||||
CMAKE_DEPENDENT_OPTION(ENABLE_GLSLANG_WEBMIN
|
||||
"Reduces glslang to minimum needed for web use"
|
||||
OFF "ENABLE_GLSLANG_JS"
|
||||
OFF)
|
||||
CMAKE_DEPENDENT_OPTION(ENABLE_GLSLANG_WEBMIN_DEVEL
|
||||
"For ENABLE_GLSLANG_WEBMIN builds, enables compilation error messages"
|
||||
OFF "ENABLE_GLSLANG_WEBMIN"
|
||||
OFF)
|
||||
CMAKE_DEPENDENT_OPTION(ENABLE_EMSCRIPTEN_SINGLE_FILE
|
||||
"If using Emscripten, enables SINGLE_FILE build"
|
||||
OFF "ENABLE_GLSLANG_JS AND EMSCRIPTEN"
|
||||
OFF)
|
||||
CMAKE_DEPENDENT_OPTION(ENABLE_EMSCRIPTEN_ENVIRONMENT_NODE
|
||||
"If using Emscripten, builds to run on Node instead of Web"
|
||||
OFF "ENABLE_GLSLANG_JS AND EMSCRIPTEN"
|
||||
OFF)
|
||||
|
||||
CMAKE_DEPENDENT_OPTION(ENABLE_HLSL
|
||||
"Enables HLSL input support"
|
||||
ON "NOT ENABLE_GLSLANG_WEBMIN"
|
||||
OFF)
|
||||
|
||||
option(ENABLE_RTTI "Enables RTTI" OFF)
|
||||
option(ENABLE_OPT "Enables spirv-opt capability if present" ON)
|
||||
option(ENABLE_PCH "Enables Precompiled header" ON)
|
||||
option(ENABLE_CTEST "Enables testing" ON)
|
||||
|
||||
if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT AND WIN32)
|
||||
set(CMAKE_INSTALL_PREFIX "install" CACHE STRING "..." FORCE)
|
||||
endif()
|
||||
|
||||
option(USE_CCACHE "Use ccache" OFF)
|
||||
if(USE_CCACHE)
|
||||
find_program(CCACHE_FOUND ccache)
|
||||
if(CCACHE_FOUND)
|
||||
set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE ccache)
|
||||
endif(CCACHE_FOUND)
|
||||
endif()
|
||||
|
||||
# Precompiled header macro. Parameters are source file list and filename for pch cpp file.
|
||||
macro(glslang_pch SRCS PCHCPP)
|
||||
if(MSVC AND CMAKE_GENERATOR MATCHES "^Visual Studio" AND NOT ${CMAKE_CXX_COMPILER_ID} MATCHES "Clang" AND ENABLE_PCH)
|
||||
set(PCH_NAME "$(IntDir)\\pch.pch")
|
||||
# make source files use/depend on PCH_NAME
|
||||
set_source_files_properties(${${SRCS}} PROPERTIES COMPILE_FLAGS "/Yupch.h /FIpch.h /Fp${PCH_NAME} /Zm300" OBJECT_DEPENDS "${PCH_NAME}")
|
||||
# make PCHCPP file compile and generate PCH_NAME
|
||||
set_source_files_properties(${PCHCPP} PROPERTIES COMPILE_FLAGS "/Ycpch.h /Fp${PCH_NAME} /Zm300" OBJECT_OUTPUTS "${PCH_NAME}")
|
||||
list(APPEND ${SRCS} "${PCHCPP}")
|
||||
endif()
|
||||
endmacro(glslang_pch)
|
||||
|
||||
project(glslang)
|
||||
|
||||
if(ENABLE_CTEST)
|
||||
include(CTest)
|
||||
endif()
|
||||
|
||||
if(ENABLE_HLSL)
|
||||
add_definitions(-DENABLE_HLSL)
|
||||
endif(ENABLE_HLSL)
|
||||
|
||||
if(ENABLE_GLSLANG_WEBMIN)
|
||||
add_definitions(-DGLSLANG_WEB)
|
||||
if(ENABLE_GLSLANG_WEBMIN_DEVEL)
|
||||
add_definitions(-DGLSLANG_WEB_DEVEL)
|
||||
endif(ENABLE_GLSLANG_WEBMIN_DEVEL)
|
||||
endif(ENABLE_GLSLANG_WEBMIN)
|
||||
|
||||
if(WIN32)
|
||||
set(CMAKE_DEBUG_POSTFIX "d")
|
||||
if(MSVC)
|
||||
include(ChooseMSVCCRT.cmake)
|
||||
endif(MSVC)
|
||||
add_definitions(-DGLSLANG_OSINCLUDE_WIN32)
|
||||
elseif(UNIX)
|
||||
add_definitions(-DGLSLANG_OSINCLUDE_UNIX)
|
||||
else(WIN32)
|
||||
message("unknown platform")
|
||||
endif(WIN32)
|
||||
|
||||
if(${CMAKE_CXX_COMPILER_ID} MATCHES "GNU")
|
||||
add_compile_options(-Wall -Wmaybe-uninitialized -Wuninitialized -Wunused -Wunused-local-typedefs
|
||||
-Wunused-parameter -Wunused-value -Wunused-variable -Wunused-but-set-parameter -Wunused-but-set-variable -fno-exceptions)
|
||||
add_compile_options(-Wno-reorder) # disable this from -Wall, since it happens all over.
|
||||
if(NOT ENABLE_RTTI)
|
||||
add_compile_options(-fno-rtti)
|
||||
endif()
|
||||
if(NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS "9.0.0")
|
||||
add_compile_options(-Werror=deprecated-copy)
|
||||
endif()
|
||||
elseif(${CMAKE_CXX_COMPILER_ID} MATCHES "Clang" AND NOT MSVC)
|
||||
add_compile_options(-Wall -Wuninitialized -Wunused -Wunused-local-typedefs
|
||||
-Wunused-parameter -Wunused-value -Wunused-variable)
|
||||
add_compile_options(-Wno-reorder) # disable this from -Wall, since it happens all over.
|
||||
if(NOT ENABLE_RTTI)
|
||||
add_compile_options(-fno-rtti)
|
||||
endif()
|
||||
elseif(MSVC)
|
||||
if(NOT ENABLE_RTTI)
|
||||
add_compile_options(/GR-) # Disable RTTI
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(ENABLE_GLSLANG_JS)
|
||||
if(MSVC)
|
||||
add_compile_options(/Os /GR-)
|
||||
else()
|
||||
add_compile_options(-Os -fno-exceptions)
|
||||
if(${CMAKE_CXX_COMPILER_ID} MATCHES "Clang" AND NOT MSVC)
|
||||
add_compile_options(-Wno-unused-parameter)
|
||||
add_compile_options(-Wno-unused-variable -Wno-unused-const-variable)
|
||||
endif()
|
||||
endif()
|
||||
endif(ENABLE_GLSLANG_JS)
|
||||
|
||||
# Request C++11
|
||||
if(${CMAKE_VERSION} VERSION_LESS 3.1)
|
||||
# CMake versions before 3.1 do not understand CMAKE_CXX_STANDARD
|
||||
# remove this block once CMake >=3.1 has fixated in the ecosystem
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
|
||||
else()
|
||||
set(CMAKE_CXX_STANDARD 11)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
set(CMAKE_CXX_EXTENSIONS OFF)
|
||||
endif()
|
||||
|
||||
function(glslang_set_link_args TARGET)
|
||||
# For MinGW compiles, statically link against the GCC and C++ runtimes.
|
||||
# This avoids the need to ship those runtimes as DLLs.
|
||||
if(WIN32 AND ${CMAKE_CXX_COMPILER_ID} MATCHES "GNU")
|
||||
set_target_properties(${TARGET} PROPERTIES
|
||||
LINK_FLAGS "-static -static-libgcc -static-libstdc++")
|
||||
endif()
|
||||
endfunction(glslang_set_link_args)
|
||||
|
||||
# CMake needs to find the right version of python, right from the beginning,
|
||||
# otherwise, it will find the wrong version and fail later
|
||||
if(BUILD_EXTERNAL AND IS_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/External)
|
||||
find_package(PythonInterp 3 REQUIRED)
|
||||
|
||||
# We depend on these for later projects, so they should come first.
|
||||
add_subdirectory(External)
|
||||
endif()
|
||||
|
||||
if(NOT TARGET SPIRV-Tools-opt)
|
||||
set(ENABLE_OPT OFF)
|
||||
endif()
|
||||
|
||||
if(ENABLE_OPT)
|
||||
message(STATUS "optimizer enabled")
|
||||
add_definitions(-DENABLE_OPT=1)
|
||||
else()
|
||||
if(ENABLE_HLSL)
|
||||
message(STATUS "spirv-tools not linked - illegal SPIRV may be generated for HLSL")
|
||||
endif()
|
||||
add_definitions(-DENABLE_OPT=0)
|
||||
endif()
|
||||
|
||||
add_subdirectory(glslang)
|
||||
add_subdirectory(OGLCompilersDLL)
|
||||
if(ENABLE_GLSLANG_BINARIES)
|
||||
add_subdirectory(StandAlone)
|
||||
endif()
|
||||
add_subdirectory(SPIRV)
|
||||
if(ENABLE_HLSL)
|
||||
add_subdirectory(hlsl)
|
||||
endif(ENABLE_HLSL)
|
||||
if(ENABLE_CTEST)
|
||||
add_subdirectory(gtests)
|
||||
endif()
|
||||
|
||||
if(BUILD_TESTING)
|
||||
# glslang-testsuite runs a bash script on Windows.
|
||||
# Make sure to use '-o igncr' flag to ignore carriage returns (\r).
|
||||
set(IGNORE_CR_FLAG "")
|
||||
if(WIN32)
|
||||
set(IGNORE_CR_FLAG -o igncr)
|
||||
endif()
|
||||
|
||||
if (CMAKE_CONFIGURATION_TYPES)
|
||||
set(RESULTS_PATH ${CMAKE_CURRENT_BINARY_DIR}/$<CONFIGURATION>/localResults)
|
||||
set(VALIDATOR_PATH ${CMAKE_CURRENT_BINARY_DIR}/StandAlone/$<CONFIGURATION>/glslangValidator)
|
||||
set(REMAP_PATH ${CMAKE_CURRENT_BINARY_DIR}/StandAlone/$<CONFIGURATION>/spirv-remap)
|
||||
else(CMAKE_CONFIGURATION_TYPES)
|
||||
set(RESULTS_PATH ${CMAKE_CURRENT_BINARY_DIR}/localResults)
|
||||
set(VALIDATOR_PATH ${CMAKE_CURRENT_BINARY_DIR}/StandAlone/glslangValidator)
|
||||
set(REMAP_PATH ${CMAKE_CURRENT_BINARY_DIR}/StandAlone/spirv-remap)
|
||||
endif(CMAKE_CONFIGURATION_TYPES)
|
||||
|
||||
add_test(NAME glslang-testsuite
|
||||
COMMAND bash ${IGNORE_CR_FLAG} runtests ${RESULTS_PATH} ${VALIDATOR_PATH} ${REMAP_PATH}
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/Test/)
|
||||
endif(BUILD_TESTING)
|
||||
@@ -1 +0,0 @@
|
||||
A reminder that this issue tracker is managed by the Khronos Group. Interactions here should follow the Khronos Code of Conduct (https://www.khronos.org/developers/code-of-conduct), which prohibits aggressive or derogatory language. Please keep the discussion friendly and civil.
|
||||
@@ -1,105 +0,0 @@
|
||||
# The macro choose_msvc_crt() takes a list of possible
|
||||
# C runtimes to choose from, in the form of compiler flags,
|
||||
# to present to the user. (MTd for /MTd, etc)
|
||||
#
|
||||
# The macro is invoked at the end of the file.
|
||||
#
|
||||
# CMake already sets CRT flags in the CMAKE_CXX_FLAGS_* and
|
||||
# CMAKE_C_FLAGS_* variables by default. To let the user
|
||||
# override that for each build type:
|
||||
# 1. Detect which CRT is already selected, and reflect this in
|
||||
# LLVM_USE_CRT_* so the user can have a better idea of what
|
||||
# changes they're making.
|
||||
# 2. Replace the flags in both variables with the new flag via a regex.
|
||||
# 3. set() the variables back into the cache so the changes
|
||||
# are user-visible.
|
||||
|
||||
### Helper macros: ###
|
||||
macro(make_crt_regex regex crts)
|
||||
set(${regex} "")
|
||||
foreach(crt ${${crts}})
|
||||
# Trying to match the beginning or end of the string with stuff
|
||||
# like [ ^]+ didn't work, so use a bunch of parentheses instead.
|
||||
set(${regex} "${${regex}}|(^| +)/${crt}($| +)")
|
||||
endforeach(crt)
|
||||
string(REGEX REPLACE "^\\|" "" ${regex} "${${regex}}")
|
||||
endmacro(make_crt_regex)
|
||||
|
||||
macro(get_current_crt crt_current regex flagsvar)
|
||||
# Find the selected-by-CMake CRT for each build type, if any.
|
||||
# Strip off the leading slash and any whitespace.
|
||||
string(REGEX MATCH "${${regex}}" ${crt_current} "${${flagsvar}}")
|
||||
string(REPLACE "/" " " ${crt_current} "${${crt_current}}")
|
||||
string(STRIP "${${crt_current}}" ${crt_current})
|
||||
endmacro(get_current_crt)
|
||||
|
||||
# Replaces or adds a flag to a variable.
|
||||
# Expects 'flag' to be padded with spaces.
|
||||
macro(set_flag_in_var flagsvar regex flag)
|
||||
string(REGEX MATCH "${${regex}}" current_flag "${${flagsvar}}")
|
||||
if("${current_flag}" STREQUAL "")
|
||||
set(${flagsvar} "${${flagsvar}}${${flag}}")
|
||||
else()
|
||||
string(REGEX REPLACE "${${regex}}" "${${flag}}" ${flagsvar} "${${flagsvar}}")
|
||||
endif()
|
||||
string(STRIP "${${flagsvar}}" ${flagsvar})
|
||||
# Make sure this change gets reflected in the cache/gui.
|
||||
# CMake requires the docstring parameter whenever set() touches the cache,
|
||||
# so get the existing docstring and re-use that.
|
||||
get_property(flagsvar_docs CACHE ${flagsvar} PROPERTY HELPSTRING)
|
||||
set(${flagsvar} "${${flagsvar}}" CACHE STRING "${flagsvar_docs}" FORCE)
|
||||
endmacro(set_flag_in_var)
|
||||
|
||||
|
||||
macro(choose_msvc_crt MSVC_CRT)
|
||||
if(LLVM_USE_CRT)
|
||||
message(FATAL_ERROR
|
||||
"LLVM_USE_CRT is deprecated. Use the CMAKE_BUILD_TYPE-specific
|
||||
variables (LLVM_USE_CRT_DEBUG, etc) instead.")
|
||||
endif()
|
||||
|
||||
make_crt_regex(MSVC_CRT_REGEX ${MSVC_CRT})
|
||||
|
||||
foreach(build_type ${CMAKE_CONFIGURATION_TYPES} ${CMAKE_BUILD_TYPE})
|
||||
string(TOUPPER "${build_type}" build)
|
||||
if (NOT LLVM_USE_CRT_${build})
|
||||
get_current_crt(LLVM_USE_CRT_${build}
|
||||
MSVC_CRT_REGEX
|
||||
CMAKE_CXX_FLAGS_${build})
|
||||
set(LLVM_USE_CRT_${build}
|
||||
"${LLVM_USE_CRT_${build}}"
|
||||
CACHE STRING "Specify VC++ CRT to use for ${build_type} configurations."
|
||||
FORCE)
|
||||
set_property(CACHE LLVM_USE_CRT_${build}
|
||||
PROPERTY STRINGS ;${${MSVC_CRT}})
|
||||
endif(NOT LLVM_USE_CRT_${build})
|
||||
endforeach(build_type)
|
||||
|
||||
foreach(build_type ${CMAKE_CONFIGURATION_TYPES} ${CMAKE_BUILD_TYPE})
|
||||
string(TOUPPER "${build_type}" build)
|
||||
if ("${LLVM_USE_CRT_${build}}" STREQUAL "")
|
||||
set(flag_string " ")
|
||||
else()
|
||||
set(flag_string " /${LLVM_USE_CRT_${build}} ")
|
||||
list(FIND ${MSVC_CRT} ${LLVM_USE_CRT_${build}} idx)
|
||||
if (idx LESS 0)
|
||||
message(FATAL_ERROR
|
||||
"Invalid value for LLVM_USE_CRT_${build}: ${LLVM_USE_CRT_${build}}. Valid options are one of: ${${MSVC_CRT}}")
|
||||
endif (idx LESS 0)
|
||||
message(STATUS "Using ${build_type} VC++ CRT: ${LLVM_USE_CRT_${build}}")
|
||||
endif()
|
||||
foreach(lang C CXX)
|
||||
set_flag_in_var(CMAKE_${lang}_FLAGS_${build} MSVC_CRT_REGEX flag_string)
|
||||
endforeach(lang)
|
||||
endforeach(build_type)
|
||||
endmacro(choose_msvc_crt MSVC_CRT)
|
||||
|
||||
|
||||
# List of valid CRTs for MSVC
|
||||
set(MSVC_CRT
|
||||
MD
|
||||
MDd
|
||||
MT
|
||||
MTd)
|
||||
|
||||
choose_msvc_crt(MSVC_CRT)
|
||||
-44
@@ -1,44 +0,0 @@
|
||||
# Suppress all warnings from external projects.
|
||||
set_property(DIRECTORY APPEND PROPERTY COMPILE_OPTIONS -w)
|
||||
|
||||
if(BUILD_TESTING)
|
||||
if(TARGET gmock)
|
||||
message(STATUS "Google Mock already configured - use it")
|
||||
elseif(IS_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/googletest)
|
||||
# We need to make sure Google Test does not mess up with the
|
||||
# global CRT settings on Windows.
|
||||
if(WIN32)
|
||||
set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
|
||||
endif(WIN32)
|
||||
# EXCLUDE_FROM_ALL keeps the install target from installing GTEST files.
|
||||
add_subdirectory(googletest EXCLUDE_FROM_ALL)
|
||||
set(GTEST_TARGETS
|
||||
gtest
|
||||
gtest_main
|
||||
gmock
|
||||
gmock_main)
|
||||
foreach(target ${GTEST_TARGETS})
|
||||
set_property(TARGET ${target} PROPERTY FOLDER gtest)
|
||||
endforeach()
|
||||
mark_as_advanced(gmock_build_tests
|
||||
BUILD_GMOCK
|
||||
BUILD_GTEST
|
||||
BUILD_SHARED_LIBS
|
||||
gtest_build_samples
|
||||
gtest_build_tests
|
||||
gtest_disable_pthreads
|
||||
gtest_force_shared_crt
|
||||
gtest_hide_internal_symbols)
|
||||
else()
|
||||
message(STATUS
|
||||
"Google Mock was not found - tests based on that will not build")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(ENABLE_OPT AND NOT TARGET SPIRV-Tools-opt)
|
||||
if(IS_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/spirv-tools)
|
||||
set(SPIRV_SKIP_TESTS ON CACHE BOOL "Skip building SPIRV-Tools tests")
|
||||
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/spirv-tools spirv-tools)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
@@ -1,108 +0,0 @@
|
||||
Here, glslang proper means core GLSL parsing, HLSL parsing, and SPIR-V code
|
||||
generation. Glslang proper requires use of two licenses, one that covers
|
||||
non-preprocessing and an additional one that covers preprocessing.
|
||||
|
||||
Bison was removed long ago. You can build glslang from the source grammar,
|
||||
using tools of your choice, without using bison or any bison files.
|
||||
|
||||
Other parts, outside of glslang proper, include:
|
||||
|
||||
- gl_types.h, only needed for OpenGL-like reflection, and can be left out of
|
||||
a parse and codegen project. See it for its license.
|
||||
|
||||
- update_glslang_sources.py, which is not part of the project proper and does
|
||||
not need to be used.
|
||||
|
||||
- the SPIR-V "remapper", which is optional, but has the same license as
|
||||
glslang proper
|
||||
|
||||
- Google tests and SPIR-V tools, and anything in the external subdirectory
|
||||
are external and optional; see them for their respective licenses.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
The core of glslang-proper, minus the preprocessor is licenced as follows:
|
||||
|
||||
//
|
||||
// Copyright (C) 2015-2018 Google, Inc.
|
||||
// Copyright (C) <various other dates and companies>
|
||||
//
|
||||
// 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 3Dlabs Inc. Ltd. 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 HOLDERS 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.
|
||||
//
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
The preprocessor has the core license stated above, plus an additional licence:
|
||||
|
||||
/****************************************************************************\
|
||||
Copyright (c) 2002, NVIDIA Corporation.
|
||||
|
||||
NVIDIA Corporation("NVIDIA") supplies this software to you in
|
||||
consideration of your agreement to the following terms, and your use,
|
||||
installation, modification or redistribution of this NVIDIA software
|
||||
constitutes acceptance of these terms. If you do not agree with these
|
||||
terms, please do not use, install, modify or redistribute this NVIDIA
|
||||
software.
|
||||
|
||||
In consideration of your agreement to abide by the following terms, and
|
||||
subject to these terms, NVIDIA grants you a personal, non-exclusive
|
||||
license, under NVIDIA's copyrights in this original NVIDIA software (the
|
||||
"NVIDIA Software"), to use, reproduce, modify and redistribute the
|
||||
NVIDIA Software, with or without modifications, in source and/or binary
|
||||
forms; provided that if you redistribute the NVIDIA Software, you must
|
||||
retain the copyright notice of NVIDIA, this notice and the following
|
||||
text and disclaimers in all such redistributions of the NVIDIA Software.
|
||||
Neither the name, trademarks, service marks nor logos of NVIDIA
|
||||
Corporation may be used to endorse or promote products derived from the
|
||||
NVIDIA Software without specific prior written permission from NVIDIA.
|
||||
Except as expressly stated in this notice, no other rights or licenses
|
||||
express or implied, are granted by NVIDIA herein, including but not
|
||||
limited to any patent rights that may be infringed by your derivative
|
||||
works or by other works in which the NVIDIA Software may be
|
||||
incorporated. No hardware is licensed hereunder.
|
||||
|
||||
THE NVIDIA SOFTWARE IS BEING PROVIDED ON AN "AS IS" BASIS, WITHOUT
|
||||
WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED,
|
||||
INCLUDING WITHOUT LIMITATION, WARRANTIES OR CONDITIONS OF TITLE,
|
||||
NON-INFRINGEMENT, MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR
|
||||
ITS USE AND OPERATION EITHER ALONE OR IN COMBINATION WITH OTHER
|
||||
PRODUCTS.
|
||||
|
||||
IN NO EVENT SHALL NVIDIA BE LIABLE FOR ANY SPECIAL, INDIRECT,
|
||||
INCIDENTAL, EXEMPLARY, CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||
TO, LOST PROFITS; PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
|
||||
USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) OR ARISING IN ANY WAY
|
||||
OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION OF THE
|
||||
NVIDIA SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT,
|
||||
TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF
|
||||
NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
\****************************************************************************/
|
||||
@@ -1,15 +0,0 @@
|
||||
set(SOURCES InitializeDll.cpp InitializeDll.h)
|
||||
|
||||
add_library(OGLCompiler STATIC ${SOURCES})
|
||||
set_property(TARGET OGLCompiler PROPERTY FOLDER glslang)
|
||||
set_property(TARGET OGLCompiler PROPERTY POSITION_INDEPENDENT_CODE ON)
|
||||
|
||||
if(WIN32)
|
||||
source_group("Source" FILES ${SOURCES})
|
||||
endif(WIN32)
|
||||
|
||||
if(ENABLE_GLSLANG_INSTALL)
|
||||
install(TARGETS OGLCompiler EXPORT OGLCompilerTargets
|
||||
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR})
|
||||
install(EXPORT OGLCompilerTargets DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake)
|
||||
endif(ENABLE_GLSLANG_INSTALL)
|
||||
@@ -1,165 +0,0 @@
|
||||
//
|
||||
// Copyright (C) 2002-2005 3Dlabs Inc. Ltd.
|
||||
// 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 3Dlabs Inc. Ltd. 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 HOLDERS 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.
|
||||
//
|
||||
|
||||
#define SH_EXPORTING
|
||||
|
||||
#include <cassert>
|
||||
|
||||
#include "InitializeDll.h"
|
||||
#include "../glslang/Include/InitializeGlobals.h"
|
||||
#include "../glslang/Public/ShaderLang.h"
|
||||
#include "../glslang/Include/PoolAlloc.h"
|
||||
|
||||
namespace glslang {
|
||||
|
||||
OS_TLSIndex ThreadInitializeIndex = OS_INVALID_TLS_INDEX;
|
||||
|
||||
// Per-process initialization.
|
||||
// Needs to be called at least once before parsing, etc. is done.
|
||||
// Will also do thread initialization for the calling thread; other
|
||||
// threads will need to do that explicitly.
|
||||
bool InitProcess()
|
||||
{
|
||||
glslang::GetGlobalLock();
|
||||
|
||||
if (ThreadInitializeIndex != OS_INVALID_TLS_INDEX) {
|
||||
//
|
||||
// Function is re-entrant.
|
||||
//
|
||||
|
||||
glslang::ReleaseGlobalLock();
|
||||
return true;
|
||||
}
|
||||
|
||||
ThreadInitializeIndex = OS_AllocTLSIndex();
|
||||
|
||||
if (ThreadInitializeIndex == OS_INVALID_TLS_INDEX) {
|
||||
assert(0 && "InitProcess(): Failed to allocate TLS area for init flag");
|
||||
|
||||
glslang::ReleaseGlobalLock();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (! InitializePoolIndex()) {
|
||||
assert(0 && "InitProcess(): Failed to initialize global pool");
|
||||
|
||||
glslang::ReleaseGlobalLock();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (! InitThread()) {
|
||||
assert(0 && "InitProcess(): Failed to initialize thread");
|
||||
|
||||
glslang::ReleaseGlobalLock();
|
||||
return false;
|
||||
}
|
||||
|
||||
glslang::ReleaseGlobalLock();
|
||||
return true;
|
||||
}
|
||||
|
||||
// Per-thread scoped initialization.
|
||||
// Must be called at least once by each new thread sharing the
|
||||
// symbol tables, etc., needed to parse.
|
||||
bool InitThread()
|
||||
{
|
||||
//
|
||||
// This function is re-entrant
|
||||
//
|
||||
if (ThreadInitializeIndex == OS_INVALID_TLS_INDEX) {
|
||||
assert(0 && "InitThread(): Process hasn't been initalised.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (OS_GetTLSValue(ThreadInitializeIndex) != 0)
|
||||
return true;
|
||||
|
||||
if (! OS_SetTLSValue(ThreadInitializeIndex, (void *)1)) {
|
||||
assert(0 && "InitThread(): Unable to set init flag.");
|
||||
return false;
|
||||
}
|
||||
|
||||
glslang::SetThreadPoolAllocator(nullptr);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Not necessary to call this: InitThread() is reentrant, and the need
|
||||
// to do per thread tear down has been removed.
|
||||
//
|
||||
// This is kept, with memory management removed, to satisfy any exiting
|
||||
// calls to it that rely on it.
|
||||
bool DetachThread()
|
||||
{
|
||||
bool success = true;
|
||||
|
||||
if (ThreadInitializeIndex == OS_INVALID_TLS_INDEX)
|
||||
return true;
|
||||
|
||||
//
|
||||
// Function is re-entrant and this thread may not have been initialized.
|
||||
//
|
||||
if (OS_GetTLSValue(ThreadInitializeIndex) != 0) {
|
||||
if (!OS_SetTLSValue(ThreadInitializeIndex, (void *)0)) {
|
||||
assert(0 && "DetachThread(): Unable to clear init flag.");
|
||||
success = false;
|
||||
}
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
// Not necessary to call this: InitProcess() is reentrant.
|
||||
//
|
||||
// This is kept, with memory management removed, to satisfy any exiting
|
||||
// calls to it that rely on it.
|
||||
//
|
||||
// Users of glslang should call shFinalize() or glslang::FinalizeProcess() for
|
||||
// process-scoped memory tear down.
|
||||
bool DetachProcess()
|
||||
{
|
||||
bool success = true;
|
||||
|
||||
if (ThreadInitializeIndex == OS_INVALID_TLS_INDEX)
|
||||
return true;
|
||||
|
||||
success = DetachThread();
|
||||
|
||||
OS_FreeTLSIndex(ThreadInitializeIndex);
|
||||
ThreadInitializeIndex = OS_INVALID_TLS_INDEX;
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
} // end namespace glslang
|
||||
@@ -1,49 +0,0 @@
|
||||
//
|
||||
// Copyright (C) 2002-2005 3Dlabs Inc. Ltd.
|
||||
// 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 3Dlabs Inc. Ltd. 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 HOLDERS 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.
|
||||
//
|
||||
#ifndef __INITIALIZEDLL_H
|
||||
#define __INITIALIZEDLL_H
|
||||
|
||||
#include "../glslang/OSDependent/osinclude.h"
|
||||
|
||||
namespace glslang {
|
||||
|
||||
bool InitProcess();
|
||||
bool InitThread();
|
||||
bool DetachThread(); // not called from standalone, perhaps other tools rely on parts of it
|
||||
bool DetachProcess(); // not called from standalone, perhaps other tools rely on parts of it
|
||||
|
||||
} // end namespace glslang
|
||||
|
||||
#endif // __INITIALIZEDLL_H
|
||||
|
||||
@@ -1,137 +0,0 @@
|
||||
|
||||
VERSION
|
||||
--------------------------------------------------------------------------------
|
||||
spirv-remap 0.97
|
||||
|
||||
INTRO:
|
||||
--------------------------------------------------------------------------------
|
||||
spirv-remap is a utility to improve compression of SPIR-V binary files via
|
||||
entropy reduction, plus optional stripping of debug information and
|
||||
load/store optimization. It transforms SPIR-V to SPIR-V, remapping IDs. The
|
||||
resulting modules have an increased ID range (IDs are not as tightly packed
|
||||
around zero), but will compress better when multiple modules are compressed
|
||||
together, since compressor's dictionary can find better cross module
|
||||
commonality.
|
||||
|
||||
Remapping is accomplished via canonicalization. Thus, modules can be
|
||||
compressed one at a time with no loss of quality relative to operating on
|
||||
many modules at once. The command line tool operates on multiple modules
|
||||
only in the trivial repetition sense, for ease of use. The remapper API
|
||||
only accepts a single module at a time.
|
||||
|
||||
There are two modes of use: command line, and a C++11 API. Both are
|
||||
described below.
|
||||
|
||||
spirv-remap is currently in an alpha state. Although there are no known
|
||||
remapping defects, it has only been exercised on one real world game shader
|
||||
workload.
|
||||
|
||||
|
||||
FEEDBACK
|
||||
--------------------------------------------------------------------------------
|
||||
Report defects, enhancements requests, code improvements, etc to:
|
||||
[email protected]
|
||||
|
||||
|
||||
COMMAND LINE USAGE:
|
||||
--------------------------------------------------------------------------------
|
||||
Examples are given with a verbosity of one (-v), but more verbosity can be
|
||||
had via -vv, -vvv, etc, or an integer parameter to --verbose, such as
|
||||
"--verbose 4". With no verbosity, the command is silent and returns 0 on
|
||||
success, and a positive integer error on failure.
|
||||
|
||||
Pre-built binaries for several OSs are available. Examples presented are
|
||||
for Linux. Command line arguments can be provided in any order.
|
||||
|
||||
1. Basic ID remapping
|
||||
|
||||
Perform ID remapping on all shaders in "*.spv", writing new files with
|
||||
the same basenames to /tmp/out_dir.
|
||||
|
||||
spirv-remap -v --map all --input *.spv --output /tmp/out_dir
|
||||
|
||||
2. Perform all possible size reductions
|
||||
|
||||
spirv-remap-linux-64 -v --do-everything --input *.spv --output /tmp/out_dir
|
||||
|
||||
Note that --do-everything is a synonym for:
|
||||
|
||||
--map all --dce all --opt all --strip all
|
||||
|
||||
API USAGE:
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
The public interface to the remapper is defined in SPIRV/SPVRemapper.h as follows:
|
||||
|
||||
namespace spv {
|
||||
|
||||
class spirvbin_t
|
||||
{
|
||||
public:
|
||||
enum Options { ... };
|
||||
spirvbin_t(int verbose = 0); // construct
|
||||
|
||||
// remap an existing binary in memory
|
||||
void remap(std::vector<std::uint32_t>& spv, std::uint32_t opts = DO_EVERYTHING);
|
||||
|
||||
// Type for error/log handler functions
|
||||
typedef std::function<void(const std::string&)> errorfn_t;
|
||||
typedef std::function<void(const std::string&)> logfn_t;
|
||||
|
||||
// Register error/log handling functions (can be c/c++ fn, lambda fn, or functor)
|
||||
static void registerErrorHandler(errorfn_t handler) { errorHandler = handler; }
|
||||
static void registerLogHandler(logfn_t handler) { logHandler = handler; }
|
||||
};
|
||||
|
||||
} // namespace spv
|
||||
|
||||
The class definition is in SPVRemapper.cpp.
|
||||
|
||||
remap() accepts an std::vector of SPIR-V words, modifies them per the
|
||||
request given in 'opts', and leaves the 'spv' container with the result.
|
||||
It is safe to instantiate one spirvbin_t per thread and process a different
|
||||
SPIR-V in each.
|
||||
|
||||
The "opts" parameter to remap() accepts a bit mask of desired remapping
|
||||
options. See REMAPPING AND OPTIMIZATION OPTIONS.
|
||||
|
||||
On error, the function supplied to registerErrorHandler() will be invoked.
|
||||
This can be a standard C/C++ function, a lambda function, or a functor.
|
||||
The default handler simply calls exit(5); The error handler is a static
|
||||
member, so need only be set up once, not once per spirvbin_t instance.
|
||||
|
||||
Log messages are supplied to registerLogHandler(). By default, log
|
||||
messages are eaten silently. The log handler is also a static member.
|
||||
|
||||
BUILD DEPENDENCIES:
|
||||
--------------------------------------------------------------------------------
|
||||
1. C++11 compatible compiler
|
||||
2. cmake
|
||||
3. glslang
|
||||
|
||||
|
||||
BUILDING
|
||||
--------------------------------------------------------------------------------
|
||||
The standalone remapper is built along side glslangValidator through its
|
||||
normal build process.
|
||||
|
||||
|
||||
REMAPPING AND OPTIMIZATION OPTIONS
|
||||
--------------------------------------------------------------------------------
|
||||
API:
|
||||
These are bits defined under spv::spirvbin_t::, and can be
|
||||
bitwise or-ed together as desired.
|
||||
|
||||
MAP_TYPES = canonicalize type IDs
|
||||
MAP_NAMES = canonicalize named data
|
||||
MAP_FUNCS = canonicalize function bodies
|
||||
DCE_FUNCS = remove dead functions
|
||||
DCE_VARS = remove dead variables
|
||||
DCE_TYPES = remove dead types
|
||||
OPT_LOADSTORE = optimize unneeded load/stores
|
||||
MAP_ALL = (MAP_TYPES | MAP_NAMES | MAP_FUNCS)
|
||||
DCE_ALL = (DCE_FUNCS | DCE_VARS | DCE_TYPES)
|
||||
OPT_ALL = (OPT_LOADSTORE)
|
||||
ALL_BUT_STRIP = (MAP_ALL | DCE_ALL | OPT_ALL)
|
||||
DO_EVERYTHING = (STRIP | ALL_BUT_STRIP)
|
||||
|
||||
@@ -1,442 +0,0 @@
|
||||
# News
|
||||
|
||||
[](https://travis-ci.org/KhronosGroup/glslang)
|
||||
[](https://ci.appveyor.com/project/Khronoswebmaster/glslang/branch/master)
|
||||
|
||||
## Planned Deprecations/Removals
|
||||
|
||||
1. **SPIRV Folder, 1-May, 2020.** Glslang, when installed through CMake,
|
||||
will install a `SPIRV` folder into `${CMAKE_INSTALL_INCLUDEDIR}`.
|
||||
This `SPIRV` folder is being moved to `glslang/SPIRV`.
|
||||
During the transition the `SPIRV` folder will be installed into both locations.
|
||||
The old install of `SPIRV/` will be removed as a CMake install target no sooner than May 1, 2020.
|
||||
See issue #1964.
|
||||
|
||||
2. **Visual Studio 2013, 20-July, 2020.** Keeping code compiling for MS Visual Studio 2013 will no longer be
|
||||
a goal as of July 20, 2020, the fifth anniversary of the release of Visual Studio 2015.
|
||||
|
||||
# Glslang Components and Status
|
||||
|
||||
There are several components:
|
||||
|
||||
### Reference Validator and GLSL/ESSL -> AST Front End
|
||||
|
||||
An OpenGL GLSL and OpenGL|ES GLSL (ESSL) front-end for reference validation and translation of GLSL/ESSL into an internal abstract syntax tree (AST).
|
||||
|
||||
**Status**: Virtually complete, with results carrying similar weight as the specifications.
|
||||
|
||||
### HLSL -> AST Front End
|
||||
|
||||
An HLSL front-end for translation of an approximation of HLSL to glslang's AST form.
|
||||
|
||||
**Status**: Partially complete. Semantics are not reference quality and input is not validated.
|
||||
This is in contrast to the [DXC project](https://github.com/Microsoft/DirectXShaderCompiler), which receives a much larger investment and attempts to have definitive/reference-level semantics.
|
||||
|
||||
See [issue 362](https://github.com/KhronosGroup/glslang/issues/362) and [issue 701](https://github.com/KhronosGroup/glslang/issues/701) for current status.
|
||||
|
||||
### AST -> SPIR-V Back End
|
||||
|
||||
Translates glslang's AST to the Khronos-specified SPIR-V intermediate language.
|
||||
|
||||
**Status**: Virtually complete.
|
||||
|
||||
### Reflector
|
||||
|
||||
An API for getting reflection information from the AST, reflection types/variables/etc. from the HLL source (not the SPIR-V).
|
||||
|
||||
**Status**: There is a large amount of functionality present, but no specification/goal to measure completeness against. It is accurate for the input HLL and AST, but only approximate for what would later be emitted for SPIR-V.
|
||||
|
||||
### Standalone Wrapper
|
||||
|
||||
`glslangValidator` is command-line tool for accessing the functionality above.
|
||||
|
||||
Status: Complete.
|
||||
|
||||
Tasks waiting to be done are documented as GitHub issues.
|
||||
|
||||
## Other References
|
||||
|
||||
Also see the Khronos landing page for glslang as a reference front end:
|
||||
|
||||
https://www.khronos.org/opengles/sdk/tools/Reference-Compiler/
|
||||
|
||||
The above page, while not kept up to date, includes additional information regarding glslang as a reference validator.
|
||||
|
||||
# How to Use Glslang
|
||||
|
||||
## Execution of Standalone Wrapper
|
||||
|
||||
To use the standalone binary form, execute `glslangValidator`, and it will print
|
||||
a usage statement. Basic operation is to give it a file containing a shader,
|
||||
and it will print out warnings/errors and optionally an AST.
|
||||
|
||||
The applied stage-specific rules are based on the file extension:
|
||||
* `.vert` for a vertex shader
|
||||
* `.tesc` for a tessellation control shader
|
||||
* `.tese` for a tessellation evaluation shader
|
||||
* `.geom` for a geometry shader
|
||||
* `.frag` for a fragment shader
|
||||
* `.comp` for a compute shader
|
||||
|
||||
There is also a non-shader extension
|
||||
* `.conf` for a configuration file of limits, see usage statement for example
|
||||
|
||||
## Building
|
||||
|
||||
Instead of building manually, you can also download the binaries for your
|
||||
platform directly from the [master-tot release][master-tot-release] on GitHub.
|
||||
Those binaries are automatically uploaded by the buildbots after successful
|
||||
testing and they always reflect the current top of the tree of the master
|
||||
branch.
|
||||
|
||||
### Dependencies
|
||||
|
||||
* A C++11 compiler.
|
||||
(For MSVS: 2015 is recommended, 2013 is fully supported/tested, and 2010 support is attempted, but not tested.)
|
||||
* [CMake][cmake]: for generating compilation targets.
|
||||
* make: _Linux_, ninja is an alternative, if configured.
|
||||
* [Python 3.x][python]: for executing SPIRV-Tools scripts. (Optional if not using SPIRV-Tools and the 'External' subdirectory does not exist.)
|
||||
* [bison][bison]: _optional_, but needed when changing the grammar (glslang.y).
|
||||
* [googletest][googletest]: _optional_, but should use if making any changes to glslang.
|
||||
|
||||
### Build steps
|
||||
|
||||
The following steps assume a Bash shell. On Windows, that could be the Git Bash
|
||||
shell or some other shell of your choosing.
|
||||
|
||||
#### 1) Check-Out this project
|
||||
|
||||
```bash
|
||||
cd <parent of where you want glslang to be>
|
||||
git clone https://github.com/KhronosGroup/glslang.git
|
||||
```
|
||||
|
||||
#### 2) Check-Out External Projects
|
||||
|
||||
```bash
|
||||
cd <the directory glslang was cloned to, "External" will be a subdirectory>
|
||||
git clone https://github.com/google/googletest.git External/googletest
|
||||
```
|
||||
|
||||
If you want to use googletest with Visual Studio 2013, you also need to check out an older version:
|
||||
|
||||
```bash
|
||||
# to use googletest with Visual Studio 2013
|
||||
cd External/googletest
|
||||
git checkout 440527a61e1c91188195f7de212c63c77e8f0a45
|
||||
cd ../..
|
||||
```
|
||||
|
||||
If you wish to assure that SPIR-V generated from HLSL is legal for Vulkan,
|
||||
wish to invoke -Os to reduce SPIR-V size from HLSL or GLSL, or wish to run the
|
||||
integrated test suite, install spirv-tools with this:
|
||||
|
||||
```bash
|
||||
./update_glslang_sources.py
|
||||
```
|
||||
|
||||
#### 3) Configure
|
||||
|
||||
Assume the source directory is `$SOURCE_DIR` and the build directory is
|
||||
`$BUILD_DIR`. First ensure the build directory exists, then navigate to it:
|
||||
|
||||
```bash
|
||||
mkdir -p $BUILD_DIR
|
||||
cd $BUILD_DIR
|
||||
```
|
||||
|
||||
For building on Linux:
|
||||
|
||||
```bash
|
||||
cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX="$(pwd)/install" $SOURCE_DIR
|
||||
# "Release" (for CMAKE_BUILD_TYPE) could also be "Debug" or "RelWithDebInfo"
|
||||
```
|
||||
|
||||
For building on Android:
|
||||
```bash
|
||||
cmake $SOURCE_DIR -G "Unix Makefiles" -DCMAKE_INSTALL_PREFIX="$(pwd)/install" -DANDROID_ABI=arm64-v8a -DCMAKE_BUILD_TYPE=Release -DANDROID_STL=c++_static -DANDROID_PLATFORM=android-24 -DCMAKE_SYSTEM_NAME=Android -DANDROID_TOOLCHAIN=clang -DANDROID_ARM_MODE=arm -DCMAKE_MAKE_PROGRAM=$ANDROID_NDK_ROOT/prebuilt/linux-x86_64/bin/make -DCMAKE_TOOLCHAIN_FILE=$ANDROID_NDK_ROOT/build/cmake/android.toolchain.cmake
|
||||
# If on Windows will be -DCMAKE_MAKE_PROGRAM=%ANDROID_NDK_ROOT%\prebuilt\windows-x86_64\bin\make.exe
|
||||
# -G is needed for building on Windows
|
||||
# -DANDROID_ABI can also be armeabi-v7a for 32 bit
|
||||
```
|
||||
|
||||
For building on Windows:
|
||||
|
||||
```bash
|
||||
cmake $SOURCE_DIR -DCMAKE_INSTALL_PREFIX="$(pwd)/install"
|
||||
# The CMAKE_INSTALL_PREFIX part is for testing (explained later).
|
||||
```
|
||||
|
||||
The CMake GUI also works for Windows (version 3.4.1 tested).
|
||||
|
||||
Also, consider using `git config --global core.fileMode false` (or with `--local`) on Windows
|
||||
to prevent the addition of execution permission on files.
|
||||
|
||||
#### 4) Build and Install
|
||||
|
||||
```bash
|
||||
# for Linux:
|
||||
make -j4 install
|
||||
|
||||
# for Windows:
|
||||
cmake --build . --config Release --target install
|
||||
# "Release" (for --config) could also be "Debug", "MinSizeRel", or "RelWithDebInfo"
|
||||
```
|
||||
|
||||
If using MSVC, after running CMake to configure, use the
|
||||
Configuration Manager to check the `INSTALL` project.
|
||||
|
||||
### If you need to change the GLSL grammar
|
||||
|
||||
The grammar in `glslang/MachineIndependent/glslang.y` has to be recompiled with
|
||||
bison if it changes, the output files are committed to the repo to avoid every
|
||||
developer needing to have bison configured to compile the project when grammar
|
||||
changes are quite infrequent. For windows you can get binaries from
|
||||
[GnuWin32][bison-gnu-win32].
|
||||
|
||||
The command to rebuild is:
|
||||
|
||||
```bash
|
||||
m4 -P MachineIndependent/glslang.m4 > MachineIndependent/glslang.y
|
||||
bison --defines=MachineIndependent/glslang_tab.cpp.h
|
||||
-t MachineIndependent/glslang.y
|
||||
-o MachineIndependent/glslang_tab.cpp
|
||||
```
|
||||
|
||||
The above commands are also available in the bash script in `updateGrammar`,
|
||||
when executed from the glslang subdirectory of the glslang repository.
|
||||
With no arguments it builds the full grammar, and with a "web" argument,
|
||||
the web grammar subset (see more about the web subset in the next section).
|
||||
|
||||
### Building to WASM for the Web and Node
|
||||
### Building a standalone JS/WASM library for the Web and Node
|
||||
|
||||
Use the steps in [Build Steps](#build-steps), with the following notes/exceptions:
|
||||
* `emsdk` needs to be present in your executable search path, *PATH* for
|
||||
Bash-like environments:
|
||||
+ [Instructions located here](https://emscripten.org/docs/getting_started/downloads.html#sdk-download-and-install)
|
||||
* Wrap cmake call: `emcmake cmake`
|
||||
* Set `-DBUILD_TESTING=OFF -DENABLE_OPT=OFF -DINSTALL_GTEST=OFF`.
|
||||
* Set `-DENABLE_HLSL=OFF` if HLSL is not needed.
|
||||
* For a standalone JS/WASM library, turn on `-DENABLE_GLSLANG_JS=ON`.
|
||||
* For building a minimum-size web subset of core glslang:
|
||||
+ turn on `-DENABLE_GLSLANG_WEBMIN=ON` (disables HLSL)
|
||||
+ execute `updateGrammar web` from the glslang subdirectory
|
||||
(or if using your own scripts, `m4` needs a `-DGLSLANG_WEB` argument)
|
||||
+ optionally, for GLSL compilation error messages, turn on
|
||||
`-DENABLE_GLSLANG_WEBMIN_DEVEL=ON`
|
||||
* To get a fully minimized build, make sure to use `brotli` to compress the .js
|
||||
and .wasm files
|
||||
|
||||
Example:
|
||||
|
||||
```sh
|
||||
emcmake cmake -DCMAKE_BUILD_TYPE=Release -DENABLE_GLSLANG_JS=ON \
|
||||
-DENABLE_HLSL=OFF -DBUILD_TESTING=OFF -DENABLE_OPT=OFF -DINSTALL_GTEST=OFF ..
|
||||
```
|
||||
|
||||
## Building glslang - Using vcpkg
|
||||
|
||||
You can download and install glslang using the [vcpkg](https://github.com/Microsoft/vcpkg) dependency manager:
|
||||
|
||||
git clone https://github.com/Microsoft/vcpkg.git
|
||||
cd vcpkg
|
||||
./bootstrap-vcpkg.sh
|
||||
./vcpkg integrate install
|
||||
./vcpkg install glslang
|
||||
|
||||
The glslang port in vcpkg is kept up to date by Microsoft team members and community contributors. If the version is out of date, please [create an issue or pull request](https://github.com/Microsoft/vcpkg) on the vcpkg repository.
|
||||
|
||||
## Testing
|
||||
|
||||
Right now, there are two test harnesses existing in glslang: one is [Google
|
||||
Test](gtests/), one is the [`runtests` script](Test/runtests). The former
|
||||
runs unit tests and single-shader single-threaded integration tests, while
|
||||
the latter runs multiple-shader linking tests and multi-threaded tests.
|
||||
|
||||
### Running tests
|
||||
|
||||
The [`runtests` script](Test/runtests) requires compiled binaries to be
|
||||
installed into `$BUILD_DIR/install`. Please make sure you have supplied the
|
||||
correct configuration to CMake (using `-DCMAKE_INSTALL_PREFIX`) when building;
|
||||
otherwise, you may want to modify the path in the `runtests` script.
|
||||
|
||||
Running Google Test-backed tests:
|
||||
|
||||
```bash
|
||||
cd $BUILD_DIR
|
||||
|
||||
# for Linux:
|
||||
ctest
|
||||
|
||||
# for Windows:
|
||||
ctest -C {Debug|Release|RelWithDebInfo|MinSizeRel}
|
||||
|
||||
# or, run the test binary directly
|
||||
# (which gives more fine-grained control like filtering):
|
||||
<dir-to-glslangtests-in-build-dir>/glslangtests
|
||||
```
|
||||
|
||||
Running `runtests` script-backed tests:
|
||||
|
||||
```bash
|
||||
cd $SOURCE_DIR/Test && ./runtests
|
||||
```
|
||||
|
||||
If some tests fail with validation errors, there may be a mismatch between the
|
||||
version of `spirv-val` on the system and the version of glslang. In this
|
||||
case, it is necessary to run `update_glslang_sources.py`. See "Check-Out
|
||||
External Projects" above for more details.
|
||||
|
||||
### Contributing tests
|
||||
|
||||
Test results should always be included with a pull request that modifies
|
||||
functionality.
|
||||
|
||||
If you are writing unit tests, please use the Google Test framework and
|
||||
place the tests under the `gtests/` directory.
|
||||
|
||||
Integration tests are placed in the `Test/` directory. It contains test input
|
||||
and a subdirectory `baseResults/` that contains the expected results of the
|
||||
tests. Both the tests and `baseResults/` are under source-code control.
|
||||
|
||||
Google Test runs those integration tests by reading the test input, compiling
|
||||
them, and then compare against the expected results in `baseResults/`. The
|
||||
integration tests to run via Google Test is registered in various
|
||||
`gtests/*.FromFile.cpp` source files. `glslangtests` provides a command-line
|
||||
option `--update-mode`, which, if supplied, will overwrite the golden files
|
||||
under the `baseResults/` directory with real output from that invocation.
|
||||
For more information, please check `gtests/` directory's
|
||||
[README](gtests/README.md).
|
||||
|
||||
For the `runtests` script, it will generate current results in the
|
||||
`localResults/` directory and `diff` them against the `baseResults/`.
|
||||
When you want to update the tracked test results, they need to be
|
||||
copied from `localResults/` to `baseResults/`. This can be done by
|
||||
the `bump` shell script.
|
||||
|
||||
You can add your own private list of tests, not tracked publicly, by using
|
||||
`localtestlist` to list non-tracked tests. This is automatically read
|
||||
by `runtests` and included in the `diff` and `bump` process.
|
||||
|
||||
## Programmatic Interfaces
|
||||
|
||||
Another piece of software can programmatically translate shaders to an AST
|
||||
using one of two different interfaces:
|
||||
* A new C++ class-oriented interface, or
|
||||
* The original C functional interface
|
||||
|
||||
The `main()` in `StandAlone/StandAlone.cpp` shows examples using both styles.
|
||||
|
||||
### C++ Class Interface (new, preferred)
|
||||
|
||||
This interface is in roughly the last 1/3 of `ShaderLang.h`. It is in the
|
||||
glslang namespace and contains the following, here with suggested calls
|
||||
for generating SPIR-V:
|
||||
|
||||
```cxx
|
||||
const char* GetEsslVersionString();
|
||||
const char* GetGlslVersionString();
|
||||
bool InitializeProcess();
|
||||
void FinalizeProcess();
|
||||
|
||||
class TShader
|
||||
setStrings(...);
|
||||
setEnvInput(EShSourceHlsl or EShSourceGlsl, stage, EShClientVulkan or EShClientOpenGL, 100);
|
||||
setEnvClient(EShClientVulkan or EShClientOpenGL, EShTargetVulkan_1_0 or EShTargetVulkan_1_1 or EShTargetOpenGL_450);
|
||||
setEnvTarget(EShTargetSpv, EShTargetSpv_1_0 or EShTargetSpv_1_3);
|
||||
bool parse(...);
|
||||
const char* getInfoLog();
|
||||
|
||||
class TProgram
|
||||
void addShader(...);
|
||||
bool link(...);
|
||||
const char* getInfoLog();
|
||||
Reflection queries
|
||||
```
|
||||
|
||||
For just validating (not generating code), substitute these calls:
|
||||
|
||||
```cxx
|
||||
setEnvInput(EShSourceHlsl or EShSourceGlsl, stage, EShClientNone, 0);
|
||||
setEnvClient(EShClientNone, 0);
|
||||
setEnvTarget(EShTargetNone, 0);
|
||||
```
|
||||
|
||||
See `ShaderLang.h` and the usage of it in `StandAlone/StandAlone.cpp` for more
|
||||
details. There is a block comment giving more detail above the calls for
|
||||
`setEnvInput, setEnvClient, and setEnvTarget`.
|
||||
|
||||
### C Functional Interface (original)
|
||||
|
||||
This interface is in roughly the first 2/3 of `ShaderLang.h`, and referred to
|
||||
as the `Sh*()` interface, as all the entry points start `Sh`.
|
||||
|
||||
The `Sh*()` interface takes a "compiler" call-back object, which it calls after
|
||||
building call back that is passed the AST and can then execute a back end on it.
|
||||
|
||||
The following is a simplified resulting run-time call stack:
|
||||
|
||||
```c
|
||||
ShCompile(shader, compiler) -> compiler(AST) -> <back end>
|
||||
```
|
||||
|
||||
In practice, `ShCompile()` takes shader strings, default version, and
|
||||
warning/error and other options for controlling compilation.
|
||||
|
||||
## Basic Internal Operation
|
||||
|
||||
* Initial lexical analysis is done by the preprocessor in
|
||||
`MachineIndependent/Preprocessor`, and then refined by a GLSL scanner
|
||||
in `MachineIndependent/Scan.cpp`. There is currently no use of flex.
|
||||
|
||||
* Code is parsed using bison on `MachineIndependent/glslang.y` with the
|
||||
aid of a symbol table and an AST. The symbol table is not passed on to
|
||||
the back-end; the intermediate representation stands on its own.
|
||||
The tree is built by the grammar productions, many of which are
|
||||
offloaded into `ParseHelper.cpp`, and by `Intermediate.cpp`.
|
||||
|
||||
* The intermediate representation is very high-level, and represented
|
||||
as an in-memory tree. This serves to lose no information from the
|
||||
original program, and to have efficient transfer of the result from
|
||||
parsing to the back-end. In the AST, constants are propagated and
|
||||
folded, and a very small amount of dead code is eliminated.
|
||||
|
||||
To aid linking and reflection, the last top-level branch in the AST
|
||||
lists all global symbols.
|
||||
|
||||
* The primary algorithm of the back-end compiler is to traverse the
|
||||
tree (high-level intermediate representation), and create an internal
|
||||
object code representation. There is an example of how to do this
|
||||
in `MachineIndependent/intermOut.cpp`.
|
||||
|
||||
* Reduction of the tree to a linear byte-code style low-level intermediate
|
||||
representation is likely a good way to generate fully optimized code.
|
||||
|
||||
* There is currently some dead old-style linker-type code still lying around.
|
||||
|
||||
* Memory pool: parsing uses types derived from C++ `std` types, using a
|
||||
custom allocator that puts them in a memory pool. This makes allocation
|
||||
of individual container/contents just few cycles and deallocation free.
|
||||
This pool is popped after the AST is made and processed.
|
||||
|
||||
The use is simple: if you are going to call `new`, there are three cases:
|
||||
|
||||
- the object comes from the pool (its base class has the macro
|
||||
`POOL_ALLOCATOR_NEW_DELETE` in it) and you do not have to call `delete`
|
||||
|
||||
- it is a `TString`, in which case call `NewPoolTString()`, which gets
|
||||
it from the pool, and there is no corresponding `delete`
|
||||
|
||||
- the object does not come from the pool, and you have to do normal
|
||||
C++ memory management of what you `new`
|
||||
|
||||
* Features can be protected by version/extension/stage/profile:
|
||||
See the comment in `glslang/MachineIndependent/Versions.cpp`.
|
||||
|
||||
[cmake]: https://cmake.org/
|
||||
[python]: https://www.python.org/
|
||||
[bison]: https://www.gnu.org/software/bison/
|
||||
[googletest]: https://github.com/google/googletest
|
||||
[bison-gnu-win32]: http://gnuwin32.sourceforge.net/packages/bison.htm
|
||||
[master-tot-release]: https://github.com/KhronosGroup/glslang/releases/tag/master-tot
|
||||
@@ -1,103 +0,0 @@
|
||||
set(SOURCES
|
||||
GlslangToSpv.cpp
|
||||
InReadableOrder.cpp
|
||||
Logger.cpp
|
||||
SpvBuilder.cpp
|
||||
SpvPostProcess.cpp
|
||||
doc.cpp
|
||||
SpvTools.cpp
|
||||
disassemble.cpp)
|
||||
|
||||
set(SPVREMAP_SOURCES
|
||||
SPVRemapper.cpp
|
||||
doc.cpp)
|
||||
|
||||
set(HEADERS
|
||||
bitutils.h
|
||||
spirv.hpp
|
||||
GLSL.std.450.h
|
||||
GLSL.ext.EXT.h
|
||||
GLSL.ext.KHR.h
|
||||
GlslangToSpv.h
|
||||
hex_float.h
|
||||
Logger.h
|
||||
SpvBuilder.h
|
||||
spvIR.h
|
||||
doc.h
|
||||
SpvTools.h
|
||||
disassemble.h
|
||||
GLSL.ext.AMD.h
|
||||
GLSL.ext.NV.h
|
||||
NonSemanticDebugPrintf.h)
|
||||
|
||||
set(SPVREMAP_HEADERS
|
||||
SPVRemapper.h
|
||||
doc.h)
|
||||
|
||||
add_library(SPIRV ${LIB_TYPE} ${SOURCES} ${HEADERS})
|
||||
set_property(TARGET SPIRV PROPERTY FOLDER glslang)
|
||||
set_property(TARGET SPIRV PROPERTY POSITION_INDEPENDENT_CODE ON)
|
||||
target_include_directories(SPIRV PUBLIC
|
||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/..>
|
||||
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>)
|
||||
|
||||
if (ENABLE_SPVREMAPPER)
|
||||
add_library(SPVRemapper ${LIB_TYPE} ${SPVREMAP_SOURCES} ${SPVREMAP_HEADERS})
|
||||
set_property(TARGET SPVRemapper PROPERTY FOLDER glslang)
|
||||
set_property(TARGET SPVRemapper PROPERTY POSITION_INDEPENDENT_CODE ON)
|
||||
endif()
|
||||
|
||||
if(WIN32 AND BUILD_SHARED_LIBS)
|
||||
set_target_properties(SPIRV PROPERTIES PREFIX "")
|
||||
if (ENABLE_SPVREMAPPER)
|
||||
set_target_properties(SPVRemapper PROPERTIES PREFIX "")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(ENABLE_OPT)
|
||||
target_include_directories(SPIRV
|
||||
PRIVATE ${spirv-tools_SOURCE_DIR}/include
|
||||
PRIVATE ${spirv-tools_SOURCE_DIR}/source
|
||||
)
|
||||
target_link_libraries(SPIRV glslang SPIRV-Tools-opt)
|
||||
target_include_directories(SPIRV PUBLIC
|
||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/../External>
|
||||
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}/External>)
|
||||
else()
|
||||
target_link_libraries(SPIRV glslang)
|
||||
endif(ENABLE_OPT)
|
||||
|
||||
if(WIN32)
|
||||
source_group("Source" FILES ${SOURCES} ${HEADERS})
|
||||
source_group("Source" FILES ${SPVREMAP_SOURCES} ${SPVREMAP_HEADERS})
|
||||
endif(WIN32)
|
||||
|
||||
if(ENABLE_GLSLANG_INSTALL)
|
||||
if(BUILD_SHARED_LIBS)
|
||||
if (ENABLE_SPVREMAPPER)
|
||||
install(TARGETS SPVRemapper EXPORT SPVRemapperTargets
|
||||
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR})
|
||||
endif()
|
||||
install(TARGETS SPIRV EXPORT SPIRVTargets
|
||||
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
|
||||
else()
|
||||
if (ENABLE_SPVREMAPPER)
|
||||
install(TARGETS SPVRemapper EXPORT SPVRemapperTargets
|
||||
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR})
|
||||
endif()
|
||||
install(TARGETS SPIRV EXPORT SPIRVTargets
|
||||
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR})
|
||||
endif()
|
||||
|
||||
if (ENABLE_SPVREMAPPER)
|
||||
install(EXPORT SPVRemapperTargets DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake)
|
||||
endif()
|
||||
|
||||
install(EXPORT SPIRVTargets DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake)
|
||||
|
||||
install(FILES ${HEADERS} ${SPVREMAP_HEADERS} DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/SPIRV/)
|
||||
install(FILES ${HEADERS} ${SPVREMAP_HEADERS} DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/glslang/SPIRV/)
|
||||
endif(ENABLE_GLSLANG_INSTALL)
|
||||
Loaded 100 of 4295 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user