mirror of
https://github.com/libsdl-org/SDL.git
synced 2025-10-03 08:28:29 +00:00
Compare commits
702 Commits
release-3.
...
release-3.
Author | SHA1 | Date | |
---|---|---|---|
![]() |
a8589a8422 | ||
![]() |
0bdaaf6c76 | ||
![]() |
390197d3aa | ||
![]() |
9fafba49dc | ||
![]() |
5d47efe7fb | ||
![]() |
824234accc | ||
![]() |
6519158ae5 | ||
![]() |
00718d60d2 | ||
![]() |
18c2e179ee | ||
![]() |
21ae008fc2 | ||
![]() |
97a8bb44e6 | ||
![]() |
5d33fce898 | ||
![]() |
bb5df96f69 | ||
![]() |
12b97944f3 | ||
![]() |
0f17fbe1ca | ||
![]() |
c3480ca99c | ||
![]() |
936d94c2ee | ||
![]() |
6cb55ebd46 | ||
![]() |
482c5130eb | ||
![]() |
066bcc5204 | ||
![]() |
21baa27bea | ||
![]() |
93fd4a1c80 | ||
![]() |
7135779599 | ||
![]() |
62c151d044 | ||
![]() |
11d38fc23b | ||
![]() |
d027f0ae6e | ||
![]() |
44290c204e | ||
![]() |
0b69860af6 | ||
![]() |
e7a1ae0ea5 | ||
![]() |
7af36d6c40 | ||
![]() |
d1ae1163dd | ||
![]() |
b2cf5729b4 | ||
![]() |
11b8dd76db | ||
![]() |
56507a6122 | ||
![]() |
8d4324cba2 | ||
![]() |
35408a2126 | ||
![]() |
e5b9dfd181 | ||
![]() |
e8a5d07e5e | ||
![]() |
8c1daf0caf | ||
![]() |
ad2b211f75 | ||
![]() |
414ae344af | ||
![]() |
71af2c020c | ||
![]() |
e755f50072 | ||
![]() |
a0b8275e9c | ||
![]() |
ea362839b1 | ||
![]() |
e7dd5d841b | ||
![]() |
5594d03da0 | ||
![]() |
f2ae66b64f | ||
![]() |
393d99338f | ||
![]() |
4d88280931 | ||
![]() |
e8cc359b5e | ||
![]() |
3b4a198655 | ||
![]() |
03dd1520a3 | ||
![]() |
a6fd74fa3b | ||
![]() |
03b36bac94 | ||
![]() |
a96677bdf6 | ||
![]() |
67f89d0a2b | ||
![]() |
f6de8877ec | ||
![]() |
7c189b1f17 | ||
![]() |
a7947080c0 | ||
![]() |
08c82a3781 | ||
![]() |
589aea50c2 | ||
![]() |
72acd7c9df | ||
![]() |
1a70d1158e | ||
![]() |
ae915c6516 | ||
![]() |
54d573332e | ||
![]() |
0204a69f6b | ||
![]() |
b2689ff76a | ||
![]() |
611940fb80 | ||
![]() |
16c0329a2a | ||
![]() |
2743716132 | ||
![]() |
a744eee993 | ||
![]() |
0e24267eb5 | ||
![]() |
f4d6043aa4 | ||
![]() |
9fb9bd31a3 | ||
![]() |
c3828bb0a3 | ||
![]() |
40371f0907 | ||
![]() |
94f9434564 | ||
![]() |
bfaf247d30 | ||
![]() |
2287c43b59 | ||
![]() |
15cc0f5f91 | ||
![]() |
68e0108b1c | ||
![]() |
7b3796bc39 | ||
![]() |
b5bc6d2cc4 | ||
![]() |
0d1d4ea1f9 | ||
![]() |
1a48f897f2 | ||
![]() |
2b42789de6 | ||
![]() |
b9c1da10ba | ||
![]() |
56f5a76696 | ||
![]() |
c7e8977e60 | ||
![]() |
e6ba3612db | ||
![]() |
5e77fb314c | ||
![]() |
1a2841deb1 | ||
![]() |
688637eca8 | ||
![]() |
85d1d70ca1 | ||
![]() |
09356c709a | ||
![]() |
07b9e86d02 | ||
![]() |
8e46e5d8b4 | ||
![]() |
96292a5b46 | ||
![]() |
ffa618c00b | ||
![]() |
291b9b3c82 | ||
![]() |
ec45117f0f | ||
![]() |
0d7aff9c56 | ||
![]() |
d31b239288 | ||
![]() |
b1cadf0e99 | ||
![]() |
c1f67585e6 | ||
![]() |
93988e28c0 | ||
![]() |
edef6e66e9 | ||
![]() |
e3f47809c4 | ||
![]() |
f759e7ac59 | ||
![]() |
544eb2c5a9 | ||
![]() |
30e3eba20a | ||
![]() |
f0e85a2a9c | ||
![]() |
106af5b46a | ||
![]() |
522716ed90 | ||
![]() |
a65fbb0211 | ||
![]() |
46ec859bd1 | ||
![]() |
2a7aa4eae4 | ||
![]() |
c31ddf021e | ||
![]() |
eaa2a8239f | ||
![]() |
d313ecb737 | ||
![]() |
64b2af0340 | ||
![]() |
58d0702948 | ||
![]() |
707717e94b | ||
![]() |
a140bba55a | ||
![]() |
f4ddacacd0 | ||
![]() |
ebba656bdb | ||
![]() |
b78c61d67a | ||
![]() |
4210aa61e1 | ||
![]() |
d8a345d924 | ||
![]() |
b8dc9767da | ||
![]() |
1ab01b9367 | ||
![]() |
ee371ff740 | ||
![]() |
ef58dd77ca | ||
![]() |
e6a7121904 | ||
![]() |
a6ed8ab59d | ||
![]() |
bd40d0ded1 | ||
![]() |
68bfcb6c54 | ||
![]() |
0d01efca52 | ||
![]() |
0e65e04ce1 | ||
![]() |
58d351fe98 | ||
![]() |
9b71f18141 | ||
![]() |
554f08bac3 | ||
![]() |
913813a933 | ||
![]() |
4e34c771e4 | ||
![]() |
9995174e68 | ||
![]() |
5a0197d430 | ||
![]() |
4a55143e15 | ||
![]() |
87c9bc1b1f | ||
![]() |
16a57b70f7 | ||
![]() |
69564cd0b1 | ||
![]() |
da648b00e7 | ||
![]() |
5886d90308 | ||
![]() |
e84df0cad1 | ||
![]() |
e482904111 | ||
![]() |
b8ee44ca6a | ||
![]() |
4a4abe4240 | ||
![]() |
fe47f5cc30 | ||
![]() |
5b64be0810 | ||
![]() |
17656d051b | ||
![]() |
233fce456a | ||
![]() |
5290bb036c | ||
![]() |
2bff72b4f6 | ||
![]() |
08ebeaee5c | ||
![]() |
12b56f5447 | ||
![]() |
165b86e7b7 | ||
![]() |
608101a185 | ||
![]() |
554bee6aae | ||
![]() |
3e0ce51067 | ||
![]() |
7261c43342 | ||
![]() |
ad57c6ea37 | ||
![]() |
caecff650d | ||
![]() |
f6300be4b2 | ||
![]() |
bde5687a3c | ||
![]() |
0f3504f78d | ||
![]() |
0aaa0321cc | ||
![]() |
caaaf52583 | ||
![]() |
56449f167d | ||
![]() |
c7325228dc | ||
![]() |
079967afa5 | ||
![]() |
2ed55b614c | ||
![]() |
28721e3cd2 | ||
![]() |
9d9845d063 | ||
![]() |
a96dc76831 | ||
![]() |
ad8e517227 | ||
![]() |
8d578d590f | ||
![]() |
6b4a211374 | ||
![]() |
55b023c961 | ||
![]() |
e2d0fe3e2f | ||
![]() |
6b56ff7a97 | ||
![]() |
67f796ebde | ||
![]() |
06da7490fc | ||
![]() |
af83c442d3 | ||
![]() |
d726e98596 | ||
![]() |
c9a6709bd2 | ||
![]() |
25816bea41 | ||
![]() |
e0f6e96da0 | ||
![]() |
57de46ae7e | ||
![]() |
59693c8996 | ||
![]() |
f0efffc093 | ||
![]() |
1b41cd759c | ||
![]() |
d42a1402e8 | ||
![]() |
5c44678d55 | ||
![]() |
0638fd58ce | ||
![]() |
cb662b6730 | ||
![]() |
e874c7515e | ||
![]() |
2ba797576b | ||
![]() |
180b454d61 | ||
![]() |
6ce7ae77b1 | ||
![]() |
abbaf95cf0 | ||
![]() |
1081b70951 | ||
![]() |
4f51f956ad | ||
![]() |
b076f4b590 | ||
![]() |
91180f8cb4 | ||
![]() |
99aa859362 | ||
![]() |
31267feb03 | ||
![]() |
6a5bac72cb | ||
![]() |
2ed5062950 | ||
![]() |
0b0b02c5a1 | ||
![]() |
28c71368a1 | ||
![]() |
25bd4285ab | ||
![]() |
180171cad6 | ||
![]() |
bc3eeecf7f | ||
![]() |
9178d14519 | ||
![]() |
6cd35f5b72 | ||
![]() |
72d5eb0ecb | ||
![]() |
5cf924420d | ||
![]() |
290574e6f6 | ||
![]() |
d9db975b4b | ||
![]() |
e5c0e5efa7 | ||
![]() |
26a1aae098 | ||
![]() |
ab114490fc | ||
![]() |
9546c54286 | ||
![]() |
4d3cdb70b5 | ||
![]() |
a66816a72f | ||
![]() |
c925f72562 | ||
![]() |
ef97329f41 | ||
![]() |
195f709eda | ||
![]() |
eb57d94ec5 | ||
![]() |
d6212ae839 | ||
![]() |
b494897b3d | ||
![]() |
559d4415eb | ||
![]() |
49e9134774 | ||
![]() |
9571b0ece8 | ||
![]() |
b55cfaf90b | ||
![]() |
509168856f | ||
![]() |
24fa2722c3 | ||
![]() |
142700f909 | ||
![]() |
f3611681df | ||
![]() |
7f0a5d6a10 | ||
![]() |
2001cc15d5 | ||
![]() |
8d604353a5 | ||
![]() |
8410e11ecb | ||
![]() |
9f8161bf4a | ||
![]() |
c038d6f7f8 | ||
![]() |
2fff37fffc | ||
![]() |
6feb86be71 | ||
![]() |
ed22220bc6 | ||
![]() |
219cb1a59d | ||
![]() |
71bd25a893 | ||
![]() |
01ef4c46a1 | ||
![]() |
64f728ec48 | ||
![]() |
ba10adf1fb | ||
![]() |
c18aa99358 | ||
![]() |
3498412611 | ||
![]() |
8c1b3ff210 | ||
![]() |
1870052af6 | ||
![]() |
3b1e3d5176 | ||
![]() |
cdf26c6e97 | ||
![]() |
9f1a1405a6 | ||
![]() |
6e97d8d1b3 | ||
![]() |
9d9a24d325 | ||
![]() |
0897f4a7d1 | ||
![]() |
5aec645191 | ||
![]() |
07c33068f3 | ||
![]() |
d684e5d57e | ||
![]() |
219500d95c | ||
![]() |
810addf7ae | ||
![]() |
4ef077ca52 | ||
![]() |
7d2275c4dc | ||
![]() |
cbd8917047 | ||
![]() |
c98a19401c | ||
![]() |
434836c480 | ||
![]() |
50d02ad732 | ||
![]() |
5ac37a8ffc | ||
![]() |
7dd2915475 | ||
![]() |
0ae1ddee17 | ||
![]() |
db4c7e47f1 | ||
![]() |
362445460e | ||
![]() |
de5cb9db23 | ||
![]() |
418eab29eb | ||
![]() |
2f3d242183 | ||
![]() |
4ad6d18203 | ||
![]() |
cd4a4f8a9f | ||
![]() |
a96e72da02 | ||
![]() |
337f012de2 | ||
![]() |
3c29b620e4 | ||
![]() |
579fc161f0 | ||
![]() |
22e968af4e | ||
![]() |
e37e96cfff | ||
![]() |
56c76c20a0 | ||
![]() |
efd812c399 | ||
![]() |
b2b92bbe25 | ||
![]() |
a29c67ac94 | ||
![]() |
f88e0aaac0 | ||
![]() |
29a4a4a5d1 | ||
![]() |
01000c73b0 | ||
![]() |
1a5d1dfef0 | ||
![]() |
2c38143834 | ||
![]() |
c56a1c664c | ||
![]() |
41cae64580 | ||
![]() |
c6dd2662c3 | ||
![]() |
f48027cf12 | ||
![]() |
fabbc8d183 | ||
![]() |
a142e5ef7d | ||
![]() |
825c0c7691 | ||
![]() |
dc30a00a26 | ||
![]() |
5a05ef01ad | ||
![]() |
0237997e4d | ||
![]() |
4f90432a49 | ||
![]() |
0cd6942bfc | ||
![]() |
1beb6fdedf | ||
![]() |
3b4472ecf7 | ||
![]() |
faed8b620c | ||
![]() |
982b778e45 | ||
![]() |
3a8f1cb7c5 | ||
![]() |
3c2d7ecdd6 | ||
![]() |
0834f1d6ce | ||
![]() |
6ce446b768 | ||
![]() |
e045edb567 | ||
![]() |
6cd14660cf | ||
![]() |
f5ac58c9f4 | ||
![]() |
c1779ca4a5 | ||
![]() |
6d8309f72e | ||
![]() |
cf95db46a7 | ||
![]() |
b8abfeb7f3 | ||
![]() |
014e24e1a8 | ||
![]() |
e42071a47c | ||
![]() |
1543f523b7 | ||
![]() |
f2d0e965fc | ||
![]() |
f782278d20 | ||
![]() |
3b17d08eb2 | ||
![]() |
18d367afd2 | ||
![]() |
9a4faf9ab9 | ||
![]() |
cb0ba020d4 | ||
![]() |
f705e2f9f7 | ||
![]() |
e76bffa183 | ||
![]() |
a4e19dc567 | ||
![]() |
4e1282617a | ||
![]() |
f102ff16a2 | ||
![]() |
50935a9d41 | ||
![]() |
a1dde664d1 | ||
![]() |
ba5325fba1 | ||
![]() |
e225a10ea8 | ||
![]() |
c4fba75a12 | ||
![]() |
5b052e6f8c | ||
![]() |
d89c3489f8 | ||
![]() |
a447863e4f | ||
![]() |
34db21cea8 | ||
![]() |
943226edc1 | ||
![]() |
281494676a | ||
![]() |
413b55deb7 | ||
![]() |
8222513f63 | ||
![]() |
2dd20ce8e7 | ||
![]() |
d308df6d62 | ||
![]() |
f51b88e6b5 | ||
![]() |
7cb0fa5c56 | ||
![]() |
976c92a2fb | ||
![]() |
15db51d7ff | ||
![]() |
4aa4e6a18e | ||
![]() |
0759f22a91 | ||
![]() |
02036ee643 | ||
![]() |
9109e05f3f | ||
![]() |
2103451d00 | ||
![]() |
b6db091d60 | ||
![]() |
9827653c38 | ||
![]() |
877399b2b2 | ||
![]() |
3f059376ac | ||
![]() |
30a6d01cc5 | ||
![]() |
b6fb47aa70 | ||
![]() |
7ecae856e5 | ||
![]() |
5db7694f22 | ||
![]() |
366294e1c5 | ||
![]() |
4d966ff546 | ||
![]() |
6b665066f0 | ||
![]() |
519011f271 | ||
![]() |
5c224a3221 | ||
![]() |
4b8c38e7ba | ||
![]() |
16f6c1058c | ||
![]() |
7939309520 | ||
![]() |
cec6073085 | ||
![]() |
a9f121f3f7 | ||
![]() |
361218ce15 | ||
![]() |
04dcfada00 | ||
![]() |
d73ad0ef18 | ||
![]() |
a1b888f622 | ||
![]() |
d6267afcb9 | ||
![]() |
b8325be9cf | ||
![]() |
e77ef86f09 | ||
![]() |
951ba597ed | ||
![]() |
ab5e178dab | ||
![]() |
04dace6c75 | ||
![]() |
013918cd83 | ||
![]() |
996466e855 | ||
![]() |
61e7878ac0 | ||
![]() |
c067cb4e7d | ||
![]() |
38697dd812 | ||
![]() |
f03572335a | ||
![]() |
d8837edfa2 | ||
![]() |
e5f8043037 | ||
![]() |
134b57f6f5 | ||
![]() |
072e760197 | ||
![]() |
d37a3e2a71 | ||
![]() |
ed8e7e85f0 | ||
![]() |
eb9faad124 | ||
![]() |
3ed80843fe | ||
![]() |
4029521a63 | ||
![]() |
f971a59746 | ||
![]() |
5836266bfb | ||
![]() |
ed893bde04 | ||
![]() |
a934a36a18 | ||
![]() |
59857acd08 | ||
![]() |
8129b637f3 | ||
![]() |
9e1675671d | ||
![]() |
d39d951f89 | ||
![]() |
10ed6f49a9 | ||
![]() |
c2c848a752 | ||
![]() |
8b191c3ca6 | ||
![]() |
06a412cd68 | ||
![]() |
b74609d5f3 | ||
![]() |
d8756582f9 | ||
![]() |
ff90984dc3 | ||
![]() |
81952f9f96 | ||
![]() |
d0122ff624 | ||
![]() |
7a36aa37aa | ||
![]() |
464cb0ab6e | ||
![]() |
ac21e3ef3f | ||
![]() |
a5b51669fb | ||
![]() |
0ac030549b | ||
![]() |
6f1afe7084 | ||
![]() |
6302589829 | ||
![]() |
3225d31679 | ||
![]() |
ae05ab280d | ||
![]() |
51a6cb2cf5 | ||
![]() |
daf468e141 | ||
![]() |
cd673c8254 | ||
![]() |
3f13c0b36d | ||
![]() |
3e34720851 | ||
![]() |
0799237d74 | ||
![]() |
53f64e40c4 | ||
![]() |
a530df20b2 | ||
![]() |
b958189c92 | ||
![]() |
341f910835 | ||
![]() |
84dff407d4 | ||
![]() |
21e6c5814c | ||
![]() |
776f0a685c | ||
![]() |
9f32fafe21 | ||
![]() |
74b3b8e9e3 | ||
![]() |
fa4a9ba74e | ||
![]() |
9a6f8a2512 | ||
![]() |
1173bc2dde | ||
![]() |
ada55bd887 | ||
![]() |
fe97cff7d1 | ||
![]() |
8cdeb1a35a | ||
![]() |
7c82171a85 | ||
![]() |
2d2085c80b | ||
![]() |
03a4eea0ef | ||
![]() |
fec3e2cd45 | ||
![]() |
2aec1c2ef6 | ||
![]() |
b32cd4f84b | ||
![]() |
550bdc658a | ||
![]() |
d75ba9c2d2 | ||
![]() |
2477f7f982 | ||
![]() |
e454d7d4be | ||
![]() |
cd8bffb2dd | ||
![]() |
9646e3cc1b | ||
![]() |
1a2362ebf1 | ||
![]() |
f6864924f7 | ||
![]() |
6b3dafa4d3 | ||
![]() |
5c0c5d2816 | ||
![]() |
de11dd3d60 | ||
![]() |
ac09af2600 | ||
![]() |
26d1afa29c | ||
![]() |
6aab3b9da8 | ||
![]() |
d959719a3d | ||
![]() |
5a7b17fec5 | ||
![]() |
1d6bb62870 | ||
![]() |
0c3603d893 | ||
![]() |
38a5bca892 | ||
![]() |
70a289076a | ||
![]() |
1d0ecf982f | ||
![]() |
18d93d11e1 | ||
![]() |
110a832f5c | ||
![]() |
6a9e970880 | ||
![]() |
4e3058ce82 | ||
![]() |
bc6307a872 | ||
![]() |
65864190cc | ||
![]() |
292e431748 | ||
![]() |
f0cb78e082 | ||
![]() |
55484ef023 | ||
![]() |
020664bd10 | ||
![]() |
b836ad4d4f | ||
![]() |
a88105784f | ||
![]() |
f868408a3a | ||
![]() |
cbdc93b17f | ||
![]() |
8a7beca122 | ||
![]() |
ee5f5c9172 | ||
![]() |
6e4193b743 | ||
![]() |
60c65f9fa4 | ||
![]() |
b8c2bc143e | ||
![]() |
7ab1412e20 | ||
![]() |
725af6ad16 | ||
![]() |
ef23ebfb5a | ||
![]() |
c682599448 | ||
![]() |
ea513fd47c | ||
![]() |
87b1c9736f | ||
![]() |
a44107540d | ||
![]() |
9a802797d2 | ||
![]() |
54c7aa9c90 | ||
![]() |
35e8cf8ee6 | ||
![]() |
281f0fae1c | ||
![]() |
d09bf56818 | ||
![]() |
edaf447678 | ||
![]() |
7b9036bea6 | ||
![]() |
f7cadcba84 | ||
![]() |
b3336c5a73 | ||
![]() |
2b784b5bf6 | ||
![]() |
eb89d0c8c3 | ||
![]() |
1ea99bc904 | ||
![]() |
56e2955b6a | ||
![]() |
cc984c9735 | ||
![]() |
ba88b6aa06 | ||
![]() |
66ecdc69ac | ||
![]() |
fab52b578f | ||
![]() |
9464aaa8af | ||
![]() |
cf819ca818 | ||
![]() |
e012573766 | ||
![]() |
34c3734953 | ||
![]() |
049a7a04de | ||
![]() |
f0f593f04b | ||
![]() |
bb748ef2d9 | ||
![]() |
38a73a1783 | ||
![]() |
85a302550d | ||
![]() |
29df99ee38 | ||
![]() |
2f77558bad | ||
![]() |
44f1ec35c4 | ||
![]() |
1c2189c7c9 | ||
![]() |
ffdca343fb | ||
![]() |
ac5fca4ae5 | ||
![]() |
fc365e945a | ||
![]() |
ad840e8796 | ||
![]() |
bb8dcf08e7 | ||
![]() |
6980325310 | ||
![]() |
e6a24fcbb5 | ||
![]() |
db4e6c1931 | ||
![]() |
0a592b78c1 | ||
![]() |
58388e8db4 | ||
![]() |
db817a37f4 | ||
![]() |
a7bc6c5e08 | ||
![]() |
60b7faa987 | ||
![]() |
2990d142c4 | ||
![]() |
a0086a5cc4 | ||
![]() |
35544df838 | ||
![]() |
deadfe0c98 | ||
![]() |
0815637cf0 | ||
![]() |
ea77472d75 | ||
![]() |
ad11c6988c | ||
![]() |
8bfde6755e | ||
![]() |
52af81ea17 | ||
![]() |
1a0a94b501 | ||
![]() |
52e64f816c | ||
![]() |
7224b40407 | ||
![]() |
945da099ae | ||
![]() |
70f657e520 | ||
![]() |
e50db698e2 | ||
![]() |
1ddba3ad55 | ||
![]() |
fdf72d1e45 | ||
![]() |
a811e0ef0f | ||
![]() |
bc85c55350 | ||
![]() |
75bbcbf87b | ||
![]() |
5c214e5e9c | ||
![]() |
03e00cd347 | ||
![]() |
fcd41c1d2c | ||
![]() |
b5297de56f | ||
![]() |
911e53dece | ||
![]() |
3b8cb62283 | ||
![]() |
9a607e886e | ||
![]() |
9d06145d6c | ||
![]() |
fa380a4004 | ||
![]() |
2a1b617fb2 | ||
![]() |
69e03094bd | ||
![]() |
c70f54e28b | ||
![]() |
2e346d7166 | ||
![]() |
5d776c070a | ||
![]() |
3293eb1a16 | ||
![]() |
7855842306 | ||
![]() |
71d1de5d96 | ||
![]() |
28f0867948 | ||
![]() |
8d3db06ff2 | ||
![]() |
c153f83df0 | ||
![]() |
52ee0c1058 | ||
![]() |
9267930fea | ||
![]() |
f24f9d3bed | ||
![]() |
2e89c53ebc | ||
![]() |
06602f4e80 | ||
![]() |
a792434a37 | ||
![]() |
baf69edfc7 | ||
![]() |
fdf8e5a704 | ||
![]() |
9784414ddd | ||
![]() |
b48de48efb | ||
![]() |
6e0264d38e | ||
![]() |
1a38960eee | ||
![]() |
8f4c5e15f1 | ||
![]() |
1a853973ab | ||
![]() |
a40b2de946 | ||
![]() |
523e6530a8 | ||
![]() |
9e4c657ed8 | ||
![]() |
7500a758b8 | ||
![]() |
a7f01cd73c | ||
![]() |
1fd626939f | ||
![]() |
31f9cb4806 | ||
![]() |
057c3602e9 | ||
![]() |
5c79f4cae1 | ||
![]() |
70d23b2349 | ||
![]() |
6aef6ae9a8 | ||
![]() |
3b4cfc11f0 | ||
![]() |
fadb261b66 | ||
![]() |
6ef687c864 | ||
![]() |
de12cb92dc | ||
![]() |
a513168902 | ||
![]() |
045a4492f1 | ||
![]() |
da2460f9e7 | ||
![]() |
7ea0ffb748 | ||
![]() |
06eb10c518 | ||
![]() |
dea99e54fd | ||
![]() |
1754943596 | ||
![]() |
e3d9f1172c | ||
![]() |
831fc70923 | ||
![]() |
c6a3b5b6ef | ||
![]() |
84a236c92e | ||
![]() |
4a9b579195 | ||
![]() |
ba45256940 | ||
![]() |
fd4e6d2949 | ||
![]() |
6f3b14a6df | ||
![]() |
5b98c4a524 | ||
![]() |
8a648dfd9b | ||
![]() |
c16b7bcb7a | ||
![]() |
ed0a03e9b5 | ||
![]() |
5dce8c748f | ||
![]() |
cedf53bbc2 | ||
![]() |
3de975884a | ||
![]() |
b9d018f2a2 | ||
![]() |
041894a523 | ||
![]() |
3be67ced64 | ||
![]() |
1354affd28 | ||
![]() |
d2b7a84651 | ||
![]() |
ca29304ce1 | ||
![]() |
f67c644649 | ||
![]() |
1b35ca9c32 | ||
![]() |
706de78a9e | ||
![]() |
715c18739b | ||
![]() |
ce69e98989 | ||
![]() |
55fd205ba4 | ||
![]() |
e6029401d9 | ||
![]() |
b03332b68d | ||
![]() |
5dd2492645 | ||
![]() |
78f816d74e | ||
![]() |
99cf16287a | ||
![]() |
6c37971521 | ||
![]() |
9b18e8438f | ||
![]() |
0bce19cf15 | ||
![]() |
3cfa476d3f | ||
![]() |
5ccee77190 | ||
![]() |
cf41ccc6ce | ||
![]() |
9308404e9a | ||
![]() |
5e31bbf05e | ||
![]() |
84b0c13c44 | ||
![]() |
3bc53b9ade | ||
![]() |
c032586262 | ||
![]() |
b63d3afc18 | ||
![]() |
0bc1f87120 | ||
![]() |
da464e9e5f | ||
![]() |
bf01cc8ce7 | ||
![]() |
ecd089bb69 | ||
![]() |
4fd0b2a85c | ||
![]() |
f6126e9ea1 | ||
![]() |
d35bef64e9 | ||
![]() |
9bd6d36471 | ||
![]() |
78721d720c | ||
![]() |
7aba6c4c73 | ||
![]() |
e29ebb9f18 | ||
![]() |
ca9a044b3e | ||
![]() |
69d28027ad | ||
![]() |
a0b6c0fd8f | ||
![]() |
864bb65ce9 | ||
![]() |
006605c3bf | ||
![]() |
dc035c5ca6 | ||
![]() |
5d1bbd9b27 | ||
![]() |
7c12c63f63 | ||
![]() |
2ced6b09fc | ||
![]() |
7af17f874c | ||
![]() |
982094c85c |
97
.github/workflows/create-test-plan.py
vendored
97
.github/workflows/create-test-plan.py
vendored
@@ -20,7 +20,6 @@ class AppleArch(Enum):
|
||||
class MsvcArch(Enum):
|
||||
X86 = "x86"
|
||||
X64 = "x64"
|
||||
Arm32 = "arm"
|
||||
Arm64 = "arm64"
|
||||
|
||||
|
||||
@@ -28,7 +27,6 @@ class JobOs(Enum):
|
||||
WindowsLatest = "windows-latest"
|
||||
UbuntuLatest = "ubuntu-latest"
|
||||
MacosLatest = "macos-latest"
|
||||
Ubuntu20_04 = "ubuntu-20.04"
|
||||
Ubuntu22_04 = "ubuntu-22.04"
|
||||
Ubuntu24_04 = "ubuntu-24.04"
|
||||
Ubuntu24_04_arm = "ubuntu-24.04-arm"
|
||||
@@ -55,12 +53,12 @@ class SdlPlatform(Enum):
|
||||
Riscos = "riscos"
|
||||
FreeBSD = "freebsd"
|
||||
NetBSD = "netbsd"
|
||||
OpenBSD = "openbsd"
|
||||
|
||||
|
||||
class Msys2Platform(Enum):
|
||||
Mingw32 = "mingw32"
|
||||
Mingw64 = "mingw64"
|
||||
Clang32 = "clang32"
|
||||
Clang64 = "clang64"
|
||||
Ucrt64 = "ucrt64"
|
||||
|
||||
@@ -104,22 +102,19 @@ class JobSpec:
|
||||
JOB_SPECS = {
|
||||
"msys2-mingw32": JobSpec(name="Windows (msys2, mingw32)", os=JobOs.WindowsLatest, platform=SdlPlatform.Msys2, artifact="SDL-mingw32", msys2_platform=Msys2Platform.Mingw32, ),
|
||||
"msys2-mingw64": JobSpec(name="Windows (msys2, mingw64)", os=JobOs.WindowsLatest, platform=SdlPlatform.Msys2, artifact="SDL-mingw64", msys2_platform=Msys2Platform.Mingw64, ),
|
||||
"msys2-clang32": JobSpec(name="Windows (msys2, clang32)", os=JobOs.WindowsLatest, platform=SdlPlatform.Msys2, artifact="SDL-mingw32-clang", msys2_platform=Msys2Platform.Clang32, ),
|
||||
"msys2-clang64": JobSpec(name="Windows (msys2, clang64)", os=JobOs.WindowsLatest, platform=SdlPlatform.Msys2, artifact="SDL-mingw64-clang", msys2_platform=Msys2Platform.Clang64, ),
|
||||
"msys2-ucrt64": JobSpec(name="Windows (msys2, ucrt64)", os=JobOs.WindowsLatest, platform=SdlPlatform.Msys2, artifact="SDL-mingw64-ucrt", msys2_platform=Msys2Platform.Ucrt64, ),
|
||||
"msvc-x64": JobSpec(name="Windows (MSVC, x64)", os=JobOs.WindowsLatest, platform=SdlPlatform.Msvc, artifact="SDL-VC-x64", msvc_arch=MsvcArch.X64, msvc_project="VisualC/SDL.sln", ),
|
||||
"msvc-x86": JobSpec(name="Windows (MSVC, x86)", os=JobOs.WindowsLatest, platform=SdlPlatform.Msvc, artifact="SDL-VC-x86", msvc_arch=MsvcArch.X86, msvc_project="VisualC/SDL.sln", ),
|
||||
"msvc-clang-x64": JobSpec(name="Windows (MSVC, clang-cl x64)", os=JobOs.WindowsLatest, platform=SdlPlatform.Msvc, artifact="SDL-clang-cl-x64", msvc_arch=MsvcArch.X64, clang_cl=True, ),
|
||||
"msvc-clang-x86": JobSpec(name="Windows (MSVC, clang-cl x86)", os=JobOs.WindowsLatest, platform=SdlPlatform.Msvc, artifact="SDL-clang-cl-x86", msvc_arch=MsvcArch.X86, clang_cl=True, ),
|
||||
"msvc-arm32": JobSpec(name="Windows (MSVC, ARM)", os=JobOs.WindowsLatest, platform=SdlPlatform.Msvc, artifact="SDL-VC-arm32", msvc_arch=MsvcArch.Arm32, ),
|
||||
"msvc-arm64": JobSpec(name="Windows (MSVC, ARM64)", os=JobOs.WindowsLatest, platform=SdlPlatform.Msvc, artifact="SDL-VC-arm64", msvc_arch=MsvcArch.Arm64, ),
|
||||
"msvc-gdk-x64": JobSpec(name="GDK (MSVC, x64)", os=JobOs.WindowsLatest, platform=SdlPlatform.Msvc, artifact="SDL-VC-GDK", msvc_arch=MsvcArch.X64, msvc_project="VisualC-GDK/SDL.sln", gdk=True, no_cmake=True, ),
|
||||
"ubuntu-20.04": JobSpec(name="Ubuntu 20.04", os=JobOs.Ubuntu20_04, platform=SdlPlatform.Linux, artifact="SDL-ubuntu20.04", ),
|
||||
"ubuntu-22.04": JobSpec(name="Ubuntu 22.04", os=JobOs.Ubuntu22_04, platform=SdlPlatform.Linux, artifact="SDL-ubuntu22.04", ),
|
||||
"ubuntu-24.04-arm64": JobSpec(name="Ubuntu 24.04 (ARM64)", os=JobOs.Ubuntu24_04_arm, platform=SdlPlatform.Linux, artifact="SDL-ubuntu24.04-arm64", ),
|
||||
"steamrt-sniper": JobSpec(name="Steam Linux Runtime (Sniper)", os=JobOs.UbuntuLatest, platform=SdlPlatform.Linux, artifact="SDL-slrsniper", container="registry.gitlab.steamos.cloud/steamrt/sniper/sdk:beta", ),
|
||||
"ubuntu-intel-icx": JobSpec(name="Ubuntu 20.04 (Intel oneAPI)", os=JobOs.Ubuntu20_04, platform=SdlPlatform.Linux, artifact="SDL-ubuntu20.04-oneapi", intel=IntelCompiler.Icx, ),
|
||||
"ubuntu-intel-icc": JobSpec(name="Ubuntu 20.04 (Intel Compiler)", os=JobOs.Ubuntu20_04, platform=SdlPlatform.Linux, artifact="SDL-ubuntu20.04-icc", intel=IntelCompiler.Icc, ),
|
||||
"ubuntu-intel-icx": JobSpec(name="Ubuntu 22.04 (Intel oneAPI)", os=JobOs.Ubuntu22_04, platform=SdlPlatform.Linux, artifact="SDL-ubuntu22.04-oneapi", intel=IntelCompiler.Icx, ),
|
||||
"ubuntu-intel-icc": JobSpec(name="Ubuntu 22.04 (Intel Compiler)", os=JobOs.Ubuntu22_04, platform=SdlPlatform.Linux, artifact="SDL-ubuntu22.04-icc", intel=IntelCompiler.Icc, ),
|
||||
"macos-framework-x64": JobSpec(name="MacOS (Framework) (x64)", os=JobOs.Macos13, platform=SdlPlatform.MacOS, artifact="SDL-macos-framework", apple_framework=True, apple_archs={AppleArch.Aarch64, AppleArch.X86_64, }, xcode=True, ),
|
||||
"macos-framework-arm64": JobSpec(name="MacOS (Framework) (arm64)", os=JobOs.MacosLatest, platform=SdlPlatform.MacOS, artifact=None, apple_framework=True, apple_archs={AppleArch.Aarch64, AppleArch.X86_64, }, ),
|
||||
"macos-gnu-arm64": JobSpec(name="MacOS (GNU prefix)", os=JobOs.MacosLatest, platform=SdlPlatform.MacOS, artifact="SDL-macos-arm64-gnu", apple_framework=False, apple_archs={AppleArch.Aarch64, }, ),
|
||||
@@ -141,6 +136,7 @@ JOB_SPECS = {
|
||||
"vita-pvr": JobSpec(name="Sony PlayStation Vita (GLES w/ PVR_PSP2)", os=JobOs.UbuntuLatest, platform=SdlPlatform.Vita, artifact="SDL-vita-pvr", container="vitasdk/vitasdk:latest", vita_gles=VitaGLES.Pvr, ),
|
||||
"riscos": JobSpec(name="RISC OS", os=JobOs.UbuntuLatest, platform=SdlPlatform.Riscos, artifact="SDL-riscos", container="riscosdotinfo/riscos-gccsdk-4.7:latest", ),
|
||||
"netbsd": JobSpec(name="NetBSD", os=JobOs.UbuntuLatest, platform=SdlPlatform.NetBSD, artifact="SDL-netbsd-x64", ),
|
||||
"openbsd": JobSpec(name="OpenBSD", os=JobOs.UbuntuLatest, platform=SdlPlatform.OpenBSD, artifact="SDL-openbsd-x64", ),
|
||||
"freebsd": JobSpec(name="FreeBSD", os=JobOs.UbuntuLatest, platform=SdlPlatform.FreeBSD, artifact="SDL-freebsd-x64", ),
|
||||
}
|
||||
|
||||
@@ -166,6 +162,7 @@ class JobDetails:
|
||||
platform: str
|
||||
artifact: str
|
||||
no_cmake: bool
|
||||
ccache: bool = False
|
||||
build_tests: bool = True
|
||||
container: str = ""
|
||||
cmake_build_type: str = "RelWithDebInfo"
|
||||
@@ -177,6 +174,7 @@ class JobDetails:
|
||||
brew_packages: list[str] = dataclasses.field(default_factory=list)
|
||||
cmake_toolchain_file: str = ""
|
||||
cmake_arguments: list[str] = dataclasses.field(default_factory=list)
|
||||
cmake_generator: str = "Ninja"
|
||||
cmake_build_arguments: list[str] = dataclasses.field(default_factory=list)
|
||||
clang_tidy: bool = True
|
||||
cppflags: list[str] = dataclasses.field(default_factory=list)
|
||||
@@ -225,12 +223,14 @@ class JobDetails:
|
||||
check_sources: bool = False
|
||||
setup_python: bool = False
|
||||
pypi_packages: list[str] = dataclasses.field(default_factory=list)
|
||||
binutils_strings: str = "strings"
|
||||
|
||||
def to_workflow(self, enable_artifacts: bool) -> dict[str, str|bool]:
|
||||
data = {
|
||||
"name": self.name,
|
||||
"key": self.key,
|
||||
"os": self.os,
|
||||
"ccache": self.ccache,
|
||||
"container": self.container if self.container else "",
|
||||
"platform": self.platform,
|
||||
"artifact": self.artifact,
|
||||
@@ -257,6 +257,7 @@ class JobDetails:
|
||||
"cflags": my_shlex_join(self.cppflags + self.cflags),
|
||||
"cxxflags": my_shlex_join(self.cppflags + self.cxxflags),
|
||||
"ldflags": my_shlex_join(self.ldflags),
|
||||
"cmake-generator": self.cmake_generator,
|
||||
"cmake-toolchain-file": self.cmake_toolchain_file,
|
||||
"clang-tidy": self.clang_tidy,
|
||||
"cmake-arguments": my_shlex_join(self.cmake_arguments),
|
||||
@@ -291,6 +292,7 @@ class JobDetails:
|
||||
"check-sources": self.check_sources,
|
||||
"setup-python": self.setup_python,
|
||||
"pypi-packages": my_shlex_join(self.pypi_packages),
|
||||
"binutils-strings": self.binutils_strings,
|
||||
}
|
||||
return {k: v for k, v in data.items() if v != ""}
|
||||
|
||||
@@ -343,7 +345,10 @@ def spec_to_job(spec: JobSpec, key: str, trackmem_symbol_names: bool) -> JobDeta
|
||||
case IntelCompiler.Icc:
|
||||
job.cc = "icc"
|
||||
job.cxx = "icpc"
|
||||
# Disable deprecation warning
|
||||
job.cppflags.append("-diag-disable=10441")
|
||||
# Avoid 'Catastrophic error: cannot open precompiled header file'
|
||||
job.cmake_arguments.append("-DCMAKE_DISABLE_PRECOMPILE_HEADERS:BOOL=ON")
|
||||
job.clang_tidy = False
|
||||
case _:
|
||||
raise ValueError(f"Invalid intel={spec.intel}")
|
||||
@@ -402,10 +407,6 @@ def spec_to_job(spec: JobSpec, key: str, trackmem_symbol_names: bool) -> JobDeta
|
||||
job.msvc_vcvars_arch = "x64_x86"
|
||||
case MsvcArch.X64:
|
||||
job.msvc_vcvars_arch = "x64"
|
||||
case MsvcArch.Arm32:
|
||||
job.msvc_vcvars_arch = "x64_arm"
|
||||
job.msvc_vcvars_sdk = "10.0.22621.0" # 10.0.26100.0 dropped ARM32 um and ucrt libraries
|
||||
job.run_tests = False
|
||||
case MsvcArch.Arm64:
|
||||
job.msvc_vcvars_arch = "x64_arm64"
|
||||
job.run_tests = False
|
||||
@@ -421,6 +422,7 @@ def spec_to_job(spec: JobSpec, key: str, trackmem_symbol_names: bool) -> JobDeta
|
||||
if spec.name.startswith("Ubuntu"):
|
||||
assert spec.os.value.startswith("ubuntu-")
|
||||
job.apt_packages.extend((
|
||||
"ccache",
|
||||
"gnome-desktop-testing",
|
||||
"libasound2-dev",
|
||||
"libpulse-dev",
|
||||
@@ -454,6 +456,7 @@ def spec_to_job(spec: JobSpec, key: str, trackmem_symbol_names: bool) -> JobDeta
|
||||
job.apt_packages.extend((
|
||||
"libunwind-dev", # For SDL_test memory tracking
|
||||
))
|
||||
job.ccache = True
|
||||
if trackmem_symbol_names:
|
||||
# older libunwind is slow
|
||||
job.cmake_arguments.append("-DSDLTEST_TIMEOUT_MULTIPLIER=2")
|
||||
@@ -462,8 +465,10 @@ def spec_to_job(spec: JobSpec, key: str, trackmem_symbol_names: bool) -> JobDeta
|
||||
fpic = True
|
||||
case SdlPlatform.Ios | SdlPlatform.Tvos:
|
||||
job.brew_packages.extend([
|
||||
"ccache",
|
||||
"ninja",
|
||||
])
|
||||
job.ccache = True
|
||||
job.clang_tidy = False
|
||||
job.run_tests = False
|
||||
job.test_pkg_config = False
|
||||
@@ -506,8 +511,15 @@ def spec_to_job(spec: JobSpec, key: str, trackmem_symbol_names: bool) -> JobDeta
|
||||
))
|
||||
job.shared_lib = SharedLibType.DYLIB
|
||||
job.static_lib = StaticLibType.A
|
||||
job.ccache = True
|
||||
if spec.os == JobOs.Macos13:
|
||||
job.ccache = False
|
||||
job.apt_packages = []
|
||||
job.brew_packages.append("ninja")
|
||||
job.brew_packages.extend((
|
||||
"ninja",
|
||||
))
|
||||
if job.ccache:
|
||||
job.brew_packages.append("ccache")
|
||||
if job.clang_tidy:
|
||||
job.brew_packages.append("llvm")
|
||||
if spec.xcode:
|
||||
@@ -515,6 +527,7 @@ def spec_to_job(spec: JobSpec, key: str, trackmem_symbol_names: bool) -> JobDeta
|
||||
case SdlPlatform.Android:
|
||||
job.android_gradle = spec.android_gradle
|
||||
job.android_mk = spec.android_mk
|
||||
job.apt_packages.append("ccache")
|
||||
job.run_tests = False
|
||||
job.shared_lib = SharedLibType.SO
|
||||
job.static_lib = StaticLibType.A
|
||||
@@ -525,6 +538,7 @@ def spec_to_job(spec: JobSpec, key: str, trackmem_symbol_names: bool) -> JobDeta
|
||||
if spec.android_mk or spec.android_gradle:
|
||||
job.apt_packages = []
|
||||
if not spec.no_cmake:
|
||||
job.ccache = True
|
||||
job.cmake_arguments.extend((
|
||||
f"-DANDROID_PLATFORM={spec.android_platform}",
|
||||
f"-DANDROID_ABI={spec.android_abi}",
|
||||
@@ -539,9 +553,15 @@ def spec_to_job(spec: JobSpec, key: str, trackmem_symbol_names: bool) -> JobDeta
|
||||
"testmultiaudio-apk",
|
||||
"testsprite-apk",
|
||||
]
|
||||
|
||||
# -fPIC is required after updating NDK from 21 to 28
|
||||
job.cflags.append("-fPIC")
|
||||
job.cxxflags.append("-fPIC")
|
||||
case SdlPlatform.Emscripten:
|
||||
job.clang_tidy = False # clang-tidy does not understand -gsource-map
|
||||
job.shared = False
|
||||
job.ccache = True
|
||||
job.apt_packages.append("ccache")
|
||||
job.cmake_config_emulator = "emcmake"
|
||||
job.cmake_build_type = "Debug"
|
||||
job.test_pkg_config = False
|
||||
@@ -567,11 +587,12 @@ def spec_to_job(spec: JobSpec, key: str, trackmem_symbol_names: bool) -> JobDeta
|
||||
job.setup_python = True
|
||||
job.pypi_packages.append("selenium")
|
||||
case SdlPlatform.Ps2:
|
||||
job.ccache = False # actions/ccache does not work in psp container (incompatible tar of busybox)
|
||||
build_parallel = False
|
||||
job.shared = False
|
||||
job.sudo = ""
|
||||
job.apt_packages = []
|
||||
job.apk_packages = ["cmake", "gmp", "mpc1", "mpfr4", "ninja", "pkgconf", "git", ]
|
||||
job.apk_packages = ["ccache", "cmake", "gmp", "mpc1", "mpfr4", "ninja", "pkgconf", "git", ]
|
||||
job.cmake_toolchain_file = "${PS2DEV}/ps2sdk/ps2dev.cmake"
|
||||
job.clang_tidy = False
|
||||
job.run_tests = False
|
||||
@@ -580,10 +601,11 @@ def spec_to_job(spec: JobSpec, key: str, trackmem_symbol_names: bool) -> JobDeta
|
||||
job.ldflags = ["-L${PS2DEV}/ps2sdk/ee/lib", "-L${PS2DEV}/gsKit/lib", "-L${PS2DEV}/ps2sdk/ports/lib", ]
|
||||
job.static_lib = StaticLibType.A
|
||||
case SdlPlatform.Psp:
|
||||
job.ccache = False # actions/ccache does not work in psp container (incompatible tar of busybox)
|
||||
build_parallel = False
|
||||
job.sudo = ""
|
||||
job.apt_packages = []
|
||||
job.apk_packages = ["cmake", "gmp", "mpc1", "mpfr4", "ninja", "pkgconf", ]
|
||||
job.apk_packages = ["ccache", "cmake", "gmp", "mpc1", "mpfr4", "ninja", "pkgconf", ]
|
||||
job.cmake_toolchain_file = "${PSPDEV}/psp/share/pspdev.cmake"
|
||||
job.clang_tidy = False
|
||||
job.run_tests = False
|
||||
@@ -593,9 +615,10 @@ def spec_to_job(spec: JobSpec, key: str, trackmem_symbol_names: bool) -> JobDeta
|
||||
job.pollute_directories = ["${PSPDEV}/include", "${PSPDEV}/psp/include", "${PSPDEV}/psp/sdk/include", ]
|
||||
job.static_lib = StaticLibType.A
|
||||
case SdlPlatform.Vita:
|
||||
job.ccache = True
|
||||
job.sudo = ""
|
||||
job.apt_packages = []
|
||||
job.apk_packages = ["cmake", "ninja", "pkgconf", "bash", "tar"]
|
||||
job.apk_packages = ["ccache", "cmake", "ninja", "pkgconf", "bash", "tar"]
|
||||
job.cmake_toolchain_file = "${VITASDK}/share/vita.toolchain.cmake"
|
||||
assert spec.vita_gles is not None
|
||||
job.setup_vita_gles_type = {
|
||||
@@ -616,8 +639,10 @@ def spec_to_job(spec: JobSpec, key: str, trackmem_symbol_names: bool) -> JobDeta
|
||||
job.cc = "arm-vita-eabi-gcc"
|
||||
job.static_lib = StaticLibType.A
|
||||
case SdlPlatform.Haiku:
|
||||
job.ccache = True
|
||||
fpic = False
|
||||
job.run_tests = False
|
||||
job.apt_packages.append("ccache")
|
||||
job.cc = "x86_64-unknown-haiku-gcc"
|
||||
job.cxx = "x86_64-unknown-haiku-g++"
|
||||
job.sudo = ""
|
||||
@@ -629,19 +654,23 @@ def spec_to_job(spec: JobSpec, key: str, trackmem_symbol_names: bool) -> JobDeta
|
||||
job.shared_lib = SharedLibType.SO_0
|
||||
job.static_lib = StaticLibType.A
|
||||
case SdlPlatform.PowerPC64 | SdlPlatform.PowerPC:
|
||||
job.ccache = True
|
||||
# FIXME: Enable SDL_WERROR
|
||||
job.werror = False
|
||||
job.clang_tidy = False
|
||||
job.run_tests = False
|
||||
job.sudo = ""
|
||||
job.apt_packages = []
|
||||
job.apt_packages = ["ccache"]
|
||||
job.shared_lib = SharedLibType.SO_0
|
||||
job.static_lib = StaticLibType.A
|
||||
job.cmake_arguments.extend((
|
||||
"-DSDL_UNIX_CONSOLE_BUILD=ON",
|
||||
))
|
||||
case SdlPlatform.LoongArch64:
|
||||
job.ccache = True
|
||||
fpic = True
|
||||
job.run_tests = False
|
||||
job.apt_packages.append("ccache")
|
||||
job.cc = "${LOONGARCH64_CC}"
|
||||
job.cxx = "${LOONGARCH64_CXX}"
|
||||
job.cmake_arguments.extend((
|
||||
@@ -653,31 +682,36 @@ def spec_to_job(spec: JobSpec, key: str, trackmem_symbol_names: bool) -> JobDeta
|
||||
job.shared_lib = SharedLibType.SO_0
|
||||
job.static_lib = StaticLibType.A
|
||||
case SdlPlatform.N3ds:
|
||||
job.cmake_generator = "Unix Makefiles"
|
||||
job.cmake_build_arguments.append("-j$(nproc)")
|
||||
job.ccache = False
|
||||
job.shared = False
|
||||
job.apt_packages = ["ninja-build", "binutils"]
|
||||
job.apt_packages = []
|
||||
job.clang_tidy = False
|
||||
job.run_tests = False
|
||||
job.cc_from_cmake = True
|
||||
job.cmake_toolchain_file = "${DEVKITPRO}/cmake/3DS.cmake"
|
||||
job.binutils_strings = "/opt/devkitpro/devkitARM/bin/arm-none-eabi-strings"
|
||||
job.static_lib = StaticLibType.A
|
||||
case SdlPlatform.Msys2:
|
||||
job.ccache = True
|
||||
job.shell = "msys2 {0}"
|
||||
assert spec.msys2_platform
|
||||
job.msys2_msystem = spec.msys2_platform.value
|
||||
job.msys2_env = {
|
||||
"mingw32": "mingw-w64-i686",
|
||||
"mingw64": "mingw-w64-x86_64",
|
||||
"clang32": "mingw-w64-clang-i686",
|
||||
"clang64": "mingw-w64-clang-x86_64",
|
||||
"ucrt64": "mingw-w64-ucrt-x86_64",
|
||||
}[spec.msys2_platform.value]
|
||||
job.msys2_no_perl = spec.msys2_platform in (Msys2Platform.Mingw32, Msys2Platform.Clang32)
|
||||
job.msys2_no_perl = spec.msys2_platform in (Msys2Platform.Mingw32, )
|
||||
job.shared_lib = SharedLibType.WIN32
|
||||
job.static_lib = StaticLibType.A
|
||||
case SdlPlatform.Riscos:
|
||||
job.ccache = False # FIXME: enable when container gets upgrade
|
||||
# FIXME: Enable SDL_WERROR
|
||||
job.werror = False
|
||||
job.apt_packages = ["cmake", "ninja-build"]
|
||||
job.apt_packages = ["ccache", "cmake", "ninja-build"]
|
||||
job.test_pkg_config = False
|
||||
job.shared = False
|
||||
job.run_tests = False
|
||||
@@ -689,7 +723,7 @@ def spec_to_job(spec: JobSpec, key: str, trackmem_symbol_names: bool) -> JobDeta
|
||||
))
|
||||
job.cmake_toolchain_file = "/home/riscos/env/toolchain-riscos.cmake"
|
||||
job.static_lib = StaticLibType.A
|
||||
case SdlPlatform.FreeBSD | SdlPlatform.NetBSD:
|
||||
case SdlPlatform.FreeBSD | SdlPlatform.NetBSD | SdlPlatform.OpenBSD:
|
||||
job.cpactions = True
|
||||
job.no_cmake = True
|
||||
job.run_tests = False
|
||||
@@ -713,6 +747,12 @@ def spec_to_job(spec: JobSpec, key: str, trackmem_symbol_names: bool) -> JobDeta
|
||||
job.cpactions_arch = "x86-64"
|
||||
job.cpactions_setup_cmd = "export PATH=\"/usr/pkg/sbin:/usr/pkg/bin:/sbin:$PATH\"; export PKG_CONFIG_PATH=\"/usr/pkg/lib/pkgconfig\";export PKG_PATH=\"https://cdn.netBSD.org/pub/pkgsrc/packages/NetBSD/$(uname -p)/$(uname -r|cut -f \"1 2\" -d.)/All/\";echo \"PKG_PATH=$PKG_PATH\";echo \"uname -a -> \"$(uname -a)\"\";sudo -E sysctl -w security.pax.aslr.enabled=0;sudo -E sysctl -w security.pax.aslr.global=0;sudo -E pkgin clean;sudo -E pkgin update"
|
||||
job.cpactions_install_cmd = "sudo -E pkgin -y install cmake dbus pkgconf ninja-build pulseaudio libxkbcommon wayland wayland-protocols libinotify libusb1"
|
||||
case SdlPlatform.OpenBSD:
|
||||
job.cpactions_os = "openbsd"
|
||||
job.cpactions_version = "7.4"
|
||||
job.cpactions_arch = "x86-64"
|
||||
job.cpactions_setup_cmd = "sudo pkg_add -u"
|
||||
job.cpactions_install_cmd = "sudo pkg_add cmake ninja pkgconf wayland wayland-protocols xwayland libxkbcommon libinotify pulseaudio dbus ibus"
|
||||
case _:
|
||||
raise ValueError(f"Unsupported platform={spec.platform}")
|
||||
|
||||
@@ -720,12 +760,17 @@ def spec_to_job(spec: JobSpec, key: str, trackmem_symbol_names: bool) -> JobDeta
|
||||
job.check_sources = True
|
||||
job.setup_python = True
|
||||
|
||||
if job.ccache:
|
||||
job.cmake_arguments.extend((
|
||||
"-DCMAKE_C_COMPILER_LAUNCHER=ccache",
|
||||
"-DCMAKE_CXX_COMPILER_LAUNCHER=ccache",
|
||||
))
|
||||
if not build_parallel:
|
||||
job.cmake_build_arguments.append("-j1")
|
||||
if job.cflags:
|
||||
job.cmake_arguments.append(f"-DCMAKE_C_FLAGS=\"{my_shlex_join(job.cflags)}\"")
|
||||
if job.cxxflags:
|
||||
job.cmake_arguments.append(f"-DCMAKE_CXX_FLAGS=\"{my_shlex_join(job.cxxflags)}\"")
|
||||
if job.cflags or job.cppflags:
|
||||
job.cmake_arguments.append(f"-DCMAKE_C_FLAGS=\"{my_shlex_join(job.cflags + job.cppflags)}\"")
|
||||
if job.cxxflags or job.cppflags:
|
||||
job.cmake_arguments.append(f"-DCMAKE_CXX_FLAGS=\"{my_shlex_join(job.cxxflags + job.cppflags)}\"")
|
||||
if job.ldflags:
|
||||
job.cmake_arguments.append(f"-DCMAKE_SHARED_LINKER_FLAGS=\"{my_shlex_join(job.ldflags)}\"")
|
||||
job.cmake_arguments.append(f"-DCMAKE_EXE_LINKER_FLAGS=\"{my_shlex_join(job.ldflags)}\"")
|
||||
|
60
.github/workflows/generic.yml
vendored
60
.github/workflows/generic.yml
vendored
@@ -34,6 +34,7 @@ jobs:
|
||||
${{ (!matrix.platform.msys2-no-perl && format('{0}-perl', matrix.platform.msys2-env)) || '' }}
|
||||
${{ matrix.platform.msys2-env }}-pkg-config
|
||||
${{ matrix.platform.msys2-env }}-clang-tools-extra
|
||||
${{ (matrix.platform.ccache && format('{0}-ccache', matrix.platform.msys2-env)) || '' }}
|
||||
- name: 'About this job'
|
||||
run: |
|
||||
echo "key=${{ matrix.platform.key }}"
|
||||
@@ -75,7 +76,7 @@ jobs:
|
||||
id: setup-ndk
|
||||
with:
|
||||
local-cache: true
|
||||
ndk-version: r21e
|
||||
ndk-version: r28c
|
||||
- name: 'Configure Android NDK variables'
|
||||
if: ${{ matrix.platform.android-ndk }}
|
||||
shell: sh
|
||||
@@ -165,12 +166,42 @@ jobs:
|
||||
done
|
||||
done
|
||||
|
||||
- name: 'Calculate ccache key'
|
||||
if: ${{ matrix.platform.ccache }}
|
||||
id: prepare-restore-ccache
|
||||
run: |
|
||||
echo "timestamp=$(date -u "+%Y%m%d%H%M_%S")" >> "$GITHUB_OUTPUT"
|
||||
- name: 'Restore ccache'
|
||||
if: ${{ matrix.platform.ccache }}
|
||||
uses: actions/cache/restore@v4
|
||||
id: restore-ccache
|
||||
with:
|
||||
path: ${{ runner.temp }}/ccache
|
||||
key: ccache-${{ matrix.platform.key }}-${{ steps.prepare-restore-ccache.outputs.timestamp }}
|
||||
restore-keys: |
|
||||
ccache-${{matrix.platform.key}}
|
||||
- name: 'Configure ccache'
|
||||
if: ${{ matrix.platform.ccache }}
|
||||
run: |
|
||||
echo 'CCACHE_DIR=${{ runner.temp }}/ccache' >>${GITHUB_ENV}
|
||||
- name: 'Prepare ccache'
|
||||
if: ${{ matrix.platform.ccache && steps.restore-ccache.outputs.cache-hit }}
|
||||
run: |
|
||||
if [ "x${{ runner.os }}" = "xmacOS" ]; then
|
||||
touch_date="2025-02-01T12:00:00Z"
|
||||
else
|
||||
touch_date="2025-02-01"
|
||||
fi
|
||||
find "${CCACHE_DIR}" -type f -exec touch -a -m -d "$touch_date" {} +
|
||||
ccache -s
|
||||
ccache -z
|
||||
|
||||
- name: 'Configure (CMake)'
|
||||
if: ${{ !matrix.platform.no-cmake }}
|
||||
#shell: ${{ matrix.platform.shell }}
|
||||
run: |
|
||||
${{ matrix.platform.source-cmd }}
|
||||
${{ matrix.platform.cmake-config-emulator }} cmake -S . -B build -GNinja \
|
||||
${{ matrix.platform.cmake-config-emulator }} cmake -S . -B build -G "${{ matrix.platform.cmake-generator }}" \
|
||||
-Wdeprecated -Wdev -Werror \
|
||||
${{ matrix.platform.cmake-toolchain-file != '' && format('-DCMAKE_TOOLCHAIN_FILE={0}', matrix.platform.cmake-toolchain-file) || '' }} \
|
||||
-DSDL_WERROR=${{ matrix.platform.werror }} \
|
||||
@@ -201,9 +232,9 @@ jobs:
|
||||
run: |
|
||||
echo "This should show us the SDL_REVISION"
|
||||
echo "Shared library:"
|
||||
${{ (matrix.platform.shared-lib && format('strings build/{0} | grep "Github Workflow"', matrix.platform.shared-lib)) || 'echo "<Shared library not supported by platform>"' }}
|
||||
${{ (matrix.platform.shared-lib && format('{0} build/{1} | grep "Github Workflow"', matrix.platform.binutils-strings, matrix.platform.shared-lib)) || 'echo "<Shared library not supported by platform>"' }}
|
||||
echo "Static library:"
|
||||
${{ (matrix.platform.static-lib && format('strings build/{0} | grep "Github Workflow"', matrix.platform.static-lib)) || 'echo "<Static library not supported by platform>"' }}
|
||||
${{ (matrix.platform.static-lib && format('{0} build/{1} | grep "Github Workflow"', matrix.platform.binutils-strings, matrix.platform.static-lib)) || 'echo "<Static library not supported by platform>"' }}
|
||||
- name: 'Run build-time tests (CMake)'
|
||||
id: tests
|
||||
if: ${{ !matrix.platform.no-cmake && matrix.platform.run-tests }}
|
||||
@@ -357,6 +388,17 @@ jobs:
|
||||
if: ${{ matrix.platform.xcode-sdk != '' }}
|
||||
run: |
|
||||
xcodebuild -project Xcode/SDL/SDL.xcodeproj -target SDL3 -configuration Release -sdk ${{ matrix.platform.xcode-sdk }} clean build
|
||||
- name: 'Prune old ccache files'
|
||||
if: ${{ matrix.platform.ccache }}
|
||||
run: |
|
||||
ccache --evict-older-than=1d
|
||||
ccache -s
|
||||
- name: 'Save ccache'
|
||||
if: ${{ matrix.platform.ccache }}
|
||||
uses: actions/cache/save@v4
|
||||
with:
|
||||
path: ${{ runner.temp }}/ccache
|
||||
key: ${{ steps.restore-ccache.outputs.cache-primary-key }}
|
||||
- name: 'Check Sources'
|
||||
if: ${{ matrix.platform.check-sources }}
|
||||
run: |
|
||||
@@ -364,6 +406,14 @@ jobs:
|
||||
build-scripts/test-versioning.sh
|
||||
python build-scripts/check_android_jni.py
|
||||
python build-scripts/check_stdlib_usage.py
|
||||
- name: 'Verify alignment of Android test apks'
|
||||
if: ${{ matrix.platform.android-ndk && !matrix.platform.no-cmake }}
|
||||
run: |
|
||||
find ./ -iname '*.apk' | xargs -L1 ./build-scripts/check_elf_alignment.sh
|
||||
- name: 'Verify alignment of Android .so files'
|
||||
if: ${{ matrix.platform.android-ndk && !matrix.platform.no-cmake }}
|
||||
run: |
|
||||
find ./ -iname '*.so' | xargs -L1 ./build-scripts/check_elf_alignment.sh
|
||||
- name: 'Upload binary package'
|
||||
uses: actions/upload-artifact@v4
|
||||
if: ${{ always() && matrix.platform.artifact != '' && (steps.package.outcome == 'success' || steps.cpactions.outcome == 'success') && (matrix.platform.enable-artifacts || steps.tests.outcome == 'failure') }}
|
||||
@@ -386,4 +436,4 @@ jobs:
|
||||
with:
|
||||
if-no-files-found: error
|
||||
name: '${{ matrix.platform.artifact }}-apks'
|
||||
path: build/test/*.apk
|
||||
path: build/test/*.apk
|
||||
|
4
.github/workflows/release.yml
vendored
4
.github/workflows/release.yml
vendored
@@ -256,7 +256,7 @@ jobs:
|
||||
|
||||
msvc:
|
||||
needs: [src]
|
||||
runs-on: windows-2019
|
||||
runs-on: windows-2025
|
||||
outputs:
|
||||
VC-x86: ${{ steps.releaser.outputs.VC-x86 }}
|
||||
VC-x64: ${{ steps.releaser.outputs.VC-x64 }}
|
||||
@@ -535,7 +535,7 @@ jobs:
|
||||
uses: nttld/setup-ndk@v1
|
||||
with:
|
||||
local-cache: true
|
||||
ndk-version: r21e
|
||||
ndk-version: r28c
|
||||
- name: 'Setup Java JDK'
|
||||
uses: actions/setup-java@v4
|
||||
with:
|
||||
|
174
CMakeLists.txt
174
CMakeLists.txt
@@ -5,7 +5,7 @@ if(NOT DEFINED CMAKE_BUILD_TYPE)
|
||||
endif()
|
||||
|
||||
# See docs/release_checklist.md
|
||||
project(SDL3 LANGUAGES C VERSION "3.2.4")
|
||||
project(SDL3 LANGUAGES C VERSION "3.2.24")
|
||||
|
||||
if(CMAKE_SOURCE_DIR STREQUAL PROJECT_SOURCE_DIR)
|
||||
set(SDL3_MAINPROJECT ON)
|
||||
@@ -79,6 +79,12 @@ include("${SDL3_SOURCE_DIR}/cmake/PreseedEmscriptenCache.cmake")
|
||||
|
||||
SDL_DetectCompiler()
|
||||
SDL_DetectTargetCPUArchitectures(SDL_CPUS)
|
||||
if(APPLE AND CMAKE_OSX_ARCHITECTURES)
|
||||
list(LENGTH CMAKE_OSX_ARCHITECTURES _num_arches)
|
||||
if(_num_arches GREATER 1)
|
||||
set(APPLE_MULTIARCH TRUE)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Increment this if there is an incompatible change - but if that happens,
|
||||
# we should rename the library from SDL3 to SDL4, at which point this would
|
||||
@@ -183,26 +189,6 @@ if(MSVC)
|
||||
set(SDL_RELOCATABLE_DEFAULT ON)
|
||||
endif()
|
||||
|
||||
if(MSVC)
|
||||
if(NOT SDL_LIBC)
|
||||
# Make sure /RTC1 is disabled, otherwise it will use functions from the CRT
|
||||
foreach(flag_var
|
||||
CMAKE_C_FLAGS CMAKE_C_FLAGS_DEBUG CMAKE_C_FLAGS_RELEASE
|
||||
CMAKE_C_FLAGS_MINSIZEREL CMAKE_C_FLAGS_RELWITHDEBINFO)
|
||||
string(REGEX REPLACE "/RTC(su|[1su])" "" ${flag_var} "${${flag_var}}")
|
||||
endforeach(flag_var)
|
||||
endif()
|
||||
|
||||
if(MSVC_CLANG)
|
||||
# clang-cl treats /W4 as '-Wall -Wextra' -- we don't need -Wextra
|
||||
foreach(flag_var
|
||||
CMAKE_C_FLAGS CMAKE_C_FLAGS_DEBUG CMAKE_C_FLAGS_RELEASE
|
||||
CMAKE_C_FLAGS_MINSIZEREL CMAKE_C_FLAGS_RELWITHDEBINFO)
|
||||
string(REGEX REPLACE "/W4" "/W3" ${flag_var} "${${flag_var}}")
|
||||
endforeach(flag_var)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
set(SDL_SHARED_DEFAULT ON)
|
||||
set(SDL_STATIC_DEFAULT ON)
|
||||
|
||||
@@ -243,6 +229,8 @@ if(SDL_SHARED_DEFAULT AND SDL_STATIC_DEFAULT AND SDL_SHARED_AVAILABLE)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
dep_option(SDL_DEPS_SHARED "Load dependencies dynamically" ON SDL_SHARED_AVAILABLE OFF)
|
||||
|
||||
set(SDL_SUBSYSTEMS )
|
||||
|
||||
macro(define_sdl_subsystem _name)
|
||||
@@ -334,19 +322,19 @@ set_option(SDL_PTHREADS "Use POSIX threads for multi-threading" ${SDL
|
||||
dep_option(SDL_PTHREADS_SEM "Use pthread semaphores" ON "SDL_PTHREADS" OFF)
|
||||
dep_option(SDL_OSS "Support the OSS audio API" ${SDL_OSS_DEFAULT} "UNIX_SYS OR RISCOS;SDL_AUDIO" OFF)
|
||||
dep_option(SDL_ALSA "Support the ALSA audio API" ${UNIX_SYS} "SDL_AUDIO" OFF)
|
||||
dep_option(SDL_ALSA_SHARED "Dynamically load ALSA audio support" ON "SDL_ALSA" OFF)
|
||||
dep_option(SDL_ALSA_SHARED "Dynamically load ALSA audio support" ON "SDL_ALSA;SDL_DEPS_SHARED" OFF)
|
||||
dep_option(SDL_JACK "Support the JACK audio API" ${UNIX_SYS} "SDL_AUDIO" OFF)
|
||||
dep_option(SDL_JACK_SHARED "Dynamically load JACK audio support" ON "SDL_JACK" OFF)
|
||||
dep_option(SDL_JACK_SHARED "Dynamically load JACK audio support" ON "SDL_JACK;SDL_DEPS_SHARED" OFF)
|
||||
set_option(SDL_PIPEWIRE "Use Pipewire audio" ${UNIX_SYS})
|
||||
dep_option(SDL_PIPEWIRE_SHARED "Dynamically load Pipewire support" ON "SDL_PIPEWIRE" OFF)
|
||||
dep_option(SDL_PIPEWIRE_SHARED "Dynamically load Pipewire support" ON "SDL_PIPEWIRE;SDL_DEPS_SHARED" OFF)
|
||||
dep_option(SDL_PULSEAUDIO "Use PulseAudio" ${UNIX_SYS} "SDL_AUDIO" OFF)
|
||||
dep_option(SDL_PULSEAUDIO_SHARED "Dynamically load PulseAudio support" ON "SDL_PULSEAUDIO" OFF)
|
||||
dep_option(SDL_PULSEAUDIO_SHARED "Dynamically load PulseAudio support" ON "SDL_PULSEAUDIO;SDL_DEPS_SHARED" OFF)
|
||||
dep_option(SDL_SNDIO "Support the sndio audio API" ${UNIX_SYS} "SDL_AUDIO" OFF)
|
||||
dep_option(SDL_SNDIO_SHARED "Dynamically load the sndio audio API" ON "SDL_SNDIO" OFF)
|
||||
dep_option(SDL_SNDIO_SHARED "Dynamically load the sndio audio API" ON "SDL_SNDIO;SDL_DEPS_SHARED" OFF)
|
||||
set_option(SDL_RPATH "Use an rpath when linking SDL" ${SDL_RPATH_DEFAULT})
|
||||
set_option(SDL_CLOCK_GETTIME "Use clock_gettime() instead of gettimeofday()" ${SDL_CLOCK_GETTIME_DEFAULT})
|
||||
dep_option(SDL_X11 "Use X11 video driver" ${UNIX_SYS} "SDL_VIDEO" OFF)
|
||||
dep_option(SDL_X11_SHARED "Dynamically load X11 support" ON "SDL_X11" OFF)
|
||||
dep_option(SDL_X11_SHARED "Dynamically load X11 support" ON "SDL_X11;SDL_DEPS_SHARED" OFF)
|
||||
dep_option(SDL_X11_XCURSOR "Enable Xcursor support" ON SDL_X11 OFF)
|
||||
dep_option(SDL_X11_XDBE "Enable Xdbe support" ON SDL_X11 OFF)
|
||||
dep_option(SDL_X11_XINPUT "Enable XInput support" ON SDL_X11 OFF)
|
||||
@@ -356,9 +344,9 @@ dep_option(SDL_X11_XSCRNSAVER "Enable Xscrnsaver support" ON SDL_X11 OFF)
|
||||
dep_option(SDL_X11_XSHAPE "Enable XShape support" ON SDL_X11 OFF)
|
||||
dep_option(SDL_X11_XSYNC "Enable Xsync support" ON SDL_X11 OFF)
|
||||
dep_option(SDL_WAYLAND "Use Wayland video driver" ${UNIX_SYS} "SDL_VIDEO" OFF)
|
||||
dep_option(SDL_WAYLAND_SHARED "Dynamically load Wayland support" ON "SDL_WAYLAND" OFF)
|
||||
dep_option(SDL_WAYLAND_SHARED "Dynamically load Wayland support" ON "SDL_WAYLAND;SDL_DEPS_SHARED" OFF)
|
||||
dep_option(SDL_WAYLAND_LIBDECOR "Use client-side window decorations on Wayland" ON "SDL_WAYLAND" OFF)
|
||||
dep_option(SDL_WAYLAND_LIBDECOR_SHARED "Dynamically load libdecor support" ON "SDL_WAYLAND_LIBDECOR;SDL_WAYLAND_SHARED" OFF)
|
||||
dep_option(SDL_WAYLAND_LIBDECOR_SHARED "Dynamically load libdecor support" ON "SDL_WAYLAND_LIBDECOR;SDL_WAYLAND_SHARED;SDL_DEPS_SHARED" OFF)
|
||||
dep_option(SDL_RPI "Use Raspberry Pi video driver" ON "SDL_VIDEO;UNIX_SYS;SDL_CPU_ARM32 OR SDL_CPU_ARM64" OFF)
|
||||
dep_option(SDL_ROCKCHIP "Use ROCKCHIP Hardware Acceleration video driver" ON "SDL_VIDEO;UNIX_SYS;SDL_CPU_ARM32 OR SDL_CPU_ARM64" OFF)
|
||||
dep_option(SDL_COCOA "Use Cocoa video driver" ON "APPLE" OFF)
|
||||
@@ -368,7 +356,7 @@ dep_option(SDL_WASAPI "Use the Windows WASAPI audio driver" ON "WIN
|
||||
dep_option(SDL_RENDER_D3D "Enable the Direct3D 9 render driver" ON "SDL_RENDER;SDL_DIRECTX" OFF)
|
||||
dep_option(SDL_RENDER_D3D11 "Enable the Direct3D 11 render driver" ON "SDL_RENDER;SDL_DIRECTX" OFF)
|
||||
dep_option(SDL_RENDER_D3D12 "Enable the Direct3D 12 render driver" ON "SDL_RENDER;SDL_DIRECTX" OFF)
|
||||
dep_option(SDL_RENDER_METAL "Enable the Metal render driver" ON "SDL_RENDER;${APPLE}" OFF)
|
||||
dep_option(SDL_RENDER_METAL "Enable the Metal render driver" ON "SDL_RENDER;APPLE" OFF)
|
||||
dep_option(SDL_RENDER_GPU "Enable the SDL_GPU render driver" ON "SDL_RENDER;SDL_GPU" OFF)
|
||||
dep_option(SDL_VIVANTE "Use Vivante EGL video driver" ON "${UNIX_SYS};SDL_CPU_ARM32" OFF)
|
||||
dep_option(SDL_VULKAN "Enable Vulkan support" ON "SDL_VIDEO;ANDROID OR APPLE OR LINUX OR FREEBSD OR WINDOWS" OFF)
|
||||
@@ -376,14 +364,14 @@ dep_option(SDL_RENDER_VULKAN "Enable the Vulkan render driver" ON "SDL_REN
|
||||
dep_option(SDL_METAL "Enable Metal support" ON "APPLE" OFF)
|
||||
set_option(SDL_OPENVR "Use OpenVR video driver" OFF)
|
||||
dep_option(SDL_KMSDRM "Use KMS DRM video driver" ${UNIX_SYS} "SDL_VIDEO" OFF)
|
||||
dep_option(SDL_KMSDRM_SHARED "Dynamically load KMS DRM support" ON "SDL_KMSDRM" OFF)
|
||||
dep_option(SDL_KMSDRM_SHARED "Dynamically load KMS DRM support" ON "SDL_KMSDRM;SDL_DEPS_SHARED" OFF)
|
||||
set_option(SDL_OFFSCREEN "Use offscreen video driver" ON)
|
||||
dep_option(SDL_DUMMYCAMERA "Support the dummy camera driver" ON SDL_CAMERA OFF)
|
||||
option_string(SDL_BACKGROUNDING_SIGNAL "number to use for magic backgrounding signal or 'OFF'" OFF)
|
||||
option_string(SDL_FOREGROUNDING_SIGNAL "number to use for magic foregrounding signal or 'OFF'" OFF)
|
||||
dep_option(SDL_HIDAPI "Enable the HIDAPI subsystem" ON "NOT VISIONOS" OFF)
|
||||
dep_option(SDL_HIDAPI_LIBUSB "Use libusb for low level joystick drivers" ON SDL_HIDAPI_LIBUSB_AVAILABLE OFF)
|
||||
dep_option(SDL_HIDAPI_LIBUSB_SHARED "Dynamically load libusb support" ON SDL_HIDAPI_LIBUSB OFF)
|
||||
dep_option(SDL_HIDAPI_LIBUSB_SHARED "Dynamically load libusb support" ON "SDL_HIDAPI_LIBUSB;SDL_DEPS_SHARED" OFF)
|
||||
dep_option(SDL_HIDAPI_JOYSTICK "Use HIDAPI for low level joystick drivers" ON SDL_HIDAPI OFF)
|
||||
dep_option(SDL_VIRTUAL_JOYSTICK "Enable the virtual-joystick driver" ON SDL_HIDAPI OFF)
|
||||
set_option(SDL_LIBUDEV "Enable libudev support" ON)
|
||||
@@ -419,6 +407,29 @@ if(SDL_PRESEED)
|
||||
SDL_Preseed_CMakeCache()
|
||||
endif()
|
||||
|
||||
if(MSVC)
|
||||
if(NOT SDL_LIBC)
|
||||
# Make sure /RTC1 is disabled, otherwise it will use functions from the CRT
|
||||
foreach(flag_var
|
||||
CMAKE_C_FLAGS CMAKE_C_FLAGS_DEBUG CMAKE_C_FLAGS_RELEASE
|
||||
CMAKE_C_FLAGS_MINSIZEREL CMAKE_C_FLAGS_RELWITHDEBINFO
|
||||
CMAKE_CXX_FLAGS CMAKE_CXX_FLAGS_DEBUG CMAKE_CXX_FLAGS_RELEASE
|
||||
CMAKE_CXX_FLAGS_MINSIZEREL CMAKE_CXX_FLAGS_RELWITHDEBINFO)
|
||||
string(REGEX REPLACE "/RTC(su|[1su])" "" ${flag_var} "${${flag_var}}")
|
||||
endforeach(flag_var)
|
||||
set(CMAKE_MSVC_RUNTIME_CHECKS "")
|
||||
endif()
|
||||
|
||||
if(MSVC_CLANG)
|
||||
# clang-cl treats /W4 as '-Wall -Wextra' -- we don't need -Wextra
|
||||
foreach(flag_var
|
||||
CMAKE_C_FLAGS CMAKE_C_FLAGS_DEBUG CMAKE_C_FLAGS_RELEASE
|
||||
CMAKE_C_FLAGS_MINSIZEREL CMAKE_C_FLAGS_RELWITHDEBINFO)
|
||||
string(REGEX REPLACE "/W4" "/W3" ${flag_var} "${${flag_var}}")
|
||||
endforeach(flag_var)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(SDL_SHARED)
|
||||
add_library(SDL3-shared SHARED)
|
||||
add_library(SDL3::SDL3-shared ALIAS SDL3-shared)
|
||||
@@ -632,6 +643,11 @@ if(MSVC)
|
||||
# Mark SDL3.dll as compatible with Control-flow Enforcement Technology (CET)
|
||||
sdl_shared_link_options("-CETCOMPAT")
|
||||
endif()
|
||||
|
||||
# for VS >= 17.14 targeting ARM64: inline the Interlocked funcs
|
||||
if(MSVC_VERSION GREATER 1943 AND SDL_CPU_ARM64 AND NOT SDL_LIBC)
|
||||
sdl_compile_options(PRIVATE "/forceInterlockedFunctions-")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(CMAKE_C_COMPILER_ID STREQUAL "MSVC")
|
||||
@@ -648,7 +664,7 @@ if(SDL_ASSEMBLY)
|
||||
if(USE_GCC OR USE_CLANG OR USE_INTELCC)
|
||||
string(APPEND CMAKE_REQUIRED_FLAGS " -mmmx")
|
||||
endif()
|
||||
check_c_source_compiles("
|
||||
check_x86_source_compiles([==[
|
||||
#include <mmintrin.h>
|
||||
void ints_add(int *dest, int *a, int *b, unsigned size) {
|
||||
for (; size >= 2; size -= 2, dest += 2, a += 2, b += 2) {
|
||||
@@ -658,7 +674,7 @@ if(SDL_ASSEMBLY)
|
||||
int main(int argc, char *argv[]) {
|
||||
ints_add((int*)0, (int*)0, (int*)0, 0);
|
||||
return 0;
|
||||
}" COMPILER_SUPPORTS_MMX)
|
||||
}]==] COMPILER_SUPPORTS_MMX)
|
||||
cmake_pop_check_state()
|
||||
if(COMPILER_SUPPORTS_MMX)
|
||||
set(HAVE_MMX TRUE)
|
||||
@@ -669,7 +685,7 @@ if(SDL_ASSEMBLY)
|
||||
if(USE_GCC OR USE_CLANG OR USE_INTELCC)
|
||||
string(APPEND CMAKE_REQUIRED_FLAGS " -msse")
|
||||
endif()
|
||||
check_c_source_compiles("
|
||||
check_x86_source_compiles([==[
|
||||
#include <xmmintrin.h>
|
||||
void floats_add(float *dest, float *a, float *b, unsigned size) {
|
||||
for (; size >= 4; size -= 4, dest += 4, a += 4, b += 4) {
|
||||
@@ -679,7 +695,7 @@ if(SDL_ASSEMBLY)
|
||||
int main(int argc, char **argv) {
|
||||
floats_add((float*)0, (float*)0, (float*)0, 0);
|
||||
return 0;
|
||||
}" COMPILER_SUPPORTS_SSE)
|
||||
}]==] COMPILER_SUPPORTS_SSE)
|
||||
cmake_pop_check_state()
|
||||
if(COMPILER_SUPPORTS_SSE)
|
||||
set(HAVE_SSE TRUE)
|
||||
@@ -690,7 +706,7 @@ if(SDL_ASSEMBLY)
|
||||
if(USE_GCC OR USE_CLANG OR USE_INTELCC)
|
||||
string(APPEND CMAKE_REQUIRED_FLAGS " -msse2")
|
||||
endif()
|
||||
check_c_source_compiles("
|
||||
check_x86_source_compiles([==[
|
||||
#include <emmintrin.h>
|
||||
void doubles_add(double *dest, double *a, double *b, unsigned size) {
|
||||
for (; size >= 4; size -= 4, dest += 4, a += 4, b += 4) {
|
||||
@@ -700,7 +716,7 @@ if(SDL_ASSEMBLY)
|
||||
int main(int argc, char **argv) {
|
||||
doubles_add((double*)0, (double*)0, (double*)0, 0);
|
||||
return 0;
|
||||
}" COMPILER_SUPPORTS_SSE2)
|
||||
}]==] COMPILER_SUPPORTS_SSE2)
|
||||
cmake_pop_check_state()
|
||||
if(COMPILER_SUPPORTS_SSE2)
|
||||
set(HAVE_SSE2 TRUE)
|
||||
@@ -711,7 +727,7 @@ if(SDL_ASSEMBLY)
|
||||
if(USE_GCC OR USE_CLANG OR USE_INTELCC)
|
||||
string(APPEND CMAKE_REQUIRED_FLAGS " -msse3")
|
||||
endif()
|
||||
check_c_source_compiles("
|
||||
check_x86_source_compiles([==[
|
||||
#include <pmmintrin.h>
|
||||
void ints_add(int *dest, int *a, int *b, unsigned size) {
|
||||
for (; size >= 4; size -= 4, dest += 4, a += 4, b += 4) {
|
||||
@@ -721,7 +737,7 @@ if(SDL_ASSEMBLY)
|
||||
int main(int argc, char **argv) {
|
||||
ints_add((int*)0, (int*)0, (int*)0, 0);
|
||||
return 0;
|
||||
}" COMPILER_SUPPORTS_SSE3)
|
||||
}]==] COMPILER_SUPPORTS_SSE3)
|
||||
cmake_pop_check_state()
|
||||
if(COMPILER_SUPPORTS_SSE3)
|
||||
set(HAVE_SSE3 TRUE)
|
||||
@@ -732,7 +748,7 @@ if(SDL_ASSEMBLY)
|
||||
if(USE_GCC OR USE_CLANG OR USE_INTELCC)
|
||||
string(APPEND CMAKE_REQUIRED_FLAGS " -msse4.1")
|
||||
endif()
|
||||
check_c_source_compiles("
|
||||
check_x86_source_compiles([==[
|
||||
#include <smmintrin.h>
|
||||
void ints_mul(int *dest, int *a, int *b, unsigned size) {
|
||||
for (; size >= 4; size -= 4, dest += 4, a += 4, b += 4) {
|
||||
@@ -742,7 +758,7 @@ if(SDL_ASSEMBLY)
|
||||
int main(int argc, char **argv) {
|
||||
ints_mul((int*)0, (int*)0, (int*)0, 0);
|
||||
return 0;
|
||||
}" COMPILER_SUPPORTS_SSE4_1)
|
||||
}]==] COMPILER_SUPPORTS_SSE4_1)
|
||||
cmake_pop_check_state()
|
||||
if(COMPILER_SUPPORTS_SSE4_1)
|
||||
set(HAVE_SSE4_1 TRUE)
|
||||
@@ -753,19 +769,14 @@ if(SDL_ASSEMBLY)
|
||||
if(USE_GCC OR USE_CLANG OR USE_INTELCC)
|
||||
string(APPEND CMAKE_REQUIRED_FLAGS " -msse4.2")
|
||||
endif()
|
||||
check_c_source_compiles("
|
||||
check_x86_source_compiles([==[
|
||||
#include <nmmintrin.h>
|
||||
unsigned calc_crc32c(const char *text, unsigned len) {
|
||||
unsigned crc32c = ~0;
|
||||
for (; len >= 4; len -= 4, text += 4) {
|
||||
crc32c = (unsigned)_mm_crc32_u32(crc32c, *(unsigned*)text);
|
||||
}
|
||||
return crc32c;
|
||||
}
|
||||
__m128i bitmask;
|
||||
char data[16];
|
||||
int main(int argc, char **argv) {
|
||||
calc_crc32c(\"SDL_SSE4\",8);
|
||||
bitmask = _mm_cmpgt_epi64(_mm_set1_epi64x(0), _mm_loadu_si128((void*)data));
|
||||
return 0;
|
||||
}" COMPILER_SUPPORTS_SSE4_2)
|
||||
}]==] COMPILER_SUPPORTS_SSE4_2)
|
||||
cmake_pop_check_state()
|
||||
if(COMPILER_SUPPORTS_SSE4_2)
|
||||
set(HAVE_SSE4_2 TRUE)
|
||||
@@ -776,7 +787,7 @@ if(SDL_ASSEMBLY)
|
||||
if(USE_GCC OR USE_CLANG OR USE_INTELCC)
|
||||
string(APPEND CMAKE_REQUIRED_FLAGS " -mavx")
|
||||
endif()
|
||||
check_c_source_compiles("
|
||||
check_x86_source_compiles([==[
|
||||
#include <immintrin.h>
|
||||
void floats_add(float *dest, float *a, float *b, unsigned size) {
|
||||
for (; size >= 8; size -= 8, dest += 8, a += 8, b += 8) {
|
||||
@@ -786,7 +797,7 @@ if(SDL_ASSEMBLY)
|
||||
int main(int argc, char **argv) {
|
||||
floats_add((float*)0, (float*)0, (float*)0, 0);
|
||||
return 0;
|
||||
}" COMPILER_SUPPORTS_AVX)
|
||||
}]==] COMPILER_SUPPORTS_AVX)
|
||||
cmake_pop_check_state()
|
||||
if(COMPILER_SUPPORTS_AVX)
|
||||
set(HAVE_AVX TRUE)
|
||||
@@ -797,7 +808,7 @@ if(SDL_ASSEMBLY)
|
||||
if(USE_GCC OR USE_CLANG OR USE_INTELCC)
|
||||
string(APPEND CMAKE_REQUIRED_FLAGS " -mavx2")
|
||||
endif()
|
||||
check_c_source_compiles("
|
||||
check_x86_source_compiles([==[
|
||||
#include <immintrin.h>
|
||||
void ints_add(int *dest, int *a, int *b, unsigned size) {
|
||||
for (; size >= 8; size -= 8, dest += 8, a += 8, b += 8) {
|
||||
@@ -807,7 +818,7 @@ if(SDL_ASSEMBLY)
|
||||
int main(int argc, char **argv) {
|
||||
ints_add((int*)0, (int*)0, (int*)0, 0);
|
||||
return 0;
|
||||
}" COMPILER_SUPPORTS_AVX2)
|
||||
}]==] COMPILER_SUPPORTS_AVX2)
|
||||
cmake_pop_check_state()
|
||||
if(COMPILER_SUPPORTS_AVX2)
|
||||
set(HAVE_AVX2 TRUE)
|
||||
@@ -818,7 +829,7 @@ if(SDL_ASSEMBLY)
|
||||
if(USE_GCC OR USE_CLANG OR USE_INTELCC)
|
||||
string(APPEND CMAKE_REQUIRED_FLAGS " -mavx512f")
|
||||
endif()
|
||||
check_c_source_compiles("
|
||||
check_x86_source_compiles([==[
|
||||
#include <immintrin.h>
|
||||
void floats_add(float *dest, float *a, float *b, unsigned size) {
|
||||
for (; size >= 16; size -= 16, dest += 16, a += 16, b += 16) {
|
||||
@@ -828,7 +839,7 @@ if(SDL_ASSEMBLY)
|
||||
int main(int argc, char **argv) {
|
||||
floats_add((float*)0, (float*)0, (float*)0, 0);
|
||||
return 0;
|
||||
}" COMPILER_SUPPORTS_AVX512F)
|
||||
}]==] COMPILER_SUPPORTS_AVX512F)
|
||||
cmake_pop_check_state()
|
||||
if(COMPILER_SUPPORTS_AVX512F)
|
||||
set(HAVE_AVX512F TRUE)
|
||||
@@ -836,18 +847,17 @@ if(SDL_ASSEMBLY)
|
||||
endif()
|
||||
|
||||
if(SDL_ARMNEON)
|
||||
check_c_source_compiles("
|
||||
#include <arm_neon.h>
|
||||
void floats_add(float *dest, float *a, float *b, unsigned size) {
|
||||
for (; size >= 4; size -= 4, dest += 4, a += 4, b += 4) {
|
||||
vst1q_f32(dest, vaddq_f32(vld1q_f32(a), vld1q_f32(b)));
|
||||
}
|
||||
check_arm_source_compiles([==[
|
||||
#include <arm_neon.h>
|
||||
void floats_add(float *dest, float *a, float *b, unsigned size) {
|
||||
for (; size >= 4; size -= 4, dest += 4, a += 4, b += 4) {
|
||||
vst1q_f32(dest, vaddq_f32(vld1q_f32(a), vld1q_f32(b)));
|
||||
}
|
||||
int main(int argc, char *argv[]) {
|
||||
floats_add((float*)0, (float*)0, (float*)0, 0);
|
||||
return 0;
|
||||
}" COMPILER_SUPPORTS_ARMNEON)
|
||||
|
||||
}
|
||||
int main(int argc, char *argv[]) {
|
||||
floats_add((float*)0, (float*)0, (float*)0, 0);
|
||||
return 0;
|
||||
}]==] COMPILER_SUPPORTS_ARMNEON)
|
||||
if(COMPILER_SUPPORTS_ARMNEON)
|
||||
set(HAVE_ARMNEON TRUE)
|
||||
endif()
|
||||
@@ -1050,8 +1060,10 @@ if(SDL_LIBC)
|
||||
cmake_push_check_state()
|
||||
if(MSVC)
|
||||
string(APPEND CMAKE_REQUIRED_FLAGS " -we4244 -WX") # 'conversion' conversion from 'type1' to 'type2', possible loss of data
|
||||
else()
|
||||
elseif(HAVE_GCC_WFLOAT_CONVERSION)
|
||||
string(APPEND CMAKE_REQUIRED_FLAGS " -Wfloat-conversion -Werror")
|
||||
else()
|
||||
string(APPEND CMAKE_REQUIRED_FLAGS " -Wconversion -Werror")
|
||||
endif()
|
||||
foreach(math_fn isinf isnan)
|
||||
string(TOUPPER "${math_fn}" MATH_FN)
|
||||
@@ -1089,6 +1101,7 @@ if(SDL_LIBC)
|
||||
check_symbol_exists(gethostname "unistd.h" HAVE_GETHOSTNAME)
|
||||
check_symbol_exists(getpagesize "unistd.h" HAVE_GETPAGESIZE)
|
||||
check_symbol_exists(sigaction "signal.h" HAVE_SIGACTION)
|
||||
check_symbol_exists(sigtimedwait "signal.h" HAVE_SIGTIMEDWAIT)
|
||||
check_symbol_exists(setjmp "setjmp.h" HAVE_SETJMP)
|
||||
check_symbol_exists(nanosleep "time.h" HAVE_NANOSLEEP)
|
||||
check_symbol_exists(gmtime_r "time.h" HAVE_GMTIME_R)
|
||||
@@ -1289,8 +1302,8 @@ if(ANDROID)
|
||||
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/cmake/android")
|
||||
|
||||
sdl_glob_sources("${SDL3_SOURCE_DIR}/src/core/android/*.c")
|
||||
sdl_sources("${ANDROID_NDK}/sources/android/cpufeatures/cpu-features.c")
|
||||
set_property(SOURCE "${ANDROID_NDK}/sources/android/cpufeatures/cpu-features.c" APPEND_STRING PROPERTY COMPILE_FLAGS " -Wno-declaration-after-statement")
|
||||
sdl_sources("${CMAKE_ANDROID_NDK}/sources/android/cpufeatures/cpu-features.c")
|
||||
set_property(SOURCE "${CMAKE_ANDROID_NDK}/sources/android/cpufeatures/cpu-features.c" APPEND_STRING PROPERTY COMPILE_FLAGS " -Wno-declaration-after-statement")
|
||||
|
||||
sdl_glob_sources("${SDL3_SOURCE_DIR}/src/misc/android/*.c")
|
||||
set(HAVE_SDL_MISC TRUE)
|
||||
@@ -1334,9 +1347,7 @@ if(ANDROID)
|
||||
set(HAVE_SDL_HAPTIC TRUE)
|
||||
endif()
|
||||
|
||||
if(SDL_HIDAPI)
|
||||
CheckHIDAPI()
|
||||
endif()
|
||||
CheckHIDAPI()
|
||||
|
||||
if(SDL_JOYSTICK)
|
||||
set(SDL_JOYSTICK_ANDROID 1)
|
||||
@@ -2186,6 +2197,7 @@ elseif(APPLE)
|
||||
set(SDL_CAMERA_DRIVER_COREMEDIA 1)
|
||||
set(HAVE_CAMERA TRUE)
|
||||
sdl_glob_sources("${SDL3_SOURCE_DIR}/src/camera/coremedia/*.m")
|
||||
set(SDL_FRAMEWORK_AVFOUNDATION 1)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
@@ -2887,6 +2899,7 @@ elseif(N3DS)
|
||||
set(SDL_THREAD_N3DS 1)
|
||||
sdl_glob_sources("${SDL3_SOURCE_DIR}/src/thread/n3ds/*.c")
|
||||
sdl_sources(
|
||||
"${SDL3_SOURCE_DIR}/src/thread/generic/SDL_syscond.c"
|
||||
"${SDL3_SOURCE_DIR}/src/thread/generic/SDL_systls.c"
|
||||
"${SDL3_SOURCE_DIR}/src/thread/generic/SDL_sysrwlock.c"
|
||||
)
|
||||
@@ -2950,7 +2963,7 @@ if(WINDOWS)
|
||||
sdl_glob_sources("${SDL3_SOURCE_DIR}/src/process/windows/*.c")
|
||||
set(SDL_PROCESS_WINDOWS 1)
|
||||
set(HAVE_SDL_PROCESS TRUE)
|
||||
else()
|
||||
elseif(NOT ANDROID)
|
||||
check_c_source_compiles("
|
||||
#include <spawn.h>
|
||||
#include <unistd.h>
|
||||
@@ -3013,7 +3026,7 @@ if(SDL_GPU)
|
||||
set(SDL_GPU_D3D11 1)
|
||||
set(HAVE_SDL_GPU TRUE)
|
||||
endif()
|
||||
if(SDL_RENDER_D3D12)
|
||||
if(WINDOWS)
|
||||
sdl_glob_sources("${SDL3_SOURCE_DIR}/src/gpu/d3d12/*.c")
|
||||
set(SDL_GPU_D3D12 1)
|
||||
set(HAVE_SDL_GPU TRUE)
|
||||
@@ -3140,14 +3153,15 @@ endforeach()
|
||||
if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/REVISION.txt")
|
||||
file(STRINGS "${CMAKE_CURRENT_SOURCE_DIR}/REVISION.txt" revisions)
|
||||
list(GET revisions 0 revisions_0)
|
||||
string(STRIP "${revisions_0}" SDL_REVISION)
|
||||
string(STRIP "${revisions_0}" revisions_0_stripped)
|
||||
set(SDL_REVISION "SDL-${revisions_0_stripped}")
|
||||
else()
|
||||
set(SDL_REVISION "" CACHE STRING "Custom SDL revision (only used when REVISION.txt does not exist)")
|
||||
endif()
|
||||
if(NOT SDL_REVISION)
|
||||
# If SDL_REVISION is not overrided, use git to describe
|
||||
git_describe(SDL_REVISION_GIT)
|
||||
set(SDL_REVISION "SDL3-${SDL3_VERSION}-${SDL_REVISION_GIT}")
|
||||
set(SDL_REVISION "SDL-${SDL3_VERSION}-${SDL_REVISION_GIT}")
|
||||
endif()
|
||||
|
||||
execute_process(COMMAND "${CMAKE_COMMAND}" -E make_directory "${SDL3_BINARY_DIR}/include-revision/SDL3")
|
||||
@@ -3284,7 +3298,7 @@ else()
|
||||
endif()
|
||||
|
||||
if(ANDROID)
|
||||
sdl_include_directories(PRIVATE SYSTEM "${ANDROID_NDK}/sources/android/cpufeatures")
|
||||
sdl_include_directories(PRIVATE SYSTEM "${CMAKE_ANDROID_NDK}/sources/android/cpufeatures")
|
||||
endif()
|
||||
|
||||
if(APPLE)
|
||||
|
@@ -3,6 +3,7 @@
|
||||
SDL supports a number of development environments:
|
||||
- [CMake](docs/INTRO-cmake.md)
|
||||
- [Visual Studio on Windows](docs/INTRO-visualstudio.md)
|
||||
- [gcc on Windows](docs/INTRO-mingw.md)
|
||||
- [Xcode on Apple platforms](docs/INTRO-xcode.md)
|
||||
- [Android Studio](docs/INTRO-androidstudio.md)
|
||||
- [Emscripten for web](docs/INTRO-emscripten.md)
|
||||
|
@@ -168,8 +168,8 @@
|
||||
</Link>
|
||||
<PreBuildEvent>
|
||||
<Command>
|
||||
call $(ProjectDir)..\..\src\render\direct3d12\compile_shaders_xbox.bat $(ProjectDir)..\
|
||||
call $(ProjectDir)..\..\src\gpu\d3d12\compile_shaders_xbox.bat $(ProjectDir)..\
|
||||
call "$(ProjectDir)..\..\src\render\direct3d12\compile_shaders_xbox.bat" "$(ProjectDir)..\"
|
||||
call "$(ProjectDir)..\..\src\gpu\d3d12\compile_shaders_xbox.bat" "$(ProjectDir)..\"
|
||||
</Command>
|
||||
</PreBuildEvent>
|
||||
<PreBuildEvent>
|
||||
@@ -425,6 +425,7 @@
|
||||
<ClInclude Include="..\..\src\camera\SDL_syscamera.h" />
|
||||
<ClInclude Include="..\..\src\core\gdk\SDL_gdk.h" />
|
||||
<ClInclude Include="..\..\src\core\windows\SDL_directx.h" />
|
||||
<ClInclude Include="..\..\src\core\windows\SDL_gameinput.h" />
|
||||
<ClInclude Include="..\..\src\core\windows\SDL_hid.h" />
|
||||
<ClInclude Include="..\..\src\core\windows\SDL_immdevice.h" />
|
||||
<ClInclude Include="..\..\src\core\windows\SDL_windows.h" />
|
||||
@@ -441,6 +442,7 @@
|
||||
<ClInclude Include="..\..\src\events\SDL_displayevents_c.h" />
|
||||
<ClInclude Include="..\..\src\events\SDL_dropevents_c.h" />
|
||||
<ClInclude Include="..\..\src\events\SDL_events_c.h" />
|
||||
<ClInclude Include="..\..\src\events\SDL_eventwatch_c.h" />
|
||||
<ClInclude Include="..\..\src\events\SDL_keyboard_c.h" />
|
||||
<ClInclude Include="..\..\src\events\SDL_keymap_c.h" />
|
||||
<ClInclude Include="..\..\src\events\SDL_mouse_c.h" />
|
||||
@@ -594,6 +596,7 @@
|
||||
<ClInclude Include="..\..\src\video\SDL_pixels_c.h" />
|
||||
<ClInclude Include="..\..\src\video\SDL_rect_c.h" />
|
||||
<ClInclude Include="..\..\src\video\SDL_RLEaccel_c.h" />
|
||||
<ClInclude Include="..\..\src\video\SDL_stb_c.h" />
|
||||
<ClInclude Include="..\..\src\video\SDL_surface_c.h" />
|
||||
<ClInclude Include="..\..\src\video\SDL_sysvideo.h" />
|
||||
<ClInclude Include="..\..\src\video\SDL_vulkan_internal.h" />
|
||||
@@ -640,6 +643,7 @@
|
||||
<ClCompile Include="..\..\src\audio\SDL_wave.c" />
|
||||
<ClCompile Include="..\..\src\audio\wasapi\SDL_wasapi.c" />
|
||||
<ClCompile Include="..\..\src\core\SDL_core_unsupported.c" />
|
||||
<ClCompile Include="..\..\src\core\windows\SDL_gameinput.c"/>
|
||||
<ClCompile Include="..\..\src\core\windows\SDL_hid.c" />
|
||||
<ClCompile Include="..\..\src\core\windows\SDL_immdevice.c" />
|
||||
<ClCompile Include="..\..\src\core\windows\SDL_windows.c" />
|
||||
@@ -673,6 +677,7 @@
|
||||
<ClCompile Include="..\..\src\events\SDL_displayevents.c" />
|
||||
<ClCompile Include="..\..\src\events\SDL_dropevents.c" />
|
||||
<ClCompile Include="..\..\src\events\SDL_events.c" />
|
||||
<ClCompile Include="..\..\src\events\SDL_eventwatch.c" />
|
||||
<ClCompile Include="..\..\src\events\SDL_keyboard.c" />
|
||||
<ClCompile Include="..\..\src\events\SDL_keymap.c" />
|
||||
<ClCompile Include="..\..\src\events\SDL_mouse.c" />
|
||||
@@ -868,6 +873,7 @@
|
||||
<ClCompile Include="..\..\src\video\SDL_pixels.c" />
|
||||
<ClCompile Include="..\..\src\video\SDL_rect.c" />
|
||||
<ClCompile Include="..\..\src\video\SDL_RLEaccel.c" />
|
||||
<ClCompile Include="..\..\src\video\SDL_stb.c" />
|
||||
<ClCompile Include="..\..\src\video\SDL_stretch.c" />
|
||||
<ClCompile Include="..\..\src\video\SDL_surface.c" />
|
||||
<ClCompile Include="..\..\src\video\SDL_video.c" />
|
||||
|
@@ -27,6 +27,7 @@
|
||||
<ClCompile Include="..\..\src\audio\SDL_wave.c" />
|
||||
<ClCompile Include="..\..\src\audio\wasapi\SDL_wasapi.c" />
|
||||
<ClCompile Include="..\..\src\core\SDL_core_unsupported.c" />
|
||||
<ClCompile Include="..\..\src\core\windows\SDL_gameinput.c" />
|
||||
<ClCompile Include="..\..\src\core\windows\SDL_hid.c" />
|
||||
<ClCompile Include="..\..\src\core\windows\SDL_immdevice.c" />
|
||||
<ClCompile Include="..\..\src\core\windows\SDL_windows.c" />
|
||||
@@ -38,6 +39,7 @@
|
||||
<ClCompile Include="..\..\src\events\SDL_displayevents.c" />
|
||||
<ClCompile Include="..\..\src\events\SDL_dropevents.c" />
|
||||
<ClCompile Include="..\..\src\events\SDL_events.c" />
|
||||
<ClCompile Include="..\..\src\events\SDL_eventwatch.c" />
|
||||
<ClCompile Include="..\..\src\events\SDL_keyboard.c" />
|
||||
<ClCompile Include="..\..\src\events\SDL_keymap.c" />
|
||||
<ClCompile Include="..\..\src\events\SDL_mouse.c" />
|
||||
@@ -175,6 +177,7 @@
|
||||
<ClCompile Include="..\..\src\video\SDL_pixels.c" />
|
||||
<ClCompile Include="..\..\src\video\SDL_rect.c" />
|
||||
<ClCompile Include="..\..\src\video\SDL_RLEaccel.c" />
|
||||
<ClCompile Include="..\..\src\video\SDL_stb.c" />
|
||||
<ClCompile Include="..\..\src\video\SDL_stretch.c" />
|
||||
<ClCompile Include="..\..\src\video\SDL_surface.c" />
|
||||
<ClCompile Include="..\..\src\video\SDL_video.c" />
|
||||
@@ -314,6 +317,7 @@
|
||||
<ClInclude Include="..\..\src\audio\wasapi\SDL_wasapi.h" />
|
||||
<ClInclude Include="..\..\src\core\gdk\SDL_gdk.h" />
|
||||
<ClInclude Include="..\..\src\core\windows\SDL_directx.h" />
|
||||
<ClInclude Include="..\..\src\core\windows\SDL_gameinput.h" />
|
||||
<ClInclude Include="..\..\src\core\windows\SDL_hid.h" />
|
||||
<ClInclude Include="..\..\src\core\windows\SDL_immdevice.h" />
|
||||
<ClInclude Include="..\..\src\core\windows\SDL_windows.h" />
|
||||
@@ -330,6 +334,7 @@
|
||||
<ClInclude Include="..\..\src\events\SDL_displayevents_c.h" />
|
||||
<ClInclude Include="..\..\src\events\SDL_dropevents_c.h" />
|
||||
<ClInclude Include="..\..\src\events\SDL_events_c.h" />
|
||||
<ClInclude Include="..\..\src\events\SDL_eventwatch_c.h" />
|
||||
<ClInclude Include="..\..\src\events\SDL_keyboard_c.h" />
|
||||
<ClInclude Include="..\..\src\events\SDL_keymap_c.h" />
|
||||
<ClInclude Include="..\..\src\events\SDL_mouse_c.h" />
|
||||
@@ -434,6 +439,7 @@
|
||||
<ClInclude Include="..\..\src\video\SDL_pixels_c.h" />
|
||||
<ClInclude Include="..\..\src\video\SDL_rect_c.h" />
|
||||
<ClInclude Include="..\..\src\video\SDL_RLEaccel_c.h" />
|
||||
<ClInclude Include="..\..\src\video\SDL_stb_c.h" />
|
||||
<ClInclude Include="..\..\src\video\SDL_surface_c.h" />
|
||||
<ClInclude Include="..\..\src\video\SDL_sysvideo.h" />
|
||||
<ClInclude Include="..\..\src\video\SDL_vulkan_internal.h" />
|
||||
|
@@ -336,6 +336,7 @@
|
||||
<ClInclude Include="..\..\src\camera\SDL_camera_c.h" />
|
||||
<ClInclude Include="..\..\src\camera\SDL_syscamera.h" />
|
||||
<ClInclude Include="..\..\src\core\windows\SDL_directx.h" />
|
||||
<ClInclude Include="..\..\src\core\windows\SDL_gameinput.h" />
|
||||
<ClInclude Include="..\..\src\core\windows\SDL_hid.h" />
|
||||
<ClInclude Include="..\..\src\core\windows\SDL_immdevice.h" />
|
||||
<ClInclude Include="..\..\src\core\windows\SDL_windows.h" />
|
||||
@@ -353,6 +354,7 @@
|
||||
<ClInclude Include="..\..\src\events\SDL_displayevents_c.h" />
|
||||
<ClInclude Include="..\..\src\events\SDL_dropevents_c.h" />
|
||||
<ClInclude Include="..\..\src\events\SDL_events_c.h" />
|
||||
<ClInclude Include="..\..\src\events\SDL_eventwatch_c.h" />
|
||||
<ClInclude Include="..\..\src\events\SDL_keyboard_c.h" />
|
||||
<ClInclude Include="..\..\src\events\SDL_keymap_c.h" />
|
||||
<ClInclude Include="..\..\src\events\SDL_mouse_c.h" />
|
||||
@@ -492,6 +494,7 @@
|
||||
<ClInclude Include="..\..\src\video\SDL_pixels_c.h" />
|
||||
<ClInclude Include="..\..\src\video\SDL_rect_c.h" />
|
||||
<ClInclude Include="..\..\src\video\SDL_RLEaccel_c.h" />
|
||||
<ClInclude Include="..\..\src\video\SDL_stb_c.h" />
|
||||
<ClInclude Include="..\..\src\video\SDL_surface_c.h" />
|
||||
<ClInclude Include="..\..\src\video\SDL_sysvideo.h" />
|
||||
<ClInclude Include="..\..\src\video\SDL_vulkan_internal.h" />
|
||||
@@ -538,6 +541,7 @@
|
||||
<ClCompile Include="..\..\src\audio\SDL_wave.c" />
|
||||
<ClCompile Include="..\..\src\audio\wasapi\SDL_wasapi.c" />
|
||||
<ClCompile Include="..\..\src\core\SDL_core_unsupported.c" />
|
||||
<ClCompile Include="..\..\src\core\windows\SDL_gameinput.c" />
|
||||
<ClCompile Include="..\..\src\core\windows\SDL_hid.c" />
|
||||
<ClCompile Include="..\..\src\core\windows\SDL_immdevice.c" />
|
||||
<ClCompile Include="..\..\src\core\windows\SDL_windows.c" />
|
||||
@@ -555,6 +559,7 @@
|
||||
<ClCompile Include="..\..\src\events\SDL_displayevents.c" />
|
||||
<ClCompile Include="..\..\src\events\SDL_dropevents.c" />
|
||||
<ClCompile Include="..\..\src\events\SDL_events.c" />
|
||||
<ClCompile Include="..\..\src\events\SDL_eventwatch.c" />
|
||||
<ClCompile Include="..\..\src\events\SDL_keyboard.c" />
|
||||
<ClCompile Include="..\..\src\events\SDL_keymap.c" />
|
||||
<ClCompile Include="..\..\src\events\SDL_mouse.c" />
|
||||
@@ -703,6 +708,7 @@
|
||||
<ClCompile Include="..\..\src\video\SDL_pixels.c" />
|
||||
<ClCompile Include="..\..\src\video\SDL_rect.c" />
|
||||
<ClCompile Include="..\..\src\video\SDL_RLEaccel.c" />
|
||||
<ClCompile Include="..\..\src\video\SDL_stb.c" />
|
||||
<ClCompile Include="..\..\src\video\SDL_stretch.c" />
|
||||
<ClCompile Include="..\..\src\video\SDL_surface.c" />
|
||||
<ClCompile Include="..\..\src\video\SDL_video.c" />
|
||||
|
@@ -486,6 +486,12 @@
|
||||
<ClInclude Include="..\..\src\audio\SDL_audioresample.h">
|
||||
<Filter>audio</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\core\windows\SDL_directx.h">
|
||||
<Filter>core\windows</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\core\windows\SDL_gameinput.h">
|
||||
<Filter>core\windows</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\core\windows\SDL_hid.h">
|
||||
<Filter>core\windows</Filter>
|
||||
</ClInclude>
|
||||
@@ -528,6 +534,9 @@
|
||||
<ClInclude Include="..\..\src\events\SDL_events_c.h">
|
||||
<Filter>events</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\events\SDL_eventfilter_c.h">
|
||||
<Filter>events</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\events\SDL_keyboard_c.h">
|
||||
<Filter>events</Filter>
|
||||
</ClInclude>
|
||||
@@ -666,6 +675,9 @@
|
||||
<ClInclude Include="..\..\src\video\SDL_egl_c.h">
|
||||
<Filter>video</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\video\SDL_stb_c.h">
|
||||
<Filter>video</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\video\SDL_yuv_c.h">
|
||||
<Filter>video</Filter>
|
||||
</ClInclude>
|
||||
@@ -1028,6 +1040,9 @@
|
||||
<ClCompile Include="..\..\src\core\SDL_core_unsupported.c">
|
||||
<Filter>core</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\core\windows\SDL_gameinput.c">
|
||||
<Filter>core\windows</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\core\windows\SDL_hid.c">
|
||||
<Filter>core\windows</Filter>
|
||||
</ClCompile>
|
||||
@@ -1064,6 +1079,9 @@
|
||||
<ClCompile Include="..\..\src\events\SDL_events.c">
|
||||
<Filter>events</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\events\SDL_eventfilter.c">
|
||||
<Filter>events</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\events\SDL_keyboard.c">
|
||||
<Filter>events</Filter>
|
||||
</ClCompile>
|
||||
@@ -1283,6 +1301,9 @@
|
||||
<ClCompile Include="..\..\src\video\SDL_rect.c">
|
||||
<Filter>video</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\video\SDL_stb.c">
|
||||
<Filter>video</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\video\SDL_stretch.c">
|
||||
<Filter>video</Filter>
|
||||
</ClCompile>
|
||||
|
10
WhatsNew.txt
10
WhatsNew.txt
@@ -1,6 +1,16 @@
|
||||
|
||||
This is a list of major changes in SDL's version history.
|
||||
|
||||
---------------------------------------------------------------------------
|
||||
3.2.10:
|
||||
---------------------------------------------------------------------------
|
||||
* Added SDL_HINT_VIDEO_X11_EXTERNAL_WINDOW_INPUT to control whether XSelectInput() should be called on external windows to enable input events.
|
||||
|
||||
---------------------------------------------------------------------------
|
||||
3.2.4:
|
||||
---------------------------------------------------------------------------
|
||||
* Added SDL_StretchSurface()
|
||||
|
||||
---------------------------------------------------------------------------
|
||||
3.2.0:
|
||||
---------------------------------------------------------------------------
|
||||
|
@@ -19,10 +19,10 @@
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>FMWK</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>3.2.4</string>
|
||||
<string>3.2.24</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>SDLX</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>3.2.4</string>
|
||||
<string>3.2.24</string>
|
||||
</dict>
|
||||
</plist>
|
||||
|
@@ -512,10 +512,16 @@
|
||||
F3D46B122D20625800D9CBDF /* SDL_egl.h in Headers */ = {isa = PBXBuildFile; fileRef = F3D46A8E2D20625800D9CBDF /* SDL_egl.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
F3D46B132D20625800D9CBDF /* SDL_filesystem.h in Headers */ = {isa = PBXBuildFile; fileRef = F3D46A922D20625800D9CBDF /* SDL_filesystem.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
F3D60A8328C16A1900788A3A /* SDL_hidapi_wii.c in Sources */ = {isa = PBXBuildFile; fileRef = F3D60A8228C16A1800788A3A /* SDL_hidapi_wii.c */; };
|
||||
F3D8BDFC2D6D2C7000B22FA1 /* SDL_eventwatch_c.h in Headers */ = {isa = PBXBuildFile; fileRef = F3D8BDFB2D6D2C7000B22FA1 /* SDL_eventwatch_c.h */; };
|
||||
F3D8BDFD2D6D2C7000B22FA1 /* SDL_eventwatch.c in Sources */ = {isa = PBXBuildFile; fileRef = F3D8BDFA2D6D2C7000B22FA1 /* SDL_eventwatch.c */; };
|
||||
F3DDCC562AFD42B600B0842B /* SDL_clipboard_c.h in Headers */ = {isa = PBXBuildFile; fileRef = F3DDCC4D2AFD42B500B0842B /* SDL_clipboard_c.h */; };
|
||||
F3DDCC5B2AFD42B600B0842B /* SDL_video_c.h in Headers */ = {isa = PBXBuildFile; fileRef = F3DDCC522AFD42B600B0842B /* SDL_video_c.h */; };
|
||||
F3DDCC5D2AFD42B600B0842B /* SDL_rect_impl.h in Headers */ = {isa = PBXBuildFile; fileRef = F3DDCC542AFD42B600B0842B /* SDL_rect_impl.h */; };
|
||||
F3E5A6EB2AD5E0E600293D83 /* SDL_properties.c in Sources */ = {isa = PBXBuildFile; fileRef = F3E5A6EA2AD5E0E600293D83 /* SDL_properties.c */; };
|
||||
F3EFA5ED2D5AB97300BCF22F /* SDL_stb_c.h in Headers */ = {isa = PBXBuildFile; fileRef = F3EFA5EA2D5AB97300BCF22F /* SDL_stb_c.h */; };
|
||||
F3EFA5EE2D5AB97300BCF22F /* stb_image.h in Headers */ = {isa = PBXBuildFile; fileRef = F3EFA5EC2D5AB97300BCF22F /* stb_image.h */; };
|
||||
F3EFA5EF2D5AB97300BCF22F /* SDL_surface_c.h in Headers */ = {isa = PBXBuildFile; fileRef = F3EFA5EB2D5AB97300BCF22F /* SDL_surface_c.h */; };
|
||||
F3EFA5F02D5AB97300BCF22F /* SDL_stb.c in Sources */ = {isa = PBXBuildFile; fileRef = F3EFA5E92D5AB97300BCF22F /* SDL_stb.c */; };
|
||||
F3F07D5A269640160074468B /* SDL_hidapi_luna.c in Sources */ = {isa = PBXBuildFile; fileRef = F3F07D59269640160074468B /* SDL_hidapi_luna.c */; };
|
||||
F3F15D7F2D011912007AE210 /* SDL_dialog.c in Sources */ = {isa = PBXBuildFile; fileRef = F3F15D7D2D011912007AE210 /* SDL_dialog.c */; };
|
||||
F3F15D802D011912007AE210 /* SDL_dialog_utils.h in Headers */ = {isa = PBXBuildFile; fileRef = F3F15D7E2D011912007AE210 /* SDL_dialog_utils.h */; };
|
||||
@@ -1075,10 +1081,16 @@
|
||||
F3D46AC82D20625800D9CBDF /* SDL_video.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SDL_video.h; sourceTree = "<group>"; };
|
||||
F3D46AC92D20625800D9CBDF /* SDL_vulkan.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SDL_vulkan.h; sourceTree = "<group>"; };
|
||||
F3D60A8228C16A1800788A3A /* SDL_hidapi_wii.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SDL_hidapi_wii.c; sourceTree = "<group>"; };
|
||||
F3D8BDFA2D6D2C7000B22FA1 /* SDL_eventwatch.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = SDL_eventwatch.c; sourceTree = "<group>"; };
|
||||
F3D8BDFB2D6D2C7000B22FA1 /* SDL_eventwatch_c.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SDL_eventwatch_c.h; sourceTree = "<group>"; };
|
||||
F3DDCC4D2AFD42B500B0842B /* SDL_clipboard_c.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDL_clipboard_c.h; sourceTree = "<group>"; };
|
||||
F3DDCC522AFD42B600B0842B /* SDL_video_c.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDL_video_c.h; sourceTree = "<group>"; };
|
||||
F3DDCC542AFD42B600B0842B /* SDL_rect_impl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDL_rect_impl.h; sourceTree = "<group>"; };
|
||||
F3E5A6EA2AD5E0E600293D83 /* SDL_properties.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SDL_properties.c; sourceTree = "<group>"; };
|
||||
F3EFA5E92D5AB97300BCF22F /* SDL_stb.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = SDL_stb.c; sourceTree = "<group>"; };
|
||||
F3EFA5EA2D5AB97300BCF22F /* SDL_stb_c.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SDL_stb_c.h; sourceTree = "<group>"; };
|
||||
F3EFA5EB2D5AB97300BCF22F /* SDL_surface_c.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SDL_surface_c.h; sourceTree = "<group>"; };
|
||||
F3EFA5EC2D5AB97300BCF22F /* stb_image.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = stb_image.h; sourceTree = "<group>"; };
|
||||
F3F07D59269640160074468B /* SDL_hidapi_luna.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SDL_hidapi_luna.c; sourceTree = "<group>"; };
|
||||
F3F15D7C2D011912007AE210 /* SDL_dialog.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SDL_dialog.h; sourceTree = "<group>"; };
|
||||
F3F15D7D2D011912007AE210 /* SDL_dialog.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = SDL_dialog.c; sourceTree = "<group>"; };
|
||||
@@ -1586,43 +1598,47 @@
|
||||
A7D8A60523E2513D00DCD162 /* dummy */,
|
||||
A7D8A72123E2513E00DCD162 /* khronos */,
|
||||
A7D8A5EC23E2513D00DCD162 /* offscreen */,
|
||||
A7D8A61823E2513D00DCD162 /* uikit */,
|
||||
A7D8A76C23E2513E00DCD162 /* yuv2rgb */,
|
||||
A7D8A76B23E2513E00DCD162 /* SDL_blit.h */,
|
||||
A7D8A64C23E2513D00DCD162 /* SDL_blit.c */,
|
||||
A7D8A66223E2513E00DCD162 /* SDL_blit_0.c */,
|
||||
A7D8A6FA23E2513E00DCD162 /* SDL_blit_1.c */,
|
||||
A7D8A66423E2513E00DCD162 /* SDL_blit_A.c */,
|
||||
A7D8A63F23E2513D00DCD162 /* SDL_blit_auto.c */,
|
||||
A7D8A73F23E2513E00DCD162 /* SDL_blit_auto.h */,
|
||||
A7D8A61623E2513D00DCD162 /* SDL_blit_copy.c */,
|
||||
A7D8A63F23E2513D00DCD162 /* SDL_blit_auto.c */,
|
||||
A7D8A76623E2513E00DCD162 /* SDL_blit_copy.h */,
|
||||
A7D8A61623E2513D00DCD162 /* SDL_blit_copy.c */,
|
||||
A7D8A64223E2513D00DCD162 /* SDL_blit_N.c */,
|
||||
A7D8A60223E2513D00DCD162 /* SDL_blit_slow.c */,
|
||||
A7D8A66323E2513E00DCD162 /* SDL_blit_slow.h */,
|
||||
A7D8A64C23E2513D00DCD162 /* SDL_blit.c */,
|
||||
A7D8A76B23E2513E00DCD162 /* SDL_blit.h */,
|
||||
A7D8A60223E2513D00DCD162 /* SDL_blit_slow.c */,
|
||||
A7D8A77323E2513E00DCD162 /* SDL_bmp.c */,
|
||||
F3DDCC4D2AFD42B500B0842B /* SDL_clipboard_c.h */,
|
||||
A7D8A67B23E2513E00DCD162 /* SDL_clipboard.c */,
|
||||
A7D8A60423E2513D00DCD162 /* SDL_egl_c.h */,
|
||||
F3DDCC4D2AFD42B500B0842B /* SDL_clipboard_c.h */,
|
||||
A7D8A6B623E2513E00DCD162 /* SDL_egl.c */,
|
||||
A7D8A60423E2513D00DCD162 /* SDL_egl_c.h */,
|
||||
A7D8A76823E2513E00DCD162 /* SDL_fillrect.c */,
|
||||
A7D8A74023E2513E00DCD162 /* SDL_pixels_c.h */,
|
||||
A7D8A64D23E2513D00DCD162 /* SDL_pixels.c */,
|
||||
A7D8A74023E2513E00DCD162 /* SDL_pixels_c.h */,
|
||||
A7D8A63423E2513D00DCD162 /* SDL_rect.c */,
|
||||
A7D8A60C23E2513D00DCD162 /* SDL_rect_c.h */,
|
||||
F3DDCC542AFD42B600B0842B /* SDL_rect_impl.h */,
|
||||
A7D8A63423E2513D00DCD162 /* SDL_rect.c */,
|
||||
A7D8A76723E2513E00DCD162 /* SDL_RLEaccel_c.h */,
|
||||
A7D8A61523E2513D00DCD162 /* SDL_RLEaccel.c */,
|
||||
A7D8A76723E2513E00DCD162 /* SDL_RLEaccel_c.h */,
|
||||
F3EFA5E92D5AB97300BCF22F /* SDL_stb.c */,
|
||||
F3EFA5EA2D5AB97300BCF22F /* SDL_stb_c.h */,
|
||||
A7D8A60323E2513D00DCD162 /* SDL_stretch.c */,
|
||||
A7D8A61423E2513D00DCD162 /* SDL_surface.c */,
|
||||
F3EFA5EB2D5AB97300BCF22F /* SDL_surface_c.h */,
|
||||
A7D8A61723E2513D00DCD162 /* SDL_sysvideo.h */,
|
||||
A7D8A60E23E2513D00DCD162 /* SDL_video.c */,
|
||||
F3DDCC522AFD42B600B0842B /* SDL_video_c.h */,
|
||||
E4F7981F2AD8D87F00669F54 /* SDL_video_unsupported.c */,
|
||||
A7D8A60E23E2513D00DCD162 /* SDL_video.c */,
|
||||
A7D8A63E23E2513D00DCD162 /* SDL_vulkan_internal.h */,
|
||||
A7D8A64023E2513D00DCD162 /* SDL_vulkan_utils.c */,
|
||||
A7D8A76A23E2513E00DCD162 /* SDL_yuv_c.h */,
|
||||
A7D8A67C23E2513E00DCD162 /* SDL_yuv.c */,
|
||||
A7D8A76A23E2513E00DCD162 /* SDL_yuv_c.h */,
|
||||
F3EFA5EC2D5AB97300BCF22F /* stb_image.h */,
|
||||
A7D8A61823E2513D00DCD162 /* uikit */,
|
||||
A7D8A76C23E2513E00DCD162 /* yuv2rgb */,
|
||||
);
|
||||
path = video;
|
||||
sourceTree = "<group>";
|
||||
@@ -2197,29 +2213,31 @@
|
||||
A7D8A93623E2514000DCD162 /* scancodes_linux.h */,
|
||||
A7D8A92C23E2514000DCD162 /* scancodes_windows.h */,
|
||||
A7D8A94123E2514000DCD162 /* scancodes_xfree86.h */,
|
||||
F3C2CB202C5DDDB2004D7998 /* SDL_categories_c.h */,
|
||||
F3C2CB212C5DDDB2004D7998 /* SDL_categories.c */,
|
||||
A7D8A93923E2514000DCD162 /* SDL_clipboardevents_c.h */,
|
||||
F3C2CB202C5DDDB2004D7998 /* SDL_categories_c.h */,
|
||||
A7D8A93A23E2514000DCD162 /* SDL_clipboardevents.c */,
|
||||
A7D8A93123E2514000DCD162 /* SDL_displayevents_c.h */,
|
||||
A7D8A93923E2514000DCD162 /* SDL_clipboardevents_c.h */,
|
||||
A7D8A92D23E2514000DCD162 /* SDL_displayevents.c */,
|
||||
A7D8A92E23E2514000DCD162 /* SDL_dropevents_c.h */,
|
||||
A7D8A93123E2514000DCD162 /* SDL_displayevents_c.h */,
|
||||
A7D8A93B23E2514000DCD162 /* SDL_dropevents.c */,
|
||||
A7D8A94223E2514000DCD162 /* SDL_events_c.h */,
|
||||
A7D8A92E23E2514000DCD162 /* SDL_dropevents_c.h */,
|
||||
A7D8A93523E2514000DCD162 /* SDL_events.c */,
|
||||
A7D8A93D23E2514000DCD162 /* SDL_keyboard_c.h */,
|
||||
A7D8A94223E2514000DCD162 /* SDL_events_c.h */,
|
||||
F3D8BDFA2D6D2C7000B22FA1 /* SDL_eventwatch.c */,
|
||||
F3D8BDFB2D6D2C7000B22FA1 /* SDL_eventwatch_c.h */,
|
||||
A7D8A93823E2514000DCD162 /* SDL_keyboard.c */,
|
||||
F31013C62C24E98200FBE946 /* SDL_keymap_c.h */,
|
||||
A7D8A93D23E2514000DCD162 /* SDL_keyboard_c.h */,
|
||||
F31013C52C24E98200FBE946 /* SDL_keymap.c */,
|
||||
A7D8A92B23E2514000DCD162 /* SDL_mouse_c.h */,
|
||||
F31013C62C24E98200FBE946 /* SDL_keymap_c.h */,
|
||||
A7D8A92A23E2514000DCD162 /* SDL_mouse.c */,
|
||||
63134A232A7902FD0021E9A6 /* SDL_pen_c.h */,
|
||||
A7D8A92B23E2514000DCD162 /* SDL_mouse_c.h */,
|
||||
63134A242A7902FD0021E9A6 /* SDL_pen.c */,
|
||||
63134A232A7902FD0021E9A6 /* SDL_pen_c.h */,
|
||||
A7D8A93C23E2514000DCD162 /* SDL_quit.c */,
|
||||
A7D8A93723E2514000DCD162 /* SDL_touch_c.h */,
|
||||
A7D8A93E23E2514000DCD162 /* SDL_touch.c */,
|
||||
A7D8A94323E2514000DCD162 /* SDL_windowevents_c.h */,
|
||||
A7D8A93723E2514000DCD162 /* SDL_touch_c.h */,
|
||||
A7D8A92F23E2514000DCD162 /* SDL_windowevents.c */,
|
||||
A7D8A94323E2514000DCD162 /* SDL_windowevents_c.h */,
|
||||
);
|
||||
path = events;
|
||||
sourceTree = "<group>";
|
||||
@@ -2458,6 +2476,9 @@
|
||||
A7D8BB6F23E2514500DCD162 /* SDL_clipboardevents_c.h in Headers */,
|
||||
A7D8AECA23E2514100DCD162 /* SDL_cocoaclipboard.h in Headers */,
|
||||
A7D8AF1223E2514100DCD162 /* SDL_cocoaevents.h in Headers */,
|
||||
F3EFA5ED2D5AB97300BCF22F /* SDL_stb_c.h in Headers */,
|
||||
F3EFA5EE2D5AB97300BCF22F /* stb_image.h in Headers */,
|
||||
F3EFA5EF2D5AB97300BCF22F /* SDL_surface_c.h in Headers */,
|
||||
A7D8AE8E23E2514100DCD162 /* SDL_cocoakeyboard.h in Headers */,
|
||||
A7D8AF0623E2514100DCD162 /* SDL_cocoamessagebox.h in Headers */,
|
||||
A7D8AEB223E2514100DCD162 /* SDL_cocoametalview.h in Headers */,
|
||||
@@ -2692,6 +2713,7 @@
|
||||
A7D8B3D423E2514300DCD162 /* yuv_rgb.h in Headers */,
|
||||
F3FA5A252B59ACE000FEAD97 /* yuv_rgb_common.h in Headers */,
|
||||
F3FA5A1D2B59ACE000FEAD97 /* yuv_rgb_internal.h in Headers */,
|
||||
F3D8BDFC2D6D2C7000B22FA1 /* SDL_eventwatch_c.h in Headers */,
|
||||
F3FA5A242B59ACE000FEAD97 /* yuv_rgb_lsx.h in Headers */,
|
||||
F3FA5A1E2B59ACE000FEAD97 /* yuv_rgb_lsx_func.h in Headers */,
|
||||
F3FA5A1F2B59ACE000FEAD97 /* yuv_rgb_sse.h in Headers */,
|
||||
@@ -2950,6 +2972,8 @@
|
||||
566E26CF246274CC00718109 /* SDL_syslocale.m in Sources */,
|
||||
A7D8AFC023E2514200DCD162 /* SDL_egl.c in Sources */,
|
||||
A7D8AC3323E2514100DCD162 /* SDL_RLEaccel.c in Sources */,
|
||||
F3D8BDFD2D6D2C7000B22FA1 /* SDL_eventwatch.c in Sources */,
|
||||
F3EFA5F02D5AB97300BCF22F /* SDL_stb.c in Sources */,
|
||||
A7D8BBB123E2514500DCD162 /* SDL_assert.c in Sources */,
|
||||
A7D8B3DA23E2514300DCD162 /* SDL_bmp.c in Sources */,
|
||||
A7D8B96E23E2514400DCD162 /* SDL_stdlib.c in Sources */,
|
||||
@@ -3062,7 +3086,7 @@
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
DEPLOYMENT_POSTPROCESSING = YES;
|
||||
DYLIB_COMPATIBILITY_VERSION = 201.0.0;
|
||||
DYLIB_CURRENT_VERSION = 201.4.0;
|
||||
DYLIB_CURRENT_VERSION = 201.24.0;
|
||||
DYLIB_INSTALL_NAME_BASE = "@rpath";
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
GCC_ALTIVEC_EXTENSIONS = YES;
|
||||
@@ -3097,7 +3121,7 @@
|
||||
"@loader_path/Frameworks",
|
||||
);
|
||||
MACOSX_DEPLOYMENT_TARGET = 10.13;
|
||||
MARKETING_VERSION = 3.2.4;
|
||||
MARKETING_VERSION = 3.2.24;
|
||||
OTHER_LDFLAGS = "$(CONFIG_FRAMEWORK_LDFLAGS)";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = org.libsdl.SDL3;
|
||||
PRODUCT_NAME = SDL3;
|
||||
@@ -3126,7 +3150,7 @@
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
DYLIB_COMPATIBILITY_VERSION = 201.0.0;
|
||||
DYLIB_CURRENT_VERSION = 201.4.0;
|
||||
DYLIB_CURRENT_VERSION = 201.24.0;
|
||||
DYLIB_INSTALL_NAME_BASE = "@rpath";
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
ENABLE_TESTABILITY = YES;
|
||||
@@ -3158,7 +3182,7 @@
|
||||
"@loader_path/Frameworks",
|
||||
);
|
||||
MACOSX_DEPLOYMENT_TARGET = 10.13;
|
||||
MARKETING_VERSION = 3.2.4;
|
||||
MARKETING_VERSION = 3.2.24;
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
OTHER_LDFLAGS = "$(CONFIG_FRAMEWORK_LDFLAGS)";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = org.libsdl.SDL3;
|
||||
|
@@ -1,4 +1,4 @@
|
||||
Title SDL 3.2.4
|
||||
Title SDL 3.2.24
|
||||
Version 1
|
||||
Description SDL Library for macOS (http://www.libsdl.org)
|
||||
DefaultLocation /Library/Frameworks
|
||||
|
@@ -92,7 +92,7 @@ if(NOT TARGET SDL3::Headers)
|
||||
add_library(SDL3::Headers INTERFACE IMPORTED)
|
||||
set_target_properties(SDL3::Headers
|
||||
PROPERTIES
|
||||
INTERFACE_COMPILE_OPTIONS "SHELL:-F \"${_sdl3_framework_parent_path}\""
|
||||
INTERFACE_COMPILE_OPTIONS "-F${_sdl3_framework_parent_path}"
|
||||
)
|
||||
endif()
|
||||
set(SDL3_Headers_FOUND TRUE)
|
||||
|
@@ -167,6 +167,9 @@
|
||||
F399C6512A7892D800C86979 /* testautomation_intrinsics.c in Sources */ = {isa = PBXBuildFile; fileRef = F399C6502A7892D800C86979 /* testautomation_intrinsics.c */; };
|
||||
F399C6522A7892D800C86979 /* testautomation_intrinsics.c in Sources */ = {isa = PBXBuildFile; fileRef = F399C6502A7892D800C86979 /* testautomation_intrinsics.c */; };
|
||||
F399C6552A78933100C86979 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F399C6542A78933000C86979 /* Cocoa.framework */; };
|
||||
F3B7FD642D73FC630086D1D0 /* SDL3.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 003FA643093FFD41000C53B3 /* SDL3.framework */; };
|
||||
F3B7FD662D73FC630086D1D0 /* SDL3.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 003FA643093FFD41000C53B3 /* SDL3.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
|
||||
F3B7FD6C2D73FC9E0086D1D0 /* testpen.c in Sources */ = {isa = PBXBuildFile; fileRef = F3B7FD6B2D73FC9E0086D1D0 /* testpen.c */; };
|
||||
F3C17C7728E40BC800E1A26D /* testutils.c in Sources */ = {isa = PBXBuildFile; fileRef = F3C17C7328E40ADE00E1A26D /* testutils.c */; };
|
||||
F3C17C7928E40C6E00E1A26D /* testutils.c in Sources */ = {isa = PBXBuildFile; fileRef = F3C17C7328E40ADE00E1A26D /* testutils.c */; };
|
||||
F3C17C7B28E40D4E00E1A26D /* testutils.c in Sources */ = {isa = PBXBuildFile; fileRef = F3C17C7328E40ADE00E1A26D /* testutils.c */; };
|
||||
@@ -717,6 +720,17 @@
|
||||
name = "Embed Frameworks";
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
F3B7FD652D73FC630086D1D0 /* Embed Frameworks */ = {
|
||||
isa = PBXCopyFilesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
dstPath = "";
|
||||
dstSubfolderSpec = 10;
|
||||
files = (
|
||||
F3B7FD662D73FC630086D1D0 /* SDL3.framework in Embed Frameworks */,
|
||||
);
|
||||
name = "Embed Frameworks";
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
F3CB568B2A7895F800766177 /* Embed Frameworks */ = {
|
||||
isa = PBXCopyFilesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
@@ -1356,6 +1370,8 @@
|
||||
F399C6492A78929400C86979 /* gamepadutils.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = gamepadutils.c; sourceTree = "<group>"; };
|
||||
F399C6502A7892D800C86979 /* testautomation_intrinsics.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = testautomation_intrinsics.c; sourceTree = "<group>"; };
|
||||
F399C6542A78933000C86979 /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = System/Library/Frameworks/Cocoa.framework; sourceTree = SDKROOT; };
|
||||
F3B7FD6A2D73FC630086D1D0 /* testpen.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = testpen.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
F3B7FD6B2D73FC9E0086D1D0 /* testpen.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = testpen.c; sourceTree = "<group>"; };
|
||||
F3C17C6A28E3FD4400E1A26D /* config.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = config.xcconfig; sourceTree = "<group>"; };
|
||||
F3C17C7328E40ADE00E1A26D /* testutils.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = testutils.c; sourceTree = "<group>"; };
|
||||
F3C17CD628E416AC00E1A26D /* testgeometry.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = testgeometry.c; sourceTree = "<group>"; };
|
||||
@@ -1732,6 +1748,14 @@
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
F3B7FD632D73FC630086D1D0 /* Frameworks */ = {
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
F3B7FD642D73FC630086D1D0 /* SDL3.framework in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
F3C17CD928E416CF00E1A26D /* Frameworks */ = {
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
@@ -1789,6 +1813,7 @@
|
||||
083E4872006D84C97F000001 /* loopwave.c */,
|
||||
0017958F1074216E00F5D044 /* testatomic.c */,
|
||||
001795B01074222D00F5D044 /* testaudioinfo.c */,
|
||||
F35E56CC2983130F00A43A5F /* testautomation.c */,
|
||||
F35E56C42983130D00A43A5F /* testautomation_audio.c */,
|
||||
F35E56BC2983130B00A43A5F /* testautomation_clipboard.c */,
|
||||
F35E56BB2983130B00A43A5F /* testautomation_events.c */,
|
||||
@@ -1815,7 +1840,6 @@
|
||||
A1A8594B2BC72FC20045DD6C /* testautomation_time.c */,
|
||||
F35E56BD2983130B00A43A5F /* testautomation_timer.c */,
|
||||
F35E56C12983130C00A43A5F /* testautomation_video.c */,
|
||||
F35E56CC2983130F00A43A5F /* testautomation.c */,
|
||||
F36C342C2C0F869B00991150 /* testcamera.c */,
|
||||
BBFC088E164C6820003E6A99 /* testcontroller.c */,
|
||||
001797711074320D00F5D044 /* testdraw.c */,
|
||||
@@ -1837,11 +1861,12 @@
|
||||
092D6D75FFB313BB7F000001 /* testlock.c */,
|
||||
DB166CBD16A1C74100A1396C /* testmessage.c */,
|
||||
001798151074359B00F5D044 /* testmultiaudio.c */,
|
||||
0017985A107436ED00F5D044 /* testnative.c */,
|
||||
0017985B107436ED00F5D044 /* testnative.h */,
|
||||
0017985A107436ED00F5D044 /* testnative.c */,
|
||||
0017985C107436ED00F5D044 /* testnativecocoa.m */,
|
||||
00179872107438D000F5D044 /* testnativex11.c */,
|
||||
002F345209CA201C00EBEB88 /* testoverlay.c */,
|
||||
F3B7FD6B2D73FC9E0086D1D0 /* testpen.c */,
|
||||
002F346F09CA20A600EBEB88 /* testplatform.c */,
|
||||
001798B910743A4900F5D044 /* testpower.c */,
|
||||
DB166CBF16A1C74100A1396C /* testrelative.c */,
|
||||
@@ -1918,6 +1943,7 @@
|
||||
F3C17CDC28E416CF00E1A26D /* testgeometry.app */,
|
||||
F35E56AA298312CB00A43A5F /* testautomation.app */,
|
||||
F36C34272C0F85DB00991150 /* testcamera.app */,
|
||||
F3B7FD6A2D73FC630086D1D0 /* testpen.app */,
|
||||
);
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
@@ -2756,6 +2782,23 @@
|
||||
productReference = F36C34272C0F85DB00991150 /* testcamera.app */;
|
||||
productType = "com.apple.product-type.application";
|
||||
};
|
||||
F3B7FD602D73FC630086D1D0 /* testpen */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = F3B7FD672D73FC630086D1D0 /* Build configuration list for PBXNativeTarget "testpen" */;
|
||||
buildPhases = (
|
||||
F3B7FD612D73FC630086D1D0 /* Sources */,
|
||||
F3B7FD632D73FC630086D1D0 /* Frameworks */,
|
||||
F3B7FD652D73FC630086D1D0 /* Embed Frameworks */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
dependencies = (
|
||||
);
|
||||
name = testpen;
|
||||
productName = testalpha;
|
||||
productReference = F3B7FD6A2D73FC630086D1D0 /* testpen.app */;
|
||||
productType = "com.apple.product-type.application";
|
||||
};
|
||||
F3C17CDB28E416CF00E1A26D /* testgeometry */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = F3C17CE828E416D000E1A26D /* Build configuration list for PBXNativeTarget "testgeometry" */;
|
||||
@@ -2972,6 +3015,7 @@
|
||||
001798781074392D00F5D044 /* testnative */,
|
||||
002F343C09CA1FB300EBEB88 /* testoverlay */,
|
||||
002F345909CA204F00EBEB88 /* testplatform */,
|
||||
F3B7FD602D73FC630086D1D0 /* testpen */,
|
||||
0017989D107439DF00F5D044 /* testpower */,
|
||||
DB166DDC16A1D50C00A1396C /* testrelative */,
|
||||
DB166DF316A1D57C00A1396C /* testrendercopyex */,
|
||||
@@ -3455,6 +3499,14 @@
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
F3B7FD612D73FC630086D1D0 /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
F3B7FD6C2D73FC9E0086D1D0 /* testpen.c in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
F3C17CD828E416CF00E1A26D /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
@@ -4704,6 +4756,26 @@
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
F3B7FD682D73FC630086D1D0 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
F3B7FD692D73FC630086D1D0 /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
F3C17CE928E416D000E1A26D /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
@@ -5159,6 +5231,15 @@
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Debug;
|
||||
};
|
||||
F3B7FD672D73FC630086D1D0 /* Build configuration list for PBXNativeTarget "testpen" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
F3B7FD682D73FC630086D1D0 /* Debug */,
|
||||
F3B7FD692D73FC630086D1D0 /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Debug;
|
||||
};
|
||||
F3C17CE828E416D000E1A26D /* Build configuration list for PBXNativeTarget "testgeometry" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
|
@@ -5,7 +5,7 @@ plugins {
|
||||
def buildWithCMake = project.hasProperty('BUILD_WITH_CMAKE');
|
||||
|
||||
android {
|
||||
namespace "org.libsdl.app"
|
||||
namespace = "org.libsdl.app"
|
||||
compileSdkVersion 35
|
||||
defaultConfig {
|
||||
minSdkVersion 21
|
||||
@@ -14,12 +14,12 @@ android {
|
||||
versionName "1.0"
|
||||
externalNativeBuild {
|
||||
ndkBuild {
|
||||
arguments "APP_PLATFORM=android-19"
|
||||
arguments "APP_PLATFORM=android-21"
|
||||
// abiFilters 'armeabi-v7a', 'arm64-v8a', 'x86', 'x86_64'
|
||||
abiFilters 'arm64-v8a'
|
||||
}
|
||||
cmake {
|
||||
arguments "-DANDROID_PLATFORM=android-19", "-DANDROID_STL=c++_static"
|
||||
arguments "-DANDROID_PLATFORM=android-21", "-DANDROID_STL=c++_static"
|
||||
// abiFilters 'armeabi-v7a', 'arm64-v8a', 'x86', 'x86_64'
|
||||
abiFilters 'arm64-v8a'
|
||||
}
|
||||
@@ -53,7 +53,7 @@ android {
|
||||
|
||||
}
|
||||
lint {
|
||||
abortOnError false
|
||||
abortOnError = false
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -7,4 +7,4 @@
|
||||
APP_ABI := armeabi-v7a arm64-v8a x86 x86_64
|
||||
|
||||
# Min runtime API level
|
||||
APP_PLATFORM=android-16
|
||||
APP_PLATFORM=android-21
|
||||
|
2
android-project/app/proguard-rules.pro
vendored
2
android-project/app/proguard-rules.pro
vendored
@@ -51,6 +51,8 @@
|
||||
boolean supportsRelativeMouse();
|
||||
int openFileDescriptor(java.lang.String, java.lang.String);
|
||||
boolean showFileDialog(java.lang.String[], boolean, boolean, int);
|
||||
java.lang.String getPreferredLocales();
|
||||
java.lang.String formatLocale(java.util.Locale);
|
||||
}
|
||||
|
||||
-keep,includedescriptorclasses,allowoptimization class org.libsdl.app.HIDDeviceManager {
|
||||
|
@@ -23,6 +23,7 @@ import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.LocaleList;
|
||||
import android.os.Message;
|
||||
import android.os.ParcelFileDescriptor;
|
||||
import android.util.DisplayMetrics;
|
||||
@@ -60,7 +61,7 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh
|
||||
private static final String TAG = "SDL";
|
||||
private static final int SDL_MAJOR_VERSION = 3;
|
||||
private static final int SDL_MINOR_VERSION = 2;
|
||||
private static final int SDL_MICRO_VERSION = 4;
|
||||
private static final int SDL_MICRO_VERSION = 24;
|
||||
/*
|
||||
// Display InputType.SOURCE/CLASS of events and devices
|
||||
//
|
||||
@@ -2116,6 +2117,44 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh
|
||||
int requestCode;
|
||||
boolean multipleChoice;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is called by SDL using JNI.
|
||||
*/
|
||||
public static String getPreferredLocales() {
|
||||
String result = "";
|
||||
if (Build.VERSION.SDK_INT >= 24 /* Android 7 (N) */) {
|
||||
LocaleList locales = LocaleList.getAdjustedDefault();
|
||||
for (int i = 0; i < locales.size(); i++) {
|
||||
if (i != 0) result += ",";
|
||||
result += formatLocale(locales.get(i));
|
||||
}
|
||||
} else if (mCurrentLocale != null) {
|
||||
result = formatLocale(mCurrentLocale);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public static String formatLocale(Locale locale) {
|
||||
String result = "";
|
||||
String lang = "";
|
||||
if (locale.getLanguage() == "in") {
|
||||
// Indonesian is "id" according to ISO 639.2, but on Android is "in" because of Java backwards compatibility
|
||||
lang = "id";
|
||||
} else if (locale.getLanguage() == "") {
|
||||
// Make sure language is never empty
|
||||
lang = "und";
|
||||
} else {
|
||||
lang = locale.getLanguage();
|
||||
}
|
||||
|
||||
if (locale.getCountry() == "") {
|
||||
result = lang;
|
||||
} else {
|
||||
result = lang + "_" + locale.getCountry();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2157,7 +2196,11 @@ class SDLClipboardHandler implements
|
||||
}
|
||||
|
||||
public boolean clipboardHasText() {
|
||||
return mClipMgr.hasPrimaryClip();
|
||||
if (Build.VERSION.SDK_INT >= 28 /* Android 9 (P) */) {
|
||||
return mClipMgr.hasPrimaryClip();
|
||||
} else {
|
||||
return mClipMgr.hasText();
|
||||
}
|
||||
}
|
||||
|
||||
public String clipboardGetText() {
|
||||
@@ -2175,10 +2218,19 @@ class SDLClipboardHandler implements
|
||||
}
|
||||
|
||||
public void clipboardSetText(String string) {
|
||||
mClipMgr.removePrimaryClipChangedListener(this);
|
||||
ClipData clip = ClipData.newPlainText(null, string);
|
||||
mClipMgr.setPrimaryClip(clip);
|
||||
mClipMgr.addPrimaryClipChangedListener(this);
|
||||
mClipMgr.removePrimaryClipChangedListener(this);
|
||||
if (string.isEmpty()) {
|
||||
if (Build.VERSION.SDK_INT >= 28 /* Android 9 (P) */) {
|
||||
mClipMgr.clearPrimaryClip();
|
||||
} else {
|
||||
ClipData clip = ClipData.newPlainText(null, "");
|
||||
mClipMgr.setPrimaryClip(clip);
|
||||
}
|
||||
} else {
|
||||
ClipData clip = ClipData.newPlainText(null, string);
|
||||
mClipMgr.setPrimaryClip(clip);
|
||||
}
|
||||
mClipMgr.addPrimaryClipChangedListener(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@@ -276,7 +276,7 @@ public class SDLSurface extends SurfaceView implements SurfaceHolder.Callback,
|
||||
int buttonState = (event.getButtonState() >> 4) | (1 << (toolType == MotionEvent.TOOL_TYPE_STYLUS ? 0 : 30));
|
||||
|
||||
SDLActivity.onNativePen(pointerId, buttonState, action, x, y, p);
|
||||
} else if (toolType == MotionEvent.TOOL_TYPE_FINGER) {
|
||||
} else { // MotionEvent.TOOL_TYPE_FINGER or MotionEvent.TOOL_TYPE_UNKNOWN
|
||||
pointerId = event.getPointerId(i);
|
||||
x = getNormalizedX(event.getX(i));
|
||||
y = getNormalizedY(event.getY(i));
|
||||
|
@@ -542,6 +542,7 @@ class AndroidApiVersion:
|
||||
def __repr__(self) -> str:
|
||||
return f"<{self.name} ({'.'.join(str(v) for v in self.ints)})>"
|
||||
|
||||
ANDROID_ABI_EXTRA_LINK_OPTIONS = {}
|
||||
|
||||
class Releaser:
|
||||
def __init__(self, release_info: dict, commit: str, revision: str, root: Path, dist_path: Path, section_printer: SectionPrinter, executer: Executer, cmake_generator: str, deps_path: Path, overwrite: bool, github: bool, fast: bool):
|
||||
@@ -1013,6 +1014,7 @@ class Releaser:
|
||||
android_devel_file_tree = ArchiveFileTree()
|
||||
|
||||
for android_abi in android_abis:
|
||||
extra_link_options = ANDROID_ABI_EXTRA_LINK_OPTIONS.get(android_abi, "")
|
||||
with self.section_printer.group(f"Building for Android {android_api} {android_abi}"):
|
||||
build_dir = self.root / "build-android" / f"{android_abi}-build"
|
||||
install_dir = self.root / "install-android" / f"{android_abi}-install"
|
||||
@@ -1023,8 +1025,11 @@ class Releaser:
|
||||
"cmake",
|
||||
"-S", str(self.root),
|
||||
"-B", str(build_dir),
|
||||
f'''-DCMAKE_C_FLAGS="-ffile-prefix-map={self.root}=/src/{self.project}"''',
|
||||
f'''-DCMAKE_CXX_FLAGS="-ffile-prefix-map={self.root}=/src/{self.project}"''',
|
||||
# NDK 21e does not support -ffile-prefix-map
|
||||
# f'''-DCMAKE_C_FLAGS="-ffile-prefix-map={self.root}=/src/{self.project}"''',
|
||||
# f'''-DCMAKE_CXX_FLAGS="-ffile-prefix-map={self.root}=/src/{self.project}"''',
|
||||
f"-DCMAKE_EXE_LINKER_FLAGS={extra_link_options}",
|
||||
f"-DCMAKE_SHARED_LINKER_FLAGS={extra_link_options}",
|
||||
f"-DCMAKE_TOOLCHAIN_FILE={cmake_toolchain_file}",
|
||||
f"-DCMAKE_PREFIX_PATH={str(android_deps_path)}",
|
||||
f"-DCMAKE_FIND_ROOT_PATH_MODE_PACKAGE=BOTH",
|
||||
@@ -1530,7 +1535,7 @@ def main(argv=None) -> int:
|
||||
parser.error("Invalid --android-api, and/or could not be detected")
|
||||
android_api_path = Path(args.android_home) / f"platforms/{args.android_api.name}"
|
||||
if not android_api_path.is_dir():
|
||||
parser.error(f"Android API directory does not exist ({android_api_path})")
|
||||
logger.warning(f"Android API directory does not exist ({android_api_path})")
|
||||
with section_printer.group("Android arguments"):
|
||||
print(f"android_home = {args.android_home}")
|
||||
print(f"android_ndk_home = {args.android_ndk_home}")
|
||||
|
127
build-scripts/check_elf_alignment.sh
Executable file
127
build-scripts/check_elf_alignment.sh
Executable file
@@ -0,0 +1,127 @@
|
||||
#!/bin/bash
|
||||
progname="${0##*/}"
|
||||
progname="${progname%.sh}"
|
||||
|
||||
# usage: check_elf_alignment.sh [path to *.so files|path to *.apk]
|
||||
|
||||
cleanup_trap() {
|
||||
if [ -n "${tmp}" -a -d "${tmp}" ]; then
|
||||
rm -rf ${tmp}
|
||||
fi
|
||||
exit $1
|
||||
}
|
||||
|
||||
usage() {
|
||||
echo "Host side script to check the ELF alignment of shared libraries."
|
||||
echo "Shared libraries are reported ALIGNED when their ELF regions are"
|
||||
echo "16 KB or 64 KB aligned. Otherwise they are reported as UNALIGNED."
|
||||
echo
|
||||
echo "Usage: ${progname} [input-path|input-APK|input-APEX]"
|
||||
}
|
||||
|
||||
if [ ${#} -ne 1 ]; then
|
||||
usage
|
||||
exit
|
||||
fi
|
||||
|
||||
case ${1} in
|
||||
--help | -h | -\?)
|
||||
usage
|
||||
exit
|
||||
;;
|
||||
|
||||
*)
|
||||
dir="${1}"
|
||||
;;
|
||||
esac
|
||||
|
||||
if ! [ -f "${dir}" -o -d "${dir}" ]; then
|
||||
echo "Invalid file: ${dir}" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ "${dir}" == *.apk ]]; then
|
||||
trap 'cleanup_trap' EXIT
|
||||
|
||||
echo
|
||||
echo "Recursively analyzing $dir"
|
||||
echo
|
||||
|
||||
if { zipalign --help 2>&1 | grep -q "\-P <pagesize_kb>"; }; then
|
||||
echo "=== APK zip-alignment ==="
|
||||
zipalign -v -c -P 16 4 "${dir}" | egrep 'lib/arm64-v8a|lib/x86_64|Verification'
|
||||
echo "========================="
|
||||
else
|
||||
echo "NOTICE: Zip alignment check requires build-tools version 35.0.0-rc3 or higher."
|
||||
echo " You can install the latest build-tools by running the below command"
|
||||
echo " and updating your \$PATH:"
|
||||
echo
|
||||
echo " sdkmanager \"build-tools;35.0.0-rc3\""
|
||||
fi
|
||||
|
||||
dir_filename=$(basename "${dir}")
|
||||
tmp=$(mktemp -d -t "${dir_filename%.apk}_out_XXXXX")
|
||||
unzip "${dir}" lib/* -d "${tmp}" >/dev/null 2>&1
|
||||
dir="${tmp}"
|
||||
fi
|
||||
|
||||
if [[ "${dir}" == *.apex ]]; then
|
||||
trap 'cleanup_trap' EXIT
|
||||
|
||||
echo
|
||||
echo "Recursively analyzing $dir"
|
||||
echo
|
||||
|
||||
dir_filename=$(basename "${dir}")
|
||||
tmp=$(mktemp -d -t "${dir_filename%.apex}_out_XXXXX")
|
||||
deapexer extract "${dir}" "${tmp}" || { echo "Failed to deapex." && exit 1; }
|
||||
dir="${tmp}"
|
||||
fi
|
||||
|
||||
RED="\e[31m"
|
||||
GREEN="\e[32m"
|
||||
ENDCOLOR="\e[0m"
|
||||
|
||||
unaligned_libs=()
|
||||
unaligned_critical_libs=()
|
||||
|
||||
echo
|
||||
echo "=== ELF alignment ==="
|
||||
|
||||
matches="$(find "${dir}" -type f)"
|
||||
IFS=$'\n'
|
||||
for match in $matches; do
|
||||
# We could recursively call this script or rewrite it to though.
|
||||
[[ "${match}" == *".apk" ]] && echo "WARNING: doesn't recursively inspect .apk file: ${match}"
|
||||
[[ "${match}" == *".apex" ]] && echo "WARNING: doesn't recursively inspect .apex file: ${match}"
|
||||
|
||||
[[ $(file "${match}") == *"ELF"* ]] || continue
|
||||
|
||||
res="$(objdump -p "${match}" | grep LOAD | awk '{ print $NF }' | head -1)"
|
||||
if [[ $res =~ 2\*\*(1[4-9]|[2-9][0-9]|[1-9][0-9]{2,}) ]]; then
|
||||
echo -e "${match}: ${GREEN}ALIGNED${ENDCOLOR} ($res)"
|
||||
else
|
||||
unaligned_libs+=("${match}")
|
||||
# Check if this is a critical architecture (arm64-v8a or x86_64)
|
||||
if [[ "${match}" == *"arm64-v8a"* ]] || [[ "${match}" == *"x86_64"* ]]; then
|
||||
unaligned_critical_libs+=("${match}")
|
||||
echo -e "${match}: ${RED}UNALIGNED${ENDCOLOR} ($res)"
|
||||
else
|
||||
echo -e "${match}: UNALIGNED ($res)"
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
if [ ${#unaligned_libs[@]} -gt 0 ]; then
|
||||
echo -e "Found ${#unaligned_libs[@]} unaligned libs (only arm64-v8a/x86_64 libs need to be aligned).${ENDCOLOR}"
|
||||
fi
|
||||
echo "====================="
|
||||
|
||||
# Exit with appropriate code: 1 if critical unaligned libs found, 0 otherwise
|
||||
if [ ${#unaligned_critical_libs[@]} -gt 0 ]; then
|
||||
echo -e "${RED}Found ${#unaligned_critical_libs[@]} critical unaligned libs.${ENDCOLOR}"
|
||||
exit 1
|
||||
else
|
||||
echo -e "${GREEN}ELF Verification Successful${ENDCOLOR}"
|
||||
exit 0
|
||||
fi
|
@@ -161,6 +161,7 @@ def find_symbols_in_file(file: pathlib.Path) -> int:
|
||||
"src/libm",
|
||||
"src/hidapi",
|
||||
"src/video/khronos",
|
||||
"src/video/stb_image.h",
|
||||
"include/SDL3",
|
||||
"build-scripts/gen_audio_resampler_filter.c",
|
||||
"build-scripts/gen_audio_channel_conversion.c",
|
||||
|
@@ -183,7 +183,7 @@
|
||||
],
|
||||
"api-minimum": 21,
|
||||
"api-target": 35,
|
||||
"ndk-minimum": 21,
|
||||
"ndk-minimum": 28,
|
||||
"aar-files": {
|
||||
"": [
|
||||
"android-project/app/proguard-rules.pro:proguard.txt",
|
||||
|
@@ -1,21 +0,0 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# libtool assumes that the compiler can handle the -fPIC flag
|
||||
# This isn't always true (for example, nasm can't handle it)
|
||||
command=""
|
||||
while [ $# -gt 0 ]; do
|
||||
case "$1" in
|
||||
-?PIC)
|
||||
# Ignore -fPIC and -DPIC options
|
||||
;;
|
||||
-fno-common)
|
||||
# Ignore -fPIC and -DPIC options
|
||||
;;
|
||||
*)
|
||||
command="$command $1"
|
||||
;;
|
||||
esac
|
||||
shift
|
||||
done
|
||||
echo $command
|
||||
exec $command
|
@@ -424,7 +424,11 @@ sub dewikify_chunk {
|
||||
$str .= "\n```$codelang\n$code\n```\n";
|
||||
}
|
||||
} elsif ($dewikify_mode eq 'manpage') {
|
||||
$str =~ s/\./\\[char46]/gms; # make sure these can't become control codes.
|
||||
# make sure these can't become part of roff syntax.
|
||||
$str =~ s/\./\\[char46]/gms;
|
||||
$str =~ s/"/\\(dq/gms;
|
||||
$str =~ s/'/\\(aq/gms;
|
||||
|
||||
if ($wikitype eq 'mediawiki') {
|
||||
# Dump obvious wikilinks.
|
||||
if (defined $apiprefixregex) {
|
||||
@@ -449,33 +453,52 @@ sub dewikify_chunk {
|
||||
# bullets
|
||||
$str =~ s/^\* /\n\\\(bu /gm;
|
||||
} elsif ($wikitype eq 'md') {
|
||||
# bullets
|
||||
$str =~ s/^\- /\n\\(bu /gm;
|
||||
# merge paragraphs
|
||||
$str =~ s/^[ \t]+//gm;
|
||||
$str =~ s/([^\-\n])\n([^\-\n])/$1 $2/g;
|
||||
$str =~ s/\n\n/\n.PP\n/g;
|
||||
|
||||
# Dump obvious wikilinks.
|
||||
if (defined $apiprefixregex) {
|
||||
$str =~ s/\[(\`?$apiprefixregex[a-zA-Z0-9_]+\`?)\]\($apiprefixregex[a-zA-Z0-9_]+\)/\n.BR $1\n/gms;
|
||||
my $apr = $apiprefixregex;
|
||||
if(!($apr =~ /\A\(.*\)\Z/s)) {
|
||||
# we're relying on the apiprefixregex having a capturing group.
|
||||
$apr = "(" . $apr . ")";
|
||||
}
|
||||
$str =~ s/(\S*?)\[\`?($apr[a-zA-Z0-9_]+)\`?\]\($apr[a-zA-Z0-9_]+\)(\S*)\s*/\n.BR "" "$1" "$2" "$5"\n/gm;
|
||||
# handle cases like "[x](x), [y](y), [z](z)" being separated.
|
||||
while($str =~ s/(\.BR[^\n]*)\n\n\.BR/$1\n.BR/gm) {}
|
||||
}
|
||||
|
||||
# links
|
||||
$str =~ s/\[(.*?)]\((https?\:\/\/.*?)\)/\n.URL "$2" "$1"\n/g;
|
||||
|
||||
# <code></code> is also popular. :/
|
||||
$str =~ s/\s*\`(.*?)\`\s*/\n.BR $1\n/gms;
|
||||
$str =~ s/\s*(\S*?)\`([^\n]*?)\`(\S*)\s*/\n.BR "" "$1" "$2" "$3"\n/gms;
|
||||
|
||||
# bold+italic (this looks bad, just make it bold).
|
||||
$str =~ s/\s*\*\*\*(.*?)\*\*\*\s*/\n.B $1\n/gms;
|
||||
$str =~ s/\s*(\S*?)\*\*\*([^\n]*?)\*\*\*(\S*)\s*/\n.BR "" "$1" "$2" "$3"\n/gms;
|
||||
|
||||
# bold
|
||||
$str =~ s/\s*\*\*(.*?)\*\*\s*/\n.B $1\n/gms;
|
||||
$str =~ s/\s*(\S*?)\*\*([^\n]*?)\*\*(\S*)\s*/\n.BR "" "$1" "$2" "$3"\n/gms;
|
||||
|
||||
# italic
|
||||
$str =~ s/\s*\*(.*?)\*\s*/\n.I $1\n/gms;
|
||||
|
||||
# bullets
|
||||
$str =~ s/^\- /\n\\\(bu /gm;
|
||||
$str =~ s/\s*(\S*?)\*([^\n]*?)\*(\S*)\s*/\n.IR "" "$1" "$2" "$3"\n/gms;
|
||||
}
|
||||
|
||||
# cleanup unnecessary quotes
|
||||
$str =~ s/(\.[IB]R?)(.*?) ""\n/$1$2\n/gm;
|
||||
$str =~ s/(\.[IB]R?) "" ""(.*?)\n/$1$2\n/gm;
|
||||
$str =~ s/"(\S+)"/$1/gm;
|
||||
# cleanup unnecessary whitespace
|
||||
$str =~ s/ +\n/\n/gm;
|
||||
|
||||
if (defined $code) {
|
||||
$code =~ s/\A\n+//gms;
|
||||
$code =~ s/\n+\Z//gms;
|
||||
$code =~ s/\\/\\(rs/gms;
|
||||
if ($dewikify_manpage_code_indent) {
|
||||
$str .= "\n.IP\n"
|
||||
} else {
|
||||
@@ -580,7 +603,7 @@ sub dewikify {
|
||||
$retval .= dewikify_chunk($wikitype, $1, $2, $3);
|
||||
}
|
||||
} elsif ($wikitype eq 'md') {
|
||||
while ($str =~ s/\A(.*?)\n```(.*?)\n(.*?)\n```\n//ms) {
|
||||
while ($str =~ s/\A(.*?)\n?```(.*?)\n(.*?)\n```\n//ms) {
|
||||
$retval .= dewikify_chunk($wikitype, $1, $2, $3);
|
||||
}
|
||||
}
|
||||
@@ -2765,7 +2788,6 @@ __EOF__
|
||||
my $wikitype = $wikitypes{$sym};
|
||||
my $sectionsref = $wikisyms{$sym};
|
||||
my $remarks = $sectionsref->{'Remarks'};
|
||||
my $params = $sectionsref->{'Function Parameters'};
|
||||
my $returns = $sectionsref->{'Return Value'};
|
||||
my $version = $sectionsref->{'Version'};
|
||||
my $threadsafety = $sectionsref->{'Thread Safety'};
|
||||
@@ -2773,6 +2795,23 @@ __EOF__
|
||||
my $examples = $sectionsref->{'Code Examples'};
|
||||
my $deprecated = $sectionsref->{'Deprecated'};
|
||||
my $headerfile = $manpageheaderfiletext;
|
||||
|
||||
my $params = undef;
|
||||
|
||||
if ($symtype == -1) { # category documentation block.
|
||||
# nothing to be done here.
|
||||
} elsif (($symtype == 1) || (($symtype == 5))) { # we'll assume a typedef (5) with a \param is a function pointer typedef.
|
||||
$params = $sectionsref->{'Function Parameters'};
|
||||
} elsif ($symtype == 2) {
|
||||
$params = $sectionsref->{'Macro Parameters'};
|
||||
} elsif ($symtype == 3) {
|
||||
$params = $sectionsref->{'Fields'};
|
||||
} elsif ($symtype == 4) {
|
||||
$params = $sectionsref->{'Values'};
|
||||
} else {
|
||||
die("Unexpected symtype $symtype");
|
||||
}
|
||||
|
||||
$headerfile =~ s/\%fname\%/$headersymslocation{$sym}/g;
|
||||
$headerfile .= "\n";
|
||||
|
||||
@@ -2839,18 +2878,22 @@ __EOF__
|
||||
$str .= dewikify($wikitype, $deprecated) . "\n";
|
||||
}
|
||||
|
||||
my $incfile = $mainincludefname;
|
||||
if (defined $headerfile) {
|
||||
$str .= ".SH HEADER FILE\n";
|
||||
$str .= dewikify($wikitype, $headerfile) . "\n";
|
||||
if($headerfile =~ /Defined in (.*)/) {
|
||||
$incfile = $1;
|
||||
}
|
||||
}
|
||||
|
||||
$str .= ".SH SYNOPSIS\n";
|
||||
$str .= ".nf\n";
|
||||
$str .= ".B #include \\(dq$mainincludefname\\(dq\n";
|
||||
$str .= ".B #include <$incfile>\n";
|
||||
$str .= ".PP\n";
|
||||
|
||||
my @decllines = split /\n/, $decl;
|
||||
foreach (@decllines) {
|
||||
$_ =~ s/\\/\\(rs/g; # fix multiline macro defs
|
||||
$_ =~ s/"/\\(dq/g;
|
||||
$str .= ".BI \"$_\n";
|
||||
}
|
||||
$str .= ".fi\n";
|
||||
@@ -2938,8 +2981,11 @@ __EOF__
|
||||
}
|
||||
|
||||
if (defined $returns) {
|
||||
# Chop datatype in parentheses off the front.
|
||||
if(!($returns =~ s/\A\([^\[]*\[[^\]]*\]\([^\)]*\)[^\)]*\) //ms)) {
|
||||
$returns =~ s/\A\([^\)]*\) //ms;
|
||||
}
|
||||
$returns = dewikify($wikitype, $returns);
|
||||
$returns =~ s/\A\(.*?\)\s*//; # Chop datatype in parentheses off the front.
|
||||
$str .= ".SH RETURN VALUE\n";
|
||||
$str .= "$returns\n";
|
||||
}
|
||||
@@ -2975,6 +3021,8 @@ __EOF__
|
||||
s/\A\/*//;
|
||||
s/\A\.BR\s+//; # dewikify added this, but we want to handle it.
|
||||
s/\A\.I\s+//; # dewikify added this, but we want to handle it.
|
||||
s/\A\.PP\s*//; # dewikify added this, but we want to handle it.
|
||||
s/\\\(bu//; # dewikify added this, but we want to handle it.
|
||||
s/\A\s*[\:\*\-]\s*//;
|
||||
s/\A\s+//;
|
||||
s/\s+\Z//;
|
||||
|
@@ -77,6 +77,9 @@ else()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(NOT SDL3_COMPONENTS AND NOT TARGET SDL3::Headers AND NOT TARGET SDL3::SDL3-shared AND NOT TARGET SDL3::SDL3-static)
|
||||
set(SDL3_FOUND FALSE)
|
||||
endif()
|
||||
check_required_components(SDL3)
|
||||
|
||||
function(_sdl_create_target_alias_compat NEW_TARGET TARGET)
|
||||
@@ -93,7 +96,7 @@ endfunction()
|
||||
if(NOT TARGET SDL3::SDL3)
|
||||
if(TARGET SDL3::SDL3-shared)
|
||||
_sdl_create_target_alias_compat(SDL3::SDL3 SDL3::SDL3-shared)
|
||||
else()
|
||||
elseif(TARGET SDL3::SDL3-static)
|
||||
_sdl_create_target_alias_compat(SDL3::SDL3 SDL3::SDL3-static)
|
||||
endif()
|
||||
endif()
|
||||
|
@@ -823,7 +823,7 @@ macro(CheckPTHREAD)
|
||||
if(CMAKE_C_COMPILER_ID MATCHES "SunPro")
|
||||
set(PTHREAD_LDFLAGS "-mt -lpthread")
|
||||
else()
|
||||
set(PTHREAD_LDFLAGS "-pthread -lposix4")
|
||||
set(PTHREAD_LDFLAGS "-pthread")
|
||||
endif()
|
||||
elseif(SYSV5)
|
||||
set(PTHREAD_CFLAGS "-D_REENTRANT -Kthread")
|
||||
@@ -1077,6 +1077,14 @@ endmacro()
|
||||
|
||||
# Check for HIDAPI support
|
||||
macro(CheckHIDAPI)
|
||||
if(ANDROID)
|
||||
enable_language(CXX)
|
||||
sdl_sources("${SDL3_SOURCE_DIR}/src/hidapi/android/hid.cpp")
|
||||
endif()
|
||||
if(IOS OR TVOS)
|
||||
sdl_sources("${SDL3_SOURCE_DIR}/src/hidapi/ios/hid.m")
|
||||
set(SDL_FRAMEWORK_COREBLUETOOTH 1)
|
||||
endif()
|
||||
if(SDL_HIDAPI)
|
||||
set(HAVE_HIDAPI ON)
|
||||
if(SDL_HIDAPI_LIBUSB)
|
||||
@@ -1109,14 +1117,6 @@ macro(CheckHIDAPI)
|
||||
endif()
|
||||
|
||||
if(HAVE_HIDAPI)
|
||||
if(ANDROID)
|
||||
enable_language(CXX)
|
||||
sdl_sources("${SDL3_SOURCE_DIR}/src/hidapi/android/hid.cpp")
|
||||
endif()
|
||||
if(IOS OR TVOS)
|
||||
sdl_sources("${SDL3_SOURCE_DIR}/src/hidapi/ios/hid.m")
|
||||
set(SDL_FRAMEWORK_COREBLUETOOTH 1)
|
||||
endif()
|
||||
set(HAVE_SDL_HIDAPI TRUE)
|
||||
|
||||
if(SDL_JOYSTICK AND SDL_HIDAPI_JOYSTICK)
|
||||
|
@@ -160,3 +160,63 @@ function(SDL_AddCommonCompilerFlags TARGET)
|
||||
endif()
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
function(check_x86_source_compiles BODY VAR)
|
||||
if(ARGN)
|
||||
message(FATAL_ERROR "Unknown arguments: ${ARGN}")
|
||||
endif()
|
||||
if(APPLE_MULTIARCH AND (SDL_CPU_X86 OR SDL_CPU_X64))
|
||||
set(test_conditional 1)
|
||||
else()
|
||||
set(test_conditional 0)
|
||||
endif()
|
||||
check_c_source_compiles("
|
||||
#if ${test_conditional}
|
||||
# if defined(__i386__) || defined(__x86_64__)
|
||||
# define test_enabled 1
|
||||
# else
|
||||
# define test_enabled 0 /* feign success in Apple multi-arch configs */
|
||||
# endif
|
||||
#else /* test normally */
|
||||
# define test_enabled 1
|
||||
#endif
|
||||
#if test_enabled
|
||||
${BODY}
|
||||
#else
|
||||
int main(int argc, char *argv[]) {
|
||||
(void)argc;
|
||||
(void)argv;
|
||||
return 0;
|
||||
}
|
||||
#endif" ${VAR})
|
||||
endfunction()
|
||||
|
||||
function(check_arm_source_compiles BODY VAR)
|
||||
if(ARGN)
|
||||
message(FATAL_ERROR "Unknown arguments: ${ARGN}")
|
||||
endif()
|
||||
if(APPLE_MULTIARCH AND (SDL_CPU_ARM32 OR SDL_CPU_ARM64))
|
||||
set(test_conditional 1)
|
||||
else()
|
||||
set(test_conditional 0)
|
||||
endif()
|
||||
check_c_source_compiles("
|
||||
#if ${test_conditional}
|
||||
# if defined(__arm__) || defined(__aarch64__)
|
||||
# define test_enabled 1
|
||||
# else
|
||||
# define test_enabled 0 /* feign success in Apple multi-arch configs */
|
||||
# endif
|
||||
#else /* test normally */
|
||||
# define test_enabled 1
|
||||
#endif
|
||||
#if test_enabled
|
||||
${BODY}
|
||||
#else
|
||||
int main(int argc, char *argv[]) {
|
||||
(void)argc;
|
||||
(void)argv;
|
||||
return 0;
|
||||
}
|
||||
#endif" ${VAR})
|
||||
endfunction()
|
||||
|
@@ -4,15 +4,15 @@ function(SDL_DetectTargetCPUArchitectures DETECTED_ARCHS)
|
||||
|
||||
if(APPLE AND CMAKE_OSX_ARCHITECTURES)
|
||||
foreach(known_arch IN LISTS known_archs)
|
||||
set(SDL_CPU_${known_arch} "0")
|
||||
set(SDL_CPU_${known_arch} "0" PARENT_SCOPE)
|
||||
endforeach()
|
||||
set(detected_archs)
|
||||
foreach(osx_arch IN LISTS CMAKE_OSX_ARCHITECTURES)
|
||||
if(osx_arch STREQUAL "x86_64")
|
||||
set(SDL_CPU_X64 "1")
|
||||
set(SDL_CPU_X64 "1" PARENT_SCOPE)
|
||||
list(APPEND detected_archs "X64")
|
||||
elseif(osx_arch STREQUAL "arm64")
|
||||
set(SDL_CPU_ARM64 "1")
|
||||
set(SDL_CPU_ARM64 "1" PARENT_SCOPE)
|
||||
list(APPEND detected_archs "ARM64")
|
||||
endif()
|
||||
endforeach()
|
||||
|
@@ -5,7 +5,12 @@ The easiest way to use SDL is to include it as a subproject in your project.
|
||||
|
||||
We'll start by creating a simple project to build and run [hello.c](hello.c)
|
||||
|
||||
Create the file CMakeLists.txt
|
||||
# Get a copy of the SDL source:
|
||||
```sh
|
||||
git clone https://github.com/libsdl-org/SDL.git vendored/SDL
|
||||
```
|
||||
|
||||
# Create the file CMakeLists.txt
|
||||
```cmake
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
project(hello)
|
||||
@@ -25,24 +30,26 @@ add_executable(hello WIN32 hello.c)
|
||||
target_link_libraries(hello PRIVATE SDL3::SDL3)
|
||||
```
|
||||
|
||||
Build:
|
||||
# Configure and Build:
|
||||
```sh
|
||||
cmake -S . -B build
|
||||
cmake --build build
|
||||
```
|
||||
|
||||
Run:
|
||||
- On Windows the executable is in the build Debug directory:
|
||||
```sh
|
||||
cd build/Debug
|
||||
./hello
|
||||
```
|
||||
- On other platforms the executable is in the build directory:
|
||||
# Run:
|
||||
The executable should be in the `build` directory:
|
||||
|
||||
```sh
|
||||
cd build
|
||||
./hello
|
||||
```
|
||||
|
||||
If there wasn't an executable there despite the above Build section running successfully, it's likely because you're following this guide using the Visual Studio toolchain, it should instead be in the `build/Debug` directory:
|
||||
```sh
|
||||
cd build/Debug
|
||||
./hello
|
||||
```
|
||||
|
||||
A more complete example is available at:
|
||||
|
||||
https://github.com/Ravbug/sdl3-sample
|
||||
|
95
docs/INTRO-mingw.md
Normal file
95
docs/INTRO-mingw.md
Normal file
@@ -0,0 +1,95 @@
|
||||
# Introduction to SDL with MinGW
|
||||
|
||||
Without getting deep into the history, MinGW is a long running project that aims to bring gcc to Windows. That said, there's many distributions, versions, and forks floating around. We recommend installing [MSYS2](https://www.msys2.org/), as it's the easiest way to get a modern toolchain with a package manager to help with dependency management. This would allow you to follow the MSYS2 section below.
|
||||
|
||||
Otherwise you'll want to follow the "Other Distributions" section below.
|
||||
|
||||
We'll start by creating a simple project to build and run [hello.c](hello.c).
|
||||
|
||||
# MSYS2
|
||||
|
||||
Open the `MSYS2 UCRT64` prompt and then ensure you've installed the following packages. This will get you working toolchain, CMake, Ninja, and of course SDL3.
|
||||
|
||||
```sh
|
||||
pacman -S mingw-w64-ucrt-x86_64-gcc mingw-w64-ucrt-x86_64-ninja mingw-w64-ucrt-x86_64-cmake mingw-w64-ucrt-x86_64-sdl3
|
||||
```
|
||||
|
||||
## Create the file CMakeLists.txt
|
||||
```cmake
|
||||
cmake_minimum_required(VERSION 3.26)
|
||||
project(hello C CXX)
|
||||
|
||||
find_package(SDL3 REQUIRED)
|
||||
|
||||
add_executable(hello)
|
||||
|
||||
target_sources(hello
|
||||
PRIVATE
|
||||
hello.c
|
||||
)
|
||||
|
||||
target_link_libraries(hello SDL3::SDL3)
|
||||
```
|
||||
|
||||
## Configure and Build:
|
||||
```sh
|
||||
cmake -S . -B build
|
||||
cmake --build build
|
||||
```
|
||||
|
||||
## Run:
|
||||
|
||||
The executable is in the `build` directory:
|
||||
```sh
|
||||
cd build
|
||||
./hello
|
||||
```
|
||||
|
||||
# Other Distributions
|
||||
|
||||
Things can get quite complicated with other distributions of MinGW. If you can't follow [the cmake intro](INTRO-cmake.md), perhaps due to issues getting cmake to understand your toolchain, this section should work.
|
||||
|
||||
## Acquire SDL
|
||||
|
||||
Download the `SDL3-devel-<version>-mingw.zip` asset from [the latest release.](https://github.com/libsdl-org/SDL/releases/latest) Then extract it inside your project folder such that the output of `ls SDL3-<version>` looks like `INSTALL.md LICENSE.txt Makefile README.md cmake i686-w64-mingw32 x86_64-w64-mingw32`.
|
||||
|
||||
## Know your Target Architecture
|
||||
|
||||
It is not uncommon for folks to not realize their distribution is targeting 32bit Windows despite things like the name of the toolchain, or the fact that they're running on a 64bit system. We'll ensure we know up front what we need:
|
||||
|
||||
Create a file named `arch.c` with the following contents:
|
||||
```c
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
int main() {
|
||||
#if defined(__x86_64__) || defined(_M_X64) || defined(i386) || defined(__i386__) || defined(__i386) || defined(_M_IX86)
|
||||
size_t ptr_size = sizeof(int*);
|
||||
if (4 == ptr_size) puts("i686-w64-mingw32");
|
||||
else if (8 == ptr_size) puts("x86_64-w64-mingw32");
|
||||
else puts("Unknown Architecture");
|
||||
#else
|
||||
puts("Unknown Architecture");
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
Then run
|
||||
|
||||
```sh
|
||||
gcc arch.c
|
||||
./a.exe
|
||||
```
|
||||
|
||||
This should print out which library directory we'll need to use when compiling, keep this value in mind, you'll need to use it when compiling in the next section as `<arch>`. If you get "Unknown Architecture" please [report a bug](https://github.com/libsdl-org/SDL/issues).
|
||||
|
||||
|
||||
## Build and Run
|
||||
|
||||
Now we should have everything needed to compile and run our program. You'll need to ensure to replace `<version>` with the version of the release of SDL3 you downloaded, as well as use the `<arch>` we learned in the previous section.
|
||||
|
||||
```sh
|
||||
gcc hello.c -o hello.exe -I SDL3-<version>/<arch>/include -L SDL3-<version>/<arch>/lib -lSDL3 -mwindows
|
||||
cp SDL3-<version>/<arch>/bin/SDL3.dll SDL3.dll
|
||||
./hello.exe
|
||||
```
|
@@ -5,10 +5,12 @@ The easiest way to use SDL is to include it as a subproject in your project.
|
||||
|
||||
We'll start by creating a simple project to build and run [hello.c](hello.c)
|
||||
|
||||
- Get a copy of the SDL source, you can clone the repo, or download the "Source Code" asset from [the latest release.](https://github.com/libsdl-org/SDL/releases/latest)
|
||||
- If you've downloaded a release, make sure to extract the contents somewhere you can find it.
|
||||
- Create a new project in Visual Studio, using the C++ Empty Project template
|
||||
- Add hello.c to the Source Files
|
||||
- Right click the solution, select add an existing project, navigate to VisualC/SDL and add SDL.vcxproj
|
||||
- Select your main project and go to Project -> Add Reference and select SDL3
|
||||
- Select your main project and go to Project -> Properties, set the filter at the top to "All Configurations" and "All Platforms", select VC++ Directories and add the SDL include directory to "Include Directories"
|
||||
- Right click the solution, select add an existing project, navigate to `VisualC/SDL` from within the source you cloned or downloaded above and add SDL.vcxproj
|
||||
- Select your main project and go to Project -> Add -> Reference and select SDL3
|
||||
- Select your main project and go to Project -> Properties, set the filter at the top to "All Configurations" and "All Platforms", select C/C++ -> General and add the SDL include directory to "Additional Include Directories"
|
||||
- Build and run!
|
||||
|
||||
|
@@ -242,7 +242,7 @@ not give you any processing time after the events are delivered.
|
||||
|
||||
e.g.
|
||||
|
||||
int HandleAppEvents(void *userdata, SDL_Event *event)
|
||||
bool HandleAppEvents(void *userdata, SDL_Event *event)
|
||||
{
|
||||
switch (event->type)
|
||||
{
|
||||
@@ -250,12 +250,12 @@ e.g.
|
||||
/* Terminate the app.
|
||||
Shut everything down before returning from this function.
|
||||
*/
|
||||
return 0;
|
||||
return false;
|
||||
case SDL_EVENT_LOW_MEMORY:
|
||||
/* You will get this when your app is paused and iOS wants more memory.
|
||||
Release as much memory as possible.
|
||||
*/
|
||||
return 0;
|
||||
return false;
|
||||
case SDL_EVENT_WILL_ENTER_BACKGROUND:
|
||||
/* Prepare your app to go into the background. Stop loops, etc.
|
||||
This gets called when the user hits the home button, or gets a call.
|
||||
@@ -264,15 +264,15 @@ e.g.
|
||||
in addition, you should set the render target to NULL, if you're using
|
||||
it, e.g. call SDL_SetRenderTarget(renderer, NULL).
|
||||
*/
|
||||
return 0;
|
||||
return false;
|
||||
case SDL_EVENT_DID_ENTER_BACKGROUND:
|
||||
/* Your app is NOT active at this point. */
|
||||
return 0;
|
||||
return false;
|
||||
case SDL_EVENT_WILL_ENTER_FOREGROUND:
|
||||
/* This call happens when your app is coming back to the foreground.
|
||||
Restore all your state here.
|
||||
*/
|
||||
return 0;
|
||||
return false;
|
||||
case SDL_EVENT_DID_ENTER_FOREGROUND:
|
||||
/* Restart your loops here.
|
||||
Your app is interactive and getting CPU again.
|
||||
@@ -283,10 +283,10 @@ e.g.
|
||||
event SDL_EVENT_RENDER_DEVICE_RESET and recreate your OpenGL context and
|
||||
restore your textures when you get it, or quit the app.
|
||||
*/
|
||||
return 0;
|
||||
return false;
|
||||
default:
|
||||
/* No special processing, add it to the event queue */
|
||||
return 1;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -1,32 +1,6 @@
|
||||
|
||||
SDL 3.0 has new support for high DPI displays. Interfaces provided by SDL uses the platform's native coordinates unless otherwise specified.
|
||||
|
||||
To reconcile platform differences in their approach to high-density scaling, SDL provides the following interfaces:
|
||||
- `SDL_GetWindowSize()` retrieves the window dimensions in native coordinates.
|
||||
- `SDL_GetWindowSizeInPixels()` retrieves the window dimensions in pixels-addressable.
|
||||
- `SDL_GetDisplayContentScale()` retrieves the suggested amplification factor when drawing in native coordinates.
|
||||
- `SDL_GetWindowDisplayScale()` retrieves the suggested amplification factor when drawing in pixels-addressable.
|
||||
- `SDL_GetWindowPixelDensity()` retrieves how many addressable pixels correspond to one unit of native coordinates.
|
||||
- `SDL_EVENT_WINDOW_PIXEL_SIZE_CHANGED` is emitted when the value retrievable from `SDL_GetWindowSizeInPixels()` changes.
|
||||
- `SDL_EVENT_WINDOW_DISPLAY_SCALE_CHANGED` is emitted when the value retrievable from `SDL_GetWindowDisplayScale()` changes.
|
||||
- Windows created with `SDL_WINDOW_HIGH_PIXEL_DENSITY` will ask the platform to display addressable pixels at their natural scale.
|
||||
|
||||
## Numeric example
|
||||
|
||||
Given a fullscreen window spanning a 3840x2160 monitor set to 2x display or 200% scaling, the following tabulates the effect of creating a window with or without `SDL_WINDOW_HIGH_PIXEL_DENSITY` on MacOS and Win32:
|
||||
|
||||
| Value | MacOS (Default) | MacOS (HD) | Win32 (Default & HD) |
|
||||
|--------------------------------|-----------------|------------|----------------------|
|
||||
| `SDL_GetWindowSize()` | 1920x1080 | 1920x1080 | 3840x2160 |
|
||||
| `SDL_GetWindowSizeInPixels()` | 1920x1080 | 3840x2160 | 3840x2160 |
|
||||
| `SDL_GetDisplayContentScale()` | 1.0 | 1.0 | 2.0 |
|
||||
| `SDL_GetWindowDisplayScale()` | 1.0 | 2.0 | 2.0 |
|
||||
| `SDL_GetWindowPixelDensity()` | 1.0 | 2.0 | 1.0 |
|
||||
|
||||
Observe the philosophical difference between the approaches taken by MacOS and Win32:
|
||||
- Win32 coordinate system always deals in physical device pixels, high DPI support is achieved by providing an advisory hint for the developer to enlarge drawn objects. Ignoring the advisory scale factor results in graphics appearing tiny.
|
||||
- MacOS coordinate system always deals in physical content sizes, high DPI support is achieved by providing an optional flag for the developer to request finer granularity. Omitting the granularity request results in graphics appearing coarse.
|
||||
|
||||
## Explanation
|
||||
|
||||
Displays now have a content display scale, which is the expected scale for content based on the DPI settings of the display. For example, a 4K display might have a 2.0 (200%) display scale, which means that the user expects UI elements to be twice as big on this display, to aid in readability. You can query the display content scale using `SDL_GetDisplayContentScale()`, and when this changes you get an `SDL_EVENT_WINDOW_DISPLAY_SCALE_CHANGED` event.
|
||||
@@ -34,3 +8,33 @@ Displays now have a content display scale, which is the expected scale for conte
|
||||
The window size is now distinct from the window pixel size, and the ratio between the two is the window pixel density. If the window is created with the `SDL_WINDOW_HIGH_PIXEL_DENSITY` flag, SDL will try to match the native pixel density for the display, otherwise it will try to have the pixel size match the window size. You can query the window pixel density using `SDL_GetWindowPixelDensity()`. You can query the window pixel size using `SDL_GetWindowSizeInPixels()`, and when this changes you get an `SDL_EVENT_WINDOW_PIXEL_SIZE_CHANGED` event. You are guaranteed to get a `SDL_EVENT_WINDOW_PIXEL_SIZE_CHANGED` event when a window is created and resized, and you can use this event to create and resize your graphics context for the window.
|
||||
|
||||
The window has a display scale, which is the scale from the pixel resolution to the desired content size, e.g. the combination of the pixel density and the content scale. For example, a 3840x2160 window displayed at 200% on Windows, and a 1920x1080 window with the high density flag on a 2x display on macOS will both have a pixel size of 3840x2160 and a display scale of 2.0. You can query the window display scale using `SDL_GetWindowDisplayScale()`, and when this changes you get an `SDL_EVENT_WINDOW_DISPLAY_SCALE_CHANGED` event.
|
||||
|
||||
## Numeric example
|
||||
|
||||
Given a window spanning a 3840x2160 monitor set to 2x display or 200% scaling, the following tabulates the effect of creating a window with or without `SDL_WINDOW_HIGH_PIXEL_DENSITY` on macOS and Windows:
|
||||
|
||||
| Value | macOS (Default) | macOS (HD) | Windows (Default & HD) |
|
||||
|--------------------------------|-----------------|------------|------------------------|
|
||||
| `SDL_GetWindowSize()` | 1920x1080 | 1920x1080 | 3840x2160 |
|
||||
| `SDL_GetWindowSizeInPixels()` | 1920x1080 | 3840x2160 | 3840x2160 |
|
||||
| `SDL_GetDisplayContentScale()` | 1.0 | 1.0 | 2.0 |
|
||||
| `SDL_GetWindowDisplayScale()` | 1.0 | 2.0 | 2.0 |
|
||||
| `SDL_GetWindowPixelDensity()` | 1.0 | 2.0 | 1.0 |
|
||||
|
||||
Observe the difference between the approaches taken by macOS and Windows:
|
||||
- The Windows and Android coordinate system always deals in physical device pixels, high DPI support is achieved by providing a content scale that tells the developer to draw objects larger. Ignoring this scale factor results in graphics appearing tiny.
|
||||
- The macOS and iOS coordinate system always deals in window coordinates, high DPI support is achieved by providing an optional flag for the developer to request more pixels. Omitting this flag results in graphics having low detail.
|
||||
- On Linux, X11 uses a similar approach to Windows and Wayland uses a similar approach to macOS.
|
||||
|
||||
## Solution
|
||||
|
||||
Proper high DPI support takes into account both the content scale and the pixel density.
|
||||
|
||||
First, you'd create your window with the `SDL_WINDOW_HIGH_PIXEL_DENSITY` flag, assuming you want the highest detail possible. Then you'd get the window display scale to see how much your UI elements should be enlarged to be readable.
|
||||
|
||||
If you're using the SDL 2D renderer, SDL provides the function `SDL_ConvertEventToRenderCoordinates()` to convert mouse coordinates between window coordinates and rendering coordinates, and the more general functions `SDL_RenderCoordinatesFromWindow()` and `SDL_RenderCoordinatesToWindow()` to do other conversion between them.
|
||||
|
||||
If you're not using the 2D renderer, you can implement this yourself using `SDL_GetWindowPixelDensity()` as scale factor to convert from window coordinates to pixels.
|
||||
|
||||
Finally you'll want to test on both Windows and macOS if possible to make sure your high DPI support works in all environments.
|
||||
|
||||
|
@@ -65,7 +65,7 @@ not give you any processing time after the events are delivered.
|
||||
|
||||
e.g.
|
||||
|
||||
int HandleAppEvents(void *userdata, SDL_Event *event)
|
||||
bool HandleAppEvents(void *userdata, SDL_Event *event)
|
||||
{
|
||||
switch (event->type)
|
||||
{
|
||||
@@ -73,37 +73,37 @@ e.g.
|
||||
/* Terminate the app.
|
||||
Shut everything down before returning from this function.
|
||||
*/
|
||||
return 0;
|
||||
return false;
|
||||
case SDL_EVENT_LOW_MEMORY:
|
||||
/* You will get this when your app is paused and iOS wants more memory.
|
||||
Release as much memory as possible.
|
||||
*/
|
||||
return 0;
|
||||
return false;
|
||||
case SDL_EVENT_WILL_ENTER_BACKGROUND:
|
||||
/* Prepare your app to go into the background. Stop loops, etc.
|
||||
This gets called when the user hits the home button, or gets a call.
|
||||
*/
|
||||
return 0;
|
||||
return false;
|
||||
case SDL_EVENT_DID_ENTER_BACKGROUND:
|
||||
/* This will get called if the user accepted whatever sent your app to the background.
|
||||
If the user got a phone call and canceled it, you'll instead get an SDL_EVENT_DID_ENTER_FOREGROUND event and restart your loops.
|
||||
When you get this, you have 5 seconds to save all your state or the app will be terminated.
|
||||
Your app is NOT active at this point.
|
||||
*/
|
||||
return 0;
|
||||
return false;
|
||||
case SDL_EVENT_WILL_ENTER_FOREGROUND:
|
||||
/* This call happens when your app is coming back to the foreground.
|
||||
Restore all your state here.
|
||||
*/
|
||||
return 0;
|
||||
return false;
|
||||
case SDL_EVENT_DID_ENTER_FOREGROUND:
|
||||
/* Restart your loops here.
|
||||
Your app is interactive and getting CPU again.
|
||||
*/
|
||||
return 0;
|
||||
return false;
|
||||
default:
|
||||
/* No special processing, add it to the event queue */
|
||||
return 1;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -19,7 +19,7 @@ Ubuntu 18.04, all available features enabled:
|
||||
libaudio-dev libjack-dev libsndio-dev libx11-dev libxext-dev \
|
||||
libxrandr-dev libxcursor-dev libxfixes-dev libxi-dev libxss-dev \
|
||||
libxkbcommon-dev libdrm-dev libgbm-dev libgl1-mesa-dev libgles2-mesa-dev \
|
||||
libegl1-mesa-dev libdbus-1-dev libibus-1.0-dev libudev-dev fcitx-libs-dev
|
||||
libegl1-mesa-dev libdbus-1-dev libibus-1.0-dev libudev-dev
|
||||
|
||||
Ubuntu 22.04+ can also add `libpipewire-0.3-dev libwayland-dev libdecor-0-dev liburing-dev` to that command line.
|
||||
|
||||
@@ -28,7 +28,7 @@ Fedora 35, all available features enabled:
|
||||
sudo yum install gcc git-core make cmake \
|
||||
alsa-lib-devel pulseaudio-libs-devel nas-devel pipewire-devel \
|
||||
libX11-devel libXext-devel libXrandr-devel libXcursor-devel libXfixes-devel \
|
||||
libXi-devel libXScrnSaver-devel dbus-devel ibus-devel fcitx-devel \
|
||||
libXi-devel libXScrnSaver-devel dbus-devel ibus-devel \
|
||||
systemd-devel mesa-libGL-devel libxkbcommon-devel mesa-libGLES-devel \
|
||||
mesa-libEGL-devel vulkan-devel wayland-devel wayland-protocols-devel \
|
||||
libdrm-devel mesa-libgbm-devel libusb-devel libdecor-devel \
|
||||
@@ -45,6 +45,10 @@ openSUSE Tumbleweed:
|
||||
sudo zypper in libunwind-devel libusb-1_0-devel Mesa-libGL-devel libxkbcommon-devel libdrm-devel \
|
||||
libgbm-devel pipewire-devel libpulse-devel sndio-devel Mesa-libEGL-devel
|
||||
|
||||
Arch:
|
||||
sudo pacman -S alsa-lib cmake hidapi ibus jack libdecor libgl libpulse libusb libx11 libxcursor libxext libxinerama libxkbcommon libxrandr libxrender libxss mesa ninja pipewire sndio vulkan-driver vulkan-headers wayland wayland-protocols
|
||||
|
||||
|
||||
Joystick does not work
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
|
@@ -49,7 +49,7 @@ NSApplicationDelegate implementation:
|
||||
```objc
|
||||
- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender
|
||||
{
|
||||
if (SDL_GetEventState(SDL_EVENT_QUIT) == SDL_ENABLE) {
|
||||
if (SDL_EventEnabled(SDL_EVENT_QUIT)) {
|
||||
SDL_Event event;
|
||||
SDL_zero(event);
|
||||
event.type = SDL_EVENT_QUIT;
|
||||
@@ -61,7 +61,7 @@ NSApplicationDelegate implementation:
|
||||
|
||||
- (BOOL)application:(NSApplication *)theApplication openFile:(NSString *)filename
|
||||
{
|
||||
if (SDL_GetEventState(SDL_EVENT_DROP_FILE) == SDL_ENABLE) {
|
||||
if (SDL_EventEnabled(SDL_EVENT_DROP_FILE)) {
|
||||
SDL_Event event;
|
||||
SDL_zero(event);
|
||||
event.type = SDL_EVENT_DROP_FILE;
|
||||
|
@@ -411,7 +411,7 @@ The iscapture field of SDL_AudioDeviceEvent has been renamed recording.
|
||||
|
||||
SDL_QUERY, SDL_IGNORE, SDL_ENABLE, and SDL_DISABLE have been removed. You can use the functions SDL_SetEventEnabled() and SDL_EventEnabled() to set and query event processing state.
|
||||
|
||||
SDL_AddEventWatch() now returns SDL_FALSE_ if it fails because it ran out of memory and couldn't add the event watch callback.
|
||||
SDL_AddEventWatch() now returns false if it fails because it ran out of memory and couldn't add the event watch callback.
|
||||
|
||||
SDL_RegisterEvents() now returns 0 if it couldn't allocate any user events.
|
||||
|
||||
|
@@ -11,7 +11,7 @@
|
||||
- [macOS](README-macos.md)
|
||||
- [NetBSD](README-bsd.md)
|
||||
- [Nintendo Switch](README-switch.md)
|
||||
- [Nintendo 3DS](README-3ds.md)
|
||||
- [Nintendo 3DS](README-n3ds.md)
|
||||
- [OpenBSD](README-bsd.md)
|
||||
- [PlayStation 2](README-ps2.md)
|
||||
- [PlayStation 4](README-ps4.md)
|
||||
|
@@ -29,7 +29,7 @@ cmake --install build
|
||||
|
||||
|
||||
## Compiling a HelloWorld
|
||||
[PSP Hello World](https://psp-dev.org/doku.php?id=tutorial:hello_world)
|
||||
[PSP Hello World](https://pspdev.github.io/basic_programs.html#hello-world)
|
||||
|
||||
## To Do
|
||||
- PSP Screen Keyboard
|
||||
|
@@ -1,60 +1,48 @@
|
||||
# Versioning
|
||||
|
||||
## Since 2.23.0
|
||||
## Since 3.2.0
|
||||
|
||||
SDL follows an "odd/even" versioning policy, similar to GLib, GTK, Flatpak
|
||||
and older versions of the Linux kernel:
|
||||
|
||||
* The major version (first part) increases when backwards compatibility
|
||||
is broken, which will happen infrequently.
|
||||
|
||||
* If the minor version (second part) is divisible by 2
|
||||
(for example 2.24.x, 2.26.x), this indicates a version of SDL that
|
||||
is believed to be stable and suitable for production use.
|
||||
* If the minor version (second part) and the patch version (third part) is
|
||||
divisible by 2 (for example 3.2.6, 3.4.0), this indicates a version of
|
||||
SDL that is believed to be stable and suitable for production use.
|
||||
|
||||
* In stable releases, the patchlevel or micro version (third part)
|
||||
indicates bugfix releases. Bugfix releases should not add or
|
||||
remove ABI, so the ".0" release (for example 2.24.0) should be
|
||||
forwards-compatible with all the bugfix releases from the
|
||||
same cycle (for example 2.24.1).
|
||||
indicates bugfix releases. Bugfix releases may add small changes
|
||||
to the ABI, so newer patch versions are backwards-compatible but
|
||||
not fully forwards-compatible. For example, programs built against
|
||||
SDL 3.2.0 should work fine with SDL 3.2.8, but programs built against
|
||||
SDL 3.2.8 may not work with 3.2.0.
|
||||
|
||||
* The minor version increases when new API or ABI is added, or when
|
||||
other significant changes are made. Newer minor versions are
|
||||
backwards-compatible, but not fully forwards-compatible.
|
||||
For example, programs built against SDL 2.24.x should work fine
|
||||
with SDL 2.26.x, but programs built against SDL 2.26.x will not
|
||||
necessarily work with 2.24.x.
|
||||
* The minor version increases when significant changes are made that
|
||||
require longer development or testing time, e.g. major new functionality,
|
||||
or revamping support for a platform. Newer minor versions are
|
||||
backwards-compatible, but not fully forwards-compatible. For example,
|
||||
programs built against SDL 3.2.x should work fine with SDL 3.4.x,
|
||||
but programs built against SDL 3.4.x may not work with 3.2.x.
|
||||
|
||||
* If the minor version (second part) is not divisible by 2
|
||||
(for example 2.23.x, 2.25.x), this indicates a development prerelease
|
||||
of SDL that is not suitable for stable software distributions.
|
||||
* If the minor version (second part) or patch version (third part) is not
|
||||
divisible by 2 (for example 3.2.9, 3.3.x), this indicates a development
|
||||
prerelease of SDL that is not suitable for stable software distributions.
|
||||
Use with caution.
|
||||
|
||||
* The patchlevel or micro version (third part) increases with
|
||||
each prerelease.
|
||||
|
||||
* Each prerelease might add new API and/or ABI.
|
||||
* The patchlevel or micro version (third part) increases with each prerelease.
|
||||
|
||||
* Prereleases are backwards-compatible with older stable branches.
|
||||
For example, 2.25.x will be backwards-compatible with 2.24.x.
|
||||
For example, programs built against SDL 3.2.x should work fine with
|
||||
SDL 3.3.x, but programs built against SDL 3.3.x may not work with 3.2.x.
|
||||
|
||||
* Prereleases are not guaranteed to be backwards-compatible with
|
||||
each other. For example, new API or ABI added in 2.25.1
|
||||
might be removed or changed in 2.25.2.
|
||||
If this would be a problem for you, please do not use prereleases.
|
||||
* Prereleases are not guaranteed to be backwards-compatible with each other.
|
||||
For example, new API or ABI added in 3.3.0 might be removed or changed in
|
||||
3.3.1. If this would be a problem for you, please do not use prereleases.
|
||||
|
||||
* Only upgrade to a prerelease if you can guarantee that you will
|
||||
promptly upgrade to the stable release that follows it.
|
||||
For example, do not upgrade to 2.23.x unless you will be able to
|
||||
upgrade to 2.24.0 when it becomes available.
|
||||
* Only use a prerelease if you can guarantee that you will promptly upgrade
|
||||
to the stable release that follows it. For example, do not use 3.3.x
|
||||
unless you will be able to upgrade to 3.4.0 when it becomes available.
|
||||
|
||||
* Software distributions that have a freeze policy (in particular Linux
|
||||
distributions with a release cycle, such as Debian and Fedora)
|
||||
should usually only package stable releases, and not prereleases.
|
||||
should only package stable releases, and not prereleases.
|
||||
|
||||
## Before 2.23.0
|
||||
|
||||
Older versions of SDL followed a similar policy, but instead of the
|
||||
odd/even rule applying to the minor version, it applied to the patchlevel
|
||||
(micro version, third part). For example, 2.0.22 was a stable release
|
||||
and 2.0.21 was a prerelease.
|
||||
|
@@ -59,6 +59,10 @@ encounter limitations or behavior that is different from other windowing systems
|
||||
`SDL_APP_ID` hint string, the desktop entry file name should match the application ID. For example, if your
|
||||
application ID is set to `org.my_org.sdl_app`, the desktop entry file should be named `org.my_org.sdl_app.desktop`.
|
||||
|
||||
### Keyboard grabs don't work when running under XWayland
|
||||
|
||||
- On GNOME based desktops, the dconf setting `org/gnome/mutter/wayland/xwayland-allow-grabs` must be enabled.
|
||||
|
||||
## Using custom Wayland windowing protocols with SDL windows
|
||||
|
||||
Under normal operation, an `SDL_Window` corresponds to an XDG toplevel window, which provides a standard desktop window.
|
||||
|
@@ -69,7 +69,7 @@ SDL_AppResult SDL_AppIterate(void *appstate)
|
||||
A sine wave is unchanging audio--easy to stream--but for video games, you'll want
|
||||
to generate significantly _less_ audio ahead of time! */
|
||||
const int minimum_audio = (8000 * sizeof (float)) / 2; /* 8000 float samples per second. Half of that. */
|
||||
if (SDL_GetAudioStreamAvailable(stream) < minimum_audio) {
|
||||
if (SDL_GetAudioStreamQueued(stream) < minimum_audio) {
|
||||
static float samples[512]; /* this will feed 512 samples each frame until we get to our maximum. */
|
||||
int i;
|
||||
|
||||
|
@@ -82,7 +82,7 @@ SDL_AppResult SDL_AppIterate(void *appstate)
|
||||
We're being lazy here, but if there's less than the entire wav file left to play,
|
||||
just shove a whole copy of it into the queue, so we always have _tons_ of
|
||||
data queued for playback. */
|
||||
if (SDL_GetAudioStreamAvailable(stream) < (int)wav_data_len) {
|
||||
if (SDL_GetAudioStreamQueued(stream) < (int)wav_data_len) {
|
||||
/* feed more data to the stream. It will queue at the end, and trickle out as the hardware needs more data. */
|
||||
SDL_PutAudioStreamData(stream, wav_data, wav_data_len);
|
||||
}
|
||||
|
@@ -104,7 +104,7 @@ SDL_AppResult SDL_AppIterate(void *appstate)
|
||||
/* If less than a full copy of the audio is queued for playback, put another copy in there.
|
||||
This is overkill, but easy when lots of RAM is cheap. One could be more careful and
|
||||
queue less at a time, as long as the stream doesn't run dry. */
|
||||
if (SDL_GetAudioStreamAvailable(sounds[i].stream) < ((int) sounds[i].wav_data_len)) {
|
||||
if (SDL_GetAudioStreamQueued(sounds[i].stream) < ((int) sounds[i].wav_data_len)) {
|
||||
SDL_PutAudioStreamData(sounds[i].stream, sounds[i].wav_data, (int) sounds[i].wav_data_len);
|
||||
}
|
||||
}
|
||||
|
@@ -208,7 +208,7 @@ void snake_step(SnakeContext *ctx)
|
||||
}
|
||||
}
|
||||
|
||||
static int handle_key_event_(SnakeContext *ctx, SDL_Scancode key_code)
|
||||
static SDL_AppResult handle_key_event_(SnakeContext *ctx, SDL_Scancode key_code)
|
||||
{
|
||||
switch (key_code) {
|
||||
/* Quit. */
|
||||
@@ -309,7 +309,7 @@ SDL_AppResult SDL_AppInit(void **appstate, int argc, char *argv[])
|
||||
return SDL_APP_FAILURE;
|
||||
}
|
||||
|
||||
AppState *as = SDL_calloc(1, sizeof(AppState));
|
||||
AppState *as = (AppState *)SDL_calloc(1, sizeof(AppState));
|
||||
if (!as) {
|
||||
return SDL_APP_FAILURE;
|
||||
}
|
||||
|
@@ -156,7 +156,7 @@ SDL_AppResult SDL_AppInit(void** appstate, int argc, char* argv[]) {
|
||||
return SDL_APP_FAILURE;
|
||||
}
|
||||
|
||||
if (!(vm = SDL_calloc(1, sizeof(*vm)))) {
|
||||
if (!(vm = (BytePusher *)SDL_calloc(1, sizeof(*vm)))) {
|
||||
return SDL_APP_FAILURE;
|
||||
}
|
||||
*(BytePusher**)appstate = vm;
|
||||
@@ -199,7 +199,7 @@ SDL_AppResult SDL_AppInit(void** appstate, int argc, char* argv[]) {
|
||||
for (r = 0; r < 6; ++r) {
|
||||
for (g = 0; g < 6; ++g) {
|
||||
for (b = 0; b < 6; ++b, ++i) {
|
||||
SDL_Color color = { r * 0x33, g * 0x33, b * 0x33, SDL_ALPHA_OPAQUE };
|
||||
SDL_Color color = { (Uint8)(r * 0x33), (Uint8)(g * 0x33), (Uint8)(b * 0x33), SDL_ALPHA_OPAQUE };
|
||||
palette->colors[i] = color;
|
||||
}
|
||||
}
|
||||
|
@@ -105,7 +105,7 @@ SDL_AppResult SDL_AppIterate(void *appstate)
|
||||
|
||||
/* draw axes as bars going across middle of screen. We don't know if it's an X or Y or whatever axis, so we can't do more than this. */
|
||||
total = SDL_GetNumJoystickAxes(joystick);
|
||||
y = (float) ((winh - (total * size)) / 2);
|
||||
y = (winh - (total * size)) / 2;
|
||||
x = ((float) winw) / 2.0f;
|
||||
for (i = 0; i < total; i++) {
|
||||
const SDL_Color *color = &colors[i % SDL_arraysize(colors)];
|
||||
@@ -119,7 +119,7 @@ SDL_AppResult SDL_AppIterate(void *appstate)
|
||||
|
||||
/* draw buttons as blocks across top of window. We only know the button numbers, but not where they are on the device. */
|
||||
total = SDL_GetNumJoystickButtons(joystick);
|
||||
x = (float) ((winw - (total * size)) / 2);
|
||||
x = (winw - (total * size)) / 2;
|
||||
for (i = 0; i < total; i++) {
|
||||
const SDL_Color *color = &colors[i % SDL_arraysize(colors)];
|
||||
const SDL_FRect dst = { x, 0.0f, size, size };
|
||||
@@ -136,7 +136,7 @@ SDL_AppResult SDL_AppIterate(void *appstate)
|
||||
|
||||
/* draw hats across the bottom of the screen. */
|
||||
total = SDL_GetNumJoystickHats(joystick);
|
||||
x = ((float) ((winw - (total * (size * 2.0f))) / 2.0f)) + (size / 2.0f);
|
||||
x = ((winw - (total * (size * 2.0f))) / 2.0f) + (size / 2.0f);
|
||||
y = ((float) winh) - size;
|
||||
for (i = 0; i < total; i++) {
|
||||
const SDL_Color *color = &colors[i % SDL_arraysize(colors)];
|
||||
|
@@ -92,8 +92,8 @@ SDL_AppResult SDL_AppIterate(void *appstate)
|
||||
/* center this one and make it grow and shrink. */
|
||||
dst_rect.w = (float) texture_width + (texture_width * scale);
|
||||
dst_rect.h = (float) texture_height + (texture_height * scale);
|
||||
dst_rect.x = ((float) (WINDOW_WIDTH - dst_rect.w)) / 2.0f;
|
||||
dst_rect.y = ((float) (WINDOW_HEIGHT - dst_rect.h)) / 2.0f;
|
||||
dst_rect.x = (WINDOW_WIDTH - dst_rect.w) / 2.0f;
|
||||
dst_rect.y = (WINDOW_HEIGHT - dst_rect.h) / 2.0f;
|
||||
SDL_RenderTexture(renderer, texture, NULL, &dst_rect);
|
||||
|
||||
SDL_RenderPresent(renderer); /* put it all on the screen! */
|
||||
|
@@ -141,7 +141,7 @@ SDL_AppResult SDL_AppIterate(void *appstate)
|
||||
/* we need one more vertex, since the two triangles can share two of them. */
|
||||
vertices[3].position.x = 600.0f;
|
||||
vertices[3].position.y = 150.0f;
|
||||
vertices[3].color.r = vertices[0].color.g = vertices[0].color.b = vertices[0].color.a = 1.0f;
|
||||
vertices[3].color.r = vertices[3].color.g = vertices[3].color.b = vertices[3].color.a = 1.0f;
|
||||
vertices[3].tex_coord.x = 1.0f;
|
||||
vertices[3].tex_coord.y = 1.0f;
|
||||
|
||||
|
@@ -20,7 +20,7 @@
|
||||
*/
|
||||
|
||||
/**
|
||||
* Main include header for the SDL library, version 3.2.4
|
||||
* Main include header for the SDL library, version 3.2.24
|
||||
*
|
||||
* It is almost always best to include just this one header instead of
|
||||
* picking out individual headers included here. There are exceptions to
|
||||
|
@@ -126,7 +126,7 @@ extern "C" {
|
||||
*/
|
||||
#define SDL_TriggerBreakpoint() TriggerABreakpointInAPlatformSpecificManner
|
||||
|
||||
#elif defined(_MSC_VER) && _MSC_VER >= 1310
|
||||
#elif defined(__MINGW32__) || (defined(_MSC_VER) && _MSC_VER >= 1310)
|
||||
/* Don't include intrin.h here because it contains C++ code */
|
||||
extern void __cdecl __debugbreak(void);
|
||||
#define SDL_TriggerBreakpoint() __debugbreak()
|
||||
@@ -149,6 +149,8 @@ extern "C" {
|
||||
#define SDL_TriggerBreakpoint() __asm__ __volatile__ ( "bkpt #22\n\t" )
|
||||
#elif defined(_WIN32) && ((defined(__GNUC__) || defined(__clang__)) && (defined(__arm64__) || defined(__aarch64__)) )
|
||||
#define SDL_TriggerBreakpoint() __asm__ __volatile__ ( "brk #0xF000\n\t" )
|
||||
#elif defined(__GNUC__) || defined(__clang__)
|
||||
#define SDL_TriggerBreakpoint() __builtin_trap() /* older gcc may not support SDL_HAS_BUILTIN(__builtin_trap) above */
|
||||
#elif defined(__386__) && defined(__WATCOMC__)
|
||||
#define SDL_TriggerBreakpoint() { _asm { int 0x03 } }
|
||||
#elif defined(HAVE_SIGNAL_H) && !defined(__WATCOMC__)
|
||||
@@ -360,7 +362,7 @@ extern SDL_DECLSPEC SDL_AssertState SDLCALL SDL_ReportAssertion(SDL_AssertData *
|
||||
#define SDL_enabled_assert(condition) \
|
||||
do { \
|
||||
while ( !(condition) ) { \
|
||||
static struct SDL_AssertData sdl_assert_data = { 0, 0, #condition, 0, 0, 0, 0 }; \
|
||||
static struct SDL_AssertData sdl_assert_data = { false, 0, #condition, NULL, 0, NULL, NULL }; \
|
||||
const SDL_AssertState sdl_assert_state = SDL_ReportAssertion(&sdl_assert_data, SDL_FUNCTION, SDL_FILE, SDL_LINE); \
|
||||
if (sdl_assert_state == SDL_ASSERTION_RETRY) { \
|
||||
continue; /* go again. */ \
|
||||
|
@@ -942,7 +942,10 @@ extern SDL_DECLSPEC void SDLCALL SDL_CloseAudioDevice(SDL_AudioDeviceID devid);
|
||||
* Binding a stream to a device will set its output format for playback
|
||||
* devices, and its input format for recording devices, so they match the
|
||||
* device's settings. The caller is welcome to change the other end of the
|
||||
* stream's format at any time with SDL_SetAudioStreamFormat().
|
||||
* stream's format at any time with SDL_SetAudioStreamFormat(). If the other
|
||||
* end of the stream's format has never been set (the audio stream was created
|
||||
* with a NULL audio spec), this function will set it to match the device
|
||||
* end's format.
|
||||
*
|
||||
* \param devid an audio device to bind a stream to.
|
||||
* \param streams an array of audio streams to bind.
|
||||
@@ -1021,7 +1024,7 @@ extern SDL_DECLSPEC void SDLCALL SDL_UnbindAudioStream(SDL_AudioStream *stream);
|
||||
/**
|
||||
* Query an audio stream for its currently-bound device.
|
||||
*
|
||||
* This reports the audio device that an audio stream is currently bound to.
|
||||
* This reports the logical audio device that an audio stream is currently bound to.
|
||||
*
|
||||
* If not bound, or invalid, this returns zero, which is not a valid device
|
||||
* ID.
|
||||
@@ -1717,7 +1720,7 @@ typedef void (SDLCALL *SDL_AudioStreamCallback)(void *userdata, SDL_AudioStream
|
||||
* audio to the stream during this call; if needed, the request that triggered
|
||||
* this callback will obtain the new data immediately.
|
||||
*
|
||||
* The callback's `approx_request` argument is roughly how many bytes of
|
||||
* The callback's `additional_amount` argument is roughly how many bytes of
|
||||
* _unconverted_ data (in the stream's input format) is needed by the caller,
|
||||
* although this may overestimate a little for safety. This takes into account
|
||||
* how much is already in the stream and only asks for any extra necessary to
|
||||
@@ -1762,13 +1765,13 @@ extern SDL_DECLSPEC bool SDLCALL SDL_SetAudioStreamGetCallback(SDL_AudioStream *
|
||||
* The callback can (optionally) call SDL_GetAudioStreamData() to obtain audio
|
||||
* from the stream during this call.
|
||||
*
|
||||
* The callback's `approx_request` argument is how many bytes of _converted_
|
||||
* data (in the stream's output format) was provided by the caller, although
|
||||
* this may underestimate a little for safety. This value might be less than
|
||||
* what is currently available in the stream, if data was already there, and
|
||||
* might be less than the caller provided if the stream needs to keep a buffer
|
||||
* to aid in resampling. Which means the callback may be provided with zero
|
||||
* bytes, and a different amount on each call.
|
||||
* The callback's `additional_amount` argument is how many bytes of
|
||||
* _converted_ data (in the stream's output format) was provided by the
|
||||
* caller, although this may underestimate a little for safety. This value
|
||||
* might be less than what is currently available in the stream, if data was
|
||||
* already there, and might be less than the caller provided if the stream
|
||||
* needs to keep a buffer to aid in resampling. Which means the callback may
|
||||
* be provided with zero bytes, and a different amount on each call.
|
||||
*
|
||||
* The callback may call SDL_GetAudioStreamAvailable to see the total amount
|
||||
* currently available to read from the stream, instead of the total provided
|
||||
|
@@ -119,7 +119,7 @@ typedef struct SDL_CameraSpec
|
||||
int width; /**< Frame width */
|
||||
int height; /**< Frame height */
|
||||
int framerate_numerator; /**< Frame rate numerator ((num / denom) == FPS, (denom / num) == duration in seconds) */
|
||||
int framerate_denominator; /**< Frame rate demoninator ((num / denom) == FPS, (denom / num) == duration in seconds) */
|
||||
int framerate_denominator; /**< Frame rate denominator ((num / denom) == FPS, (denom / num) == duration in seconds) */
|
||||
} SDL_CameraSpec;
|
||||
|
||||
/**
|
||||
|
@@ -106,7 +106,7 @@ extern SDL_DECLSPEC bool SDLCALL SDL_SetClipboardText(const char *text);
|
||||
/**
|
||||
* Get UTF-8 text from the clipboard.
|
||||
*
|
||||
* This functions returns an empty string if there was not enough memory left
|
||||
* This function returns an empty string if there is not enough memory left
|
||||
* for a copy of the clipboard's content.
|
||||
*
|
||||
* \returns the clipboard text on success or an empty string on failure; call
|
||||
@@ -155,7 +155,7 @@ extern SDL_DECLSPEC bool SDLCALL SDL_SetPrimarySelectionText(const char *text);
|
||||
/**
|
||||
* Get UTF-8 text from the primary selection.
|
||||
*
|
||||
* This functions returns an empty string if there was not enough memory left
|
||||
* This function returns an empty string if there is not enough memory left
|
||||
* for a copy of the primary selection's content.
|
||||
*
|
||||
* \returns the primary selection text on success or an empty string on
|
||||
@@ -194,15 +194,15 @@ extern SDL_DECLSPEC bool SDLCALL SDL_HasPrimarySelectionText(void);
|
||||
* clipboard is cleared or new data is set. The clipboard is automatically
|
||||
* cleared in SDL_Quit().
|
||||
*
|
||||
* \param userdata a pointer to provided user data.
|
||||
* \param userdata a pointer to the provided user data.
|
||||
* \param mime_type the requested mime-type.
|
||||
* \param size a pointer filled in with the length of the returned data.
|
||||
* \returns a pointer to the data for the provided mime-type. Returning NULL
|
||||
* or setting length to 0 will cause no data to be sent to the
|
||||
* or setting the length to 0 will cause no data to be sent to the
|
||||
* "receiver". It is up to the receiver to handle this. Essentially
|
||||
* returning no data is more or less undefined behavior and may cause
|
||||
* breakage in receiving applications. The returned data will not be
|
||||
* freed so it needs to be retained and dealt with internally.
|
||||
* freed, so it needs to be retained and dealt with internally.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
@@ -211,10 +211,10 @@ extern SDL_DECLSPEC bool SDLCALL SDL_HasPrimarySelectionText(void);
|
||||
typedef const void *(SDLCALL *SDL_ClipboardDataCallback)(void *userdata, const char *mime_type, size_t *size);
|
||||
|
||||
/**
|
||||
* Callback function that will be called when the clipboard is cleared, or new
|
||||
* Callback function that will be called when the clipboard is cleared, or when new
|
||||
* data is set.
|
||||
*
|
||||
* \param userdata a pointer to provided user data.
|
||||
* \param userdata a pointer to the provided user data.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
@@ -231,7 +231,7 @@ typedef void (SDLCALL *SDL_ClipboardCleanupCallback)(void *userdata);
|
||||
* respond with the data for the requested mime-type.
|
||||
*
|
||||
* The size of text data does not include any terminator, and the text does
|
||||
* not need to be null terminated (e.g. you can directly copy a portion of a
|
||||
* not need to be null-terminated (e.g., you can directly copy a portion of a
|
||||
* document).
|
||||
*
|
||||
* \param callback a function pointer to the function that provides the
|
||||
@@ -239,7 +239,7 @@ typedef void (SDLCALL *SDL_ClipboardCleanupCallback)(void *userdata);
|
||||
* \param cleanup a function pointer to the function that cleans up the
|
||||
* clipboard data.
|
||||
* \param userdata an opaque pointer that will be forwarded to the callbacks.
|
||||
* \param mime_types a list of mime-types that are being offered.
|
||||
* \param mime_types a list of mime-types that are being offered. SDL copies the given list.
|
||||
* \param num_mime_types the number of mime-types in the mime_types list.
|
||||
* \returns true on success or false on failure; call SDL_GetError() for more
|
||||
* information.
|
||||
@@ -269,10 +269,10 @@ extern SDL_DECLSPEC bool SDLCALL SDL_SetClipboardData(SDL_ClipboardDataCallback
|
||||
extern SDL_DECLSPEC bool SDLCALL SDL_ClearClipboardData(void);
|
||||
|
||||
/**
|
||||
* Get the data from clipboard for a given mime type.
|
||||
* Get the data from the clipboard for a given mime type.
|
||||
*
|
||||
* The size of text data does not include the terminator, but the text is
|
||||
* guaranteed to be null terminated.
|
||||
* guaranteed to be null-terminated.
|
||||
*
|
||||
* \param mime_type the mime type to read from the clipboard.
|
||||
* \param size a pointer filled in with the length of the returned data.
|
||||
@@ -292,8 +292,8 @@ extern SDL_DECLSPEC void * SDLCALL SDL_GetClipboardData(const char *mime_type, s
|
||||
/**
|
||||
* Query whether there is data in the clipboard for the provided mime type.
|
||||
*
|
||||
* \param mime_type the mime type to check for data for.
|
||||
* \returns true if there exists data in clipboard for the provided mime type,
|
||||
* \param mime_type the mime type to check for data.
|
||||
* \returns true if data exists in the clipboard for the provided mime type,
|
||||
* false if it does not.
|
||||
*
|
||||
* \threadsafety This function should only be called on the main thread.
|
||||
@@ -310,7 +310,7 @@ extern SDL_DECLSPEC bool SDLCALL SDL_HasClipboardData(const char *mime_type);
|
||||
*
|
||||
* \param num_mime_types a pointer filled with the number of mime types, may
|
||||
* be NULL.
|
||||
* \returns a null terminated array of strings with mime types, or NULL on
|
||||
* \returns a null-terminated array of strings with mime types, or NULL on
|
||||
* failure; call SDL_GetError() for more information. This should be
|
||||
* freed with SDL_free() when it is no longer needed.
|
||||
*
|
||||
|
@@ -84,8 +84,8 @@ typedef struct SDL_DialogFileFilter
|
||||
* - A pointer to NULL, the user either didn't choose any file or canceled the
|
||||
* dialog.
|
||||
* - A pointer to non-`NULL`, the user chose one or more files. The argument
|
||||
* is a null-terminated list of pointers to C strings, each containing a
|
||||
* path.
|
||||
* is a null-terminated array of pointers to UTF-8 encoded strings, each
|
||||
* containing a path.
|
||||
*
|
||||
* The filelist argument should not be freed; it will automatically be freed
|
||||
* when the callback returns.
|
||||
|
@@ -46,7 +46,7 @@
|
||||
#if defined(_MSC_VER) && (_MSC_VER >= 1400)
|
||||
/* As of Clang 11, '_m_prefetchw' is conflicting with the winnt.h's version,
|
||||
so we define the needed '_m_prefetch' here as a pseudo-header, until the issue is fixed. */
|
||||
#ifdef __clang__
|
||||
#if defined(__clang__) && !SDL_HAS_BUILTIN(_m_prefetch)
|
||||
#ifndef __PRFCHWINTRIN_H
|
||||
#define __PRFCHWINTRIN_H
|
||||
static __inline__ void __attribute__((__always_inline__, __nodebug__))
|
||||
@@ -128,7 +128,7 @@ _m_prefetch(void *__P)
|
||||
* \sa SDL_BIG_ENDIAN
|
||||
*/
|
||||
#define SDL_BYTEORDER SDL_LIL_ENDIAN___or_maybe___SDL_BIG_ENDIAN
|
||||
#elif defined(SDL_PLATFORM_LINUX)
|
||||
#elif defined(SDL_PLATFORM_LINUX) || defined(__GLIBC__)
|
||||
#include <endian.h>
|
||||
#define SDL_BYTEORDER __BYTE_ORDER
|
||||
#elif defined(SDL_PLATFORM_SOLARIS)
|
||||
@@ -486,7 +486,7 @@ SDL_FORCE_INLINE Uint32 SDL_Swap32(Uint32 x) { return x_but_byteswapped; }
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*/
|
||||
SDL_FORCE_INLINE Uint32 SDL_Swap64(Uint64 x) { return x_but_byteswapped; }
|
||||
SDL_FORCE_INLINE Uint64 SDL_Swap64(Uint64 x) { return x_but_byteswapped; }
|
||||
|
||||
/**
|
||||
* Swap a 16-bit value from littleendian to native byte order.
|
||||
|
@@ -132,7 +132,7 @@ typedef enum SDL_EventType
|
||||
|
||||
/* Window events */
|
||||
/* 0x200 was SDL_WINDOWEVENT, reserve the number for sdl2-compat */
|
||||
/* 0x201 was SDL_EVENT_SYSWM, reserve the number for sdl2-compat */
|
||||
/* 0x201 was SDL_SYSWMEVENT, reserve the number for sdl2-compat */
|
||||
SDL_EVENT_WINDOW_SHOWN = 0x202, /**< Window has been shown */
|
||||
SDL_EVENT_WINDOW_HIDDEN, /**< Window has been hidden */
|
||||
SDL_EVENT_WINDOW_EXPOSED, /**< Window has been exposed and should be redrawn, and can be redrawn directly from event watchers for this event */
|
||||
@@ -492,6 +492,8 @@ typedef struct SDL_MouseWheelEvent
|
||||
SDL_MouseWheelDirection direction; /**< Set to one of the SDL_MOUSEWHEEL_* defines. When FLIPPED the values in X and Y will be opposite. Multiply by -1 to change them back */
|
||||
float mouse_x; /**< X coordinate, relative to window */
|
||||
float mouse_y; /**< Y coordinate, relative to window */
|
||||
Sint32 integer_x; /**< The amount scrolled horizontally, accumulated to whole scroll "ticks" (added in 3.2.12) */
|
||||
Sint32 integer_y; /**< The amount scrolled vertically, accumulated to whole scroll "ticks" (added in 3.2.12) */
|
||||
} SDL_MouseWheelEvent;
|
||||
|
||||
/**
|
||||
@@ -1108,7 +1110,7 @@ typedef enum SDL_EventAction
|
||||
* \param numevents if action is SDL_ADDEVENT, the number of events to add
|
||||
* back to the event queue; if action is SDL_PEEKEVENT or
|
||||
* SDL_GETEVENT, the maximum number of events to retrieve.
|
||||
* \param action action to take; see [[#action|Remarks]] for details.
|
||||
* \param action action to take; see [Remarks](#remarks) for details.
|
||||
* \param minType minimum value of the event type to be considered;
|
||||
* SDL_EVENT_FIRST is a safe choice.
|
||||
* \param maxType maximum value of the event type to be considered;
|
||||
|
@@ -35,13 +35,14 @@
|
||||
* can render offscreen entirely, perhaps for image processing, and not use a
|
||||
* window at all.
|
||||
*
|
||||
* Next the app prepares static data (things that are created once and used
|
||||
* Next, the app prepares static data (things that are created once and used
|
||||
* over and over). For example:
|
||||
*
|
||||
* - Shaders (programs that run on the GPU): use SDL_CreateGPUShader().
|
||||
* - Vertex buffers (arrays of geometry data) and other data rendering will
|
||||
* need: use SDL_UploadToGPUBuffer().
|
||||
* - Textures (images): use SDL_UploadToGPUTexture().
|
||||
* - Vertex buffers (arrays of geometry data) and other rendering data: use
|
||||
* SDL_CreateGPUBuffer() and SDL_UploadToGPUBuffer().
|
||||
* - Textures (images): use SDL_CreateGPUTexture() and
|
||||
* SDL_UploadToGPUTexture().
|
||||
* - Samplers (how textures should be read from): use SDL_CreateGPUSampler().
|
||||
* - Render pipelines (precalculated rendering state): use
|
||||
* SDL_CreateGPUGraphicsPipeline()
|
||||
@@ -223,8 +224,8 @@
|
||||
* - `drawIndirectFirstInstance`
|
||||
*
|
||||
* **D3D12:** Supported on Windows 10 or newer, Xbox One (GDK), and Xbox
|
||||
* Series X|S (GDK). Requires a GPU that supports DirectX 12 Feature Level
|
||||
* 11_1.
|
||||
* Series X|S (GDK). Requires a GPU that supports DirectX 12 Feature Level 11_0 and
|
||||
* Resource Binding Tier 2 or above.
|
||||
*
|
||||
* **Metal:** Supported on macOS 10.14+ and iOS/tvOS 13.0+. Hardware
|
||||
* requirements vary by operating system:
|
||||
@@ -1090,7 +1091,7 @@ typedef enum SDL_GPUCompareOp
|
||||
SDL_GPU_COMPAREOP_LESS_OR_EQUAL, /**< The comparison evaluates reference <= test. */
|
||||
SDL_GPU_COMPAREOP_GREATER, /**< The comparison evaluates reference > test. */
|
||||
SDL_GPU_COMPAREOP_NOT_EQUAL, /**< The comparison evaluates reference != test. */
|
||||
SDL_GPU_COMPAREOP_GREATER_OR_EQUAL, /**< The comparison evalutes reference >= test. */
|
||||
SDL_GPU_COMPAREOP_GREATER_OR_EQUAL, /**< The comparison evaluates reference >= test. */
|
||||
SDL_GPU_COMPAREOP_ALWAYS /**< The comparison always evaluates true. */
|
||||
} SDL_GPUCompareOp;
|
||||
|
||||
@@ -1495,9 +1496,16 @@ typedef struct SDL_GPUIndirectDispatchCommand
|
||||
/**
|
||||
* A structure specifying the parameters of a sampler.
|
||||
*
|
||||
* Note that mip_lod_bias is a no-op for the Metal driver. For Metal, LOD bias
|
||||
* must be applied via shader instead.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_CreateGPUSampler
|
||||
* \sa SDL_GPUFilter
|
||||
* \sa SDL_GPUSamplerMipmapMode
|
||||
* \sa SDL_GPUSamplerAddressMode
|
||||
* \sa SDL_GPUCompareOp
|
||||
*/
|
||||
typedef struct SDL_GPUSamplerCreateInfo
|
||||
{
|
||||
@@ -1536,14 +1544,14 @@ typedef struct SDL_GPUSamplerCreateInfo
|
||||
* \since This struct is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_GPUVertexAttribute
|
||||
* \sa SDL_GPUVertexInputState
|
||||
* \sa SDL_GPUVertexInputRate
|
||||
*/
|
||||
typedef struct SDL_GPUVertexBufferDescription
|
||||
{
|
||||
Uint32 slot; /**< The binding slot of the vertex buffer. */
|
||||
Uint32 pitch; /**< The byte pitch between consecutive elements of the vertex buffer. */
|
||||
Uint32 pitch; /**< The size of a single element + the offset between elements. */
|
||||
SDL_GPUVertexInputRate input_rate; /**< Whether attribute addressing is a function of the vertex index or instance index. */
|
||||
Uint32 instance_step_rate; /**< The number of instances to draw using the same per-instance data before advancing in the instance buffer by one element. Ignored unless input_rate is SDL_GPU_VERTEXINPUTRATE_INSTANCE */
|
||||
Uint32 instance_step_rate; /**< Reserved for future use. Must be set to 0. */
|
||||
} SDL_GPUVertexBufferDescription;
|
||||
|
||||
/**
|
||||
@@ -1713,10 +1721,13 @@ typedef struct SDL_GPUTransferBufferCreateInfo
|
||||
* A structure specifying the parameters of the graphics pipeline rasterizer
|
||||
* state.
|
||||
*
|
||||
* NOTE: Some backend APIs (D3D11/12) will enable depth clamping even if
|
||||
* enable_depth_clip is true. If you rely on this clamp+clip behavior,
|
||||
* consider enabling depth clip and then manually clamping depth in your
|
||||
* fragment shaders on Metal and Vulkan.
|
||||
* Note that SDL_GPU_FILLMODE_LINE is not supported on many Android devices.
|
||||
* For those devices, the fill mode will automatically fall back to FILL.
|
||||
*
|
||||
* Also note that the D3D12 driver will enable depth clamping even if
|
||||
* enable_depth_clip is true. If you need this clamp+clip behavior, consider
|
||||
* enabling depth clip and then manually clamping depth in your fragment
|
||||
* shaders on Metal and Vulkan.
|
||||
*
|
||||
* \since This struct is available since SDL 3.2.0.
|
||||
*
|
||||
@@ -1747,8 +1758,8 @@ typedef struct SDL_GPURasterizerState
|
||||
typedef struct SDL_GPUMultisampleState
|
||||
{
|
||||
SDL_GPUSampleCount sample_count; /**< The number of samples to be used in rasterization. */
|
||||
Uint32 sample_mask; /**< Determines which samples get updated in the render targets. Treated as 0xFFFFFFFF if enable_mask is false. */
|
||||
bool enable_mask; /**< Enables sample masking. */
|
||||
Uint32 sample_mask; /**< Reserved for future use. Must be set to 0. */
|
||||
bool enable_mask; /**< Reserved for future use. Must be set to false. */
|
||||
Uint8 padding1;
|
||||
Uint8 padding2;
|
||||
Uint8 padding3;
|
||||
@@ -1798,6 +1809,8 @@ typedef struct SDL_GPUColorTargetDescription
|
||||
* \since This struct is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_GPUGraphicsPipelineCreateInfo
|
||||
* \sa SDL_GPUColorTargetDescription
|
||||
* \sa SDL_GPUTextureFormat
|
||||
*/
|
||||
typedef struct SDL_GPUGraphicsPipelineTargetInfo
|
||||
{
|
||||
@@ -2454,9 +2467,9 @@ extern SDL_DECLSPEC SDL_GPUShader * SDLCALL SDL_CreateGPUShader(
|
||||
* - `SDL_PROP_GPU_TEXTURE_CREATE_D3D12_CLEAR_DEPTH_FLOAT`: (Direct3D 12 only)
|
||||
* if the texture usage is SDL_GPU_TEXTUREUSAGE_DEPTH_STENCIL_TARGET, clear
|
||||
* the texture to a depth of this value. Defaults to zero.
|
||||
* - `SDL_PROP_GPU_TEXTURE_CREATE_D3D12_CLEAR_STENCIL_UINT8`: (Direct3D 12
|
||||
* - `SDL_PROP_GPU_TEXTURE_CREATE_D3D12_CLEAR_STENCIL_NUMBER`: (Direct3D 12
|
||||
* only) if the texture usage is SDL_GPU_TEXTUREUSAGE_DEPTH_STENCIL_TARGET,
|
||||
* clear the texture to a stencil of this value. Defaults to zero.
|
||||
* clear the texture to a stencil of this Uint8 value. Defaults to zero.
|
||||
* - `SDL_PROP_GPU_TEXTURE_CREATE_NAME_STRING`: a name that can be displayed
|
||||
* in debugging tools.
|
||||
*
|
||||
@@ -2482,13 +2495,13 @@ extern SDL_DECLSPEC SDL_GPUTexture * SDLCALL SDL_CreateGPUTexture(
|
||||
SDL_GPUDevice *device,
|
||||
const SDL_GPUTextureCreateInfo *createinfo);
|
||||
|
||||
#define SDL_PROP_GPU_TEXTURE_CREATE_D3D12_CLEAR_R_FLOAT "SDL.gpu.texture.create.d3d12.clear.r"
|
||||
#define SDL_PROP_GPU_TEXTURE_CREATE_D3D12_CLEAR_G_FLOAT "SDL.gpu.texture.create.d3d12.clear.g"
|
||||
#define SDL_PROP_GPU_TEXTURE_CREATE_D3D12_CLEAR_B_FLOAT "SDL.gpu.texture.create.d3d12.clear.b"
|
||||
#define SDL_PROP_GPU_TEXTURE_CREATE_D3D12_CLEAR_A_FLOAT "SDL.gpu.texture.create.d3d12.clear.a"
|
||||
#define SDL_PROP_GPU_TEXTURE_CREATE_D3D12_CLEAR_DEPTH_FLOAT "SDL.gpu.texture.create.d3d12.clear.depth"
|
||||
#define SDL_PROP_GPU_TEXTURE_CREATE_D3D12_CLEAR_STENCIL_UINT8 "SDL.gpu.texture.create.d3d12.clear.stencil"
|
||||
#define SDL_PROP_GPU_TEXTURE_CREATE_NAME_STRING "SDL.gpu.texture.create.name"
|
||||
#define SDL_PROP_GPU_TEXTURE_CREATE_D3D12_CLEAR_R_FLOAT "SDL.gpu.texture.create.d3d12.clear.r"
|
||||
#define SDL_PROP_GPU_TEXTURE_CREATE_D3D12_CLEAR_G_FLOAT "SDL.gpu.texture.create.d3d12.clear.g"
|
||||
#define SDL_PROP_GPU_TEXTURE_CREATE_D3D12_CLEAR_B_FLOAT "SDL.gpu.texture.create.d3d12.clear.b"
|
||||
#define SDL_PROP_GPU_TEXTURE_CREATE_D3D12_CLEAR_A_FLOAT "SDL.gpu.texture.create.d3d12.clear.a"
|
||||
#define SDL_PROP_GPU_TEXTURE_CREATE_D3D12_CLEAR_DEPTH_FLOAT "SDL.gpu.texture.create.d3d12.clear.depth"
|
||||
#define SDL_PROP_GPU_TEXTURE_CREATE_D3D12_CLEAR_STENCIL_NUMBER "SDL.gpu.texture.create.d3d12.clear.stencil"
|
||||
#define SDL_PROP_GPU_TEXTURE_CREATE_NAME_STRING "SDL.gpu.texture.create.name"
|
||||
|
||||
/**
|
||||
* Creates a buffer object to be used in graphics or compute workflows.
|
||||
@@ -2635,7 +2648,7 @@ extern SDL_DECLSPEC void SDLCALL SDL_InsertGPUDebugLabel(
|
||||
const char *text);
|
||||
|
||||
/**
|
||||
* Begins a debug group with an arbitary name.
|
||||
* Begins a debug group with an arbitrary name.
|
||||
*
|
||||
* Used for denoting groups of calls when viewing the command buffer
|
||||
* callstream in a graphics debugging tool.
|
||||
@@ -3762,7 +3775,7 @@ extern SDL_DECLSPEC void SDLCALL SDL_ReleaseWindowFromGPUDevice(
|
||||
* supported via SDL_WindowSupportsGPUPresentMode /
|
||||
* SDL_WindowSupportsGPUSwapchainComposition prior to calling this function.
|
||||
*
|
||||
* SDL_GPU_PRESENTMODE_VSYNC and SDL_GPU_SWAPCHAINCOMPOSITION_SDR are always
|
||||
* SDL_GPU_PRESENTMODE_VSYNC with SDL_GPU_SWAPCHAINCOMPOSITION_SDR are always
|
||||
* supported.
|
||||
*
|
||||
* \param device a GPU context.
|
||||
@@ -3920,6 +3933,9 @@ extern SDL_DECLSPEC bool SDLCALL SDL_WaitForGPUSwapchain(
|
||||
* freed by the user. You MUST NOT call this function from any thread other
|
||||
* than the one that created the window.
|
||||
*
|
||||
* The swapchain texture is write-only and cannot be used as a sampler or for
|
||||
* another reading operation.
|
||||
*
|
||||
* \param command_buffer a command buffer.
|
||||
* \param window a window that has been claimed.
|
||||
* \param swapchain_texture a pointer filled in with a swapchain texture
|
||||
@@ -3938,6 +3954,7 @@ extern SDL_DECLSPEC bool SDLCALL SDL_WaitForGPUSwapchain(
|
||||
*
|
||||
* \sa SDL_SubmitGPUCommandBuffer
|
||||
* \sa SDL_SubmitGPUCommandBufferAndAcquireFence
|
||||
* \sa SDL_AcquireGPUSwapchainTexture
|
||||
*/
|
||||
extern SDL_DECLSPEC bool SDLCALL SDL_WaitAndAcquireGPUSwapchainTexture(
|
||||
SDL_GPUCommandBuffer *command_buffer,
|
||||
@@ -4128,7 +4145,7 @@ extern SDL_DECLSPEC bool SDLCALL SDL_GPUTextureSupportsFormat(
|
||||
* \param device a GPU context.
|
||||
* \param format the texture format to check.
|
||||
* \param sample_count the sample count to check.
|
||||
* \returns a hardware-specific version of min(preferred, possible).
|
||||
* \returns whether the sample count is supported for this texture format.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*/
|
||||
|
@@ -595,7 +595,7 @@ extern "C" {
|
||||
* A variable that limits what CPU features are available.
|
||||
*
|
||||
* By default, SDL marks all features the current CPU supports as available.
|
||||
* This hint allows to limit these to a subset.
|
||||
* This hint allows the enabled features to be limited to a subset.
|
||||
*
|
||||
* When the hint is unset, or empty, SDL will enable all detected CPU
|
||||
* features.
|
||||
@@ -1074,8 +1074,8 @@ extern "C" {
|
||||
*
|
||||
* By default, SDL will try all available GPU backends in a reasonable order
|
||||
* until it finds one that can work, but this hint allows the app or user to
|
||||
* force a specific target, such as "direct3d11" if, say, your hardware
|
||||
* supports D3D12 but want to try using D3D11 instead.
|
||||
* force a specific target, such as "direct3d12" if, say, your hardware
|
||||
* supports Vulkan but you want to try using D3D12 instead.
|
||||
*
|
||||
* This hint should be set before any GPU functions are called.
|
||||
*
|
||||
@@ -2026,8 +2026,8 @@ extern "C" {
|
||||
*
|
||||
* The variable can be set to the following values:
|
||||
*
|
||||
* - "0": RAWINPUT drivers are not used.
|
||||
* - "1": RAWINPUT drivers are used. (default)
|
||||
* - "0": RAWINPUT drivers are not used. (default)
|
||||
* - "1": RAWINPUT drivers are used.
|
||||
*
|
||||
* This hint should be set before SDL is initialized.
|
||||
*
|
||||
@@ -2126,8 +2126,8 @@ extern "C" {
|
||||
*
|
||||
* The variable can be set to the following values:
|
||||
*
|
||||
* - "0": WGI is not used.
|
||||
* - "1": WGI is used. (default)
|
||||
* - "0": WGI is not used. (default)
|
||||
* - "1": WGI is used.
|
||||
*
|
||||
* This hint should be set before SDL is initialized.
|
||||
*
|
||||
@@ -2191,6 +2191,28 @@ extern "C" {
|
||||
*/
|
||||
#define SDL_HINT_JOYSTICK_ZERO_CENTERED_DEVICES "SDL_JOYSTICK_ZERO_CENTERED_DEVICES"
|
||||
|
||||
/**
|
||||
* A variable containing a list of devices and their desired number of haptic
|
||||
* (force feedback) enabled axis.
|
||||
*
|
||||
* The format of the string is a comma separated list of USB VID/PID pairs in
|
||||
* hexadecimal form plus the number of desired axes, e.g.
|
||||
*
|
||||
* `0xAAAA/0xBBBB/1,0xCCCC/0xDDDD/3`
|
||||
*
|
||||
* This hint supports a "wildcard" device that will set the number of haptic
|
||||
* axes on all initialized haptic devices which were not defined explicitly in
|
||||
* this hint.
|
||||
*
|
||||
* `0xFFFF/0xFFFF/1`
|
||||
*
|
||||
* This hint should be set before a controller is opened. The number of haptic
|
||||
* axes won't exceed the number of real axes found on the device.
|
||||
*
|
||||
* \since This hint is available since SDL 3.2.5.
|
||||
*/
|
||||
#define SDL_HINT_JOYSTICK_HAPTIC_AXES "SDL_JOYSTICK_HAPTIC_AXES"
|
||||
|
||||
/**
|
||||
* A variable that controls keycode representation in keyboard events.
|
||||
*
|
||||
@@ -3585,6 +3607,22 @@ extern "C" {
|
||||
*/
|
||||
#define SDL_HINT_VIDEO_WIN_D3DCOMPILER "SDL_VIDEO_WIN_D3DCOMPILER"
|
||||
|
||||
/**
|
||||
* A variable controlling whether SDL should call XSelectInput() to enable
|
||||
* input events on X11 windows wrapped by SDL windows.
|
||||
*
|
||||
* The variable can be set to the following values:
|
||||
*
|
||||
* - "0": Don't call XSelectInput(), assuming the native window code has done
|
||||
* it already.
|
||||
* - "1": Call XSelectInput() to enable input events. (default)
|
||||
*
|
||||
* This hint should be set before creating a window.
|
||||
*
|
||||
* \since This hint is available since SDL 3.2.10.
|
||||
*/
|
||||
#define SDL_HINT_VIDEO_X11_EXTERNAL_WINDOW_INPUT "SDL_VIDEO_X11_EXTERNAL_WINDOW_INPUT"
|
||||
|
||||
/**
|
||||
* A variable controlling whether the X11 _NET_WM_BYPASS_COMPOSITOR hint
|
||||
* should be used.
|
||||
|
@@ -79,7 +79,7 @@ typedef Uint32 SDL_InitFlags;
|
||||
|
||||
#define SDL_INIT_AUDIO 0x00000010u /**< `SDL_INIT_AUDIO` implies `SDL_INIT_EVENTS` */
|
||||
#define SDL_INIT_VIDEO 0x00000020u /**< `SDL_INIT_VIDEO` implies `SDL_INIT_EVENTS`, should be initialized on the main thread */
|
||||
#define SDL_INIT_JOYSTICK 0x00000200u /**< `SDL_INIT_JOYSTICK` implies `SDL_INIT_EVENTS`, should be initialized on the same thread as SDL_INIT_VIDEO on Windows if you don't set SDL_HINT_JOYSTICK_THREAD */
|
||||
#define SDL_INIT_JOYSTICK 0x00000200u /**< `SDL_INIT_JOYSTICK` implies `SDL_INIT_EVENTS` */
|
||||
#define SDL_INIT_HAPTIC 0x00001000u
|
||||
#define SDL_INIT_GAMEPAD 0x00002000u /**< `SDL_INIT_GAMEPAD` implies `SDL_INIT_JOYSTICK` */
|
||||
#define SDL_INIT_EVENTS 0x00004000u
|
||||
|
@@ -41,8 +41,8 @@
|
||||
* "system", "audio", "video", "render", "input", "test", or `*` for any
|
||||
* unspecified category.
|
||||
*
|
||||
* The level can be a numeric level, one of "verbose", "debug", "info",
|
||||
* "warn", "error", "critical", or "quiet" to disable that category.
|
||||
* The level can be a numeric level, one of "trace", "verbose", "debug",
|
||||
* "info", "warn", "error", "critical", or "quiet" to disable that category.
|
||||
*
|
||||
* You can omit the category if you want to set the logging level for all
|
||||
* categories.
|
||||
|
@@ -28,6 +28,9 @@
|
||||
* should look like this:
|
||||
*
|
||||
* ```c
|
||||
* #include <SDL3/SDL.h>
|
||||
* #include <SDL3/SDL_main.h>
|
||||
*
|
||||
* int main(int argc, char *argv[])
|
||||
* {
|
||||
* }
|
||||
@@ -38,9 +41,9 @@
|
||||
* This is also where an app can be configured to use the main callbacks, via
|
||||
* the SDL_MAIN_USE_CALLBACKS macro.
|
||||
*
|
||||
* This is a "single-header library," which is to say that including this
|
||||
* header inserts code into your program, and you should only include it once
|
||||
* in most cases. SDL.h does not include this header automatically.
|
||||
* SDL_main.h is a "single-header library," which is to say that including
|
||||
* this header inserts code into your program, and you should only include it
|
||||
* once in most cases. SDL.h does not include this header automatically.
|
||||
*
|
||||
* For more information, see:
|
||||
*
|
||||
|
@@ -517,7 +517,7 @@ typedef enum SDL_PackedLayout
|
||||
* ABGR32, define a platform-independent encoding into bytes in the order
|
||||
* specified. For example, in RGB24 data, each pixel is encoded in 3 bytes
|
||||
* (red, green, blue) in that order, and in ABGR32 data, each pixel is
|
||||
* encoded in 4 bytes alpha, blue, green, red) in that order. Use these
|
||||
* encoded in 4 bytes (alpha, blue, green, red) in that order. Use these
|
||||
* names if the property of a format that is important to you is the order
|
||||
* of the bytes in memory or on disk.
|
||||
* - Names with a bit count per component, such as ARGB8888 and XRGB1555, are
|
||||
@@ -676,6 +676,9 @@ typedef enum SDL_PixelFormat
|
||||
SDL_PIXELFORMAT_EXTERNAL_OES = 0x2053454fu, /**< Android video texture format */
|
||||
/* SDL_DEFINE_PIXELFOURCC('O', 'E', 'S', ' ') */
|
||||
|
||||
SDL_PIXELFORMAT_MJPG = 0x47504a4du, /**< Motion JPEG */
|
||||
/* SDL_DEFINE_PIXELFOURCC('M', 'J', 'P', 'G') */
|
||||
|
||||
/* Aliases for RGBA byte arrays of color data, for the current platform */
|
||||
#if SDL_BYTEORDER == SDL_BIG_ENDIAN
|
||||
SDL_PIXELFORMAT_RGBA32 = SDL_PIXELFORMAT_RGBA8888,
|
||||
|
@@ -79,6 +79,10 @@ typedef enum SDL_PowerState
|
||||
* It's possible a platform can only report battery percentage or time left
|
||||
* but not both.
|
||||
*
|
||||
* On some platforms, retrieving power supply details might be expensive. If
|
||||
* you want to display continuous status you could call this function every
|
||||
* minute or so.
|
||||
*
|
||||
* \param seconds a pointer filled in with the seconds of battery life left,
|
||||
* or NULL to ignore. This will be filled in with -1 if we
|
||||
* can't determine a value or there is no battery.
|
||||
|
@@ -490,6 +490,9 @@ extern SDL_DECLSPEC SDL_PropertiesID SDLCALL SDL_GetRendererProperties(SDL_Rende
|
||||
* This returns the true output size in pixels, ignoring any render targets or
|
||||
* logical size and presentation.
|
||||
*
|
||||
* For the output size of the current rendering target, with logical size
|
||||
* adjustments, use SDL_GetCurrentRenderOutputSize() instead.
|
||||
*
|
||||
* \param renderer the rendering context.
|
||||
* \param w a pointer filled in with the width in pixels.
|
||||
* \param h a pointer filled in with the height in pixels.
|
||||
@@ -508,9 +511,10 @@ extern SDL_DECLSPEC bool SDLCALL SDL_GetRenderOutputSize(SDL_Renderer *renderer,
|
||||
* Get the current output size in pixels of a rendering context.
|
||||
*
|
||||
* If a rendering target is active, this will return the size of the rendering
|
||||
* target in pixels, otherwise if a logical size is set, it will return the
|
||||
* logical size, otherwise it will return the value of
|
||||
* SDL_GetRenderOutputSize().
|
||||
* target in pixels, otherwise return the value of SDL_GetRenderOutputSize().
|
||||
*
|
||||
* Rendering target or not, the output will be adjusted by the current logical
|
||||
* presentation state, dictated by SDL_SetRenderLogicalPresentation().
|
||||
*
|
||||
* \param renderer the rendering context.
|
||||
* \param w a pointer filled in with the current width.
|
||||
@@ -1318,6 +1322,11 @@ extern SDL_DECLSPEC void SDLCALL SDL_UnlockTexture(SDL_Texture *texture);
|
||||
* To stop rendering to a texture and render to the window again, call this
|
||||
* function with a NULL `texture`.
|
||||
*
|
||||
* Viewport, cliprect, scale, and logical presentation are unique to each
|
||||
* render target. Get and set functions for these states apply to the current
|
||||
* render target set by this function, and those states persist on each target
|
||||
* when the current render target changes.
|
||||
*
|
||||
* \param renderer the rendering context.
|
||||
* \param texture the targeted texture, which must be created with the
|
||||
* `SDL_TEXTUREACCESS_TARGET` flag, or NULL to render to the
|
||||
@@ -1351,25 +1360,39 @@ extern SDL_DECLSPEC bool SDLCALL SDL_SetRenderTarget(SDL_Renderer *renderer, SDL
|
||||
extern SDL_DECLSPEC SDL_Texture * SDLCALL SDL_GetRenderTarget(SDL_Renderer *renderer);
|
||||
|
||||
/**
|
||||
* Set a device independent resolution and presentation mode for rendering.
|
||||
* Set a device-independent resolution and presentation mode for rendering.
|
||||
*
|
||||
* This function sets the width and height of the logical rendering output.
|
||||
* The renderer will act as if the window is always the requested dimensions,
|
||||
* scaling to the actual window resolution as necessary.
|
||||
* The renderer will act as if the current render target is always the
|
||||
* requested dimensions, scaling to the actual resolution as necessary.
|
||||
*
|
||||
* This can be useful for games that expect a fixed size, but would like to
|
||||
* scale the output to whatever is available, regardless of how a user resizes
|
||||
* a window, or if the display is high DPI.
|
||||
*
|
||||
* Logical presentation can be used with both render target textures and the
|
||||
* renderer's window; the state is unique to each render target, and this
|
||||
* function sets the state for the current render target. It might be useful
|
||||
* to draw to a texture that matches the window dimensions with logical
|
||||
* presentation enabled, and then draw that texture across the entire window
|
||||
* with logical presentation disabled. Be careful not to render both with
|
||||
* logical presentation enabled, however, as this could produce
|
||||
* double-letterboxing, etc.
|
||||
*
|
||||
* You can disable logical coordinates by setting the mode to
|
||||
* SDL_LOGICAL_PRESENTATION_DISABLED, and in that case you get the full pixel
|
||||
* resolution of the output window; it is safe to toggle logical presentation
|
||||
* resolution of the render target; it is safe to toggle logical presentation
|
||||
* during the rendering of a frame: perhaps most of the rendering is done to
|
||||
* specific dimensions but to make fonts look sharp, the app turns off logical
|
||||
* presentation while drawing text.
|
||||
* presentation while drawing text, for example.
|
||||
*
|
||||
* Letterboxing will only happen if logical presentation is enabled during
|
||||
* SDL_RenderPresent; be sure to reenable it first if you were using it.
|
||||
* For the renderer's window, letterboxing is drawn into the framebuffer if
|
||||
* logical presentation is enabled during SDL_RenderPresent; be sure to
|
||||
* reenable it before presenting if you were toggling it, otherwise the
|
||||
* letterbox areas might have artifacts from previous frames (or artifacts
|
||||
* from external overlays, etc). Letterboxing is never drawn into texture
|
||||
* render targets; be sure to call SDL_RenderClear() before drawing into the
|
||||
* texture so the letterboxing areas are cleared, if appropriate.
|
||||
*
|
||||
* You can convert coordinates in an event into rendering coordinates using
|
||||
* SDL_ConvertEventToRenderCoordinates().
|
||||
@@ -1397,6 +1420,9 @@ extern SDL_DECLSPEC bool SDLCALL SDL_SetRenderLogicalPresentation(SDL_Renderer *
|
||||
* This function gets the width and height of the logical rendering output, or
|
||||
* the output size in pixels if a logical resolution is not enabled.
|
||||
*
|
||||
* Each render target has its own logical presentation state. This function
|
||||
* gets the state for the current render target.
|
||||
*
|
||||
* \param renderer the rendering context.
|
||||
* \param w an int to be filled with the width.
|
||||
* \param h an int to be filled with the height.
|
||||
@@ -1420,6 +1446,9 @@ extern SDL_DECLSPEC bool SDLCALL SDL_GetRenderLogicalPresentation(SDL_Renderer *
|
||||
* presentation is disabled, it will fill the rectangle with the output size,
|
||||
* in pixels.
|
||||
*
|
||||
* Each render target has its own logical presentation state. This function
|
||||
* gets the rectangle for the current render target.
|
||||
*
|
||||
* \param renderer the rendering context.
|
||||
* \param rect a pointer filled in with the final presentation rectangle, may
|
||||
* be NULL.
|
||||
@@ -1536,6 +1565,9 @@ extern SDL_DECLSPEC bool SDLCALL SDL_ConvertEventToRenderCoordinates(SDL_Rendere
|
||||
*
|
||||
* The area's width and height must be >= 0.
|
||||
*
|
||||
* Each render target has its own viewport. This function sets the viewport
|
||||
* for the current render target.
|
||||
*
|
||||
* \param renderer the rendering context.
|
||||
* \param rect the SDL_Rect structure representing the drawing area, or NULL
|
||||
* to set the viewport to the entire target.
|
||||
@@ -1554,6 +1586,9 @@ extern SDL_DECLSPEC bool SDLCALL SDL_SetRenderViewport(SDL_Renderer *renderer, c
|
||||
/**
|
||||
* Get the drawing area for the current target.
|
||||
*
|
||||
* Each render target has its own viewport. This function gets the viewport
|
||||
* for the current render target.
|
||||
*
|
||||
* \param renderer the rendering context.
|
||||
* \param rect an SDL_Rect structure filled in with the current drawing area.
|
||||
* \returns true on success or false on failure; call SDL_GetError() for more
|
||||
@@ -1572,8 +1607,10 @@ extern SDL_DECLSPEC bool SDLCALL SDL_GetRenderViewport(SDL_Renderer *renderer, S
|
||||
* Return whether an explicit rectangle was set as the viewport.
|
||||
*
|
||||
* This is useful if you're saving and restoring the viewport and want to know
|
||||
* whether you should restore a specific rectangle or NULL. Note that the
|
||||
* viewport is always reset when changing rendering targets.
|
||||
* whether you should restore a specific rectangle or NULL.
|
||||
*
|
||||
* Each render target has its own viewport. This function checks the viewport
|
||||
* for the current render target.
|
||||
*
|
||||
* \param renderer the rendering context.
|
||||
* \returns true if the viewport was set to a specific rectangle, or false if
|
||||
@@ -1613,6 +1650,9 @@ extern SDL_DECLSPEC bool SDLCALL SDL_GetRenderSafeArea(SDL_Renderer *renderer, S
|
||||
/**
|
||||
* Set the clip rectangle for rendering on the specified target.
|
||||
*
|
||||
* Each render target has its own clip rectangle. This function sets the
|
||||
* cliprect for the current render target.
|
||||
*
|
||||
* \param renderer the rendering context.
|
||||
* \param rect an SDL_Rect structure representing the clip area, relative to
|
||||
* the viewport, or NULL to disable clipping.
|
||||
@@ -1631,6 +1671,9 @@ extern SDL_DECLSPEC bool SDLCALL SDL_SetRenderClipRect(SDL_Renderer *renderer, c
|
||||
/**
|
||||
* Get the clip rectangle for the current target.
|
||||
*
|
||||
* Each render target has its own clip rectangle. This function gets the
|
||||
* cliprect for the current render target.
|
||||
*
|
||||
* \param renderer the rendering context.
|
||||
* \param rect an SDL_Rect structure filled in with the current clipping area
|
||||
* or an empty rectangle if clipping is disabled.
|
||||
@@ -1647,7 +1690,10 @@ extern SDL_DECLSPEC bool SDLCALL SDL_SetRenderClipRect(SDL_Renderer *renderer, c
|
||||
extern SDL_DECLSPEC bool SDLCALL SDL_GetRenderClipRect(SDL_Renderer *renderer, SDL_Rect *rect);
|
||||
|
||||
/**
|
||||
* Get whether clipping is enabled on the given renderer.
|
||||
* Get whether clipping is enabled on the given render target.
|
||||
*
|
||||
* Each render target has its own clip rectangle. This function checks the
|
||||
* cliprect for the current render target.
|
||||
*
|
||||
* \param renderer the rendering context.
|
||||
* \returns true if clipping is enabled or false if not; call SDL_GetError()
|
||||
@@ -1673,6 +1719,9 @@ extern SDL_DECLSPEC bool SDLCALL SDL_RenderClipEnabled(SDL_Renderer *renderer);
|
||||
* will be handled using the appropriate quality hints. For best results use
|
||||
* integer scaling factors.
|
||||
*
|
||||
* Each render target has its own scale. This function sets the scale for the
|
||||
* current render target.
|
||||
*
|
||||
* \param renderer the rendering context.
|
||||
* \param scaleX the horizontal scaling factor.
|
||||
* \param scaleY the vertical scaling factor.
|
||||
@@ -1690,6 +1739,9 @@ extern SDL_DECLSPEC bool SDLCALL SDL_SetRenderScale(SDL_Renderer *renderer, floa
|
||||
/**
|
||||
* Get the drawing scale for the current target.
|
||||
*
|
||||
* Each render target has its own scale. This function gets the scale for the
|
||||
* current render target.
|
||||
*
|
||||
* \param renderer the rendering context.
|
||||
* \param scaleX a pointer filled in with the horizontal scaling factor.
|
||||
* \param scaleY a pointer filled in with the vertical scaling factor.
|
||||
@@ -2247,15 +2299,21 @@ extern SDL_DECLSPEC bool SDLCALL SDL_RenderGeometryRaw(SDL_Renderer *renderer,
|
||||
/**
|
||||
* Read pixels from the current rendering target.
|
||||
*
|
||||
* The returned surface should be freed with SDL_DestroySurface()
|
||||
* The returned surface contains pixels inside the desired area clipped to the
|
||||
* current viewport, and should be freed with SDL_DestroySurface().
|
||||
*
|
||||
* Note that this returns the actual pixels on the screen, so if you are using
|
||||
* logical presentation you should use SDL_GetRenderLogicalPresentationRect()
|
||||
* to get the area containing your content.
|
||||
*
|
||||
* **WARNING**: This is a very slow operation, and should not be used
|
||||
* frequently. If you're using this on the main rendering target, it should be
|
||||
* called after rendering and before SDL_RenderPresent().
|
||||
*
|
||||
* \param renderer the rendering context.
|
||||
* \param rect an SDL_Rect structure representing the area in pixels relative
|
||||
* to the to current viewport, or NULL for the entire viewport.
|
||||
* \param rect an SDL_Rect structure representing the area to read, which will
|
||||
* be clipped to the current viewport, or NULL for the entire
|
||||
* viewport.
|
||||
* \returns a new SDL_Surface on success or NULL on failure; call
|
||||
* SDL_GetError() for more information.
|
||||
*
|
||||
@@ -2554,7 +2612,7 @@ extern SDL_DECLSPEC bool SDLCALL SDL_RenderDebugText(SDL_Renderer *renderer, flo
|
||||
* Draw debug text to an SDL_Renderer.
|
||||
*
|
||||
* This function will render a printf()-style format string to a renderer.
|
||||
* Note that this is a convinence function for debugging, with severe
|
||||
* Note that this is a convenience function for debugging, with severe
|
||||
* limitations, and is not intended to be used for production apps and games.
|
||||
*
|
||||
* For the full list of limitations and other useful information, see
|
||||
|
@@ -208,7 +208,7 @@ typedef enum SDL_Scancode
|
||||
|
||||
SDL_SCANCODE_NONUSBACKSLASH = 100, /**< This is the additional key that ISO
|
||||
* keyboards have over ANSI ones,
|
||||
* located between left shift and Y.
|
||||
* located between left shift and Z.
|
||||
* Produces GRAVE ACCENT and TILDE in a
|
||||
* US or UK Mac layout, REVERSE SOLIDUS
|
||||
* (backslash) and VERTICAL LINE in a
|
||||
|
@@ -138,7 +138,8 @@ typedef enum SDL_SensorType
|
||||
SDL_SENSOR_ACCEL_L, /**< Accelerometer for left Joy-Con controller and Wii nunchuk */
|
||||
SDL_SENSOR_GYRO_L, /**< Gyroscope for left Joy-Con controller */
|
||||
SDL_SENSOR_ACCEL_R, /**< Accelerometer for right Joy-Con controller */
|
||||
SDL_SENSOR_GYRO_R /**< Gyroscope for right Joy-Con controller */
|
||||
SDL_SENSOR_GYRO_R, /**< Gyroscope for right Joy-Con controller */
|
||||
SDL_SENSOR_COUNT
|
||||
} SDL_SensorType;
|
||||
|
||||
|
||||
|
@@ -1299,8 +1299,11 @@ extern "C" {
|
||||
*
|
||||
* If `size` is 0, it will be set to 1.
|
||||
*
|
||||
* If you want to allocate memory aligned to a specific alignment, consider
|
||||
* using SDL_aligned_alloc().
|
||||
* If the allocation is successful, the returned pointer is guaranteed to be
|
||||
* aligned to either the *fundamental alignment* (`alignof(max_align_t)` in
|
||||
* C11 and later) or `2 * sizeof(void *)`, whichever is smaller. Use
|
||||
* SDL_aligned_alloc() if you need to allocate memory aligned to an alignment
|
||||
* greater than this guarantee.
|
||||
*
|
||||
* \param size the size to allocate.
|
||||
* \returns a pointer to the allocated memory, or NULL if allocation failed.
|
||||
@@ -1323,6 +1326,10 @@ extern SDL_DECLSPEC SDL_MALLOC void * SDLCALL SDL_malloc(size_t size);
|
||||
*
|
||||
* If either of `nmemb` or `size` is 0, they will both be set to 1.
|
||||
*
|
||||
* If the allocation is successful, the returned pointer is guaranteed to be
|
||||
* aligned to either the *fundamental alignment* (`alignof(max_align_t)` in
|
||||
* C11 and later) or `2 * sizeof(void *)`, whichever is smaller.
|
||||
*
|
||||
* \param nmemb the number of elements in the array.
|
||||
* \param size the size of each element of the array.
|
||||
* \returns a pointer to the allocated array, or NULL if allocation failed.
|
||||
@@ -1357,6 +1364,11 @@ extern SDL_DECLSPEC SDL_MALLOC SDL_ALLOC_SIZE2(1, 2) void * SDLCALL SDL_calloc(s
|
||||
* - If it returns NULL (indicating failure), then `mem` will remain valid and
|
||||
* must still be freed with SDL_free().
|
||||
*
|
||||
* If the allocation is successfully resized, the returned pointer is
|
||||
* guaranteed to be aligned to either the *fundamental alignment*
|
||||
* (`alignof(max_align_t)` in C11 and later) or `2 * sizeof(void *)`,
|
||||
* whichever is smaller.
|
||||
*
|
||||
* \param mem a pointer to allocated memory to reallocate, or NULL.
|
||||
* \param size the new size of the memory.
|
||||
* \returns a pointer to the newly allocated memory, or NULL if allocation
|
||||
@@ -3414,7 +3426,7 @@ extern SDL_DECLSPEC size_t SDLCALL SDL_utf8strnlen(const char *str, size_t bytes
|
||||
* Convert an integer into a string.
|
||||
*
|
||||
* This requires a radix to specified for string format. Specifying 10
|
||||
* produces a decimal number, 16 hexidecimal, etc. Must be in the range of 2
|
||||
* produces a decimal number, 16 hexadecimal, etc. Must be in the range of 2
|
||||
* to 36.
|
||||
*
|
||||
* Note that this function will overflow a buffer if `str` is not large enough
|
||||
@@ -3442,7 +3454,7 @@ extern SDL_DECLSPEC char * SDLCALL SDL_itoa(int value, char *str, int radix);
|
||||
* Convert an unsigned integer into a string.
|
||||
*
|
||||
* This requires a radix to specified for string format. Specifying 10
|
||||
* produces a decimal number, 16 hexidecimal, etc. Must be in the range of 2
|
||||
* produces a decimal number, 16 hexadecimal, etc. Must be in the range of 2
|
||||
* to 36.
|
||||
*
|
||||
* Note that this function will overflow a buffer if `str` is not large enough
|
||||
@@ -3470,7 +3482,7 @@ extern SDL_DECLSPEC char * SDLCALL SDL_uitoa(unsigned int value, char *str, int
|
||||
* Convert a long integer into a string.
|
||||
*
|
||||
* This requires a radix to specified for string format. Specifying 10
|
||||
* produces a decimal number, 16 hexidecimal, etc. Must be in the range of 2
|
||||
* produces a decimal number, 16 hexadecimal, etc. Must be in the range of 2
|
||||
* to 36.
|
||||
*
|
||||
* Note that this function will overflow a buffer if `str` is not large enough
|
||||
@@ -3498,7 +3510,7 @@ extern SDL_DECLSPEC char * SDLCALL SDL_ltoa(long value, char *str, int radix);
|
||||
* Convert an unsigned long integer into a string.
|
||||
*
|
||||
* This requires a radix to specified for string format. Specifying 10
|
||||
* produces a decimal number, 16 hexidecimal, etc. Must be in the range of 2
|
||||
* produces a decimal number, 16 hexadecimal, etc. Must be in the range of 2
|
||||
* to 36.
|
||||
*
|
||||
* Note that this function will overflow a buffer if `str` is not large enough
|
||||
@@ -3528,7 +3540,7 @@ extern SDL_DECLSPEC char * SDLCALL SDL_ultoa(unsigned long value, char *str, int
|
||||
* Convert a long long integer into a string.
|
||||
*
|
||||
* This requires a radix to specified for string format. Specifying 10
|
||||
* produces a decimal number, 16 hexidecimal, etc. Must be in the range of 2
|
||||
* produces a decimal number, 16 hexadecimal, etc. Must be in the range of 2
|
||||
* to 36.
|
||||
*
|
||||
* Note that this function will overflow a buffer if `str` is not large enough
|
||||
@@ -3556,7 +3568,7 @@ extern SDL_DECLSPEC char * SDLCALL SDL_lltoa(long long value, char *str, int rad
|
||||
* Convert an unsigned long long integer into a string.
|
||||
*
|
||||
* This requires a radix to specified for string format. Specifying 10
|
||||
* produces a decimal number, 16 hexidecimal, etc. Must be in the range of 2
|
||||
* produces a decimal number, 16 hexadecimal, etc. Must be in the range of 2
|
||||
* to 36.
|
||||
*
|
||||
* Note that this function will overflow a buffer if `str` is not large enough
|
||||
@@ -3911,7 +3923,7 @@ extern SDL_DECLSPEC int SDLCALL SDL_strcasecmp(const char *str1, const char *str
|
||||
extern SDL_DECLSPEC int SDLCALL SDL_strncasecmp(const char *str1, const char *str2, size_t maxlen);
|
||||
|
||||
/**
|
||||
* Searches a string for the first occurence of any character contained in a
|
||||
* Searches a string for the first occurrence of any character contained in a
|
||||
* breakset, and returns a pointer from the string to that character.
|
||||
*
|
||||
* \param str The null-terminated string to be searched. Must not be NULL, and
|
||||
@@ -3919,7 +3931,7 @@ extern SDL_DECLSPEC int SDLCALL SDL_strncasecmp(const char *str1, const char *st
|
||||
* \param breakset A null-terminated string containing the list of characters
|
||||
* to look for. Must not be NULL, and must not overlap with
|
||||
* `str`.
|
||||
* \returns A pointer to the location, in str, of the first occurence of a
|
||||
* \returns A pointer to the location, in str, of the first occurrence of a
|
||||
* character present in the breakset, or NULL if none is found.
|
||||
*
|
||||
* \threadsafety It is safe to call this function from any thread.
|
||||
@@ -4243,14 +4255,14 @@ extern SDL_DECLSPEC int SDLCALL SDL_vasprintf(char **strp, SDL_PRINTF_FORMAT_STR
|
||||
/**
|
||||
* Seeds the pseudo-random number generator.
|
||||
*
|
||||
* Reusing the seed number will cause SDL_rand_*() to repeat the same stream
|
||||
* of 'random' numbers.
|
||||
* Reusing the seed number will cause SDL_rand() to repeat the same stream of
|
||||
* 'random' numbers.
|
||||
*
|
||||
* \param seed the value to use as a random number seed, or 0 to use
|
||||
* SDL_GetPerformanceCounter().
|
||||
*
|
||||
* \threadsafety This should be called on the same thread that calls
|
||||
* SDL_rand*()
|
||||
* SDL_rand()
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
@@ -4644,7 +4656,7 @@ extern SDL_DECLSPEC float SDLCALL SDL_atanf(float x);
|
||||
*
|
||||
* Domain: `-INF <= x <= INF`, `-INF <= y <= INF`
|
||||
*
|
||||
* Range: `-Pi/2 <= y <= Pi/2`
|
||||
* Range: `-Pi <= y <= Pi`
|
||||
*
|
||||
* This function operates on double-precision floating point values, use
|
||||
* SDL_atan2f for single-precision floats.
|
||||
@@ -4680,7 +4692,7 @@ extern SDL_DECLSPEC double SDLCALL SDL_atan2(double y, double x);
|
||||
*
|
||||
* Domain: `-INF <= x <= INF`, `-INF <= y <= INF`
|
||||
*
|
||||
* Range: `-Pi/2 <= y <= Pi/2`
|
||||
* Range: `-Pi <= y <= Pi`
|
||||
*
|
||||
* This function operates on single-precision floating point values, use
|
||||
* SDL_atan2 for double-precision floats.
|
||||
@@ -5809,7 +5821,7 @@ extern SDL_DECLSPEC int SDLCALL SDL_iconv_close(SDL_iconv_t cd);
|
||||
* This function converts text between encodings, reading from and writing to
|
||||
* a buffer.
|
||||
*
|
||||
* It returns the number of succesful conversions on success. On error,
|
||||
* It returns the number of successful conversions on success. On error,
|
||||
* SDL_ICONV_E2BIG is returned when the output buffer is too small, or
|
||||
* SDL_ICONV_EILSEQ is returned when an invalid input sequence is encountered,
|
||||
* or SDL_ICONV_EINVAL is returned when an incomplete input sequence is
|
||||
@@ -5962,14 +5974,17 @@ size_t wcslcpy(wchar_t *dst, const wchar_t *src, size_t size);
|
||||
size_t wcslcat(wchar_t *dst, const wchar_t *src, size_t size);
|
||||
#endif
|
||||
|
||||
#ifndef _WIN32
|
||||
/* strdup is not ANSI but POSIX, and its prototype might be hidden... */
|
||||
/* not for windows: might conflict with string.h where strdup may have
|
||||
* dllimport attribute: https://github.com/libsdl-org/SDL/issues/12948 */
|
||||
char *strdup(const char *str);
|
||||
#endif
|
||||
|
||||
/* Starting LLVM 16, the analyser errors out if these functions do not have
|
||||
their prototype defined (clang-diagnostic-implicit-function-declaration) */
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <strings.h>
|
||||
|
||||
#define SDL_malloc malloc
|
||||
#define SDL_calloc calloc
|
||||
|
@@ -450,7 +450,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_CloseStorage(SDL_Storage *storage);
|
||||
*
|
||||
* This function should be called in regular intervals until it returns true -
|
||||
* however, it is not recommended to spinwait on this call, as the backend may
|
||||
* depend on a synchronous message loop.
|
||||
* depend on a synchronous message loop. You might instead poll this in your
|
||||
* game's main loop while processing events and drawing a loading screen.
|
||||
*
|
||||
* \param storage a storage container to query.
|
||||
* \returns true if the container is ready, false otherwise.
|
||||
|
@@ -82,6 +82,7 @@ typedef Uint32 SDL_SurfaceFlags;
|
||||
*/
|
||||
typedef enum SDL_ScaleMode
|
||||
{
|
||||
SDL_SCALEMODE_INVALID = -1,
|
||||
SDL_SCALEMODE_NEAREST, /**< nearest pixel sampling */
|
||||
SDL_SCALEMODE_LINEAR /**< linear filtering */
|
||||
} SDL_ScaleMode;
|
||||
@@ -120,6 +121,9 @@ typedef enum SDL_FlipMode
|
||||
* format with a pitch of 32 would consist of 32x32 bytes of Y plane followed
|
||||
* by 32x16 bytes of UV plane.
|
||||
*
|
||||
* When a surface holds MJPG format data, pixels points at the compressed JPEG
|
||||
* image and pitch is the length of that data.
|
||||
*
|
||||
* \since This struct is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_CreateSurface
|
||||
@@ -153,6 +157,8 @@ typedef struct SDL_Surface SDL_Surface;
|
||||
* \returns the new SDL_Surface structure that is created or NULL on failure;
|
||||
* call SDL_GetError() for more information.
|
||||
*
|
||||
* \threadsafety It is safe to call this function from any thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_CreateSurfaceFrom
|
||||
@@ -181,6 +187,8 @@ extern SDL_DECLSPEC SDL_Surface * SDLCALL SDL_CreateSurface(int width, int heigh
|
||||
* \returns the new SDL_Surface structure that is created or NULL on failure;
|
||||
* call SDL_GetError() for more information.
|
||||
*
|
||||
* \threadsafety It is safe to call this function from any thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_CreateSurface
|
||||
@@ -195,6 +203,8 @@ extern SDL_DECLSPEC SDL_Surface * SDLCALL SDL_CreateSurfaceFrom(int width, int h
|
||||
*
|
||||
* \param surface the SDL_Surface to free.
|
||||
*
|
||||
* \threadsafety No other thread should be using the surface when it is freed.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_CreateSurface
|
||||
@@ -221,11 +231,17 @@ extern SDL_DECLSPEC void SDLCALL SDL_DestroySurface(SDL_Surface *surface);
|
||||
* the same tone mapping that Chrome uses for HDR content, the form "*=N",
|
||||
* where N is a floating point scale factor applied in linear space, and
|
||||
* "none", which disables tone mapping. This defaults to "chrome".
|
||||
* - `SDL_PROP_SURFACE_HOTSPOT_X_NUMBER`: the hotspot pixel offset from the
|
||||
* left edge of the image, if this surface is being used as a cursor.
|
||||
* - `SDL_PROP_SURFACE_HOTSPOT_Y_NUMBER`: the hotspot pixel offset from the
|
||||
* top edge of the image, if this surface is being used as a cursor.
|
||||
*
|
||||
* \param surface the SDL_Surface structure to query.
|
||||
* \returns a valid property ID on success or 0 on failure; call
|
||||
* SDL_GetError() for more information.
|
||||
*
|
||||
* \threadsafety It is safe to call this function from any thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*/
|
||||
extern SDL_DECLSPEC SDL_PropertiesID SDLCALL SDL_GetSurfaceProperties(SDL_Surface *surface);
|
||||
@@ -233,6 +249,8 @@ extern SDL_DECLSPEC SDL_PropertiesID SDLCALL SDL_GetSurfaceProperties(SDL_Surfac
|
||||
#define SDL_PROP_SURFACE_SDR_WHITE_POINT_FLOAT "SDL.surface.SDR_white_point"
|
||||
#define SDL_PROP_SURFACE_HDR_HEADROOM_FLOAT "SDL.surface.HDR_headroom"
|
||||
#define SDL_PROP_SURFACE_TONEMAP_OPERATOR_STRING "SDL.surface.tonemap"
|
||||
#define SDL_PROP_SURFACE_HOTSPOT_X_NUMBER "SDL.surface.hotspot.x"
|
||||
#define SDL_PROP_SURFACE_HOTSPOT_Y_NUMBER "SDL.surface.hotspot.y"
|
||||
|
||||
/**
|
||||
* Set the colorspace used by a surface.
|
||||
@@ -246,6 +264,8 @@ extern SDL_DECLSPEC SDL_PropertiesID SDLCALL SDL_GetSurfaceProperties(SDL_Surfac
|
||||
* \returns true on success or false on failure; call SDL_GetError() for more
|
||||
* information.
|
||||
*
|
||||
* \threadsafety This function is not thread safe.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_GetSurfaceColorspace
|
||||
@@ -263,6 +283,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_SetSurfaceColorspace(SDL_Surface *surface,
|
||||
* \returns the colorspace used by the surface, or SDL_COLORSPACE_UNKNOWN if
|
||||
* the surface is NULL.
|
||||
*
|
||||
* \threadsafety This function is not thread safe.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_SetSurfaceColorspace
|
||||
@@ -291,6 +313,8 @@ extern SDL_DECLSPEC SDL_Colorspace SDLCALL SDL_GetSurfaceColorspace(SDL_Surface
|
||||
* the surface didn't have an index format); call SDL_GetError() for
|
||||
* more information.
|
||||
*
|
||||
* \threadsafety This function is not thread safe.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_SetPaletteColors
|
||||
@@ -307,6 +331,8 @@ extern SDL_DECLSPEC SDL_Palette * SDLCALL SDL_CreateSurfacePalette(SDL_Surface *
|
||||
* \returns true on success or false on failure; call SDL_GetError() for more
|
||||
* information.
|
||||
*
|
||||
* \threadsafety This function is not thread safe.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_CreatePalette
|
||||
@@ -321,6 +347,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_SetSurfacePalette(SDL_Surface *surface, SDL
|
||||
* \returns a pointer to the palette used by the surface, or NULL if there is
|
||||
* no palette used.
|
||||
*
|
||||
* \threadsafety It is safe to call this function from any thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_SetSurfacePalette
|
||||
@@ -344,6 +372,8 @@ extern SDL_DECLSPEC SDL_Palette * SDLCALL SDL_GetSurfacePalette(SDL_Surface *sur
|
||||
* \returns true on success or false on failure; call SDL_GetError() for more
|
||||
* information.
|
||||
*
|
||||
* \threadsafety This function is not thread safe.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_RemoveSurfaceAlternateImages
|
||||
@@ -358,6 +388,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_AddSurfaceAlternateImage(SDL_Surface *surfa
|
||||
* \param surface the SDL_Surface structure to query.
|
||||
* \returns true if alternate versions are available or false otherwise.
|
||||
*
|
||||
* \threadsafety It is safe to call this function from any thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_AddSurfaceAlternateImage
|
||||
@@ -383,6 +415,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_SurfaceHasAlternateImages(SDL_Surface *surf
|
||||
* failure; call SDL_GetError() for more information. This should be
|
||||
* freed with SDL_free() when it is no longer needed.
|
||||
*
|
||||
* \threadsafety This function is not thread safe.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_AddSurfaceAlternateImage
|
||||
@@ -399,6 +433,8 @@ extern SDL_DECLSPEC SDL_Surface ** SDLCALL SDL_GetSurfaceImages(SDL_Surface *sur
|
||||
*
|
||||
* \param surface the SDL_Surface structure to update.
|
||||
*
|
||||
* \threadsafety This function is not thread safe.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_AddSurfaceAlternateImage
|
||||
@@ -423,6 +459,10 @@ extern SDL_DECLSPEC void SDLCALL SDL_RemoveSurfaceAlternateImages(SDL_Surface *s
|
||||
* \returns true on success or false on failure; call SDL_GetError() for more
|
||||
* information.
|
||||
*
|
||||
* \threadsafety This function is not thread safe. The locking referred to by
|
||||
* this function is making the pixels available for direct
|
||||
* access, not thread-safe locking.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_MUSTLOCK
|
||||
@@ -435,6 +475,10 @@ extern SDL_DECLSPEC bool SDLCALL SDL_LockSurface(SDL_Surface *surface);
|
||||
*
|
||||
* \param surface the SDL_Surface structure to be unlocked.
|
||||
*
|
||||
* \threadsafety This function is not thread safe. The locking referred to by
|
||||
* this function is making the pixels available for direct
|
||||
* access, not thread-safe locking.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_LockSurface
|
||||
@@ -453,6 +497,8 @@ extern SDL_DECLSPEC void SDLCALL SDL_UnlockSurface(SDL_Surface *surface);
|
||||
* \returns a pointer to a new SDL_Surface structure or NULL on failure; call
|
||||
* SDL_GetError() for more information.
|
||||
*
|
||||
* \threadsafety It is safe to call this function from any thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_DestroySurface
|
||||
@@ -471,6 +517,8 @@ extern SDL_DECLSPEC SDL_Surface * SDLCALL SDL_LoadBMP_IO(SDL_IOStream *src, bool
|
||||
* \returns a pointer to a new SDL_Surface structure or NULL on failure; call
|
||||
* SDL_GetError() for more information.
|
||||
*
|
||||
* \threadsafety It is safe to call this function from any thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_DestroySurface
|
||||
@@ -495,6 +543,8 @@ extern SDL_DECLSPEC SDL_Surface * SDLCALL SDL_LoadBMP(const char *file);
|
||||
* \returns true on success or false on failure; call SDL_GetError() for more
|
||||
* information.
|
||||
*
|
||||
* \threadsafety This function is not thread safe.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_LoadBMP_IO
|
||||
@@ -516,6 +566,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_SaveBMP_IO(SDL_Surface *surface, SDL_IOStre
|
||||
* \returns true on success or false on failure; call SDL_GetError() for more
|
||||
* information.
|
||||
*
|
||||
* \threadsafety This function is not thread safe.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_LoadBMP
|
||||
@@ -534,6 +586,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_SaveBMP(SDL_Surface *surface, const char *f
|
||||
* \returns true on success or false on failure; call SDL_GetError() for more
|
||||
* information.
|
||||
*
|
||||
* \threadsafety This function is not thread safe.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_BlitSurface
|
||||
@@ -550,6 +604,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_SetSurfaceRLE(SDL_Surface *surface, bool en
|
||||
* \param surface the SDL_Surface structure to query.
|
||||
* \returns true if the surface is RLE enabled, false otherwise.
|
||||
*
|
||||
* \threadsafety It is safe to call this function from any thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_SetSurfaceRLE
|
||||
@@ -572,6 +628,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_SurfaceHasRLE(SDL_Surface *surface);
|
||||
* \returns true on success or false on failure; call SDL_GetError() for more
|
||||
* information.
|
||||
*
|
||||
* \threadsafety This function is not thread safe.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_GetSurfaceColorKey
|
||||
@@ -588,6 +646,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_SetSurfaceColorKey(SDL_Surface *surface, bo
|
||||
* \param surface the SDL_Surface structure to query.
|
||||
* \returns true if the surface has a color key, false otherwise.
|
||||
*
|
||||
* \threadsafety It is safe to call this function from any thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_SetSurfaceColorKey
|
||||
@@ -608,6 +668,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_SurfaceHasColorKey(SDL_Surface *surface);
|
||||
* \returns true on success or false on failure; call SDL_GetError() for more
|
||||
* information.
|
||||
*
|
||||
* \threadsafety It is safe to call this function from any thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_SetSurfaceColorKey
|
||||
@@ -631,6 +693,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_GetSurfaceColorKey(SDL_Surface *surface, Ui
|
||||
* \returns true on success or false on failure; call SDL_GetError() for more
|
||||
* information.
|
||||
*
|
||||
* \threadsafety This function is not thread safe.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_GetSurfaceColorMod
|
||||
@@ -649,6 +713,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_SetSurfaceColorMod(SDL_Surface *surface, Ui
|
||||
* \returns true on success or false on failure; call SDL_GetError() for more
|
||||
* information.
|
||||
*
|
||||
* \threadsafety This function is not thread safe.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_GetSurfaceAlphaMod
|
||||
@@ -669,6 +735,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_GetSurfaceColorMod(SDL_Surface *surface, Ui
|
||||
* \returns true on success or false on failure; call SDL_GetError() for more
|
||||
* information.
|
||||
*
|
||||
* \threadsafety This function is not thread safe.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_GetSurfaceAlphaMod
|
||||
@@ -684,6 +752,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_SetSurfaceAlphaMod(SDL_Surface *surface, Ui
|
||||
* \returns true on success or false on failure; call SDL_GetError() for more
|
||||
* information.
|
||||
*
|
||||
* \threadsafety It is safe to call this function from any thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_GetSurfaceColorMod
|
||||
@@ -703,6 +773,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_GetSurfaceAlphaMod(SDL_Surface *surface, Ui
|
||||
* \returns true on success or false on failure; call SDL_GetError() for more
|
||||
* information.
|
||||
*
|
||||
* \threadsafety This function is not thread safe.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_GetSurfaceBlendMode
|
||||
@@ -717,6 +789,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_SetSurfaceBlendMode(SDL_Surface *surface, S
|
||||
* \returns true on success or false on failure; call SDL_GetError() for more
|
||||
* information.
|
||||
*
|
||||
* \threadsafety It is safe to call this function from any thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_SetSurfaceBlendMode
|
||||
@@ -738,6 +812,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_GetSurfaceBlendMode(SDL_Surface *surface, S
|
||||
* \returns true if the rectangle intersects the surface, otherwise false and
|
||||
* blits will be completely clipped.
|
||||
*
|
||||
* \threadsafety This function is not thread safe.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_GetSurfaceClipRect
|
||||
@@ -757,6 +833,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_SetSurfaceClipRect(SDL_Surface *surface, co
|
||||
* \returns true on success or false on failure; call SDL_GetError() for more
|
||||
* information.
|
||||
*
|
||||
* \threadsafety This function is not thread safe.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_SetSurfaceClipRect
|
||||
@@ -771,6 +849,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_GetSurfaceClipRect(SDL_Surface *surface, SD
|
||||
* \returns true on success or false on failure; call SDL_GetError() for more
|
||||
* information.
|
||||
*
|
||||
* \threadsafety This function is not thread safe.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*/
|
||||
extern SDL_DECLSPEC bool SDLCALL SDL_FlipSurface(SDL_Surface *surface, SDL_FlipMode flip);
|
||||
@@ -787,6 +867,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_FlipSurface(SDL_Surface *surface, SDL_FlipM
|
||||
* \returns a copy of the surface or NULL on failure; call SDL_GetError() for
|
||||
* more information.
|
||||
*
|
||||
* \threadsafety This function is not thread safe.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_DestroySurface
|
||||
@@ -806,6 +888,8 @@ extern SDL_DECLSPEC SDL_Surface * SDLCALL SDL_DuplicateSurface(SDL_Surface *surf
|
||||
* \returns a copy of the surface or NULL on failure; call SDL_GetError() for
|
||||
* more information.
|
||||
*
|
||||
* \threadsafety This function is not thread safe.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_DestroySurface
|
||||
@@ -831,6 +915,8 @@ extern SDL_DECLSPEC SDL_Surface * SDLCALL SDL_ScaleSurface(SDL_Surface *surface,
|
||||
* \returns the new SDL_Surface structure that is created or NULL on failure;
|
||||
* call SDL_GetError() for more information.
|
||||
*
|
||||
* \threadsafety This function is not thread safe.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_ConvertSurfaceAndColorspace
|
||||
@@ -857,6 +943,8 @@ extern SDL_DECLSPEC SDL_Surface * SDLCALL SDL_ConvertSurface(SDL_Surface *surfac
|
||||
* \returns the new SDL_Surface structure that is created or NULL on failure;
|
||||
* call SDL_GetError() for more information.
|
||||
*
|
||||
* \threadsafety This function is not thread safe.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_ConvertSurface
|
||||
@@ -878,6 +966,10 @@ extern SDL_DECLSPEC SDL_Surface * SDLCALL SDL_ConvertSurfaceAndColorspace(SDL_Su
|
||||
* \returns true on success or false on failure; call SDL_GetError() for more
|
||||
* information.
|
||||
*
|
||||
* \threadsafety The same destination pixels should not be used from two
|
||||
* threads at once. It is safe to use the same source pixels
|
||||
* from multiple threads.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_ConvertPixelsAndColorspace
|
||||
@@ -907,6 +999,10 @@ extern SDL_DECLSPEC bool SDLCALL SDL_ConvertPixels(int width, int height, SDL_Pi
|
||||
* \returns true on success or false on failure; call SDL_GetError() for more
|
||||
* information.
|
||||
*
|
||||
* \threadsafety The same destination pixels should not be used from two
|
||||
* threads at once. It is safe to use the same source pixels
|
||||
* from multiple threads.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_ConvertPixels
|
||||
@@ -931,6 +1027,10 @@ extern SDL_DECLSPEC bool SDLCALL SDL_ConvertPixelsAndColorspace(int width, int h
|
||||
* \returns true on success or false on failure; call SDL_GetError() for more
|
||||
* information.
|
||||
*
|
||||
* \threadsafety The same destination pixels should not be used from two
|
||||
* threads at once. It is safe to use the same source pixels
|
||||
* from multiple threads.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*/
|
||||
extern SDL_DECLSPEC bool SDLCALL SDL_PremultiplyAlpha(int width, int height, SDL_PixelFormat src_format, const void *src, int src_pitch, SDL_PixelFormat dst_format, void *dst, int dst_pitch, bool linear);
|
||||
@@ -946,6 +1046,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_PremultiplyAlpha(int width, int height, SDL
|
||||
* \returns true on success or false on failure; call SDL_GetError() for more
|
||||
* information.
|
||||
*
|
||||
* \threadsafety This function is not thread safe.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*/
|
||||
extern SDL_DECLSPEC bool SDLCALL SDL_PremultiplySurfaceAlpha(SDL_Surface *surface, bool linear);
|
||||
@@ -966,6 +1068,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_PremultiplySurfaceAlpha(SDL_Surface *surfac
|
||||
* \returns true on success or false on failure; call SDL_GetError() for more
|
||||
* information.
|
||||
*
|
||||
* \threadsafety This function is not thread safe.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*/
|
||||
extern SDL_DECLSPEC bool SDLCALL SDL_ClearSurface(SDL_Surface *surface, float r, float g, float b, float a);
|
||||
@@ -989,6 +1093,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_ClearSurface(SDL_Surface *surface, float r,
|
||||
* \returns true on success or false on failure; call SDL_GetError() for more
|
||||
* information.
|
||||
*
|
||||
* \threadsafety This function is not thread safe.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_FillSurfaceRects
|
||||
@@ -1014,6 +1120,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_FillSurfaceRect(SDL_Surface *dst, const SDL
|
||||
* \returns true on success or false on failure; call SDL_GetError() for more
|
||||
* information.
|
||||
*
|
||||
* \threadsafety This function is not thread safe.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_FillSurfaceRect
|
||||
@@ -1027,9 +1135,6 @@ extern SDL_DECLSPEC bool SDLCALL SDL_FillSurfaceRects(SDL_Surface *dst, const SD
|
||||
* If either `srcrect` or `dstrect` are NULL, the entire surface (`src` or
|
||||
* `dst`) is copied while ensuring clipping to `dst->clip_rect`.
|
||||
*
|
||||
* The final blit rectangles are saved in `srcrect` and `dstrect` after all
|
||||
* clipping is performed.
|
||||
*
|
||||
* The blit function should not be called on a locked surface.
|
||||
*
|
||||
* The blit semantics for surfaces with and without blending and colorkey are
|
||||
@@ -1087,9 +1192,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_FillSurfaceRects(SDL_Surface *dst, const SD
|
||||
* \returns true on success or false on failure; call SDL_GetError() for more
|
||||
* information.
|
||||
*
|
||||
* \threadsafety The same destination surface should not be used from two
|
||||
* threads at once. It is safe to use the same source surface
|
||||
* from multiple threads.
|
||||
* \threadsafety Only one thread should be using the `src` and `dst` surfaces
|
||||
* at any given time.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
@@ -1112,9 +1216,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_BlitSurface(SDL_Surface *src, const SDL_Rec
|
||||
* \returns true on success or false on failure; call SDL_GetError() for more
|
||||
* information.
|
||||
*
|
||||
* \threadsafety The same destination surface should not be used from two
|
||||
* threads at once. It is safe to use the same source surface
|
||||
* from multiple threads.
|
||||
* \threadsafety Only one thread should be using the `src` and `dst` surfaces
|
||||
* at any given time.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
@@ -1137,9 +1240,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_BlitSurfaceUnchecked(SDL_Surface *src, cons
|
||||
* \returns true on success or false on failure; call SDL_GetError() for more
|
||||
* information.
|
||||
*
|
||||
* \threadsafety The same destination surface should not be used from two
|
||||
* threads at once. It is safe to use the same source surface
|
||||
* from multiple threads.
|
||||
* \threadsafety Only one thread should be using the `src` and `dst` surfaces
|
||||
* at any given time.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
@@ -1163,9 +1265,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_BlitSurfaceScaled(SDL_Surface *src, const S
|
||||
* \returns true on success or false on failure; call SDL_GetError() for more
|
||||
* information.
|
||||
*
|
||||
* \threadsafety The same destination surface should not be used from two
|
||||
* threads at once. It is safe to use the same source surface
|
||||
* from multiple threads.
|
||||
* \threadsafety Only one thread should be using the `src` and `dst` surfaces
|
||||
* at any given time.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
@@ -1178,17 +1279,17 @@ extern SDL_DECLSPEC bool SDLCALL SDL_BlitSurfaceUncheckedScaled(SDL_Surface *src
|
||||
*
|
||||
* \param src the SDL_Surface structure to be copied from.
|
||||
* \param srcrect the SDL_Rect structure representing the rectangle to be
|
||||
* copied, may not be NULL.
|
||||
* copied, or NULL to copy the entire surface.
|
||||
* \param dst the SDL_Surface structure that is the blit target.
|
||||
* \param dstrect the SDL_Rect structure representing the target rectangle in
|
||||
* the destination surface, may not be NULL.
|
||||
* the destination surface, or NULL to fill the entire
|
||||
* destination surface.
|
||||
* \param scaleMode the SDL_ScaleMode to be used.
|
||||
* \returns true on success or false on failure; call SDL_GetError() for more
|
||||
* information.
|
||||
*
|
||||
* \threadsafety The same destination surface should not be used from two
|
||||
* threads at once. It is safe to use the same source surface
|
||||
* from multiple threads.
|
||||
* \threadsafety Only one thread should be using the `src` and `dst` surfaces
|
||||
* at any given time.
|
||||
*
|
||||
* \since This function is available since SDL 3.4.0.
|
||||
*
|
||||
@@ -1212,9 +1313,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_StretchSurface(SDL_Surface *src, const SDL_
|
||||
* \returns true on success or false on failure; call SDL_GetError() for more
|
||||
* information.
|
||||
*
|
||||
* \threadsafety The same destination surface should not be used from two
|
||||
* threads at once. It is safe to use the same source surface
|
||||
* from multiple threads.
|
||||
* \threadsafety Only one thread should be using the `src` and `dst` surfaces
|
||||
* at any given time.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
@@ -1242,9 +1342,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_BlitSurfaceTiled(SDL_Surface *src, const SD
|
||||
* \returns true on success or false on failure; call SDL_GetError() for more
|
||||
* information.
|
||||
*
|
||||
* \threadsafety The same destination surface should not be used from two
|
||||
* threads at once. It is safe to use the same source surface
|
||||
* from multiple threads.
|
||||
* \threadsafety Only one thread should be using the `src` and `dst` surfaces
|
||||
* at any given time.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
@@ -1279,9 +1378,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_BlitSurfaceTiledWithScale(SDL_Surface *src,
|
||||
* \returns true on success or false on failure; call SDL_GetError() for more
|
||||
* information.
|
||||
*
|
||||
* \threadsafety The same destination surface should not be used from two
|
||||
* threads at once. It is safe to use the same source surface
|
||||
* from multiple threads.
|
||||
* \threadsafety Only one thread should be using the `src` and `dst` surfaces
|
||||
* at any given time.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
@@ -1313,6 +1411,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_BlitSurface9Grid(SDL_Surface *src, const SD
|
||||
* \param b the blue component of the pixel in the range 0-255.
|
||||
* \returns a pixel value.
|
||||
*
|
||||
* \threadsafety It is safe to call this function from any thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_MapSurfaceRGBA
|
||||
@@ -1344,6 +1444,8 @@ extern SDL_DECLSPEC Uint32 SDLCALL SDL_MapSurfaceRGB(SDL_Surface *surface, Uint8
|
||||
* \param a the alpha component of the pixel in the range 0-255.
|
||||
* \returns a pixel value.
|
||||
*
|
||||
* \threadsafety It is safe to call this function from any thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_MapSurfaceRGB
|
||||
@@ -1373,6 +1475,8 @@ extern SDL_DECLSPEC Uint32 SDLCALL SDL_MapSurfaceRGBA(SDL_Surface *surface, Uint
|
||||
* \returns true on success or false on failure; call SDL_GetError() for more
|
||||
* information.
|
||||
*
|
||||
* \threadsafety This function is not thread safe.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*/
|
||||
extern SDL_DECLSPEC bool SDLCALL SDL_ReadSurfacePixel(SDL_Surface *surface, int x, int y, Uint8 *r, Uint8 *g, Uint8 *b, Uint8 *a);
|
||||
@@ -1397,6 +1501,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_ReadSurfacePixel(SDL_Surface *surface, int
|
||||
* \returns true on success or false on failure; call SDL_GetError() for more
|
||||
* information.
|
||||
*
|
||||
* \threadsafety This function is not thread safe.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*/
|
||||
extern SDL_DECLSPEC bool SDLCALL SDL_ReadSurfacePixelFloat(SDL_Surface *surface, int x, int y, float *r, float *g, float *b, float *a);
|
||||
@@ -1420,6 +1526,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_ReadSurfacePixelFloat(SDL_Surface *surface,
|
||||
* \returns true on success or false on failure; call SDL_GetError() for more
|
||||
* information.
|
||||
*
|
||||
* \threadsafety This function is not thread safe.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*/
|
||||
extern SDL_DECLSPEC bool SDLCALL SDL_WriteSurfacePixel(SDL_Surface *surface, int x, int y, Uint8 r, Uint8 g, Uint8 b, Uint8 a);
|
||||
@@ -1440,6 +1548,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_WriteSurfacePixel(SDL_Surface *surface, int
|
||||
* \returns true on success or false on failure; call SDL_GetError() for more
|
||||
* information.
|
||||
*
|
||||
* \threadsafety This function is not thread safe.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*/
|
||||
extern SDL_DECLSPEC bool SDLCALL SDL_WriteSurfacePixelFloat(SDL_Surface *surface, int x, int y, float r, float g, float b, float a);
|
||||
|
@@ -62,7 +62,7 @@ extern "C" {
|
||||
*
|
||||
* \since This macro is available since SDL 3.2.0.
|
||||
*/
|
||||
#define SDL_MICRO_VERSION 4
|
||||
#define SDL_MICRO_VERSION 24
|
||||
|
||||
/**
|
||||
* This macro turns the version numbers into a numeric value.
|
||||
|
@@ -426,10 +426,10 @@ typedef SDL_EGLint *(SDLCALL *SDL_EGLIntArrayCallback)(void *userdata, SDL_EGLDi
|
||||
*/
|
||||
typedef enum SDL_GLAttr
|
||||
{
|
||||
SDL_GL_RED_SIZE, /**< the minimum number of bits for the red channel of the color buffer; defaults to 3. */
|
||||
SDL_GL_GREEN_SIZE, /**< the minimum number of bits for the green channel of the color buffer; defaults to 3. */
|
||||
SDL_GL_BLUE_SIZE, /**< the minimum number of bits for the blue channel of the color buffer; defaults to 2. */
|
||||
SDL_GL_ALPHA_SIZE, /**< the minimum number of bits for the alpha channel of the color buffer; defaults to 0. */
|
||||
SDL_GL_RED_SIZE, /**< the minimum number of bits for the red channel of the color buffer; defaults to 8. */
|
||||
SDL_GL_GREEN_SIZE, /**< the minimum number of bits for the green channel of the color buffer; defaults to 8. */
|
||||
SDL_GL_BLUE_SIZE, /**< the minimum number of bits for the blue channel of the color buffer; defaults to 8. */
|
||||
SDL_GL_ALPHA_SIZE, /**< the minimum number of bits for the alpha channel of the color buffer; defaults to 8. */
|
||||
SDL_GL_BUFFER_SIZE, /**< the minimum number of bits for frame buffer size; defaults to 0. */
|
||||
SDL_GL_DOUBLEBUFFER, /**< whether the output is single or double buffered; defaults to double buffering on. */
|
||||
SDL_GL_DEPTH_SIZE, /**< the minimum number of bits in the depth buffer; defaults to 16. */
|
||||
@@ -1041,6 +1041,10 @@ extern SDL_DECLSPEC SDL_Window ** SDLCALL SDL_GetWindows(int *count);
|
||||
/**
|
||||
* Create a window with the specified dimensions and flags.
|
||||
*
|
||||
* The window size is a request and may be different than expected based on
|
||||
* the desktop layout and window manager policies. Your application should be
|
||||
* prepared to handle a window of any size.
|
||||
*
|
||||
* `flags` may be any of the following OR'd together:
|
||||
*
|
||||
* - `SDL_WINDOW_FULLSCREEN`: fullscreen window at desktop resolution
|
||||
@@ -1127,6 +1131,10 @@ extern SDL_DECLSPEC SDL_Window * SDLCALL SDL_CreateWindow(const char *title, int
|
||||
/**
|
||||
* Create a child popup window of the specified parent window.
|
||||
*
|
||||
* The window size is a request and may be different than expected based on
|
||||
* the desktop layout and window manager policies. Your application should be
|
||||
* prepared to handle a window of any size.
|
||||
*
|
||||
* The flags parameter **must** contain at least one of the following:
|
||||
*
|
||||
* - `SDL_WINDOW_TOOLTIP`: The popup window is a tooltip and will not pass any
|
||||
@@ -1159,6 +1167,15 @@ extern SDL_DECLSPEC SDL_Window * SDLCALL SDL_CreateWindow(const char *title, int
|
||||
* Popup windows implicitly do not have a border/decorations and do not appear
|
||||
* on the taskbar/dock or in lists of windows such as alt-tab menus.
|
||||
*
|
||||
* By default, popup window positions will automatically be constrained to keep
|
||||
* the entire window within display bounds. This can be overridden with the
|
||||
* `SDL_PROP_WINDOW_CREATE_CONSTRAIN_POPUP_BOOLEAN` property.
|
||||
*
|
||||
* By default, popup menus will automatically grab keyboard focus from the parent
|
||||
* when shown. This behavior can be overridden by setting the `SDL_WINDOW_NOT_FOCUSABLE`
|
||||
* flag, setting the `SDL_PROP_WINDOW_CREATE_FOCUSABLE_BOOLEAN` property to false, or
|
||||
* toggling it after creation via the `SDL_SetWindowFocusable()` function.
|
||||
*
|
||||
* If a parent window is hidden or destroyed, any child popup windows will be
|
||||
* recursively hidden or destroyed as well. Child popup windows not explicitly
|
||||
* hidden will be restored when the parent is shown.
|
||||
@@ -1189,12 +1206,19 @@ extern SDL_DECLSPEC SDL_Window * SDLCALL SDL_CreatePopupWindow(SDL_Window *paren
|
||||
/**
|
||||
* Create a window with the specified properties.
|
||||
*
|
||||
* The window size is a request and may be different than expected based on
|
||||
* the desktop layout and window manager policies. Your application should be
|
||||
* prepared to handle a window of any size.
|
||||
*
|
||||
* These are the supported properties:
|
||||
*
|
||||
* - `SDL_PROP_WINDOW_CREATE_ALWAYS_ON_TOP_BOOLEAN`: true if the window should
|
||||
* be always on top
|
||||
* - `SDL_PROP_WINDOW_CREATE_BORDERLESS_BOOLEAN`: true if the window has no
|
||||
* window decoration
|
||||
* - `SDL_PROP_WINDOW_CREATE_CONSTRAIN_POPUP_BOOLEAN`: true if the "tooltip" and
|
||||
* "menu" window types should be automatically constrained to be entirely within
|
||||
* display bounds (default), false if no constraints on the position are desired.
|
||||
* - `SDL_PROP_WINDOW_CREATE_EXTERNAL_GRAPHICS_CONTEXT_BOOLEAN`: true if the
|
||||
* window will be used with an externally managed graphics context.
|
||||
* - `SDL_PROP_WINDOW_CREATE_FOCUSABLE_BOOLEAN`: true if the window should
|
||||
@@ -1309,6 +1333,7 @@ extern SDL_DECLSPEC SDL_Window * SDLCALL SDL_CreateWindowWithProperties(SDL_Prop
|
||||
|
||||
#define SDL_PROP_WINDOW_CREATE_ALWAYS_ON_TOP_BOOLEAN "SDL.window.create.always_on_top"
|
||||
#define SDL_PROP_WINDOW_CREATE_BORDERLESS_BOOLEAN "SDL.window.create.borderless"
|
||||
#define SDL_PROP_WINDOW_CREATE_CONSTRAIN_POPUP_BOOLEAN "SDL.window.create.constrain_popup"
|
||||
#define SDL_PROP_WINDOW_CREATE_FOCUSABLE_BOOLEAN "SDL.window.create.focusable"
|
||||
#define SDL_PROP_WINDOW_CREATE_EXTERNAL_GRAPHICS_CONTEXT_BOOLEAN "SDL.window.create.external_graphics_context"
|
||||
#define SDL_PROP_WINDOW_CREATE_FLAGS_NUMBER "SDL.window.create.flags"
|
||||
@@ -1448,7 +1473,7 @@ extern SDL_DECLSPEC SDL_Window * SDLCALL SDL_GetWindowParent(SDL_Window *window)
|
||||
* - `SDL_PROP_WINDOW_COCOA_WINDOW_POINTER`: the `(__unsafe_unretained)`
|
||||
* NSWindow associated with the window
|
||||
* - `SDL_PROP_WINDOW_COCOA_METAL_VIEW_TAG_NUMBER`: the NSInteger tag
|
||||
* assocated with metal views on the window
|
||||
* associated with metal views on the window
|
||||
*
|
||||
* On OpenVR:
|
||||
*
|
||||
|
@@ -51,14 +51,14 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Avoid including vulkan.h, don't define VkInstance if it's already included */
|
||||
#ifdef VULKAN_H_
|
||||
/* Avoid including vulkan_core.h, don't define VkInstance if it's already included */
|
||||
#ifdef VULKAN_CORE_H_
|
||||
#define NO_SDL_VULKAN_TYPEDEFS
|
||||
#endif
|
||||
#ifndef NO_SDL_VULKAN_TYPEDEFS
|
||||
#define VK_DEFINE_HANDLE(object) typedef struct object##_T* object;
|
||||
|
||||
#if defined(__LP64__) || defined(_WIN64) || defined(__x86_64__) || defined(_M_X64) || defined(__ia64) || defined (_M_IA64) || defined(__aarch64__) || defined(__powerpc64__)
|
||||
#if defined(__LP64__) || defined(_WIN64) || (defined(__x86_64__) && !defined(__ILP32__)) || defined(_M_X64) || defined(__ia64) || defined (_M_IA64) || defined(__aarch64__) || defined(__powerpc64__) || (defined(__riscv) && __riscv_xlen == 64)
|
||||
#define VK_DEFINE_NON_DISPATCHABLE_HANDLE(object) typedef struct object##_T *object;
|
||||
#else
|
||||
#define VK_DEFINE_NON_DISPATCHABLE_HANDLE(object) typedef uint64_t object;
|
||||
|
@@ -174,6 +174,7 @@
|
||||
#cmakedefine HAVE_MEMFD_CREATE 1
|
||||
#cmakedefine HAVE_POSIX_FALLOCATE 1
|
||||
#cmakedefine HAVE_SIGACTION 1
|
||||
#cmakedefine HAVE_SIGTIMEDWAIT 1
|
||||
#cmakedefine HAVE_SA_SIGACTION 1
|
||||
#cmakedefine HAVE_ST_MTIM 1
|
||||
#cmakedefine HAVE_SETJMP 1
|
||||
|
@@ -111,6 +111,9 @@ typedef unsigned int uintptr_t;
|
||||
# define SDL_DISABLE_AVX 1
|
||||
#endif
|
||||
|
||||
#define HAVE_STDARG_H 1
|
||||
#define HAVE_STDDEF_H 1
|
||||
|
||||
/* This can be disabled to avoid C runtime dependencies and manifest requirements */
|
||||
#ifndef HAVE_LIBC
|
||||
#define HAVE_LIBC 1
|
||||
@@ -122,8 +125,6 @@ typedef unsigned int uintptr_t;
|
||||
#define HAVE_LIMITS_H 1
|
||||
#define HAVE_MATH_H 1
|
||||
#define HAVE_SIGNAL_H 1
|
||||
#define HAVE_STDARG_H 1
|
||||
#define HAVE_STDDEF_H 1
|
||||
#define HAVE_STDIO_H 1
|
||||
#define HAVE_STDLIB_H 1
|
||||
#define HAVE_STRING_H 1
|
||||
@@ -153,7 +154,6 @@ typedef unsigned int uintptr_t;
|
||||
#define HAVE_STRCMP 1
|
||||
#define HAVE_STRNCMP 1
|
||||
#define HAVE_STRPBRK 1
|
||||
#define HAVE_VSSCANF 1
|
||||
#define HAVE_VSNPRINTF 1
|
||||
#define HAVE_ACOS 1
|
||||
#define HAVE_ASIN 1
|
||||
@@ -211,10 +211,7 @@ typedef unsigned int uintptr_t;
|
||||
#if _MSC_VER >= 1400
|
||||
#define HAVE__FSEEKI64 1
|
||||
#endif
|
||||
#endif /* _MSC_VER */
|
||||
#else
|
||||
#define HAVE_STDARG_H 1
|
||||
#define HAVE_STDDEF_H 1
|
||||
#endif /* _MSC_VER */
|
||||
#endif
|
||||
|
||||
/* Enable various audio drivers */
|
||||
|
22
src/SDL.c
22
src/SDL.c
@@ -65,7 +65,7 @@
|
||||
|
||||
// Initialization/Cleanup routines
|
||||
#include "timer/SDL_timer_c.h"
|
||||
#ifdef SDL_VIDEO_DRIVER_WINDOWS
|
||||
#ifdef SDL_PLATFORM_WINDOWS
|
||||
extern bool SDL_HelperWindowCreate(void);
|
||||
extern void SDL_HelperWindowDestroy(void);
|
||||
#endif
|
||||
@@ -317,7 +317,7 @@ bool SDL_InitSubSystem(SDL_InitFlags flags)
|
||||
SDL_DBus_Init();
|
||||
#endif
|
||||
|
||||
#ifdef SDL_VIDEO_DRIVER_WINDOWS
|
||||
#ifdef SDL_PLATFORM_WINDOWS
|
||||
if (flags & (SDL_INIT_HAPTIC | SDL_INIT_JOYSTICK)) {
|
||||
if (!SDL_HelperWindowCreate()) {
|
||||
goto quit_and_error;
|
||||
@@ -356,7 +356,9 @@ bool SDL_InitSubSystem(SDL_InitFlags flags)
|
||||
SDL_IncrementSubsystemRefCount(SDL_INIT_VIDEO);
|
||||
if (!SDL_VideoInit(NULL)) {
|
||||
SDL_DecrementSubsystemRefCount(SDL_INIT_VIDEO);
|
||||
SDL_PushError();
|
||||
SDL_QuitSubSystem(SDL_INIT_EVENTS);
|
||||
SDL_PopError();
|
||||
goto quit_and_error;
|
||||
}
|
||||
} else {
|
||||
@@ -381,7 +383,9 @@ bool SDL_InitSubSystem(SDL_InitFlags flags)
|
||||
SDL_IncrementSubsystemRefCount(SDL_INIT_AUDIO);
|
||||
if (!SDL_InitAudio(NULL)) {
|
||||
SDL_DecrementSubsystemRefCount(SDL_INIT_AUDIO);
|
||||
SDL_PushError();
|
||||
SDL_QuitSubSystem(SDL_INIT_EVENTS);
|
||||
SDL_PopError();
|
||||
goto quit_and_error;
|
||||
}
|
||||
} else {
|
||||
@@ -406,7 +410,9 @@ bool SDL_InitSubSystem(SDL_InitFlags flags)
|
||||
SDL_IncrementSubsystemRefCount(SDL_INIT_JOYSTICK);
|
||||
if (!SDL_InitJoysticks()) {
|
||||
SDL_DecrementSubsystemRefCount(SDL_INIT_JOYSTICK);
|
||||
SDL_PushError();
|
||||
SDL_QuitSubSystem(SDL_INIT_EVENTS);
|
||||
SDL_PopError();
|
||||
goto quit_and_error;
|
||||
}
|
||||
} else {
|
||||
@@ -430,7 +436,9 @@ bool SDL_InitSubSystem(SDL_InitFlags flags)
|
||||
SDL_IncrementSubsystemRefCount(SDL_INIT_GAMEPAD);
|
||||
if (!SDL_InitGamepads()) {
|
||||
SDL_DecrementSubsystemRefCount(SDL_INIT_GAMEPAD);
|
||||
SDL_PushError();
|
||||
SDL_QuitSubSystem(SDL_INIT_JOYSTICK);
|
||||
SDL_PopError();
|
||||
goto quit_and_error;
|
||||
}
|
||||
} else {
|
||||
@@ -493,7 +501,9 @@ bool SDL_InitSubSystem(SDL_InitFlags flags)
|
||||
SDL_IncrementSubsystemRefCount(SDL_INIT_CAMERA);
|
||||
if (!SDL_CameraInit(NULL)) {
|
||||
SDL_DecrementSubsystemRefCount(SDL_INIT_CAMERA);
|
||||
SDL_PushError();
|
||||
SDL_QuitSubSystem(SDL_INIT_EVENTS);
|
||||
SDL_PopError();
|
||||
goto quit_and_error;
|
||||
}
|
||||
} else {
|
||||
@@ -511,7 +521,11 @@ bool SDL_InitSubSystem(SDL_InitFlags flags)
|
||||
return SDL_ClearError();
|
||||
|
||||
quit_and_error:
|
||||
SDL_QuitSubSystem(flags_initialized);
|
||||
{
|
||||
SDL_PushError();
|
||||
SDL_QuitSubSystem(flags_initialized);
|
||||
SDL_PopError();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -639,7 +653,7 @@ void SDL_Quit(void)
|
||||
SDL_bInMainQuit = true;
|
||||
|
||||
// Quit all subsystems
|
||||
#ifdef SDL_VIDEO_DRIVER_WINDOWS
|
||||
#ifdef SDL_PLATFORM_WINDOWS
|
||||
SDL_HelperWindowDestroy();
|
||||
#endif
|
||||
SDL_QuitSubSystem(SDL_INIT_EVERYTHING);
|
||||
|
@@ -34,15 +34,7 @@
|
||||
#endif
|
||||
|
||||
#ifdef SDL_PLATFORM_EMSCRIPTEN
|
||||
#include <emscripten.h>
|
||||
// older Emscriptens don't have this, but we need to for wasm64 compatibility.
|
||||
#ifndef MAIN_THREAD_EM_ASM_PTR
|
||||
#ifdef __wasm64__
|
||||
#error You need to upgrade your Emscripten compiler to support wasm64
|
||||
#else
|
||||
#define MAIN_THREAD_EM_ASM_PTR MAIN_THREAD_EM_ASM_INT
|
||||
#endif
|
||||
#endif
|
||||
#include <emscripten.h>
|
||||
#endif
|
||||
|
||||
// The size of the stack buffer to use for rendering assert messages.
|
||||
@@ -252,7 +244,7 @@ static SDL_AssertState SDLCALL SDL_PromptAssertion(const SDL_AssertData *data, v
|
||||
for (;;) {
|
||||
bool okay = true;
|
||||
/* *INDENT-OFF* */ // clang-format off
|
||||
char *buf = (char *) MAIN_THREAD_EM_ASM_PTR({
|
||||
int reply = MAIN_THREAD_EM_ASM_INT({
|
||||
var str =
|
||||
UTF8ToString($0) + '\n\n' +
|
||||
'Abort/Retry/Ignore/AlwaysIgnore? [ariA] :';
|
||||
@@ -260,26 +252,32 @@ static SDL_AssertState SDLCALL SDL_PromptAssertion(const SDL_AssertData *data, v
|
||||
if (reply === null) {
|
||||
reply = "i";
|
||||
}
|
||||
return allocate(intArrayFromString(reply), 'i8', ALLOC_NORMAL);
|
||||
return reply.length === 1 ? reply.charCodeAt(0) : -1;
|
||||
}, message);
|
||||
/* *INDENT-ON* */ // clang-format on
|
||||
|
||||
if (SDL_strcmp(buf, "a") == 0) {
|
||||
switch (reply) {
|
||||
case 'a':
|
||||
state = SDL_ASSERTION_ABORT;
|
||||
break;
|
||||
#if 0 // (currently) no break functionality on Emscripten
|
||||
} else if (SDL_strcmp(buf, "b") == 0) {
|
||||
case 'b':
|
||||
state = SDL_ASSERTION_BREAK;
|
||||
break;
|
||||
#endif
|
||||
} else if (SDL_strcmp(buf, "r") == 0) {
|
||||
case 'r':
|
||||
state = SDL_ASSERTION_RETRY;
|
||||
} else if (SDL_strcmp(buf, "i") == 0) {
|
||||
break;
|
||||
case 'i':
|
||||
state = SDL_ASSERTION_IGNORE;
|
||||
} else if (SDL_strcmp(buf, "A") == 0) {
|
||||
break;
|
||||
case 'A':
|
||||
state = SDL_ASSERTION_ALWAYS_IGNORE;
|
||||
} else {
|
||||
break;
|
||||
default:
|
||||
okay = false;
|
||||
break;
|
||||
}
|
||||
free(buf); // This should NOT be SDL_free()
|
||||
|
||||
if (okay) {
|
||||
break;
|
||||
|
@@ -46,4 +46,16 @@ typedef struct SDL_error
|
||||
// Defined in SDL_thread.c
|
||||
extern SDL_error *SDL_GetErrBuf(bool create);
|
||||
|
||||
// Macros to save and restore error values
|
||||
#define SDL_PushError() \
|
||||
char *saved_error = SDL_strdup(SDL_GetError())
|
||||
|
||||
#define SDL_PopError() \
|
||||
do { \
|
||||
if (saved_error) { \
|
||||
SDL_SetError("%s", saved_error); \
|
||||
SDL_free(saved_error); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#endif // SDL_error_c_h_
|
||||
|
@@ -19,34 +19,6 @@
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
#include "SDL_internal.h"
|
||||
#include "SDL_hashtable.h"
|
||||
|
||||
// XXX: We can't use SDL_assert here because it's going to call into hashtable code
|
||||
#ifdef NDEBUG
|
||||
#define HT_ASSERT(x) (void)(0)
|
||||
#else
|
||||
#if (defined(_WIN32) || defined(SDL_PLATFORM_CYGWIN)) && !defined(SDL_PLATFORM_XBOXONE) && !defined(SDL_PLATFORM_XBOXSERIES)
|
||||
#include <windows.h>
|
||||
#endif
|
||||
/* This is not declared in any header, although it is shared between some
|
||||
parts of SDL, because we don't want anything calling it without an
|
||||
extremely good reason. */
|
||||
extern SDL_NORETURN void SDL_ExitProcess(int exitcode);
|
||||
static void HT_ASSERT_FAIL(const char *msg)
|
||||
{
|
||||
const char *caption = "SDL_HashTable Assertion Failure!";
|
||||
(void)caption;
|
||||
#if (defined(_WIN32) || defined(SDL_PLATFORM_CYGWIN)) && !defined(SDL_PLATFORM_XBOXONE) && !defined(SDL_PLATFORM_XBOXSERIES)
|
||||
MessageBoxA(NULL, msg, caption, MB_OK | MB_ICONERROR);
|
||||
#elif defined(HAVE_STDIO_H)
|
||||
fprintf(stderr, "\n\n%s\n%s\n\n", caption, msg);
|
||||
fflush(stderr);
|
||||
#endif
|
||||
SDL_TriggerBreakpoint();
|
||||
SDL_ExitProcess(-1);
|
||||
}
|
||||
#define HT_ASSERT(x) if (!(x)) HT_ASSERT_FAIL("SDL_HashTable Assertion Failure: " #x)
|
||||
#endif
|
||||
|
||||
typedef struct SDL_HashItem
|
||||
{
|
||||
@@ -67,47 +39,49 @@ SDL_COMPILE_TIME_ASSERT(sizeof_SDL_HashItem, sizeof(SDL_HashItem) <= MAX_HASHITE
|
||||
|
||||
struct SDL_HashTable
|
||||
{
|
||||
SDL_RWLock *lock;
|
||||
SDL_RWLock *lock; // NULL if not created threadsafe
|
||||
SDL_HashItem *table;
|
||||
SDL_HashTable_HashFn hash;
|
||||
SDL_HashTable_KeyMatchFn keymatch;
|
||||
SDL_HashTable_NukeFn nuke;
|
||||
void *data;
|
||||
SDL_HashCallback hash;
|
||||
SDL_HashKeyMatchCallback keymatch;
|
||||
SDL_HashDestroyCallback destroy;
|
||||
void *userdata;
|
||||
Uint32 hash_mask;
|
||||
Uint32 max_probe_len;
|
||||
Uint32 num_occupied_slots;
|
||||
bool stackable;
|
||||
};
|
||||
|
||||
SDL_HashTable *SDL_CreateHashTable(void *data,
|
||||
Uint32 num_buckets,
|
||||
SDL_HashTable_HashFn hashfn,
|
||||
SDL_HashTable_KeyMatchFn keymatchfn,
|
||||
SDL_HashTable_NukeFn nukefn,
|
||||
bool threadsafe,
|
||||
bool stackable)
|
||||
|
||||
static Uint32 CalculateHashBucketsFromEstimate(int estimated_capacity)
|
||||
{
|
||||
SDL_HashTable *table;
|
||||
|
||||
// num_buckets must be a power of two so we can derive the bucket index with just a bit-and.
|
||||
if ((num_buckets < 1) || !SDL_HasExactlyOneBitSet32(num_buckets)) {
|
||||
SDL_SetError("num_buckets must be a power of two");
|
||||
return NULL;
|
||||
if (estimated_capacity <= 0) {
|
||||
return 4; // start small, grow as necessary.
|
||||
}
|
||||
|
||||
if (num_buckets > MAX_HASHTABLE_SIZE) {
|
||||
SDL_SetError("num_buckets is too large");
|
||||
return NULL;
|
||||
const Uint32 estimated32 = (Uint32) estimated_capacity;
|
||||
Uint32 buckets = ((Uint32) 1) << SDL_MostSignificantBitIndex32(estimated32);
|
||||
if (!SDL_HasExactlyOneBitSet32(estimated32)) {
|
||||
buckets <<= 1; // need next power of two up to fit overflow capacity bits.
|
||||
}
|
||||
|
||||
table = (SDL_HashTable *)SDL_calloc(1, sizeof(SDL_HashTable));
|
||||
return SDL_min(buckets, MAX_HASHTABLE_SIZE);
|
||||
}
|
||||
|
||||
SDL_HashTable *SDL_CreateHashTable(int estimated_capacity, bool threadsafe, SDL_HashCallback hash,
|
||||
SDL_HashKeyMatchCallback keymatch,
|
||||
SDL_HashDestroyCallback destroy, void *userdata)
|
||||
{
|
||||
const Uint32 num_buckets = CalculateHashBucketsFromEstimate(estimated_capacity);
|
||||
SDL_HashTable *table = (SDL_HashTable *)SDL_calloc(1, sizeof(SDL_HashTable));
|
||||
if (!table) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (threadsafe) {
|
||||
// Don't fail if we can't create a lock (single threaded environment?)
|
||||
table->lock = SDL_CreateRWLock();
|
||||
if (!table->lock) {
|
||||
SDL_DestroyHashTable(table);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
table->table = (SDL_HashItem *)SDL_calloc(num_buckets, sizeof(SDL_HashItem));
|
||||
@@ -117,24 +91,22 @@ SDL_HashTable *SDL_CreateHashTable(void *data,
|
||||
}
|
||||
|
||||
table->hash_mask = num_buckets - 1;
|
||||
table->stackable = stackable;
|
||||
table->data = data;
|
||||
table->hash = hashfn;
|
||||
table->keymatch = keymatchfn;
|
||||
table->nuke = nukefn;
|
||||
table->userdata = userdata;
|
||||
table->hash = hash;
|
||||
table->keymatch = keymatch;
|
||||
table->destroy = destroy;
|
||||
return table;
|
||||
}
|
||||
|
||||
static SDL_INLINE Uint32 calc_hash(const SDL_HashTable *table, const void *key)
|
||||
{
|
||||
const Uint32 BitMixer = 0x9E3779B1u;
|
||||
return table->hash(key, table->data) * BitMixer;
|
||||
return table->hash(table->userdata, key) * BitMixer;
|
||||
}
|
||||
|
||||
static SDL_INLINE Uint32 get_probe_length(Uint32 zero_idx, Uint32 actual_idx, Uint32 num_buckets)
|
||||
{
|
||||
// returns the probe sequence length from zero_idx to actual_idx
|
||||
|
||||
if (actual_idx < zero_idx) {
|
||||
return num_buckets - zero_idx + actual_idx;
|
||||
}
|
||||
@@ -149,7 +121,7 @@ static SDL_HashItem *find_item(const SDL_HashTable *ht, const void *key, Uint32
|
||||
|
||||
SDL_HashItem *table = ht->table;
|
||||
|
||||
for (;;) {
|
||||
while (true) {
|
||||
SDL_HashItem *item = table + *i;
|
||||
Uint32 item_hash = item->hash;
|
||||
|
||||
@@ -157,12 +129,12 @@ static SDL_HashItem *find_item(const SDL_HashTable *ht, const void *key, Uint32
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (item_hash == hash && ht->keymatch(item->key, key, ht->data)) {
|
||||
if (item_hash == hash && ht->keymatch(ht->userdata, item->key, key)) {
|
||||
return item;
|
||||
}
|
||||
|
||||
Uint32 item_probe_len = item->probe_len;
|
||||
HT_ASSERT(item_probe_len == get_probe_length(item_hash & hash_mask, (Uint32)(item - table), hash_mask + 1));
|
||||
SDL_assert(item_probe_len == get_probe_length(item_hash & hash_mask, (Uint32)(item - table), hash_mask + 1));
|
||||
|
||||
if (*probe_len > item_probe_len) {
|
||||
return NULL;
|
||||
@@ -185,23 +157,23 @@ static SDL_HashItem *find_first_item(const SDL_HashTable *ht, const void *key, U
|
||||
|
||||
static SDL_HashItem *insert_item(SDL_HashItem *item_to_insert, SDL_HashItem *table, Uint32 hash_mask, Uint32 *max_probe_len_ptr)
|
||||
{
|
||||
const Uint32 num_buckets = hash_mask + 1;
|
||||
Uint32 idx = item_to_insert->hash & hash_mask;
|
||||
SDL_HashItem temp_item, *target = NULL;
|
||||
Uint32 num_buckets = hash_mask + 1;
|
||||
SDL_HashItem *target = NULL;
|
||||
SDL_HashItem temp_item;
|
||||
|
||||
for (;;) {
|
||||
while (true) {
|
||||
SDL_HashItem *candidate = table + idx;
|
||||
|
||||
if (!candidate->live) {
|
||||
// Found an empty slot. Put it here and we're done.
|
||||
|
||||
*candidate = *item_to_insert;
|
||||
|
||||
if (target == NULL) {
|
||||
target = candidate;
|
||||
}
|
||||
|
||||
Uint32 probe_len = get_probe_length(candidate->hash & hash_mask, idx, num_buckets);
|
||||
const Uint32 probe_len = get_probe_length(candidate->hash & hash_mask, idx, num_buckets);
|
||||
candidate->probe_len = probe_len;
|
||||
|
||||
if (*max_probe_len_ptr < probe_len) {
|
||||
@@ -211,9 +183,9 @@ static SDL_HashItem *insert_item(SDL_HashItem *item_to_insert, SDL_HashItem *tab
|
||||
break;
|
||||
}
|
||||
|
||||
Uint32 candidate_probe_len = candidate->probe_len;
|
||||
HT_ASSERT(candidate_probe_len == get_probe_length(candidate->hash & hash_mask, idx, num_buckets));
|
||||
Uint32 new_probe_len = get_probe_length(item_to_insert->hash & hash_mask, idx, num_buckets);
|
||||
const Uint32 candidate_probe_len = candidate->probe_len;
|
||||
SDL_assert(candidate_probe_len == get_probe_length(candidate->hash & hash_mask, idx, num_buckets));
|
||||
const Uint32 new_probe_len = get_probe_length(item_to_insert->hash & hash_mask, idx, num_buckets);
|
||||
|
||||
if (candidate_probe_len < new_probe_len) {
|
||||
// Robin Hood hashing: the item at idx has a better probe length than our item would at this position.
|
||||
@@ -229,7 +201,7 @@ static SDL_HashItem *insert_item(SDL_HashItem *item_to_insert, SDL_HashItem *tab
|
||||
|
||||
*item_to_insert = temp_item;
|
||||
|
||||
HT_ASSERT(new_probe_len == get_probe_length(candidate->hash & hash_mask, idx, num_buckets));
|
||||
SDL_assert(new_probe_len == get_probe_length(candidate->hash & hash_mask, idx, num_buckets));
|
||||
candidate->probe_len = new_probe_len;
|
||||
|
||||
if (*max_probe_len_ptr < new_probe_len) {
|
||||
@@ -245,17 +217,19 @@ static SDL_HashItem *insert_item(SDL_HashItem *item_to_insert, SDL_HashItem *tab
|
||||
|
||||
static void delete_item(SDL_HashTable *ht, SDL_HashItem *item)
|
||||
{
|
||||
Uint32 hash_mask = ht->hash_mask;
|
||||
const Uint32 hash_mask = ht->hash_mask;
|
||||
SDL_HashItem *table = ht->table;
|
||||
|
||||
if (ht->nuke) {
|
||||
ht->nuke(item->key, item->value, ht->data);
|
||||
if (ht->destroy) {
|
||||
ht->destroy(ht->userdata, item->key, item->value);
|
||||
}
|
||||
|
||||
SDL_assert(ht->num_occupied_slots > 0);
|
||||
ht->num_occupied_slots--;
|
||||
|
||||
Uint32 idx = (Uint32)(item - ht->table);
|
||||
|
||||
for (;;) {
|
||||
while (true) {
|
||||
idx = (idx + 1) & hash_mask;
|
||||
SDL_HashItem *next_item = table + idx;
|
||||
|
||||
@@ -266,22 +240,23 @@ static void delete_item(SDL_HashTable *ht, SDL_HashItem *item)
|
||||
|
||||
*item = *next_item;
|
||||
item->probe_len -= 1;
|
||||
HT_ASSERT(item->probe_len < ht->max_probe_len);
|
||||
SDL_assert(item->probe_len < ht->max_probe_len);
|
||||
item = next_item;
|
||||
}
|
||||
}
|
||||
|
||||
static bool resize(SDL_HashTable *ht, Uint32 new_size)
|
||||
{
|
||||
SDL_HashItem *old_table = ht->table;
|
||||
Uint32 old_size = ht->hash_mask + 1;
|
||||
Uint32 new_hash_mask = new_size - 1;
|
||||
const Uint32 new_hash_mask = new_size - 1;
|
||||
SDL_HashItem *new_table = SDL_calloc(new_size, sizeof(*new_table));
|
||||
|
||||
if (!new_table) {
|
||||
return false;
|
||||
}
|
||||
|
||||
SDL_HashItem *old_table = ht->table;
|
||||
const Uint32 old_size = ht->hash_mask + 1;
|
||||
|
||||
ht->max_probe_len = 0;
|
||||
ht->hash_mask = new_hash_mask;
|
||||
ht->table = new_table;
|
||||
@@ -299,14 +274,14 @@ static bool resize(SDL_HashTable *ht, Uint32 new_size)
|
||||
|
||||
static bool maybe_resize(SDL_HashTable *ht)
|
||||
{
|
||||
Uint32 capacity = ht->hash_mask + 1;
|
||||
const Uint32 capacity = ht->hash_mask + 1;
|
||||
|
||||
if (capacity >= MAX_HASHTABLE_SIZE) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Uint32 max_load_factor = 217; // range: 0-255; 217 is roughly 85%
|
||||
Uint32 resize_threshold = (Uint32)((max_load_factor * (Uint64)capacity) >> 8);
|
||||
const Uint32 max_load_factor = 217; // range: 0-255; 217 is roughly 85%
|
||||
const Uint32 resize_threshold = (Uint32)((max_load_factor * (Uint64)capacity) >> 8);
|
||||
|
||||
if (ht->num_occupied_slots > resize_threshold) {
|
||||
return resize(ht, capacity * 2);
|
||||
@@ -315,72 +290,66 @@ static bool maybe_resize(SDL_HashTable *ht)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SDL_InsertIntoHashTable(SDL_HashTable *table, const void *key, const void *value)
|
||||
bool SDL_InsertIntoHashTable(SDL_HashTable *table, const void *key, const void *value, bool replace)
|
||||
{
|
||||
SDL_HashItem *item;
|
||||
Uint32 hash;
|
||||
if (!table) {
|
||||
return SDL_InvalidParamError("table");
|
||||
}
|
||||
|
||||
bool result = false;
|
||||
|
||||
if (!table) {
|
||||
return false;
|
||||
SDL_LockRWLockForWriting(table->lock);
|
||||
|
||||
const Uint32 hash = calc_hash(table, key);
|
||||
SDL_HashItem *item = find_first_item(table, key, hash);
|
||||
bool do_insert = true;
|
||||
|
||||
if (item) {
|
||||
if (replace) {
|
||||
delete_item(table, item);
|
||||
} else {
|
||||
SDL_SetError("key already exists and replace is disabled");
|
||||
do_insert = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (table->lock) {
|
||||
SDL_LockRWLockForWriting(table->lock);
|
||||
if (do_insert) {
|
||||
SDL_HashItem new_item;
|
||||
new_item.key = key;
|
||||
new_item.value = value;
|
||||
new_item.hash = hash;
|
||||
new_item.live = true;
|
||||
new_item.probe_len = 0;
|
||||
|
||||
table->num_occupied_slots++;
|
||||
|
||||
if (!maybe_resize(table)) {
|
||||
table->num_occupied_slots--;
|
||||
} else {
|
||||
// This never returns NULL
|
||||
insert_item(&new_item, table->table, table->hash_mask, &table->max_probe_len);
|
||||
result = true;
|
||||
}
|
||||
}
|
||||
|
||||
hash = calc_hash(table, key);
|
||||
item = find_first_item(table, key, hash);
|
||||
|
||||
if (item && !table->stackable) {
|
||||
// Allow overwrites, this might have been inserted on another thread
|
||||
delete_item(table, item);
|
||||
}
|
||||
|
||||
SDL_HashItem new_item;
|
||||
new_item.key = key;
|
||||
new_item.value = value;
|
||||
new_item.hash = hash;
|
||||
new_item.live = true;
|
||||
new_item.probe_len = 0;
|
||||
|
||||
table->num_occupied_slots++;
|
||||
|
||||
if (!maybe_resize(table)) {
|
||||
table->num_occupied_slots--;
|
||||
goto done;
|
||||
}
|
||||
|
||||
// This never returns NULL
|
||||
insert_item(&new_item, table->table, table->hash_mask, &table->max_probe_len);
|
||||
result = true;
|
||||
|
||||
done:
|
||||
if (table->lock) {
|
||||
SDL_UnlockRWLock(table->lock);
|
||||
}
|
||||
SDL_UnlockRWLock(table->lock);
|
||||
return result;
|
||||
}
|
||||
|
||||
bool SDL_FindInHashTable(const SDL_HashTable *table, const void *key, const void **value)
|
||||
{
|
||||
Uint32 hash;
|
||||
SDL_HashItem *i;
|
||||
bool result = false;
|
||||
|
||||
if (!table) {
|
||||
if (value) {
|
||||
*value = NULL;
|
||||
}
|
||||
return false;
|
||||
return SDL_InvalidParamError("table");
|
||||
}
|
||||
|
||||
if (table->lock) {
|
||||
SDL_LockRWLockForReading(table->lock);
|
||||
}
|
||||
SDL_LockRWLockForReading(table->lock);
|
||||
|
||||
hash = calc_hash(table, key);
|
||||
i = find_first_item(table, key, hash);
|
||||
bool result = false;
|
||||
const Uint32 hash = calc_hash(table, key);
|
||||
SDL_HashItem *i = find_first_item(table, key, hash);
|
||||
if (i) {
|
||||
if (value) {
|
||||
*value = i->value;
|
||||
@@ -388,156 +357,91 @@ bool SDL_FindInHashTable(const SDL_HashTable *table, const void *key, const void
|
||||
result = true;
|
||||
}
|
||||
|
||||
if (table->lock) {
|
||||
SDL_UnlockRWLock(table->lock);
|
||||
}
|
||||
SDL_UnlockRWLock(table->lock);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool SDL_RemoveFromHashTable(SDL_HashTable *table, const void *key)
|
||||
{
|
||||
Uint32 hash;
|
||||
SDL_HashItem *item;
|
||||
bool result = false;
|
||||
|
||||
if (!table) {
|
||||
return false;
|
||||
return SDL_InvalidParamError("table");
|
||||
}
|
||||
|
||||
if (table->lock) {
|
||||
SDL_LockRWLockForWriting(table->lock);
|
||||
SDL_LockRWLockForWriting(table->lock);
|
||||
|
||||
bool result = false;
|
||||
const Uint32 hash = calc_hash(table, key);
|
||||
SDL_HashItem *item = find_first_item(table, key, hash);
|
||||
if (item) {
|
||||
delete_item(table, item);
|
||||
result = true;
|
||||
}
|
||||
|
||||
// FIXME: what to do for stacking hashtables?
|
||||
// The original code removes just one item.
|
||||
// This hashtable happens to preserve the insertion order of multi-value keys,
|
||||
// so deleting the first one will always delete the least-recently inserted one.
|
||||
// But maybe it makes more sense to remove all matching items?
|
||||
|
||||
hash = calc_hash(table, key);
|
||||
item = find_first_item(table, key, hash);
|
||||
if (!item) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
delete_item(table, item);
|
||||
result = true;
|
||||
|
||||
done:
|
||||
if (table->lock) {
|
||||
SDL_UnlockRWLock(table->lock);
|
||||
}
|
||||
SDL_UnlockRWLock(table->lock);
|
||||
return result;
|
||||
}
|
||||
|
||||
bool SDL_IterateHashTableKey(const SDL_HashTable *table, const void *key, const void **_value, void **iter)
|
||||
bool SDL_IterateHashTable(const SDL_HashTable *table, SDL_HashTableIterateCallback callback, void *userdata)
|
||||
{
|
||||
SDL_HashItem *item = (SDL_HashItem *)*iter;
|
||||
|
||||
if (!table) {
|
||||
return false;
|
||||
return SDL_InvalidParamError("table");
|
||||
} else if (!callback) {
|
||||
return SDL_InvalidParamError("callback");
|
||||
}
|
||||
|
||||
Uint32 i, probe_len, hash;
|
||||
|
||||
if (item) {
|
||||
HT_ASSERT(item >= table->table);
|
||||
HT_ASSERT(item < table->table + (table->hash_mask + 1));
|
||||
|
||||
hash = item->hash;
|
||||
probe_len = item->probe_len + 1;
|
||||
i = ((Uint32)(item - table->table) + 1) & table->hash_mask;
|
||||
item = table->table + i;
|
||||
} else {
|
||||
hash = calc_hash(table, key);
|
||||
i = hash & table->hash_mask;
|
||||
probe_len = 0;
|
||||
}
|
||||
|
||||
item = find_item(table, key, hash, &i, &probe_len);
|
||||
|
||||
if (!item) {
|
||||
*_value = NULL;
|
||||
return false;
|
||||
}
|
||||
|
||||
*_value = item->value;
|
||||
*iter = item;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SDL_IterateHashTable(const SDL_HashTable *table, const void **_key, const void **_value, void **iter)
|
||||
{
|
||||
SDL_HashItem *item = (SDL_HashItem *)*iter;
|
||||
|
||||
if (!table) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!item) {
|
||||
item = table->table;
|
||||
} else {
|
||||
item++;
|
||||
}
|
||||
|
||||
HT_ASSERT(item >= table->table);
|
||||
SDL_LockRWLockForReading(table->lock);
|
||||
SDL_HashItem *end = table->table + (table->hash_mask + 1);
|
||||
Uint32 num_iterated = 0;
|
||||
|
||||
while (item < end && !item->live) {
|
||||
++item;
|
||||
}
|
||||
|
||||
HT_ASSERT(item <= end);
|
||||
|
||||
if (item == end) {
|
||||
if (_key) {
|
||||
*_key = NULL;
|
||||
for (SDL_HashItem *item = table->table; item < end; item++) {
|
||||
if (item->live) {
|
||||
if (!callback(userdata, table, item->key, item->value)) {
|
||||
break; // callback requested iteration stop.
|
||||
} else if (++num_iterated >= table->num_occupied_slots) {
|
||||
break; // we can drop out early because we've seen all the live items.
|
||||
}
|
||||
}
|
||||
if (_value) {
|
||||
*_value = NULL;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
if (_key) {
|
||||
*_key = item->key;
|
||||
}
|
||||
if (_value) {
|
||||
*_value = item->value;
|
||||
}
|
||||
*iter = item;
|
||||
|
||||
SDL_UnlockRWLock(table->lock);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SDL_HashTableEmpty(SDL_HashTable *table)
|
||||
{
|
||||
return !(table && table->num_occupied_slots);
|
||||
if (!table) {
|
||||
return SDL_InvalidParamError("table");
|
||||
}
|
||||
|
||||
SDL_LockRWLockForReading(table->lock);
|
||||
const bool retval = (table->num_occupied_slots == 0);
|
||||
SDL_UnlockRWLock(table->lock);
|
||||
return retval;
|
||||
}
|
||||
|
||||
static void nuke_all(SDL_HashTable *table)
|
||||
{
|
||||
void *data = table->data;
|
||||
SDL_HashItem *end = table->table + (table->hash_mask + 1);
|
||||
SDL_HashItem *i;
|
||||
|
||||
for (i = table->table; i < end; ++i) {
|
||||
if (i->live) {
|
||||
table->nuke(i->key, i->value, data);
|
||||
static void destroy_all(SDL_HashTable *table)
|
||||
{
|
||||
SDL_HashDestroyCallback destroy = table->destroy;
|
||||
if (destroy) {
|
||||
void *userdata = table->userdata;
|
||||
SDL_HashItem *end = table->table + (table->hash_mask + 1);
|
||||
for (SDL_HashItem *i = table->table; i < end; ++i) {
|
||||
if (i->live) {
|
||||
i->live = false;
|
||||
destroy(userdata, i->key, i->value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SDL_EmptyHashTable(SDL_HashTable *table)
|
||||
void SDL_ClearHashTable(SDL_HashTable *table)
|
||||
{
|
||||
if (table) {
|
||||
SDL_LockRWLockForWriting(table->lock);
|
||||
{
|
||||
if (table->nuke) {
|
||||
nuke_all(table);
|
||||
}
|
||||
|
||||
destroy_all(table);
|
||||
SDL_memset(table->table, 0, sizeof(*table->table) * (table->hash_mask + 1));
|
||||
table->num_occupied_slots = 0;
|
||||
}
|
||||
@@ -548,9 +452,10 @@ void SDL_EmptyHashTable(SDL_HashTable *table)
|
||||
void SDL_DestroyHashTable(SDL_HashTable *table)
|
||||
{
|
||||
if (table) {
|
||||
SDL_EmptyHashTable(table);
|
||||
|
||||
SDL_DestroyRWLock(table->lock);
|
||||
destroy_all(table);
|
||||
if (table->lock) {
|
||||
SDL_DestroyRWLock(table->lock);
|
||||
}
|
||||
SDL_free(table->table);
|
||||
SDL_free(table);
|
||||
}
|
||||
@@ -566,26 +471,26 @@ static SDL_INLINE Uint32 hash_string_djbxor(const char *str, size_t len)
|
||||
return hash;
|
||||
}
|
||||
|
||||
Uint32 SDL_HashPointer(const void *key, void *unused)
|
||||
Uint32 SDL_HashPointer(void *unused, const void *key)
|
||||
{
|
||||
(void)unused;
|
||||
return SDL_murmur3_32(&key, sizeof(key), 0);
|
||||
}
|
||||
|
||||
bool SDL_KeyMatchPointer(const void *a, const void *b, void *unused)
|
||||
bool SDL_KeyMatchPointer(void *unused, const void *a, const void *b)
|
||||
{
|
||||
(void)unused;
|
||||
return (a == b);
|
||||
}
|
||||
|
||||
Uint32 SDL_HashString(const void *key, void *unused)
|
||||
Uint32 SDL_HashString(void *unused, const void *key)
|
||||
{
|
||||
(void)unused;
|
||||
const char *str = (const char *)key;
|
||||
return hash_string_djbxor(str, SDL_strlen(str));
|
||||
}
|
||||
|
||||
bool SDL_KeyMatchString(const void *a, const void *b, void *unused)
|
||||
bool SDL_KeyMatchString(void *unused, const void *a, const void *b)
|
||||
{
|
||||
const char *a_string = (const char *)a;
|
||||
const char *b_string = (const char *)b;
|
||||
@@ -604,26 +509,33 @@ bool SDL_KeyMatchString(const void *a, const void *b, void *unused)
|
||||
// We assume we can fit the ID in the key directly
|
||||
SDL_COMPILE_TIME_ASSERT(SDL_HashID_KeySize, sizeof(Uint32) <= sizeof(const void *));
|
||||
|
||||
Uint32 SDL_HashID(const void *key, void *unused)
|
||||
Uint32 SDL_HashID(void *unused, const void *key)
|
||||
{
|
||||
(void)unused;
|
||||
return (Uint32)(uintptr_t)key;
|
||||
}
|
||||
|
||||
bool SDL_KeyMatchID(const void *a, const void *b, void *unused)
|
||||
bool SDL_KeyMatchID(void *unused, const void *a, const void *b)
|
||||
{
|
||||
(void)unused;
|
||||
return (a == b);
|
||||
}
|
||||
|
||||
void SDL_NukeFreeKey(const void *key, const void *value, void *unused)
|
||||
void SDL_DestroyHashKeyAndValue(void *unused, const void *key, const void *value)
|
||||
{
|
||||
(void)unused;
|
||||
SDL_free((void *)key);
|
||||
SDL_free((void *)value);
|
||||
}
|
||||
|
||||
void SDL_DestroyHashKey(void *unused, const void *key, const void *value)
|
||||
{
|
||||
(void)value;
|
||||
(void)unused;
|
||||
SDL_free((void *)key);
|
||||
}
|
||||
|
||||
void SDL_NukeFreeValue(const void *key, const void *value, void *unused)
|
||||
void SDL_DestroyHashValue(void *unused, const void *key, const void *value)
|
||||
{
|
||||
(void)key;
|
||||
(void)unused;
|
||||
|
@@ -18,61 +18,616 @@
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
/* this is over-documented because it was almost a public API. Leaving the
|
||||
full docs here in case it _does_ become public some day. */
|
||||
|
||||
/* WIKI CATEGORY: HashTable */
|
||||
|
||||
/**
|
||||
* # CategoryHashTable
|
||||
*
|
||||
* SDL offers a hash table implementation, as a convenience for C code that
|
||||
* needs efficient organization and access of arbitrary data.
|
||||
*
|
||||
* Hash tables are a popular data structure, designed to make it quick to
|
||||
* store and look up arbitrary data. Data is stored with an associated "key."
|
||||
* While one would look up an element of an array with an index, a hash table
|
||||
* uses a unique key to find an element later.
|
||||
*
|
||||
* A key can be anything, as long as its unique and in a format that the table
|
||||
* understands. For example, it's popular to use strings as keys: the key
|
||||
* might be a username, and it is used to lookup account information for that
|
||||
* user, etc.
|
||||
*
|
||||
* Hash tables are named because they "hash" their keys down into simple
|
||||
* integers that can be used to efficiently organize and access the associated
|
||||
* data.
|
||||
*
|
||||
* As this is a C API, there is one generic interface that is intended to work
|
||||
* with different data types. This can be a little awkward to set up, but is
|
||||
* easy to use after that.
|
||||
*
|
||||
* Hashtables are generated by a call to SDL_CreateHashTable(). This function
|
||||
* requires several callbacks to be provided (for hashing keys, comparing
|
||||
* entries, and cleaning up entries when removed). These are necessary to
|
||||
* allow the hash to manage any arbitrary data type.
|
||||
*
|
||||
* Once a hash table is created, the common tasks are inserting data into the
|
||||
* table, (SDL_InsertIntoHashTable), looking up previously inserted data
|
||||
* (SDL_FindInHashTable), and removing data (SDL_RemoveFromHashTable and
|
||||
* SDL_ClearHashTable). Less common but still useful is the ability to
|
||||
* iterate through all the items in the table (SDL_IterateHashTable).
|
||||
*
|
||||
* The underlying hash table implementation is always subject to change, but
|
||||
* at the time of writing, it uses open addressing and Robin Hood hashing.
|
||||
* The technical details are explained [here](https://github.com/libsdl-org/SDL/pull/10897).
|
||||
*
|
||||
* Hashtables keep an SDL_RWLock internally, so multiple threads can perform
|
||||
* hash lookups in parallel, while changes to the table will safely serialize
|
||||
* access between threads.
|
||||
*
|
||||
* SDL provides a layer on top of this hash table implementation that might be
|
||||
* more pleasant to use. SDL_PropertiesID maps a string to arbitrary data of
|
||||
* various types in the same table, which could be both easier to use and more
|
||||
* flexible. Refer to [CategoryProperties](CategoryProperties) for details.
|
||||
*/
|
||||
|
||||
#ifndef SDL_hashtable_h_
|
||||
#define SDL_hashtable_h_
|
||||
|
||||
// this is not (currently) a public API. But maybe it should be!
|
||||
#include <SDL3/SDL_stdinc.h>
|
||||
|
||||
struct SDL_HashTable;
|
||||
#include <SDL3/SDL_begin_code.h>
|
||||
/* Set up for C function definitions, even when using C++ */
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* The opaque type that represents a hash table.
|
||||
*
|
||||
* This is hidden behind an opaque pointer because not only does the table
|
||||
* need to store arbitrary data types, but the hash table implementation may
|
||||
* change in the future.
|
||||
*
|
||||
* \since This struct is available since SDL 3.4.0.
|
||||
*
|
||||
* \sa SDL_CreateHashTable
|
||||
*/
|
||||
typedef struct SDL_HashTable SDL_HashTable;
|
||||
typedef Uint32 (*SDL_HashTable_HashFn)(const void *key, void *data);
|
||||
typedef bool (*SDL_HashTable_KeyMatchFn)(const void *a, const void *b, void *data);
|
||||
typedef void (*SDL_HashTable_NukeFn)(const void *key, const void *value, void *data);
|
||||
|
||||
extern SDL_HashTable *SDL_CreateHashTable(void *data,
|
||||
Uint32 num_buckets,
|
||||
SDL_HashTable_HashFn hashfn,
|
||||
SDL_HashTable_KeyMatchFn keymatchfn,
|
||||
SDL_HashTable_NukeFn nukefn,
|
||||
bool threadsafe,
|
||||
bool stackable);
|
||||
/**
|
||||
* A function pointer representing a hash table hashing callback.
|
||||
*
|
||||
* This is called by SDL_HashTable when it needs to look up a key in
|
||||
* its dataset. It generates a hash value from that key, and then uses that
|
||||
* value as a basis for an index into an internal array.
|
||||
*
|
||||
* There are no rules on what hashing algorithm is used, so long as it
|
||||
* can produce a reliable 32-bit value from `key`, and ideally distributes
|
||||
* those values well across the 32-bit value space. The quality of a
|
||||
* hashing algorithm is directly related to how well a hash table performs.
|
||||
*
|
||||
* Hashing can be a complicated subject, and often times what works best
|
||||
* for one dataset will be suboptimal for another. There is a good discussion
|
||||
* of the field [on Wikipedia](https://en.wikipedia.org/wiki/Hash_function).
|
||||
*
|
||||
* Also: do you _need_ to write a hashing function? SDL provides generic
|
||||
* functions for strings (SDL_HashString), generic integer IDs (SDL_HashID),
|
||||
* and generic pointers (SDL_HashPointer). Often you should use one of these
|
||||
* before writing your own.
|
||||
*
|
||||
* \param userdata what was passed as `userdata` to SDL_CreateHashTable().
|
||||
* \param key the key to be hashed.
|
||||
* \returns a 32-bit value that represents a hash of `key`.
|
||||
*
|
||||
* \threadsafety This function must be thread safe if the hash table is used
|
||||
* from multiple threads at the same time.
|
||||
*
|
||||
* \since This datatype is available since SDL 3.4.0.
|
||||
*
|
||||
* \sa SDL_CreateHashTable
|
||||
* \sa SDL_HashString
|
||||
* \sa SDL_HashID
|
||||
* \sa SDL_HashPointer
|
||||
*/
|
||||
typedef Uint32 (SDLCALL *SDL_HashCallback)(void *userdata, const void *key);
|
||||
|
||||
// This function is thread-safe if the hashtable was created with threadsafe = true
|
||||
extern void SDL_EmptyHashTable(SDL_HashTable *table);
|
||||
|
||||
// This function is not thread-safe.
|
||||
/**
|
||||
* A function pointer representing a hash table matching callback.
|
||||
*
|
||||
* This is called by SDL_HashTable when it needs to look up a key in its
|
||||
* dataset. After hashing the key, it looks for items stored in relation to
|
||||
* that hash value. Since there can be more than one item found through the
|
||||
* same hash value, this function verifies a specific value is actually
|
||||
* correct before choosing it.
|
||||
*
|
||||
* So this function needs to compare the keys at `a` and `b` and decide if
|
||||
* they are actually the same.
|
||||
*
|
||||
* For example, if the keys are C strings, this function might just be:
|
||||
*
|
||||
* ```c
|
||||
* return (SDL_strcmp((const char *) a, const char *b) == 0);`
|
||||
* ```
|
||||
*
|
||||
* Also: do you _need_ to write a matching function? SDL provides generic
|
||||
* functions for strings (SDL_KeyMatchString), generic integer IDs
|
||||
* (SDL_KeyMatchID), and generic pointers (SDL_KeyMatchPointer). Often you
|
||||
* should use one of these before writing your own.
|
||||
*
|
||||
* \param userdata what was passed as `userdata` to SDL_CreateHashTable().
|
||||
* \param a the first key to be compared.
|
||||
* \param b the second key to be compared.
|
||||
* \returns true if two keys are identical, false otherwise.
|
||||
*
|
||||
* \threadsafety This function must be thread safe if the hash table is used
|
||||
* from multiple threads at the same time.
|
||||
*
|
||||
* \since This datatype is available since SDL 3.4.0.
|
||||
*
|
||||
* \sa SDL_CreateHashTable
|
||||
*/
|
||||
typedef bool (SDLCALL *SDL_HashKeyMatchCallback)(void *userdata, const void *a, const void *b);
|
||||
|
||||
|
||||
/**
|
||||
* A function pointer representing a hash table cleanup callback.
|
||||
*
|
||||
* This is called by SDL_HashTable when removing items from the hash, or
|
||||
* destroying the hash table. It is used to optionally deallocate the
|
||||
* key/value pairs.
|
||||
*
|
||||
* This is not required to do anything, if all the data in the table is
|
||||
* static or POD data, but it can also do more than a simple free: for
|
||||
* example, if the hash table is storing open files, it can close them here.
|
||||
* It can also free only the key or only the value; it depends on what the
|
||||
* hash table contains.
|
||||
*
|
||||
* \param userdata what was passed as `userdata` to SDL_CreateHashTable().
|
||||
* \param key the key to deallocate.
|
||||
* \param value the value to deallocate.
|
||||
*
|
||||
* \threadsafety This function must be thread safe if the hash table is used
|
||||
* from multiple threads at the same time.
|
||||
*
|
||||
* \since This datatype is available since SDL 3.4.0.
|
||||
*
|
||||
* \sa SDL_CreateHashTable
|
||||
*/
|
||||
typedef void (SDLCALL *SDL_HashDestroyCallback)(void *userdata, const void *key, const void *value);
|
||||
|
||||
|
||||
/**
|
||||
* A function pointer representing a hash table iterator callback.
|
||||
*
|
||||
* This function is called once for each key/value pair to be considered
|
||||
* when iterating a hash table.
|
||||
*
|
||||
* Iteration continues as long as there are more items to examine and this
|
||||
* callback continues to return true.
|
||||
*
|
||||
* Do not attempt to modify the hash table during this callback, as it will
|
||||
* cause incorrect behavior and possibly crashes.
|
||||
*
|
||||
* \param userdata what was passed as `userdata` to an iterator function.
|
||||
* \param table the hash table being iterated.
|
||||
* \param key the current key being iterated.
|
||||
* \param value the current value being iterated.
|
||||
* \returns true to keep iterating, false to stop iteration.
|
||||
*
|
||||
* \threadsafety A read lock is held during iteration, so other threads can
|
||||
* still access the the hash table, but threads attempting to
|
||||
* make changes will be blocked until iteration completes. If
|
||||
* this is a concern, do as little in the callback as possible
|
||||
* and finish iteration quickly.
|
||||
*
|
||||
* \since This datatype is available since SDL 3.4.0.
|
||||
*
|
||||
* \sa SDL_IterateHashTable
|
||||
*/
|
||||
typedef bool (SDLCALL *SDL_HashTableIterateCallback)(void *userdata, const SDL_HashTable *table, const void *key, const void *value);
|
||||
|
||||
|
||||
/**
|
||||
* Create a new hash table.
|
||||
*
|
||||
* To deal with different datatypes and needs of the caller, hash tables
|
||||
* require several callbacks that deal with some specifics: how to hash a key,
|
||||
* how to compare a key for equality, and how to clean up keys and values.
|
||||
* SDL provides a few generic functions that can be used for these callbacks:
|
||||
*
|
||||
* - SDL_HashString and SDL_KeyMatchString for C strings.
|
||||
* - SDL_HashPointer and SDL_KeyMatchPointer for generic pointers.
|
||||
* - SDL_HashID and SDL_KeyMatchID for generic (possibly small) integers.
|
||||
*
|
||||
* Oftentimes, these are all you need for any hash table, but depending on
|
||||
* your dataset, custom implementations might make more sense.
|
||||
*
|
||||
* You can specify an estimate of the number of items expected to be stored
|
||||
* in the table, which can help make the table run more efficiently. The table
|
||||
* will preallocate resources to accomodate this number of items, which is
|
||||
* most useful if you intend to fill the table with a lot of data right after
|
||||
* creating it. Otherwise, it might make more sense to specify the _minimum_
|
||||
* you expect the table to hold and let it grow as necessary from there. This
|
||||
* number is only a hint, and the table will be able to handle any amount of
|
||||
* data--as long as the system doesn't run out of resources--so a perfect
|
||||
* answer is not required. A value of 0 signifies no guess at all, and the
|
||||
* table will start small and reallocate as necessary; often this is the
|
||||
* correct thing to do.
|
||||
*
|
||||
* !!! FIXME: add note about `threadsafe` here. And update `threadsafety` tags.
|
||||
* !!! FIXME: note that `threadsafe` tables can't be recursively locked, so
|
||||
* !!! FIXME: you can't use `destroy` callbacks that might end up relocking.
|
||||
*
|
||||
* Note that SDL provides a higher-level option built on its hash tables:
|
||||
* SDL_PropertiesID lets you map strings to various datatypes, and this
|
||||
* might be easier to use. It only allows strings for keys, however. Those are
|
||||
* created with SDL_CreateProperties().
|
||||
*
|
||||
* The returned hash table should be destroyed with SDL_DestroyHashTable()
|
||||
* when no longer needed.
|
||||
*
|
||||
* \param estimated_capacity the approximate maximum number of items to be held
|
||||
* in the hash table, or 0 for no estimate.
|
||||
* \param threadsafe true to create an internal rwlock for this table.
|
||||
* \param hash the function to use to hash keys.
|
||||
* \param keymatch the function to use to compare keys.
|
||||
* \param destroy the function to use to clean up keys and values, may be NULL.
|
||||
* \param userdata a pointer that is passed to the callbacks.
|
||||
* \returns a newly-created hash table, or NULL if there was an error; call
|
||||
* SDL_GetError() for more information.
|
||||
*
|
||||
* \threadsafety It is safe to call this function from any thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.4.0.
|
||||
*
|
||||
* \sa SDL_DestroyHashTable
|
||||
*/
|
||||
extern SDL_HashTable * SDL_CreateHashTable(int estimated_capacity,
|
||||
bool threadsafe,
|
||||
SDL_HashCallback hash,
|
||||
SDL_HashKeyMatchCallback keymatch,
|
||||
SDL_HashDestroyCallback destroy,
|
||||
void *userdata);
|
||||
|
||||
|
||||
/**
|
||||
* Destroy a hash table.
|
||||
*
|
||||
* This will call the hash table's SDL_HashDestroyCallback for each item in
|
||||
* the table, removing all inserted items, before deallocating the table
|
||||
* itself.
|
||||
*
|
||||
* The table becomes invalid once this function is called, and no other thread
|
||||
* should be accessing this table once this function has started.
|
||||
*
|
||||
* \param table the hash table to destroy.
|
||||
*
|
||||
* \threadsafety It is safe to call this function from any thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.4.0.
|
||||
*/
|
||||
extern void SDL_DestroyHashTable(SDL_HashTable *table);
|
||||
|
||||
// This function is thread-safe if the hashtable was created with threadsafe = true
|
||||
extern bool SDL_InsertIntoHashTable(SDL_HashTable *table, const void *key, const void *value);
|
||||
/**
|
||||
* Add an item to a hash table.
|
||||
*
|
||||
* All keys in the table must be unique. If attempting to insert a key that
|
||||
* already exists in the hash table, what will be done depends on the
|
||||
* `replace` value:
|
||||
*
|
||||
* - If `replace` is false, this function will return false without modifying
|
||||
* the table.
|
||||
* - If `replace` is true, SDL will remove the previous item first, so the new
|
||||
* value is the only one associated with that key. This will call the hash
|
||||
* table's SDL_HashDestroyCallback for the previous item.
|
||||
*
|
||||
* \param table the hash table to insert into.
|
||||
* \param key the key of the new item to insert.
|
||||
* \param value the value of the new item to insert.
|
||||
* \param replace true if a duplicate key should replace the previous value.
|
||||
* \returns true if the new item was inserted, false otherwise.
|
||||
*
|
||||
* \threadsafety It is safe to call this function from any thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.4.0.
|
||||
*/
|
||||
extern bool SDL_InsertIntoHashTable(SDL_HashTable *table, const void *key, const void *value, bool replace);
|
||||
|
||||
// This function is thread-safe if the hashtable was created with threadsafe = true
|
||||
/**
|
||||
* Look up an item in a hash table.
|
||||
*
|
||||
* On return, the value associated with `key` is stored to `*value`.
|
||||
* If the key does not exist in the table, `*value` will be set to NULL.
|
||||
*
|
||||
* It is legal for `value` to be NULL, to not retrieve the key's value. In
|
||||
* this case, the return value is still useful for reporting if the key exists
|
||||
* in the table at all.
|
||||
*
|
||||
* \param table the hash table to search.
|
||||
* \param key the key to search for in the table.
|
||||
* \param value the found value will be stored here. Can be NULL.
|
||||
* \returns true if key exists in the table, false otherwise.
|
||||
*
|
||||
* \threadsafety It is safe to call this function from any thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.4.0.
|
||||
*
|
||||
* \sa SDL_InsertIntoHashTable
|
||||
*/
|
||||
extern bool SDL_FindInHashTable(const SDL_HashTable *table, const void *key, const void **value);
|
||||
|
||||
/**
|
||||
* Remove an item from a hash table.
|
||||
*
|
||||
* If there is an item that matches `key`, it is removed from the table. This
|
||||
* will call the hash table's SDL_HashDestroyCallback for the item to be
|
||||
* removed.
|
||||
*
|
||||
* \param table the hash table to remove from.
|
||||
* \param key the key of the item to remove from the table.
|
||||
* \returns true if a key was removed, false if the key was not found.
|
||||
*
|
||||
* \threadsafety It is safe to call this function from any thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.4.0.
|
||||
*/
|
||||
extern bool SDL_RemoveFromHashTable(SDL_HashTable *table, const void *key);
|
||||
|
||||
// This function is thread-safe if the hashtable was created with threadsafe = true
|
||||
extern bool SDL_FindInHashTable(const SDL_HashTable *table, const void *key, const void **_value);
|
||||
/**
|
||||
* Remove all items in a hash table.
|
||||
*
|
||||
* This will call the hash table's SDL_HashDestroyCallback for each item in
|
||||
* the table, removing all inserted items.
|
||||
*
|
||||
* When this function returns, the hash table will be empty.
|
||||
*
|
||||
* \param table the hash table to clear.
|
||||
*
|
||||
* \threadsafety It is safe to call this function from any thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.4.0.
|
||||
*/
|
||||
extern void SDL_ClearHashTable(SDL_HashTable *table);
|
||||
|
||||
// This function is thread-safe if the hashtable was created with threadsafe = true
|
||||
/**
|
||||
* Check if any items are currently stored in a hash table.
|
||||
*
|
||||
* If there are no items stored (the table is completely empty), this will
|
||||
* return true.
|
||||
*
|
||||
* \param table the hash table to check.
|
||||
* \returns true if the table is completely empty, false otherwise.
|
||||
*
|
||||
* \threadsafety It is safe to call this function from any thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.4.0.
|
||||
*
|
||||
* \sa SDL_ClearHashTable
|
||||
*/
|
||||
extern bool SDL_HashTableEmpty(SDL_HashTable *table);
|
||||
|
||||
// iterate all values for a specific key. This only makes sense if the hash is stackable. If not-stackable, just use SDL_FindInHashTable().
|
||||
// This function is not thread-safe, you should use external locking if you use this function
|
||||
extern bool SDL_IterateHashTableKey(const SDL_HashTable *table, const void *key, const void **_value, void **iter);
|
||||
/**
|
||||
* Iterate all key/value pairs in a hash table.
|
||||
*
|
||||
* This function will call `callback` once for each key/value pair in the
|
||||
* table, until either all pairs have been presented to the callback, or the
|
||||
* callback has returned false to signal it is done.
|
||||
*
|
||||
* There is no guarantee what order results will be returned in.
|
||||
*
|
||||
* \param table the hash table to iterate.
|
||||
* \param callback the function pointer to call for each value.
|
||||
* \param userdata a pointer that is passed to `callback`.
|
||||
* \returns true if iteration happened, false if not (bogus parameter, etc).
|
||||
*
|
||||
* \since This function is available since SDL 3.4.0.
|
||||
*/
|
||||
extern bool SDL_IterateHashTable(const SDL_HashTable *table, SDL_HashTableIterateCallback callback, void *userdata);
|
||||
|
||||
// iterate all key/value pairs in a hash (stackable hashes can have duplicate keys with multiple values).
|
||||
// This function is not thread-safe, you should use external locking if you use this function
|
||||
extern bool SDL_IterateHashTable(const SDL_HashTable *table, const void **_key, const void **_value, void **iter);
|
||||
|
||||
extern Uint32 SDL_HashPointer(const void *key, void *unused);
|
||||
extern bool SDL_KeyMatchPointer(const void *a, const void *b, void *unused);
|
||||
/* Helper functions for SDL_CreateHashTable callbacks... */
|
||||
|
||||
extern Uint32 SDL_HashString(const void *key, void *unused);
|
||||
extern bool SDL_KeyMatchString(const void *a, const void *b, void *unused);
|
||||
/**
|
||||
* Generate a hash from a generic pointer.
|
||||
*
|
||||
* The key is intended to be a unique pointer to any datatype.
|
||||
*
|
||||
* This is intended to be used as one of the callbacks to SDL_CreateHashTable,
|
||||
* if this is useful to the type of keys to be used with the hash table.
|
||||
*
|
||||
* Note that the implementation may change in the future; do not expect
|
||||
* the results to be stable vs future SDL releases. Use this in a hash table
|
||||
* in the current process and don't store them to disk for the future.
|
||||
*
|
||||
* \param unused this parameter is ignored.
|
||||
* \param key the key to hash as a generic pointer.
|
||||
* \returns a 32-bit hash of the key.
|
||||
*
|
||||
* \threadsafety It is safe to call this function from any thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.4.0.
|
||||
*
|
||||
* \sa SDL_CreateHashTable
|
||||
*/
|
||||
extern Uint32 SDL_HashPointer(void *unused, const void *key);
|
||||
|
||||
extern Uint32 SDL_HashID(const void *key, void *unused);
|
||||
extern bool SDL_KeyMatchID(const void *a, const void *b, void *unused);
|
||||
/**
|
||||
* Compare two generic pointers as hash table keys.
|
||||
*
|
||||
* This is intended to be used as one of the callbacks to SDL_CreateHashTable,
|
||||
* if this is useful to the type of keys to be used with the hash table.
|
||||
*
|
||||
* \param unused this parameter is ignored.
|
||||
* \param a the first generic pointer to compare.
|
||||
* \param b the second generic pointer to compare.
|
||||
* \returns true if the pointers are the same, false otherwise.
|
||||
*
|
||||
* \threadsafety It is safe to call this function from any thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.4.0.
|
||||
*
|
||||
* \sa SDL_CreateHashTable
|
||||
*/
|
||||
extern bool SDL_KeyMatchPointer(void *unused, const void *a, const void *b);
|
||||
|
||||
extern void SDL_NukeFreeKey(const void *key, const void *value, void *unused);
|
||||
extern void SDL_NukeFreeValue(const void *key, const void *value, void *unused);
|
||||
/**
|
||||
* Generate a hash from a C string.
|
||||
*
|
||||
* The key is intended to be a NULL-terminated string, in UTF-8 format.
|
||||
*
|
||||
* This is intended to be used as one of the callbacks to SDL_CreateHashTable,
|
||||
* if this is useful to the type of keys to be used with the hash table.
|
||||
*
|
||||
* Note that the implementation may change in the future; do not expect
|
||||
* the results to be stable vs future SDL releases. Use this in a hash table
|
||||
* in the current process and don't store them to disk for the future.
|
||||
*
|
||||
* \param unused this parameter is ignored.
|
||||
* \param key the key to hash as a generic pointer.
|
||||
* \returns a 32-bit hash of the key.
|
||||
*
|
||||
* \threadsafety It is safe to call this function from any thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.4.0.
|
||||
*
|
||||
* \sa SDL_CreateHashTable
|
||||
*/
|
||||
extern Uint32 SDL_HashString(void *unused, const void *key);
|
||||
|
||||
#endif // SDL_hashtable_h_
|
||||
/**
|
||||
* Compare two C strings as hash table keys.
|
||||
*
|
||||
* Strings will be compared in a case-sensitive manner. More specifically,
|
||||
* they'll be compared as NULL-terminated arrays of bytes.
|
||||
*
|
||||
* This is intended to be used as one of the callbacks to SDL_CreateHashTable,
|
||||
* if this is useful to the type of keys to be used with the hash table.
|
||||
*
|
||||
* \param unused this parameter is ignored.
|
||||
* \param a the first string to compare.
|
||||
* \param b the second string to compare.
|
||||
* \returns true if the strings are the same, false otherwise.
|
||||
*
|
||||
* \threadsafety It is safe to call this function from any thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.4.0.
|
||||
*
|
||||
* \sa SDL_CreateHashTable
|
||||
*/
|
||||
extern bool SDL_KeyMatchString(void *unused, const void *a, const void *b);
|
||||
|
||||
/**
|
||||
* Generate a hash from an integer ID.
|
||||
*
|
||||
* The key is intended to a unique integer, possibly within a small range.
|
||||
*
|
||||
* This is intended to be used as one of the callbacks to SDL_CreateHashTable,
|
||||
* if this is useful to the type of keys to be used with the hash table.
|
||||
*
|
||||
* Note that the implementation may change in the future; do not expect
|
||||
* the results to be stable vs future SDL releases. Use this in a hash table
|
||||
* in the current process and don't store them to disk for the future.
|
||||
*
|
||||
* \param unused this parameter is ignored.
|
||||
* \param key the key to hash as a generic pointer.
|
||||
* \returns a 32-bit hash of the key.
|
||||
*
|
||||
* \threadsafety It is safe to call this function from any thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.4.0.
|
||||
*
|
||||
* \sa SDL_CreateHashTable
|
||||
*/
|
||||
extern Uint32 SDL_HashID(void *unused, const void *key);
|
||||
|
||||
/**
|
||||
* Compare two integer IDs as hash table keys.
|
||||
*
|
||||
* This is intended to be used as one of the callbacks to SDL_CreateHashTable,
|
||||
* if this is useful to the type of keys to be used with the hash table.
|
||||
*
|
||||
* \param unused this parameter is ignored.
|
||||
* \param a the first ID to compare.
|
||||
* \param b the second ID to compare.
|
||||
* \returns true if the IDs are the same, false otherwise.
|
||||
*
|
||||
* \threadsafety It is safe to call this function from any thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.4.0.
|
||||
*
|
||||
* \sa SDL_CreateHashTable
|
||||
*/
|
||||
extern bool SDL_KeyMatchID(void *unused, const void *a, const void *b);
|
||||
|
||||
/**
|
||||
* Free both the key and value pointers of a hash table item.
|
||||
*
|
||||
* This is intended to be used as one of the callbacks to SDL_CreateHashTable,
|
||||
* if this is useful to the type of data to be used with the hash table.
|
||||
*
|
||||
* This literally calls `SDL_free(key);` and `SDL_free(value);`.
|
||||
*
|
||||
* \param unused this parameter is ignored.
|
||||
* \param key the key to be destroyed.
|
||||
* \param value the value to be destroyed.
|
||||
*
|
||||
* \threadsafety It is safe to call this function from any thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.4.0.
|
||||
*
|
||||
* \sa SDL_CreateHashTable
|
||||
*/
|
||||
extern void SDL_DestroyHashKeyAndValue(void *unused, const void *key, const void *value);
|
||||
|
||||
/**
|
||||
* Free just the value pointer of a hash table item.
|
||||
*
|
||||
* This is intended to be used as one of the callbacks to SDL_CreateHashTable,
|
||||
* if this is useful to the type of data to be used with the hash table.
|
||||
*
|
||||
* This literally calls `SDL_free(key);` and leaves `value` alone.
|
||||
*
|
||||
* \param unused this parameter is ignored.
|
||||
* \param key the key to be destroyed.
|
||||
* \param value the value to be destroyed.
|
||||
*
|
||||
* \threadsafety It is safe to call this function from any thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.4.0.
|
||||
*
|
||||
* \sa SDL_CreateHashTable
|
||||
*/
|
||||
extern void SDL_DestroyHashKey(void *unused, const void *key, const void *value);
|
||||
|
||||
/**
|
||||
* Free just the value pointer of a hash table item.
|
||||
*
|
||||
* This is intended to be used as one of the callbacks to SDL_CreateHashTable,
|
||||
* if this is useful to the type of data to be used with the hash table.
|
||||
*
|
||||
* This literally calls `SDL_free(value);` and leaves `key` alone.
|
||||
*
|
||||
* \param unused this parameter is ignored.
|
||||
* \param key the key to be destroyed.
|
||||
* \param value the value to be destroyed.
|
||||
*
|
||||
* \threadsafety It is safe to call this function from any thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.4.0.
|
||||
*
|
||||
* \sa SDL_CreateHashTable
|
||||
*/
|
||||
extern void SDL_DestroyHashValue(void *unused, const void *key, const void *value);
|
||||
|
||||
|
||||
/* Ends C function definitions when using C++ */
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#include <SDL3/SDL_close_code.h>
|
||||
|
||||
#endif /* SDL_hashtable_h_ */
|
||||
|
@@ -22,6 +22,10 @@
|
||||
|
||||
#include "SDL_hints_c.h"
|
||||
|
||||
#ifdef SDL_PLATFORM_ANDROID
|
||||
#include "core/android/SDL_android.h"
|
||||
#endif
|
||||
|
||||
typedef struct SDL_HintWatch
|
||||
{
|
||||
SDL_HintCallback callback;
|
||||
@@ -147,6 +151,13 @@ bool SDL_SetHintWithPriority(const char *name, const char *value, SDL_HintPriori
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef SDL_PLATFORM_ANDROID
|
||||
if (SDL_strcmp(name, SDL_HINT_ANDROID_ALLOW_RECREATE_ACTIVITY) == 0) {
|
||||
// Special handling for this hint, which needs to persist outside the normal application flow
|
||||
Android_SetAllowRecreateActivity(SDL_GetStringBoolean(value, false));
|
||||
}
|
||||
#endif // SDL_PLATFORM_ANDROID
|
||||
|
||||
SDL_UnlockProperties(hints);
|
||||
|
||||
return result;
|
||||
@@ -185,6 +196,17 @@ bool SDL_ResetHint(const char *name)
|
||||
result = true;
|
||||
}
|
||||
|
||||
#ifdef SDL_PLATFORM_ANDROID
|
||||
if (SDL_strcmp(name, SDL_HINT_ANDROID_ALLOW_RECREATE_ACTIVITY) == 0) {
|
||||
// Special handling for this hint, which needs to persist outside the normal application flow
|
||||
if (env) {
|
||||
Android_SetAllowRecreateActivity(SDL_GetStringBoolean(env, false));
|
||||
} else {
|
||||
Android_SetAllowRecreateActivity(false);
|
||||
}
|
||||
}
|
||||
#endif // SDL_PLATFORM_ANDROID
|
||||
|
||||
SDL_UnlockProperties(hints);
|
||||
|
||||
return result;
|
||||
@@ -210,6 +232,17 @@ static void SDLCALL ResetHintsCallback(void *userdata, SDL_PropertiesID hints, c
|
||||
SDL_free(hint->value);
|
||||
hint->value = NULL;
|
||||
hint->priority = SDL_HINT_DEFAULT;
|
||||
|
||||
#ifdef SDL_PLATFORM_ANDROID
|
||||
if (SDL_strcmp(name, SDL_HINT_ANDROID_ALLOW_RECREATE_ACTIVITY) == 0) {
|
||||
// Special handling for this hint, which needs to persist outside the normal application flow
|
||||
if (env) {
|
||||
Android_SetAllowRecreateActivity(SDL_GetStringBoolean(env, false));
|
||||
} else {
|
||||
Android_SetAllowRecreateActivity(false);
|
||||
}
|
||||
}
|
||||
#endif // SDL_PLATFORM_ANDROID
|
||||
}
|
||||
|
||||
void SDL_ResetHints(void)
|
||||
|
@@ -191,6 +191,11 @@
|
||||
#define SDL_VIDEO_RENDER_SW 1
|
||||
#endif
|
||||
|
||||
/* STB image conversion */
|
||||
#if !defined(SDL_HAVE_STB) && !defined(SDL_LEAN_AND_MEAN)
|
||||
#define SDL_HAVE_STB 1
|
||||
#endif
|
||||
|
||||
/* YUV formats
|
||||
- handling of YUV surfaces
|
||||
- blitting and conversion functions */
|
||||
@@ -198,6 +203,17 @@
|
||||
#define SDL_HAVE_YUV 1
|
||||
#endif
|
||||
|
||||
#ifdef SDL_CAMERA_DISABLED
|
||||
#undef SDL_CAMERA_DRIVER_ANDROID
|
||||
#undef SDL_CAMERA_DRIVER_COREMEDIA
|
||||
#undef SDL_CAMERA_DRIVER_DUMMY
|
||||
#undef SDL_CAMERA_DRIVER_EMSCRIPTEN
|
||||
#undef SDL_CAMERA_DRIVER_MEDIAFOUNDATION
|
||||
#undef SDL_CAMERA_DRIVER_PIPEWIRE
|
||||
#undef SDL_CAMERA_DRIVER_V4L2
|
||||
#undef SDL_CAMERA_DRIVER_VITA
|
||||
#endif
|
||||
|
||||
#ifdef SDL_RENDER_DISABLED
|
||||
#undef SDL_VIDEO_RENDER_SW
|
||||
#undef SDL_VIDEO_RENDER_D3D
|
||||
@@ -249,6 +265,12 @@ extern "C" {
|
||||
#include "SDL_utils_c.h"
|
||||
#include "SDL_hashtable.h"
|
||||
|
||||
#define PUSH_SDL_ERROR() \
|
||||
{ char *_error = SDL_strdup(SDL_GetError());
|
||||
|
||||
#define POP_SDL_ERROR() \
|
||||
SDL_SetError("%s", _error); SDL_free(_error); }
|
||||
|
||||
// Do any initialization that needs to happen before threads are started
|
||||
extern void SDL_InitMainThread(void);
|
||||
|
||||
|
@@ -76,7 +76,7 @@ static void SDL_FreePropertyWithCleanup(const void *key, const void *value, void
|
||||
SDL_free((void *)value);
|
||||
}
|
||||
|
||||
static void SDL_FreeProperty(const void *key, const void *value, void *data)
|
||||
static void SDLCALL SDL_FreeProperty(void *data, const void *key, const void *value)
|
||||
{
|
||||
SDL_FreePropertyWithCleanup(key, value, data, true);
|
||||
}
|
||||
@@ -84,14 +84,8 @@ static void SDL_FreeProperty(const void *key, const void *value, void *data)
|
||||
static void SDL_FreeProperties(SDL_Properties *properties)
|
||||
{
|
||||
if (properties) {
|
||||
if (properties->props) {
|
||||
SDL_DestroyHashTable(properties->props);
|
||||
properties->props = NULL;
|
||||
}
|
||||
if (properties->lock) {
|
||||
SDL_DestroyMutex(properties->lock);
|
||||
properties->lock = NULL;
|
||||
}
|
||||
SDL_DestroyHashTable(properties->props);
|
||||
SDL_DestroyMutex(properties->lock);
|
||||
SDL_free(properties);
|
||||
}
|
||||
}
|
||||
@@ -102,18 +96,16 @@ bool SDL_InitProperties(void)
|
||||
return true;
|
||||
}
|
||||
|
||||
SDL_properties = SDL_CreateHashTable(NULL, 16, SDL_HashID, SDL_KeyMatchID, NULL, true, false);
|
||||
if (!SDL_properties) {
|
||||
goto error;
|
||||
}
|
||||
SDL_properties = SDL_CreateHashTable(0, true, SDL_HashID, SDL_KeyMatchID, NULL, NULL);
|
||||
const bool initialized = (SDL_properties != NULL);
|
||||
SDL_SetInitialized(&SDL_properties_init, initialized);
|
||||
return initialized;
|
||||
}
|
||||
|
||||
SDL_SetInitialized(&SDL_properties_init, true);
|
||||
return true;
|
||||
|
||||
error:
|
||||
SDL_SetInitialized(&SDL_properties_init, true);
|
||||
SDL_QuitProperties();
|
||||
return false;
|
||||
static bool SDLCALL FreeOneProperties(void *userdata, const SDL_HashTable *table, const void *key, const void *value)
|
||||
{
|
||||
SDL_FreeProperties((SDL_Properties *)value);
|
||||
return true; // keep iterating.
|
||||
}
|
||||
|
||||
void SDL_QuitProperties(void)
|
||||
@@ -131,17 +123,13 @@ void SDL_QuitProperties(void)
|
||||
SDL_DestroyProperties(props);
|
||||
}
|
||||
|
||||
if (SDL_properties) {
|
||||
void *iter;
|
||||
const void *key, *value;
|
||||
|
||||
iter = NULL;
|
||||
while (SDL_IterateHashTable(SDL_properties, &key, &value, &iter)) {
|
||||
SDL_FreeProperties((SDL_Properties *)value);
|
||||
}
|
||||
SDL_DestroyHashTable(SDL_properties);
|
||||
SDL_properties = NULL;
|
||||
}
|
||||
// this can't just DestroyHashTable with SDL_FreeProperties as the destructor, because
|
||||
// other destructors under this might cause use to attempt a recursive lock on SDL_properties,
|
||||
// which isn't allowed with rwlocks. So manually iterate and free everything.
|
||||
SDL_HashTable *properties = SDL_properties;
|
||||
SDL_properties = NULL;
|
||||
SDL_IterateHashTable(properties, FreeOneProperties, NULL);
|
||||
SDL_DestroyHashTable(properties);
|
||||
|
||||
SDL_SetInitialized(&SDL_properties_init, false);
|
||||
}
|
||||
@@ -167,55 +155,101 @@ SDL_PropertiesID SDL_GetGlobalProperties(void)
|
||||
|
||||
SDL_PropertiesID SDL_CreateProperties(void)
|
||||
{
|
||||
SDL_PropertiesID props = 0;
|
||||
SDL_Properties *properties = NULL;
|
||||
bool inserted = false;
|
||||
|
||||
if (!SDL_CheckInitProperties()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
properties = (SDL_Properties *)SDL_calloc(1, sizeof(*properties));
|
||||
SDL_Properties *properties = (SDL_Properties *)SDL_calloc(1, sizeof(*properties));
|
||||
if (!properties) {
|
||||
goto error;
|
||||
}
|
||||
properties->props = SDL_CreateHashTable(NULL, 4, SDL_HashString, SDL_KeyMatchString, SDL_FreeProperty, false, false);
|
||||
if (!properties->props) {
|
||||
goto error;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// If this fails we'll continue without it.
|
||||
properties->lock = SDL_CreateMutex();
|
||||
if (!properties->lock) {
|
||||
SDL_free(properties);
|
||||
return 0;
|
||||
}
|
||||
|
||||
for ( ; ; ) {
|
||||
properties->props = SDL_CreateHashTable(0, false, SDL_HashString, SDL_KeyMatchString, SDL_FreeProperty, NULL);
|
||||
if (!properties->props) {
|
||||
SDL_DestroyMutex(properties->lock);
|
||||
SDL_free(properties);
|
||||
return 0;
|
||||
}
|
||||
|
||||
SDL_PropertiesID props = 0;
|
||||
while (true) {
|
||||
props = (SDL_GetAtomicU32(&SDL_last_properties_id) + 1);
|
||||
if (props == 0) {
|
||||
continue;
|
||||
}
|
||||
if (SDL_CompareAndSwapAtomicU32(&SDL_last_properties_id, props - 1, props)) {
|
||||
} else if (SDL_CompareAndSwapAtomicU32(&SDL_last_properties_id, props - 1, props)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (SDL_InsertIntoHashTable(SDL_properties, (const void *)(uintptr_t)props, properties)) {
|
||||
inserted = true;
|
||||
|
||||
SDL_assert(!SDL_FindInHashTable(SDL_properties, (const void *)(uintptr_t)props, NULL)); // should NOT be in the hash table already.
|
||||
|
||||
if (!SDL_InsertIntoHashTable(SDL_properties, (const void *)(uintptr_t)props, properties, false)) {
|
||||
SDL_FreeProperties(properties);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (inserted) {
|
||||
// All done!
|
||||
return props;
|
||||
return props; // All done!
|
||||
}
|
||||
|
||||
typedef struct CopyOnePropertyData
|
||||
{
|
||||
SDL_Properties *dst_properties;
|
||||
bool result;
|
||||
} CopyOnePropertyData;
|
||||
|
||||
static bool SDLCALL CopyOneProperty(void *userdata, const SDL_HashTable *table, const void *key, const void *value)
|
||||
{
|
||||
const SDL_Property *src_property = (const SDL_Property *)value;
|
||||
if (src_property->cleanup) {
|
||||
// Can't copy properties with cleanup functions, we don't know how to duplicate the data
|
||||
return true; // keep iterating.
|
||||
}
|
||||
|
||||
error:
|
||||
SDL_FreeProperties(properties);
|
||||
return 0;
|
||||
CopyOnePropertyData *data = (CopyOnePropertyData *) userdata;
|
||||
SDL_Properties *dst_properties = data->dst_properties;
|
||||
const char *src_name = (const char *)key;
|
||||
SDL_Property *dst_property;
|
||||
|
||||
char *dst_name = SDL_strdup(src_name);
|
||||
if (!dst_name) {
|
||||
data->result = false;
|
||||
return true; // keep iterating (I guess...?)
|
||||
}
|
||||
|
||||
dst_property = (SDL_Property *)SDL_malloc(sizeof(*dst_property));
|
||||
if (!dst_property) {
|
||||
SDL_free(dst_name);
|
||||
data->result = false;
|
||||
return true; // keep iterating (I guess...?)
|
||||
}
|
||||
|
||||
SDL_copyp(dst_property, src_property);
|
||||
if (src_property->type == SDL_PROPERTY_TYPE_STRING) {
|
||||
dst_property->value.string_value = SDL_strdup(src_property->value.string_value);
|
||||
if (!dst_property->value.string_value) {
|
||||
SDL_free(dst_name);
|
||||
SDL_free(dst_property);
|
||||
data->result = false;
|
||||
return true; // keep iterating (I guess...?)
|
||||
}
|
||||
}
|
||||
|
||||
if (!SDL_InsertIntoHashTable(dst_properties->props, dst_name, dst_property, true)) {
|
||||
SDL_FreePropertyWithCleanup(dst_name, dst_property, NULL, false);
|
||||
data->result = false;
|
||||
}
|
||||
|
||||
return true; // keep iterating.
|
||||
}
|
||||
|
||||
bool SDL_CopyProperties(SDL_PropertiesID src, SDL_PropertiesID dst)
|
||||
{
|
||||
SDL_Properties *src_properties = NULL;
|
||||
SDL_Properties *dst_properties = NULL;
|
||||
bool result = true;
|
||||
|
||||
if (!src) {
|
||||
return SDL_InvalidParamError("src");
|
||||
}
|
||||
@@ -223,55 +257,25 @@ bool SDL_CopyProperties(SDL_PropertiesID src, SDL_PropertiesID dst)
|
||||
return SDL_InvalidParamError("dst");
|
||||
}
|
||||
|
||||
SDL_Properties *src_properties = NULL;
|
||||
SDL_Properties *dst_properties = NULL;
|
||||
|
||||
SDL_FindInHashTable(SDL_properties, (const void *)(uintptr_t)src, (const void **)&src_properties);
|
||||
SDL_FindInHashTable(SDL_properties, (const void *)(uintptr_t)dst, (const void **)&dst_properties);
|
||||
if (!src_properties) {
|
||||
return SDL_InvalidParamError("src");
|
||||
}
|
||||
SDL_FindInHashTable(SDL_properties, (const void *)(uintptr_t)dst, (const void **)&dst_properties);
|
||||
if (!dst_properties) {
|
||||
return SDL_InvalidParamError("dst");
|
||||
}
|
||||
|
||||
bool result = true;
|
||||
SDL_LockMutex(src_properties->lock);
|
||||
SDL_LockMutex(dst_properties->lock);
|
||||
{
|
||||
void *iter;
|
||||
const void *key, *value;
|
||||
|
||||
iter = NULL;
|
||||
while (SDL_IterateHashTable(src_properties->props, &key, &value, &iter)) {
|
||||
const char *src_name = (const char *)key;
|
||||
const SDL_Property *src_property = (const SDL_Property *)value;
|
||||
char *dst_name;
|
||||
SDL_Property *dst_property;
|
||||
|
||||
if (src_property->cleanup) {
|
||||
// Can't copy properties with cleanup functions, we don't know how to duplicate the data
|
||||
continue;
|
||||
}
|
||||
|
||||
SDL_RemoveFromHashTable(dst_properties->props, src_name);
|
||||
|
||||
dst_name = SDL_strdup(src_name);
|
||||
if (!dst_name) {
|
||||
result = false;
|
||||
continue;
|
||||
}
|
||||
dst_property = (SDL_Property *)SDL_malloc(sizeof(*dst_property));
|
||||
if (!dst_property) {
|
||||
SDL_free(dst_name);
|
||||
result = false;
|
||||
continue;
|
||||
}
|
||||
SDL_copyp(dst_property, src_property);
|
||||
if (src_property->type == SDL_PROPERTY_TYPE_STRING) {
|
||||
dst_property->value.string_value = SDL_strdup(src_property->value.string_value);
|
||||
}
|
||||
if (!SDL_InsertIntoHashTable(dst_properties->props, dst_name, dst_property)) {
|
||||
SDL_FreePropertyWithCleanup(dst_name, dst_property, NULL, false);
|
||||
result = false;
|
||||
}
|
||||
}
|
||||
CopyOnePropertyData data = { dst_properties, true };
|
||||
SDL_IterateHashTable(src_properties->props, CopyOneProperty, &data);
|
||||
result = data.result;
|
||||
}
|
||||
SDL_UnlockMutex(dst_properties->lock);
|
||||
SDL_UnlockMutex(src_properties->lock);
|
||||
@@ -337,7 +341,7 @@ static bool SDL_PrivateSetProperty(SDL_PropertiesID props, const char *name, SDL
|
||||
SDL_RemoveFromHashTable(properties->props, name);
|
||||
if (property) {
|
||||
char *key = SDL_strdup(name);
|
||||
if (!SDL_InsertIntoHashTable(properties->props, key, property)) {
|
||||
if (!key || !SDL_InsertIntoHashTable(properties->props, key, property, false)) {
|
||||
SDL_FreePropertyWithCleanup(key, property, NULL, true);
|
||||
result = false;
|
||||
}
|
||||
@@ -518,10 +522,9 @@ void *SDL_GetPointerProperty(SDL_PropertiesID props, const char *name, void *def
|
||||
return value;
|
||||
}
|
||||
|
||||
/* Note that taking the lock here only guarantees that we won't read the
|
||||
* hashtable while it's being modified. The value itself can easily be
|
||||
* freed from another thread after it is returned here.
|
||||
*/
|
||||
// Note that taking the lock here only guarantees that we won't read the
|
||||
// hashtable while it's being modified. The value itself can easily be
|
||||
// freed from another thread after it is returned here.
|
||||
SDL_LockMutex(properties->lock);
|
||||
{
|
||||
SDL_Property *property = NULL;
|
||||
@@ -731,6 +734,23 @@ bool SDL_ClearProperty(SDL_PropertiesID props, const char *name)
|
||||
return SDL_PrivateSetProperty(props, name, NULL);
|
||||
}
|
||||
|
||||
typedef struct EnumerateOnePropertyData
|
||||
{
|
||||
SDL_EnumeratePropertiesCallback callback;
|
||||
void *userdata;
|
||||
SDL_PropertiesID props;
|
||||
} EnumerateOnePropertyData;
|
||||
|
||||
|
||||
static bool SDLCALL EnumerateOneProperty(void *userdata, const SDL_HashTable *table, const void *key, const void *value)
|
||||
{
|
||||
(void) table;
|
||||
(void) value;
|
||||
const EnumerateOnePropertyData *data = (const EnumerateOnePropertyData *) userdata;
|
||||
data->callback(data->userdata, data->props, (const char *)key);
|
||||
return true; // keep iterating.
|
||||
}
|
||||
|
||||
bool SDL_EnumerateProperties(SDL_PropertiesID props, SDL_EnumeratePropertiesCallback callback, void *userdata)
|
||||
{
|
||||
SDL_Properties *properties = NULL;
|
||||
@@ -749,13 +769,8 @@ bool SDL_EnumerateProperties(SDL_PropertiesID props, SDL_EnumeratePropertiesCall
|
||||
|
||||
SDL_LockMutex(properties->lock);
|
||||
{
|
||||
void *iter;
|
||||
const void *key, *value;
|
||||
|
||||
iter = NULL;
|
||||
while (SDL_IterateHashTable(properties->props, &key, &value, &iter)) {
|
||||
callback(userdata, props, (const char *)key);
|
||||
}
|
||||
EnumerateOnePropertyData data = { callback, userdata, props };
|
||||
SDL_IterateHashTable(properties->props, EnumerateOneProperty, &data);
|
||||
}
|
||||
SDL_UnlockMutex(properties->lock);
|
||||
|
||||
@@ -796,14 +811,14 @@ bool SDL_DumpProperties(SDL_PropertiesID props)
|
||||
|
||||
void SDL_DestroyProperties(SDL_PropertiesID props)
|
||||
{
|
||||
SDL_Properties *properties = NULL;
|
||||
|
||||
if (!props) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (SDL_FindInHashTable(SDL_properties, (const void *)(uintptr_t)props, (const void **)&properties)) {
|
||||
SDL_FreeProperties(properties);
|
||||
SDL_RemoveFromHashTable(SDL_properties, (const void *)(uintptr_t)props);
|
||||
if (props) {
|
||||
// this can't just use RemoveFromHashTable with SDL_FreeProperties as the destructor, because
|
||||
// other destructors under this might cause use to attempt a recursive lock on SDL_properties,
|
||||
// which isn't allowed with rwlocks. So manually look it up and remove/free it.
|
||||
SDL_Properties *properties = NULL;
|
||||
if (SDL_FindInHashTable(SDL_properties, (const void *)(uintptr_t)props, (const void **)&properties)) {
|
||||
SDL_FreeProperties(properties);
|
||||
SDL_RemoveFromHashTable(SDL_properties, (const void *)(uintptr_t)props);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
281
src/SDL_utils.c
281
src/SDL_utils.c
@@ -24,6 +24,9 @@
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include "joystick/SDL_joystick_c.h" // For SDL_GetGamepadTypeFromVIDPID()
|
||||
|
||||
|
||||
// Common utility functions that aren't in the public API
|
||||
|
||||
int SDL_powerof2(int x)
|
||||
@@ -135,12 +138,12 @@ Uint32 SDL_GetNextObjectID(void)
|
||||
static SDL_InitState SDL_objects_init;
|
||||
static SDL_HashTable *SDL_objects;
|
||||
|
||||
static Uint32 SDL_HashObject(const void *key, void *unused)
|
||||
static Uint32 SDLCALL SDL_HashObject(void *unused, const void *key)
|
||||
{
|
||||
return (Uint32)(uintptr_t)key;
|
||||
}
|
||||
|
||||
static bool SDL_KeyMatchObject(const void *a, const void *b, void *unused)
|
||||
static bool SDL_KeyMatchObject(void *unused, const void *a, const void *b)
|
||||
{
|
||||
return (a == b);
|
||||
}
|
||||
@@ -149,16 +152,17 @@ void SDL_SetObjectValid(void *object, SDL_ObjectType type, bool valid)
|
||||
{
|
||||
SDL_assert(object != NULL);
|
||||
|
||||
if (valid && SDL_ShouldInit(&SDL_objects_init)) {
|
||||
SDL_objects = SDL_CreateHashTable(NULL, 32, SDL_HashObject, SDL_KeyMatchObject, NULL, true, false);
|
||||
if (!SDL_objects) {
|
||||
SDL_SetInitialized(&SDL_objects_init, false);
|
||||
if (SDL_ShouldInit(&SDL_objects_init)) {
|
||||
SDL_objects = SDL_CreateHashTable(0, true, SDL_HashObject, SDL_KeyMatchObject, NULL, NULL);
|
||||
const bool initialized = (SDL_objects != NULL);
|
||||
SDL_SetInitialized(&SDL_objects_init, initialized);
|
||||
if (!initialized) {
|
||||
return;
|
||||
}
|
||||
SDL_SetInitialized(&SDL_objects_init, true);
|
||||
}
|
||||
|
||||
if (valid) {
|
||||
SDL_InsertIntoHashTable(SDL_objects, object, (void *)(uintptr_t)type);
|
||||
SDL_InsertIntoHashTable(SDL_objects, object, (void *)(uintptr_t)type, true);
|
||||
} else {
|
||||
SDL_RemoveFromHashTable(SDL_objects, object);
|
||||
}
|
||||
@@ -178,75 +182,65 @@ bool SDL_ObjectValid(void *object, SDL_ObjectType type)
|
||||
return (((SDL_ObjectType)(uintptr_t)object_type) == type);
|
||||
}
|
||||
|
||||
typedef struct GetOneObjectData
|
||||
{
|
||||
const SDL_ObjectType type;
|
||||
void **objects;
|
||||
const int count;
|
||||
int num_objects;
|
||||
} GetOneObjectData;
|
||||
|
||||
static bool SDLCALL GetOneObject(void *userdata, const SDL_HashTable *table, const void *object, const void *object_type)
|
||||
{
|
||||
GetOneObjectData *data = (GetOneObjectData *) userdata;
|
||||
if ((SDL_ObjectType)(uintptr_t)object_type == data->type) {
|
||||
if (data->num_objects < data->count) {
|
||||
data->objects[data->num_objects] = (void *)object;
|
||||
}
|
||||
++data->num_objects;
|
||||
}
|
||||
return true; // keep iterating.
|
||||
}
|
||||
|
||||
|
||||
int SDL_GetObjects(SDL_ObjectType type, void **objects, int count)
|
||||
{
|
||||
const void *object, *object_type;
|
||||
void *iter = NULL;
|
||||
int num_objects = 0;
|
||||
while (SDL_IterateHashTable(SDL_objects, &object, &object_type, &iter)) {
|
||||
if ((SDL_ObjectType)(uintptr_t)object_type == type) {
|
||||
if (num_objects < count) {
|
||||
objects[num_objects] = (void *)object;
|
||||
}
|
||||
++num_objects;
|
||||
}
|
||||
GetOneObjectData data = { type, objects, count, 0 };
|
||||
SDL_IterateHashTable(SDL_objects, GetOneObject, &data);
|
||||
return data.num_objects;
|
||||
}
|
||||
|
||||
static bool SDLCALL LogOneLeakedObject(void *userdata, const SDL_HashTable *table, const void *object, const void *object_type)
|
||||
{
|
||||
const char *type = "unknown object";
|
||||
switch ((SDL_ObjectType)(uintptr_t)object_type) {
|
||||
#define SDLOBJTYPECASE(typ, name) case SDL_OBJECT_TYPE_##typ: type = name; break
|
||||
SDLOBJTYPECASE(WINDOW, "SDL_Window");
|
||||
SDLOBJTYPECASE(RENDERER, "SDL_Renderer");
|
||||
SDLOBJTYPECASE(TEXTURE, "SDL_Texture");
|
||||
SDLOBJTYPECASE(JOYSTICK, "SDL_Joystick");
|
||||
SDLOBJTYPECASE(GAMEPAD, "SDL_Gamepad");
|
||||
SDLOBJTYPECASE(HAPTIC, "SDL_Haptic");
|
||||
SDLOBJTYPECASE(SENSOR, "SDL_Sensor");
|
||||
SDLOBJTYPECASE(HIDAPI_DEVICE, "hidapi device");
|
||||
SDLOBJTYPECASE(HIDAPI_JOYSTICK, "hidapi joystick");
|
||||
SDLOBJTYPECASE(THREAD, "thread");
|
||||
SDLOBJTYPECASE(TRAY, "SDL_Tray");
|
||||
#undef SDLOBJTYPECASE
|
||||
default: break;
|
||||
}
|
||||
return num_objects;
|
||||
SDL_Log("Leaked %s (%p)", type, object);
|
||||
return true; // keep iterating.
|
||||
}
|
||||
|
||||
void SDL_SetObjectsInvalid(void)
|
||||
{
|
||||
if (SDL_ShouldQuit(&SDL_objects_init)) {
|
||||
// Log any leaked objects
|
||||
const void *object, *object_type;
|
||||
void *iter = NULL;
|
||||
while (SDL_IterateHashTable(SDL_objects, &object, &object_type, &iter)) {
|
||||
const char *type;
|
||||
switch ((SDL_ObjectType)(uintptr_t)object_type) {
|
||||
case SDL_OBJECT_TYPE_WINDOW:
|
||||
type = "SDL_Window";
|
||||
break;
|
||||
case SDL_OBJECT_TYPE_RENDERER:
|
||||
type = "SDL_Renderer";
|
||||
break;
|
||||
case SDL_OBJECT_TYPE_TEXTURE:
|
||||
type = "SDL_Texture";
|
||||
break;
|
||||
case SDL_OBJECT_TYPE_JOYSTICK:
|
||||
type = "SDL_Joystick";
|
||||
break;
|
||||
case SDL_OBJECT_TYPE_GAMEPAD:
|
||||
type = "SDL_Gamepad";
|
||||
break;
|
||||
case SDL_OBJECT_TYPE_HAPTIC:
|
||||
type = "SDL_Haptic";
|
||||
break;
|
||||
case SDL_OBJECT_TYPE_SENSOR:
|
||||
type = "SDL_Sensor";
|
||||
break;
|
||||
case SDL_OBJECT_TYPE_HIDAPI_DEVICE:
|
||||
type = "hidapi device";
|
||||
break;
|
||||
case SDL_OBJECT_TYPE_HIDAPI_JOYSTICK:
|
||||
type = "hidapi joystick";
|
||||
break;
|
||||
case SDL_OBJECT_TYPE_THREAD:
|
||||
type = "thread";
|
||||
break;
|
||||
case SDL_OBJECT_TYPE_TRAY:
|
||||
type = "SDL_Tray";
|
||||
break;
|
||||
default:
|
||||
type = "unknown object";
|
||||
break;
|
||||
}
|
||||
SDL_Log("Leaked %s (%p)", type, object);
|
||||
}
|
||||
SDL_IterateHashTable(SDL_objects, LogOneLeakedObject, NULL);
|
||||
SDL_assert(SDL_HashTableEmpty(SDL_objects));
|
||||
|
||||
SDL_DestroyHashTable(SDL_objects);
|
||||
SDL_objects = NULL;
|
||||
|
||||
SDL_SetInitialized(&SDL_objects_init, false);
|
||||
}
|
||||
}
|
||||
@@ -384,7 +378,7 @@ const char *SDL_GetPersistentString(const char *string)
|
||||
|
||||
SDL_HashTable *strings = (SDL_HashTable *)SDL_GetTLS(&SDL_string_storage);
|
||||
if (!strings) {
|
||||
strings = SDL_CreateHashTable(NULL, 32, SDL_HashString, SDL_KeyMatchString, SDL_NukeFreeValue, false, false);
|
||||
strings = SDL_CreateHashTable(0, false, SDL_HashString, SDL_KeyMatchString, SDL_DestroyHashValue, NULL);
|
||||
if (!strings) {
|
||||
return NULL;
|
||||
}
|
||||
@@ -400,8 +394,161 @@ const char *SDL_GetPersistentString(const char *string)
|
||||
}
|
||||
|
||||
// If the hash table insert fails, at least we can return the string we allocated
|
||||
SDL_InsertIntoHashTable(strings, new_string, new_string);
|
||||
SDL_InsertIntoHashTable(strings, new_string, new_string, false);
|
||||
result = new_string;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static int PrefixMatch(const char *a, const char *b)
|
||||
{
|
||||
int matchlen = 0;
|
||||
// Fixes the "HORI HORl Taiko No Tatsujin Drum Controller"
|
||||
if (SDL_strncmp(a, "HORI ", 5) == 0 && SDL_strncmp(b, "HORl ", 5) == 0) {
|
||||
return 5;
|
||||
}
|
||||
while (*a && *b) {
|
||||
if (SDL_tolower((unsigned char)*a++) == SDL_tolower((unsigned char)*b++)) {
|
||||
++matchlen;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return matchlen;
|
||||
}
|
||||
|
||||
char *SDL_CreateDeviceName(Uint16 vendor, Uint16 product, const char *vendor_name, const char *product_name, const char *default_name)
|
||||
{
|
||||
static struct
|
||||
{
|
||||
const char *prefix;
|
||||
const char *replacement;
|
||||
} replacements[] = {
|
||||
{ "8BitDo Tech Ltd", "8BitDo" },
|
||||
{ "ASTRO Gaming", "ASTRO" },
|
||||
{ "Bensussen Deutsch & Associates,Inc.(BDA)", "BDA" },
|
||||
{ "Guangzhou Chicken Run Network Technology Co., Ltd.", "GameSir" },
|
||||
{ "HORI CO.,LTD.", "HORI" },
|
||||
{ "HORI CO.,LTD", "HORI" },
|
||||
{ "Mad Catz Inc.", "Mad Catz" },
|
||||
{ "Nintendo Co., Ltd.", "Nintendo" },
|
||||
{ "NVIDIA Corporation ", "" },
|
||||
{ "Performance Designed Products", "PDP" },
|
||||
{ "QANBA USA, LLC", "Qanba" },
|
||||
{ "QANBA USA,LLC", "Qanba" },
|
||||
{ "Unknown ", "" },
|
||||
};
|
||||
char *name = NULL;
|
||||
size_t i, len;
|
||||
|
||||
if (!vendor_name) {
|
||||
vendor_name = "";
|
||||
}
|
||||
if (!product_name) {
|
||||
product_name = "";
|
||||
}
|
||||
|
||||
while (*vendor_name == ' ') {
|
||||
++vendor_name;
|
||||
}
|
||||
while (*product_name == ' ') {
|
||||
++product_name;
|
||||
}
|
||||
|
||||
if (*vendor_name && *product_name) {
|
||||
len = (SDL_strlen(vendor_name) + 1 + SDL_strlen(product_name) + 1);
|
||||
name = (char *)SDL_malloc(len);
|
||||
if (name) {
|
||||
(void)SDL_snprintf(name, len, "%s %s", vendor_name, product_name);
|
||||
}
|
||||
} else if (*product_name) {
|
||||
name = SDL_strdup(product_name);
|
||||
} else if (vendor || product) {
|
||||
// Couldn't find a controller name, try to give it one based on device type
|
||||
switch (SDL_GetGamepadTypeFromVIDPID(vendor, product, NULL, true)) {
|
||||
case SDL_GAMEPAD_TYPE_XBOX360:
|
||||
name = SDL_strdup("Xbox 360 Controller");
|
||||
break;
|
||||
case SDL_GAMEPAD_TYPE_XBOXONE:
|
||||
name = SDL_strdup("Xbox One Controller");
|
||||
break;
|
||||
case SDL_GAMEPAD_TYPE_PS3:
|
||||
name = SDL_strdup("PS3 Controller");
|
||||
break;
|
||||
case SDL_GAMEPAD_TYPE_PS4:
|
||||
name = SDL_strdup("PS4 Controller");
|
||||
break;
|
||||
case SDL_GAMEPAD_TYPE_PS5:
|
||||
name = SDL_strdup("DualSense Wireless Controller");
|
||||
break;
|
||||
case SDL_GAMEPAD_TYPE_NINTENDO_SWITCH_PRO:
|
||||
name = SDL_strdup("Nintendo Switch Pro Controller");
|
||||
break;
|
||||
default:
|
||||
len = (6 + 1 + 6 + 1);
|
||||
name = (char *)SDL_malloc(len);
|
||||
if (name) {
|
||||
(void)SDL_snprintf(name, len, "0x%.4x/0x%.4x", vendor, product);
|
||||
}
|
||||
break;
|
||||
}
|
||||
} else if (default_name) {
|
||||
name = SDL_strdup(default_name);
|
||||
}
|
||||
|
||||
if (!name) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Trim trailing whitespace
|
||||
for (len = SDL_strlen(name); (len > 0 && name[len - 1] == ' '); --len) {
|
||||
// continue
|
||||
}
|
||||
name[len] = '\0';
|
||||
|
||||
// Compress duplicate spaces
|
||||
for (i = 0; i < (len - 1);) {
|
||||
if (name[i] == ' ' && name[i + 1] == ' ') {
|
||||
SDL_memmove(&name[i], &name[i + 1], (len - i));
|
||||
--len;
|
||||
} else {
|
||||
++i;
|
||||
}
|
||||
}
|
||||
|
||||
// Perform any manufacturer replacements
|
||||
for (i = 0; i < SDL_arraysize(replacements); ++i) {
|
||||
size_t prefixlen = SDL_strlen(replacements[i].prefix);
|
||||
if (SDL_strncasecmp(name, replacements[i].prefix, prefixlen) == 0) {
|
||||
size_t replacementlen = SDL_strlen(replacements[i].replacement);
|
||||
if (replacementlen <= prefixlen) {
|
||||
SDL_memcpy(name, replacements[i].replacement, replacementlen);
|
||||
SDL_memmove(name + replacementlen, name + prefixlen, (len - prefixlen) + 1);
|
||||
len -= (prefixlen - replacementlen);
|
||||
} else {
|
||||
// FIXME: Need to handle the expand case by reallocating the string
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Remove duplicate manufacturer or product in the name
|
||||
* e.g. Razer Razer Raiju Tournament Edition Wired
|
||||
*/
|
||||
for (i = 1; i < (len - 1); ++i) {
|
||||
int matchlen = PrefixMatch(name, &name[i]);
|
||||
while (matchlen > 0) {
|
||||
if (name[matchlen] == ' ' || name[matchlen] == '-') {
|
||||
SDL_memmove(name, name + matchlen + 1, len - matchlen);
|
||||
break;
|
||||
}
|
||||
--matchlen;
|
||||
}
|
||||
if (matchlen > 0) {
|
||||
// We matched the manufacturer's name and removed it
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return name;
|
||||
}
|
||||
|
@@ -73,4 +73,6 @@ extern void SDL_SetObjectsInvalid(void);
|
||||
|
||||
extern const char *SDL_GetPersistentString(const char *string);
|
||||
|
||||
extern char *SDL_CreateDeviceName(Uint16 vendor, Uint16 product, const char *vendor_name, const char *product_name, const char *default_name);
|
||||
|
||||
#endif // SDL_utils_h_
|
||||
|
@@ -136,6 +136,7 @@ const char *SDL_GetAudioDriver(int index)
|
||||
if (index >= 0 && index < SDL_GetNumAudioDrivers()) {
|
||||
return deduped_bootstrap[index]->name;
|
||||
}
|
||||
SDL_InvalidParamError("index");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -409,6 +410,7 @@ static SDL_LogicalAudioDevice *ObtainLogicalAudioDevice(SDL_AudioDeviceID devid,
|
||||
SDL_LockRWLockForReading(current_audio.device_hash_lock);
|
||||
SDL_FindInHashTable(current_audio.device_hash, (const void *) (uintptr_t) devid, (const void **) &logdev);
|
||||
if (logdev) {
|
||||
SDL_assert(logdev->instance_id == devid);
|
||||
device = logdev->physical_device;
|
||||
SDL_assert(device != NULL);
|
||||
RefPhysicalAudioDevice(device); // reference it, in case the logical device migrates to a new default.
|
||||
@@ -458,6 +460,7 @@ static SDL_AudioDevice *ObtainPhysicalAudioDevice(SDL_AudioDeviceID devid) // !
|
||||
} else {
|
||||
SDL_LockRWLockForReading(current_audio.device_hash_lock);
|
||||
SDL_FindInHashTable(current_audio.device_hash, (const void *) (uintptr_t) devid, (const void **) &device);
|
||||
SDL_assert(device->instance_id == devid);
|
||||
SDL_UnlockRWLock(current_audio.device_hash_lock);
|
||||
|
||||
if (!device) {
|
||||
@@ -650,7 +653,7 @@ static SDL_AudioDevice *CreatePhysicalAudioDevice(const char *name, bool recordi
|
||||
device->instance_id = AssignAudioDeviceInstanceId(recording, /*islogical=*/false);
|
||||
|
||||
SDL_LockRWLockForWriting(current_audio.device_hash_lock);
|
||||
if (SDL_InsertIntoHashTable(current_audio.device_hash, (const void *) (uintptr_t) device->instance_id, device)) {
|
||||
if (SDL_InsertIntoHashTable(current_audio.device_hash, (const void *) (uintptr_t) device->instance_id, device, false)) {
|
||||
SDL_AddAtomicInt(device_count, 1);
|
||||
} else {
|
||||
SDL_DestroyCondition(device->close_cond);
|
||||
@@ -864,50 +867,48 @@ static void CompleteAudioEntryPoints(void)
|
||||
#undef FILL_STUB
|
||||
}
|
||||
|
||||
static SDL_AudioDevice *GetFirstAddedAudioDevice(const bool recording)
|
||||
typedef struct FindLowestDeviceIDData
|
||||
{
|
||||
SDL_AudioDeviceID highest = (SDL_AudioDeviceID) SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK; // According to AssignAudioDeviceInstanceId, nothing can have a value this large.
|
||||
SDL_AudioDevice *result = NULL;
|
||||
const bool recording;
|
||||
SDL_AudioDeviceID highest;
|
||||
SDL_AudioDevice *result;
|
||||
} FindLowestDeviceIDData;
|
||||
|
||||
// (Device IDs increase as new devices are added, so the first device added has the lowest SDL_AudioDeviceID value.)
|
||||
SDL_LockRWLockForReading(current_audio.device_hash_lock);
|
||||
|
||||
const void *key;
|
||||
const void *value;
|
||||
void *iter = NULL;
|
||||
while (SDL_IterateHashTable(current_audio.device_hash, &key, &value, &iter)) {
|
||||
const SDL_AudioDeviceID devid = (SDL_AudioDeviceID) (uintptr_t) key;
|
||||
// bit #0 of devid is set for playback devices and unset for recording.
|
||||
// bit #1 of devid is set for physical devices and unset for logical.
|
||||
const bool devid_recording = !(devid & (1 << 0));
|
||||
const bool isphysical = !!(devid & (1 << 1));
|
||||
if (isphysical && (devid_recording == recording) && (devid < highest)) {
|
||||
highest = devid;
|
||||
result = (SDL_AudioDevice *) value;
|
||||
}
|
||||
static bool SDLCALL FindLowestDeviceID(void *userdata, const SDL_HashTable *table, const void *key, const void *value)
|
||||
{
|
||||
FindLowestDeviceIDData *data = (FindLowestDeviceIDData *) userdata;
|
||||
const SDL_AudioDeviceID devid = (SDL_AudioDeviceID) (uintptr_t) key;
|
||||
// bit #0 of devid is set for playback devices and unset for recording.
|
||||
// bit #1 of devid is set for physical devices and unset for logical.
|
||||
const bool devid_recording = !(devid & (1 << 0));
|
||||
const bool isphysical = !!(devid & (1 << 1));
|
||||
if (isphysical && (devid_recording == data->recording) && (devid < data->highest)) {
|
||||
data->highest = devid;
|
||||
data->result = (SDL_AudioDevice *) value;
|
||||
SDL_assert(data->result->instance_id == devid);
|
||||
}
|
||||
|
||||
SDL_UnlockRWLock(current_audio.device_hash_lock);
|
||||
return result;
|
||||
return true; // keep iterating.
|
||||
}
|
||||
|
||||
static Uint32 HashAudioDeviceID(const void *key, void *data)
|
||||
static SDL_AudioDevice *GetFirstAddedAudioDevice(const bool recording)
|
||||
{
|
||||
const SDL_AudioDeviceID highest = SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK; // According to AssignAudioDeviceInstanceId, nothing can have a value this large.
|
||||
|
||||
// (Device IDs increase as new devices are added, so the first device added has the lowest SDL_AudioDeviceID value.)
|
||||
FindLowestDeviceIDData data = { recording, highest, NULL };
|
||||
SDL_LockRWLockForReading(current_audio.device_hash_lock);
|
||||
SDL_IterateHashTable(current_audio.device_hash, FindLowestDeviceID, &data);
|
||||
SDL_UnlockRWLock(current_audio.device_hash_lock);
|
||||
return data.result;
|
||||
}
|
||||
|
||||
static Uint32 SDLCALL HashAudioDeviceID(void *userdata, const void *key)
|
||||
{
|
||||
// shift right 2, to dump the first two bits, since these are flags
|
||||
// (recording vs playback, logical vs physical) and the rest are unique incrementing integers.
|
||||
return ((Uint32) ((uintptr_t) key)) >> 2;
|
||||
}
|
||||
|
||||
static bool MatchAudioDeviceID(const void *a, const void *b, void *data)
|
||||
{
|
||||
return (a == b);
|
||||
}
|
||||
|
||||
static void NukeAudioDeviceHashItem(const void *key, const void *value, void *data)
|
||||
{
|
||||
// no-op, keys and values in this hashtable are treated as Plain Old Data and don't get freed here.
|
||||
}
|
||||
|
||||
// !!! FIXME: the video subsystem does SDL_VideoInit, not SDL_InitVideo. Make this match.
|
||||
bool SDL_InitAudio(const char *driver_name)
|
||||
{
|
||||
@@ -926,7 +927,7 @@ bool SDL_InitAudio(const char *driver_name)
|
||||
return false;
|
||||
}
|
||||
|
||||
SDL_HashTable *device_hash = SDL_CreateHashTable(NULL, 8, HashAudioDeviceID, MatchAudioDeviceID, NukeAudioDeviceHashItem, false, false);
|
||||
SDL_HashTable *device_hash = SDL_CreateHashTable(0, false, HashAudioDeviceID, SDL_KeyMatchID, NULL, NULL);
|
||||
if (!device_hash) {
|
||||
SDL_DestroyRWLock(device_hash_lock);
|
||||
return false;
|
||||
@@ -964,7 +965,7 @@ bool SDL_InitAudio(const char *driver_name)
|
||||
}
|
||||
|
||||
for (int i = 0; bootstrap[i]; ++i) {
|
||||
if (SDL_strcasecmp(bootstrap[i]->name, driver_attempt) == 0) {
|
||||
if (!bootstrap[i]->is_preferred && SDL_strcasecmp(bootstrap[i]->name, driver_attempt) == 0) {
|
||||
tried_to_init = true;
|
||||
SDL_zero(current_audio);
|
||||
current_audio.pending_events_tail = ¤t_audio.pending_events;
|
||||
@@ -1047,6 +1048,20 @@ bool SDL_InitAudio(const char *driver_name)
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool SDLCALL DestroyOnePhysicalAudioDevice(void *userdata, const SDL_HashTable *table, const void *key, const void *value)
|
||||
{
|
||||
// bit #1 of devid is set for physical devices and unset for logical.
|
||||
const SDL_AudioDeviceID devid = (SDL_AudioDeviceID) (uintptr_t) key;
|
||||
const bool isphysical = !!(devid & (1<<1));
|
||||
if (isphysical) {
|
||||
SDL_AudioDevice *dev = (SDL_AudioDevice *) value;
|
||||
|
||||
SDL_assert(dev->instance_id == devid);
|
||||
DestroyPhysicalAudioDevice(dev);
|
||||
}
|
||||
return true; // keep iterating.
|
||||
}
|
||||
|
||||
void SDL_QuitAudio(void)
|
||||
{
|
||||
if (!current_audio.name) { // not initialized?!
|
||||
@@ -1076,17 +1091,7 @@ void SDL_QuitAudio(void)
|
||||
SDL_free(i);
|
||||
}
|
||||
|
||||
const void *key;
|
||||
const void *value;
|
||||
void *iter = NULL;
|
||||
while (SDL_IterateHashTable(device_hash, &key, &value, &iter)) {
|
||||
// bit #1 of devid is set for physical devices and unset for logical.
|
||||
const SDL_AudioDeviceID devid = (SDL_AudioDeviceID) (uintptr_t) key;
|
||||
const bool isphysical = !!(devid & (1<<1));
|
||||
if (isphysical) {
|
||||
DestroyPhysicalAudioDevice((SDL_AudioDevice *) value);
|
||||
}
|
||||
}
|
||||
SDL_IterateHashTable(device_hash, DestroyOnePhysicalAudioDevice, NULL);
|
||||
|
||||
// Free the driver data
|
||||
current_audio.impl.Deinitialize();
|
||||
@@ -1148,7 +1153,10 @@ bool SDL_PlaybackAudioThreadIterate(SDL_AudioDevice *device)
|
||||
// We should have updated this elsewhere if the format changed!
|
||||
SDL_assert(SDL_AudioSpecsEqual(&stream->dst_spec, &device->spec, NULL, NULL));
|
||||
|
||||
SDL_assert(stream->src_spec.format != SDL_AUDIO_UNKNOWN);
|
||||
|
||||
const int br = SDL_GetAtomicInt(&logdev->paused) ? 0 : SDL_GetAudioStreamDataAdjustGain(stream, device_buffer, buffer_size, logdev->gain);
|
||||
|
||||
if (br < 0) { // Probably OOM. Kill the audio device; the whole thing is likely dying soon anyhow.
|
||||
failed = true;
|
||||
SDL_memset(device_buffer, device->silence_value, buffer_size); // just supply silence to the device before we die.
|
||||
@@ -1190,6 +1198,8 @@ bool SDL_PlaybackAudioThreadIterate(SDL_AudioDevice *device)
|
||||
// We should have updated this elsewhere if the format changed!
|
||||
SDL_assert(SDL_AudioSpecsEqual(&stream->dst_spec, &outspec, NULL, NULL));
|
||||
|
||||
SDL_assert(stream->src_spec.format != SDL_AUDIO_UNKNOWN);
|
||||
|
||||
/* this will hold a lock on `stream` while getting. We don't explicitly lock the streams
|
||||
for iterating here because the binding linked list can only change while the device lock is held.
|
||||
(we _do_ lock the stream during binding/unbinding to make sure that two threads can't try to bind
|
||||
@@ -1257,11 +1267,11 @@ static int SDLCALL PlaybackAudioThread(void *devicep) // thread entry point
|
||||
SDL_assert(!device->recording);
|
||||
SDL_PlaybackAudioThreadSetup(device);
|
||||
|
||||
do {
|
||||
while (SDL_PlaybackAudioThreadIterate(device)) {
|
||||
if (!device->WaitDevice(device)) {
|
||||
SDL_AudioDeviceDisconnected(device); // doh. (but don't break out of the loop, just be a zombie for now!)
|
||||
}
|
||||
} while (SDL_PlaybackAudioThreadIterate(device));
|
||||
}
|
||||
|
||||
SDL_PlaybackAudioThreadShutdown(device);
|
||||
return 0;
|
||||
@@ -1325,6 +1335,7 @@ bool SDL_RecordingAudioThreadIterate(SDL_AudioDevice *device)
|
||||
SDL_assert(stream->src_spec.format == ((logdev->postmix || (logdev->gain != 1.0f)) ? SDL_AUDIO_F32 : device->spec.format));
|
||||
SDL_assert(stream->src_spec.channels == device->spec.channels);
|
||||
SDL_assert(stream->src_spec.freq == device->spec.freq);
|
||||
SDL_assert(stream->dst_spec.format != SDL_AUDIO_UNKNOWN);
|
||||
|
||||
void *final_buf = output_buffer;
|
||||
|
||||
@@ -1383,6 +1394,35 @@ static int SDLCALL RecordingAudioThread(void *devicep) // thread entry point
|
||||
return 0;
|
||||
}
|
||||
|
||||
typedef struct CountAudioDevicesData
|
||||
{
|
||||
int devs_seen;
|
||||
int devs_skipped;
|
||||
const int num_devices;
|
||||
SDL_AudioDeviceID *result;
|
||||
const bool recording;
|
||||
} CountAudioDevicesData;
|
||||
|
||||
static bool SDLCALL CountAudioDevices(void *userdata, const SDL_HashTable *table, const void *key, const void *value)
|
||||
{
|
||||
CountAudioDevicesData *data = (CountAudioDevicesData *) userdata;
|
||||
const SDL_AudioDeviceID devid = (SDL_AudioDeviceID) (uintptr_t) key;
|
||||
// bit #0 of devid is set for playback devices and unset for recording.
|
||||
// bit #1 of devid is set for physical devices and unset for logical.
|
||||
const bool devid_recording = !(devid & (1<<0));
|
||||
const bool isphysical = !!(devid & (1<<1));
|
||||
if (isphysical && (devid_recording == data->recording)) {
|
||||
SDL_assert(data->devs_seen < data->num_devices);
|
||||
SDL_AudioDevice *device = (SDL_AudioDevice *) value; // this is normally risky, but we hold the device_hash_lock here.
|
||||
const bool zombie = SDL_GetAtomicInt(&device->zombie) != 0;
|
||||
if (zombie) {
|
||||
data->devs_skipped++;
|
||||
} else {
|
||||
data->result[data->devs_seen++] = devid;
|
||||
}
|
||||
}
|
||||
return true; // keep iterating.
|
||||
}
|
||||
|
||||
static SDL_AudioDeviceID *GetAudioDevices(int *count, bool recording)
|
||||
{
|
||||
@@ -1395,24 +1435,11 @@ static SDL_AudioDeviceID *GetAudioDevices(int *count, bool recording)
|
||||
num_devices = SDL_GetAtomicInt(recording ? ¤t_audio.recording_device_count : ¤t_audio.playback_device_count);
|
||||
result = (SDL_AudioDeviceID *) SDL_malloc((num_devices + 1) * sizeof (SDL_AudioDeviceID));
|
||||
if (result) {
|
||||
int devs_seen = 0;
|
||||
const void *key;
|
||||
const void *value;
|
||||
void *iter = NULL;
|
||||
while (SDL_IterateHashTable(current_audio.device_hash, &key, &value, &iter)) {
|
||||
const SDL_AudioDeviceID devid = (SDL_AudioDeviceID) (uintptr_t) key;
|
||||
// bit #0 of devid is set for playback devices and unset for recording.
|
||||
// bit #1 of devid is set for physical devices and unset for logical.
|
||||
const bool devid_recording = !(devid & (1<<0));
|
||||
const bool isphysical = !!(devid & (1<<1));
|
||||
if (isphysical && (devid_recording == recording)) {
|
||||
SDL_assert(devs_seen < num_devices);
|
||||
result[devs_seen++] = devid;
|
||||
}
|
||||
}
|
||||
|
||||
SDL_assert(devs_seen == num_devices);
|
||||
result[devs_seen] = 0; // null-terminated.
|
||||
CountAudioDevicesData data = { 0, 0, num_devices, result, recording };
|
||||
SDL_IterateHashTable(current_audio.device_hash, CountAudioDevices, &data);
|
||||
SDL_assert((data.devs_seen + data.devs_skipped) == num_devices);
|
||||
num_devices = data.devs_seen; // might be less if we skipped any.
|
||||
result[num_devices] = 0; // null-terminated.
|
||||
}
|
||||
}
|
||||
SDL_UnlockRWLock(current_audio.device_hash_lock);
|
||||
@@ -1440,7 +1467,31 @@ SDL_AudioDeviceID *SDL_GetAudioRecordingDevices(int *count)
|
||||
return GetAudioDevices(count, true);
|
||||
}
|
||||
|
||||
typedef struct FindAudioDeviceByCallbackData
|
||||
{
|
||||
bool (*callback)(SDL_AudioDevice *device, void *userdata);
|
||||
void *userdata;
|
||||
SDL_AudioDevice *retval;
|
||||
} FindAudioDeviceByCallbackData;
|
||||
|
||||
static bool SDLCALL FindAudioDeviceByCallback(void *userdata, const SDL_HashTable *table, const void *key, const void *value)
|
||||
{
|
||||
FindAudioDeviceByCallbackData *data = (FindAudioDeviceByCallbackData *) userdata;
|
||||
const SDL_AudioDeviceID devid = (SDL_AudioDeviceID) (uintptr_t) key;
|
||||
// bit #1 of devid is set for physical devices and unset for logical.
|
||||
const bool isphysical = !!(devid & (1<<1));
|
||||
if (isphysical) {
|
||||
SDL_AudioDevice *device = (SDL_AudioDevice *) value;
|
||||
if (data->callback(device, data->userdata)) { // found it?
|
||||
data->retval = device;
|
||||
SDL_assert(data->retval->instance_id == devid);
|
||||
return false; // stop iterating, we found it.
|
||||
}
|
||||
}
|
||||
return true; // keep iterating.
|
||||
}
|
||||
|
||||
// !!! FIXME: SDL convention is for userdata to come first in the callback's params. Fix this at some point.
|
||||
SDL_AudioDevice *SDL_FindPhysicalAudioDeviceByCallback(bool (*callback)(SDL_AudioDevice *device, void *userdata), void *userdata)
|
||||
{
|
||||
if (!SDL_GetCurrentAudioDriver()) {
|
||||
@@ -1448,27 +1499,16 @@ SDL_AudioDevice *SDL_FindPhysicalAudioDeviceByCallback(bool (*callback)(SDL_Audi
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const void *key;
|
||||
const void *value;
|
||||
void *iter = NULL;
|
||||
|
||||
FindAudioDeviceByCallbackData data = { callback, userdata, NULL };
|
||||
SDL_LockRWLockForReading(current_audio.device_hash_lock);
|
||||
while (SDL_IterateHashTable(current_audio.device_hash, &key, &value, &iter)) {
|
||||
const SDL_AudioDeviceID devid = (SDL_AudioDeviceID) (uintptr_t) key;
|
||||
// bit #1 of devid is set for physical devices and unset for logical.
|
||||
const bool isphysical = !!(devid & (1<<1));
|
||||
if (isphysical) {
|
||||
SDL_AudioDevice *device = (SDL_AudioDevice *) value;
|
||||
if (callback(device, userdata)) { // found it?
|
||||
SDL_UnlockRWLock(current_audio.device_hash_lock);
|
||||
return device;
|
||||
}
|
||||
}
|
||||
}
|
||||
SDL_IterateHashTable(current_audio.device_hash, FindAudioDeviceByCallback, &data);
|
||||
SDL_UnlockRWLock(current_audio.device_hash_lock);
|
||||
|
||||
SDL_SetError("Device not found");
|
||||
return NULL;
|
||||
if (!data.retval) {
|
||||
SDL_SetError("Device not found");
|
||||
}
|
||||
|
||||
return data.retval;
|
||||
}
|
||||
|
||||
static bool TestDeviceHandleCallback(SDL_AudioDevice *device, void *handle)
|
||||
@@ -1483,12 +1523,33 @@ SDL_AudioDevice *SDL_FindPhysicalAudioDeviceByHandle(void *handle)
|
||||
|
||||
const char *SDL_GetAudioDeviceName(SDL_AudioDeviceID devid)
|
||||
{
|
||||
// bit #1 of devid is set for physical devices and unset for logical.
|
||||
const bool islogical = !(devid & (1<<1));
|
||||
const char *result = NULL;
|
||||
SDL_AudioDevice *device = ObtainPhysicalAudioDevice(devid);
|
||||
if (device) {
|
||||
result = SDL_GetPersistentString(device->name);
|
||||
const void *vdev = NULL;
|
||||
|
||||
if (!SDL_GetCurrentAudioDriver()) {
|
||||
SDL_SetError("Audio subsystem is not initialized");
|
||||
} else {
|
||||
// This does not call ObtainPhysicalAudioDevice() because the device's name never changes, so
|
||||
// it doesn't have to lock the whole device. However, just to make sure the device pointer itself
|
||||
// remains valid (in case the device is unplugged at the wrong moment), we hold the
|
||||
// device_hash_lock while we copy the string.
|
||||
SDL_LockRWLockForReading(current_audio.device_hash_lock);
|
||||
SDL_FindInHashTable(current_audio.device_hash, (const void *) (uintptr_t) devid, &vdev);
|
||||
if (!vdev) {
|
||||
SDL_SetError("Invalid audio device instance ID");
|
||||
} else if (islogical) {
|
||||
const SDL_LogicalAudioDevice *logdev = (const SDL_LogicalAudioDevice *) vdev;
|
||||
SDL_assert(logdev->instance_id == devid);
|
||||
result = SDL_GetPersistentString(logdev->physical_device->name);
|
||||
} else {
|
||||
const SDL_AudioDevice *device = (const SDL_AudioDevice *) vdev;
|
||||
SDL_assert(device->instance_id == devid);
|
||||
result = SDL_GetPersistentString(device->name);
|
||||
}
|
||||
SDL_UnlockRWLock(current_audio.device_hash_lock);
|
||||
}
|
||||
ReleaseAudioDevice(device);
|
||||
|
||||
return result;
|
||||
}
|
||||
@@ -1520,7 +1581,9 @@ int *SDL_GetAudioDeviceChannelMap(SDL_AudioDeviceID devid, int *count)
|
||||
SDL_AudioDevice *device = ObtainPhysicalAudioDeviceDefaultAllowed(devid);
|
||||
if (device) {
|
||||
channels = device->spec.channels;
|
||||
result = SDL_ChannelMapDup(device->chmap, channels);
|
||||
if (channels > 0 && device->chmap) {
|
||||
result = SDL_ChannelMapDup(device->chmap, channels);
|
||||
}
|
||||
}
|
||||
ReleaseAudioDevice(device);
|
||||
|
||||
@@ -1696,13 +1759,18 @@ static bool OpenPhysicalAudioDevice(SDL_AudioDevice *device, const SDL_AudioSpec
|
||||
SDL_copyp(&spec, inspec ? inspec : &device->default_spec);
|
||||
PrepareAudioFormat(device->recording, &spec);
|
||||
|
||||
/* We allow the device format to change if it's better than the current settings (by various definitions of "better"). This prevents
|
||||
something low quality, like an old game using S8/8000Hz audio, from ruining a music thing playing at CD quality that tries to open later.
|
||||
(or some VoIP library that opens for mono output ruining your surround-sound game because it got there first).
|
||||
/* We impose a simple minimum on device formats. This prevents something low quality, like an old game using S8/8000Hz audio,
|
||||
from ruining a music thing playing at CD quality that tries to open later, or some VoIP library that opens for mono output
|
||||
ruining your surround-sound game because it got there first.
|
||||
These are just requests! The backend may change any of these values during OpenDevice method! */
|
||||
device->spec.format = (SDL_AUDIO_BITSIZE(device->default_spec.format) >= SDL_AUDIO_BITSIZE(spec.format)) ? device->default_spec.format : spec.format;
|
||||
device->spec.freq = SDL_max(device->default_spec.freq, spec.freq);
|
||||
device->spec.channels = SDL_max(device->default_spec.channels, spec.channels);
|
||||
|
||||
const SDL_AudioFormat minimum_format = device->recording ? DEFAULT_AUDIO_RECORDING_FORMAT : DEFAULT_AUDIO_PLAYBACK_FORMAT;
|
||||
const int minimum_channels = device->recording ? DEFAULT_AUDIO_RECORDING_CHANNELS : DEFAULT_AUDIO_PLAYBACK_CHANNELS;
|
||||
const int minimum_freq = device->recording ? DEFAULT_AUDIO_RECORDING_FREQUENCY : DEFAULT_AUDIO_PLAYBACK_FREQUENCY;
|
||||
|
||||
device->spec.format = (SDL_AUDIO_BITSIZE(minimum_format) >= SDL_AUDIO_BITSIZE(spec.format)) ? minimum_format : spec.format;
|
||||
device->spec.channels = SDL_max(minimum_channels, spec.channels);
|
||||
device->spec.freq = SDL_max(minimum_freq, spec.freq);
|
||||
device->sample_frames = SDL_GetDefaultSampleFramesFromFreq(device->spec.freq);
|
||||
SDL_UpdatedAudioDeviceFormat(device); // start this off sane.
|
||||
|
||||
@@ -1794,7 +1862,7 @@ SDL_AudioDeviceID SDL_OpenAudioDevice(SDL_AudioDeviceID devid, const SDL_AudioSp
|
||||
|
||||
if (result) {
|
||||
SDL_LockRWLockForWriting(current_audio.device_hash_lock);
|
||||
const bool inserted = SDL_InsertIntoHashTable(current_audio.device_hash, (const void *) (uintptr_t) result, logdev);
|
||||
const bool inserted = SDL_InsertIntoHashTable(current_audio.device_hash, (const void *) (uintptr_t) result, logdev, false);
|
||||
SDL_UnlockRWLock(current_audio.device_hash_lock);
|
||||
if (!inserted) {
|
||||
SDL_CloseAudioDevice(result);
|
||||
@@ -1913,10 +1981,6 @@ bool SDL_BindAudioStreams(SDL_AudioDeviceID devid, SDL_AudioStream * const *stre
|
||||
} else if (logdev->simplified) {
|
||||
result = SDL_SetError("Cannot change stream bindings on device opened with SDL_OpenAudioDeviceStream");
|
||||
} else {
|
||||
|
||||
// !!! FIXME: We'll set the device's side's format below, but maybe we should refuse to bind a stream if the app's side doesn't have a format set yet.
|
||||
// !!! FIXME: Actually, why do we allow there to be an invalid format, again?
|
||||
|
||||
// make sure start of list is sane.
|
||||
SDL_assert(!logdev->bound_streams || (logdev->bound_streams->prev_binding == NULL));
|
||||
|
||||
@@ -1951,9 +2015,17 @@ bool SDL_BindAudioStreams(SDL_AudioDeviceID devid, SDL_AudioStream * const *stre
|
||||
|
||||
if (result) {
|
||||
// Now that everything is verified, chain everything together.
|
||||
const bool recording = device->recording;
|
||||
for (int i = 0; i < num_streams; i++) {
|
||||
SDL_AudioStream *stream = streams[i];
|
||||
if (stream) { // shouldn't be NULL, but just in case...
|
||||
// if the stream never had its non-device-end format set, just set it to the device end's format.
|
||||
if (recording && (stream->dst_spec.format == SDL_AUDIO_UNKNOWN)) {
|
||||
SDL_copyp(&stream->dst_spec, &device->spec);
|
||||
} else if (!recording && (stream->src_spec.format == SDL_AUDIO_UNKNOWN)) {
|
||||
SDL_copyp(&stream->src_spec, &device->spec);
|
||||
}
|
||||
|
||||
stream->bound_device = logdev;
|
||||
stream->prev_binding = NULL;
|
||||
stream->next_binding = logdev->bound_streams;
|
||||
|
@@ -444,7 +444,7 @@ static void SincTable(float *table, int len)
|
||||
}
|
||||
|
||||
// Calculate Sinc(x/y), using a lookup table
|
||||
static float Sinc(float *table, int x, int y)
|
||||
static float Sinc(const float *table, int x, int y)
|
||||
{
|
||||
float s = table[x % y];
|
||||
s = ((x / y) & 1) ? -s : s;
|
||||
@@ -587,7 +587,18 @@ Sint64 SDL_GetResampleRate(int src_rate, int dst_rate)
|
||||
SDL_assert(src_rate > 0);
|
||||
SDL_assert(dst_rate > 0);
|
||||
|
||||
Sint64 sample_rate = ((Sint64)src_rate << 32) / (Sint64)dst_rate;
|
||||
Sint64 numerator = (Sint64)src_rate << 32;
|
||||
Sint64 denominator = (Sint64)dst_rate;
|
||||
|
||||
// Generally it's expected that `dst_frames = (src_frames * dst_rate) / src_rate`
|
||||
// To match this as closely as possible without infinite precision, always round up the resample rate.
|
||||
// For example, without rounding up, a sample ratio of 2:3 would have `sample_rate = 0xAAAAAAAA`
|
||||
// After 3 frames, the position would be 0x1.FFFFFFFE, meaning we haven't fully consumed the second input frame.
|
||||
// By rounding up to 0xAAAAAAAB, we would instead reach 0x2.00000001, fulling consuming the second frame.
|
||||
// Technically you could say this is kicking the can 0x100000000 steps down the road, but I'm fine with that :)
|
||||
// sample_rate = div_ceil(numerator, denominator)
|
||||
Sint64 sample_rate = ((numerator - 1) / denominator) + 1;
|
||||
|
||||
SDL_assert(sample_rate > 0);
|
||||
|
||||
return sample_rate;
|
||||
@@ -657,7 +668,7 @@ Sint64 SDL_GetResamplerOutputFrames(Sint64 input_frames, Sint64 resample_rate, S
|
||||
}
|
||||
|
||||
// output_frames = div_ceil(input_offset, resample_rate)
|
||||
Sint64 output_frames = (input_offset > 0) ? ((input_offset + resample_rate * 3 / 4) / resample_rate) : 0;
|
||||
Sint64 output_frames = (input_offset > 0) ? ((input_offset - 1) / resample_rate) + 1 : 0;
|
||||
|
||||
*inout_resample_offset = (output_frames * resample_rate) - input_offset;
|
||||
|
||||
|
@@ -22,6 +22,10 @@
|
||||
|
||||
#include "SDL_sysaudio.h"
|
||||
|
||||
#ifdef SDL_NEON_INTRINSICS
|
||||
#include <fenv.h>
|
||||
#endif
|
||||
|
||||
#define DIVBY2147483648 0.0000000004656612873077392578125f // 0x1p-31f
|
||||
|
||||
// start fallback scalar converters
|
||||
@@ -527,9 +531,29 @@ static void SDL_TARGETING("ssse3") SDL_Convert_Swap32_SSSE3(Uint32* dst, const U
|
||||
#endif
|
||||
|
||||
#ifdef SDL_NEON_INTRINSICS
|
||||
|
||||
// C99 requires that all code modifying floating point environment should
|
||||
// be guarded by the STDC FENV_ACCESS pragma; otherwise, it's undefined
|
||||
// behavior. However, the compiler support for this pragma is bad.
|
||||
#if defined(__clang__)
|
||||
#if __clang_major__ >= 12
|
||||
#if defined(__aarch64__)
|
||||
#pragma STDC FENV_ACCESS ON
|
||||
#endif
|
||||
#endif
|
||||
#elif defined(_MSC_VER)
|
||||
#pragma fenv_access (on)
|
||||
#elif defined(__GNUC__)
|
||||
// GCC does not support the pragma at all
|
||||
#else
|
||||
#pragma STDC FENV_ACCESS ON
|
||||
#endif
|
||||
|
||||
static void SDL_Convert_S8_to_F32_NEON(float *dst, const Sint8 *src, int num_samples)
|
||||
{
|
||||
LOG_DEBUG_AUDIO_CONVERT("S8", "F32 (using NEON)");
|
||||
fenv_t fenv;
|
||||
feholdexcept(&fenv);
|
||||
|
||||
CONVERT_16_REV({
|
||||
vst1_lane_f32(&dst[i], vcvt_n_f32_s32(vdup_n_s32(src[i]), 7), 0);
|
||||
@@ -549,11 +573,14 @@ static void SDL_Convert_S8_to_F32_NEON(float *dst, const Sint8 *src, int num_sam
|
||||
vst1q_f32(&dst[i + 8], floats2);
|
||||
vst1q_f32(&dst[i + 12], floats3);
|
||||
})
|
||||
fesetenv(&fenv);
|
||||
}
|
||||
|
||||
static void SDL_Convert_U8_to_F32_NEON(float *dst, const Uint8 *src, int num_samples)
|
||||
{
|
||||
LOG_DEBUG_AUDIO_CONVERT("U8", "F32 (using NEON)");
|
||||
fenv_t fenv;
|
||||
feholdexcept(&fenv);
|
||||
|
||||
uint8x16_t flipper = vdupq_n_u8(0x80);
|
||||
|
||||
@@ -575,11 +602,14 @@ static void SDL_Convert_U8_to_F32_NEON(float *dst, const Uint8 *src, int num_sam
|
||||
vst1q_f32(&dst[i + 8], floats2);
|
||||
vst1q_f32(&dst[i + 12], floats3);
|
||||
})
|
||||
fesetenv(&fenv);
|
||||
}
|
||||
|
||||
static void SDL_Convert_S16_to_F32_NEON(float *dst, const Sint16 *src, int num_samples)
|
||||
{
|
||||
LOG_DEBUG_AUDIO_CONVERT("S16", "F32 (using NEON)");
|
||||
fenv_t fenv;
|
||||
feholdexcept(&fenv);
|
||||
|
||||
CONVERT_16_REV({
|
||||
vst1_lane_f32(&dst[i], vcvt_n_f32_s32(vdup_n_s32(src[i]), 15), 0);
|
||||
@@ -597,11 +627,14 @@ static void SDL_Convert_S16_to_F32_NEON(float *dst, const Sint16 *src, int num_s
|
||||
vst1q_f32(&dst[i + 8], floats2);
|
||||
vst1q_f32(&dst[i + 12], floats3);
|
||||
})
|
||||
fesetenv(&fenv);
|
||||
}
|
||||
|
||||
static void SDL_Convert_S32_to_F32_NEON(float *dst, const Sint32 *src, int num_samples)
|
||||
{
|
||||
LOG_DEBUG_AUDIO_CONVERT("S32", "F32 (using NEON)");
|
||||
fenv_t fenv;
|
||||
feholdexcept(&fenv);
|
||||
|
||||
CONVERT_16_FWD({
|
||||
vst1_lane_f32(&dst[i], vcvt_n_f32_s32(vld1_dup_s32(&src[i]), 31), 0);
|
||||
@@ -621,11 +654,14 @@ static void SDL_Convert_S32_to_F32_NEON(float *dst, const Sint32 *src, int num_s
|
||||
vst1q_f32(&dst[i + 8], floats2);
|
||||
vst1q_f32(&dst[i + 12], floats3);
|
||||
})
|
||||
fesetenv(&fenv);
|
||||
}
|
||||
|
||||
static void SDL_Convert_F32_to_S8_NEON(Sint8 *dst, const float *src, int num_samples)
|
||||
{
|
||||
LOG_DEBUG_AUDIO_CONVERT("F32", "S8 (using NEON)");
|
||||
fenv_t fenv;
|
||||
feholdexcept(&fenv);
|
||||
|
||||
CONVERT_16_FWD({
|
||||
vst1_lane_s8(&dst[i], vreinterpret_s8_s32(vcvt_n_s32_f32(vld1_dup_f32(&src[i]), 31)), 3);
|
||||
@@ -647,11 +683,14 @@ static void SDL_Convert_F32_to_S8_NEON(Sint8 *dst, const float *src, int num_sam
|
||||
|
||||
vst1q_s8(&dst[i], bytes);
|
||||
})
|
||||
fesetenv(&fenv);
|
||||
}
|
||||
|
||||
static void SDL_Convert_F32_to_U8_NEON(Uint8 *dst, const float *src, int num_samples)
|
||||
{
|
||||
LOG_DEBUG_AUDIO_CONVERT("F32", "U8 (using NEON)");
|
||||
fenv_t fenv;
|
||||
feholdexcept(&fenv);
|
||||
|
||||
uint8x16_t flipper = vdupq_n_u8(0x80);
|
||||
|
||||
@@ -679,11 +718,14 @@ static void SDL_Convert_F32_to_U8_NEON(Uint8 *dst, const float *src, int num_sam
|
||||
|
||||
vst1q_u8(&dst[i], bytes);
|
||||
})
|
||||
fesetenv(&fenv);
|
||||
}
|
||||
|
||||
static void SDL_Convert_F32_to_S16_NEON(Sint16 *dst, const float *src, int num_samples)
|
||||
{
|
||||
LOG_DEBUG_AUDIO_CONVERT("F32", "S16 (using NEON)");
|
||||
fenv_t fenv;
|
||||
feholdexcept(&fenv);
|
||||
|
||||
CONVERT_16_FWD({
|
||||
vst1_lane_s16(&dst[i], vreinterpret_s16_s32(vcvt_n_s32_f32(vld1_dup_f32(&src[i]), 31)), 1);
|
||||
@@ -704,11 +746,14 @@ static void SDL_Convert_F32_to_S16_NEON(Sint16 *dst, const float *src, int num_s
|
||||
vst1q_s16(&dst[i], shorts0);
|
||||
vst1q_s16(&dst[i + 8], shorts1);
|
||||
})
|
||||
fesetenv(&fenv);
|
||||
}
|
||||
|
||||
static void SDL_Convert_F32_to_S32_NEON(Sint32 *dst, const float *src, int num_samples)
|
||||
{
|
||||
LOG_DEBUG_AUDIO_CONVERT("F32", "S32 (using NEON)");
|
||||
fenv_t fenv;
|
||||
feholdexcept(&fenv);
|
||||
|
||||
CONVERT_16_FWD({
|
||||
vst1_lane_s32(&dst[i], vcvt_n_s32_f32(vld1_dup_f32(&src[i]), 31), 0);
|
||||
@@ -728,6 +773,7 @@ static void SDL_Convert_F32_to_S32_NEON(Sint32 *dst, const float *src, int num_s
|
||||
vst1q_s32(&dst[i + 8], ints2);
|
||||
vst1q_s32(&dst[i + 12], ints3);
|
||||
})
|
||||
fesetenv(&fenv);
|
||||
}
|
||||
|
||||
static void SDL_Convert_Swap16_NEON(Uint16* dst, const Uint16* src, int num_samples)
|
||||
@@ -767,6 +813,21 @@ static void SDL_Convert_Swap32_NEON(Uint32* dst, const Uint32* src, int num_samp
|
||||
vst1q_u8((Uint8*)&dst[i + 12], ints3);
|
||||
})
|
||||
}
|
||||
|
||||
#if defined(__clang__)
|
||||
#if __clang_major__ >= 12
|
||||
#if defined(__aarch64__)
|
||||
#pragma STDC FENV_ACCESS DEFAULT
|
||||
#endif
|
||||
#endif
|
||||
#elif defined(_MSC_VER)
|
||||
#pragma fenv_access (off)
|
||||
#elif defined(__GNUC__)
|
||||
//
|
||||
#else
|
||||
#pragma STDC FENV_ACCESS DEFAULT
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#undef CONVERT_16_FWD
|
||||
|
@@ -360,6 +360,7 @@ typedef struct AudioBootStrap
|
||||
const char *desc;
|
||||
bool (*init)(SDL_AudioDriverImpl *impl);
|
||||
bool demand_only; // if true: request explicitly, or it won't be available.
|
||||
bool is_preferred;
|
||||
} AudioBootStrap;
|
||||
|
||||
// Not all of these are available in a given build. Use #ifdefs, etc.
|
||||
|
@@ -1775,6 +1775,7 @@ static bool WaveLoad(SDL_IOStream *src, WaveFile *file, SDL_AudioSpec *spec, Uin
|
||||
int result;
|
||||
Uint32 chunkcount = 0;
|
||||
Uint32 chunkcountlimit = 10000;
|
||||
const Sint64 flen = SDL_GetIOSize(src); // this might be -1 if the IOStream can't determine the total size.
|
||||
const char *hint;
|
||||
Sint64 RIFFstart, RIFFend, lastchunkpos;
|
||||
bool RIFFlengthknown = false;
|
||||
@@ -1883,6 +1884,14 @@ static bool WaveLoad(SDL_IOStream *src, WaveFile *file, SDL_AudioSpec *spec, Uin
|
||||
fmtchunk = *chunk;
|
||||
}
|
||||
} else if (chunk->fourcc == DATA) {
|
||||
/* If the data chunk is bigger than the file, it might be corrupt
|
||||
or the file is truncated. Try to recover by clamping the file
|
||||
size. This also means a malicious file can't allocate 4 gigabytes
|
||||
for the chunks without actually supplying a 4 gigabyte file. */
|
||||
if ((flen > 0) && ((chunk->position + chunk->length) > flen)) {
|
||||
chunk->length = (Uint32) (flen - chunk->position);
|
||||
}
|
||||
|
||||
/* Only use the first data chunk. Handling the wavl list madness
|
||||
* may require a different approach.
|
||||
*/
|
||||
@@ -2114,8 +2123,8 @@ bool SDL_LoadWAV_IO(SDL_IOStream *src, bool closeio, SDL_AudioSpec *spec, Uint8
|
||||
result = WaveLoad(src, &file, spec, audio_buf, audio_len);
|
||||
if (!result) {
|
||||
SDL_free(*audio_buf);
|
||||
audio_buf = NULL;
|
||||
audio_len = 0;
|
||||
*audio_buf = NULL;
|
||||
*audio_len = 0;
|
||||
}
|
||||
|
||||
// Cleanup
|
||||
|
@@ -308,6 +308,12 @@ static bool BuildAAudioStream(SDL_AudioDevice *device)
|
||||
ctx.AAudioStreamBuilder_setFormat(builder, format);
|
||||
ctx.AAudioStreamBuilder_setSampleRate(builder, device->spec.freq);
|
||||
ctx.AAudioStreamBuilder_setChannelCount(builder, device->spec.channels);
|
||||
|
||||
// If no specific buffer size has been requested, the device will pick the optimal
|
||||
if(SDL_GetHint(SDL_HINT_AUDIO_DEVICE_SAMPLE_FRAMES)) {
|
||||
ctx.AAudioStreamBuilder_setBufferCapacityInFrames(builder, 2 * device->sample_frames); // AAudio requires that the buffer capacity is at least
|
||||
ctx.AAudioStreamBuilder_setFramesPerDataCallback(builder, device->sample_frames); // twice the size of the data callback buffer size
|
||||
}
|
||||
|
||||
const aaudio_direction_t direction = (recording ? AAUDIO_DIRECTION_INPUT : AAUDIO_DIRECTION_OUTPUT);
|
||||
ctx.AAudioStreamBuilder_setDirection(builder, direction);
|
||||
@@ -366,7 +372,7 @@ static bool BuildAAudioStream(SDL_AudioDevice *device)
|
||||
hidden->processed_bytes = 0;
|
||||
hidden->callback_bytes = 0;
|
||||
|
||||
hidden->semaphore = SDL_CreateSemaphore(recording ? 0 : hidden->num_buffers);
|
||||
hidden->semaphore = SDL_CreateSemaphore(recording ? 0 : hidden->num_buffers - 1);
|
||||
if (!hidden->semaphore) {
|
||||
LOGI("SDL Failed SDL_CreateSemaphore %s recording:%d", SDL_GetError(), recording);
|
||||
return false;
|
||||
@@ -545,7 +551,7 @@ static bool AAUDIO_Init(SDL_AudioDriverImpl *impl)
|
||||
}
|
||||
|
||||
AudioBootStrap AAUDIO_bootstrap = {
|
||||
"AAudio", "AAudio audio driver", AAUDIO_Init, false
|
||||
"AAudio", "AAudio audio driver", AAUDIO_Init, false, false
|
||||
};
|
||||
|
||||
#endif // SDL_AUDIO_DRIVER_AAUDIO
|
||||
|
@@ -31,7 +31,7 @@ SDL_PROC_UNUSED(void, AAudioStreamBuilder_setSamplesPerFrame, (AAudioStreamBuild
|
||||
SDL_PROC(void, AAudioStreamBuilder_setFormat, (AAudioStreamBuilder * builder, aaudio_format_t format))
|
||||
SDL_PROC_UNUSED(void, AAudioStreamBuilder_setSharingMode, (AAudioStreamBuilder * builder, aaudio_sharing_mode_t sharingMode))
|
||||
SDL_PROC(void, AAudioStreamBuilder_setDirection, (AAudioStreamBuilder * builder, aaudio_direction_t direction))
|
||||
SDL_PROC_UNUSED(void, AAudioStreamBuilder_setBufferCapacityInFrames, (AAudioStreamBuilder * builder, int32_t numFrames))
|
||||
SDL_PROC(void, AAudioStreamBuilder_setBufferCapacityInFrames, (AAudioStreamBuilder * builder, int32_t numFrames))
|
||||
SDL_PROC(void, AAudioStreamBuilder_setPerformanceMode, (AAudioStreamBuilder * builder, aaudio_performance_mode_t mode))
|
||||
SDL_PROC_UNUSED(void, AAudioStreamBuilder_setUsage, (AAudioStreamBuilder * builder, aaudio_usage_t usage)) // API 28
|
||||
SDL_PROC_UNUSED(void, AAudioStreamBuilder_setContentType, (AAudioStreamBuilder * builder, aaudio_content_type_t contentType)) // API 28
|
||||
|
@@ -566,7 +566,7 @@ static enum snd_pcm_chmap_position sdl_channel_maps[SDL_AUDIO_ALSA__SDL_CHMAPS_N
|
||||
};
|
||||
|
||||
// Helper for the function right below.
|
||||
static bool has_pos(unsigned int *chmap, unsigned int pos)
|
||||
static bool has_pos(const unsigned int *chmap, unsigned int pos)
|
||||
{
|
||||
for (unsigned int chan_idx = 0; ; chan_idx++) {
|
||||
if (chan_idx == 6) {
|
||||
@@ -586,7 +586,7 @@ static bool has_pos(unsigned int *chmap, unsigned int pos)
|
||||
#define HAVE_REAR 1
|
||||
#define HAVE_SIDE 2
|
||||
#define HAVE_BOTH 3
|
||||
static void sdl_6chans_set_rear_or_side_channels_from_alsa_6chans(unsigned int *sdl_6chans, unsigned int *alsa_6chans)
|
||||
static void sdl_6chans_set_rear_or_side_channels_from_alsa_6chans(unsigned int *sdl_6chans, const unsigned int *alsa_6chans)
|
||||
{
|
||||
// For alsa channel maps with 6 channels and with SND_CHMAP_FL,SND_CHMAP_FR,SND_CHMAP_FC,
|
||||
// SND_CHMAP_LFE, reduce our 6 channels maps to a uniq one.
|
||||
@@ -638,7 +638,7 @@ static void sdl_6chans_set_rear_or_side_channels_from_alsa_6chans(unsigned int *
|
||||
#undef HAVE_SIDE
|
||||
#undef HAVE_BOTH
|
||||
|
||||
static void swizzle_map_compute_alsa_subscan(struct ALSA_pcm_cfg_ctx *ctx, int *swizzle_map, unsigned int sdl_pos_idx)
|
||||
static void swizzle_map_compute_alsa_subscan(const struct ALSA_pcm_cfg_ctx *ctx, int *swizzle_map, unsigned int sdl_pos_idx)
|
||||
{
|
||||
swizzle_map[sdl_pos_idx] = -1;
|
||||
for (unsigned int alsa_pos_idx = 0; ; alsa_pos_idx++) {
|
||||
@@ -652,7 +652,7 @@ static void swizzle_map_compute_alsa_subscan(struct ALSA_pcm_cfg_ctx *ctx, int *
|
||||
}
|
||||
|
||||
// XXX: this must stay playback/recording symetric.
|
||||
static void swizzle_map_compute(struct ALSA_pcm_cfg_ctx *ctx, int *swizzle_map, bool *needs_swizzle)
|
||||
static void swizzle_map_compute(const struct ALSA_pcm_cfg_ctx *ctx, int *swizzle_map, bool *needs_swizzle)
|
||||
{
|
||||
*needs_swizzle = false;
|
||||
for (unsigned int sdl_pos_idx = 0; sdl_pos_idx != ctx->chans_n; sdl_pos_idx++) {
|
||||
@@ -668,7 +668,7 @@ static void swizzle_map_compute(struct ALSA_pcm_cfg_ctx *ctx, int *swizzle_map,
|
||||
#define CHMAP_NOT_FOUND 2
|
||||
// Should always be a queried alsa channel map unless the queried alsa channel map was of type VAR,
|
||||
// namely we can program the channel positions directly from the SDL channel map.
|
||||
static int alsa_chmap_install(struct ALSA_pcm_cfg_ctx *ctx, unsigned int *chmap)
|
||||
static int alsa_chmap_install(struct ALSA_pcm_cfg_ctx *ctx, const unsigned int *chmap)
|
||||
{
|
||||
bool isstack;
|
||||
snd_pcm_chmap_t *chmap_to_install = (snd_pcm_chmap_t*)SDL_small_alloc(unsigned int, 1 + ctx->chans_n, &isstack);
|
||||
@@ -698,7 +698,7 @@ static int alsa_chmap_install(struct ALSA_pcm_cfg_ctx *ctx, unsigned int *chmap)
|
||||
|
||||
// We restrict the alsa channel maps because in the unordered matches we do only simple accounting.
|
||||
// In the end, this will handle mostly alsa channel maps with more than one SND_CHMAP_NA position fillers.
|
||||
static bool alsa_chmap_has_duplicate_position(struct ALSA_pcm_cfg_ctx *ctx, unsigned int *pos)
|
||||
static bool alsa_chmap_has_duplicate_position(const struct ALSA_pcm_cfg_ctx *ctx, const unsigned int *pos)
|
||||
{
|
||||
if (ctx->chans_n < 2) {// we need at least 2 positions
|
||||
LOGDEBUG("channel map:no duplicate");
|
||||
@@ -1156,7 +1156,7 @@ static bool ALSA_OpenDevice(SDL_AudioDevice *device)
|
||||
#if SDL_ALSA_DEBUG
|
||||
snd_pcm_uframes_t bufsize;
|
||||
ALSA_snd_pcm_hw_params_get_buffer_size(cfg_ctx.hwparams, &bufsize);
|
||||
SDL_LogError(SDL_LOG_CATEGORY_AUDIO,
|
||||
SDL_LogDebug(SDL_LOG_CATEGORY_AUDIO,
|
||||
"ALSA: period size = %ld, periods = %u, buffer size = %lu",
|
||||
cfg_ctx.persize, cfg_ctx.periods, bufsize);
|
||||
#endif
|
||||
@@ -1187,7 +1187,6 @@ static bool ALSA_OpenDevice(SDL_AudioDevice *device)
|
||||
ALSA_snd_pcm_nonblock(cfg_ctx.device->hidden->pcm, 0);
|
||||
}
|
||||
#endif
|
||||
ALSA_snd_pcm_start(cfg_ctx.device->hidden->pcm);
|
||||
return true; // We're ready to rock and roll. :-)
|
||||
|
||||
err_cleanup_ctx:
|
||||
@@ -1200,6 +1199,13 @@ err_free_device_hidden:
|
||||
return false;
|
||||
}
|
||||
|
||||
static void ALSA_ThreadInit(SDL_AudioDevice *device)
|
||||
{
|
||||
SDL_SetCurrentThreadPriority(device->recording ? SDL_THREAD_PRIORITY_HIGH : SDL_THREAD_PRIORITY_TIME_CRITICAL);
|
||||
// do snd_pcm_start as close to the first time we PlayDevice as possible to prevent an underrun at startup.
|
||||
ALSA_snd_pcm_start(device->hidden->pcm);
|
||||
}
|
||||
|
||||
static ALSA_Device *hotplug_devices = NULL;
|
||||
|
||||
static int hotplug_device_process(snd_ctl_t *ctl, snd_ctl_card_info_t *ctl_card_info, int dev_idx,
|
||||
@@ -1497,6 +1503,7 @@ static bool ALSA_Init(SDL_AudioDriverImpl *impl)
|
||||
|
||||
impl->DetectDevices = ALSA_DetectDevices;
|
||||
impl->OpenDevice = ALSA_OpenDevice;
|
||||
impl->ThreadInit = ALSA_ThreadInit;
|
||||
impl->WaitDevice = ALSA_WaitDevice;
|
||||
impl->GetDeviceBuf = ALSA_GetDeviceBuf;
|
||||
impl->PlayDevice = ALSA_PlayDevice;
|
||||
@@ -1513,7 +1520,7 @@ static bool ALSA_Init(SDL_AudioDriverImpl *impl)
|
||||
}
|
||||
|
||||
AudioBootStrap ALSA_bootstrap = {
|
||||
"alsa", "ALSA PCM audio", ALSA_Init, false
|
||||
"alsa", "ALSA PCM audio", ALSA_Init, false, false
|
||||
};
|
||||
|
||||
#endif // SDL_AUDIO_DRIVER_ALSA
|
||||
|
@@ -420,7 +420,8 @@ static bool UpdateAudioSession(SDL_AudioDevice *device, bool open, bool allow_pl
|
||||
|
||||
hint = SDL_GetHint(SDL_HINT_AUDIO_CATEGORY);
|
||||
if (hint) {
|
||||
if (SDL_strcasecmp(hint, "AVAudioSessionCategoryAmbient") == 0) {
|
||||
if (SDL_strcasecmp(hint, "AVAudioSessionCategoryAmbient") == 0 ||
|
||||
SDL_strcasecmp(hint, "ambient") == 0) {
|
||||
category = AVAudioSessionCategoryAmbient;
|
||||
} else if (SDL_strcasecmp(hint, "AVAudioSessionCategorySoloAmbient") == 0) {
|
||||
category = AVAudioSessionCategorySoloAmbient;
|
||||
@@ -1034,7 +1035,7 @@ static bool COREAUDIO_Init(SDL_AudioDriverImpl *impl)
|
||||
}
|
||||
|
||||
AudioBootStrap COREAUDIO_bootstrap = {
|
||||
"coreaudio", "CoreAudio", COREAUDIO_Init, false
|
||||
"coreaudio", "CoreAudio", COREAUDIO_Init, false, false
|
||||
};
|
||||
|
||||
#endif // SDL_AUDIO_DRIVER_COREAUDIO
|
||||
|
@@ -206,7 +206,7 @@ static void DSOUND_DetectDevices(SDL_AudioDevice **default_playback, SDL_AudioDe
|
||||
{
|
||||
#ifdef HAVE_MMDEVICEAPI_H
|
||||
if (SupportsIMMDevice) {
|
||||
SDL_IMMDevice_EnumerateEndpoints(default_playback, default_recording);
|
||||
SDL_IMMDevice_EnumerateEndpoints(default_playback, default_recording, SDL_AUDIO_UNKNOWN);
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
@@ -674,7 +674,7 @@ static bool DSOUND_Init(SDL_AudioDriverImpl *impl)
|
||||
}
|
||||
|
||||
AudioBootStrap DSOUND_bootstrap = {
|
||||
"directsound", "DirectSound", DSOUND_Init, false
|
||||
"directsound", "DirectSound", DSOUND_Init, false, false
|
||||
};
|
||||
|
||||
#endif // SDL_AUDIO_DRIVER_DSOUND
|
||||
|
@@ -165,7 +165,7 @@ static bool DISKAUDIO_Init(SDL_AudioDriverImpl *impl)
|
||||
}
|
||||
|
||||
AudioBootStrap DISKAUDIO_bootstrap = {
|
||||
"disk", "direct-to-disk audio", DISKAUDIO_Init, true
|
||||
"disk", "direct-to-disk audio", DISKAUDIO_Init, true, false
|
||||
};
|
||||
|
||||
#endif // SDL_AUDIO_DRIVER_DISK
|
||||
|
@@ -297,7 +297,7 @@ static bool DSP_Init(SDL_AudioDriverImpl *impl)
|
||||
}
|
||||
|
||||
AudioBootStrap DSP_bootstrap = {
|
||||
"dsp", "Open Sound System (/dev/dsp)", DSP_Init, false
|
||||
"dsp", "Open Sound System (/dev/dsp)", DSP_Init, false, false
|
||||
};
|
||||
|
||||
#endif // SDL_AUDIO_DRIVER_OSS
|
||||
|
@@ -131,5 +131,5 @@ static bool DUMMYAUDIO_Init(SDL_AudioDriverImpl *impl)
|
||||
}
|
||||
|
||||
AudioBootStrap DUMMYAUDIO_bootstrap = {
|
||||
"dummy", "SDL dummy audio driver", DUMMYAUDIO_Init, true
|
||||
"dummy", "SDL dummy audio driver", DUMMYAUDIO_Init, true, false
|
||||
};
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user