mirror of
https://github.com/MobileGL-Dev/MobileGL
synced 2026-09-08 04:08:32 +09:00
Compare commits
1129
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
30c6f55c2d | ||
|
|
b373535d6e | ||
|
|
4a3a44924a | ||
|
|
1b2a7989af | ||
|
|
83d1ce177e | ||
|
|
4321c4a827 | ||
|
|
a039ce0987 | ||
|
|
accfaab720 | ||
|
|
35658eb998 | ||
|
|
ccbde0196e | ||
|
|
0209c5461f | ||
|
|
810b4886c7 | ||
|
|
7dfc2149d8 | ||
|
|
9d1e8bd7cd | ||
|
|
bfa4049ac1 | ||
|
|
87c56ce3d5 | ||
|
|
f2ab50b84e | ||
|
|
b6ac6c182e | ||
|
|
5e9f0f0c70 | ||
|
|
e4455aed9a | ||
|
|
bc018c9513 | ||
|
|
2ecba4d70c | ||
|
|
1e11a5950e | ||
|
|
b324363db0 | ||
|
|
a654b15190 | ||
|
|
75ea7f8c0c | ||
|
|
09aeee4c03 | ||
|
|
87122973be | ||
|
|
8b9adc5121 | ||
|
|
9e42e40705 | ||
|
|
8a91225eb1 | ||
|
|
e82815802e | ||
|
|
67069d4a12 | ||
|
|
4a38e7224e | ||
|
|
645f2f748f | ||
|
|
5652f9ae5f | ||
|
|
f3b0b242dd | ||
|
|
876cb7bcd3 | ||
|
|
ee9a121c6f | ||
|
|
00439c5c4a | ||
|
|
d7286a5832 | ||
|
|
972804fdc7 | ||
|
|
bca7328421 | ||
|
|
8097c0d7b1 | ||
|
|
641f54e1b7 | ||
|
|
c36bfe0843 | ||
|
|
8ae66521e3 | ||
|
|
6e21fd9a35 | ||
|
|
a2e8faafe5 | ||
|
|
668fa3033e | ||
|
|
139f3f978d | ||
|
|
09f96e5ba5 | ||
|
|
592a69b1c4 | ||
|
|
9211341ae7 | ||
|
|
5f9d354adb | ||
|
|
0ae36b71f5 | ||
|
|
20e2768f27 | ||
|
|
00c8b5ae3a | ||
|
|
7687c19b33 | ||
|
|
fc3a7cd5f1 | ||
|
|
0b7f906533 | ||
|
|
c78a94ed09 | ||
|
|
debcb171ce | ||
|
|
282468c9d5 | ||
|
|
34b06da83b | ||
|
|
3d55f38dab | ||
|
|
16426db244 | ||
|
|
6f8c76f06c | ||
|
|
43f2043478 | ||
|
|
f61f068e28 | ||
|
|
e234d471fe | ||
|
|
6ff97a9bb1 | ||
|
|
8adf1d3b8a | ||
|
|
2935279603 | ||
|
|
918b39bb63 | ||
|
|
963e88943c | ||
|
|
1a75bcba5e | ||
|
|
b64309edfc | ||
|
|
e3f1db0a9a | ||
|
|
2c848ab44b | ||
|
|
9b23594415 | ||
|
|
e2e52965df | ||
|
|
6e7907f183 | ||
|
|
b4be1292b8 | ||
|
|
db58f4c214 | ||
|
|
59bad77176 | ||
|
|
3504fca8da | ||
|
|
e61817ff6a | ||
|
|
b9df28838c | ||
|
|
fff00e65c4 | ||
|
|
8320b4f456 | ||
|
|
a757669df5 | ||
|
|
e16c0645c0 | ||
|
|
8d37763fd3 | ||
|
|
e0d0551e7b | ||
|
|
caa814e8f9 | ||
|
|
2502d32a2e | ||
|
|
e57dd3529e | ||
|
|
4b8d809237 | ||
|
|
d42182befc | ||
|
|
5efdb1016e | ||
|
|
15e24cda78 | ||
|
|
d22d2d64f2 | ||
|
|
5013108a7f | ||
|
|
359ba1c572 | ||
|
|
733523011b | ||
|
|
14fc13c34d | ||
|
|
e9fee1358d | ||
|
|
dae3dd9996 | ||
|
|
556db8b02e | ||
|
|
96e993eecf | ||
|
|
fb3e2123cc | ||
|
|
bd8bc1e251 | ||
|
|
22416cf2f0 | ||
|
|
8bdf990810 | ||
|
|
9e90d9508b | ||
|
|
7ccf858181 | ||
|
|
3c66016489 | ||
|
|
b88042bdff | ||
|
|
6540c2eec1 | ||
|
|
d5940f40be | ||
|
|
033ba16aff | ||
|
|
47467ea1ab | ||
|
|
d84b4da766 | ||
|
|
07b7f7eba5 | ||
|
|
7f9953fdee | ||
|
|
ccd51bf2d3 | ||
|
|
60f06d1b8d | ||
|
|
e34f3d915c | ||
|
|
f65c71da27 | ||
|
|
5fbed32ef6 | ||
|
|
8413874e82 | ||
|
|
fe89dc82dc | ||
|
|
5938a18131 | ||
|
|
f79b7a91d7 | ||
|
|
ea71b3d96f | ||
|
|
f96f4a0a3b | ||
|
|
9f062fbd69 | ||
|
|
56428df5e5 | ||
|
|
25a5fe0757 | ||
|
|
2104d9865d | ||
|
|
dcb8bb1871 | ||
|
|
6b656d3f96 | ||
|
|
c2a0db3d12 | ||
|
|
c810b27a83 | ||
|
|
25f6c67859 | ||
|
|
5f78ff2b51 | ||
|
|
9226ea092c | ||
|
|
12d514229c | ||
|
|
b69b6b2987 | ||
|
|
377b967996 | ||
|
|
e132e9edc1 | ||
|
|
49a18f68e1 | ||
|
|
fe6e7902d3 | ||
|
|
c4e40c2eb2 | ||
|
|
f7ea6cd1d9 | ||
|
|
cf229c4a5b | ||
|
|
058ec6d26e | ||
|
|
098f8d0738 | ||
|
|
5f6a0b5969 | ||
|
|
49b0743422 | ||
|
|
13aa88b5ef | ||
|
|
e055b9a644 | ||
|
|
324498ccac | ||
|
|
206d8ab36a | ||
|
|
53989d1711 | ||
|
|
7b7e00dbb3 | ||
|
|
7d4ebfc305 | ||
|
|
dfe91e96a5 | ||
|
|
4d61f11bb8 | ||
|
|
5412d1c165 | ||
|
|
3ce7a2fd46 | ||
|
|
f8f3d6e657 | ||
|
|
781bda2573 | ||
|
|
d06720f534 | ||
|
|
a3b440e7c5 | ||
|
|
ebdadcecff | ||
|
|
876d5e13af | ||
|
|
2ad1207a31 | ||
|
|
8bd6c9719f | ||
|
|
91326025f3 | ||
|
|
3324dbfbf6 | ||
|
|
e1b59bcb46 | ||
|
|
8f57e837b8 | ||
|
|
6b7de70bf3 | ||
|
|
0ac4d8658d | ||
|
|
1a4fde893f | ||
|
|
e01ebc8fc7 | ||
|
|
533e6bd57c | ||
|
|
ad822e1095 | ||
|
|
129091a430 | ||
|
|
1a91e48219 | ||
|
|
4bcedc84b9 | ||
|
|
1357435e94 | ||
|
|
7c67c99717 | ||
|
|
a58016f49d | ||
|
|
8a66b0a542 | ||
|
|
92cdcd952b | ||
|
|
d7156631d1 | ||
|
|
81125dd06d | ||
|
|
7bd4d74b2c | ||
|
|
b25562711a | ||
|
|
927d95fb41 | ||
|
|
843fdcb47a | ||
|
|
ad6ffbe42e | ||
|
|
5f94f72be5 | ||
|
|
0ce95894a3 | ||
|
|
beb9301282 | ||
|
|
0822cb871d | ||
|
|
bfea5dc8ba | ||
|
|
9fb5a38172 | ||
|
|
74ff24e4a4 | ||
|
|
178dbd33ba | ||
|
|
f5e59b1c84 | ||
|
|
ba7bf87ee0 | ||
|
|
99bc2e121b | ||
|
|
341749706d | ||
|
|
a25bfcb0d0 | ||
|
|
b2ea29b91d | ||
|
|
a28f5eeee6 | ||
|
|
2febb10319 | ||
|
|
ae3a27bf06 | ||
|
|
5a751a6745 | ||
|
|
0a7061f375 | ||
|
|
c7db89a200 | ||
|
|
a6784e7714 | ||
|
|
a9b92a756b | ||
|
|
52eb6b3f2a | ||
|
|
43e59d8fce | ||
|
|
ceaa6ff5f8 | ||
|
|
a77088eeb3 | ||
|
|
162dbf8750 | ||
|
|
1c2924eef9 | ||
|
|
acc826ee9f | ||
|
|
8e58875b8f | ||
|
|
51451e8de3 | ||
|
|
b806397ae3 | ||
|
|
358efe4d1b | ||
|
|
cd3ff1f881 | ||
|
|
6c10876532 | ||
|
|
ce8a2356d7 | ||
|
|
37f26d1bb1 | ||
|
|
22bc4fbbc9 | ||
|
|
18941f9e83 | ||
|
|
0b332bdc58 | ||
|
|
2abdebcd96 | ||
|
|
e39af3b940 | ||
|
|
3b2c2028b9 | ||
|
|
55020a1e86 | ||
|
|
6d4ddc47f6 | ||
|
|
2aff5dc650 | ||
|
|
7aa7b82628 | ||
|
|
fd530156a6 | ||
|
|
56c98041e3 | ||
|
|
b90df42a45 | ||
|
|
40333fa84a | ||
|
|
a079e5e6b9 | ||
|
|
f6f84267b6 | ||
|
|
6eeb67f08b | ||
|
|
155aaa0d4b | ||
|
|
9a6cf7fc7f | ||
|
|
aaeb2711ff | ||
|
|
d4d0407a1c | ||
|
|
eb3621cb3c | ||
|
|
2ad7e2da40 | ||
|
|
a7d8e90600 | ||
|
|
e8f385820a | ||
|
|
07927dc4a3 | ||
|
|
91eb75a95d | ||
|
|
a109675f1f | ||
|
|
78f42b5cd0 | ||
|
|
68bdea41d2 | ||
|
|
00eb158196 | ||
|
|
3b27533793 | ||
|
|
93f08e251d | ||
|
|
cd3936666d | ||
|
|
41c8850846 | ||
|
|
8fe266e027 | ||
|
|
9af964de67 | ||
|
|
9f4c9b61a0 | ||
|
|
8e962345e4 | ||
|
|
5319367869 | ||
|
|
e351ef9f41 | ||
|
|
4bfa8ce934 | ||
|
|
6855ae42ef | ||
|
|
7fd9eb15d3 | ||
|
|
319806c48a | ||
|
|
de8342a96b | ||
|
|
6577e1bcc1 | ||
|
|
07638b8577 | ||
|
|
d13a19126b | ||
|
|
dfaa2c259b | ||
|
|
cb27ebc576 | ||
|
|
fd5cc2e5c1 | ||
|
|
5bfb55cfd8 | ||
|
|
1b47f1bb92 | ||
|
|
f4ce17af51 | ||
|
|
2088009c01 | ||
|
|
77378bbf07 | ||
|
|
74509ae0a3 | ||
|
|
f0ab82ea2a | ||
|
|
d251bd3a91 | ||
|
|
850d363cac | ||
|
|
5addbb3bdd | ||
|
|
8e3bbda2f2 | ||
|
|
eb4a81b55f | ||
|
|
ea098c0409 | ||
|
|
bf0bae0e59 | ||
|
|
41f6670a10 | ||
|
|
c2ffa93c90 | ||
|
|
fc9653f460 | ||
|
|
afa89772e7 | ||
|
|
ca23fe4d6f | ||
|
|
522d5ad9f7 | ||
|
|
202922613b | ||
|
|
4db0fe58c0 | ||
|
|
5eff8b2e30 | ||
|
|
b966ef8b5e | ||
|
|
751c5745b0 | ||
|
|
6823b1e46a | ||
|
|
207b746273 | ||
|
|
edff307782 | ||
|
|
1143c961b6 | ||
|
|
2fab6c5b0b | ||
|
|
42ad1634bf | ||
|
|
8e897d54a2 | ||
|
|
863aa77ff0 | ||
|
|
5e3cb98934 | ||
|
|
c301591dcc | ||
|
|
5c63515259 | ||
|
|
0ae1b76262 | ||
|
|
99d32439a8 | ||
|
|
4225cc4333 | ||
|
|
7daa69cf73 | ||
|
|
653ca9ea74 | ||
|
|
3f0744a8ce | ||
|
|
7f1cb14d33 | ||
|
|
de17fdf5b0 | ||
|
|
39a8e72ee9 | ||
|
|
8f55179493 | ||
|
|
cb2ce8f2a5 | ||
|
|
33a4afba5e | ||
|
|
3d420f6d12 | ||
|
|
1e58be34da | ||
|
|
0cf9d9223d | ||
|
|
938b92277f | ||
|
|
419ffb3b5e | ||
|
|
ad7d145ece | ||
|
|
516566321d | ||
|
|
7918300848 | ||
|
|
00679642d6 | ||
|
|
4769a9cf7b | ||
|
|
9f9e955b92 | ||
|
|
85f7c8f4a6 | ||
|
|
f0ccd40a6b | ||
|
|
2f39c43270 | ||
|
|
acda4c24aa | ||
|
|
1021a7f741 | ||
|
|
91650e29c5 | ||
|
|
a09d6fa8ff | ||
|
|
9d6a6548e8 | ||
|
|
b112fc0408 | ||
|
|
d0f54395c7 | ||
|
|
31b3053c56 | ||
|
|
f69fbef4b0 | ||
|
|
99299cf0f3 | ||
|
|
197fdb972b | ||
|
|
9ae554cabe | ||
|
|
0fe514fe1d | ||
|
|
5c7457dbc6 | ||
|
|
77aa26661d | ||
|
|
ffec1618f1 | ||
|
|
afc97efcaf | ||
|
|
aa0cff5742 | ||
|
|
639ec18a50 | ||
|
|
0b4014d665 | ||
|
|
e9ef6db44b | ||
|
|
eac7a9e474 | ||
|
|
53e4778054 | ||
|
|
484174767d | ||
|
|
3b5047f2c4 | ||
|
|
0a7bd794b5 | ||
|
|
8c2dd621b6 | ||
|
|
f60a3002e9 | ||
|
|
a52ec9116e | ||
|
|
20fbfc2956 | ||
|
|
8a388f3908 | ||
|
|
35fd55d4be | ||
|
|
80bb46cbb9 | ||
|
|
97cbb35dbd | ||
|
|
c7ca2fecf2 | ||
|
|
00b972252b | ||
|
|
fbac2ceb4e | ||
|
|
b67a8d2e3a | ||
|
|
a051e51946 | ||
|
|
3b807f6275 | ||
|
|
26ab093679 | ||
|
|
db2806a12a | ||
|
|
cc7e95c84d | ||
|
|
48d5e522d8 | ||
|
|
60ab186b5c | ||
|
|
c24015b618 | ||
|
|
27ed4cd30b | ||
|
|
1e49519c81 | ||
|
|
39182f3a5e | ||
|
|
d7139894da | ||
|
|
6efcecc147 | ||
|
|
0d4c227196 | ||
|
|
d7e1aee645 | ||
|
|
a601307d6f | ||
|
|
4b8e558565 | ||
|
|
4c0cc8b038 | ||
|
|
d4a98ad94f | ||
|
|
bdd4261a5a | ||
|
|
0a1e85e9e6 | ||
|
|
08a9c9bb61 | ||
|
|
b3fe9c1544 | ||
|
|
5e9844a4e5 | ||
|
|
c6443e5039 | ||
|
|
141eeb4e87 | ||
|
|
4233a6031a | ||
|
|
05f5c0c2b5 | ||
|
|
2657edc003 | ||
|
|
52d98ee7c3 | ||
|
|
c537f9814c | ||
|
|
7819a8e405 | ||
|
|
b281afe665 | ||
|
|
28c15148f2 | ||
|
|
3822d8169a | ||
|
|
8db0841949 | ||
|
|
e5c0782615 | ||
|
|
b68d2859e8 | ||
|
|
21dcbc9e52 | ||
|
|
e4f027e13b | ||
|
|
876195de80 | ||
|
|
e298e5be51 | ||
|
|
0b262d4f3a | ||
|
|
da0e326534 | ||
|
|
3714e275ab | ||
|
|
ee4dc70336 | ||
|
|
7c2380ccce | ||
|
|
adc927668b | ||
|
|
04335fdad7 | ||
|
|
e7d9da42dc | ||
|
|
58b620dee3 | ||
|
|
c902721683 | ||
|
|
e5c3a6beba | ||
|
|
937ace68a6 | ||
|
|
2c214affbe | ||
|
|
9f4a1041ba | ||
|
|
8ed8efe347 | ||
|
|
aa83aa1519 | ||
|
|
69caca5903 | ||
|
|
e886a93a18 | ||
|
|
45276bbb7c | ||
|
|
b220c8baab | ||
|
|
02a2f4af4a | ||
|
|
de028204a2 | ||
|
|
5071a98e00 | ||
|
|
4f1def412c | ||
|
|
9ab001bf75 | ||
|
|
69a7374b51 | ||
|
|
e4cc101639 | ||
|
|
3063374834 | ||
|
|
100d5bca99 | ||
|
|
711e427b76 | ||
|
|
5bb9faaaa5 | ||
|
|
96c3024544 | ||
|
|
5d2a954b4b | ||
|
|
c3755d77ef | ||
|
|
81a717ada7 | ||
|
|
17bbe3e6ba | ||
|
|
0519cdeb9c | ||
|
|
f08859d1c5 | ||
|
|
6a9738a7c5 | ||
|
|
91b04f6995 | ||
|
|
ffd4ec3408 | ||
|
|
0e9bca40f3 | ||
|
|
1e64a85bcd | ||
|
|
f94861926a | ||
|
|
6b4c911f06 | ||
|
|
eb705c53bf | ||
|
|
a1a9b16457 | ||
|
|
b79424a78c | ||
|
|
cb4e6b5f19 | ||
|
|
3f36248638 | ||
|
|
0a89ad4f30 | ||
|
|
56f45499e1 | ||
|
|
4089a42d3b | ||
|
|
13abb24324 | ||
|
|
407d57e9b9 | ||
|
|
b3824c871c | ||
|
|
1da2550774 | ||
|
|
ecc91290cb | ||
|
|
c69cae1ba2 | ||
|
|
9934b1b2b3 | ||
|
|
5860856bc1 | ||
|
|
ab6d9f60e7 | ||
|
|
6293f3f0ab | ||
|
|
7a9cb2dafb | ||
|
|
fe6bd76cfa | ||
|
|
ea61946bfc | ||
|
|
5e0a6c70b8 | ||
|
|
e8b668a701 | ||
|
|
fe741f892e | ||
|
|
1b48ffaaf7 | ||
|
|
e58402bc9e | ||
|
|
0ee8a060e2 | ||
|
|
3ba9709748 | ||
|
|
51554eac7c | ||
|
|
11aff346f1 | ||
|
|
a9c49cbc77 | ||
|
|
d1c58904f4 | ||
|
|
49e80ae4cf | ||
|
|
37ffacb373 | ||
|
|
a87a828297 | ||
|
|
882a9302e5 | ||
|
|
b048037145 | ||
|
|
d2d95cb4cc | ||
|
|
1a9f546309 | ||
|
|
521bcadbee | ||
|
|
7a30c56b13 | ||
|
|
32c062d019 | ||
|
|
75fc52febe | ||
|
|
6ba9382321 | ||
|
|
8ca8fa1520 | ||
|
|
936abafde9 | ||
|
|
e72bdb67b5 | ||
|
|
657c672899 | ||
|
|
a6b34ee5bf | ||
|
|
c67e6e26fa | ||
|
|
d1f5aff440 | ||
|
|
e244974928 | ||
|
|
da5b9686ba | ||
|
|
a0aaba3cb5 | ||
|
|
4d44dda117 | ||
|
|
45ae87c017 | ||
|
|
e79d2fd059 | ||
|
|
352df37b91 | ||
|
|
1a997ae8d4 | ||
|
|
7fe156cebc | ||
|
|
64fd36bb60 | ||
|
|
419a67cd08 | ||
|
|
73b583cc00 | ||
|
|
d0f4b1d7d1 | ||
|
|
718eeaab43 | ||
|
|
d3db296b6d | ||
|
|
1454c967c6 | ||
|
|
ca8d2b7bab | ||
|
|
1c318db4a0 | ||
|
|
9cd749b707 | ||
|
|
363bedb245 | ||
|
|
4af61f9c00 | ||
|
|
6e5e458501 | ||
|
|
69cf694ca1 | ||
|
|
e3f73291e9 | ||
|
|
854d293404 | ||
|
|
caf10a267d | ||
|
|
d8cd5a235a | ||
|
|
0c31de3afc | ||
|
|
8d3dd14498 | ||
|
|
2709b9754f | ||
|
|
ef6ef0fc31 | ||
|
|
fb9a32c224 | ||
|
|
55db06bf5c | ||
|
|
0139cabfbc | ||
|
|
ff0a3c5b9a | ||
|
|
8182d9e402 | ||
|
|
126239db24 | ||
|
|
6efc4d4fc3 | ||
|
|
6d86c9fe98 | ||
|
|
2b915d5680 | ||
|
|
dc49873d3e | ||
|
|
426895766d | ||
|
|
1e5e993704 | ||
|
|
37e0312c72 | ||
|
|
95e086442c | ||
|
|
131c9a2db6 | ||
|
|
fe7af0839e | ||
|
|
6b6f224e1e | ||
|
|
850081d313 | ||
|
|
60bb091927 | ||
|
|
3809a9f52f | ||
|
|
c664815fee | ||
|
|
784b53344c | ||
|
|
8b39e3c8a9 | ||
|
|
e944944e7c | ||
|
|
7af4c7d71b | ||
|
|
845f699e3f | ||
|
|
49b66c30c1 | ||
|
|
a0cc3e5f3e | ||
|
|
2ce2d1c731 | ||
|
|
e85b067314 | ||
|
|
4cb82e2e50 | ||
|
|
2534394df3 | ||
|
|
1c8af9253b | ||
|
|
ac5c26af99 | ||
|
|
e93dff52dc | ||
|
|
899563165e | ||
|
|
0d3236c3cc | ||
|
|
1f831d79a9 | ||
|
|
651c91f78e | ||
|
|
a01037b6fe | ||
|
|
55e89e169f | ||
|
|
0d26f49d0b | ||
|
|
7ee85e5a76 | ||
|
|
89bfebf767 | ||
|
|
b3b304e9e6 | ||
|
|
5b2d18fdff | ||
|
|
1c3a3455ab | ||
|
|
2878939712 | ||
|
|
cf87891b35 | ||
|
|
b04481e6da | ||
|
|
d3ea83992c | ||
|
|
e6c5e132b8 | ||
|
|
6e65942891 | ||
|
|
755b4605e4 | ||
|
|
9bc0ae6b97 | ||
|
|
bfeb827eb7 | ||
|
|
8b8fa41ef2 | ||
|
|
f0cf49f3ec | ||
|
|
6ac0fd6f0a | ||
|
|
3e9b53cecc | ||
|
|
fd3b5c3881 | ||
|
|
d51d75c3ed | ||
|
|
c30ce008ca | ||
|
|
b83977b906 | ||
|
|
e68089590d | ||
|
|
b151b2bba7 | ||
|
|
3f36992f98 | ||
|
|
7228b01c2d | ||
|
|
98a8a3a5e9 | ||
|
|
a6ffb24f30 | ||
|
|
13319a6847 | ||
|
|
ef1924d7f9 | ||
|
|
c39c03d866 | ||
|
|
62798ce1b8 | ||
|
|
57dd0fe480 | ||
|
|
2f67620a6e | ||
|
|
1ea32e8538 | ||
|
|
c69e83735c | ||
|
|
6a21462554 | ||
|
|
1d3fbedf29 | ||
|
|
4b4d38a00a | ||
|
|
effeb7d9f7 | ||
|
|
a39d6b67f9 | ||
|
|
4e2b348e96 | ||
|
|
278656ac5a | ||
|
|
2c05d937e5 | ||
|
|
984ae97579 | ||
|
|
4706dea9de | ||
|
|
69a867a9a9 | ||
|
|
fc745c402c | ||
|
|
d652645346 | ||
|
|
bcb947235d | ||
|
|
708db4b5eb | ||
|
|
6c4340af43 | ||
|
|
cb768f9644 | ||
|
|
5ffc4d1e2d | ||
|
|
4d8db7fb3b | ||
|
|
dfb08ac8b0 | ||
|
|
e8d6cd4b31 | ||
|
|
0ae69cfe9e | ||
|
|
3858e8ebda | ||
|
|
7abd9af8b6 | ||
|
|
c4992797c7 | ||
|
|
394cf14198 | ||
|
|
1269bc76f3 | ||
|
|
8da681c720 | ||
|
|
9b0589840b | ||
|
|
d36e42103b | ||
|
|
731281eb61 | ||
|
|
6959405518 | ||
|
|
73f8b88b5c | ||
|
|
d982928a23 | ||
|
|
2652a12fdc | ||
|
|
e190f3887d | ||
|
|
b82c481605 | ||
|
|
683d8b35bf | ||
|
|
2416225502 | ||
|
|
1d00808719 | ||
|
|
798898b9ad | ||
|
|
6927f81754 | ||
|
|
0e01a7281e | ||
|
|
b3e7987985 | ||
|
|
67475fcf34 | ||
|
|
2597a184f0 | ||
|
|
de78e423fd | ||
|
|
7151080a67 | ||
|
|
bd01e4f99d | ||
|
|
507476d513 | ||
|
|
56c6d73185 | ||
|
|
460b7a6eb3 | ||
|
|
9883ab47fa | ||
|
|
5b3d5c998a | ||
|
|
8e5cc46577 | ||
|
|
e31f3b8057 | ||
|
|
47ea1788db | ||
|
|
ea9fc4dbe8 | ||
|
|
034aeb9b12 | ||
|
|
5e5d0f3dbe | ||
|
|
d73bd5dcd2 | ||
|
|
b91f180c7b | ||
|
|
f951f0451f | ||
|
|
63295b5493 | ||
|
|
5da6a0e05e | ||
|
|
b8d8188239 | ||
|
|
d90e35d630 | ||
|
|
21d659214f | ||
|
|
60129e1a61 | ||
|
|
6423a32a2e | ||
|
|
93a0bbaed8 | ||
|
|
ef2221659a | ||
|
|
bd1056f9c9 | ||
|
|
e37dedb72d | ||
|
|
7275df3d60 | ||
|
|
5e42d15c61 | ||
|
|
bcb02fe5e6 | ||
|
|
834a40247c | ||
|
|
e77b01ac84 | ||
|
|
f7df90447b | ||
|
|
30d4964a5e | ||
|
|
1e2922faa5 | ||
|
|
4a303184e4 | ||
|
|
e2e7ee93db | ||
|
|
87f487c3aa | ||
|
|
3ba1842758 | ||
|
|
d6b54f8e30 | ||
|
|
776e1d99cf | ||
|
|
ee971306ca | ||
|
|
69fe996e15 | ||
|
|
14415d42a9 | ||
|
|
000a2ba3a7 | ||
|
|
19a965c1ef | ||
|
|
968d645d17 | ||
|
|
f865d231d0 | ||
|
|
7310071945 | ||
|
|
1c85d133e4 | ||
|
|
32f2b1fbb6 | ||
|
|
6d6bec3d3e | ||
|
|
be46765c56 | ||
|
|
4d45bfc242 | ||
|
|
84b2192ca1 | ||
|
|
fd82a2495f | ||
|
|
57aba42dd7 | ||
|
|
445f55af92 | ||
|
|
701e93f26d | ||
|
|
e4c61a926a | ||
|
|
7b9c154f85 | ||
|
|
c601169b84 | ||
|
|
e5b91eaeba | ||
|
|
f5c3f12746 | ||
|
|
c8e46fb6e2 | ||
|
|
281a28f901 | ||
|
|
c723d1c9b9 | ||
|
|
d9e7b9c975 | ||
|
|
5354ff04c6 | ||
|
|
69f7dda3de | ||
|
|
3513e3bffe | ||
|
|
b86a749b00 | ||
|
|
262e2be9cb | ||
|
|
b92bc0b44a | ||
|
|
427e069085 | ||
|
|
a19c0a214a | ||
|
|
86a68df114 | ||
|
|
aebfa2745a | ||
|
|
2be199bad8 | ||
|
|
700d72f180 | ||
|
|
fae9bcd0df | ||
|
|
591f61a9f0 | ||
|
|
a5ab9fe503 | ||
|
|
556d47a9d5 | ||
|
|
620391b7ec | ||
|
|
0da2a59e4d | ||
|
|
ee129c4fb6 | ||
|
|
c33056fd8e | ||
|
|
7a7f6a0533 | ||
|
|
03cf61441b | ||
|
|
2be194c147 | ||
|
|
bc46cb9c5f | ||
|
|
476de2b8f7 | ||
|
|
2617903e71 | ||
|
|
cb59bc0431 | ||
|
|
2036caa4a0 | ||
|
|
f6a0042356 | ||
|
|
dc1a344cf5 | ||
|
|
a072c2fc70 | ||
|
|
6416788856 | ||
|
|
f328f71f62 | ||
|
|
d6620959b3 | ||
|
|
e50d4bb19c | ||
|
|
a21dcae309 | ||
|
|
13a5fd9761 | ||
|
|
5a729cd02e | ||
|
|
a050248982 | ||
|
|
ec95c0401a | ||
|
|
ef5b7cd99a | ||
|
|
4aa70fda65 | ||
|
|
a4769996c3 | ||
|
|
7bece3f8c9 | ||
|
|
a2c5ed20de | ||
|
|
a989cf9958 | ||
|
|
f4ec3c3997 | ||
|
|
c1966c5f04 | ||
|
|
634fb4fa57 | ||
|
|
0a3fd42019 | ||
|
|
94508f6395 | ||
|
|
5ee9b44f3b | ||
|
|
c624cc1b0c | ||
|
|
62922288a1 | ||
|
|
675ee4915b | ||
|
|
3743922d4d | ||
|
|
0cba505ad0 | ||
|
|
a39a46c7e3 | ||
|
|
1c1d3e00a2 | ||
|
|
c9fd4ecb8f | ||
|
|
a4556a3742 | ||
|
|
fc74360fd2 | ||
|
|
4ce1b33304 | ||
|
|
f713a3785b | ||
|
|
115cdef6fd | ||
|
|
238d0ffade | ||
|
|
eb926848be | ||
|
|
238d63cff7 | ||
|
|
70b440839d | ||
|
|
bb75045584 | ||
|
|
aa2aefac28 | ||
|
|
5422dcf164 | ||
|
|
df444655e3 | ||
|
|
b7d5de7ce0 | ||
|
|
ded4ef195f | ||
|
|
b48e632829 | ||
|
|
09d1e035ed | ||
|
|
bfb62872c9 | ||
|
|
d1942bc57d | ||
|
|
7f0e65f8c7 | ||
|
|
5e1407ec95 | ||
|
|
00f5741f7f | ||
|
|
a347a9780c | ||
|
|
7ba3258150 | ||
|
|
4eba014513 | ||
|
|
a78c53ecdd | ||
|
|
256e947a5d | ||
|
|
5127479874 | ||
|
|
0a95d64f2b | ||
|
|
c50d5255ec | ||
|
|
1f7053cb31 | ||
|
|
323df933c4 | ||
|
|
2b685e4e18 | ||
|
|
af32784f37 | ||
|
|
408b62a495 | ||
|
|
21a46ee151 | ||
|
|
7517711308 | ||
|
|
19071c0217 | ||
|
|
eb9866cd87 | ||
|
|
b7ecc69cfb | ||
|
|
429618a00a | ||
|
|
4ec815a383 | ||
|
|
2c40177f06 | ||
|
|
9944408104 | ||
|
|
e96e0ecc42 | ||
|
|
ace0b6d226 | ||
|
|
99a8726506 | ||
|
|
1ca0a96628 | ||
|
|
fefccf808a | ||
|
|
98efe13ac5 | ||
|
|
253e14f2c9 | ||
|
|
0b13cb5714 | ||
|
|
12335da41b | ||
|
|
93ca669929 | ||
|
|
a8914c09ce | ||
|
|
4ecd4e4a07 | ||
|
|
4b4b876a25 | ||
|
|
e848ca8730 | ||
|
|
c34f816544 | ||
|
|
919274924e | ||
|
|
916fdf40af | ||
|
|
fcd52a9177 | ||
|
|
38c0a54fcc | ||
|
|
70d66d320f | ||
|
|
b44950bddd | ||
|
|
fa2bf8b665 | ||
|
|
75f0d27ca7 | ||
|
|
548263279e | ||
|
|
cbf6019d92 | ||
|
|
70614b769a | ||
|
|
8501745c43 | ||
|
|
510c2fa01e | ||
|
|
3606b80016 | ||
|
|
2c651f2359 | ||
|
|
25fa70ff9d | ||
|
|
d52c3ddfde | ||
|
|
a696fb2350 | ||
|
|
e8af08aff0 | ||
|
|
3d18e702b0 | ||
|
|
972a4efed1 | ||
|
|
8e0284faec | ||
|
|
26a9cafcb8 | ||
|
|
47f7039720 | ||
|
|
e7a21423da | ||
|
|
17bd9801e0 | ||
|
|
6b66608354 | ||
|
|
4154d3f4ee | ||
|
|
fc9018f97c | ||
|
|
5962499147 | ||
|
|
e79a2fa809 | ||
|
|
06804d94f8 | ||
|
|
d317f7f99b | ||
|
|
fa82c9b964 | ||
|
|
01e71d7b5f | ||
|
|
97a951fabb | ||
|
|
bbd05fe8aa | ||
|
|
cb59412fd9 | ||
|
|
4dfbb789be | ||
|
|
1ad2513700 | ||
|
|
bb396f8651 | ||
|
|
0afe4c4acb | ||
|
|
0dfd535c40 | ||
|
|
f1ae8f0353 | ||
|
|
4c9f0c5399 | ||
|
|
90a004cdd4 | ||
|
|
94af204ed8 | ||
|
|
bff7711e2c | ||
|
|
ad041d6dab | ||
|
|
18675f72f3 | ||
|
|
0388cd316b | ||
|
|
bd2c5e1ebc | ||
|
|
4665735c89 | ||
|
|
ded2691155 | ||
|
|
29a3704463 | ||
|
|
6c920ce5dc | ||
|
|
46da761dcf | ||
|
|
3ae519d600 | ||
|
|
8a9340749d | ||
|
|
16697b8c2b | ||
|
|
6f455bc26a | ||
|
|
ba485e4adc | ||
|
|
509f3d2879 | ||
|
|
0d73120d15 | ||
|
|
99eaf317ba | ||
|
|
3f0a99d272 | ||
|
|
5c1b0a8f10 | ||
|
|
6de362cd1c | ||
|
|
e72c1f70aa | ||
|
|
f000ef4cbd | ||
|
|
7cabf01944 | ||
|
|
ea64124963 | ||
|
|
6a2b122ab7 | ||
|
|
9604bdd50a | ||
|
|
9ceff83c91 | ||
|
|
62be9fed93 | ||
|
|
1d40f89dfe | ||
|
|
1ee6a1349c | ||
|
|
b056e7be0a | ||
|
|
38e3222c31 | ||
|
|
8e1427fbd0 | ||
|
|
ea30e0ee92 | ||
|
|
d6bdd6854f | ||
|
|
9194e1c97f | ||
|
|
9542512209 | ||
|
|
c552bc6a4e | ||
|
|
f928661045 | ||
|
|
3078667e1d | ||
|
|
62e141000e | ||
|
|
b76c23429f | ||
|
|
0eed6f17a2 | ||
|
|
08ca58c867 | ||
|
|
614730543c | ||
|
|
8f950fc345 | ||
|
|
83cfacf94b | ||
|
|
dae5827666 | ||
|
|
b119c45c16 | ||
|
|
a59fe679a7 | ||
|
|
82a4be37f2 | ||
|
|
f56453093f | ||
|
|
59e0291f9e | ||
|
|
833679e58a | ||
|
|
f04207905f | ||
|
|
8c98afb1ac | ||
|
|
8c52cd34ed | ||
|
|
fbb1fc1fdb | ||
|
|
c43ae7ed2c | ||
|
|
ad626025d5 | ||
|
|
9db24e6593 | ||
|
|
e3765f1f50 | ||
|
|
532ca5ced5 | ||
|
|
20d02b75e1 | ||
|
|
992ea967a7 | ||
|
|
9e3a5aefad | ||
|
|
bf0c29b384 | ||
|
|
164c2f25d4 | ||
|
|
4cf85c4f2a | ||
|
|
bcaf0e6e32 | ||
|
|
92cd0f3a82 | ||
|
|
067d517527 | ||
|
|
a6bcded3e4 | ||
|
|
79e5eb6a74 | ||
|
|
1078a33147 | ||
|
|
3fb314fc44 | ||
|
|
7618ff27f4 | ||
|
|
05493e5e15 | ||
|
|
e1fd5678ec | ||
|
|
8a0d00f94b | ||
|
|
0207ee85b7 | ||
|
|
a5a661261d | ||
|
|
d056acf0af | ||
|
|
229b5f292e | ||
|
|
3e71f83d61 | ||
|
|
fa6ace0955 | ||
|
|
1e6f91809e | ||
|
|
afcc892b32 | ||
|
|
1c0a1fcbcb | ||
|
|
bf8aaaa9c1 | ||
|
|
0359a4e97f | ||
|
|
a18360c931 | ||
|
|
0c031d3e0b | ||
|
|
20a945c6f0 | ||
|
|
433a5ac39d | ||
|
|
b444b7de88 | ||
|
|
94dfdb6905 | ||
|
|
2f1b06d0f9 | ||
|
|
14b1d5a2d1 | ||
|
|
7c3912b9ae | ||
|
|
fa657fbf0b | ||
|
|
6e9f990eed | ||
|
|
a8ae34b3bd | ||
|
|
e959126ac0 | ||
|
|
7e1906da57 | ||
|
|
9075177533 | ||
|
|
e73db426eb | ||
|
|
150bfa15a6 | ||
|
|
cab375917b | ||
|
|
6ac9beaa61 | ||
|
|
a1bdaed2f6 | ||
|
|
ee29a397da | ||
|
|
cbf63dd2b6 | ||
|
|
6d73806d1a | ||
|
|
f6c416bdf1 | ||
|
|
99dd2f5dec | ||
|
|
d3b94dd1c6 | ||
|
|
edd1ad1a80 | ||
|
|
ae5c37b7e4 | ||
|
|
7c3b4e52c3 | ||
|
|
61ae5e2e34 | ||
|
|
6992c541af | ||
|
|
5d6bf42397 | ||
|
|
bc61669dad | ||
|
|
537ec9e2b0 | ||
|
|
4ae9c00c06 | ||
|
|
3583e24bd8 | ||
|
|
c7a8d7e785 | ||
|
|
22b6254a16 | ||
|
|
db1879d098 | ||
|
|
832fc56a1b | ||
|
|
e77b56c9ad | ||
|
|
ac4cb2217e | ||
|
|
cc2177e36c | ||
|
|
ac6827fdd8 | ||
|
|
3c30d3aba9 | ||
|
|
5c0b675ca8 | ||
|
|
e4c77d1432 | ||
|
|
e8ca8161c8 | ||
|
|
a65ae7202e | ||
|
|
09d13579fc | ||
|
|
3d2596f701 | ||
|
|
6bc28c2ae9 | ||
|
|
2cd5edd08b | ||
|
|
58a46c6106 | ||
|
|
db93ddd280 | ||
|
|
6a1b1a5ed9 | ||
|
|
df95930481 | ||
|
|
0c2449dc5e | ||
|
|
8fcf58a732 | ||
|
|
937cab736b | ||
|
|
fa7bb59a82 | ||
|
|
a0016861e8 | ||
|
|
964f483fd5 | ||
|
|
c5ea0a7bf1 | ||
|
|
aad270bcd0 | ||
|
|
994e0a6675 | ||
|
|
836c169100 | ||
|
|
2fb0690804 | ||
|
|
30b7f4d69d | ||
|
|
44e787c56a | ||
|
|
0c4a5f54f2 | ||
|
|
b73c6e749e | ||
|
|
1022a4dfc3 | ||
|
|
ee72f7d07f | ||
|
|
8af2aa262b | ||
|
|
40a458b743 | ||
|
|
e645167c94 | ||
|
|
c183203264 | ||
|
|
4dfbc01479 | ||
|
|
f3497bd2fa | ||
|
|
3c98bc5eca | ||
|
|
9640e167df | ||
|
|
b580605c86 | ||
|
|
292c7eeecf | ||
|
|
848f110658 | ||
|
|
979d31407f | ||
|
|
f5c3514dde | ||
|
|
beecb3dac0 | ||
|
|
ea871e0188 | ||
|
|
ad6b9c1ca7 | ||
|
|
2caade5a36 | ||
|
|
8eb055ca81 | ||
|
|
852b843b4a | ||
|
|
211bf5de39 | ||
|
|
f5a14c20a9 | ||
|
|
c95077f263 | ||
|
|
ca5c1a123b | ||
|
|
6075ae1445 | ||
|
|
47cd496e6d | ||
|
|
2466897531 | ||
|
|
604482d55c | ||
|
|
906323f219 | ||
|
|
13022c79bf | ||
|
|
aa491bb801 | ||
|
|
605c5daf54 | ||
|
|
223ae1e33f | ||
|
|
33e4b6d8de | ||
|
|
3b1ab8d9d9 | ||
|
|
9297542dcf | ||
|
|
c848255b43 | ||
|
|
b082e2e06b | ||
|
|
96774ef3da | ||
|
|
12cedbae0e | ||
|
|
4e239832a6 | ||
|
|
c68cbfa37b |
@@ -0,0 +1,27 @@
|
||||
BasedOnStyle: Microsoft
|
||||
IndentWidth: 4
|
||||
UseTab: Never
|
||||
AccessModifierOffset: -4
|
||||
PointerAlignment: Left
|
||||
BreakBeforeBraces: Custom
|
||||
BraceWrapping:
|
||||
AfterFunction: false
|
||||
AfterClass: false
|
||||
AfterControlStatement: Never
|
||||
AfterEnum: false
|
||||
AfterNamespace: false
|
||||
AfterStruct: false
|
||||
AfterUnion: false
|
||||
BeforeElse: false
|
||||
SplitEmptyFunction: false
|
||||
SplitEmptyRecord: false
|
||||
|
||||
AllowShortBlocksOnASingleLine: Empty
|
||||
AllowShortIfStatementsOnASingleLine: WithoutElse
|
||||
AlwaysBreakTemplateDeclarations: Yes
|
||||
NamespaceIndentation: All
|
||||
AllowShortFunctionsOnASingleLine: Inline
|
||||
SortIncludes: false
|
||||
FixNamespaceComments: true
|
||||
ShortNamespaceLines: 0
|
||||
CompactNamespaces: false
|
||||
+142
@@ -0,0 +1,142 @@
|
||||
#Generated from CLion Inspection settings
|
||||
---
|
||||
Checks: '-*,
|
||||
bugprone-argument-comment,
|
||||
bugprone-assert-side-effect,
|
||||
bugprone-bad-signal-to-kill-thread,
|
||||
bugprone-branch-clone,
|
||||
bugprone-copy-constructor-init,
|
||||
bugprone-dangling-handle,
|
||||
bugprone-dynamic-static-initializers,
|
||||
bugprone-fold-init-type,
|
||||
bugprone-forward-declaration-namespace,
|
||||
bugprone-forwarding-reference-overload,
|
||||
bugprone-inaccurate-erase,
|
||||
bugprone-incorrect-roundings,
|
||||
bugprone-integer-division,
|
||||
bugprone-macro-parentheses,
|
||||
bugprone-macro-repeated-side-effects,
|
||||
bugprone-misplaced-operator-in-strlen-in-alloc,
|
||||
bugprone-misplaced-pointer-arithmetic-in-alloc,
|
||||
bugprone-misplaced-widening-cast,
|
||||
bugprone-move-forwarding-reference,
|
||||
bugprone-multiple-statement-macro,
|
||||
bugprone-no-escape,
|
||||
bugprone-parent-virtual-call,
|
||||
bugprone-posix-return,
|
||||
bugprone-reserved-identifier,
|
||||
bugprone-sizeof-container,
|
||||
bugprone-sizeof-expression,
|
||||
bugprone-spuriously-wake-up-functions,
|
||||
bugprone-string-constructor,
|
||||
bugprone-string-integer-assignment,
|
||||
bugprone-string-literal-with-embedded-nul,
|
||||
bugprone-suspicious-enum-usage,
|
||||
bugprone-suspicious-include,
|
||||
bugprone-suspicious-memset-usage,
|
||||
bugprone-suspicious-missing-comma,
|
||||
bugprone-suspicious-semicolon,
|
||||
bugprone-suspicious-string-compare,
|
||||
bugprone-suspicious-memory-comparison,
|
||||
bugprone-suspicious-realloc-usage,
|
||||
bugprone-swapped-arguments,
|
||||
bugprone-terminating-continue,
|
||||
bugprone-throw-keyword-missing,
|
||||
bugprone-too-small-loop-variable,
|
||||
bugprone-undefined-memory-manipulation,
|
||||
bugprone-undelegated-constructor,
|
||||
bugprone-unhandled-self-assignment,
|
||||
bugprone-unused-raii,
|
||||
bugprone-unused-return-value,
|
||||
bugprone-use-after-move,
|
||||
bugprone-virtual-near-miss,
|
||||
cert-dcl21-cpp,
|
||||
cert-dcl58-cpp,
|
||||
cert-err34-c,
|
||||
cert-err52-cpp,
|
||||
cert-err60-cpp,
|
||||
cert-flp30-c,
|
||||
cert-msc50-cpp,
|
||||
cert-msc51-cpp,
|
||||
cert-str34-c,
|
||||
cppcoreguidelines-interfaces-global-init,
|
||||
cppcoreguidelines-narrowing-conversions,
|
||||
cppcoreguidelines-pro-type-member-init,
|
||||
cppcoreguidelines-slicing,
|
||||
google-default-arguments,
|
||||
google-runtime-operator,
|
||||
hicpp-exception-baseclass,
|
||||
hicpp-multiway-paths-covered,
|
||||
misc-misplaced-const,
|
||||
misc-new-delete-overloads,
|
||||
misc-non-copyable-objects,
|
||||
misc-throw-by-value-catch-by-reference,
|
||||
misc-unconventional-assign-operator,
|
||||
misc-uniqueptr-reset-release,
|
||||
modernize-avoid-bind,
|
||||
modernize-concat-nested-namespaces,
|
||||
modernize-deprecated-headers,
|
||||
modernize-deprecated-ios-base-aliases,
|
||||
modernize-loop-convert,
|
||||
modernize-make-shared,
|
||||
modernize-make-unique,
|
||||
modernize-pass-by-value,
|
||||
modernize-raw-string-literal,
|
||||
modernize-redundant-void-arg,
|
||||
modernize-replace-auto-ptr,
|
||||
modernize-replace-disallow-copy-and-assign-macro,
|
||||
modernize-replace-random-shuffle,
|
||||
modernize-return-braced-init-list,
|
||||
modernize-shrink-to-fit,
|
||||
modernize-unary-static-assert,
|
||||
modernize-use-auto,
|
||||
modernize-use-bool-literals,
|
||||
modernize-use-emplace,
|
||||
modernize-use-equals-default,
|
||||
modernize-use-equals-delete,
|
||||
modernize-use-noexcept,
|
||||
modernize-use-nullptr,
|
||||
modernize-use-override,
|
||||
modernize-use-transparent-functors,
|
||||
modernize-use-uncaught-exceptions,
|
||||
mpi-buffer-deref,
|
||||
mpi-type-mismatch,
|
||||
openmp-use-default-none,
|
||||
performance-faster-string-find,
|
||||
performance-for-range-copy,
|
||||
performance-implicit-conversion-in-loop,
|
||||
performance-inefficient-algorithm,
|
||||
performance-inefficient-string-concatenation,
|
||||
performance-inefficient-vector-operation,
|
||||
performance-move-const-arg,
|
||||
performance-move-constructor-init,
|
||||
performance-no-automatic-move,
|
||||
performance-noexcept-move-constructor,
|
||||
performance-trivially-destructible,
|
||||
performance-type-promotion-in-math-fn,
|
||||
performance-unnecessary-copy-initialization,
|
||||
performance-unnecessary-value-param,
|
||||
portability-simd-intrinsics,
|
||||
readability-avoid-const-params-in-decls,
|
||||
readability-const-return-type,
|
||||
readability-container-size-empty,
|
||||
readability-convert-member-functions-to-static,
|
||||
readability-delete-null-pointer,
|
||||
readability-deleted-default,
|
||||
readability-inconsistent-declaration-parameter-name,
|
||||
readability-make-member-function-const,
|
||||
readability-misleading-indentation,
|
||||
readability-misplaced-array-index,
|
||||
readability-non-const-parameter,
|
||||
readability-redundant-control-flow,
|
||||
readability-redundant-declaration,
|
||||
readability-redundant-function-ptr-dereference,
|
||||
readability-redundant-smartptr-get,
|
||||
readability-redundant-string-cstr,
|
||||
readability-redundant-string-init,
|
||||
readability-simplify-subscript-expr,
|
||||
readability-static-accessed-through-instance,
|
||||
readability-static-definition-in-anonymous-namespace,
|
||||
readability-string-compare,
|
||||
readability-uniqueptr-delete-release,
|
||||
readability-use-anyofallof'
|
||||
@@ -0,0 +1,64 @@
|
||||
name: Benchmark
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- dev
|
||||
- Feat/Backend-Direct-GLES
|
||||
- Feat/Backend-Direct-Vulkan
|
||||
|
||||
jobs:
|
||||
benchmark:
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
# BENCH_ROOT: ${{github.workspace}}/MobileGL/MG_Benchmark
|
||||
BENCH_ROOT: ${{github.workspace}}
|
||||
|
||||
steps:
|
||||
- name: Set Swap Space
|
||||
uses: pierotofy/set-swap-space@master
|
||||
with:
|
||||
swap-size-gb: 32
|
||||
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: true
|
||||
|
||||
- name: Get CMake
|
||||
uses: lukka/get-cmake@latest
|
||||
|
||||
- name: Prepare Vulkan SDK
|
||||
uses: humbletim/setup-vulkan-sdk@v1.2.1
|
||||
with:
|
||||
vulkan-query-version: 1.4.304.1
|
||||
vulkan-components: Vulkan-Headers, Vulkan-Loader
|
||||
vulkan-use-cache: true
|
||||
|
||||
- name: Update glslang external sources
|
||||
working-directory: ${{env.BENCH_ROOT}}/3rdparty/glslang
|
||||
run: python update_glslang_sources.py
|
||||
|
||||
- name: Install clang-20
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y clang-20 clang++-20 lld-20 libc++-20-dev libc++abi-20-dev libvulkan-dev
|
||||
|
||||
- name: Show installed toolchain
|
||||
run: |
|
||||
clang-20 --version
|
||||
clang++-20 --version
|
||||
ld.lld-20 --version || ld.lld --version || true
|
||||
dpkg -l 'libc++*' || true
|
||||
|
||||
- name: Configure CMake
|
||||
working-directory: ${{env.BENCH_ROOT}}
|
||||
run: cmake -S . -B build-bench -G Ninja -DCMAKE_BUILD_TYPE=Release -DCMAKE_C_COMPILER=clang-20 -DCMAKE_CXX_COMPILER=clang++-20 -DBENCHMARK_DOWNLOAD_DEPENDENCIES=ON -DBENCHMARK_ENABLE_TESTING=OFF -DMOBILEGL_BUILD_TEST=OFF -DMOBILEGL_BUILD_BENCHMARK=ON -DCMAKE_POLICY_VERSION_MINIMUM=3.5
|
||||
|
||||
- name: Build
|
||||
working-directory: ${{env.BENCH_ROOT}}/build-bench
|
||||
run: cmake --build .
|
||||
|
||||
- name: Benchmark
|
||||
working-directory: ${{env.BENCH_ROOT}}/build-bench/MobileGL/MG_Benchmark
|
||||
run: ctest -V -C Release
|
||||
@@ -0,0 +1,74 @@
|
||||
name: Test
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- dev
|
||||
- Feat/Backend-Direct-GLES
|
||||
- Feat/Backend-Direct-Vulkan
|
||||
|
||||
jobs:
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
# TEST_ROOT: ${{github.workspace}}/MobileGL/MG_Test
|
||||
TEST_ROOT: ${{github.workspace}}
|
||||
|
||||
steps:
|
||||
- name: Set Swap Space
|
||||
uses: pierotofy/set-swap-space@master
|
||||
with:
|
||||
swap-size-gb: 32
|
||||
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: true
|
||||
|
||||
- name: Get CMake
|
||||
uses: lukka/get-cmake@latest
|
||||
|
||||
- name: Prepare Vulkan SDK
|
||||
uses: humbletim/setup-vulkan-sdk@v1.2.1
|
||||
with:
|
||||
vulkan-query-version: 1.4.304.1
|
||||
vulkan-components: Vulkan-Headers, Vulkan-Loader
|
||||
vulkan-use-cache: true
|
||||
|
||||
- name: Update glslang external sources
|
||||
working-directory: ${{env.TEST_ROOT}}/3rdparty/glslang
|
||||
run: python update_glslang_sources.py
|
||||
|
||||
- name: Install clang-20
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y clang-20 clang++-20 lld-20 libc++-20-dev libc++abi-20-dev libvulkan-dev
|
||||
|
||||
- name: Show installed toolchain
|
||||
run: |
|
||||
clang-20 --version
|
||||
clang++-20 --version
|
||||
ld.lld-20 --version || ld.lld --version || true
|
||||
dpkg -l 'libc++*' || true
|
||||
|
||||
- name: Configure CMake
|
||||
working-directory: ${{env.TEST_ROOT}}
|
||||
run: |
|
||||
if [ "${{ secrets.ACTIONS_STEP_DEBUG }}" == "true" ]; then
|
||||
cmake -S . -B build-test -G Ninja -DCMAKE_C_COMPILER=clang-20 -DCMAKE_CXX_COMPILER=clang++-20 -DCMAKE_BUILD_TYPE=Debug -DMOBILEGL_BUILD_TEST=ON -DMOBILEGL_BUILD_BENCHMARK=OFF -DCMAKE_POLICY_VERSION_MINIMUM=3.5
|
||||
else
|
||||
cmake -S . -B build-test -G Ninja -DCMAKE_C_COMPILER=clang-20 -DCMAKE_CXX_COMPILER=clang++-20 -DCMAKE_BUILD_TYPE=Release -DMOBILEGL_BUILD_TEST=ON -DMOBILEGL_BUILD_BENCHMARK=OFF -DCMAKE_POLICY_VERSION_MINIMUM=3.5
|
||||
fi
|
||||
|
||||
- name: Build
|
||||
working-directory: ${{env.TEST_ROOT}}/build-test
|
||||
run: cmake --build .
|
||||
|
||||
- name: Test
|
||||
working-directory: ${{env.TEST_ROOT}}/build-test/MobileGL/MG_Test
|
||||
run: |
|
||||
if [ "${{ secrets.ACTIONS_STEP_DEBUG }}" == "true" ]; then
|
||||
ctest -V
|
||||
else
|
||||
ctest
|
||||
fi
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
################################################################################
|
||||
# 此 .gitignore 文件已由 Microsoft(R) Visual Studio 自动创建。
|
||||
################################################################################
|
||||
|
||||
/build
|
||||
.cxx
|
||||
/.vs
|
||||
/out/build
|
||||
CMakeSettings.json
|
||||
MobileGL/MG_Test/out
|
||||
MobileGL/MG_Test/.vs
|
||||
MobileGLCodeManager.*
|
||||
MobileGLCodeManager
|
||||
.vscode
|
||||
.clangd
|
||||
MobileGL/MG_Test/build
|
||||
/build_*
|
||||
/cmake-build*
|
||||
.idea
|
||||
MobileGL/MG*/build*
|
||||
MobileGL/MG*/cmake-build*
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
[submodule "3rdparty/DiligentCore"]
|
||||
path = 3rdparty/DiligentCore
|
||||
url = https://github.com/DiligentGraphics/DiligentCore.git
|
||||
[submodule "3rdparty/glslang"]
|
||||
path = 3rdparty/glslang
|
||||
url = https://github.com/MobileGL-Dev/glslang.git
|
||||
[submodule "3rdparty/SPIRV-Cross"]
|
||||
path = 3rdparty/SPIRV-Cross
|
||||
url = https://github.com/KhronosGroup/SPIRV-Cross.git
|
||||
[submodule "include/FastSTL"]
|
||||
path = include/FastSTL
|
||||
url = https://github.com/MobileGL-Dev/FastSTL.git
|
||||
[submodule "3rdparty/tracy"]
|
||||
path = 3rdparty/tracy
|
||||
url = https://github.com/wolfpld/tracy.git
|
||||
[submodule "3rdparty/xxHash"]
|
||||
path = 3rdparty/xxHash
|
||||
url = https://github.com/Cyan4973/xxHash.git
|
||||
[submodule "3rdparty/VulkanMemoryAllocator"]
|
||||
path = 3rdparty/VulkanMemoryAllocator
|
||||
url = https://github.com/GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator.git
|
||||
[submodule "3rdparty/Vulkan-Utility-Libraries"]
|
||||
path = 3rdparty/Vulkan-Utility-Libraries
|
||||
url = https://github.com/KhronosGroup/Vulkan-Utility-Libraries.git
|
||||
[submodule "3rdparty/Vulkan-Headers"]
|
||||
path = 3rdparty/Vulkan-Headers
|
||||
url = https://github.com/KhronosGroup/Vulkan-Headers.git
|
||||
[submodule "3rdparty/SPIRV-Reflect"]
|
||||
path = 3rdparty/SPIRV-Reflect
|
||||
url = https://github.com/KhronosGroup/SPIRV-Reflect.git
|
||||
+1
Submodule 3rdparty/DiligentCore added at f36e638805
+1
Submodule 3rdparty/SPIRV-Cross added at 072444287f
+1
Submodule 3rdparty/SPIRV-Reflect added at 10b4f09a24
+1
Submodule 3rdparty/Vulkan-Headers added at ad9ce1235e
+1
Submodule 3rdparty/Vulkan-Utility-Libraries added at 738ec97a3f
+1
Submodule 3rdparty/VulkanMemoryAllocator added at e722e57c89
+1
Submodule 3rdparty/glslang added at 26fe5ceb45
+1
Submodule 3rdparty/tracy added at e6b9ea4609
+1
Submodule 3rdparty/xxHash added at 1d7b2a9d21
+371
-94
@@ -2,120 +2,397 @@ cmake_minimum_required(VERSION 3.22.1)
|
||||
|
||||
project("MobileGL")
|
||||
|
||||
option(MOBILEGL_BUILD_TEST "Build MobileGL tests" ON )
|
||||
option(MOBILEGL_BUILD_BENCHMARK "Build MobileGL benchmarks" ON )
|
||||
option(MOBILEGL_FORCE_RELEASE_OPT "Enable Release optimization flags in Debug build" ON )
|
||||
option(MOBILEGL_ENABLE_TRACY "Enable tracy for profiling" OFF)
|
||||
|
||||
if (ANDROID)
|
||||
set(MOBILEGL_BUILD_TEST OFF CACHE BOOL "Build MobileGL tests" FORCE)
|
||||
set(MOBILEGL_BUILD_BENCHMARK OFF CACHE BOOL "Build MobileGL benchmarks" FORCE)
|
||||
endif()
|
||||
|
||||
if (NOT CMAKE_BUILD_TYPE STREQUAL "Debug" OR MOBILEGL_FORCE_RELEASE_OPT)
|
||||
# Check if ThinLTO or LTO is suppported
|
||||
include(CheckIPOSupported)
|
||||
include(CheckCCompilerFlag)
|
||||
include(CheckCXXCompilerFlag)
|
||||
|
||||
check_ipo_supported(RESULT LTOSupported OUTPUT LTOError)
|
||||
|
||||
check_c_compiler_flag("-flto" HAS_LTO_C)
|
||||
check_cxx_compiler_flag("-flto" HAS_LTO_CXX)
|
||||
|
||||
if (LTOSupported OR (HAS_LTO_C AND HAS_LTO_CXX))
|
||||
# Check ThinLTO
|
||||
check_c_compiler_flag("-flto=thin" HAS_THINLTO_C)
|
||||
check_cxx_compiler_flag("-flto=thin" HAS_THINLTO_CXX)
|
||||
if (HAS_THINLTO_C AND HAS_THINLTO_CXX)
|
||||
message(STATUS "ThinLTO supported, using -flto=thin")
|
||||
|
||||
add_compile_options(-flto=thin)
|
||||
add_link_options(-flto=thin)
|
||||
else()
|
||||
# ThinLTO is not supported
|
||||
message(STATUS "ThinLTO not available, fallback to CMAKE IPO")
|
||||
set(CMAKE_INTERPROCEDURAL_OPTIMIZATION TRUE)
|
||||
endif()
|
||||
else()
|
||||
message(STATUS "IPO not supported: ${LTOError}")
|
||||
endif()
|
||||
|
||||
if (CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang" AND NOT MATCHES "AppleClang")
|
||||
add_compile_options(-O3 -ffunction-sections -fdata-sections)
|
||||
add_link_options(-Wl,--gc-sections)
|
||||
elseif (CMAKE_CXX_COMPILER_ID MATCHES "MSVC")
|
||||
# add_compile_options(/O2)
|
||||
else ()
|
||||
add_compile_options(-O2)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if (CMAKE_CXX_COMPILER_ID MATCHES "MSVC")
|
||||
add_compile_options(/Zc:preprocessor)
|
||||
add_compile_options(/Zc:__cplusplus)
|
||||
endif()
|
||||
|
||||
enable_language(CXX)
|
||||
|
||||
set(CMAKE_CXX_STANDARD 20)
|
||||
set(CMAKE_CXX_STANDARD 23)
|
||||
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -w -fvisibility=hidden -funwind-tables -g -D_THREAD_SAFE -fPIC -stdlib=libc++")
|
||||
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
|
||||
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -w -g -std=gnu99 -funwind-tables -O3 -fvisibility=hidden")
|
||||
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
|
||||
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -static-libstdc++")
|
||||
if (MSVC)
|
||||
set(CMAKE_CXX_FLAGS "/EHsc ${CMAKE_CXX_FLAGS}")
|
||||
endif()
|
||||
|
||||
set(CMAKE_ANDROID_STL_TYPE c++_static)
|
||||
# Generate MGGitHash.h
|
||||
execute_process(
|
||||
COMMAND git rev-parse HEAD
|
||||
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
|
||||
OUTPUT_VARIABLE GIT_COMMIT_HASH_FULL
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
)
|
||||
|
||||
#set(CMAKE_BUILD_TYPE Release)
|
||||
string(SUBSTRING "${GIT_COMMIT_HASH_FULL}" 0 7 GIT_COMMIT_HASH_SHORT)
|
||||
|
||||
set(PROFILING OFF)
|
||||
configure_file(
|
||||
${CMAKE_SOURCE_DIR}/MobileGL/MG_Util/Miscellany/MGGitHash.h.in
|
||||
${CMAKE_BINARY_DIR}/generated/MGGitHash.h
|
||||
@ONLY
|
||||
)
|
||||
|
||||
find_library(GLSLANG_LIB glslang PATHS ${CMAKE_SOURCE_DIR}/libraries/arm64-v8a/)
|
||||
include_directories(${CMAKE_BINARY_DIR}/generated)
|
||||
|
||||
set(ENABLE_RTTI ON CACHE BOOL "Enables RTTI (will be took by glslang)" FORCE)
|
||||
|
||||
set(ENABLE_GLSLANG_BINARIES OFF CACHE BOOL "Enable glslangValidator/spirv-remap" FORCE)
|
||||
set(ENABLE_SPVREMAPPER OFF CACHE BOOL "Enable SPVRemapper" FORCE)
|
||||
set(ENABLE_OPT ON CACHE BOOL "Enable SPIRV-Tools opt usage in glslang" FORCE)
|
||||
set(BUILD_EXTERNAL ON CACHE BOOL "Build external deps in External/" FORCE)
|
||||
set(ENABLE_GLSLANG_INSTALL OFF CACHE BOOL "Install glslang targets" FORCE)
|
||||
|
||||
set(SPIRV_CROSS_C_API ON CACHE BOOL "Enable C API" FORCE)
|
||||
set(SPIRV_CROSS_ENABLE_GLSL ON CACHE BOOL "Enable GLSL backend" FORCE)
|
||||
set(SPIRV_CROSS_ENABLE_HLSL OFF CACHE BOOL "Disable HLSL backend" FORCE)
|
||||
set(SPIRV_CROSS_ENABLE_MSL OFF CACHE BOOL "Disable MSL backend" FORCE)
|
||||
set(SPIRV_CROSS_ENABLE_CPP OFF CACHE BOOL "Disable C++ API target" FORCE)
|
||||
set(SPIRV_CROSS_CLI OFF CACHE BOOL "Disable CLI binary" FORCE)
|
||||
set(SPIRV_CROSS_STATIC ON CACHE BOOL "Prefer static libs" FORCE)
|
||||
|
||||
set(SPIRV_REFLECT_EXECUTABLE OFF CACHE BOOL "Build spirv-reflect executable" FORCE)
|
||||
set(SPIRV_REFLECT_STATIC_LIB ON CACHE BOOL "Build a SPIRV-Reflect static library" FORCE)
|
||||
set(SPIRV_REFLECT_BUILD_TESTS OFF CACHE BOOL "Build the SPIRV-Reflect test suite" FORCE)
|
||||
set(SPIRV_REFLECT_ENABLE_ASSERTS OFF CACHE BOOL "Enable asserts for debugging" FORCE)
|
||||
set(SPIRV_REFLECT_ENABLE_ASAN OFF CACHE BOOL "Use address sanitization" FORCE)
|
||||
set(SPIRV_REFLECT_INSTALL OFF CACHE BOOL "Whether to install" FORCE)
|
||||
|
||||
# add_subdirectory(3rdparty/DiligentCore)
|
||||
add_subdirectory(3rdparty/glslang)
|
||||
add_subdirectory(3rdparty/SPIRV-Cross)
|
||||
add_subdirectory(3rdparty/VulkanMemoryAllocator)
|
||||
add_subdirectory(3rdparty/Vulkan-Headers)
|
||||
add_subdirectory(3rdparty/Vulkan-Utility-Libraries)
|
||||
add_subdirectory(3rdparty/SPIRV-Reflect)
|
||||
|
||||
set(XXHASH_BUILD_XXHSUM OFF)
|
||||
option(BUILD_SHARED_LIBS OFF)
|
||||
add_subdirectory(3rdparty/xxHash/build/cmake xxhash_build EXCLUDE_FROM_ALL)
|
||||
|
||||
set(TRACY_ENABLE ${MOBILEGL_ENABLE_TRACY} CACHE BOOL "Enable Tracy, this is an internal variable" FORCE)
|
||||
|
||||
if (TRACY_ENABLE)
|
||||
set(TRACY_ON_DEMAND ON CACHE BOOL "Enable profiling only connected" FORCE)
|
||||
set(TRACY_NO_EXIT OFF CACHE BOOL "Don't exit Tracy until connected" FORCE)
|
||||
set(TRACY_DELAYED_INIT ON CACHE BOOL "Don't init Tracy on library load" FORCE)
|
||||
set(TRACY_MANUAL_LIFETIME ON CACHE BOOL "Manually control Tracy lifetime" FORCE)
|
||||
set(TRACY_NO_CRASH_HANDLER ON CACHE BOOL "Disable crash handling" FORCE)
|
||||
|
||||
add_subdirectory(3rdparty/tracy)
|
||||
endif ()
|
||||
|
||||
set(SOURCE_FILES
|
||||
MobileGL/Init.cpp
|
||||
MobileGL/GlobalObjects.cpp
|
||||
MobileGL/ConfigLoader.cpp
|
||||
|
||||
MobileGL/MG_Util/Debug/Log.cpp
|
||||
|
||||
MobileGL/MG_Util/Math/VectorTypes.cpp
|
||||
MobileGL/MG_Util/Metrics/TextureMetrics.cpp
|
||||
|
||||
MobileGL/MG_Util/Metrics/BufferMetrics.cpp
|
||||
|
||||
MobileGL/MG_Util/Converters/GLToStr/GLEnumConverter.cpp
|
||||
MobileGL/MG_Util/Converters/EGLToStr/EGLEnumConverter.cpp
|
||||
MobileGL/MG_Util/Converters/MGToStr/DataTypeConverter.cpp
|
||||
MobileGL/MG_Util/Converters/MGToStr/RenderStateEnumConverter.cpp
|
||||
MobileGL/MG_Util/Converters/MGToStr/GLExtensionConverter.cpp
|
||||
MobileGL/MG_Util/Converters/MGToStr/BufferEnumConverter.cpp
|
||||
MobileGL/MG_Util/Converters/MGToStr/FramebufferEnumConverter.cpp
|
||||
MobileGL/MG_Util/Converters/MGToStr/TextureEnumConverter.cpp
|
||||
MobileGL/MG_Util/Converters/GLToGlslang/ProgramEnumConverter.cpp
|
||||
MobileGL/MG_Util/Converters/MGToGL/ErrorCodeConverter.cpp
|
||||
MobileGL/MG_Util/Converters/MGToGL/BufferEnumConverter.cpp
|
||||
MobileGL/MG_Util/Converters/MGToGL/FramebufferEnumConverter.cpp
|
||||
MobileGL/MG_Util/Converters/MGToGL/TextureEnumConverter.cpp
|
||||
MobileGL/MG_Util/Converters/MGToGL/DataTypeConverter.cpp
|
||||
MobileGL/MG_Util/Converters/MGToGL/RenderStateEnumConverter.cpp
|
||||
MobileGL/MG_Util/Converters/MGToGL/ProgramEnumConverter.cpp
|
||||
MobileGL/MG_Util/Converters/GLToMG/BufferEnumConverter.cpp
|
||||
MobileGL/MG_Util/Converters/GLToMG/FramebufferEnumConverter.cpp
|
||||
MobileGL/MG_Util/Converters/GLToMG/TextureEnumConverter.cpp
|
||||
MobileGL/MG_Util/Converters/GLToMG/DataTypeConverter.cpp
|
||||
MobileGL/MG_Util/Converters/GLToMG/RenderStateEnumConverter.cpp
|
||||
MobileGL/MG_Util/Converters/GLToMG/ProgramEnumConverter.cpp
|
||||
MobileGL/MG_Util/Converters/MGToMG/TextureEnumConverter.cpp
|
||||
MobileGL/MG_Util/Converters/MGToVk/RenderStateEnumConverter.cpp
|
||||
MobileGL/MG_Util/Converters/MGToVk/TextureEnumConverter.cpp
|
||||
|
||||
MobileGL/MG_Util/Classifiers/TextureEnumClassifier.cpp
|
||||
|
||||
MobileGL/MG_Util/ShaderTranspiler/ShaderCompiler.cpp
|
||||
MobileGL/MG_Util/ShaderTranspiler/SpvcSession.cpp
|
||||
MobileGL/MG_Util/ShaderTranspiler/ShaderSourceProcessor.cpp
|
||||
MobileGL/MG_Util/ShaderTranspiler/glslang/TMglGlslIoResolver.cpp
|
||||
MobileGL/MG_Util/ShaderTranspiler/SpirvPasses/EliminateFloatEqualsZeroPass.cpp
|
||||
|
||||
MobileGL/MG_Util/BackendLoaders/OpenGL/Loader.cpp
|
||||
MobileGL/MG_Util/BackendLoaders/Vulkan/Loader.cpp
|
||||
|
||||
MobileGL/MG_Util/Texture/PixelStoreProcessor.cpp
|
||||
MobileGL/MG_Util/Texture/TextureFormatProcessor.cpp
|
||||
|
||||
MobileGL/MG_Impl/GLXImpl/Exporting/Definitions.cpp
|
||||
MobileGL/MG_Impl/GLXImpl/LookUp/LookUp.cpp
|
||||
|
||||
MobileGL/MG_Impl/EGLImpl/Exporting/Definitions.cpp
|
||||
MobileGL/MG_Impl/EGLImpl/EGLImpl.cpp
|
||||
|
||||
# @INSERTION_POINT:SOURCE_FILE_GLIMPL@ #
|
||||
MobileGL/MG_Impl/GLImpl/Sampler/Validators.cpp
|
||||
MobileGL/MG_Impl/GLImpl/Sampler/GL_Sampler.cpp
|
||||
MobileGL/MG_Impl/GLImpl/Drawing/GL_Drawing.cpp
|
||||
MobileGL/MG_Impl/GLImpl/RenderState/GL_RenderState.cpp
|
||||
MobileGL/MG_Impl/GLImpl/Framebuffer/Validators.cpp
|
||||
MobileGL/MG_Impl/GLImpl/Framebuffer/GL_Framebuffer.cpp
|
||||
MobileGL/MG_Impl/GLImpl/Program/GL_Program.cpp
|
||||
MobileGL/MG_Impl/GLImpl/Texture/GL_Texture.cpp
|
||||
MobileGL/MG_Impl/GLImpl/Texture/Validators.cpp
|
||||
MobileGL/MG_Impl/GLImpl/Texture/ProxyTexture.cpp
|
||||
MobileGL/MG_Impl/GLImpl/VertexArray/GL_VertexArray.cpp
|
||||
MobileGL/MG_Impl/GLImpl/VertexArray/Validators.cpp
|
||||
MobileGL/MG_Impl/GLImpl/Buffer/GL_Buffer.cpp
|
||||
MobileGL/MG_Impl/GLImpl/Buffer/Validators.cpp
|
||||
MobileGL/MG_Impl/GLImpl/Exporting/Definitions.cpp
|
||||
MobileGL/MG_Impl/GLImpl/Getter/GL_Getter.cpp
|
||||
MobileGL/MG_Impl/GLImpl/Sync/GL_Sync.cpp
|
||||
|
||||
MobileGL/MG_Impl/Init.cpp
|
||||
MobileGL/MG_Impl/GetProcAddress.cpp
|
||||
|
||||
MobileGL/MG_Backend/Init.cpp
|
||||
MobileGL/MG_Backend/BackendObject.cpp
|
||||
|
||||
MobileGL/MG_Backend/DirectGLES/DirectGLES.cpp
|
||||
MobileGL/MG_Backend/DirectGLES/BackendObject_DirectGLES.cpp
|
||||
MobileGL/MG_Backend/DirectGLES/Utils.cpp
|
||||
MobileGL/MG_Backend/DirectGLES/Managers.cpp
|
||||
|
||||
MobileGL/MG_Backend/DirectVulkan/DirectVulkan.cpp
|
||||
MobileGL/MG_Backend/DirectVulkan/BackendObject_DirectVulkan.cpp
|
||||
MobileGL/MG_Backend/DirectVulkan/VmaImpl.cpp
|
||||
MobileGL/MG_Backend/DirectVulkan/Renderer/VulkanRenderer.cpp
|
||||
MobileGL/MG_Backend/DirectVulkan/Renderer/SwapchainObject.cpp
|
||||
MobileGL/MG_Backend/DirectVulkan/Renderer/FrameContext.cpp
|
||||
MobileGL/MG_Backend/DirectVulkan/Renderer/PipelineFactory.cpp
|
||||
MobileGL/MG_Backend/DirectVulkan/Renderer/ProgramFactory.cpp
|
||||
MobileGL/MG_Backend/DirectVulkan/Renderer/UniformManager.cpp
|
||||
MobileGL/MG_Backend/DirectVulkan/Renderer/BufferArena.cpp
|
||||
MobileGL/MG_Backend/DirectVulkan/Renderer/VkBufferManager.cpp
|
||||
MobileGL/MG_Backend/DirectVulkan/Renderer/VertexInputStateBuilder.cpp
|
||||
MobileGL/MG_Backend/DirectVulkan/Renderer/VertexInputStateFactory.cpp
|
||||
MobileGL/MG_Backend/DirectVulkan/Renderer/VkBufferObject.cpp
|
||||
MobileGL/MG_Backend/DirectVulkan/Renderer/VkTextureManager.cpp
|
||||
MobileGL/MG_Backend/DirectVulkan/Renderer/VkSamplerManager.cpp
|
||||
MobileGL/MG_Backend/DirectVulkan/Renderer/VkClearManager.cpp
|
||||
MobileGL/MG_Backend/DirectVulkan/Renderer/VkRenderPassManager.cpp
|
||||
|
||||
MobileGL/MG_State/GLState/Core.cpp
|
||||
MobileGL/MG_State/EGLState/Core.cpp
|
||||
MobileGL/MG_State/GLState/ErrorState/Error.cpp
|
||||
MobileGL/MG_State/GLState/BufferState/BufferState.cpp
|
||||
MobileGL/MG_State/GLState/BufferState/BufferObject.cpp
|
||||
MobileGL/MG_State/GLState/VertexArrayState/VertexArrayState.cpp
|
||||
MobileGL/MG_State/GLState/VertexArrayState/VertexArrayObject.cpp
|
||||
MobileGL/MG_State/GLState/TextureState/MipmapStorage.cpp
|
||||
MobileGL/MG_State/GLState/TextureState/TextureObject.cpp
|
||||
MobileGL/MG_State/GLState/TextureState/TextureObject1D.cpp
|
||||
MobileGL/MG_State/GLState/TextureState/TextureObject2D.cpp
|
||||
MobileGL/MG_State/GLState/TextureState/TextureObject2DCube.cpp
|
||||
MobileGL/MG_State/GLState/TextureState/TextureObject3D.cpp
|
||||
MobileGL/MG_State/GLState/TextureState/TextureObjectBuffer.cpp
|
||||
MobileGL/MG_State/GLState/TextureState/TextureUnit.cpp
|
||||
MobileGL/MG_State/GLState/TextureState/TextureState.cpp
|
||||
MobileGL/MG_State/GLState/ProgramState/ProgramObject.cpp
|
||||
MobileGL/MG_State/GLState/ProgramState/ShaderObject.cpp
|
||||
MobileGL/MG_State/GLState/ProgramState/ProgramState.cpp
|
||||
MobileGL/MG_State/GLState/RenderState/RenderState.cpp
|
||||
MobileGL/MG_State/GLState/FramebufferState/FramebufferObject.cpp
|
||||
MobileGL/MG_State/GLState/FramebufferState/FramebufferState.cpp
|
||||
MobileGL/MG_State/GLState/SamplerState/SamplerObject.cpp
|
||||
MobileGL/MG_State/GLState/SamplerState/SamplerState.cpp
|
||||
MobileGL/MG_State/GLState/RenderbufferState/RenderbufferObject.cpp
|
||||
MobileGL/MG_State/GLState/RenderbufferState/RenderbufferState.cpp
|
||||
)
|
||||
|
||||
set(MOBILEGL_LINK_LIBRARIES
|
||||
glslang::glslang
|
||||
spirv-cross-c
|
||||
SPIRV-Tools-opt
|
||||
SPIRV-Tools
|
||||
xxHash::xxhash
|
||||
GPUOpen::VulkanMemoryAllocator
|
||||
Vulkan::UtilityHeaders
|
||||
spirv-reflect-static
|
||||
)
|
||||
|
||||
set(MOBILEGL_COMPILE_DEF
|
||||
-DVMA_STATIC_VULKAN_FUNCTIONS=0
|
||||
-DVMA_DYNAMIC_VULKAN_FUNCTIONS=1
|
||||
-DVMA_VULKAN_VERSION=1001000
|
||||
)
|
||||
|
||||
message(STATUS "MOBILEGL_COMPILE_DEF=${MOBILEGL_COMPILE_DEF}")
|
||||
|
||||
set(MOBILEGL_INCLUDE_DIR
|
||||
${CMAKE_SOURCE_DIR}/include
|
||||
${CMAKE_SOURCE_DIR}/MobileGL
|
||||
${spirv-tools_SOURCE_DIR}
|
||||
${spirv-tools_SOURCE_DIR}/include
|
||||
${spirv-tools_BINARY_DIR}
|
||||
${SPIRV-Headers_SOURCE_DIR}/include
|
||||
)
|
||||
|
||||
add_library(${CMAKE_PROJECT_NAME} SHARED
|
||||
MG/Init.cpp
|
||||
|
||||
# MG_GL/Implementations/GL
|
||||
MG/MG_GL/Implementations/GL/GLFuncsDefinitions/GLFuncsDefinitions.cpp
|
||||
|
||||
MG/MG_GL/Implementations/GL/Getter/GL_Getter.cpp
|
||||
MG/MG_GL/Implementations/GL/Getter/BackendInfo.cpp
|
||||
|
||||
MG/MG_GL/Implementations/GL/Framebuffer/GL_Framebuffer.cpp
|
||||
|
||||
MG/MG_GL/Implementations/GL/Common/GL_Common.cpp
|
||||
|
||||
MG/MG_GL/Implementations/GL/Buffer/GL_Buffer.cpp
|
||||
|
||||
MG/MG_GL/Implementations/GL/Drawing/GL_Drawing.cpp
|
||||
|
||||
MG/MG_GL/Implementations/GL/Program/GL_Program.cpp
|
||||
|
||||
MG/MG_GL/Implementations/GL/Texture/GL_Texture.cpp
|
||||
|
||||
MG/MG_GL/Implementations/GL/VertexArray/GL_VertexArray.cpp
|
||||
|
||||
# MG_GL/Implementations/GLX
|
||||
MG/MG_GL/Implementations/GLX/LookUp/LookUp.cpp
|
||||
|
||||
# MG_GL/Implementations/EGL
|
||||
MG/MG_GL/Implementations/EGL/VK/EGL_EMU.cpp
|
||||
|
||||
MG/MG_GL/Implementations/EGL/GLES/EGL_WRAP.cpp
|
||||
|
||||
# MG_GL/State
|
||||
MG/MG_GL/State/Core/GLState.cpp
|
||||
|
||||
MG/MG_GL/State/Common/CommonState.cpp
|
||||
|
||||
MG/MG_GL/State/Texture/TextureState.cpp
|
||||
|
||||
MG/MG_GL/State/VertexArray/VertexArrayState.cpp
|
||||
|
||||
MG/MG_GL/State/Buffer/BufferState.cpp
|
||||
|
||||
MG/MG_GL/State/Program/ShaderObject.cpp
|
||||
MG/MG_GL/State/Program/ProgramState.cpp
|
||||
|
||||
MG/MG_GL/State/Framebuffer/FramebufferState.cpp
|
||||
|
||||
# MG_GL/BackendLoader
|
||||
MG/MG_GL/BackendLoader/GLES/Loader.cpp
|
||||
|
||||
# MG_UTIL/Debug
|
||||
MG/MG_UTIL/Debug/Debug.cpp
|
||||
|
||||
# MG_UTIL/Program
|
||||
MG/MG_UTIL/Program/DebugTool.cpp
|
||||
MG/MG_UTIL/Program/GLSLTool.cpp
|
||||
|
||||
# MG_RHI/GLES
|
||||
MG/MG_RHI/GLES/Test/TestDrawing.cpp
|
||||
${SOURCE_FILES}
|
||||
)
|
||||
|
||||
target_include_directories(${CMAKE_PROJECT_NAME} PRIVATE ./includes)
|
||||
if (CMAKE_BUILD_TYPE STREQUAL "Debug")
|
||||
set_target_properties(${CMAKE_PROJECT_NAME} PROPERTIES
|
||||
C_VISIBILITY_PRESET default
|
||||
CXX_VISIBILITY_PRESET default
|
||||
VISIBILITY_INLINES_HIDDEN OFF
|
||||
)
|
||||
else()
|
||||
set_target_properties(${CMAKE_PROJECT_NAME} PROPERTIES
|
||||
C_VISIBILITY_PRESET hidden
|
||||
CXX_VISIBILITY_PRESET hidden
|
||||
VISIBILITY_INLINES_HIDDEN ON
|
||||
)
|
||||
endif()
|
||||
|
||||
target_include_directories(${CMAKE_PROJECT_NAME} PUBLIC
|
||||
${MOBILEGL_INCLUDE_DIR}
|
||||
)
|
||||
|
||||
target_link_libraries(${CMAKE_PROJECT_NAME}
|
||||
${CMAKE_SOURCE_DIR}/library/arm64-v8a/libglslang.a
|
||||
${CMAKE_SOURCE_DIR}/library/arm64-v8a/libspirv-cross-c-shared.so
|
||||
#${CMAKE_SOURCE_DIR}/library/arm64-v8a/libshaderconv.so
|
||||
${CMAKE_SOURCE_DIR}/library/arm64-v8a/libGenericCodeGen.a
|
||||
${CMAKE_SOURCE_DIR}/library/arm64-v8a/libglslang-default-resource-limits.a
|
||||
${CMAKE_SOURCE_DIR}/library/arm64-v8a/libMachineIndependent.a
|
||||
${CMAKE_SOURCE_DIR}/library/arm64-v8a/libOSDependent.a
|
||||
${CMAKE_SOURCE_DIR}/library/arm64-v8a/libSPIRV-Tools-diff.a
|
||||
${CMAKE_SOURCE_DIR}/library/arm64-v8a/libSPIRV-Tools-link.a
|
||||
${CMAKE_SOURCE_DIR}/library/arm64-v8a/libSPIRV-Tools-lint.a
|
||||
${CMAKE_SOURCE_DIR}/library/arm64-v8a/libSPIRV-Tools-opt.a
|
||||
${CMAKE_SOURCE_DIR}/library/arm64-v8a/libSPIRV-Tools-reduce.a
|
||||
${CMAKE_SOURCE_DIR}/library/arm64-v8a/libSPIRV-Tools.a
|
||||
${CMAKE_SOURCE_DIR}/library/arm64-v8a/libSPIRV.a
|
||||
${CMAKE_SOURCE_DIR}/library/arm64-v8a/libSPVRemapper.a
|
||||
android
|
||||
log
|
||||
EGL
|
||||
vulkan
|
||||
PUBLIC
|
||||
${MOBILEGL_LINK_LIBRARIES}
|
||||
)
|
||||
|
||||
target_include_directories(MobileGL PUBLIC
|
||||
${CMAKE_SOURCE_DIR}/include
|
||||
target_compile_definitions(${CMAKE_PROJECT_NAME}
|
||||
PUBLIC
|
||||
${MOBILEGL_COMPILE_DEF}
|
||||
)
|
||||
|
||||
if(NOT ANDROID)
|
||||
add_library(${CMAKE_PROJECT_NAME}_s STATIC
|
||||
${SOURCE_FILES}
|
||||
)
|
||||
|
||||
if (CMAKE_BUILD_TYPE STREQUAL "Debug")
|
||||
set_target_properties(${CMAKE_PROJECT_NAME}_s PROPERTIES
|
||||
C_VISIBILITY_PRESET default
|
||||
CXX_VISIBILITY_PRESET default
|
||||
VISIBILITY_INLINES_HIDDEN OFF
|
||||
)
|
||||
else()
|
||||
set_target_properties(${CMAKE_PROJECT_NAME}_s PROPERTIES
|
||||
C_VISIBILITY_PRESET hidden
|
||||
CXX_VISIBILITY_PRESET hidden
|
||||
VISIBILITY_INLINES_HIDDEN ON
|
||||
)
|
||||
endif()
|
||||
|
||||
target_include_directories(${CMAKE_PROJECT_NAME}_s PUBLIC
|
||||
${MOBILEGL_INCLUDE_DIR}
|
||||
)
|
||||
|
||||
if (PROFILING)
|
||||
find_package(Threads)
|
||||
include_directories(${CMAKE_SOURCE_DIR}/3rdparty/perfetto/sdk)
|
||||
add_library(perfetto STATIC ${CMAKE_SOURCE_DIR}/3rdparty/perfetto/sdk/perfetto.cc)
|
||||
target_link_libraries(MobileGL perfetto ${CMAKE_THREAD_LIBS_INIT})
|
||||
target_compile_definitions(MobileGL PUBLIC PROFILING=1)
|
||||
target_link_libraries(${CMAKE_PROJECT_NAME}_s
|
||||
PUBLIC
|
||||
${MOBILEGL_LINK_LIBRARIES}
|
||||
)
|
||||
|
||||
target_compile_definitions(${CMAKE_PROJECT_NAME}_s
|
||||
PUBLIC
|
||||
${MOBILEGL_COMPILE_DEF}
|
||||
)
|
||||
endif()
|
||||
|
||||
if (TRACY_ENABLE)
|
||||
target_link_libraries(${CMAKE_PROJECT_NAME} PUBLIC Tracy::TracyClient)
|
||||
target_link_libraries(${CMAKE_PROJECT_NAME}_s PUBLIC Tracy::TracyClient)
|
||||
target_compile_definitions(${CMAKE_PROJECT_NAME} PUBLIC -DTRACY_ENABLE)
|
||||
target_compile_definitions(${CMAKE_PROJECT_NAME}_s PUBLIC -DTRACY_ENABLE)
|
||||
endif ()
|
||||
|
||||
if (ANDROID)
|
||||
target_link_libraries(${CMAKE_PROJECT_NAME} PUBLIC
|
||||
android
|
||||
log
|
||||
vulkan
|
||||
)
|
||||
endif()
|
||||
|
||||
if (NOT ANDROID)
|
||||
find_package(Vulkan)
|
||||
if (Vulkan_FOUND)
|
||||
target_link_libraries(${CMAKE_PROJECT_NAME} PUBLIC Vulkan::Vulkan Vulkan::Headers)
|
||||
target_link_libraries(${CMAKE_PROJECT_NAME}_s PUBLIC Vulkan::Vulkan Vulkan::Headers)
|
||||
target_include_directories(${CMAKE_PROJECT_NAME} PUBLIC ${Vulkan_INCLUDE_DIR})
|
||||
target_include_directories(${CMAKE_PROJECT_NAME}_s PUBLIC ${Vulkan_INCLUDE_DIR})
|
||||
endif ()
|
||||
|
||||
if (MOBILEGL_BUILD_TEST)
|
||||
add_subdirectory(MobileGL/MG_Test)
|
||||
endif()
|
||||
|
||||
if (MOBILEGL_BUILD_BENCHMARK)
|
||||
add_subdirectory(MobileGL/MG_Benchmark)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
@@ -0,0 +1,674 @@
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The GNU General Public License is a free, copyleft license for
|
||||
software and other kinds of works.
|
||||
|
||||
The licenses for most software and other practical works are designed
|
||||
to take away your freedom to share and change the works. By contrast,
|
||||
the GNU General Public License is intended to guarantee your freedom to
|
||||
share and change all versions of a program--to make sure it remains free
|
||||
software for all its users. We, the Free Software Foundation, use the
|
||||
GNU General Public License for most of our software; it applies also to
|
||||
any other work released this way by its authors. You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
them if you wish), that you receive source code or can get it if you
|
||||
want it, that you can change the software or use pieces of it in new
|
||||
free programs, and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to prevent others from denying you
|
||||
these rights or asking you to surrender the rights. Therefore, you have
|
||||
certain responsibilities if you distribute copies of the software, or if
|
||||
you modify it: responsibilities to respect the freedom of others.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must pass on to the recipients the same
|
||||
freedoms that you received. You must make sure that they, too, receive
|
||||
or can get the source code. And you must show them these terms so they
|
||||
know their rights.
|
||||
|
||||
Developers that use the GNU GPL protect your rights with two steps:
|
||||
(1) assert copyright on the software, and (2) offer you this License
|
||||
giving you legal permission to copy, distribute and/or modify it.
|
||||
|
||||
For the developers' and authors' protection, the GPL clearly explains
|
||||
that there is no warranty for this free software. For both users' and
|
||||
authors' sake, the GPL requires that modified versions be marked as
|
||||
changed, so that their problems will not be attributed erroneously to
|
||||
authors of previous versions.
|
||||
|
||||
Some devices are designed to deny users access to install or run
|
||||
modified versions of the software inside them, although the manufacturer
|
||||
can do so. This is fundamentally incompatible with the aim of
|
||||
protecting users' freedom to change the software. The systematic
|
||||
pattern of such abuse occurs in the area of products for individuals to
|
||||
use, which is precisely where it is most unacceptable. Therefore, we
|
||||
have designed this version of the GPL to prohibit the practice for those
|
||||
products. If such problems arise substantially in other domains, we
|
||||
stand ready to extend this provision to those domains in future versions
|
||||
of the GPL, as needed to protect the freedom of users.
|
||||
|
||||
Finally, every program is threatened constantly by software patents.
|
||||
States should not allow patents to restrict development and use of
|
||||
software on general-purpose computers, but in those that do, we wish to
|
||||
avoid the special danger that patents applied to a free program could
|
||||
make it effectively proprietary. To prevent this, the GPL assures that
|
||||
patents cannot be used to render the program non-free.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
TERMS AND CONDITIONS
|
||||
|
||||
0. Definitions.
|
||||
|
||||
"This License" refers to version 3 of the GNU General Public License.
|
||||
|
||||
"Copyright" also means copyright-like laws that apply to other kinds of
|
||||
works, such as semiconductor masks.
|
||||
|
||||
"The Program" refers to any copyrightable work licensed under this
|
||||
License. Each licensee is addressed as "you". "Licensees" and
|
||||
"recipients" may be individuals or organizations.
|
||||
|
||||
To "modify" a work means to copy from or adapt all or part of the work
|
||||
in a fashion requiring copyright permission, other than the making of an
|
||||
exact copy. The resulting work is called a "modified version" of the
|
||||
earlier work or a work "based on" the earlier work.
|
||||
|
||||
A "covered work" means either the unmodified Program or a work based
|
||||
on the Program.
|
||||
|
||||
To "propagate" a work means to do anything with it that, without
|
||||
permission, would make you directly or secondarily liable for
|
||||
infringement under applicable copyright law, except executing it on a
|
||||
computer or modifying a private copy. Propagation includes copying,
|
||||
distribution (with or without modification), making available to the
|
||||
public, and in some countries other activities as well.
|
||||
|
||||
To "convey" a work means any kind of propagation that enables other
|
||||
parties to make or receive copies. Mere interaction with a user through
|
||||
a computer network, with no transfer of a copy, is not conveying.
|
||||
|
||||
An interactive user interface displays "Appropriate Legal Notices"
|
||||
to the extent that it includes a convenient and prominently visible
|
||||
feature that (1) displays an appropriate copyright notice, and (2)
|
||||
tells the user that there is no warranty for the work (except to the
|
||||
extent that warranties are provided), that licensees may convey the
|
||||
work under this License, and how to view a copy of this License. If
|
||||
the interface presents a list of user commands or options, such as a
|
||||
menu, a prominent item in the list meets this criterion.
|
||||
|
||||
1. Source Code.
|
||||
|
||||
The "source code" for a work means the preferred form of the work
|
||||
for making modifications to it. "Object code" means any non-source
|
||||
form of a work.
|
||||
|
||||
A "Standard Interface" means an interface that either is an official
|
||||
standard defined by a recognized standards body, or, in the case of
|
||||
interfaces specified for a particular programming language, one that
|
||||
is widely used among developers working in that language.
|
||||
|
||||
The "System Libraries" of an executable work include anything, other
|
||||
than the work as a whole, that (a) is included in the normal form of
|
||||
packaging a Major Component, but which is not part of that Major
|
||||
Component, and (b) serves only to enable use of the work with that
|
||||
Major Component, or to implement a Standard Interface for which an
|
||||
implementation is available to the public in source code form. A
|
||||
"Major Component", in this context, means a major essential component
|
||||
(kernel, window system, and so on) of the specific operating system
|
||||
(if any) on which the executable work runs, or a compiler used to
|
||||
produce the work, or an object code interpreter used to run it.
|
||||
|
||||
The "Corresponding Source" for a work in object code form means all
|
||||
the source code needed to generate, install, and (for an executable
|
||||
work) run the object code and to modify the work, including scripts to
|
||||
control those activities. However, it does not include the work's
|
||||
System Libraries, or general-purpose tools or generally available free
|
||||
programs which are used unmodified in performing those activities but
|
||||
which are not part of the work. For example, Corresponding Source
|
||||
includes interface definition files associated with source files for
|
||||
the work, and the source code for shared libraries and dynamically
|
||||
linked subprograms that the work is specifically designed to require,
|
||||
such as by intimate data communication or control flow between those
|
||||
subprograms and other parts of the work.
|
||||
|
||||
The Corresponding Source need not include anything that users
|
||||
can regenerate automatically from other parts of the Corresponding
|
||||
Source.
|
||||
|
||||
The Corresponding Source for a work in source code form is that
|
||||
same work.
|
||||
|
||||
2. Basic Permissions.
|
||||
|
||||
All rights granted under this License are granted for the term of
|
||||
copyright on the Program, and are irrevocable provided the stated
|
||||
conditions are met. This License explicitly affirms your unlimited
|
||||
permission to run the unmodified Program. The output from running a
|
||||
covered work is covered by this License only if the output, given its
|
||||
content, constitutes a covered work. This License acknowledges your
|
||||
rights of fair use or other equivalent, as provided by copyright law.
|
||||
|
||||
You may make, run and propagate covered works that you do not
|
||||
convey, without conditions so long as your license otherwise remains
|
||||
in force. You may convey covered works to others for the sole purpose
|
||||
of having them make modifications exclusively for you, or provide you
|
||||
with facilities for running those works, provided that you comply with
|
||||
the terms of this License in conveying all material for which you do
|
||||
not control copyright. Those thus making or running the covered works
|
||||
for you must do so exclusively on your behalf, under your direction
|
||||
and control, on terms that prohibit them from making any copies of
|
||||
your copyrighted material outside their relationship with you.
|
||||
|
||||
Conveying under any other circumstances is permitted solely under
|
||||
the conditions stated below. Sublicensing is not allowed; section 10
|
||||
makes it unnecessary.
|
||||
|
||||
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
|
||||
|
||||
No covered work shall be deemed part of an effective technological
|
||||
measure under any applicable law fulfilling obligations under article
|
||||
11 of the WIPO copyright treaty adopted on 20 December 1996, or
|
||||
similar laws prohibiting or restricting circumvention of such
|
||||
measures.
|
||||
|
||||
When you convey a covered work, you waive any legal power to forbid
|
||||
circumvention of technological measures to the extent such circumvention
|
||||
is effected by exercising rights under this License with respect to
|
||||
the covered work, and you disclaim any intention to limit operation or
|
||||
modification of the work as a means of enforcing, against the work's
|
||||
users, your or third parties' legal rights to forbid circumvention of
|
||||
technological measures.
|
||||
|
||||
4. Conveying Verbatim Copies.
|
||||
|
||||
You may convey verbatim copies of the Program's source code as you
|
||||
receive it, in any medium, provided that you conspicuously and
|
||||
appropriately publish on each copy an appropriate copyright notice;
|
||||
keep intact all notices stating that this License and any
|
||||
non-permissive terms added in accord with section 7 apply to the code;
|
||||
keep intact all notices of the absence of any warranty; and give all
|
||||
recipients a copy of this License along with the Program.
|
||||
|
||||
You may charge any price or no price for each copy that you convey,
|
||||
and you may offer support or warranty protection for a fee.
|
||||
|
||||
5. Conveying Modified Source Versions.
|
||||
|
||||
You may convey a work based on the Program, or the modifications to
|
||||
produce it from the Program, in the form of source code under the
|
||||
terms of section 4, provided that you also meet all of these conditions:
|
||||
|
||||
a) The work must carry prominent notices stating that you modified
|
||||
it, and giving a relevant date.
|
||||
|
||||
b) The work must carry prominent notices stating that it is
|
||||
released under this License and any conditions added under section
|
||||
7. This requirement modifies the requirement in section 4 to
|
||||
"keep intact all notices".
|
||||
|
||||
c) You must license the entire work, as a whole, under this
|
||||
License to anyone who comes into possession of a copy. This
|
||||
License will therefore apply, along with any applicable section 7
|
||||
additional terms, to the whole of the work, and all its parts,
|
||||
regardless of how they are packaged. This License gives no
|
||||
permission to license the work in any other way, but it does not
|
||||
invalidate such permission if you have separately received it.
|
||||
|
||||
d) If the work has interactive user interfaces, each must display
|
||||
Appropriate Legal Notices; however, if the Program has interactive
|
||||
interfaces that do not display Appropriate Legal Notices, your
|
||||
work need not make them do so.
|
||||
|
||||
A compilation of a covered work with other separate and independent
|
||||
works, which are not by their nature extensions of the covered work,
|
||||
and which are not combined with it such as to form a larger program,
|
||||
in or on a volume of a storage or distribution medium, is called an
|
||||
"aggregate" if the compilation and its resulting copyright are not
|
||||
used to limit the access or legal rights of the compilation's users
|
||||
beyond what the individual works permit. Inclusion of a covered work
|
||||
in an aggregate does not cause this License to apply to the other
|
||||
parts of the aggregate.
|
||||
|
||||
6. Conveying Non-Source Forms.
|
||||
|
||||
You may convey a covered work in object code form under the terms
|
||||
of sections 4 and 5, provided that you also convey the
|
||||
machine-readable Corresponding Source under the terms of this License,
|
||||
in one of these ways:
|
||||
|
||||
a) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by the
|
||||
Corresponding Source fixed on a durable physical medium
|
||||
customarily used for software interchange.
|
||||
|
||||
b) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by a
|
||||
written offer, valid for at least three years and valid for as
|
||||
long as you offer spare parts or customer support for that product
|
||||
model, to give anyone who possesses the object code either (1) a
|
||||
copy of the Corresponding Source for all the software in the
|
||||
product that is covered by this License, on a durable physical
|
||||
medium customarily used for software interchange, for a price no
|
||||
more than your reasonable cost of physically performing this
|
||||
conveying of source, or (2) access to copy the
|
||||
Corresponding Source from a network server at no charge.
|
||||
|
||||
c) Convey individual copies of the object code with a copy of the
|
||||
written offer to provide the Corresponding Source. This
|
||||
alternative is allowed only occasionally and noncommercially, and
|
||||
only if you received the object code with such an offer, in accord
|
||||
with subsection 6b.
|
||||
|
||||
d) Convey the object code by offering access from a designated
|
||||
place (gratis or for a charge), and offer equivalent access to the
|
||||
Corresponding Source in the same way through the same place at no
|
||||
further charge. You need not require recipients to copy the
|
||||
Corresponding Source along with the object code. If the place to
|
||||
copy the object code is a network server, the Corresponding Source
|
||||
may be on a different server (operated by you or a third party)
|
||||
that supports equivalent copying facilities, provided you maintain
|
||||
clear directions next to the object code saying where to find the
|
||||
Corresponding Source. Regardless of what server hosts the
|
||||
Corresponding Source, you remain obligated to ensure that it is
|
||||
available for as long as needed to satisfy these requirements.
|
||||
|
||||
e) Convey the object code using peer-to-peer transmission, provided
|
||||
you inform other peers where the object code and Corresponding
|
||||
Source of the work are being offered to the general public at no
|
||||
charge under subsection 6d.
|
||||
|
||||
A separable portion of the object code, whose source code is excluded
|
||||
from the Corresponding Source as a System Library, need not be
|
||||
included in conveying the object code work.
|
||||
|
||||
A "User Product" is either (1) a "consumer product", which means any
|
||||
tangible personal property which is normally used for personal, family,
|
||||
or household purposes, or (2) anything designed or sold for incorporation
|
||||
into a dwelling. In determining whether a product is a consumer product,
|
||||
doubtful cases shall be resolved in favor of coverage. For a particular
|
||||
product received by a particular user, "normally used" refers to a
|
||||
typical or common use of that class of product, regardless of the status
|
||||
of the particular user or of the way in which the particular user
|
||||
actually uses, or expects or is expected to use, the product. A product
|
||||
is a consumer product regardless of whether the product has substantial
|
||||
commercial, industrial or non-consumer uses, unless such uses represent
|
||||
the only significant mode of use of the product.
|
||||
|
||||
"Installation Information" for a User Product means any methods,
|
||||
procedures, authorization keys, or other information required to install
|
||||
and execute modified versions of a covered work in that User Product from
|
||||
a modified version of its Corresponding Source. The information must
|
||||
suffice to ensure that the continued functioning of the modified object
|
||||
code is in no case prevented or interfered with solely because
|
||||
modification has been made.
|
||||
|
||||
If you convey an object code work under this section in, or with, or
|
||||
specifically for use in, a User Product, and the conveying occurs as
|
||||
part of a transaction in which the right of possession and use of the
|
||||
User Product is transferred to the recipient in perpetuity or for a
|
||||
fixed term (regardless of how the transaction is characterized), the
|
||||
Corresponding Source conveyed under this section must be accompanied
|
||||
by the Installation Information. But this requirement does not apply
|
||||
if neither you nor any third party retains the ability to install
|
||||
modified object code on the User Product (for example, the work has
|
||||
been installed in ROM).
|
||||
|
||||
The requirement to provide Installation Information does not include a
|
||||
requirement to continue to provide support service, warranty, or updates
|
||||
for a work that has been modified or installed by the recipient, or for
|
||||
the User Product in which it has been modified or installed. Access to a
|
||||
network may be denied when the modification itself materially and
|
||||
adversely affects the operation of the network or violates the rules and
|
||||
protocols for communication across the network.
|
||||
|
||||
Corresponding Source conveyed, and Installation Information provided,
|
||||
in accord with this section must be in a format that is publicly
|
||||
documented (and with an implementation available to the public in
|
||||
source code form), and must require no special password or key for
|
||||
unpacking, reading or copying.
|
||||
|
||||
7. Additional Terms.
|
||||
|
||||
"Additional permissions" are terms that supplement the terms of this
|
||||
License by making exceptions from one or more of its conditions.
|
||||
Additional permissions that are applicable to the entire Program shall
|
||||
be treated as though they were included in this License, to the extent
|
||||
that they are valid under applicable law. If additional permissions
|
||||
apply only to part of the Program, that part may be used separately
|
||||
under those permissions, but the entire Program remains governed by
|
||||
this License without regard to the additional permissions.
|
||||
|
||||
When you convey a copy of a covered work, you may at your option
|
||||
remove any additional permissions from that copy, or from any part of
|
||||
it. (Additional permissions may be written to require their own
|
||||
removal in certain cases when you modify the work.) You may place
|
||||
additional permissions on material, added by you to a covered work,
|
||||
for which you have or can give appropriate copyright permission.
|
||||
|
||||
Notwithstanding any other provision of this License, for material you
|
||||
add to a covered work, you may (if authorized by the copyright holders of
|
||||
that material) supplement the terms of this License with terms:
|
||||
|
||||
a) Disclaiming warranty or limiting liability differently from the
|
||||
terms of sections 15 and 16 of this License; or
|
||||
|
||||
b) Requiring preservation of specified reasonable legal notices or
|
||||
author attributions in that material or in the Appropriate Legal
|
||||
Notices displayed by works containing it; or
|
||||
|
||||
c) Prohibiting misrepresentation of the origin of that material, or
|
||||
requiring that modified versions of such material be marked in
|
||||
reasonable ways as different from the original version; or
|
||||
|
||||
d) Limiting the use for publicity purposes of names of licensors or
|
||||
authors of the material; or
|
||||
|
||||
e) Declining to grant rights under trademark law for use of some
|
||||
trade names, trademarks, or service marks; or
|
||||
|
||||
f) Requiring indemnification of licensors and authors of that
|
||||
material by anyone who conveys the material (or modified versions of
|
||||
it) with contractual assumptions of liability to the recipient, for
|
||||
any liability that these contractual assumptions directly impose on
|
||||
those licensors and authors.
|
||||
|
||||
All other non-permissive additional terms are considered "further
|
||||
restrictions" within the meaning of section 10. If the Program as you
|
||||
received it, or any part of it, contains a notice stating that it is
|
||||
governed by this License along with a term that is a further
|
||||
restriction, you may remove that term. If a license document contains
|
||||
a further restriction but permits relicensing or conveying under this
|
||||
License, you may add to a covered work material governed by the terms
|
||||
of that license document, provided that the further restriction does
|
||||
not survive such relicensing or conveying.
|
||||
|
||||
If you add terms to a covered work in accord with this section, you
|
||||
must place, in the relevant source files, a statement of the
|
||||
additional terms that apply to those files, or a notice indicating
|
||||
where to find the applicable terms.
|
||||
|
||||
Additional terms, permissive or non-permissive, may be stated in the
|
||||
form of a separately written license, or stated as exceptions;
|
||||
the above requirements apply either way.
|
||||
|
||||
8. Termination.
|
||||
|
||||
You may not propagate or modify a covered work except as expressly
|
||||
provided under this License. Any attempt otherwise to propagate or
|
||||
modify it is void, and will automatically terminate your rights under
|
||||
this License (including any patent licenses granted under the third
|
||||
paragraph of section 11).
|
||||
|
||||
However, if you cease all violation of this License, then your
|
||||
license from a particular copyright holder is reinstated (a)
|
||||
provisionally, unless and until the copyright holder explicitly and
|
||||
finally terminates your license, and (b) permanently, if the copyright
|
||||
holder fails to notify you of the violation by some reasonable means
|
||||
prior to 60 days after the cessation.
|
||||
|
||||
Moreover, your license from a particular copyright holder is
|
||||
reinstated permanently if the copyright holder notifies you of the
|
||||
violation by some reasonable means, this is the first time you have
|
||||
received notice of violation of this License (for any work) from that
|
||||
copyright holder, and you cure the violation prior to 30 days after
|
||||
your receipt of the notice.
|
||||
|
||||
Termination of your rights under this section does not terminate the
|
||||
licenses of parties who have received copies or rights from you under
|
||||
this License. If your rights have been terminated and not permanently
|
||||
reinstated, you do not qualify to receive new licenses for the same
|
||||
material under section 10.
|
||||
|
||||
9. Acceptance Not Required for Having Copies.
|
||||
|
||||
You are not required to accept this License in order to receive or
|
||||
run a copy of the Program. Ancillary propagation of a covered work
|
||||
occurring solely as a consequence of using peer-to-peer transmission
|
||||
to receive a copy likewise does not require acceptance. However,
|
||||
nothing other than this License grants you permission to propagate or
|
||||
modify any covered work. These actions infringe copyright if you do
|
||||
not accept this License. Therefore, by modifying or propagating a
|
||||
covered work, you indicate your acceptance of this License to do so.
|
||||
|
||||
10. Automatic Licensing of Downstream Recipients.
|
||||
|
||||
Each time you convey a covered work, the recipient automatically
|
||||
receives a license from the original licensors, to run, modify and
|
||||
propagate that work, subject to this License. You are not responsible
|
||||
for enforcing compliance by third parties with this License.
|
||||
|
||||
An "entity transaction" is a transaction transferring control of an
|
||||
organization, or substantially all assets of one, or subdividing an
|
||||
organization, or merging organizations. If propagation of a covered
|
||||
work results from an entity transaction, each party to that
|
||||
transaction who receives a copy of the work also receives whatever
|
||||
licenses to the work the party's predecessor in interest had or could
|
||||
give under the previous paragraph, plus a right to possession of the
|
||||
Corresponding Source of the work from the predecessor in interest, if
|
||||
the predecessor has it or can get it with reasonable efforts.
|
||||
|
||||
You may not impose any further restrictions on the exercise of the
|
||||
rights granted or affirmed under this License. For example, you may
|
||||
not impose a license fee, royalty, or other charge for exercise of
|
||||
rights granted under this License, and you may not initiate litigation
|
||||
(including a cross-claim or counterclaim in a lawsuit) alleging that
|
||||
any patent claim is infringed by making, using, selling, offering for
|
||||
sale, or importing the Program or any portion of it.
|
||||
|
||||
11. Patents.
|
||||
|
||||
A "contributor" is a copyright holder who authorizes use under this
|
||||
License of the Program or a work on which the Program is based. The
|
||||
work thus licensed is called the contributor's "contributor version".
|
||||
|
||||
A contributor's "essential patent claims" are all patent claims
|
||||
owned or controlled by the contributor, whether already acquired or
|
||||
hereafter acquired, that would be infringed by some manner, permitted
|
||||
by this License, of making, using, or selling its contributor version,
|
||||
but do not include claims that would be infringed only as a
|
||||
consequence of further modification of the contributor version. For
|
||||
purposes of this definition, "control" includes the right to grant
|
||||
patent sublicenses in a manner consistent with the requirements of
|
||||
this License.
|
||||
|
||||
Each contributor grants you a non-exclusive, worldwide, royalty-free
|
||||
patent license under the contributor's essential patent claims, to
|
||||
make, use, sell, offer for sale, import and otherwise run, modify and
|
||||
propagate the contents of its contributor version.
|
||||
|
||||
In the following three paragraphs, a "patent license" is any express
|
||||
agreement or commitment, however denominated, not to enforce a patent
|
||||
(such as an express permission to practice a patent or covenant not to
|
||||
sue for patent infringement). To "grant" such a patent license to a
|
||||
party means to make such an agreement or commitment not to enforce a
|
||||
patent against the party.
|
||||
|
||||
If you convey a covered work, knowingly relying on a patent license,
|
||||
and the Corresponding Source of the work is not available for anyone
|
||||
to copy, free of charge and under the terms of this License, through a
|
||||
publicly available network server or other readily accessible means,
|
||||
then you must either (1) cause the Corresponding Source to be so
|
||||
available, or (2) arrange to deprive yourself of the benefit of the
|
||||
patent license for this particular work, or (3) arrange, in a manner
|
||||
consistent with the requirements of this License, to extend the patent
|
||||
license to downstream recipients. "Knowingly relying" means you have
|
||||
actual knowledge that, but for the patent license, your conveying the
|
||||
covered work in a country, or your recipient's use of the covered work
|
||||
in a country, would infringe one or more identifiable patents in that
|
||||
country that you have reason to believe are valid.
|
||||
|
||||
If, pursuant to or in connection with a single transaction or
|
||||
arrangement, you convey, or propagate by procuring conveyance of, a
|
||||
covered work, and grant a patent license to some of the parties
|
||||
receiving the covered work authorizing them to use, propagate, modify
|
||||
or convey a specific copy of the covered work, then the patent license
|
||||
you grant is automatically extended to all recipients of the covered
|
||||
work and works based on it.
|
||||
|
||||
A patent license is "discriminatory" if it does not include within
|
||||
the scope of its coverage, prohibits the exercise of, or is
|
||||
conditioned on the non-exercise of one or more of the rights that are
|
||||
specifically granted under this License. You may not convey a covered
|
||||
work if you are a party to an arrangement with a third party that is
|
||||
in the business of distributing software, under which you make payment
|
||||
to the third party based on the extent of your activity of conveying
|
||||
the work, and under which the third party grants, to any of the
|
||||
parties who would receive the covered work from you, a discriminatory
|
||||
patent license (a) in connection with copies of the covered work
|
||||
conveyed by you (or copies made from those copies), or (b) primarily
|
||||
for and in connection with specific products or compilations that
|
||||
contain the covered work, unless you entered into that arrangement,
|
||||
or that patent license was granted, prior to 28 March 2007.
|
||||
|
||||
Nothing in this License shall be construed as excluding or limiting
|
||||
any implied license or other defenses to infringement that may
|
||||
otherwise be available to you under applicable patent law.
|
||||
|
||||
12. No Surrender of Others' Freedom.
|
||||
|
||||
If conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot convey a
|
||||
covered work so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you may
|
||||
not convey it at all. For example, if you agree to terms that obligate you
|
||||
to collect a royalty for further conveying from those to whom you convey
|
||||
the Program, the only way you could satisfy both those terms and this
|
||||
License would be to refrain entirely from conveying the Program.
|
||||
|
||||
13. Use with the GNU Affero General Public License.
|
||||
|
||||
Notwithstanding any other provision of this License, you have
|
||||
permission to link or combine any covered work with a work licensed
|
||||
under version 3 of the GNU Affero General Public License into a single
|
||||
combined work, and to convey the resulting work. The terms of this
|
||||
License will continue to apply to the part which is the covered work,
|
||||
but the special requirements of the GNU Affero General Public License,
|
||||
section 13, concerning interaction through a network will apply to the
|
||||
combination as such.
|
||||
|
||||
14. Revised Versions of this License.
|
||||
|
||||
The Free Software Foundation may publish revised and/or new versions of
|
||||
the GNU General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the
|
||||
Program specifies that a certain numbered version of the GNU General
|
||||
Public License "or any later version" applies to it, you have the
|
||||
option of following the terms and conditions either of that numbered
|
||||
version or of any later version published by the Free Software
|
||||
Foundation. If the Program does not specify a version number of the
|
||||
GNU General Public License, you may choose any version ever published
|
||||
by the Free Software Foundation.
|
||||
|
||||
If the Program specifies that a proxy can decide which future
|
||||
versions of the GNU General Public License can be used, that proxy's
|
||||
public statement of acceptance of a version permanently authorizes you
|
||||
to choose that version for the Program.
|
||||
|
||||
Later license versions may give you additional or different
|
||||
permissions. However, no additional obligations are imposed on any
|
||||
author or copyright holder as a result of your choosing to follow a
|
||||
later version.
|
||||
|
||||
15. Disclaimer of Warranty.
|
||||
|
||||
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
|
||||
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
|
||||
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
|
||||
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
|
||||
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
|
||||
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
|
||||
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||
|
||||
16. Limitation of Liability.
|
||||
|
||||
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
|
||||
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
|
||||
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
|
||||
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
|
||||
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
|
||||
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
|
||||
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
|
||||
SUCH DAMAGES.
|
||||
|
||||
17. Interpretation of Sections 15 and 16.
|
||||
|
||||
If the disclaimer of warranty and limitation of liability provided
|
||||
above cannot be given local legal effect according to their terms,
|
||||
reviewing courts shall apply local law that most closely approximates
|
||||
an absolute waiver of all civil liability in connection with the
|
||||
Program, unless a warranty or assumption of liability accompanies a
|
||||
copy of the Program in return for a fee.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
state the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program does terminal interaction, make it output a short
|
||||
notice like this when it starts in an interactive mode:
|
||||
|
||||
<program> Copyright (C) <year> <name of author>
|
||||
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, your program's commands
|
||||
might be different; for a GUI interface, you would use an "about box".
|
||||
|
||||
You should also get your employer (if you work as a programmer) or school,
|
||||
if any, to sign a "copyright disclaimer" for the program, if necessary.
|
||||
For more information on this, and how to apply and follow the GNU GPL, see
|
||||
<https://www.gnu.org/licenses/>.
|
||||
|
||||
The GNU General Public License does not permit incorporating your program
|
||||
into proprietary programs. If your program is a subroutine library, you
|
||||
may consider it more useful to permit linking proprietary applications with
|
||||
the library. If this is what you want to do, use the GNU Lesser General
|
||||
Public License instead of this License. But first, please read
|
||||
<https://www.gnu.org/licenses/why-not-lgpl.html>.
|
||||
+165
@@ -0,0 +1,165 @@
|
||||
GNU LESSER GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
|
||||
This version of the GNU Lesser General Public License incorporates
|
||||
the terms and conditions of version 3 of the GNU General Public
|
||||
License, supplemented by the additional permissions listed below.
|
||||
|
||||
0. Additional Definitions.
|
||||
|
||||
As used herein, "this License" refers to version 3 of the GNU Lesser
|
||||
General Public License, and the "GNU GPL" refers to version 3 of the GNU
|
||||
General Public License.
|
||||
|
||||
"The Library" refers to a covered work governed by this License,
|
||||
other than an Application or a Combined Work as defined below.
|
||||
|
||||
An "Application" is any work that makes use of an interface provided
|
||||
by the Library, but which is not otherwise based on the Library.
|
||||
Defining a subclass of a class defined by the Library is deemed a mode
|
||||
of using an interface provided by the Library.
|
||||
|
||||
A "Combined Work" is a work produced by combining or linking an
|
||||
Application with the Library. The particular version of the Library
|
||||
with which the Combined Work was made is also called the "Linked
|
||||
Version".
|
||||
|
||||
The "Minimal Corresponding Source" for a Combined Work means the
|
||||
Corresponding Source for the Combined Work, excluding any source code
|
||||
for portions of the Combined Work that, considered in isolation, are
|
||||
based on the Application, and not on the Linked Version.
|
||||
|
||||
The "Corresponding Application Code" for a Combined Work means the
|
||||
object code and/or source code for the Application, including any data
|
||||
and utility programs needed for reproducing the Combined Work from the
|
||||
Application, but excluding the System Libraries of the Combined Work.
|
||||
|
||||
1. Exception to Section 3 of the GNU GPL.
|
||||
|
||||
You may convey a covered work under sections 3 and 4 of this License
|
||||
without being bound by section 3 of the GNU GPL.
|
||||
|
||||
2. Conveying Modified Versions.
|
||||
|
||||
If you modify a copy of the Library, and, in your modifications, a
|
||||
facility refers to a function or data to be supplied by an Application
|
||||
that uses the facility (other than as an argument passed when the
|
||||
facility is invoked), then you may convey a copy of the modified
|
||||
version:
|
||||
|
||||
a) under this License, provided that you make a good faith effort to
|
||||
ensure that, in the event an Application does not supply the
|
||||
function or data, the facility still operates, and performs
|
||||
whatever part of its purpose remains meaningful, or
|
||||
|
||||
b) under the GNU GPL, with none of the additional permissions of
|
||||
this License applicable to that copy.
|
||||
|
||||
3. Object Code Incorporating Material from Library Header Files.
|
||||
|
||||
The object code form of an Application may incorporate material from
|
||||
a header file that is part of the Library. You may convey such object
|
||||
code under terms of your choice, provided that, if the incorporated
|
||||
material is not limited to numerical parameters, data structure
|
||||
layouts and accessors, or small macros, inline functions and templates
|
||||
(ten or fewer lines in length), you do both of the following:
|
||||
|
||||
a) Give prominent notice with each copy of the object code that the
|
||||
Library is used in it and that the Library and its use are
|
||||
covered by this License.
|
||||
|
||||
b) Accompany the object code with a copy of the GNU GPL and this license
|
||||
document.
|
||||
|
||||
4. Combined Works.
|
||||
|
||||
You may convey a Combined Work under terms of your choice that,
|
||||
taken together, effectively do not restrict modification of the
|
||||
portions of the Library contained in the Combined Work and reverse
|
||||
engineering for debugging such modifications, if you also do each of
|
||||
the following:
|
||||
|
||||
a) Give prominent notice with each copy of the Combined Work that
|
||||
the Library is used in it and that the Library and its use are
|
||||
covered by this License.
|
||||
|
||||
b) Accompany the Combined Work with a copy of the GNU GPL and this license
|
||||
document.
|
||||
|
||||
c) For a Combined Work that displays copyright notices during
|
||||
execution, include the copyright notice for the Library among
|
||||
these notices, as well as a reference directing the user to the
|
||||
copies of the GNU GPL and this license document.
|
||||
|
||||
d) Do one of the following:
|
||||
|
||||
0) Convey the Minimal Corresponding Source under the terms of this
|
||||
License, and the Corresponding Application Code in a form
|
||||
suitable for, and under terms that permit, the user to
|
||||
recombine or relink the Application with a modified version of
|
||||
the Linked Version to produce a modified Combined Work, in the
|
||||
manner specified by section 6 of the GNU GPL for conveying
|
||||
Corresponding Source.
|
||||
|
||||
1) Use a suitable shared library mechanism for linking with the
|
||||
Library. A suitable mechanism is one that (a) uses at run time
|
||||
a copy of the Library already present on the user's computer
|
||||
system, and (b) will operate properly with a modified version
|
||||
of the Library that is interface-compatible with the Linked
|
||||
Version.
|
||||
|
||||
e) Provide Installation Information, but only if you would otherwise
|
||||
be required to provide such information under section 6 of the
|
||||
GNU GPL, and only to the extent that such information is
|
||||
necessary to install and execute a modified version of the
|
||||
Combined Work produced by recombining or relinking the
|
||||
Application with a modified version of the Linked Version. (If
|
||||
you use option 4d0, the Installation Information must accompany
|
||||
the Minimal Corresponding Source and Corresponding Application
|
||||
Code. If you use option 4d1, you must provide the Installation
|
||||
Information in the manner specified by section 6 of the GNU GPL
|
||||
for conveying Corresponding Source.)
|
||||
|
||||
5. Combined Libraries.
|
||||
|
||||
You may place library facilities that are a work based on the
|
||||
Library side by side in a single library together with other library
|
||||
facilities that are not Applications and are not covered by this
|
||||
License, and convey such a combined library under terms of your
|
||||
choice, if you do both of the following:
|
||||
|
||||
a) Accompany the combined library with a copy of the same work based
|
||||
on the Library, uncombined with any other library facilities,
|
||||
conveyed under the terms of this License.
|
||||
|
||||
b) Give prominent notice with the combined library that part of it
|
||||
is a work based on the Library, and explaining where to find the
|
||||
accompanying uncombined form of the same work.
|
||||
|
||||
6. Revised Versions of the GNU Lesser General Public License.
|
||||
|
||||
The Free Software Foundation may publish revised and/or new versions
|
||||
of the GNU Lesser General Public License from time to time. Such new
|
||||
versions will be similar in spirit to the present version, but may
|
||||
differ in detail to address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the
|
||||
Library as you received it specifies that a certain numbered version
|
||||
of the GNU Lesser General Public License "or any later version"
|
||||
applies to it, you have the option of following the terms and
|
||||
conditions either of that published version or of any later version
|
||||
published by the Free Software Foundation. If the Library as you
|
||||
received it does not specify a version number of the GNU Lesser
|
||||
General Public License, you may choose any version of the GNU Lesser
|
||||
General Public License ever published by the Free Software Foundation.
|
||||
|
||||
If the Library as you received it specifies that a proxy can decide
|
||||
whether future versions of the GNU Lesser General Public License shall
|
||||
apply, that proxy's public statement of acceptance of any version is
|
||||
permanent authorization for you to choose that version for the
|
||||
Library.
|
||||
@@ -1,458 +1,4 @@
|
||||
Copyright (c) 2025 MobileGL-Dev
|
||||
Copyright (c) 2025-2026 MobileGL-Dev
|
||||
|
||||
GNU LESSER GENERAL PUBLIC LICENSE
|
||||
Version 2.1, February 1999
|
||||
|
||||
Copyright (C) 1991, 1999 Free Software Foundation, Inc.
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
[This is the first released version of the Lesser GPL. It also counts
|
||||
as the successor of the GNU Library Public License, version 2, hence
|
||||
the version number 2.1.]
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
Licenses are intended to guarantee your freedom to share and change
|
||||
free software--to make sure the software is free for all its users.
|
||||
|
||||
This license, the Lesser General Public License, applies to some
|
||||
specially designated software packages--typically libraries--of the
|
||||
Free Software Foundation and other authors who decide to use it. You
|
||||
can use it too, but we suggest you first think carefully about whether
|
||||
this license or the ordinary General Public License is the better
|
||||
strategy to use in any particular case, based on the explanations below.
|
||||
|
||||
When we speak of free software, we are referring to freedom of use,
|
||||
not price. Our General Public Licenses are designed to make sure that
|
||||
you have the freedom to distribute copies of free software (and charge
|
||||
for this service if you wish); that you receive source code or can get
|
||||
it if you want it; that you can change the software and use pieces of
|
||||
it in new free programs; and that you are informed that you can do
|
||||
these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
distributors to deny you these rights or to ask you to surrender these
|
||||
rights. These restrictions translate to certain responsibilities for
|
||||
you if you distribute copies of the library or if you modify it.
|
||||
|
||||
For example, if you distribute copies of the library, whether gratis
|
||||
or for a fee, you must give the recipients all the rights that we gave
|
||||
you. You must make sure that they, too, receive or can get the source
|
||||
code. If you link other code with the library, you must provide
|
||||
complete object files to the recipients, so that they can relink them
|
||||
with the library after making changes to the library and recompiling
|
||||
it. And you must show them these terms so they know their rights.
|
||||
|
||||
We protect your rights with a two-step method: (1) we copyright the
|
||||
library, and (2) we offer you this license, which gives you legal
|
||||
permission to copy, distribute and/or modify the library.
|
||||
|
||||
To protect each distributor, we want to make it very clear that
|
||||
there is no warranty for the free library. Also, if the library is
|
||||
modified by someone else and passed on, the recipients should know
|
||||
that what they have is not the original version, so that the original
|
||||
author's reputation will not be affected by problems that might be
|
||||
introduced by others.
|
||||
|
||||
Finally, software patents pose a constant threat to the existence of
|
||||
any free program. We wish to make sure that a company cannot
|
||||
effectively restrict the users of a free program by obtaining a
|
||||
restrictive license from a patent holder. Therefore, we insist that
|
||||
any patent license obtained for a version of the library must be
|
||||
consistent with the full freedom of use specified in this license.
|
||||
|
||||
Most GNU software, including some libraries, is covered by the
|
||||
ordinary GNU General Public License. This license, the GNU Lesser
|
||||
General Public License, applies to certain designated libraries, and
|
||||
is quite different from the ordinary General Public License. We use
|
||||
this license for certain libraries in order to permit linking those
|
||||
libraries into non-free programs.
|
||||
|
||||
When a program is linked with a library, whether statically or using
|
||||
a shared library, the combination of the two is legally speaking a
|
||||
combined work, a derivative of the original library. The ordinary
|
||||
General Public License therefore permits such linking only if the
|
||||
entire combination fits its criteria of freedom. The Lesser General
|
||||
Public License permits more lax criteria for linking other code with
|
||||
the library.
|
||||
|
||||
We call this license the "Lesser" General Public License because it
|
||||
does Less to protect the user's freedom than the ordinary General
|
||||
Public License. It also provides other free software developers Less
|
||||
of an advantage over competing non-free programs. These disadvantages
|
||||
are the reason we use the ordinary General Public License for many
|
||||
libraries. However, the Lesser license provides advantages in certain
|
||||
special circumstances.
|
||||
|
||||
For example, on rare occasions, there may be a special need to
|
||||
encourage the widest possible use of a certain library, so that it becomes
|
||||
a de-facto standard. To achieve this, non-free programs must be
|
||||
allowed to use the library. A more frequent case is that a free
|
||||
library does the same job as widely used non-free libraries. In this
|
||||
case, there is little to gain by limiting the free library to free
|
||||
software only, so we use the Lesser General Public License.
|
||||
|
||||
In other cases, permission to use a particular library in non-free
|
||||
programs enables a greater number of people to use a large body of
|
||||
free software. For example, permission to use the GNU C Library in
|
||||
non-free programs enables many more people to use the whole GNU
|
||||
operating system, as well as its variant, the GNU/Linux operating
|
||||
system.
|
||||
|
||||
Although the Lesser General Public License is Less protective of the
|
||||
users' freedom, it does ensure that the user of a program that is
|
||||
linked with the Library has the freedom and the wherewithal to run
|
||||
that program using a modified version of the Library.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow. Pay close attention to the difference between a
|
||||
"work based on the library" and a "work that uses the library". The
|
||||
former contains code derived from the library, whereas the latter must
|
||||
be combined with the library in order to run.
|
||||
|
||||
GNU LESSER GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License Agreement applies to any software library or other
|
||||
program which contains a notice placed by the copyright holder or
|
||||
other authorized party saying it may be distributed under the terms of
|
||||
this Lesser General Public License (also called "this License").
|
||||
Each licensee is addressed as "you".
|
||||
|
||||
A "library" means a collection of software functions and/or data
|
||||
prepared so as to be conveniently linked with application programs
|
||||
(which use some of those functions and data) to form executables.
|
||||
|
||||
The "Library", below, refers to any such software library or work
|
||||
which has been distributed under these terms. A "work based on the
|
||||
Library" means either the Library or any derivative work under
|
||||
copyright law: that is to say, a work containing the Library or a
|
||||
portion of it, either verbatim or with modifications and/or translated
|
||||
straightforwardly into another language. (Hereinafter, translation is
|
||||
included without limitation in the term "modification".)
|
||||
|
||||
"Source code" for a work means the preferred form of the work for
|
||||
making modifications to it. For a library, complete source code means
|
||||
all the source code for all modules it contains, plus any associated
|
||||
interface definition files, plus the scripts used to control compilation
|
||||
and installation of the library.
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running a program using the Library is not restricted, and output from
|
||||
such a program is covered only if its contents constitute a work based
|
||||
on the Library (independent of the use of the Library in a tool for
|
||||
writing it). Whether that is true depends on what the Library does
|
||||
and what the program that uses the Library does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Library's
|
||||
complete source code as you receive it, in any medium, provided that
|
||||
you conspicuously and appropriately publish on each copy an
|
||||
appropriate copyright notice and disclaimer of warranty; keep intact
|
||||
all the notices that refer to this License and to the absence of any
|
||||
warranty; and distribute a copy of this License along with the
|
||||
Library.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy,
|
||||
and you may at your option offer warranty protection in exchange for a
|
||||
fee.
|
||||
|
||||
2. You may modify your copy or copies of the Library or any portion
|
||||
of it, thus forming a work based on the Library, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) The modified work must itself be a software library.
|
||||
|
||||
b) You must cause the files modified to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
c) You must cause the whole of the work to be licensed at no
|
||||
charge to all third parties under the terms of this License.
|
||||
|
||||
d) If a facility in the modified Library refers to a function or a
|
||||
table of data to be supplied by an application program that uses
|
||||
the facility, other than as an argument passed when the facility
|
||||
is invoked, then you must make a good faith effort to ensure that,
|
||||
in the event an application does not supply such function or
|
||||
table, the facility still operates, and performs whatever part of
|
||||
its purpose remains meaningful.
|
||||
|
||||
(For example, a function in a library to compute square roots has
|
||||
a purpose that is entirely well-defined independent of the
|
||||
application. Therefore, Subsection 2d requires that any
|
||||
application-supplied function or table used by this function must
|
||||
be optional: if the application does not supply it, the square
|
||||
root function must still compute square roots.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Library,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Library, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote
|
||||
it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Library.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Library
|
||||
with the Library (or with a work based on the Library) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may opt to apply the terms of the ordinary GNU General Public
|
||||
License instead of this License to a given copy of the Library. To do
|
||||
this, you must alter all the notices that refer to this License, so
|
||||
that they refer to the ordinary GNU General Public License, version 2,
|
||||
instead of to this License. (If a newer version than version 2 of the
|
||||
ordinary GNU General Public License has appeared, then you can specify
|
||||
that version instead if you wish.) Do not make any other change in
|
||||
these notices.
|
||||
|
||||
Once this change is made in a given copy, it is irreversible for
|
||||
that copy, so the ordinary GNU General Public License applies to all
|
||||
subsequent copies and derivative works made from that copy.
|
||||
|
||||
This option is useful when you wish to copy part of the code of
|
||||
the Library into a program that is not a library.
|
||||
|
||||
4. You may copy and distribute the Library (or a portion or
|
||||
derivative of it, under Section 2) in object code or executable form
|
||||
under the terms of Sections 1 and 2 above provided that you accompany
|
||||
it with the complete corresponding machine-readable source code, which
|
||||
must be distributed under the terms of Sections 1 and 2 above on a
|
||||
medium customarily used for software interchange.
|
||||
|
||||
If distribution of object code is made by offering access to copy
|
||||
from a designated place, then offering equivalent access to copy the
|
||||
source code from the same place satisfies the requirement to
|
||||
distribute the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
5. A program that contains no derivative of any portion of the
|
||||
Library, but is designed to work with the Library by being compiled or
|
||||
linked with it, is called a "work that uses the Library". Such a
|
||||
work, in isolation, is not a derivative work of the Library, and
|
||||
therefore falls outside the scope of this License.
|
||||
|
||||
However, linking a "work that uses the Library" with the Library
|
||||
creates an executable that is a derivative of the Library (because it
|
||||
contains portions of the Library), rather than a "work that uses the
|
||||
library". The executable is therefore covered by this License.
|
||||
Section 6 states terms for distribution of such executables.
|
||||
|
||||
When a "work that uses the Library" uses material from a header file
|
||||
that is part of the Library, the object code for the work may be a
|
||||
derivative work of the Library even though the source code is not.
|
||||
Whether this is true is especially significant if the work can be
|
||||
linked without the Library, or if the work is itself a library. The
|
||||
threshold for this to be true is not precisely defined by law.
|
||||
|
||||
If such an object file uses only numerical parameters, data
|
||||
structure layouts and accessors, and small macros and small inline
|
||||
functions (ten lines or less in length), then the use of the object
|
||||
file is unrestricted, regardless of whether it is legally a derivative
|
||||
work. (Executables containing this object code plus portions of the
|
||||
Library will still fall under Section 6.)
|
||||
|
||||
Otherwise, if the work is a derivative of the Library, you may
|
||||
distribute the object code for the work under the terms of Section 6.
|
||||
Any executables containing that work also fall under Section 6,
|
||||
whether or not they are linked directly with the Library itself.
|
||||
|
||||
6. As an exception to the Sections above, you may also combine or
|
||||
link a "work that uses the Library" with the Library to produce a
|
||||
work containing portions of the Library, and distribute that work
|
||||
under terms of your choice, provided that the terms permit
|
||||
modification of the work for the customer's own use and reverse
|
||||
engineering for debugging such modifications.
|
||||
|
||||
You must give prominent notice with each copy of the work that the
|
||||
Library is used in it and that the Library and its use are covered by
|
||||
this License. You must supply a copy of this License. If the work
|
||||
during execution displays copyright notices, you must include the
|
||||
copyright notice for the Library among them, as well as a reference
|
||||
directing the user to the copy of this License. Also, you must do one
|
||||
of these things:
|
||||
|
||||
a) Accompany the work with the complete corresponding
|
||||
machine-readable source code for the Library including whatever
|
||||
changes were used in the work (which must be distributed under
|
||||
Sections 1 and 2 above); and, if the work is an executable linked
|
||||
with the Library, with the complete machine-readable "work that
|
||||
uses the Library", as object code and/or source code, so that the
|
||||
user can modify the Library and then relink to produce a modified
|
||||
executable containing the modified Library. (It is understood
|
||||
that the user who changes the contents of definitions files in the
|
||||
Library will not necessarily be able to recompile the application
|
||||
to use the modified definitions.)
|
||||
|
||||
b) Use a suitable shared library mechanism for linking with the
|
||||
Library. A suitable mechanism is one that (1) uses at run time a
|
||||
copy of the library already present on the user's computer system,
|
||||
rather than copying library functions into the executable, and (2)
|
||||
will operate properly with a modified version of the library, if
|
||||
the user installs one, as long as the modified version is
|
||||
interface-compatible with the version that the work was made with.
|
||||
|
||||
c) Accompany the work with a written offer, valid for at
|
||||
least three years, to give the same user the materials
|
||||
specified in Subsection 6a, above, for a charge no more
|
||||
than the cost of performing this distribution.
|
||||
|
||||
d) If distribution of the work is made by offering access to copy
|
||||
from a designated place, offer equivalent access to copy the above
|
||||
specified materials from the same place.
|
||||
|
||||
e) Verify that the user has already received a copy of these
|
||||
materials or that you have already sent this user a copy.
|
||||
|
||||
For an executable, the required form of the "work that uses the
|
||||
Library" must include any data and utility programs needed for
|
||||
reproducing the executable from it. However, as a special exception,
|
||||
the materials to be distributed need not include anything that is
|
||||
normally distributed (in either source or binary form) with the major
|
||||
components (compiler, kernel, and so on) of the operating system on
|
||||
which the executable runs, unless that component itself accompanies
|
||||
the executable.
|
||||
|
||||
It may happen that this requirement contradicts the license
|
||||
restrictions of other proprietary libraries that do not normally
|
||||
accompany the operating system. Such a contradiction means you cannot
|
||||
use both them and the Library together in an executable that you
|
||||
distribute.
|
||||
|
||||
7. You may place library facilities that are a work based on the
|
||||
Library side-by-side in a single library together with other library
|
||||
facilities not covered by this License, and distribute such a combined
|
||||
library, provided that the separate distribution of the work based on
|
||||
the Library and of the other library facilities is otherwise
|
||||
permitted, and provided that you do these two things:
|
||||
|
||||
a) Accompany the combined library with a copy of the same work
|
||||
based on the Library, uncombined with any other library
|
||||
facilities. This must be distributed under the terms of the
|
||||
Sections above.
|
||||
|
||||
b) Give prominent notice with the combined library of the fact
|
||||
that part of it is a work based on the Library, and explaining
|
||||
where to find the accompanying uncombined form of the same work.
|
||||
|
||||
8. You may not copy, modify, sublicense, link with, or distribute
|
||||
the Library except as expressly provided under this License. Any
|
||||
attempt otherwise to copy, modify, sublicense, link with, or
|
||||
distribute the Library is void, and will automatically terminate your
|
||||
rights under this License. However, parties who have received copies,
|
||||
or rights, from you under this License will not have their licenses
|
||||
terminated so long as such parties remain in full compliance.
|
||||
|
||||
9. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Library or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Library (or any work based on the
|
||||
Library), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Library or works based on it.
|
||||
|
||||
10. Each time you redistribute the Library (or any work based on the
|
||||
Library), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute, link with or modify the Library
|
||||
subject to these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties with
|
||||
this License.
|
||||
|
||||
11. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Library at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Library by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Library.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under any
|
||||
particular circumstance, the balance of the section is intended to apply,
|
||||
and the section as a whole is intended to apply in other circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
12. If the distribution and/or use of the Library is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Library under this License may add
|
||||
an explicit geographical distribution limitation excluding those countries,
|
||||
so that distribution is permitted only in or among countries not thus
|
||||
excluded. In such case, this License incorporates the limitation as if
|
||||
written in the body of this License.
|
||||
|
||||
13. The Free Software Foundation may publish revised and/or new
|
||||
versions of the Lesser General Public License from time to time.
|
||||
Such new versions will be similar in spirit to the present version,
|
||||
but may differ in detail to address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Library
|
||||
specifies a version number of this License which applies to it and
|
||||
"any later version", you have the option of following the terms and
|
||||
conditions either of that version or of any later version published by
|
||||
the Free Software Foundation. If the Library does not specify a
|
||||
license version number, you may choose any version ever published by
|
||||
the Free Software Foundation.
|
||||
|
||||
14. If you wish to incorporate parts of the Library into other free
|
||||
programs whose distribution conditions are incompatible with these,
|
||||
write to the author to ask for permission. For software which is
|
||||
copyrighted by the Free Software Foundation, write to the Free
|
||||
Software Foundation; we sometimes make exceptions for this. Our
|
||||
decision will be guided by the two goals of preserving the free status
|
||||
of all derivatives of our free software and of promoting the sharing
|
||||
and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
|
||||
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
|
||||
EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
|
||||
OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
|
||||
KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
|
||||
LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
|
||||
THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||
|
||||
16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
|
||||
WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
|
||||
AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
|
||||
FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
|
||||
CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
|
||||
LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
|
||||
RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
|
||||
FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
|
||||
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
||||
DAMAGES.
|
||||
This project is licensed under the GNU Lesser General Public License v3.0.
|
||||
See COPYING and COPYING.LESSER for the full text of the LGPLv3 license.
|
||||
|
||||
-185
@@ -1,185 +0,0 @@
|
||||
//
|
||||
// Created by BZLZHH on 2025/3/15.
|
||||
//
|
||||
|
||||
#ifndef MOBILEGL_CONSTANTS_H
|
||||
#define MOBILEGL_CONSTANTS_H
|
||||
|
||||
#include <array>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include <GL/gl.h>
|
||||
#include <ankerl/unordered_dense.h>
|
||||
|
||||
#ifdef __ANDROID__
|
||||
#define __ANDROID_API__ 26
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
#define MG_EXPORT extern "C" __declspec(dllexport)
|
||||
#else
|
||||
#define MG_EXPORT extern "C" __attribute__((visibility("default")))
|
||||
#endif
|
||||
|
||||
namespace ankerl {
|
||||
template <typename K, typename V>
|
||||
using unordered_map = ankerl::unordered_dense::map<K, V>;
|
||||
|
||||
template <typename T>
|
||||
using unordered_set = ankerl::unordered_dense::set<T>;
|
||||
}
|
||||
|
||||
namespace MG_Constants {
|
||||
namespace Common {
|
||||
inline const int LOG_LEVEL_DEBUG = 0x0010;
|
||||
inline const int LOG_LEVEL_WARN = 0x0011;
|
||||
inline const int LOG_LEVEL_ERROR = 0x0012;
|
||||
inline const int LOG_LEVEL_INFO = 0x0013;
|
||||
inline const int LOG_LEVEL_FATAL = 0x0014;
|
||||
}
|
||||
|
||||
namespace Blend {
|
||||
static const ankerl::unordered_set<GLenum> VALID_FACTORS = {
|
||||
GL_ZERO, GL_ONE, GL_SRC_COLOR, GL_ONE_MINUS_SRC_COLOR,
|
||||
GL_DST_COLOR, GL_ONE_MINUS_DST_COLOR, GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA,
|
||||
GL_DST_ALPHA, GL_ONE_MINUS_DST_ALPHA, GL_CONSTANT_COLOR, GL_ONE_MINUS_CONSTANT_COLOR,
|
||||
GL_CONSTANT_ALPHA, GL_ONE_MINUS_CONSTANT_ALPHA, GL_SRC_ALPHA_SATURATE
|
||||
}; // OpenGL 3
|
||||
}
|
||||
|
||||
namespace Depth {
|
||||
static const ankerl::unordered_set<GLenum> VALID_FUNCS = {
|
||||
GL_NEVER, GL_LESS, GL_EQUAL, GL_LEQUAL, GL_GREATER, GL_NOTEQUAL, GL_GEQUAL, GL_ALWAYS
|
||||
}; // OpenGL 3
|
||||
}
|
||||
|
||||
namespace CommonState {
|
||||
static const ankerl::unordered_set<GLenum> VALID_CAPS = {
|
||||
GL_BLEND, GL_DEPTH_TEST, GL_STENCIL_TEST, GL_SCISSOR_TEST, GL_CULL_FACE,
|
||||
GL_POLYGON_OFFSET_FILL, GL_SAMPLE_ALPHA_TO_COVERAGE, GL_SAMPLE_COVERAGE
|
||||
}; // OpenGL 3
|
||||
}
|
||||
|
||||
namespace Framebuffer {
|
||||
static const ankerl::unordered_set<GLenum> VALID_ATTACHMENTS = {
|
||||
GL_COLOR_ATTACHMENT0, GL_DEPTH_ATTACHMENT,
|
||||
GL_STENCIL_ATTACHMENT, GL_DEPTH_STENCIL_ATTACHMENT
|
||||
}; // OpenGL 3
|
||||
|
||||
static const ankerl::unordered_set<GLenum> VALID_TARGETS = {
|
||||
GL_FRAMEBUFFER, GL_DRAW_FRAMEBUFFER, GL_READ_FRAMEBUFFER
|
||||
}; // OpenGL 3
|
||||
|
||||
static const ankerl::unordered_set<GLenum> VALID_ACCESS = {
|
||||
GL_READ_ONLY, GL_WRITE_ONLY, GL_READ_WRITE
|
||||
}; // OpenGL 3
|
||||
}
|
||||
|
||||
namespace Buffer {
|
||||
static const ankerl::unordered_set<GLenum> VALID_PARAM_NAMES = {
|
||||
GL_BUFFER_ACCESS, GL_BUFFER_MAPPED, GL_BUFFER_SIZE, GL_BUFFER_USAGE
|
||||
}; // OpenGL 3
|
||||
|
||||
static const ankerl::unordered_set<GLenum> VALID_TARGETS = {
|
||||
GL_ARRAY_BUFFER, GL_COPY_READ_BUFFER, GL_COPY_WRITE_BUFFER, GL_ELEMENT_ARRAY_BUFFER,
|
||||
GL_PIXEL_PACK_BUFFER, GL_PIXEL_UNPACK_BUFFER, GL_TEXTURE_BUFFER,
|
||||
GL_TRANSFORM_FEEDBACK_BUFFER, GL_UNIFORM_BUFFER
|
||||
}; // OpenGL 3
|
||||
|
||||
static const ankerl::unordered_set<GLenum> VALID_ACCESS = {
|
||||
GL_READ_ONLY, GL_WRITE_ONLY, GL_READ_WRITE
|
||||
}; // OpenGL 3
|
||||
}
|
||||
|
||||
namespace PixelStore {
|
||||
static const ankerl::unordered_map<GLenum, GLint> DEFAULT_VALUES_MAP = {
|
||||
{GL_PACK_SWAP_BYTES, GL_FALSE},
|
||||
{GL_PACK_LSB_FIRST, GL_FALSE},
|
||||
{GL_PACK_ROW_LENGTH, 0},
|
||||
{GL_PACK_IMAGE_HEIGHT, 0},
|
||||
{GL_PACK_SKIP_ROWS, 0},
|
||||
{GL_PACK_SKIP_PIXELS, 0},
|
||||
{GL_PACK_SKIP_IMAGES, 0},
|
||||
{GL_PACK_ALIGNMENT, 4},
|
||||
{GL_UNPACK_SWAP_BYTES, GL_FALSE},
|
||||
{GL_UNPACK_LSB_FIRST, GL_FALSE},
|
||||
{GL_UNPACK_ROW_LENGTH, 0},
|
||||
{GL_UNPACK_IMAGE_HEIGHT, 0},
|
||||
{GL_UNPACK_SKIP_ROWS, 0},
|
||||
{GL_UNPACK_SKIP_PIXELS,0},
|
||||
{GL_UNPACK_SKIP_IMAGES,0},
|
||||
{GL_UNPACK_ALIGNMENT, 4}
|
||||
}; // OpenGL 3
|
||||
|
||||
static const ankerl::unordered_set<GLenum> VALID_PARAM_NAMES = {
|
||||
GL_PACK_SWAP_BYTES, GL_PACK_LSB_FIRST, GL_PACK_ROW_LENGTH, GL_PACK_IMAGE_HEIGHT,
|
||||
GL_PACK_SKIP_ROWS, GL_PACK_SKIP_PIXELS, GL_PACK_SKIP_IMAGES, GL_PACK_ALIGNMENT,
|
||||
GL_UNPACK_SWAP_BYTES, GL_UNPACK_LSB_FIRST, GL_UNPACK_ROW_LENGTH,
|
||||
GL_UNPACK_IMAGE_HEIGHT,
|
||||
GL_UNPACK_SKIP_ROWS, GL_UNPACK_SKIP_PIXELS, GL_UNPACK_SKIP_IMAGES,
|
||||
GL_UNPACK_ALIGNMENT
|
||||
}; // OpenGL 3
|
||||
}
|
||||
|
||||
namespace Texture {
|
||||
inline const GLuint MAX_TEXTURE_UNITS = 80;
|
||||
const GLsizei MAX_TEXTURE_SIZE = 32768;
|
||||
const GLsizei MAX_ARRAY_LAYERS = 256;
|
||||
inline const ankerl::unordered_set<GLenum> VALID_TARGETS = {
|
||||
GL_TEXTURE_2D, GL_PROXY_TEXTURE_2D, GL_TEXTURE_1D_ARRAY, GL_PROXY_TEXTURE_1D_ARRAY,
|
||||
GL_TEXTURE_RECTANGLE, GL_PROXY_TEXTURE_RECTANGLE, GL_TEXTURE_CUBE_MAP_POSITIVE_X,
|
||||
GL_TEXTURE_CUBE_MAP_NEGATIVE_X, GL_TEXTURE_CUBE_MAP_POSITIVE_Y, GL_TEXTURE_CUBE_MAP_NEGATIVE_Y,
|
||||
GL_TEXTURE_CUBE_MAP_POSITIVE_Z, GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, GL_PROXY_TEXTURE_CUBE_MAP
|
||||
}; // OpenGL 3
|
||||
|
||||
inline const ankerl::unordered_set<GLenum> VALID_FORMATS = {
|
||||
GL_RED, GL_RG, GL_RGB, GL_BGR, GL_RGBA, GL_BGRA, GL_DEPTH_COMPONENT, GL_DEPTH_STENCIL
|
||||
}; // OpenGL 3
|
||||
|
||||
inline const ankerl::unordered_set<GLenum> VALID_INTERNAL_FORMATS = {
|
||||
GL_RED, GL_RG, GL_RGB, GL_BGR, GL_RGBA, GL_BGRA, GL_DEPTH_COMPONENT, GL_DEPTH_STENCIL,
|
||||
GL_RGBA32F, GL_RGBA32I, GL_RGBA32UI, GL_RGBA16, GL_RGBA16F, GL_RGBA16I,
|
||||
GL_RGBA16UI, GL_RGBA8, GL_RGBA8UI, GL_SRGB8_ALPHA8, GL_RGB10_A2, GL_RGB10_A2UI,
|
||||
GL_R11F_G11F_B10F, GL_RG32F, GL_RG32I, GL_RG32UI, GL_RG16, GL_RG16F, GL_RGB16I,
|
||||
GL_RGB16UI, GL_RG8, GL_RG8I, GL_RG8UI, GL_R32F, GL_R32I, GL_R32UI, GL_R16F,
|
||||
GL_R16I, GL_R16UI, GL_R8, GL_R8I, GL_R8UI, GL_RGBA16_SNORM, GL_RGBA8_SNORM,
|
||||
GL_RGB32F, GL_RGB32I, GL_RGB32UI, GL_RGB16_SNORM, GL_RGB16F, GL_RGB16I, GL_RGB16UI,
|
||||
GL_RGB16, GL_RGB8_SNORM, GL_RGB8, GL_RGB8I, GL_RGB8UI, GL_SRGB8, GL_RGB9_E5,
|
||||
GL_RG16_SNORM, GL_RG8_SNORM, GL_COMPRESSED_RG_RGTC2, GL_COMPRESSED_SIGNED_RG_RGTC2,
|
||||
GL_R16_SNORM, GL_R8_SNORM, GL_COMPRESSED_RED_RGTC1, GL_COMPRESSED_SIGNED_RED_RGTC1,
|
||||
GL_DEPTH_COMPONENT32F, GL_DEPTH_COMPONENT32, GL_DEPTH_COMPONENT24, GL_DEPTH_COMPONENT16,
|
||||
GL_DEPTH32F_STENCIL8, GL_DEPTH24_STENCIL8
|
||||
}; // OpenGL 3
|
||||
|
||||
inline const ankerl::unordered_set<GLenum> VALID_TYPES = {
|
||||
GL_UNSIGNED_BYTE, GL_BYTE, GL_UNSIGNED_SHORT, GL_SHORT, GL_UNSIGNED_INT, GL_INT,
|
||||
GL_FLOAT, GL_UNSIGNED_BYTE_3_3_2, GL_UNSIGNED_BYTE_2_3_3_REV, GL_UNSIGNED_SHORT_5_6_5,
|
||||
GL_UNSIGNED_SHORT_5_6_5_REV, GL_UNSIGNED_SHORT_4_4_4_4, GL_UNSIGNED_SHORT_4_4_4_4_REV,
|
||||
GL_UNSIGNED_SHORT_5_5_5_1, GL_UNSIGNED_SHORT_1_5_5_5_REV, GL_UNSIGNED_INT_8_8_8_8,
|
||||
GL_UNSIGNED_INT_8_8_8_8_REV, GL_UNSIGNED_INT_10_10_10_2, GL_UNSIGNED_INT_2_10_10_10_REV
|
||||
}; // OpenGL 3
|
||||
|
||||
inline const ankerl::unordered_set<GLenum> VALID_TEXTURE_PARAM_NAMES = {
|
||||
GL_TEXTURE_BASE_LEVEL, GL_TEXTURE_COMPARE_FUNC, GL_TEXTURE_COMPARE_MODE, GL_TEXTURE_MIN_FILTER,
|
||||
GL_TEXTURE_MAG_FILTER, GL_TEXTURE_MAX_LEVEL, GL_TEXTURE_SWIZZLE_R, GL_TEXTURE_SWIZZLE_G,
|
||||
GL_TEXTURE_SWIZZLE_B, GL_TEXTURE_SWIZZLE_A, GL_TEXTURE_SWIZZLE_RGBA, GL_TEXTURE_WRAP_S,
|
||||
GL_TEXTURE_WRAP_T, GL_TEXTURE_WRAP_R, GL_TEXTURE_LOD_BIAS, GL_TEXTURE_MIN_LOD, GL_TEXTURE_MAX_LOD, GL_TEXTURE_BORDER_COLOR
|
||||
}; // OpenGL 3
|
||||
|
||||
inline const ankerl::unordered_set<GLenum> VALID_QUERY_LEVEL_PROPERTY_PARAM_NAMES = {
|
||||
GL_TEXTURE_WIDTH, GL_TEXTURE_HEIGHT, GL_TEXTURE_DEPTH, GL_TEXTURE_INTERNAL_FORMAT,
|
||||
GL_TEXTURE_RED_SIZE, GL_TEXTURE_GREEN_SIZE, GL_TEXTURE_BLUE_SIZE, GL_TEXTURE_ALPHA_SIZE,
|
||||
GL_TEXTURE_DEPTH_SIZE, GL_TEXTURE_COMPRESSED, GL_TEXTURE_COMPRESSED_IMAGE_SIZE
|
||||
}; // OpenGL 3
|
||||
}
|
||||
|
||||
namespace Backend {
|
||||
#define BACKEND_VULKAN 0x0015
|
||||
#define BACKEND_METAL 0x0016
|
||||
#define BACKEND_GLES 0x0017
|
||||
}
|
||||
|
||||
inline const char* RenderName = "MobileGL";
|
||||
}
|
||||
|
||||
#endif //MOBILEGL_CONSTANTS_H
|
||||
-40
@@ -1,40 +0,0 @@
|
||||
//
|
||||
// Created by BZLZHH on 2025/3/15.
|
||||
//
|
||||
|
||||
#ifndef MOBILEGL_GLOBAL_H
|
||||
#define MOBILEGL_GLOBAL_H
|
||||
|
||||
#include "Includes.h"
|
||||
|
||||
namespace MG_Global {
|
||||
namespace MG {
|
||||
inline const int VersionMajor = 1;
|
||||
inline const int VersionMinor = 0;
|
||||
inline const int VersionRevision = 0;
|
||||
inline const int VersionPatch = 0;
|
||||
inline const std::string VersionSuffix = "-ShittilyDraw";
|
||||
}
|
||||
|
||||
namespace Backend {
|
||||
// BACKEND_TYPE is defined in Includes.h
|
||||
}
|
||||
|
||||
namespace GL {
|
||||
inline const int GLVersionMajor = 3;
|
||||
inline const int GLVersionMinor = 2;
|
||||
inline const int GLVersionRevision = 0;
|
||||
}
|
||||
|
||||
namespace Common {
|
||||
inline constexpr int LogLevel = MG_Constants::Common::LOG_LEVEL_INFO;
|
||||
|
||||
#ifdef __ANDROID__
|
||||
inline const char* LOG_FILE_PATH = "/sdcard/MG/latest.log";
|
||||
#else
|
||||
inline const char* LOG_FILE_PATH = nullptr;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
#endif //MOBILEGL_GLOBAL_H
|
||||
-136
@@ -1,136 +0,0 @@
|
||||
//
|
||||
// Created by BZLZHH on 2025/3/15.
|
||||
//
|
||||
|
||||
#include "Constants.h"
|
||||
#define BACKEND_TYPE BACKEND_GLES
|
||||
#include "Global.h"
|
||||
#ifndef MOBILEGL_GLES_LOADER_H
|
||||
#include "MG_GL/BackendLoader/GLES/Loader.h"
|
||||
#endif
|
||||
#ifndef MOBILEGL_GL_FRAMEBUFFER_H
|
||||
#include "MG_GL/Implementations/GL/Framebuffer/GL_Framebuffer.h"
|
||||
#endif
|
||||
#ifndef MOBILEGL_GL_GETTER_H
|
||||
#include "MG_GL/Implementations/GL/Getter/GL_Getter.h"
|
||||
#endif
|
||||
#ifndef MOBILEGL_BACKENDINFO_H
|
||||
#include "MG_GL/Implementations/GL/Getter/BackendInfo.h"
|
||||
#endif
|
||||
#ifndef MOBILEGL_GL_BUFFER_H
|
||||
#include "MG_GL/Implementations/GL/Buffer/GL_Buffer.h"
|
||||
#endif
|
||||
#ifndef MOBILEGL_GL_DRAWING_H
|
||||
#include "MG_GL/Implementations/GL/Drawing/GL_Drawing.h"
|
||||
#endif
|
||||
#ifndef MOBILEGL_GL_PROGRAM_H
|
||||
#include "MG_GL/Implementations/GL/Program/GL_Program.h"
|
||||
#endif
|
||||
#ifndef MOBILEGL_GL_TEXTURE_H
|
||||
#include "MG_GL/Implementations/GL/Texture/GL_Texture.h"
|
||||
#endif
|
||||
#ifndef MOBILEGL_GL_VERTEXARRAY_H
|
||||
#include "MG_GL/Implementations/GL/VertexArray/GL_VertexArray.h"
|
||||
#endif
|
||||
#ifndef MOBILEGL_GLSTATE_H
|
||||
#include "MG_GL/State/Core/GLState.h"
|
||||
#endif
|
||||
#ifndef MOBILEGL_COMMONSTATE_H
|
||||
#include "MG_GL/State/Common/CommonState.h"
|
||||
#endif
|
||||
#ifndef MOBILEGL_TEXTURESTATE_H
|
||||
#include "MG_GL/State/Texture/TextureState.h"
|
||||
#endif
|
||||
#ifndef MOBILEGL_VERTEXARRAYSTATE_H
|
||||
#include "MG_GL/State/VertexArray/VertexArrayState.h"
|
||||
#endif
|
||||
#ifndef MOBILEGL_BUFFERSTATE_H
|
||||
#include "MG_GL/State/Buffer/BufferState.h"
|
||||
#endif
|
||||
#ifndef MOBILEGL_SHADEROBJECT_H
|
||||
#include "MG_GL/State/Program/ShaderObject.h"
|
||||
#endif
|
||||
#ifndef MOBILEGL_PROGRAMSTATE_H
|
||||
#include "MG_GL/State/Program/ProgramState.h"
|
||||
#endif
|
||||
#ifndef MOBILEGL_FRAMEBUFFERSTATE_H
|
||||
#include "MG_GL/State/Framebuffer/FramebufferState.h"
|
||||
#endif
|
||||
#ifndef MOBILEGL_LOOKUP_H
|
||||
#include "MG_GL/Implementations/GLX/LookUp/LookUp.h"
|
||||
#endif
|
||||
#ifndef MOBILEGL_DEBUG_H
|
||||
#include "MG_UTIL/Debug/Debug.h"
|
||||
#endif
|
||||
#ifndef MOBILEGL_GLSLTOOL_H
|
||||
#include "MG_UTIL/Program/GLSLTool.h"
|
||||
#endif
|
||||
#ifndef MOBILEGL_PROGRAM_DEBUGTOOL_H
|
||||
#include "MG_UTIL/Program/DebugTool.h"
|
||||
#endif
|
||||
#ifndef MOBILEGL_GL_COMMON_H
|
||||
#include "MG_GL/Implementations/GL/Common/GL_Common.h"
|
||||
#endif
|
||||
#ifndef MOBILEGL_EGL_VK_EMU_H
|
||||
#include "MG_GL/Implementations/EGL/VK/EGL_EMU.h"
|
||||
#endif
|
||||
#ifndef MOBILEGL_EGL_GLES_EGL_WRAP_H
|
||||
#include "MG_GL/Implementations/EGL/GLES/EGL_WRAP.h"
|
||||
#endif
|
||||
#ifndef MOBILEGL_TESTDRAWING_H
|
||||
#include "MG_RHI/GLES/Test/TestDrawing.h"
|
||||
#endif
|
||||
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
#include <cstdio>
|
||||
#include <ctime>
|
||||
#include <chrono>
|
||||
#include <thread>
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include <stdexcept>
|
||||
#include <atomic>
|
||||
#include <regex>
|
||||
#include <strstream>
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <random>
|
||||
#include <optional>
|
||||
#include <unordered_map>
|
||||
#include <queue>
|
||||
#include <format>
|
||||
#include <glslang/Public/ShaderLang.h>
|
||||
#include <glslang/Include/Types.h>
|
||||
#include <glslang/Public/ShaderLang.h>
|
||||
#include <spirv_cross/spirv_cross_c.h>
|
||||
#include <glslang/SPIRV/GlslangToSpv.h>
|
||||
#include <glm/gtc/matrix_transform.hpp>
|
||||
#include <glm/glm.hpp>
|
||||
#include <ankerl/unordered_dense.h>
|
||||
#include <GLES3/gl32.h>
|
||||
|
||||
#include "MG_Include/UncertainBool.hpp"
|
||||
|
||||
#ifndef _WIN32
|
||||
#include <dlfcn.h>
|
||||
#include <unistd.h>
|
||||
#include <vulkan/vulkan.h>
|
||||
#endif
|
||||
|
||||
#ifdef __ANDROID__
|
||||
#include <android/log.h>
|
||||
#include <pthread.h>
|
||||
#include <vulkan/vulkan_android.h>
|
||||
#include <android/native_window.h>
|
||||
#elif _WIN32
|
||||
#include <windows.h>
|
||||
#include <processthreadsapi.h>
|
||||
#else
|
||||
#include <pthread.h>
|
||||
#endif
|
||||
|
||||
#include <EGL/egl.h>
|
||||
#include <GL/gl.h>
|
||||
#include <GL/glext.h>
|
||||
-17
@@ -1,17 +0,0 @@
|
||||
//
|
||||
// Created by BZLZHH on 2025/3/15.
|
||||
//
|
||||
|
||||
#include "Includes.h"
|
||||
|
||||
__attribute__((constructor)) void MG_Initialize() {
|
||||
MG_Util::Debug::LogInit();
|
||||
MG_Util::Debug::LogI("MobileGL Initializing...");
|
||||
MG_State::Init();
|
||||
MG_GL::BackendLoader::Init();
|
||||
}
|
||||
|
||||
__attribute__((destructor)) void MG_Destroy() {
|
||||
MG_Util::Debug::LogI("MobileGL Exiting...");
|
||||
MG_State::Destroy();
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,179 +0,0 @@
|
||||
//
|
||||
// Created by BZLZHH on 2025/4/26.
|
||||
//
|
||||
|
||||
#include "EGL_WRAP.h"
|
||||
|
||||
#if BACKEND_TYPE == BACKEND_GLES
|
||||
|
||||
MG_EXPORT EGLint eglGetError(void) {
|
||||
LOAD_EGL(eglGetError)
|
||||
return egl_eglGetError();
|
||||
}
|
||||
|
||||
MG_EXPORT EGLDisplay eglGetDisplay(EGLNativeDisplayType display_id) {
|
||||
LOAD_EGL(eglGetDisplay)
|
||||
return egl_eglGetDisplay(display_id);
|
||||
}
|
||||
|
||||
MG_EXPORT EGLBoolean eglInitialize(EGLDisplay dpy, EGLint *major, EGLint *minor) {
|
||||
LOAD_EGL(eglInitialize)
|
||||
return egl_eglInitialize(dpy, major, minor);
|
||||
}
|
||||
|
||||
MG_EXPORT EGLBoolean eglTerminate(EGLDisplay dpy) {
|
||||
LOAD_EGL(eglTerminate)
|
||||
return egl_eglTerminate(dpy);
|
||||
}
|
||||
|
||||
MG_EXPORT const char *eglQueryString(EGLDisplay dpy, EGLint name) {
|
||||
LOAD_EGL(eglQueryString)
|
||||
return egl_eglQueryString(dpy, name);
|
||||
}
|
||||
|
||||
MG_EXPORT EGLBoolean eglGetConfigs(EGLDisplay dpy, EGLConfig *configs, EGLint config_size, EGLint *num_config) {
|
||||
LOAD_EGL(eglGetConfigs)
|
||||
return egl_eglGetConfigs(dpy, configs, config_size, num_config);
|
||||
}
|
||||
|
||||
MG_EXPORT EGLBoolean eglChooseConfig(EGLDisplay dpy, const EGLint *attrib_list, EGLConfig *configs, EGLint config_size, EGLint *num_config) {
|
||||
LOAD_EGL(eglChooseConfig)
|
||||
return egl_eglChooseConfig(dpy, attrib_list, configs, config_size, num_config);
|
||||
}
|
||||
|
||||
MG_EXPORT EGLBoolean eglGetConfigAttrib(EGLDisplay dpy, EGLConfig config, EGLint attribute, EGLint *value) {
|
||||
LOAD_EGL(eglGetConfigAttrib)
|
||||
return egl_eglGetConfigAttrib(dpy, config, attribute, value);
|
||||
}
|
||||
|
||||
MG_EXPORT EGLSurface eglCreateWindowSurface(EGLDisplay dpy, EGLConfig config, EGLNativeWindowType win, const EGLint *attrib_list) {
|
||||
LOAD_EGL(eglCreateWindowSurface)
|
||||
return egl_eglCreateWindowSurface(dpy, config, win, attrib_list);
|
||||
}
|
||||
|
||||
MG_EXPORT EGLSurface eglCreatePbufferSurface(EGLDisplay dpy, EGLConfig config, const EGLint *attrib_list) {
|
||||
LOAD_EGL(eglCreatePbufferSurface)
|
||||
return egl_eglCreatePbufferSurface(dpy, config, attrib_list);
|
||||
}
|
||||
|
||||
MG_EXPORT EGLSurface eglCreatePixmapSurface(EGLDisplay dpy, EGLConfig config, EGLNativePixmapType pixmap, const EGLint *attrib_list) {
|
||||
LOAD_EGL(eglCreatePixmapSurface)
|
||||
return egl_eglCreatePixmapSurface(dpy, config, pixmap, attrib_list);
|
||||
}
|
||||
|
||||
MG_EXPORT EGLBoolean eglDestroySurface(EGLDisplay dpy, EGLSurface surface) {
|
||||
LOAD_EGL(eglDestroySurface)
|
||||
return egl_eglDestroySurface(dpy, surface);
|
||||
}
|
||||
|
||||
MG_EXPORT EGLBoolean eglQuerySurface(EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint *value) {
|
||||
LOAD_EGL(eglQuerySurface)
|
||||
return egl_eglQuerySurface(dpy, surface, attribute, value);
|
||||
}
|
||||
|
||||
MG_EXPORT EGLBoolean eglBindAPI(EGLenum api) {
|
||||
LOAD_EGL(eglBindAPI)
|
||||
return egl_eglBindAPI(api);
|
||||
}
|
||||
|
||||
MG_EXPORT EGLenum eglQueryAPI(void) {
|
||||
LOAD_EGL(eglQueryAPI)
|
||||
return egl_eglQueryAPI();
|
||||
}
|
||||
|
||||
MG_EXPORT EGLBoolean eglWaitClient(void) {
|
||||
LOAD_EGL(eglWaitClient)
|
||||
return egl_eglWaitClient();
|
||||
}
|
||||
|
||||
MG_EXPORT EGLBoolean eglReleaseThread(void) {
|
||||
LOAD_EGL(eglReleaseThread)
|
||||
return egl_eglReleaseThread();
|
||||
}
|
||||
|
||||
MG_EXPORT EGLSurface eglCreatePbufferFromClientBuffer(EGLDisplay dpy, EGLenum buftype, EGLClientBuffer buffer, EGLConfig config, const EGLint *attrib_list) {
|
||||
LOAD_EGL(eglCreatePbufferFromClientBuffer)
|
||||
return egl_eglCreatePbufferFromClientBuffer(dpy, buftype, buffer, config, attrib_list);
|
||||
}
|
||||
|
||||
MG_EXPORT EGLBoolean eglSurfaceAttrib(EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint value) {
|
||||
LOAD_EGL(eglSurfaceAttrib)
|
||||
return egl_eglSurfaceAttrib(dpy, surface, attribute, value);
|
||||
}
|
||||
|
||||
MG_EXPORT EGLBoolean eglBindTexImage(EGLDisplay dpy, EGLSurface surface, EGLint buffer) {
|
||||
LOAD_EGL(eglBindTexImage)
|
||||
return egl_eglBindTexImage(dpy, surface, buffer);
|
||||
}
|
||||
|
||||
MG_EXPORT EGLBoolean eglReleaseTexImage(EGLDisplay dpy, EGLSurface surface, EGLint buffer) {
|
||||
LOAD_EGL(eglReleaseTexImage)
|
||||
return egl_eglReleaseTexImage(dpy, surface, buffer);
|
||||
}
|
||||
|
||||
MG_EXPORT EGLBoolean eglSwapInterval(EGLDisplay dpy, EGLint interval) {
|
||||
LOAD_EGL(eglSwapInterval)
|
||||
return egl_eglSwapInterval(dpy, interval);
|
||||
}
|
||||
|
||||
MG_EXPORT EGLContext eglCreateContext(EGLDisplay dpy, EGLConfig config, EGLContext share_context, const EGLint *attrib_list) {
|
||||
LOAD_EGL(eglCreateContext)
|
||||
return egl_eglCreateContext(dpy, config, share_context, attrib_list);
|
||||
}
|
||||
|
||||
MG_EXPORT EGLBoolean eglDestroyContext(EGLDisplay dpy, EGLContext ctx) {
|
||||
LOAD_EGL(eglDestroyContext)
|
||||
return egl_eglDestroyContext(dpy, ctx);
|
||||
}
|
||||
|
||||
MG_EXPORT EGLBoolean eglMakeCurrent(EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLContext ctx) {
|
||||
LOAD_EGL(eglMakeCurrent)
|
||||
return egl_eglMakeCurrent(dpy, draw, read, ctx);
|
||||
}
|
||||
|
||||
MG_EXPORT EGLContext eglGetCurrentContext(void) {
|
||||
LOAD_EGL(eglGetCurrentContext)
|
||||
return egl_eglGetCurrentContext();
|
||||
}
|
||||
|
||||
MG_EXPORT EGLSurface eglGetCurrentSurface(EGLint readdraw) {
|
||||
LOAD_EGL(eglGetCurrentSurface)
|
||||
return egl_eglGetCurrentSurface(readdraw);
|
||||
}
|
||||
|
||||
MG_EXPORT EGLDisplay eglGetCurrentDisplay(void) {
|
||||
LOAD_EGL(eglGetCurrentDisplay)
|
||||
return egl_eglGetCurrentDisplay();
|
||||
}
|
||||
|
||||
MG_EXPORT EGLBoolean eglQueryContext(EGLDisplay dpy, EGLContext ctx, EGLint attribute, EGLint *value) {
|
||||
LOAD_EGL(eglQueryContext)
|
||||
return egl_eglQueryContext(dpy, ctx, attribute, value);
|
||||
}
|
||||
|
||||
MG_EXPORT EGLBoolean eglWaitGL(void) {
|
||||
LOAD_EGL(eglWaitGL)
|
||||
return egl_eglWaitGL();
|
||||
}
|
||||
|
||||
MG_EXPORT EGLBoolean eglWaitNative(EGLint engine) {
|
||||
LOAD_EGL(eglWaitNative)
|
||||
return egl_eglWaitNative(engine);
|
||||
}
|
||||
|
||||
MG_EXPORT EGLBoolean eglSwapBuffers(EGLDisplay dpy, EGLSurface surface) {
|
||||
LOAD_EGL(eglSwapBuffers)
|
||||
return egl_eglSwapBuffers(dpy, surface);
|
||||
}
|
||||
|
||||
MG_EXPORT EGLBoolean eglCopyBuffers(EGLDisplay dpy, EGLSurface surface, EGLNativePixmapType target) {
|
||||
LOAD_EGL(eglCopyBuffers)
|
||||
return egl_eglCopyBuffers(dpy, surface, target);
|
||||
}
|
||||
|
||||
MG_EXPORT EGLDisplay eglGetPlatformDisplay(EGLenum platform, void *native_display, const EGLAttrib *attrib_list) {
|
||||
LOAD_EGL(eglGetPlatformDisplay)
|
||||
return egl_eglGetPlatformDisplay(platform, native_display, (const EGLint *)attrib_list);
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,14 +0,0 @@
|
||||
//
|
||||
// Created by BZLZHH on 2025/4/26.
|
||||
//
|
||||
|
||||
#ifndef MOBILEGL_EGL_GLES_EGL_WRAP_H
|
||||
#define MOBILEGL_EGL_GLES_EGL_WRAP_H
|
||||
|
||||
#include "../../../../Includes.h"
|
||||
|
||||
#if BACKEND_TYPE == BACKEND_GLES
|
||||
|
||||
#endif
|
||||
|
||||
#endif //MOBILEGL_EGL_GLES_EGL_WRAP_H
|
||||
@@ -1,551 +0,0 @@
|
||||
//
|
||||
// Created by BZLZHH on 2025/3/30.
|
||||
//
|
||||
|
||||
#include "EGL_EMU.h"
|
||||
|
||||
#if BACKEND_TYPE == BACKEND_VULKAN
|
||||
|
||||
std::atomic<uintptr_t> g_nextContextId{1};
|
||||
std::atomic<uintptr_t> g_nextSurfaceId{1};
|
||||
EGLenum g_currentAPI = EGL_OPENGL_ES_API;
|
||||
|
||||
std::mutex g_globalMutex;
|
||||
ankerl::unordered_map<EGLDisplay, VulkanDisplay> g_displays;
|
||||
ankerl::unordered_map<EGLSurface, VulkanSurface> g_surfaces;
|
||||
ankerl::unordered_map<EGLContext, VulkanContext> g_contexts;
|
||||
EGLint g_lastError = EGL_SUCCESS;
|
||||
|
||||
thread_local EGLContext tls_currentContext = EGL_NO_CONTEXT;
|
||||
thread_local EGLSurface tls_drawSurface = EGL_NO_SURFACE;
|
||||
thread_local EGLSurface tls_readSurface = EGL_NO_SURFACE;
|
||||
|
||||
static VkResult CreateRenderPass(VulkanDisplay& display, VulkanContext& ctx) {
|
||||
VkAttachmentDescription colorAttachment{};
|
||||
colorAttachment.format = VK_FORMAT_B8G8R8A8_SRGB;
|
||||
colorAttachment.samples = VK_SAMPLE_COUNT_1_BIT;
|
||||
colorAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
|
||||
colorAttachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
|
||||
colorAttachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
|
||||
colorAttachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
|
||||
colorAttachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||
colorAttachment.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
|
||||
|
||||
VkAttachmentReference colorRef{0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL};
|
||||
|
||||
VkSubpassDescription subpass{};
|
||||
subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
|
||||
subpass.colorAttachmentCount = 1;
|
||||
subpass.pColorAttachments = &colorRef;
|
||||
|
||||
VkRenderPassCreateInfo rpInfo{};
|
||||
rpInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
|
||||
rpInfo.subpassCount = 1;
|
||||
rpInfo.pSubpasses = &subpass;
|
||||
rpInfo.attachmentCount = 1;
|
||||
rpInfo.pAttachments = &colorAttachment;
|
||||
|
||||
return vkCreateRenderPass(display.device, &rpInfo, nullptr, &ctx.renderPass);
|
||||
}
|
||||
|
||||
EGLDisplay eglGetDisplay(NativeDisplayType display) {
|
||||
std::lock_guard<std::mutex> lock(g_globalMutex);
|
||||
static uintptr_t nextDisplayId = 1;
|
||||
EGLDisplay newDisplay = (EGLDisplay)nextDisplayId++;
|
||||
g_displays[newDisplay].initialized = false;
|
||||
return newDisplay;
|
||||
}
|
||||
|
||||
EGLBoolean eglInitialize(EGLDisplay dpy, EGLint* major, EGLint* minor) {
|
||||
VulkanDisplay& vkDpy = g_displays[dpy];
|
||||
if (vkDpy.initialized) return EGL_TRUE;
|
||||
|
||||
VkInstanceCreateInfo instInfo{};
|
||||
instInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
|
||||
const char* extensions[] = {
|
||||
VK_KHR_SURFACE_EXTENSION_NAME,
|
||||
VK_KHR_ANDROID_SURFACE_EXTENSION_NAME
|
||||
};
|
||||
instInfo.enabledExtensionCount = 2;
|
||||
instInfo.ppEnabledExtensionNames = extensions;
|
||||
|
||||
if (vkCreateInstance(&instInfo, nullptr, &vkDpy.instance) != VK_SUCCESS) {
|
||||
g_lastError = EGL_NOT_INITIALIZED;
|
||||
return EGL_FALSE;
|
||||
}
|
||||
|
||||
uint32_t devCount = 0;
|
||||
vkEnumeratePhysicalDevices(vkDpy.instance, &devCount, nullptr);
|
||||
std::vector<VkPhysicalDevice> devices(devCount);
|
||||
vkEnumeratePhysicalDevices(vkDpy.instance, &devCount, devices.data());
|
||||
vkDpy.physicalDevice = devices[0];
|
||||
|
||||
|
||||
uint32_t queueFamilyCount = 0;
|
||||
vkGetPhysicalDeviceQueueFamilyProperties(vkDpy.physicalDevice, &queueFamilyCount, nullptr);
|
||||
std::vector<VkQueueFamilyProperties> queueFamilies(queueFamilyCount);
|
||||
vkGetPhysicalDeviceQueueFamilyProperties(vkDpy.physicalDevice, &queueFamilyCount, queueFamilies.data());
|
||||
|
||||
// 寻找支持图形和呈现的队列家族
|
||||
bool foundQueue = false;
|
||||
for (uint32_t i = 0; i < queueFamilyCount; ++i) {
|
||||
VkBool32 presentSupport = VK_FALSE;
|
||||
vkGetPhysicalDeviceSurfaceSupportKHR(vkDpy.physicalDevice, i, VK_NULL_HANDLE, &presentSupport);
|
||||
|
||||
if ((queueFamilies[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) && presentSupport) {
|
||||
vkDpy.graphicsQueueFamily = i;
|
||||
foundQueue = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!foundQueue) {
|
||||
g_lastError = EGL_NOT_INITIALIZED;
|
||||
return EGL_FALSE;
|
||||
}
|
||||
|
||||
// 创建逻辑设备时请求队列
|
||||
float queuePriority = 1.0f;
|
||||
VkDeviceQueueCreateInfo queueInfo{};
|
||||
queueInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
|
||||
queueInfo.queueFamilyIndex = vkDpy.graphicsQueueFamily;
|
||||
queueInfo.queueCount = 1;
|
||||
queueInfo.pQueuePriorities = &queuePriority;
|
||||
|
||||
const char* devExtensions[] = {VK_KHR_SWAPCHAIN_EXTENSION_NAME};
|
||||
VkDeviceCreateInfo devInfo{};
|
||||
devInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
|
||||
devInfo.pQueueCreateInfos = &queueInfo;
|
||||
devInfo.queueCreateInfoCount = 1;
|
||||
devInfo.ppEnabledExtensionNames = devExtensions;
|
||||
devInfo.enabledExtensionCount = 1;
|
||||
|
||||
if (vkCreateDevice(vkDpy.physicalDevice, &devInfo, nullptr, &vkDpy.device) != VK_SUCCESS) {
|
||||
g_lastError = EGL_NOT_INITIALIZED;
|
||||
return EGL_FALSE;
|
||||
}
|
||||
|
||||
vkDpy.vkCreateSwapchainKHR = (PFN_vkCreateSwapchainKHR)vkGetDeviceProcAddr(vkDpy.device, "vkCreateSwapchainKHR");
|
||||
vkDpy.vkDestroySwapchainKHR = (PFN_vkDestroySwapchainKHR)vkGetDeviceProcAddr(vkDpy.device, "vkDestroySwapchainKHR");
|
||||
vkDpy.vkGetSwapchainImagesKHR = (PFN_vkGetSwapchainImagesKHR)vkGetDeviceProcAddr(vkDpy.device, "vkGetSwapchainImagesKHR");
|
||||
vkDpy.vkAcquireNextImageKHR = (PFN_vkAcquireNextImageKHR)vkGetDeviceProcAddr(vkDpy.device, "vkAcquireNextImageKHR");
|
||||
vkDpy.vkQueuePresentKHR = (PFN_vkQueuePresentKHR)vkGetDeviceProcAddr(vkDpy.device, "vkQueuePresentKHR");
|
||||
vkGetDeviceQueue(vkDpy.device, vkDpy.graphicsQueueFamily, 0, &vkDpy.graphicsQueue);
|
||||
vkDpy.presentQueue = vkDpy.graphicsQueue;
|
||||
vkDpy.initialized = true;
|
||||
if (major) *major = 1;
|
||||
if (minor) *minor = 5;
|
||||
return EGL_TRUE;
|
||||
}
|
||||
|
||||
EGLBoolean eglChooseConfig(EGLDisplay dpy, const EGLint* attrib_list, EGLConfig* configs, EGLint config_size, EGLint* num_config) {
|
||||
VulkanDisplay& vkDpy = g_displays[dpy];
|
||||
EGLInternalConfig defaultConfig{ VK_FORMAT_B8G8R8A8_SRGB, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR, 1 };
|
||||
vkDpy.configs = {defaultConfig};
|
||||
|
||||
EGLint returnCount = 1;
|
||||
if (configs && config_size > 0) {
|
||||
configs[0] = (EGLConfig)0;
|
||||
}
|
||||
|
||||
if (num_config) *num_config = returnCount;
|
||||
return EGL_TRUE;
|
||||
}
|
||||
|
||||
EGLSurface eglCreateWindowSurface(EGLDisplay dpy, EGLConfig config, NativeWindowType window, const EGLint* attrib_list) {
|
||||
VulkanDisplay& disp = g_displays[dpy];
|
||||
static uintptr_t nextSurfId = 1;
|
||||
|
||||
ANativeWindow* nativeWindow = static_cast<ANativeWindow*>(window);
|
||||
if (!nativeWindow || ANativeWindow_getWidth(nativeWindow) <= 0 || ANativeWindow_getHeight(nativeWindow) <= 0) {
|
||||
g_lastError = EGL_BAD_NATIVE_WINDOW;
|
||||
return EGL_NO_SURFACE;
|
||||
}
|
||||
|
||||
auto vkCreateAndroidSurfaceKHR = (PFN_vkCreateAndroidSurfaceKHR)vkGetInstanceProcAddr(
|
||||
disp.instance, "vkCreateAndroidSurfaceKHR");
|
||||
if (!vkCreateAndroidSurfaceKHR) {
|
||||
g_lastError = EGL_BAD_ALLOC;
|
||||
return EGL_NO_SURFACE;
|
||||
}
|
||||
|
||||
VulkanSurface surface{};
|
||||
surface.type = VulkanSurface::WINDOW;
|
||||
|
||||
VkAndroidSurfaceCreateInfoKHR createInfo{};
|
||||
createInfo.sType = VK_STRUCTURE_TYPE_ANDROID_SURFACE_CREATE_INFO_KHR;
|
||||
createInfo.window = nativeWindow;
|
||||
VkResult result = vkCreateAndroidSurfaceKHR(disp.instance, &createInfo, nullptr, &surface.surface);
|
||||
if (result != VK_SUCCESS) {
|
||||
g_lastError = (result == VK_ERROR_NATIVE_WINDOW_IN_USE_KHR) ?
|
||||
EGL_BAD_NATIVE_WINDOW : EGL_BAD_ALLOC;
|
||||
return EGL_NO_SURFACE;
|
||||
}
|
||||
|
||||
VkBool32 supported = VK_FALSE;
|
||||
vkGetPhysicalDeviceSurfaceSupportKHR(disp.physicalDevice,
|
||||
disp.graphicsQueueFamily,
|
||||
surface.surface,
|
||||
&supported);
|
||||
if (!supported) {
|
||||
vkDestroySurfaceKHR(disp.instance, surface.surface, nullptr);
|
||||
g_lastError = EGL_BAD_MATCH;
|
||||
return EGL_NO_SURFACE;
|
||||
}
|
||||
|
||||
VkSurfaceCapabilitiesKHR caps;
|
||||
vkGetPhysicalDeviceSurfaceCapabilitiesKHR(disp.physicalDevice, surface.surface, &caps);
|
||||
|
||||
const VkExtent2D swapchainExtent = {
|
||||
(std::max)(caps.minImageExtent.width, (uint32_t)ANativeWindow_getWidth(nativeWindow)),
|
||||
(std::max)(caps.minImageExtent.height, (uint32_t)ANativeWindow_getHeight(nativeWindow))
|
||||
};
|
||||
|
||||
VkSwapchainCreateInfoKHR swapInfo{};
|
||||
swapInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
|
||||
swapInfo.surface = surface.surface;
|
||||
swapInfo.minImageCount = 3;
|
||||
swapInfo.imageFormat = VK_FORMAT_R8G8B8A8_SRGB;
|
||||
swapInfo.imageColorSpace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR;
|
||||
swapInfo.imageExtent = swapchainExtent;
|
||||
swapInfo.imageArrayLayers = 1;
|
||||
swapInfo.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
|
||||
swapInfo.preTransform = caps.currentTransform;
|
||||
swapInfo.compositeAlpha = VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR;
|
||||
swapInfo.presentMode = VK_PRESENT_MODE_MAILBOX_KHR;
|
||||
|
||||
if (disp.vkCreateSwapchainKHR(disp.device, &swapInfo, nullptr, &surface.swapchain) != VK_SUCCESS) {
|
||||
vkDestroySurfaceKHR(disp.instance, surface.surface, nullptr);
|
||||
g_lastError = EGL_BAD_ALLOC;
|
||||
return EGL_NO_SURFACE;
|
||||
}
|
||||
|
||||
uint32_t imageCount = 0;
|
||||
disp.vkGetSwapchainImagesKHR(disp.device, surface.swapchain, &imageCount, nullptr);
|
||||
surface.images.resize(imageCount);
|
||||
disp.vkGetSwapchainImagesKHR(disp.device, surface.swapchain, &imageCount, surface.images.data());
|
||||
|
||||
surface.imageViews.resize(imageCount);
|
||||
for (uint32_t i = 0; i < imageCount; ++i) {
|
||||
VkImageViewCreateInfo viewInfo{};
|
||||
viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
|
||||
viewInfo.image = surface.images[i];
|
||||
viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
|
||||
viewInfo.format = swapInfo.imageFormat;
|
||||
viewInfo.subresourceRange = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1};
|
||||
|
||||
if (vkCreateImageView(disp.device, &viewInfo, nullptr, &surface.imageViews[i]) != VK_SUCCESS) {
|
||||
// Handle error
|
||||
}
|
||||
}
|
||||
|
||||
ANativeWindow_acquire(nativeWindow);
|
||||
ANativeWindow_setBuffersGeometry(nativeWindow,
|
||||
swapchainExtent.width,
|
||||
swapchainExtent.height,
|
||||
AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM);
|
||||
EGLSurface surfId = (EGLSurface)nextSurfId++;
|
||||
g_surfaces[surfId] = std::move(surface);
|
||||
return surfId;
|
||||
}
|
||||
|
||||
EGLContext eglCreateContext(EGLDisplay dpy, EGLConfig config, EGLContext shareCtx, const EGLint* attrib_list) {
|
||||
static uintptr_t nextCtxId = 1;
|
||||
VulkanDisplay &disp = g_displays[dpy];
|
||||
|
||||
VulkanContext ctx{};
|
||||
VkCommandPoolCreateInfo poolInfo{};
|
||||
poolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
|
||||
poolInfo.queueFamilyIndex = 0;
|
||||
if (vkCreateCommandPool(disp.device, &poolInfo, nullptr, &ctx.cmdPool) != VK_SUCCESS) {
|
||||
g_lastError = EGL_BAD_ALLOC;
|
||||
return EGL_NO_CONTEXT;
|
||||
}
|
||||
|
||||
ctx.frameFences.resize(2);
|
||||
ctx.acquireSemaphores.resize(2);
|
||||
ctx.presentSemaphores.resize(2);
|
||||
for (uint32_t i = 0; i < 2; ++i) {
|
||||
VkFenceCreateInfo fenceInfo{VK_STRUCTURE_TYPE_FENCE_CREATE_INFO, nullptr,
|
||||
VK_FENCE_CREATE_SIGNALED_BIT};
|
||||
vkCreateFence(disp.device, &fenceInfo, nullptr, &ctx.frameFences[i]);
|
||||
|
||||
VkSemaphoreCreateInfo semInfo{VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO};
|
||||
vkCreateSemaphore(disp.device, &semInfo, nullptr, &ctx.acquireSemaphores[i]);
|
||||
vkCreateSemaphore(disp.device, &semInfo, nullptr, &ctx.presentSemaphores[i]);
|
||||
}
|
||||
|
||||
if (CreateRenderPass(disp, ctx) != VK_SUCCESS) {
|
||||
g_lastError = EGL_BAD_CONFIG;
|
||||
return EGL_NO_CONTEXT;
|
||||
}
|
||||
|
||||
EGLContext ctxId = (EGLContext)nextCtxId++;
|
||||
g_contexts[ctxId] = std::move(ctx);
|
||||
return ctxId;
|
||||
}
|
||||
|
||||
EGLint eglGetError() {
|
||||
return EGL_SUCCESS;
|
||||
}
|
||||
|
||||
EGLBoolean eglMakeCurrent(EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLContext ctx) {
|
||||
std::lock_guard<std::mutex> lock(g_globalMutex);
|
||||
|
||||
if (dpy == EGL_NO_DISPLAY || (ctx != EGL_NO_CONTEXT && !g_contexts.count(ctx)) ||
|
||||
(draw != EGL_NO_SURFACE && !g_surfaces.count(draw)) ||
|
||||
(read != EGL_NO_SURFACE && !g_surfaces.count(read))) {
|
||||
g_lastError = EGL_BAD_PARAMETER;
|
||||
return EGL_FALSE;
|
||||
}
|
||||
|
||||
if (tls_currentContext != EGL_NO_CONTEXT) {
|
||||
VulkanContext& oldCtx = g_contexts[tls_currentContext];
|
||||
if (oldCtx.currentCmdBuffer) {
|
||||
vkEndCommandBuffer(oldCtx.currentCmdBuffer);
|
||||
oldCtx.currentCmdBuffer = VK_NULL_HANDLE;
|
||||
}
|
||||
}
|
||||
|
||||
if (ctx != EGL_NO_CONTEXT) {
|
||||
VulkanContext& newCtx = g_contexts[ctx];
|
||||
VulkanDisplay& disp = g_displays[dpy];
|
||||
|
||||
VkCommandBufferAllocateInfo allocInfo{};
|
||||
allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
|
||||
allocInfo.commandPool = newCtx.cmdPool;
|
||||
allocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
|
||||
allocInfo.commandBufferCount = 1;
|
||||
|
||||
if (vkAllocateCommandBuffers(disp.device, &allocInfo, &newCtx.currentCmdBuffer) != VK_SUCCESS) {
|
||||
g_lastError = EGL_BAD_ALLOC;
|
||||
return EGL_FALSE;
|
||||
}
|
||||
|
||||
VkCommandBufferBeginInfo beginInfo{};
|
||||
beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
|
||||
vkBeginCommandBuffer(newCtx.currentCmdBuffer, &beginInfo);
|
||||
}
|
||||
|
||||
tls_currentContext = ctx;
|
||||
tls_drawSurface = draw;
|
||||
tls_readSurface = read;
|
||||
return EGL_TRUE;
|
||||
}
|
||||
|
||||
EGLBoolean eglDestroyContext(EGLDisplay dpy, EGLContext ctx) {
|
||||
std::lock_guard<std::mutex> lock(g_globalMutex);
|
||||
|
||||
if (!g_contexts.count(ctx)) {
|
||||
g_lastError = EGL_BAD_CONTEXT;
|
||||
return EGL_FALSE;
|
||||
}
|
||||
|
||||
VulkanContext& vkCtx = g_contexts[ctx];
|
||||
VulkanDisplay& disp = g_displays[dpy];
|
||||
|
||||
vkDeviceWaitIdle(disp.device);
|
||||
|
||||
vkDestroyCommandPool(disp.device, vkCtx.cmdPool, nullptr);
|
||||
vkDestroyRenderPass(disp.device, vkCtx.renderPass, nullptr);
|
||||
|
||||
for (auto& fence : vkCtx.frameFences)
|
||||
vkDestroyFence(disp.device, fence, nullptr);
|
||||
for (auto& sem : vkCtx.acquireSemaphores)
|
||||
vkDestroySemaphore(disp.device, sem, nullptr);
|
||||
for (auto& sem : vkCtx.presentSemaphores)
|
||||
vkDestroySemaphore(disp.device, sem, nullptr);
|
||||
|
||||
g_contexts.erase(ctx);
|
||||
if (tls_currentContext == ctx)
|
||||
tls_currentContext = EGL_NO_CONTEXT;
|
||||
|
||||
return EGL_TRUE;
|
||||
}
|
||||
|
||||
EGLBoolean eglDestroySurface(EGLDisplay dpy, EGLSurface surface) {
|
||||
std::lock_guard<std::mutex> lock(g_globalMutex);
|
||||
|
||||
if (!g_surfaces.count(surface)) {
|
||||
g_lastError = EGL_BAD_SURFACE;
|
||||
return EGL_FALSE;
|
||||
}
|
||||
|
||||
VulkanSurface& surf = g_surfaces[surface];
|
||||
VulkanDisplay& disp = g_displays[dpy];
|
||||
|
||||
vkDeviceWaitIdle(disp.device);
|
||||
|
||||
if (surf.type == VulkanSurface::WINDOW) {
|
||||
disp.vkDestroySwapchainKHR(disp.device, surf.swapchain, nullptr);
|
||||
vkDestroySurfaceKHR(disp.instance, surf.surface, nullptr);
|
||||
for (auto& view : surf.imageViews)
|
||||
vkDestroyImageView(disp.device, view, nullptr);
|
||||
} else {
|
||||
vkDestroyImageView(disp.device, surf.pbufferImageView, nullptr);
|
||||
vkDestroyImage(disp.device, surf.pbufferImage, nullptr);
|
||||
}
|
||||
|
||||
g_surfaces.erase(surface);
|
||||
return EGL_TRUE;
|
||||
}
|
||||
|
||||
EGLBoolean eglTerminate(EGLDisplay dpy) {
|
||||
std::lock_guard<std::mutex> lock(g_globalMutex);
|
||||
|
||||
if (!g_displays.count(dpy)) {
|
||||
g_lastError = EGL_BAD_DISPLAY;
|
||||
return EGL_FALSE;
|
||||
}
|
||||
|
||||
VulkanDisplay& disp = g_displays[dpy];
|
||||
|
||||
for (auto& [ctxId, ctx] : g_contexts)
|
||||
eglDestroyContext(dpy, ctxId);
|
||||
for (auto& [surfId, surf] : g_surfaces)
|
||||
eglDestroySurface(dpy, surfId);
|
||||
|
||||
vkDestroyDevice(disp.device, nullptr);
|
||||
vkDestroyInstance(disp.instance, nullptr);
|
||||
|
||||
g_displays.erase(dpy);
|
||||
return EGL_TRUE;
|
||||
}
|
||||
|
||||
EGLBoolean eglReleaseThread(void) {
|
||||
tls_currentContext = EGL_NO_CONTEXT;
|
||||
tls_drawSurface = EGL_NO_SURFACE;
|
||||
tls_readSurface = EGL_NO_SURFACE;
|
||||
return EGL_TRUE;
|
||||
}
|
||||
|
||||
EGLContext eglGetCurrentContext(void) {
|
||||
return tls_currentContext;
|
||||
}
|
||||
|
||||
EGLBoolean eglGetConfigAttrib(EGLDisplay dpy, EGLConfig config, EGLint attribute, EGLint *value) {
|
||||
VulkanDisplay& disp = g_displays[dpy];
|
||||
if (!disp.configs.empty() && config == (EGLConfig)0) {
|
||||
switch (attribute) {
|
||||
case EGL_BUFFER_SIZE: *value = 32; break;
|
||||
case EGL_RED_SIZE: *value = 8; break;
|
||||
case EGL_GREEN_SIZE: *value = 8; break;
|
||||
case EGL_BLUE_SIZE: *value = 8; break;
|
||||
case EGL_ALPHA_SIZE: *value = 8; break;
|
||||
case EGL_CONFIG_ID: *value = 1; break;
|
||||
default: return EGL_FALSE;
|
||||
}
|
||||
return EGL_TRUE;
|
||||
}
|
||||
return EGL_FALSE;
|
||||
}
|
||||
|
||||
EGLBoolean eglBindAPI(EGLenum api) {
|
||||
if (api == EGL_OPENGL_ES_API) {
|
||||
g_currentAPI = api;
|
||||
return EGL_TRUE;
|
||||
}
|
||||
return EGL_FALSE;
|
||||
}
|
||||
|
||||
EGLSurface eglCreatePbufferSurface(EGLDisplay dpy, EGLConfig config, const EGLint *attrib_list) {
|
||||
VulkanDisplay& disp = g_displays[dpy];
|
||||
VulkanSurface surface{};
|
||||
surface.type = VulkanSurface::PBUFFER;
|
||||
|
||||
VkImageCreateInfo imgInfo{};
|
||||
imgInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
|
||||
imgInfo.imageType = VK_IMAGE_TYPE_2D;
|
||||
imgInfo.format = VK_FORMAT_R8G8B8A8_SRGB;
|
||||
imgInfo.extent = {512, 512, 1};
|
||||
imgInfo.mipLevels = 1;
|
||||
imgInfo.arrayLayers = 1;
|
||||
imgInfo.samples = VK_SAMPLE_COUNT_1_BIT;
|
||||
imgInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
|
||||
imgInfo.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
|
||||
imgInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||
|
||||
if (vkCreateImage(disp.device, &imgInfo, nullptr, &surface.pbufferImage) != VK_SUCCESS) {
|
||||
g_lastError = EGL_BAD_ALLOC;
|
||||
return EGL_NO_SURFACE;
|
||||
}
|
||||
|
||||
VkImageViewCreateInfo viewInfo{};
|
||||
viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
|
||||
viewInfo.image = surface.pbufferImage;
|
||||
viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
|
||||
viewInfo.format = imgInfo.format;
|
||||
viewInfo.subresourceRange = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1};
|
||||
|
||||
if (vkCreateImageView(disp.device, &viewInfo, nullptr, &surface.pbufferImageView) != VK_SUCCESS) {
|
||||
vkDestroyImage(disp.device, surface.pbufferImage, nullptr);
|
||||
g_lastError = EGL_BAD_ALLOC;
|
||||
return EGL_NO_SURFACE;
|
||||
}
|
||||
|
||||
EGLSurface surfId = (EGLSurface)g_nextSurfaceId++;
|
||||
g_surfaces[surfId] = surface;
|
||||
return surfId;
|
||||
}
|
||||
|
||||
EGLBoolean eglSwapBuffers(EGLDisplay dpy, EGLSurface draw) {
|
||||
VulkanSurface& surf = g_surfaces[draw];
|
||||
VulkanDisplay& disp = g_displays[dpy];
|
||||
VulkanContext& ctx = g_contexts[tls_currentContext];
|
||||
|
||||
if (!disp.presentQueue) {
|
||||
g_lastError = EGL_BAD_DISPLAY;
|
||||
return EGL_FALSE;
|
||||
}
|
||||
|
||||
if (surf.type != VulkanSurface::WINDOW) {
|
||||
g_lastError = EGL_BAD_SURFACE;
|
||||
return EGL_FALSE;
|
||||
}
|
||||
|
||||
vkEndCommandBuffer(ctx.currentCmdBuffer);
|
||||
|
||||
VkSubmitInfo submitInfo{};
|
||||
submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
|
||||
submitInfo.commandBufferCount = 1;
|
||||
submitInfo.pCommandBuffers = &ctx.currentCmdBuffer;
|
||||
|
||||
vkQueueSubmit(disp.graphicsQueue, 1, &submitInfo, VK_NULL_HANDLE);
|
||||
|
||||
VkPresentInfoKHR presentInfo{};
|
||||
presentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
|
||||
presentInfo.swapchainCount = 1;
|
||||
presentInfo.pSwapchains = &surf.swapchain;
|
||||
presentInfo.pImageIndices = &ctx.frameIndex;
|
||||
|
||||
VkResult result = disp.vkQueuePresentKHR(disp.presentQueue, &presentInfo);
|
||||
if (result != VK_SUCCESS) {
|
||||
g_lastError = EGL_BAD_ALLOC;
|
||||
return EGL_FALSE;
|
||||
}
|
||||
|
||||
ctx.frameIndex = (ctx.frameIndex + 1) % surf.images.size();
|
||||
return EGL_TRUE;
|
||||
}
|
||||
|
||||
EGLBoolean eglSwapInterval(EGLDisplay dpy, EGLint interval) {
|
||||
// TODO
|
||||
return EGL_TRUE;
|
||||
}
|
||||
|
||||
EGLSurface eglGetCurrentSurface(EGLint readdraw) {
|
||||
return (readdraw == EGL_READ) ? tls_readSurface : tls_drawSurface;
|
||||
}
|
||||
|
||||
EGLBoolean eglQuerySurface(EGLDisplay display, EGLSurface surface, EGLint attribute, EGLint *value) {
|
||||
VulkanSurface& surf = g_surfaces[surface];
|
||||
switch (attribute) {
|
||||
case EGL_WIDTH: *value = surf.extent.width; break;
|
||||
case EGL_HEIGHT: *value = surf.extent.height; break;
|
||||
case EGL_CONFIG_ID: *value = 1; break;
|
||||
default: return EGL_FALSE;
|
||||
}
|
||||
return EGL_TRUE;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,103 +0,0 @@
|
||||
//
|
||||
// Created by BZLZHH on 2025/3/30.
|
||||
//
|
||||
|
||||
#ifndef MOBILEGL_EGL_VK_EMU_H
|
||||
#define MOBILEGL_EGL_VK_EMU_H
|
||||
|
||||
#include "../../../../Includes.h"
|
||||
|
||||
#if BACKEND_TYPE == BACKEND_VULKAN
|
||||
|
||||
struct EGLInternalConfig {
|
||||
VkFormat format;
|
||||
VkColorSpaceKHR colorSpace;
|
||||
uint32_t samples;
|
||||
};
|
||||
|
||||
struct VulkanDisplay {
|
||||
VkInstance instance;
|
||||
VkPhysicalDevice physicalDevice;
|
||||
VkDevice device;
|
||||
uint32_t graphicsQueueFamily;
|
||||
VkQueue graphicsQueue;
|
||||
std::vector<EGLInternalConfig> configs;
|
||||
bool initialized = false;
|
||||
PFN_vkCreateSwapchainKHR vkCreateSwapchainKHR;
|
||||
PFN_vkDestroySwapchainKHR vkDestroySwapchainKHR;
|
||||
PFN_vkGetSwapchainImagesKHR vkGetSwapchainImagesKHR;
|
||||
PFN_vkAcquireNextImageKHR vkAcquireNextImageKHR;
|
||||
PFN_vkQueuePresentKHR vkQueuePresentKHR;
|
||||
VkRenderPass defaultRenderPass;
|
||||
VkQueue presentQueue = VK_NULL_HANDLE;
|
||||
};
|
||||
|
||||
struct VulkanSurface {
|
||||
enum Type { WINDOW, PBUFFER } type;
|
||||
VkSurfaceKHR surface;
|
||||
VkSwapchainKHR swapchain;
|
||||
std::vector<VkImage> images;
|
||||
std::vector<VkImageView> imageViews;
|
||||
VkExtent2D extent;
|
||||
VkFormat format;
|
||||
VkImage pbImage;
|
||||
VkImageView pbImageView;
|
||||
VkDeviceMemory pbMemory;
|
||||
VkFramebuffer framebuffer;
|
||||
VkImage pbufferImage;
|
||||
VkImageView pbufferImageView;
|
||||
};
|
||||
|
||||
struct VulkanContext {
|
||||
VkCommandPool cmdPool;
|
||||
std::vector<VkCommandBuffer> cmdBuffers;
|
||||
uint32_t currentFrame = 0;
|
||||
VkRenderPass renderPass;
|
||||
VkPipelineLayout pipelineLayout;
|
||||
VkPipeline graphicsPipeline;
|
||||
std::vector<VkFence> frameFences;
|
||||
std::vector<VkSemaphore> acquireSemaphores;
|
||||
std::vector<VkSemaphore> presentSemaphores;
|
||||
VulkanSurface* boundSurface = nullptr;
|
||||
VkCommandBuffer currentCmdBuffer;
|
||||
uint32_t frameIndex;
|
||||
VkClearColorValue clearColor;
|
||||
};
|
||||
|
||||
extern std::atomic<uintptr_t> g_nextContextId;
|
||||
extern std::atomic<uintptr_t> g_nextSurfaceId;
|
||||
extern EGLenum g_currentAPI;
|
||||
|
||||
extern std::mutex g_globalMutex;
|
||||
extern ankerl::unordered_map<EGLDisplay, VulkanDisplay> g_displays;
|
||||
extern ankerl::unordered_map<EGLSurface, VulkanSurface> g_surfaces;
|
||||
extern ankerl::unordered_map<EGLContext, VulkanContext> g_contexts;
|
||||
extern EGLint g_lastError;
|
||||
|
||||
extern thread_local EGLContext tls_currentContext;
|
||||
extern thread_local EGLSurface tls_drawSurface;
|
||||
extern thread_local EGLSurface tls_readSurface;
|
||||
|
||||
MG_EXPORT EGLSurface eglCreateWindowSurface(EGLDisplay dpy, EGLConfig config, NativeWindowType window, const EGLint* attrib_list);
|
||||
MG_EXPORT EGLBoolean eglChooseConfig(EGLDisplay dpy, const EGLint* attrib_list, EGLConfig* configs, EGLint config_size, EGLint* num_config);
|
||||
MG_EXPORT EGLContext eglCreateContext(EGLDisplay dpy, EGLConfig config, EGLContext shareCtx, const EGLint* attrib_list);
|
||||
MG_EXPORT EGLBoolean eglInitialize(EGLDisplay dpy, EGLint* major, EGLint* minor);
|
||||
MG_EXPORT EGLDisplay eglGetDisplay(NativeDisplayType display);
|
||||
MG_EXPORT EGLint eglGetError();
|
||||
MG_EXPORT EGLBoolean eglMakeCurrent(EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLContext ctx);
|
||||
MG_EXPORT EGLBoolean eglDestroyContext(EGLDisplay dpy, EGLContext ctx);
|
||||
MG_EXPORT EGLBoolean eglDestroySurface(EGLDisplay dpy, EGLSurface surface);
|
||||
MG_EXPORT EGLBoolean eglTerminate(EGLDisplay dpy);
|
||||
MG_EXPORT EGLBoolean eglReleaseThread(void);
|
||||
MG_EXPORT EGLContext eglGetCurrentContext(void);
|
||||
MG_EXPORT EGLBoolean eglGetConfigAttrib(EGLDisplay dpy, EGLConfig config, EGLint attribute, EGLint *value);
|
||||
MG_EXPORT EGLBoolean eglBindAPI(EGLenum api);
|
||||
MG_EXPORT EGLSurface eglGetCurrentSurface(EGLint readdraw);
|
||||
MG_EXPORT EGLBoolean eglQuerySurface(EGLDisplay display, EGLSurface surface, EGLint attribute, EGLint *value);
|
||||
MG_EXPORT EGLBoolean eglSwapInterval(EGLDisplay dpy, EGLint interval);
|
||||
MG_EXPORT EGLBoolean eglSwapBuffers(EGLDisplay dpy, EGLSurface draw);
|
||||
MG_EXPORT EGLSurface eglCreatePbufferSurface(EGLDisplay dpy, EGLConfig config, const EGLint *attrib_list);
|
||||
|
||||
#endif
|
||||
|
||||
#endif //MOBILEGL_EGL_VK_EMU_H
|
||||
@@ -1,188 +0,0 @@
|
||||
//
|
||||
// Created by BZLZHH on 2025/3/15.
|
||||
//
|
||||
|
||||
#include "GL_Buffer.h"
|
||||
|
||||
namespace MG_GL::GL {
|
||||
void* MapBufferRange(GLenum target, GLintptr offset, GLsizeiptr length,
|
||||
GLbitfield access) {
|
||||
MG_Util::Debug::LogD("glMapBufferRange, target: %s, offset: %lld, length: %lld, access: 0x%X",
|
||||
MG_Util::Debug::GLEnumToString(target),
|
||||
static_cast<long long>(offset),
|
||||
static_cast<long long>(length),
|
||||
access);
|
||||
void* mappedPointer = nullptr;
|
||||
GLenum result = MG_State::AcquireBufferMemoryRange(target, offset, length, access, &mappedPointer);
|
||||
|
||||
if (result == GL_NO_ERROR) {
|
||||
MG_Util::Debug::LogD("Mapped pointer: %p", mappedPointer);
|
||||
return mappedPointer;
|
||||
}
|
||||
MG_State::SetError(result);
|
||||
MG_Util::Debug::LogE("Error mapping buffer range: %s", MG_Util::Debug::GLEnumToString(result));
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void FlushMappedBufferRange(GLenum target, GLintptr offset, GLsizeiptr length) {
|
||||
MG_Util::Debug::LogD("glFlushMappedBufferRange, target: %s, offset: %lld, length: %lld",
|
||||
MG_Util::Debug::GLEnumToString(target),
|
||||
static_cast<long long>(offset),
|
||||
static_cast<long long>(length));
|
||||
GLenum result = MG_State::SyncBufferMemory(target, offset, length);
|
||||
if (result == GL_NO_ERROR) {
|
||||
return;
|
||||
}
|
||||
MG_State::SetError(result);
|
||||
MG_Util::Debug::LogE("Error flushing mapped buffer range: %s",
|
||||
MG_Util::Debug::GLEnumToString(result));
|
||||
}
|
||||
|
||||
void CopyBufferSubData(GLenum readTarget, GLenum writeTarget,
|
||||
GLintptr readOffset, GLintptr writeOffset,
|
||||
GLsizeiptr size) {
|
||||
MG_Util::Debug::LogD("glCopyBufferSubData, readTarget: %s, writeTarget: %s, "
|
||||
"readOffset: %lld, writeOffset: %lld, size: %lld",
|
||||
MG_Util::Debug::GLEnumToString(readTarget),
|
||||
MG_Util::Debug::GLEnumToString(writeTarget),
|
||||
static_cast<long long>(readOffset),
|
||||
static_cast<long long>(writeOffset),
|
||||
static_cast<long long>(size));
|
||||
GLenum result = MG_State::CopyBufferRange(readTarget, writeTarget, readOffset, writeOffset, size);
|
||||
if (result == GL_NO_ERROR) {
|
||||
return;
|
||||
}
|
||||
MG_State::SetError(result);
|
||||
MG_Util::Debug::LogE("Error copying buffer subdata: %s",
|
||||
MG_Util::Debug::GLEnumToString(result));
|
||||
}
|
||||
|
||||
void* MapBuffer(GLenum target, GLenum access) {
|
||||
MG_Util::Debug::LogD("glMapBuffer(target=0x%x, access=0x%x)", target, access);
|
||||
void* mappedPtr = nullptr;
|
||||
GLenum err = MG_State::AcquireBufferMemory(target, access, &mappedPtr);
|
||||
if (err != GL_NO_ERROR) {
|
||||
MG_State::SetError(err);
|
||||
MG_Util::Debug::LogE("glMapBuffer failed: %s", MG_Util::Debug::GLEnumToString(err));
|
||||
return nullptr;
|
||||
}
|
||||
MG_Util::Debug::LogD("glMapBuffer returns %p", mappedPtr);
|
||||
return mappedPtr;
|
||||
}
|
||||
|
||||
GLboolean UnmapBuffer(GLenum target) {
|
||||
MG_Util::Debug::LogD("glUnmapBuffer(target=0x%x)", target);
|
||||
GLenum err = MG_State::ReleaseBufferMemory(target);
|
||||
if (err != GL_NO_ERROR) {
|
||||
MG_State::SetError(err);
|
||||
MG_Util::Debug::LogE("glUnmapBuffer failed: %s", MG_Util::Debug::GLEnumToString(err));
|
||||
return GL_FALSE;
|
||||
}
|
||||
MG_Util::Debug::LogD("glUnmapBuffer succeeded");
|
||||
return GL_TRUE;
|
||||
}
|
||||
|
||||
void BindBuffer(GLenum target, GLuint buffer) {
|
||||
MG_Util::Debug::LogD("glBindBuffer, target: %s, buffer: %d", MG_Util::Debug::GLEnumToString(target), buffer);
|
||||
if (buffer != 0 &&
|
||||
MG_State::ValidateGeneratedName(buffer) &&
|
||||
!MG_State::ValidateAllocatedBufferHandle(buffer)) {
|
||||
MG_Util::Debug::LogD("Actually creating buffer: %u", buffer);
|
||||
GLenum result = MG_State::CreateBuffer(buffer);
|
||||
if (result != GL_NO_ERROR) {
|
||||
MG_State::SetError(result);
|
||||
MG_Util::Debug::LogE("Error from MG State: %s", MG_Util::Debug::GLEnumToString(result));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (buffer != 0 && !MG_State::ValidateAllocatedBufferHandle(buffer)) {
|
||||
MG_State::SetError(GL_INVALID_VALUE);
|
||||
MG_Util::Debug::LogE("Invalid buffer handle: %u", buffer);
|
||||
return;
|
||||
}
|
||||
GLenum result = MG_State::BindBuffer(target, buffer);
|
||||
if (result == GL_NO_ERROR)
|
||||
return;
|
||||
MG_State::SetError(result);
|
||||
MG_Util::Debug::LogE("Error from MG State: %s", MG_Util::Debug::GLEnumToString(result));
|
||||
}
|
||||
|
||||
void BufferData(GLenum target, GLsizeiptr size, const void* data, GLenum usage) {
|
||||
MG_Util::Debug::LogD("glBufferData, target: %s, size: %zd, data: %p, usage: %s",
|
||||
MG_Util::Debug::GLEnumToString(target), size, data, MG_Util::Debug::GLEnumToString(usage));
|
||||
GLenum result = MG_State::CommitBufferStorage(target, size, data, usage);
|
||||
if (result == GL_NO_ERROR)
|
||||
return;
|
||||
MG_State::SetError(result);
|
||||
MG_Util::Debug::LogE("Error from MG State: %s", MG_Util::Debug::GLEnumToString(result));
|
||||
}
|
||||
|
||||
void GetBufferParameteriv(GLenum target, GLenum pname, GLint* params) {
|
||||
MG_Util::Debug::LogD("glGetBufferParameteriv, target: %d, pname: %d, params: %p",
|
||||
target, pname, params);
|
||||
GLenum result = MG_State::QueryBufferPropertyIntVector(target, pname, params);
|
||||
if (result == GL_NO_ERROR)
|
||||
return;
|
||||
MG_State::SetError(result);
|
||||
MG_Util::Debug::LogE("GetBufferParameteriv not implemented");
|
||||
}
|
||||
|
||||
void GenBuffers(GLsizei n, GLuint* buffers) {
|
||||
MG_Util::Debug::LogD("glGenBuffers, n: %d, buffers: %p", n, buffers);
|
||||
|
||||
if (n < 0) {
|
||||
MG_State::SetError(GL_INVALID_VALUE);
|
||||
MG_Util::Debug::LogE("Invalid buffer count: %d", n);
|
||||
return;
|
||||
}
|
||||
|
||||
GLenum result = MG_State::GenBufferNames(n, buffers);
|
||||
if (result == GL_NO_ERROR) {
|
||||
MG_Util::Debug::LogD("Generated buffer names:");
|
||||
for (GLsizei i = 0; i < n; ++i) {
|
||||
MG_Util::Debug::LogD(" Buffer[%d] = %u", i, buffers[i]);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
MG_State::SetError(result);
|
||||
MG_Util::Debug::LogE("Error from MG State: %s", MG_Util::Debug::GLEnumToString(result));
|
||||
}
|
||||
|
||||
GLboolean IsBuffer(GLuint buffer) {
|
||||
MG_Util::Debug::LogD("glIsBuffer, buffer: %u", buffer);
|
||||
|
||||
if (buffer == 0) {
|
||||
return GL_FALSE;
|
||||
}
|
||||
|
||||
bool isValid = MG_State::ValidateAllocatedBufferHandle(buffer);
|
||||
// Should we report gl error here or in MG_State?
|
||||
MG_Util::Debug::LogD("Buffer %u is %s", buffer, isValid ? "valid" : "invalid");
|
||||
return isValid ? GL_TRUE : GL_FALSE;
|
||||
}
|
||||
|
||||
void BufferSubData(GLenum target, GLintptr offset, GLsizeiptr size, const void* data) {
|
||||
MG_Util::Debug::LogD("glBufferSubData, target: %s, offset: %lld, size: %lld, data: %p",
|
||||
MG_Util::Debug::GLEnumToString(target),
|
||||
static_cast<long long>(offset),
|
||||
static_cast<long long>(size),
|
||||
data);
|
||||
GLenum result = MG_State::CommitBufferStorageRegion(target, offset, size, data);
|
||||
if (result != GL_NO_ERROR) {
|
||||
MG_State::SetError(result);
|
||||
MG_Util::Debug::LogE("Error from MG State: %s", MG_Util::Debug::GLEnumToString(result));
|
||||
}
|
||||
}
|
||||
void DeleteBuffers(GLsizei n, const GLuint *buffers) {
|
||||
MG_Util::Debug::LogD("glDeleteBuffers, n: %d, buffers: %p", n, buffers);
|
||||
|
||||
GLenum result = MG_State::DeleteBuffers(n, buffers);
|
||||
if (result == GL_NO_ERROR)
|
||||
return;
|
||||
|
||||
MG_State::SetError(result);
|
||||
MG_Util::Debug::LogE("Error from MG State: %s", MG_Util::Debug::GLEnumToString(result));
|
||||
}
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
//
|
||||
// Created by BZLZHH on 2025/3/15.
|
||||
//
|
||||
|
||||
#ifndef MOBILEGL_GL_BUFFER_H
|
||||
#define MOBILEGL_GL_BUFFER_H
|
||||
|
||||
#include "../../../../Includes.h"
|
||||
|
||||
namespace MG_GL::GL {
|
||||
void* MapBufferRange(GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access);
|
||||
void FlushMappedBufferRange(GLenum target, GLintptr offset, GLsizeiptr length);
|
||||
void CopyBufferSubData(GLenum readTarget, GLenum writeTarget, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size);
|
||||
void* MapBuffer(GLenum target, GLenum access);
|
||||
GLboolean UnmapBuffer(GLenum target);
|
||||
void BindBuffer(GLenum target, GLuint buffer);
|
||||
void BufferData(GLenum target, GLsizeiptr size, const void* data, GLenum usage);
|
||||
void BufferSubData(GLenum target, GLintptr offset, GLsizeiptr size, const void* data);
|
||||
void GetBufferParameteriv(GLenum target, GLenum pname, GLint* params);
|
||||
void GenBuffers(GLsizei n, GLuint* buffers);
|
||||
void DeleteBuffers(GLsizei n, const GLuint *buffers);
|
||||
GLboolean IsBuffer(GLuint buffer);
|
||||
}
|
||||
|
||||
#endif //MOBILEGL_GL_BUFFER_H
|
||||
@@ -1,103 +0,0 @@
|
||||
//
|
||||
// Created by BZLZHH on 2025/3/15.
|
||||
//
|
||||
|
||||
#include "GL_Common.h"
|
||||
|
||||
namespace MG_GL::GL {
|
||||
void Enable(GLenum cap) {
|
||||
MG_Util::Debug::LogD("glEnable, cap: %s", MG_Util::Debug::GLEnumToString(cap));
|
||||
GLenum result = MG_State::glEnable(cap);
|
||||
if (result == GL_NO_ERROR) return;
|
||||
MG_State::SetError(result);
|
||||
MG_Util::Debug::LogE("Error enabling capability: %s", MG_Util::Debug::GLEnumToString(result));
|
||||
}
|
||||
|
||||
void Disable(GLenum cap) {
|
||||
MG_Util::Debug::LogD("glDisable, cap: %s", MG_Util::Debug::GLEnumToString(cap));
|
||||
GLenum result = MG_State::glDisable(cap);
|
||||
if (result == GL_NO_ERROR) return;
|
||||
MG_State::SetError(result);
|
||||
MG_Util::Debug::LogE("Error disabling capability: %s", MG_Util::Debug::GLEnumToString(result));
|
||||
}
|
||||
|
||||
void BlendFunc(GLenum sfactor, GLenum dfactor) {
|
||||
MG_Util::Debug::LogD("glBlendFunc, sfactor: %s, dfactor: %s",
|
||||
MG_Util::Debug::GLEnumToString(sfactor),
|
||||
MG_Util::Debug::GLEnumToString(dfactor));
|
||||
GLenum result = MG_State::glBlendFunc(sfactor, dfactor);
|
||||
if (result == GL_NO_ERROR) return;
|
||||
MG_State::SetError(result);
|
||||
MG_Util::Debug::LogE("Error setting blend func: %s", MG_Util::Debug::GLEnumToString(result));
|
||||
}
|
||||
|
||||
void BlendFuncSeparate(GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha) {
|
||||
MG_Util::Debug::LogD("glBlendFuncSeparate, srcRGB: %s, dstRGB: %s, srcAlpha: %s, dstAlpha: %s",
|
||||
MG_Util::Debug::GLEnumToString(srcRGB),
|
||||
MG_Util::Debug::GLEnumToString(dstRGB),
|
||||
MG_Util::Debug::GLEnumToString(srcAlpha),
|
||||
MG_Util::Debug::GLEnumToString(dstAlpha));
|
||||
GLenum result = MG_State::glBlendFuncSeparate(srcRGB, dstRGB, srcAlpha, dstAlpha);
|
||||
if (result == GL_NO_ERROR) return;
|
||||
MG_State::SetError(result);
|
||||
MG_Util::Debug::LogE("Error setting separate blend func: %s", MG_Util::Debug::GLEnumToString(result));
|
||||
}
|
||||
|
||||
void ClearColor(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha) {
|
||||
MG_Util::Debug::LogD("glClearColor, rgba: [%.2f, %.2f, %.2f, %.2f]", red, green, blue, alpha);
|
||||
GLenum result = MG_State::glClearColor(red, green, blue, alpha);
|
||||
if (result == GL_NO_ERROR) return;
|
||||
MG_State::SetError(result);
|
||||
MG_Util::Debug::LogE("Error setting clear color: %s", MG_Util::Debug::GLEnumToString(result));
|
||||
}
|
||||
|
||||
void ClearDepth(GLdouble depth) {
|
||||
MG_Util::Debug::LogD("glClearDepth, depth: %.3f", depth);
|
||||
GLenum result = MG_State::glClearDepth(depth);
|
||||
if (result == GL_NO_ERROR) return;
|
||||
MG_State::SetError(result);
|
||||
MG_Util::Debug::LogE("Error setting clear depth: %s", MG_Util::Debug::GLEnumToString(result));
|
||||
}
|
||||
|
||||
void ColorMask(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha) {
|
||||
MG_Util::Debug::LogD("glColorMask, rgba: [%d, %d, %d, %d]", red, green, blue, alpha);
|
||||
GLenum result = MG_State::glColorMask(red, green, blue, alpha);
|
||||
if (result == GL_NO_ERROR) return;
|
||||
MG_State::SetError(result);
|
||||
MG_Util::Debug::LogE("Error setting color mask: %s", MG_Util::Debug::GLEnumToString(result));
|
||||
}
|
||||
|
||||
void DepthFunc(GLenum func) {
|
||||
MG_Util::Debug::LogD("glDepthFunc, func: %s", MG_Util::Debug::GLEnumToString(func));
|
||||
GLenum result = MG_State::glDepthFunc(func);
|
||||
if (result == GL_NO_ERROR) return;
|
||||
MG_State::SetError(result);
|
||||
MG_Util::Debug::LogE("Error setting depth func: %s", MG_Util::Debug::GLEnumToString(result));
|
||||
}
|
||||
|
||||
void DepthMask(GLboolean flag) {
|
||||
MG_Util::Debug::LogD("glDepthMask, flag: %d", flag);
|
||||
GLenum result = MG_State::glDepthMask(flag);
|
||||
if (result == GL_NO_ERROR) return;
|
||||
MG_State::SetError(result);
|
||||
MG_Util::Debug::LogE("Error setting depth mask: %s", MG_Util::Debug::GLEnumToString(result));
|
||||
}
|
||||
|
||||
void Viewport(GLint x, GLint y, GLsizei width, GLsizei height) {
|
||||
MG_Util::Debug::LogD("glViewport, x: %d, y: %d, width: %d, height: %d",
|
||||
x, y, width, height);
|
||||
GLenum result = MG_State::glViewport(x, y, width, height);
|
||||
if (result == GL_NO_ERROR) return;
|
||||
MG_State::SetError(result);
|
||||
MG_Util::Debug::LogE("Error setting viewport: %s", MG_Util::Debug::GLEnumToString(result));
|
||||
}
|
||||
|
||||
void PixelStorei(GLenum pname, GLint param) {
|
||||
MG_Util::Debug::LogD("glPixelStorei, pname: %d, param: %d", pname, param);
|
||||
GLenum result = MG_State::SetPixelStoreInt(pname,param);
|
||||
if (result == GL_NO_ERROR)
|
||||
return;
|
||||
MG_State::SetError(result);
|
||||
MG_Util::Debug::LogE("Error from MG State: %s", MG_Util::Debug::GLEnumToString(result));
|
||||
}
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
//
|
||||
// Created by BZLZHH on 2025/3/15.
|
||||
//
|
||||
|
||||
#ifndef MOBILEGL_GL_COMMON_H
|
||||
#define MOBILEGL_GL_COMMON_H
|
||||
|
||||
#include "../../../../Includes.h"
|
||||
|
||||
namespace MG_GL::GL {
|
||||
void ClearDepth(GLdouble depth);
|
||||
void ClearColor(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha);
|
||||
void Clear(GLbitfield mask);
|
||||
void PixelStorei(GLenum pname, GLint param);
|
||||
void Enable(GLenum cap);
|
||||
void Disable(GLenum cap);
|
||||
void BlendFunc(GLenum sfactor, GLenum dfactor);
|
||||
void BlendFuncSeparate(GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha);
|
||||
void ColorMask(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha);
|
||||
void DepthFunc(GLenum func);
|
||||
void DepthMask(GLboolean flag);
|
||||
void Viewport(GLint x, GLint y, GLsizei width, GLsizei height);
|
||||
}
|
||||
|
||||
#endif //MOBILEGL_GL_COMMON_H
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,17 +0,0 @@
|
||||
//
|
||||
// Created by BZLZHH on 2025/3/15.
|
||||
//
|
||||
|
||||
#ifndef MOBILEGL_GL_DRAWING_H
|
||||
#define MOBILEGL_GL_DRAWING_H
|
||||
#include "../../../../Includes.h"
|
||||
namespace MG_GL::GL {
|
||||
void DrawElements(GLenum mode, GLsizei count, GLenum type, const void *indices);
|
||||
void DrawArrays(GLenum mode, GLint first, GLsizei count);
|
||||
void DrawElementsBaseVertex(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices, GLint basevertex);
|
||||
void MultiDrawElements(GLenum mode, const GLsizei *count, GLenum type, const GLvoid *const *indices, GLsizei drawcount);
|
||||
void MultiDrawElementsBaseVertex(GLenum mode, const GLsizei *count, GLenum type, const GLvoid *const *indices, GLsizei drawcount, const GLint *basevertex);
|
||||
void DrawBuffer(GLenum buf);
|
||||
}
|
||||
|
||||
#endif //MOBILEGL_GL_DRAWING_H
|
||||
@@ -1,68 +0,0 @@
|
||||
//
|
||||
// Created by BZLZHH on 2025/3/15.
|
||||
//
|
||||
|
||||
#include "GL_Framebuffer.h"
|
||||
|
||||
namespace MG_GL::GL {
|
||||
void GenFramebuffers(GLsizei n, GLuint* framebuffers) {
|
||||
MG_Util::Debug::LogD("glGenFramebuffers, n: %d, framebuffers: %p", n, framebuffers);
|
||||
GLenum result = MG_State::CreateFramebuffers(n, framebuffers);
|
||||
if (result == GL_NO_ERROR) return;
|
||||
MG_State::SetError(result);
|
||||
MG_Util::Debug::LogE("Framebuffer generation failed: %s", MG_Util::Debug::GLEnumToString(result));
|
||||
}
|
||||
|
||||
void DeleteFramebuffers(GLsizei n, const GLuint* framebuffers) {
|
||||
MG_Util::Debug::LogD("glDeleteFramebuffers, n: %d, framebuffers: %p", n, framebuffers);
|
||||
for (GLsizei i = 0; i < n; ++i) {
|
||||
GLenum result = MG_State::DeleteFramebuffer(framebuffers[i]);
|
||||
if (result != GL_NO_ERROR) {
|
||||
MG_State::SetError(result);
|
||||
MG_Util::Debug::LogE("Failed to delete framebuffer %u: %s",
|
||||
framebuffers[i], MG_Util::Debug::GLEnumToString(result));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void BindFramebuffer(GLenum target, GLuint framebuffer) {
|
||||
MG_Util::Debug::LogD("glBindFramebuffer, target: %s, fb: %u",
|
||||
MG_Util::Debug::GLEnumToString(target), framebuffer);
|
||||
GLenum result = MG_State::BindFramebuffer(target, framebuffer);
|
||||
if (result == GL_NO_ERROR) return;
|
||||
MG_State::SetError(result);
|
||||
MG_Util::Debug::LogE("Framebuffer bind error: %s", MG_Util::Debug::GLEnumToString(result));
|
||||
}
|
||||
|
||||
void FramebufferTexture2D(GLenum target, GLenum attachment, GLenum textarget,
|
||||
GLuint texture, GLint level) {
|
||||
MG_Util::Debug::LogD("glFramebufferTexture2D, target: %s, attach: %s, textarget: %s, tex: %u, level: %d",
|
||||
MG_Util::Debug::GLEnumToString(target),
|
||||
MG_Util::Debug::GLEnumToString(attachment),
|
||||
MG_Util::Debug::GLEnumToString(textarget),
|
||||
texture, level);
|
||||
|
||||
GLenum result = MG_State::AttachTexture2DToFramebuffer(
|
||||
target, attachment, textarget, texture, level
|
||||
);
|
||||
|
||||
if (result == GL_NO_ERROR) return;
|
||||
MG_State::SetError(result);
|
||||
MG_Util::Debug::LogE("Texture attachment failed: %s", MG_Util::Debug::GLEnumToString(result));
|
||||
}
|
||||
|
||||
GLenum CheckFramebufferStatus(GLenum target) {
|
||||
MG_Util::Debug::LogD("glCheckFramebufferStatus, target: %s",
|
||||
MG_Util::Debug::GLEnumToString(target));
|
||||
GLenum result = MG_State::ValidateFramebufferCompleteness(target);
|
||||
if (result >= GL_FRAMEBUFFER_COMPLETE) {
|
||||
MG_Util::Debug::LogD("Framebuffer status: %s",
|
||||
MG_Util::Debug::GLEnumToString(result));
|
||||
return result;
|
||||
}
|
||||
MG_State::SetError(result);
|
||||
MG_Util::Debug::LogE("Framebuffer incomplete: %s",
|
||||
MG_Util::Debug::GLEnumToString(result));
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
//
|
||||
// Created by BZLZHH on 2025/3/15.
|
||||
//
|
||||
|
||||
#ifndef MOBILEGL_GL_FRAMEBUFFER_H
|
||||
#define MOBILEGL_GL_FRAMEBUFFER_H
|
||||
|
||||
#include "../../../../Includes.h"
|
||||
|
||||
namespace MG_GL::GL {
|
||||
void GenFramebuffers(GLsizei n, GLuint* framebuffers);
|
||||
void DeleteFramebuffers(GLsizei n, const GLuint* framebuffers);
|
||||
void BindFramebuffer(GLenum target, GLuint framebuffer);
|
||||
void FramebufferTexture2D(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level);
|
||||
GLenum CheckFramebufferStatus(GLenum target);
|
||||
void BlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter);
|
||||
}
|
||||
|
||||
#endif //MOBILEGL_GL_FRAMEBUFFER_H
|
||||
@@ -1,10 +0,0 @@
|
||||
//
|
||||
// Created by BZLZHH on 2025/3/15.
|
||||
//
|
||||
|
||||
#ifndef MOBILEGL_GL_FUNCS_DEFINITIONS_H
|
||||
#define MOBILEGL_GL_FUNCS_DEFINITIONS_H
|
||||
|
||||
#include "../../../../Includes.h"
|
||||
|
||||
#endif //MOBILEGL_GL_FUNCS_DEFINITIONS_H
|
||||
@@ -1,93 +0,0 @@
|
||||
//
|
||||
// Created by BZLZHH on 2025/3/15.
|
||||
//
|
||||
|
||||
#include "BackendInfo.h"
|
||||
|
||||
namespace MG_GL::Getter {
|
||||
const std::string GetBackendName() {
|
||||
#if BACKEND_TYPE == BACKEND_VULKAN
|
||||
return "Vulkan";
|
||||
#elif BACKEND_TYPE == BACKEND_METAL
|
||||
return "Metal";
|
||||
#elif BACKEND_TYPE == BACKEND_GLES
|
||||
return "OpenGL ES";
|
||||
#else
|
||||
return "<Unknown Backend>";
|
||||
#endif
|
||||
}
|
||||
|
||||
const std::string GetMGName() {
|
||||
#if BACKEND_TYPE == BACKEND_VULKAN
|
||||
return "MobileGluvk";
|
||||
#elif BACKEND_TYPE == BACKEND_METAL
|
||||
return "MobileGlumtl";
|
||||
#elif BACKEND_TYPE == BACKEND_GLES
|
||||
return "MobileGlues";
|
||||
#else
|
||||
return "<Unknown MobileGL Version>";
|
||||
#endif
|
||||
}
|
||||
|
||||
void LogMGInfo() {
|
||||
std::string MGName = MG_GL::Getter::GetMGName() + " (MobileGL Core)";
|
||||
|
||||
std::string MGVersion = std::to_string(MG_Global::MG::VersionMajor) + "."
|
||||
+ std::to_string(MG_Global::MG::VersionMinor) + "."
|
||||
+ std::to_string(MG_Global::MG::VersionRevision);
|
||||
if (MG_Global::MG::VersionPatch != 0)
|
||||
MGVersion += "." + std::to_string(MG_Global::MG::VersionPatch);
|
||||
MGVersion += MG_Global::MG::VersionSuffix;
|
||||
|
||||
std::string GLVersion = std::to_string(MG_Global::GL::GLVersionMajor) + "."
|
||||
+ std::to_string(MG_Global::GL::GLVersionMinor) + "."
|
||||
+ std::to_string(MG_Global::GL::GLVersionRevision);
|
||||
|
||||
std::string backendName = MG_GL::Getter::GetBackendName();
|
||||
|
||||
std::string backendVersion;
|
||||
#if BACKEND_TYPE == BACKEND_VULKAN
|
||||
VkApplicationInfo appInfo = {};
|
||||
appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
|
||||
appInfo.pApplicationName = "Vulkan Version Query";
|
||||
appInfo.applicationVersion = VK_MAKE_VERSION(1, 0, 0);
|
||||
appInfo.pEngineName = "No Engine";
|
||||
appInfo.engineVersion = VK_MAKE_VERSION(1, 0, 0);
|
||||
appInfo.apiVersion = VK_API_VERSION_1_0;
|
||||
VkInstanceCreateInfo createInfo = {};
|
||||
createInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
|
||||
createInfo.pApplicationInfo = &appInfo;
|
||||
VkInstance instance;
|
||||
if (vkCreateInstance(&createInfo, nullptr, &instance) != VK_SUCCESS) {
|
||||
throw std::runtime_error("Failed to create Vulkan instance!");
|
||||
}
|
||||
uint32_t deviceCount = 0;
|
||||
vkEnumeratePhysicalDevices(instance, &deviceCount, nullptr);
|
||||
if (deviceCount == 0) {
|
||||
throw std::runtime_error("No Vulkan devices found!");
|
||||
}
|
||||
VkPhysicalDevice physicalDevice;
|
||||
vkEnumeratePhysicalDevices(instance, &deviceCount, &physicalDevice);
|
||||
VkPhysicalDeviceProperties deviceProperties;
|
||||
vkGetPhysicalDeviceProperties(physicalDevice, &deviceProperties);
|
||||
uint32_t major = VK_VERSION_MAJOR(deviceProperties.apiVersion);
|
||||
uint32_t minor = VK_VERSION_MINOR(deviceProperties.apiVersion);
|
||||
uint32_t patch = VK_VERSION_PATCH(deviceProperties.apiVersion);
|
||||
vkDestroyInstance(instance, nullptr);
|
||||
|
||||
backendVersion = "Vulkan " + std::to_string(major) + "." +
|
||||
std::to_string(minor)+"." + std::to_string(patch);
|
||||
#elif BACKEND_TYPE == BACKEND_GLES
|
||||
backendVersion = std::string((const char*)::GLES::glGetString(GL_VERSION));
|
||||
#else
|
||||
backendVersion = "<Unknown Backend>";
|
||||
#endif
|
||||
|
||||
MG_Util::Debug::LogI("MobileGL Renderer Info:");
|
||||
MG_Util::Debug::LogI("----%s:", MGName.c_str());
|
||||
MG_Util::Debug::LogI("--------MobileGL Version: %s", MGVersion.c_str());
|
||||
MG_Util::Debug::LogI("--------Target OpenGL Implementation Version: %s", GLVersion.c_str());
|
||||
MG_Util::Debug::LogI("--------Backend: %s", backendName.c_str());
|
||||
MG_Util::Debug::LogI("--------Backend Version: %s", backendVersion.c_str());
|
||||
}
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
//
|
||||
// Created by BZLZHH on 2025/3/15.
|
||||
//
|
||||
|
||||
#ifndef MOBILEGL_BACKENDINFO_H
|
||||
#define MOBILEGL_BACKENDINFO_H
|
||||
|
||||
#include "../../../../Includes.h"
|
||||
|
||||
namespace MG_GL::Getter {
|
||||
const std::string GetBackendName();
|
||||
const std::string GetMGName();
|
||||
void LogMGInfo();
|
||||
}
|
||||
|
||||
#endif //MOBILEGL_BACKENDINFO_H
|
||||
@@ -1,320 +0,0 @@
|
||||
//
|
||||
// Created by BZLZHH on 2025/3/15.
|
||||
//
|
||||
|
||||
#include "GL_Getter.h"
|
||||
|
||||
namespace MG_GL::GL {
|
||||
static std::string rendererString;
|
||||
static bool loggedMGInfo;
|
||||
const GLubyte* GetString(GLenum name) {
|
||||
if (!loggedMGInfo) {
|
||||
loggedMGInfo = true;
|
||||
MG_GL::Getter::LogMGInfo();
|
||||
}
|
||||
MG_Util::Debug::LogD("glGetString, name: %s", MG_Util::Debug::GLEnumToString(name));
|
||||
switch (name) {
|
||||
case GL_VENDOR:
|
||||
return (const GLubyte *)"MobileGL-Dev";
|
||||
case GL_VERSION: {
|
||||
static std::string versionStr;
|
||||
if (versionStr.empty()) {
|
||||
versionStr = std::to_string(MG_Global::GL::GLVersionMajor) + "."
|
||||
+ std::to_string(MG_Global::GL::GLVersionMinor) + "."
|
||||
+ std::to_string(MG_Global::GL::GLVersionRevision)
|
||||
+ " "+ MG_GL::Getter::GetMGName() +
|
||||
", MobileGL Core, " + MG_GL::Getter::GetBackendName() + " Backend, Version "
|
||||
+ std::to_string(MG_Global::MG::VersionMajor) + "."
|
||||
+ std::to_string(MG_Global::MG::VersionMinor) + "."
|
||||
+ std::to_string(MG_Global::MG::VersionRevision);
|
||||
if (MG_Global::MG::VersionPatch != 0)
|
||||
versionStr += "." + std::to_string(MG_Global::MG::VersionPatch);
|
||||
versionStr += MG_Global::MG::VersionSuffix;
|
||||
}
|
||||
return (const GLubyte *)versionStr.c_str();
|
||||
}
|
||||
|
||||
case GL_RENDERER:
|
||||
{
|
||||
/*
|
||||
if (rendererString == std::string("")) {
|
||||
const char* gpuName = getGpuName();
|
||||
const char* glesName = getGLESName();
|
||||
rendererString = std::string(gpuName) + " | " + std::string(glesName);
|
||||
}
|
||||
return (const GLubyte *)rendererString.c_str();
|
||||
*/
|
||||
return (const GLubyte *)(MG_GL::Getter::GetMGName() + " (MobileGL Core) Renderer").c_str();
|
||||
}
|
||||
case GL_SHADING_LANGUAGE_VERSION:
|
||||
return (const GLubyte *) "4.50 MobileGL with glslang";
|
||||
case GL_EXTENSIONS:
|
||||
return (const GLubyte *) "OpenGL11 "
|
||||
"OpenGL12 "
|
||||
"OpenGL13 "
|
||||
"OpenGL14 "
|
||||
"OpenGL15 "
|
||||
"OpenGL20 "
|
||||
"OpenGL21 "
|
||||
"OpenGL30 ";
|
||||
default:
|
||||
return (const GLubyte *) "Unknown enum";
|
||||
}
|
||||
}
|
||||
|
||||
const GLubyte* GetStringi(GLenum name, GLuint index) {
|
||||
MG_Util::Debug::LogD("glGetStringi, name: %s, index: %d", MG_Util::Debug::GLEnumToString(name), index);
|
||||
if (name != GL_EXTENSIONS)
|
||||
return (const GLubyte*)"";
|
||||
typedef struct {
|
||||
GLenum name;
|
||||
const char** parts;
|
||||
GLuint count;
|
||||
} StringCache;
|
||||
static StringCache caches[] = {
|
||||
{GL_EXTENSIONS, nullptr, 0},
|
||||
};
|
||||
static int initialized = 0;
|
||||
if (!initialized) {
|
||||
for (auto & cache : caches) {
|
||||
GLenum target = cache.name;
|
||||
const GLubyte* str = nullptr;
|
||||
const char* delimiter = " ";
|
||||
str = GetString(GL_EXTENSIONS);
|
||||
|
||||
char* copy = strdup((const char*)str);
|
||||
char* token = strtok(copy, delimiter);
|
||||
while (token) {
|
||||
cache.parts = (const char**)realloc(cache.parts, (cache.count + 1) * sizeof(char*));
|
||||
cache.parts[cache.count++] = strdup(token);
|
||||
token = strtok(nullptr, delimiter);
|
||||
}
|
||||
free(copy);
|
||||
}
|
||||
initialized = 1;
|
||||
}
|
||||
|
||||
for (auto & cache : caches) {
|
||||
if (cache.name == name) {
|
||||
if (index >= cache.count) {
|
||||
return nullptr;
|
||||
}
|
||||
return (const GLubyte*)cache.parts[index];
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
GLenum GetError() {
|
||||
GLenum error = MG_State::GetError();
|
||||
MG_Util::Debug::LogD("glGetError -> %s", MG_Util::Debug::GLEnumToString(error));
|
||||
return error;
|
||||
}
|
||||
|
||||
void GetIntegerv(GLenum pname, GLint *params) {
|
||||
MG_Util::Debug::LogD("glGetIntegerv, pname: %s", MG_Util::Debug::GLEnumToString(pname));
|
||||
if (!params) {
|
||||
MG_State::SetError(GL_INVALID_VALUE);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (pname) {
|
||||
// General
|
||||
case GL_CONTEXT_PROFILE_MASK:
|
||||
params[0] = GL_CONTEXT_CORE_PROFILE_BIT;
|
||||
break;
|
||||
case GL_NUM_EXTENSIONS:
|
||||
static GLint num_extensions = -1;
|
||||
if (num_extensions == -1) {
|
||||
const GLubyte* ext_str = MG_GL::GL::GetString(GL_EXTENSIONS);
|
||||
char *copy = strdup((const char *) ext_str);
|
||||
char *token = strtok(copy, " ");
|
||||
num_extensions = 0;
|
||||
while (token) {
|
||||
num_extensions++;
|
||||
token = strtok(nullptr, " ");
|
||||
}
|
||||
free(copy);
|
||||
}
|
||||
params[0] = num_extensions;
|
||||
break;
|
||||
case GL_MAJOR_VERSION:
|
||||
params[0] = MG_Global::GL::GLVersionMajor;
|
||||
break;
|
||||
case GL_MINOR_VERSION:
|
||||
params[0] = MG_Global::GL::GLVersionMinor;
|
||||
break;
|
||||
|
||||
// Viewport and scissor
|
||||
case GL_VIEWPORT:
|
||||
memcpy(params, MG_State_T::commonState->viewport, 4 * sizeof(GLint));
|
||||
break;
|
||||
case GL_SCISSOR_BOX:
|
||||
// TODO: memcpy(params, MG_State_T::commonState->scissorBox, 4 * sizeof(GLint));
|
||||
break;
|
||||
case GL_MAX_VIEWPORT_DIMS: {
|
||||
static const GLint maxDims[2] = {16384, 16384};
|
||||
memcpy(params, maxDims, sizeof(maxDims));
|
||||
break;
|
||||
}
|
||||
|
||||
// Buffer bindings
|
||||
case GL_ARRAY_BUFFER_BINDING:
|
||||
params[0] = static_cast<GLint>(MG_State_T::bufferState->GetCurrentBinding(GL_ARRAY_BUFFER));
|
||||
break;
|
||||
|
||||
case GL_ELEMENT_ARRAY_BUFFER_BINDING:
|
||||
params[0] = static_cast<GLint>(MG_State_T::vertexArrayState->GetBoundElementBuffer());
|
||||
break;
|
||||
case GL_DRAW_FRAMEBUFFER_BINDING:
|
||||
params[0] = static_cast<GLint>(MG_State_T::framebufferState->currentBindings_[GL_DRAW_FRAMEBUFFER]);
|
||||
break;
|
||||
case GL_READ_FRAMEBUFFER_BINDING:
|
||||
params[0] = static_cast<GLint>(MG_State_T::framebufferState->currentBindings_[GL_READ_FRAMEBUFFER]);
|
||||
break;
|
||||
case GL_RENDERBUFFER_BINDING:
|
||||
// TODO: params[0] = static_cast<GLint>(MG_State_T::framebufferState->currentRenderbuffer_);
|
||||
break;
|
||||
|
||||
// Program state
|
||||
case GL_CURRENT_PROGRAM:
|
||||
params[0] = static_cast<GLint>(MG_State_T::programState->currentProgram_);
|
||||
break;
|
||||
case GL_MAX_VERTEX_ATTRIBS:
|
||||
// TODO: Check the real value
|
||||
params[0] = 64;
|
||||
break;
|
||||
|
||||
// Texture state
|
||||
case GL_TEXTURE_BINDING_2D: {
|
||||
GLuint unit = MG_State_T::textureState->activeTextureUnit_;
|
||||
auto& textures = MG_State_T::textureState->textureUnits_[unit].boundTextures;
|
||||
params[0] = textures.count(GL_TEXTURE_2D) ? static_cast<GLint>(textures[GL_TEXTURE_2D]) : 0;
|
||||
break;
|
||||
}
|
||||
case GL_ACTIVE_TEXTURE:
|
||||
params[0] = GL_TEXTURE0 + MG_State_T::textureState->activeTextureUnit_;
|
||||
break;
|
||||
case GL_MAX_TEXTURE_SIZE:
|
||||
params[0] = 8192;
|
||||
break;
|
||||
|
||||
// Blend state
|
||||
case GL_BLEND_SRC_RGB:
|
||||
params[0] = static_cast<GLint>(MG_State_T::commonState->blendSrcRGB);
|
||||
break;
|
||||
case GL_BLEND_DST_RGB:
|
||||
params[0] = static_cast<GLint>(MG_State_T::commonState->blendDstRGB);
|
||||
break;
|
||||
case GL_BLEND_SRC_ALPHA:
|
||||
params[0] = static_cast<GLint>(MG_State_T::commonState->blendSrcAlpha);
|
||||
break;
|
||||
case GL_BLEND_DST_ALPHA:
|
||||
params[0] = static_cast<GLint>(MG_State_T::commonState->blendDstAlpha);
|
||||
break;
|
||||
|
||||
// Depth and stencil
|
||||
case GL_DEPTH_FUNC:
|
||||
params[0] = static_cast<GLint>(MG_State_T::commonState->depthFunc);
|
||||
break;
|
||||
case GL_DEPTH_WRITEMASK:
|
||||
params[0] = static_cast<GLint>(MG_State_T::commonState->depthMask);
|
||||
break;
|
||||
case GL_STENCIL_REF:
|
||||
// TODO: params[0] = MG_State_T::commonState->stencilRef;
|
||||
break;
|
||||
|
||||
// Capability enables
|
||||
case GL_BLEND:
|
||||
params[0] = MG_State_T::commonState->capabilities[GL_BLEND] ? GL_TRUE : GL_FALSE;
|
||||
break;
|
||||
case GL_DEPTH_TEST:
|
||||
params[0] = MG_State_T::commonState->capabilities[GL_DEPTH_TEST] ? GL_TRUE : GL_FALSE;
|
||||
break;
|
||||
case GL_SCISSOR_TEST:
|
||||
params[0] = MG_State_T::commonState->capabilities[GL_SCISSOR_TEST] ? GL_TRUE : GL_FALSE;
|
||||
break;
|
||||
|
||||
// Pixel operations
|
||||
case GL_PACK_ALIGNMENT:
|
||||
params[0] = MG_State_T::commonState->QueryPixelStoreInt(GL_PACK_ALIGNMENT);
|
||||
break;
|
||||
case GL_UNPACK_ALIGNMENT:
|
||||
params[0] = MG_State_T::commonState->QueryPixelStoreInt(GL_UNPACK_ALIGNMENT);
|
||||
break;
|
||||
|
||||
// Hardware limits, TODO: Check the real values
|
||||
case GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS:
|
||||
params[0] = 32;
|
||||
break;
|
||||
case GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS:
|
||||
params[0] = 32;
|
||||
break;
|
||||
case GL_MAX_TEXTURE_IMAGE_UNITS:
|
||||
params[0] = 32;
|
||||
break;
|
||||
case GL_MAX_RENDERBUFFER_SIZE:
|
||||
params[0] = 65537;
|
||||
break;
|
||||
case GL_MAX_DRAW_BUFFERS:
|
||||
params[0] = 32;
|
||||
break;
|
||||
case GL_MAX_COLOR_ATTACHMENTS:
|
||||
params[0] = 32;
|
||||
break;
|
||||
|
||||
// Color state
|
||||
case GL_COLOR_CLEAR_VALUE: {
|
||||
const auto& c = MG_State_T::commonState->clearColor;
|
||||
params[0] = static_cast<GLint>(c[0] * 0x7FFF);
|
||||
params[1] = static_cast<GLint>(c[1] * 0x7FFF);
|
||||
params[2] = static_cast<GLint>(c[2] * 0x7FFF);
|
||||
params[3] = static_cast<GLint>(c[3] * 0x7FFF);
|
||||
break;
|
||||
}
|
||||
case GL_COLOR_WRITEMASK:
|
||||
params[0] = MG_State_T::commonState->colorMask[0];
|
||||
params[1] = MG_State_T::commonState->colorMask[1];
|
||||
params[2] = MG_State_T::commonState->colorMask[2];
|
||||
params[3] = MG_State_T::commonState->colorMask[3];
|
||||
break;
|
||||
|
||||
// Stencil operations
|
||||
case GL_STENCIL_CLEAR_VALUE:
|
||||
// TODO: params[0] = MG_State_T::commonState->stencilClearValue;
|
||||
break;
|
||||
case GL_STENCIL_BITS:
|
||||
// TODO: Check the real value
|
||||
params[0] = 8;
|
||||
break;
|
||||
|
||||
// Implementation limits
|
||||
case GL_SUBPIXEL_BITS:
|
||||
// TODO: Check the real value
|
||||
params[0] = 4;
|
||||
break;
|
||||
case GL_NUM_COMPRESSED_TEXTURE_FORMATS:
|
||||
// TODO: params[0] = static_cast<GLint>(MG_State_T::textureState->compressedFormats_.size());
|
||||
break;
|
||||
case GL_COMPRESSED_TEXTURE_FORMATS:
|
||||
// TODO: Implement GL_COMPRESSED_TEXTURE_FORMATS
|
||||
break;
|
||||
|
||||
// Polygon state
|
||||
case GL_POLYGON_OFFSET_FACTOR:
|
||||
// TODO: params[0] = static_cast<GLint>(MG_State_T::commonState->polygonOffsetFactor);
|
||||
break;
|
||||
case GL_POLYGON_OFFSET_UNITS:
|
||||
// TODO: params[0] = static_cast<GLint>(MG_State_T::commonState->polygonOffsetUnits);
|
||||
break;
|
||||
|
||||
// Others...
|
||||
default:
|
||||
MG_Util::Debug::LogE("glGetIntegerv: Invalid enum %s (0x%X)", MG_Util::Debug::GLEnumToString(pname), pname);
|
||||
MG_State::SetError(GL_INVALID_ENUM);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
//
|
||||
// Created by BZLZHH on 2025/3/15.
|
||||
//
|
||||
|
||||
#ifndef MOBILEGL_GL_GETTER_H
|
||||
#define MOBILEGL_GL_GETTER_H
|
||||
|
||||
#include "../../../../Includes.h"
|
||||
|
||||
namespace MG_GL::GL {
|
||||
const GLubyte* GetString(GLenum name);
|
||||
const GLubyte* GetStringi(GLenum name, GLuint index);
|
||||
GLenum GetError();
|
||||
void GetIntegerv(GLenum pname, GLint *params);
|
||||
}
|
||||
|
||||
#endif //MOBILEGL_GL_GETTER_H
|
||||
@@ -1,298 +0,0 @@
|
||||
//
|
||||
// Created by BZLZHH on 2025/3/15.
|
||||
//
|
||||
|
||||
#include "GL_Program.h"
|
||||
|
||||
namespace MG_GL::GL {
|
||||
GLuint CreateShader(GLenum type) {
|
||||
MG_Util::Debug::LogD("glCreateShader, type: %s", MG_Util::Debug::GLEnumToString(type));
|
||||
GLuint shader;
|
||||
GLenum result = MG_State::CreateShader(type, &shader);
|
||||
if (result == GL_NO_ERROR) {
|
||||
MG_Util::Debug::LogD("Created shader ID: %u", shader);
|
||||
return shader;
|
||||
}
|
||||
MG_State::SetError(result);
|
||||
MG_Util::Debug::LogE("Error creating shader: %s", MG_Util::Debug::GLEnumToString(result));
|
||||
return 0;
|
||||
}
|
||||
|
||||
GLuint CreateProgram() {
|
||||
MG_Util::Debug::LogD("glCreateProgram");
|
||||
GLuint program;
|
||||
GLenum result = MG_State::CreateProgram(&program);
|
||||
if (result == GL_NO_ERROR) {
|
||||
MG_Util::Debug::LogD("Created program ID: %u", program);
|
||||
return program;
|
||||
}
|
||||
MG_State::SetError(result);
|
||||
MG_Util::Debug::LogE("Error creating program: %s", MG_Util::Debug::GLEnumToString(result));
|
||||
return 0;
|
||||
}
|
||||
|
||||
void DeleteShader(GLuint shader) {
|
||||
MG_Util::Debug::LogD("glDeleteShader, shader: %u", shader);
|
||||
GLenum result = MG_State::DeleteShader(shader);
|
||||
if (result == GL_NO_ERROR) return;
|
||||
MG_State::SetError(result);
|
||||
MG_Util::Debug::LogE("Error deleting shader: %s", MG_Util::Debug::GLEnumToString(result));
|
||||
}
|
||||
|
||||
void DeleteProgram(GLuint program) {
|
||||
MG_Util::Debug::LogD("glDeleteProgram, program: %u", program);
|
||||
GLenum result = MG_State::DeleteProgram(program);
|
||||
if (result == GL_NO_ERROR) return;
|
||||
MG_State::SetError(result);
|
||||
MG_Util::Debug::LogE("Error deleting program: %s", MG_Util::Debug::GLEnumToString(result));
|
||||
}
|
||||
|
||||
void AttachShader(GLuint program, GLuint shader) {
|
||||
MG_Util::Debug::LogD("glAttachShader, program: %u, shader: %u", program, shader);
|
||||
GLenum result = MG_State::LinkShaderToProgram(program, shader);
|
||||
if (result == GL_NO_ERROR) return;
|
||||
MG_State::SetError(result);
|
||||
MG_Util::Debug::LogE("Error attaching shader: %s", MG_Util::Debug::GLEnumToString(result));
|
||||
}
|
||||
|
||||
void ShaderSource(GLuint shader, GLsizei count, const GLchar *const*string, const GLint* length) {
|
||||
MG_Util::Debug::LogD("glShaderSource, shader: %u, count: %d", shader, count);
|
||||
GLenum result = MG_State::UploadShaderSource(shader, count, (const GLchar **)string, length);
|
||||
if (result == GL_NO_ERROR) return;
|
||||
MG_State::SetError(result);
|
||||
MG_Util::Debug::LogE("Error setting shader source: %s", MG_Util::Debug::GLEnumToString(result));
|
||||
}
|
||||
|
||||
void CompileShader(GLuint shader) {
|
||||
MG_Util::Debug::LogD("glCompileShader, shader: %u", shader);
|
||||
GLenum result = MG_State::BuildShaderStage(shader);
|
||||
if (result == GL_NO_ERROR) return;
|
||||
MG_State::SetError(result);
|
||||
MG_Util::Debug::LogE("Error compiling shader: %s", MG_Util::Debug::GLEnumToString(result));
|
||||
}
|
||||
|
||||
void LinkProgram(GLuint program) {
|
||||
MG_Util::Debug::LogD("glLinkProgram, program: %u", program);
|
||||
GLenum result = MG_State::FinalizeProgramPipeline(program);
|
||||
if (result == GL_NO_ERROR) return;
|
||||
MG_State::SetError(result);
|
||||
MG_Util::Debug::LogE("Error linking program: %s", MG_Util::Debug::GLEnumToString(result));
|
||||
}
|
||||
|
||||
void UseProgram(GLuint program) {
|
||||
MG_Util::Debug::LogD("glUseProgram, program: %u", program);
|
||||
GLenum result = MG_State::ActivateRenderProgram(program);
|
||||
if (result == GL_NO_ERROR) return;
|
||||
MG_State::SetError(result);
|
||||
MG_Util::Debug::LogE("Error using program: %s", MG_Util::Debug::GLEnumToString(result));
|
||||
}
|
||||
|
||||
void BindAttribLocation(GLuint program, GLuint index, const GLchar* name) {
|
||||
MG_Util::Debug::LogD("glBindAttribLocation, program: %u, index: %u, name: %s", program, index, name);
|
||||
GLenum result = MG_State::DefineProgramAttributeBinding(program, index, name);
|
||||
if (result == GL_NO_ERROR) return;
|
||||
MG_State::SetError(result);
|
||||
MG_Util::Debug::LogE("Error binding attribute: %s", MG_Util::Debug::GLEnumToString(result));
|
||||
}
|
||||
|
||||
GLint GetAttribLocation(GLuint program, const GLchar* name) {
|
||||
MG_Util::Debug::LogD("glGetAttribLocation, program: %u, name: %s", program, name);
|
||||
GLint location = MG_State::QueryProgramAttributeBinding(program, name);
|
||||
if (location != -1) return location;
|
||||
MG_State::SetError(GL_INVALID_OPERATION);
|
||||
MG_Util::Debug::LogE("Attribute not found: %s", name);
|
||||
return -1;
|
||||
}
|
||||
|
||||
GLint GetUniformLocation(GLuint program, const GLchar* name) {
|
||||
MG_Util::Debug::LogD("glGetUniformLocation, program: %u, name: %s", program, name);
|
||||
GLint location = MG_State::QueryProgramUniformLocation(program, name);
|
||||
if (location != -1) return location;
|
||||
MG_State::SetError(GL_INVALID_OPERATION);
|
||||
MG_Util::Debug::LogE("Uniform not found: %s", name);
|
||||
return -1;
|
||||
}
|
||||
|
||||
void GetProgramiv(GLuint program, GLenum pname, GLint* params) {
|
||||
MG_Util::Debug::LogD("glGetProgramiv, program: %u, pname: %s",
|
||||
program, MG_Util::Debug::GLEnumToString(pname));
|
||||
GLenum result = MG_State::QueryProgramStateIntVector(program, pname, params);
|
||||
if (result == GL_NO_ERROR) return;
|
||||
MG_State::SetError(result);
|
||||
MG_Util::Debug::LogE("Error getting program param: %s", MG_Util::Debug::GLEnumToString(result));
|
||||
}
|
||||
|
||||
void GetShaderiv(GLuint shader, GLenum pname, GLint* params) {
|
||||
MG_Util::Debug::LogD("glGetShaderiv, shader: %u, pname: %s",
|
||||
shader, MG_Util::Debug::GLEnumToString(pname));
|
||||
GLenum result = MG_State::QueryShaderStateIntVector(shader, pname, params);
|
||||
if (result == GL_NO_ERROR) return;
|
||||
MG_State::SetError(result);
|
||||
MG_Util::Debug::LogE("Error getting shader param: %s", MG_Util::Debug::GLEnumToString(result));
|
||||
}
|
||||
|
||||
void Uniform1f(GLint location, GLfloat v0) {
|
||||
MG_Util::Debug::LogD("glUniform1f, location: %d, v0: %f", location, v0);
|
||||
MG_State::UpdateProgramUniformFloat1(location, v0);
|
||||
}
|
||||
|
||||
void Uniform2f(GLint location, GLfloat v0, GLfloat v1) {
|
||||
MG_Util::Debug::LogD("glUniform2f, location: %d, v0: %f, v1: %f", location, v0, v1);
|
||||
MG_State::UpdateProgramUniformFloat2(location, v0, v1);
|
||||
}
|
||||
|
||||
void Uniform3f(GLint location, GLfloat v0, GLfloat v1, GLfloat v2) {
|
||||
MG_Util::Debug::LogD("glUniform3f, location: %d, v0: %f, v1: %f, v2: %f", location, v0, v1, v2);
|
||||
MG_State::UpdateProgramUniformFloat3(location, v0, v1, v2);
|
||||
}
|
||||
|
||||
void Uniform4f(GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3) {
|
||||
MG_Util::Debug::LogD("glUniform4f, location: %d, v0: %f, v1: %f, v2: %f, v3: %f", location, v0, v1, v2, v3);
|
||||
MG_State::UpdateProgramUniformFloat4(location, v0, v1, v2, v3);
|
||||
}
|
||||
|
||||
void Uniform1fv(GLint location, GLsizei count, const GLfloat* value) {
|
||||
MG_Util::Debug::LogD("glUniform1fv, location: %d, count: %d", location, count);
|
||||
MG_State::UpdateProgramUniformFloatVector1(location, count, value);
|
||||
}
|
||||
|
||||
void Uniform2fv(GLint location, GLsizei count, const GLfloat* value) {
|
||||
MG_Util::Debug::LogD("glUniform2fv, location: %d, count: %d", location, count);
|
||||
MG_State::UpdateProgramUniformFloatVector2(location, count, value);
|
||||
}
|
||||
|
||||
void Uniform3fv(GLint location, GLsizei count, const GLfloat* value) {
|
||||
MG_Util::Debug::LogD("glUniform3fv, location: %d, count: %d", location, count);
|
||||
MG_State::UpdateProgramUniformFloatVector3(location, count, value);
|
||||
}
|
||||
|
||||
void Uniform4fv(GLint location, GLsizei count, const GLfloat* value) {
|
||||
MG_Util::Debug::LogD("glUniform4fv, location: %d, count: %d", location, count);
|
||||
MG_State::UpdateProgramUniformFloatVector4(location, count, value);
|
||||
}
|
||||
|
||||
void Uniform1i(GLint location, GLint v0) {
|
||||
MG_Util::Debug::LogD("glUniform1i, location: %d, v0: %d", location, v0);
|
||||
MG_State::UpdateProgramUniformInt1(location, v0);
|
||||
}
|
||||
|
||||
void Uniform2i(GLint location, GLint v0, GLint v1) {
|
||||
MG_Util::Debug::LogD("glUniform2i, location: %d, v0: %d, v1: %d", location, v0, v1);
|
||||
MG_State::UpdateProgramUniformInt2(location, v0, v1);
|
||||
}
|
||||
|
||||
void Uniform3i(GLint location, GLint v0, GLint v1, GLint v2) {
|
||||
MG_Util::Debug::LogD("glUniform3i, location: %d, v0: %d, v1: %d, v2: %d", location, v0, v1, v2);
|
||||
MG_State::UpdateProgramUniformInt3(location, v0, v1, v2);
|
||||
}
|
||||
|
||||
void Uniform4i(GLint location, GLint v0, GLint v1, GLint v2, GLint v3) {
|
||||
MG_Util::Debug::LogD("glUniform4i, location: %d, v0: %d, v1: %d, v2: %d, v3: %d", location, v0, v1, v2, v3);
|
||||
MG_State::UpdateProgramUniformInt4(location, v0, v1, v2, v3);
|
||||
}
|
||||
|
||||
void Uniform1iv(GLint location, GLsizei count, const GLint* value) {
|
||||
MG_Util::Debug::LogD("glUniform1iv, location: %d, count: %d", location, count);
|
||||
MG_State::UpdateProgramUniformIntVector1(location, count, value);
|
||||
}
|
||||
|
||||
void Uniform2iv(GLint location, GLsizei count, const GLint* value) {
|
||||
MG_Util::Debug::LogD("glUniform2iv, location: %d, count: %d", location, count);
|
||||
MG_State::UpdateProgramUniformIntVector2(location, count, value);
|
||||
}
|
||||
|
||||
void Uniform3iv(GLint location, GLsizei count, const GLint* value) {
|
||||
MG_Util::Debug::LogD("glUniform3iv, location: %d, count: %d", location, count);
|
||||
MG_State::UpdateProgramUniformIntVector3(location, count, value);
|
||||
}
|
||||
|
||||
void Uniform4iv(GLint location, GLsizei count, const GLint* value) {
|
||||
MG_Util::Debug::LogD("glUniform4iv, location: %d, count: %d", location, count);
|
||||
MG_State::UpdateProgramUniformIntVector4(location, count, value);
|
||||
}
|
||||
|
||||
void Uniform1ui(GLint location, GLuint v0) {
|
||||
MG_Util::Debug::LogD("glUniform1ui, location: %d, v0: %u", location, v0);
|
||||
MG_State::UpdateProgramUniformUInt1(location, v0);
|
||||
}
|
||||
|
||||
void Uniform2ui(GLint location, GLuint v0, GLuint v1) {
|
||||
MG_Util::Debug::LogD("glUniform2ui, location: %d, v0: %u, v1: %u", location, v0, v1);
|
||||
MG_State::UpdateProgramUniformUInt2(location, v0, v1);
|
||||
}
|
||||
|
||||
void Uniform3ui(GLint location, GLuint v0, GLuint v1, GLuint v2) {
|
||||
MG_Util::Debug::LogD("glUniform3ui, location: %d, v0: %u, v1: %u, v2: %u", location, v0, v1, v2);
|
||||
MG_State::UpdateProgramUniformUInt3(location, v0, v1, v2);
|
||||
}
|
||||
|
||||
void Uniform4ui(GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3) {
|
||||
MG_Util::Debug::LogD("glUniform4ui, location: %d, v0: %u, v1: %u, v2: %u, v3: %u", location, v0, v1, v2, v3);
|
||||
MG_State::UpdateProgramUniformUInt4(location, v0, v1, v2, v3);
|
||||
}
|
||||
|
||||
void Uniform1uiv(GLint location, GLsizei count, const GLuint* value) {
|
||||
MG_Util::Debug::LogD("glUniform1uiv, location: %d, count: %d", location, count);
|
||||
MG_State::UpdateProgramUniformUIntVector1(location, count, value);
|
||||
}
|
||||
|
||||
void Uniform2uiv(GLint location, GLsizei count, const GLuint* value) {
|
||||
MG_Util::Debug::LogD("glUniform2uiv, location: %d, count: %d", location, count);
|
||||
MG_State::UpdateProgramUniformUIntVector2(location, count, value);
|
||||
}
|
||||
|
||||
void Uniform3uiv(GLint location, GLsizei count, const GLuint* value) {
|
||||
MG_Util::Debug::LogD("glUniform3uiv, location: %d, count: %d", location, count);
|
||||
MG_State::UpdateProgramUniformUIntVector3(location, count, value);
|
||||
}
|
||||
|
||||
void Uniform4uiv(GLint location, GLsizei count, const GLuint* value) {
|
||||
MG_Util::Debug::LogD("glUniform4uiv, location: %d, count: %d", location, count);
|
||||
MG_State::UpdateProgramUniformUIntVector4(location, count, value);
|
||||
}
|
||||
|
||||
void UniformMatrix2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) {
|
||||
MG_Util::Debug::LogD("glUniformMatrix2fv, location: %d, count: %d, transpose: %d", location, count, transpose);
|
||||
MG_State::UpdateProgramUniformMatrix2x2Vector(location, count, transpose, value);
|
||||
}
|
||||
|
||||
void UniformMatrix3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) {
|
||||
MG_Util::Debug::LogD("glUniformMatrix3fv, location: %d, count: %d, transpose: %d", location, count, transpose);
|
||||
MG_State::UpdateProgramUniformMatrix3x3Vector(location, count, transpose, value);
|
||||
}
|
||||
|
||||
void UniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) {
|
||||
MG_Util::Debug::LogD("glUniformMatrix4fv, location: %d, count: %d, transpose: %d", location, count, transpose);
|
||||
MG_State::UpdateProgramUniformMatrix4x4Vector(location, count, transpose, value);
|
||||
}
|
||||
|
||||
void UniformMatrix2x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) {
|
||||
MG_Util::Debug::LogD("glUniformMatrix2x3fv, location: %d, count: %d, transpose: %d", location, count, transpose);
|
||||
MG_State::UpdateProgramUniformMatrix2x3Vector(location, count, transpose, value);
|
||||
}
|
||||
|
||||
void UniformMatrix2x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) {
|
||||
MG_Util::Debug::LogD("glUniformMatrix2x4fv, location: %d, count: %d, transpose: %d", location, count, transpose);
|
||||
MG_State::UpdateProgramUniformMatrix2x4Vector(location, count, transpose, value);
|
||||
}
|
||||
|
||||
void UniformMatrix3x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) {
|
||||
MG_Util::Debug::LogD("glUniformMatrix3x2fv, location: %d, count: %d, transpose: %d", location, count, transpose);
|
||||
MG_State::UpdateProgramUniformMatrix3x2Vector(location, count, transpose, value);
|
||||
}
|
||||
|
||||
void UniformMatrix3x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) {
|
||||
MG_Util::Debug::LogD("glUniformMatrix3x4fv, location: %d, count: %d, transpose: %d", location, count, transpose);
|
||||
MG_State::UpdateProgramUniformMatrix3x4Vector(location, count, transpose, value);
|
||||
}
|
||||
|
||||
void UniformMatrix4x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) {
|
||||
MG_Util::Debug::LogD("glUniformMatrix4x2fv, location: %d, count: %d, transpose: %d", location, count, transpose);
|
||||
MG_State::UpdateProgramUniformMatrix4x2Vector(location, count, transpose, value);
|
||||
}
|
||||
|
||||
void UniformMatrix4x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) {
|
||||
MG_Util::Debug::LogD("glUniformMatrix4x3fv, location: %d, count: %d, transpose: %d", location, count, transpose);
|
||||
MG_State::UpdateProgramUniformMatrix4x3Vector(location, count, transpose, value);
|
||||
}
|
||||
}
|
||||
@@ -1,60 +0,0 @@
|
||||
//
|
||||
// Created by BZLZHH on 2025/3/15.
|
||||
//
|
||||
|
||||
#ifndef MOBILEGL_GL_PROGRAM_H
|
||||
#define MOBILEGL_GL_PROGRAM_H
|
||||
|
||||
#include "../../../../Includes.h"
|
||||
|
||||
namespace MG_GL::GL {
|
||||
GLuint CreateShader(GLenum type);
|
||||
GLuint CreateProgram();
|
||||
void DeleteShader(GLuint shader);
|
||||
void DeleteProgram(GLuint program);
|
||||
void AttachShader(GLuint program, GLuint shader);
|
||||
void ShaderSource(GLuint shader, GLsizei count, const GLchar *const*string, const GLint* length);
|
||||
void CompileShader(GLuint shader);
|
||||
void LinkProgram(GLuint program);
|
||||
void UseProgram(GLuint program);
|
||||
void BindAttribLocation(GLuint program, GLuint index, const GLchar* name);
|
||||
GLint GetAttribLocation(GLuint program, const GLchar* name);
|
||||
GLint GetUniformLocation(GLuint program, const GLchar* name);
|
||||
void GetProgramiv(GLuint program, GLenum pname, GLint* params);
|
||||
void GetShaderiv(GLuint shader, GLenum pname, GLint* params);
|
||||
void Uniform1f(GLint location, GLfloat v0);
|
||||
void Uniform2f(GLint location, GLfloat v0, GLfloat v1);
|
||||
void Uniform3f(GLint location, GLfloat v0, GLfloat v1, GLfloat v2);
|
||||
void Uniform4f(GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3);
|
||||
void Uniform1fv(GLint location, GLsizei count, const GLfloat* value);
|
||||
void Uniform2fv(GLint location, GLsizei count, const GLfloat* value);
|
||||
void Uniform3fv(GLint location, GLsizei count, const GLfloat* value);
|
||||
void Uniform4fv(GLint location, GLsizei count, const GLfloat* value);
|
||||
void Uniform1i(GLint location, GLint v0);
|
||||
void Uniform2i(GLint location, GLint v0, GLint v1);
|
||||
void Uniform3i(GLint location, GLint v0, GLint v1, GLint v2);
|
||||
void Uniform4i(GLint location, GLint v0, GLint v1, GLint v2, GLint v3);
|
||||
void Uniform1iv(GLint location, GLsizei count, const GLint* value);
|
||||
void Uniform2iv(GLint location, GLsizei count, const GLint* value);
|
||||
void Uniform3iv(GLint location, GLsizei count, const GLint* value);
|
||||
void Uniform4iv(GLint location, GLsizei count, const GLint* value);
|
||||
void Uniform1ui(GLint location, GLuint v0);
|
||||
void Uniform2ui(GLint location, GLuint v0, GLuint v1);
|
||||
void Uniform3ui(GLint location, GLuint v0, GLuint v1, GLuint v2);
|
||||
void Uniform4ui(GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3);
|
||||
void Uniform1uiv(GLint location, GLsizei count, const GLuint* value);
|
||||
void Uniform2uiv(GLint location, GLsizei count, const GLuint* value);
|
||||
void Uniform3uiv(GLint location, GLsizei count, const GLuint* value);
|
||||
void Uniform4uiv(GLint location, GLsizei count, const GLuint* value);
|
||||
void UniformMatrix2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value);
|
||||
void UniformMatrix3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value);
|
||||
void UniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value);
|
||||
void UniformMatrix2x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value);
|
||||
void UniformMatrix2x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value);
|
||||
void UniformMatrix3x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value);
|
||||
void UniformMatrix3x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value);
|
||||
void UniformMatrix4x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value);
|
||||
void UniformMatrix4x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value);
|
||||
}
|
||||
|
||||
#endif //MOBILEGL_GL_PROGRAM_H
|
||||
@@ -1,93 +0,0 @@
|
||||
//
|
||||
// Created by BZLZHH on 2025/3/15.
|
||||
//
|
||||
|
||||
#include "GL_Texture.h"
|
||||
|
||||
namespace MG_GL::GL {
|
||||
void ActiveTexture(GLenum texture) {
|
||||
MG_Util::Debug::LogD("glActiveTexture, texture: %d", texture);
|
||||
GLenum result = MG_State::BindTextureUnit(texture);
|
||||
if (result == GL_NO_ERROR)
|
||||
return;
|
||||
MG_State::SetError(result);
|
||||
MG_Util::Debug::LogE("Error from MG State: %s", MG_Util::Debug::GLEnumToString(result));
|
||||
}
|
||||
|
||||
void BindTexture(GLenum target, GLuint texture) {
|
||||
MG_Util::Debug::LogD("glBindTexture, target: %d, texture: %d", target, texture);
|
||||
GLenum result = MG_State::BindTexture(target, texture);
|
||||
if (result == GL_NO_ERROR)
|
||||
return;
|
||||
MG_State::SetError(result);
|
||||
MG_Util::Debug::LogE("Error from MG State: %s", MG_Util::Debug::GLEnumToString(result));
|
||||
}
|
||||
|
||||
void DeleteTextures(GLsizei n, const GLuint* textures) {
|
||||
MG_Util::Debug::LogD("glDeleteTextures, n: %d, textures: %p", n, textures);
|
||||
GLenum result = MG_State::DeleteTextures(n, textures);
|
||||
if (result == GL_NO_ERROR)
|
||||
return;
|
||||
MG_State::SetError(result);
|
||||
MG_Util::Debug::LogE("Error from MG State: %s", MG_Util::Debug::GLEnumToString(result));
|
||||
}
|
||||
|
||||
void GenTextures(GLsizei n, GLuint* textures) {
|
||||
MG_Util::Debug::LogD("glGenTextures, n: %d, textures: %p", n, textures);
|
||||
GLenum result = MG_State::CreateTextures(n, textures);
|
||||
if (result == GL_NO_ERROR)
|
||||
return;
|
||||
MG_State::SetError(result);
|
||||
MG_Util::Debug::LogE("Error from MG State: %s", MG_Util::Debug::GLEnumToString(result));
|
||||
}
|
||||
|
||||
void TexImage2D(GLenum target, GLint level, GLint internalFormat, GLsizei width, GLsizei height, GLint border,
|
||||
GLenum format, GLenum type, const void* data) {
|
||||
MG_Util::Debug::LogD("glTexImage2D, target: %d, level: %d, internalFormat: %d, width: %d, height: %d, format: %d, type: %d, data: %p",
|
||||
target, level, internalFormat, width, height, format, type, data);
|
||||
GLenum result = MG_State::UploadTexture2D(target, level, internalFormat, width, height, border, format, type, data);
|
||||
if (result == GL_NO_ERROR)
|
||||
return;
|
||||
MG_State::SetError(result);
|
||||
MG_Util::Debug::LogE("Error from MG State: %s", MG_Util::Debug::GLEnumToString(result));
|
||||
}
|
||||
|
||||
void TexParameterf(GLenum target, GLenum pname, GLfloat param) {
|
||||
MG_Util::Debug::LogD("glTexParameterf, target: %d, pname: %d, param: %f", target, pname, param);
|
||||
GLenum result = MG_State::SetTexturePropertyFloat(target, pname, param);
|
||||
if (result == GL_NO_ERROR)
|
||||
return;
|
||||
MG_State::SetError(result);
|
||||
MG_Util::Debug::LogE("Error from MG State: %s", MG_Util::Debug::GLEnumToString(result));
|
||||
}
|
||||
|
||||
void TexParameteri(GLenum target, GLenum pname, GLint param) {
|
||||
MG_Util::Debug::LogD("glTexParameteri, target: %d, pname: %d, param: %d", target, pname, param);
|
||||
GLenum result = MG_State::SetTexturePropertyInt(target, pname, param);
|
||||
if (result == GL_NO_ERROR)
|
||||
return;
|
||||
MG_State::SetError(result);
|
||||
MG_Util::Debug::LogE("Error from MG State: %s", MG_Util::Debug::GLEnumToString(result));
|
||||
}
|
||||
|
||||
void TexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width,
|
||||
GLsizei height, GLenum format, GLenum type, const void* pixels) {
|
||||
MG_Util::Debug::LogD("glTexSubImage2D, target: %d, level: %d, xoffset: %d, yoffset: %d, width: %d, height: %d, format: %d, type: %d, pixels: %p",
|
||||
target, level, xoffset, yoffset, width, height, format, type, pixels);
|
||||
GLenum result = MG_State::UpdateTextureRegion2D(target, level, xoffset, yoffset, width, height, format, type, pixels);
|
||||
if (result == GL_NO_ERROR)
|
||||
return;
|
||||
MG_State::SetError(result);
|
||||
MG_Util::Debug::LogE("Error from MG State: %s", MG_Util::Debug::GLEnumToString(result));
|
||||
}
|
||||
|
||||
void GetTexLevelParameteriv(GLenum target, GLint level, GLenum pname, GLint* params) {
|
||||
MG_Util::Debug::LogD("glGetTexLevelParameteriv, target: %d, level: %d, pname: %d, params: %p",
|
||||
target, level, pname, params);
|
||||
GLenum result = MG_State::QueryTextureLevelPropertyIntVector(target, level, pname, params);
|
||||
if (result == GL_NO_ERROR)
|
||||
return;
|
||||
MG_State::SetError(result);
|
||||
MG_Util::Debug::LogE("Error from MG State: %s", MG_Util::Debug::GLEnumToString(result));
|
||||
}
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
//
|
||||
// Created by BZLZHH on 2025/3/15.
|
||||
//
|
||||
|
||||
#ifndef MOBILEGL_GL_TEXTURE_H
|
||||
#define MOBILEGL_GL_TEXTURE_H
|
||||
|
||||
#include "../../../../Includes.h"
|
||||
|
||||
namespace MG_GL::GL {
|
||||
void ActiveTexture(GLenum texture);
|
||||
void BindTexture(GLenum target, GLuint texture);
|
||||
void DeleteTextures(GLsizei n, const GLuint* textures);
|
||||
void GenTextures(GLsizei n, GLuint* textures);
|
||||
void TexImage2D(GLenum target, GLint level, GLint internalFormat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void* data);
|
||||
void TexParameterf(GLenum target, GLenum pname, GLfloat param);
|
||||
void TexParameteri(GLenum target, GLenum pname, GLint param);
|
||||
void TexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void* pixels);
|
||||
void GetTexLevelParameteriv(GLenum target, GLint level, GLenum pname, GLint* params);
|
||||
}
|
||||
|
||||
#endif //MOBILEGL_GL_TEXTURE_H
|
||||
@@ -1,53 +0,0 @@
|
||||
//
|
||||
// Created by BZLZHH on 2025/3/15.
|
||||
//
|
||||
|
||||
#include "GL_VertexArray.h"
|
||||
|
||||
namespace MG_GL::GL {
|
||||
void GenVertexArrays(GLsizei n, GLuint* arrays) {
|
||||
MG_Util::Debug::LogD("glGenVertexArrays, n: %d, arrays: %p", n, arrays);
|
||||
GLenum result = MG_State::GenVertexArraysNames(n, arrays);
|
||||
if (result == GL_NO_ERROR) return;
|
||||
MG_State::SetError(result);
|
||||
MG_Util::Debug::LogE("Error from MG State: %s", MG_Util::Debug::GLEnumToString(result));
|
||||
}
|
||||
|
||||
void BindVertexArray(GLuint array) {
|
||||
MG_Util::Debug::LogD("glBindVertexArray, array: %u", array);
|
||||
GLenum result = MG_State::BindVertexArray(array);
|
||||
if (result == GL_NO_ERROR) return;
|
||||
MG_State::SetError(result);
|
||||
MG_Util::Debug::LogE("Error from MG State: %s", MG_Util::Debug::GLEnumToString(result));
|
||||
}
|
||||
|
||||
void EnableVertexAttribArray(GLuint index) {
|
||||
MG_Util::Debug::LogD("glEnableVertexAttribArray, index: %u", index);
|
||||
GLenum result = MG_State::EnableVertexAttribArray(index);
|
||||
if (result == GL_NO_ERROR) return;
|
||||
MG_State::SetError(result);
|
||||
MG_Util::Debug::LogE("Error from MG State: %s", MG_Util::Debug::GLEnumToString(result));
|
||||
}
|
||||
|
||||
void VertexAttribPointer(GLuint index, GLint size, GLenum type,
|
||||
GLboolean normalized, GLsizei stride, const void* pointer) {
|
||||
MG_Util::Debug::LogD("glVertexAttribPointer, index: %u, size: %d, type: %s, norm: %d, stride: %d, ptr: %p",
|
||||
index, size, MG_Util::Debug::GLEnumToString(type), normalized, stride, pointer);
|
||||
|
||||
GLenum result = MG_State::SetVertexAttributeLayout(index, size, type, normalized, stride, pointer);
|
||||
if (result == GL_NO_ERROR) return;
|
||||
MG_State::SetError(result);
|
||||
MG_Util::Debug::LogE("Error from MG State: %s", MG_Util::Debug::GLEnumToString(result));
|
||||
}
|
||||
|
||||
void VertexAttribIPointer(GLuint index, GLint size, GLenum type,
|
||||
GLsizei stride, const void* pointer) {
|
||||
MG_Util::Debug::LogD("glVertexAttribIPointer, index: %u, size: %d, type: %s, stride: %d, ptr: %p",
|
||||
index, size, MG_Util::Debug::GLEnumToString(type), stride, pointer);
|
||||
|
||||
GLenum result = MG_State::SetVertexAttributeLayoutInt(index, size, type, stride, pointer);
|
||||
if (result == GL_NO_ERROR) return;
|
||||
MG_State::SetError(result);
|
||||
MG_Util::Debug::LogE("Error from MG State: %s", MG_Util::Debug::GLEnumToString(result));
|
||||
}
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
//
|
||||
// Created by BZLZHH on 2025/3/15.
|
||||
//
|
||||
|
||||
#ifndef MOBILEGL_GL_VERTEXARRAY_H
|
||||
#define MOBILEGL_GL_VERTEXARRAY_H
|
||||
|
||||
#include "../../../../Includes.h"
|
||||
|
||||
namespace MG_GL::GL {
|
||||
void GenVertexArrays(GLsizei n, GLuint* arrays);
|
||||
void BindVertexArray(GLuint array);
|
||||
void EnableVertexAttribArray(GLuint index);
|
||||
void VertexAttribPointer(GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void* pointer);
|
||||
void VertexAttribIPointer(GLuint index, GLint size, GLenum type, GLsizei stride, const void* pointer);
|
||||
}
|
||||
|
||||
#endif //MOBILEGL_GL_VERTEXARRAY_H
|
||||
@@ -1,24 +0,0 @@
|
||||
//
|
||||
// Created by BZLZHH on 2025/3/15.
|
||||
//
|
||||
|
||||
#include "LookUp.h"
|
||||
|
||||
#include "../../../../Includes.h"
|
||||
|
||||
namespace MG_GL::GLX {
|
||||
void* GetProcAddress(const char *name) {
|
||||
void* proc = dlsym(RTLD_DEFAULT, (const char*)name);
|
||||
|
||||
if (!proc) {
|
||||
MG_Util::Debug::LogW("Failed to get function: %s", (const char*)name);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return proc;
|
||||
}
|
||||
|
||||
void* GetProcAddressARB(const char *name) {
|
||||
return GetProcAddress(name);
|
||||
}
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
//
|
||||
// Created by BZLZHH on 2025/3/15.
|
||||
//
|
||||
|
||||
#ifndef MOBILEGL_LOOKUP_H
|
||||
#define MOBILEGL_LOOKUP_H
|
||||
|
||||
namespace MG_GL::GLX {
|
||||
void* GetProcAddress(const char *name);
|
||||
void* GetProcAddressARB(const char *name);
|
||||
}
|
||||
#endif //MOBILEGL_LOOKUP_H
|
||||
@@ -1,328 +0,0 @@
|
||||
//
|
||||
// Created by BZLZHH on 2025/5/1.
|
||||
//
|
||||
|
||||
// TODO: Add more gl error check for buffer state manager.
|
||||
|
||||
#include "BufferState.h"
|
||||
|
||||
GLenum BufferState::GenName(GLuint *buffer) {
|
||||
MG_Util::Debug::LogD("MG_State: Buffer: GenName");
|
||||
if (!buffer)
|
||||
return GL_INVALID_VALUE;
|
||||
|
||||
GLuint id = 0;
|
||||
if (freeId_.empty()) {
|
||||
id = lastId_++;
|
||||
} else {
|
||||
id = freeId_.back();
|
||||
freeId_.pop_back();
|
||||
}
|
||||
|
||||
*buffer = id;
|
||||
MG_Util::Debug::LogD("MG_State: Buffer: Gen new name %d", id);
|
||||
|
||||
return GL_NO_ERROR;
|
||||
}
|
||||
|
||||
GLenum BufferState::GenNameN(GLsizei n, GLuint* buffers) {
|
||||
MG_Util::Debug::LogD("MG_State: Buffer: GenNameN called with n=%d", n);
|
||||
if (n < 0) return GL_INVALID_VALUE;
|
||||
|
||||
for (GLsizei i = 0; i < n; ++i) {
|
||||
GLenum result = GenName(&buffers[i]);
|
||||
if (result != GL_NO_ERROR) {
|
||||
MG_Util::Debug::LogE("MG_State: Buffer: GenNameN failed with error 0x%x", result);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
MG_Util::Debug::LogD("MG_State: Buffer: GenNameN created buffers successfully");
|
||||
return GL_NO_ERROR;
|
||||
}
|
||||
|
||||
GLenum BufferState::Create(GLuint buffer) {
|
||||
MG_Util::Debug::LogD("MG_State: Buffer: Create called");
|
||||
if (!buffer)
|
||||
return GL_INVALID_VALUE;
|
||||
|
||||
if (ValidateAllocatedHandle(buffer))
|
||||
return GL_INVALID_VALUE;
|
||||
|
||||
BufferObject& obj = buffers_[buffer];
|
||||
MG_Util::Debug::LogD("MG_State: Buffer: Create created buffer %d", buffer);
|
||||
obj.generated = true;
|
||||
obj.dirty = true;
|
||||
|
||||
return GL_NO_ERROR;
|
||||
}
|
||||
|
||||
GLenum BufferState::Bind(GLenum target, GLuint buffer) {
|
||||
// We don't handle unallocated buffer names here, just plain bind
|
||||
if (!IsValidTarget_(target)) return GL_INVALID_ENUM;
|
||||
MG_Util::Debug::LogD("MG_State: Buffer: Bind called with target=%s, buffer=%u", MG_Util::Debug::GLEnumToString(target), buffer);
|
||||
currentBindings_[target] = buffer;
|
||||
MG_Util::Debug::LogD("MG_State: Buffer: Bind succeed bind buffer %u to target 0x%x", buffer, target);
|
||||
return GL_NO_ERROR;
|
||||
}
|
||||
|
||||
GLenum BufferState::CommitStorage(GLenum target, GLsizeiptr size, const void* data, GLenum usage) {
|
||||
MG_Util::Debug::LogD("MG_State: Buffer: CommitStorage called on target 0x%x",target);
|
||||
auto it = currentBindings_.find(target);
|
||||
if (it == currentBindings_.end() || it->second == 0)
|
||||
return GL_INVALID_OPERATION;
|
||||
|
||||
BufferObject& obj = buffers_[it->second];
|
||||
MG_Util::Debug::LogD("MG_State: Buffer: CommitStorage get buffer object %u at target 0x%x",it->second,target);
|
||||
obj.usage = usage;
|
||||
obj.data.resize(size);
|
||||
if (data) {
|
||||
memcpy(obj.data.data(), data, size);
|
||||
obj.dataValid = true;
|
||||
}
|
||||
obj.dirty = true;
|
||||
MG_Util::Debug::LogD("MG_State: Buffer: CommitStorage buffer at target 0x%x committed storage, size = %zu, usage=0x%x", target, size, usage);
|
||||
|
||||
return GL_NO_ERROR;
|
||||
}
|
||||
|
||||
GLenum BufferState::CommitStorageRegion(GLenum target, GLintptr offset, GLsizeiptr size, const void* data) {
|
||||
MG_Util::Debug::LogD("MG_State: Buffer: BufferSubData called on target 0x%x, offset=%ld, size=%ld", target, offset, size);
|
||||
if (!IsValidTarget_(target)) return GL_INVALID_ENUM;
|
||||
if (offset < 0 || size < 0) return GL_INVALID_VALUE;
|
||||
|
||||
auto it = currentBindings_.find(target);
|
||||
if (it == currentBindings_.end() || it->second == 0)
|
||||
return GL_INVALID_OPERATION;
|
||||
|
||||
BufferObject& obj = buffers_[it->second];
|
||||
MG_Util::Debug::LogD("MG_State: Buffer: BufferSubData get buffer object %u at target 0x%x", it->second, target);
|
||||
|
||||
if (static_cast<size_t>(offset + size) > obj.data.size()) return GL_INVALID_VALUE;
|
||||
|
||||
if (data) {
|
||||
memcpy(obj.data.data() + offset, data, size);
|
||||
obj.dirty = true;
|
||||
}
|
||||
return GL_NO_ERROR;
|
||||
}
|
||||
|
||||
GLenum BufferState::AcquireBufferMemoryRange(GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access, void** mappedPointer) {
|
||||
MG_Util::Debug::LogD("MG_State: Buffer: AcquireBufferMemoryRange called with target=0x%x, offset=%ld, length=%ld, access=0x%x", target, offset, length, access);
|
||||
if (!IsValidTarget_(target)) {
|
||||
MG_Util::Debug::LogE("MG_State: Buffer: AcquireBufferMemoryRange failed: invalid target 0x%x", target);
|
||||
return GL_INVALID_ENUM;
|
||||
}
|
||||
if (offset < 0 || length <= 0) {
|
||||
MG_Util::Debug::LogE("MG_State: Buffer: AcquireBufferMemoryRange failed: invalid offset %ld or length %ld", offset, length);
|
||||
return GL_INVALID_VALUE;
|
||||
}
|
||||
|
||||
auto it = currentBindings_.find(target);
|
||||
if (it == currentBindings_.end() || it->second == 0) {
|
||||
MG_Util::Debug::LogE("MG_State: Buffer: AcquireBufferMemoryRange failed: no buffer bound to target 0x%x", target);
|
||||
return GL_INVALID_OPERATION;
|
||||
}
|
||||
|
||||
BufferObject& obj = buffers_[it->second];
|
||||
MG_Util::Debug::LogD("MG_State: Buffer: AcquireBufferMemoryRange operating on buffer %u", it->second);
|
||||
if (obj.isMapped) {
|
||||
MG_Util::Debug::LogE("MG_State: Buffer: AcquireBufferMemoryRange failed: buffer %u is already mapped", it->second);
|
||||
return GL_INVALID_OPERATION;
|
||||
}
|
||||
|
||||
const GLbitfield validFlags = GL_MAP_READ_BIT | GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_RANGE_BIT | GL_MAP_FLUSH_EXPLICIT_BIT | GL_MAP_UNSYNCHRONIZED_BIT | GL_MAP_INVALIDATE_BUFFER_BIT ;
|
||||
if ((access & ~validFlags) != 0) {
|
||||
MG_Util::Debug::LogE("MG_State: Buffer: AcquireBufferMemoryRange failed: invalid access flags 0x%x", access);
|
||||
return GL_INVALID_VALUE;
|
||||
}
|
||||
|
||||
if (static_cast<size_t>(offset + length) > obj.data.size()) {
|
||||
MG_Util::Debug::LogE("MG_State: Buffer: AcquireBufferMemoryRange failed: requested range [%ld, %ld) exceeds buffer size %zu", offset, offset + length, obj.data.size());
|
||||
return GL_INVALID_VALUE;
|
||||
}
|
||||
|
||||
obj.isMapped = true;
|
||||
obj.mapOffset = offset;
|
||||
obj.mapLength = length;
|
||||
obj.mapAccessFlags = access;
|
||||
obj.dirty = true;
|
||||
*mappedPointer = obj.data.data() + offset;
|
||||
MG_Util::Debug::LogD("MG_State: Buffer: AcquireBufferMemoryRange succeeded for buffer %u. Mapped pointer: %p", it->second, *mappedPointer);
|
||||
return GL_NO_ERROR;
|
||||
}
|
||||
|
||||
GLenum BufferState::SyncBufferMemory(GLenum target, GLintptr offset, GLsizeiptr length) {
|
||||
if (!IsValidTarget_(target)) return GL_INVALID_ENUM;
|
||||
if (offset < 0 || length <= 0) return GL_INVALID_VALUE;
|
||||
|
||||
auto it = currentBindings_.find(target);
|
||||
if (it == currentBindings_.end() || it->second == 0)
|
||||
return GL_INVALID_OPERATION;
|
||||
|
||||
BufferObject& obj = buffers_[it->second];
|
||||
if (!obj.isMapped || !(obj.mapAccessFlags & GL_MAP_FLUSH_EXPLICIT_BIT))
|
||||
return GL_INVALID_OPERATION;
|
||||
|
||||
if (offset < obj.mapOffset || offset + length > obj.mapOffset + obj.mapLength)
|
||||
return GL_INVALID_VALUE;
|
||||
|
||||
// TODO: Add support for flush range.
|
||||
// Now only mark it as dirty.
|
||||
obj.dirty = true;
|
||||
return GL_NO_ERROR;
|
||||
}
|
||||
|
||||
GLenum BufferState::CopyBufferRange(GLenum readTarget, GLenum writeTarget, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size) {
|
||||
if (!IsValidTarget_(readTarget) || !IsValidTarget_(writeTarget))
|
||||
return GL_INVALID_ENUM;
|
||||
if (readOffset < 0 || writeOffset < 0 || size < 0)
|
||||
return GL_INVALID_VALUE;
|
||||
|
||||
GLuint readBuffer = currentBindings_[readTarget];
|
||||
GLuint writeBuffer = currentBindings_[writeTarget];
|
||||
if (readBuffer == 0 || writeBuffer == 0 || readBuffer == writeBuffer)
|
||||
return GL_INVALID_OPERATION;
|
||||
|
||||
BufferObject& src = buffers_[readBuffer];
|
||||
BufferObject& dst = buffers_[writeBuffer];
|
||||
|
||||
if (static_cast<size_t>(readOffset + size) > src.data.size() ||
|
||||
static_cast<size_t>(writeOffset + size) > dst.data.size())
|
||||
return GL_INVALID_VALUE;
|
||||
|
||||
memcpy(dst.data.data() + writeOffset, src.data.data() + readOffset, size);
|
||||
dst.dirty = true;
|
||||
return GL_NO_ERROR;
|
||||
}
|
||||
|
||||
GLenum BufferState::AcquireBufferMemory(GLenum target, GLenum access, void** mappedPointer) {
|
||||
GLbitfield flags = 0;
|
||||
switch (access) {
|
||||
case GL_READ_ONLY: flags = GL_MAP_READ_BIT; break;
|
||||
case GL_WRITE_ONLY: flags = GL_MAP_WRITE_BIT; break;
|
||||
case GL_READ_WRITE: flags = GL_MAP_READ_BIT | GL_MAP_WRITE_BIT; break;
|
||||
default:
|
||||
flags = access;
|
||||
}
|
||||
return AcquireBufferMemoryRange(target, 0, buffers_[currentBindings_[target]].data.size(), flags, mappedPointer);
|
||||
}
|
||||
|
||||
GLenum BufferState::ReleaseBufferMemory(GLenum target) {
|
||||
if (!IsValidTarget_(target))
|
||||
return GL_INVALID_ENUM;
|
||||
|
||||
auto it = currentBindings_.find(target);
|
||||
if (it == currentBindings_.end() || it->second == 0)
|
||||
return GL_INVALID_OPERATION;
|
||||
|
||||
BufferObject& obj = buffers_[it->second];
|
||||
if (!obj.isMapped)
|
||||
return GL_INVALID_OPERATION;
|
||||
|
||||
if ((obj.mapAccessFlags & GL_MAP_FLUSH_EXPLICIT_BIT) == 0) {
|
||||
obj.dirty = true;
|
||||
}
|
||||
|
||||
obj.isMapped = false;
|
||||
obj.mapOffset = 0;
|
||||
obj.mapLength = 0;
|
||||
obj.mapAccessFlags = 0;
|
||||
obj.accessMode = GL_READ_WRITE;
|
||||
|
||||
return GL_NO_ERROR;
|
||||
}
|
||||
|
||||
bool BufferState::ValidateAllocatedHandle(GLuint buffer) {
|
||||
bool isValid = buffers_.find(buffer) != buffers_.end();
|
||||
MG_Util::Debug::LogD("MG_State: Buffer: ValidateAllocatedHandle called on buffer %u returns %d", buffer, isValid);
|
||||
return isValid;
|
||||
}
|
||||
|
||||
bool BufferState::ValidateGeneratedName(GLuint buffer) {
|
||||
bool inFreeList = std::find(freeId_.begin(), freeId_.end(), buffer) != freeId_.end();
|
||||
bool lessThanLast = buffer < lastId_; // lastId_ is not generated yet
|
||||
MG_Util::Debug::LogD("MG_State: Buffer: ValidateGeneratedName called on buffer %u returns %d", buffer, lessThanLast && !inFreeList);
|
||||
return lessThanLast && !inFreeList;
|
||||
}
|
||||
|
||||
void BufferState::Delete(GLuint buffer) {
|
||||
buffers_.erase(buffer);
|
||||
if (ValidateGeneratedName(buffer))
|
||||
// TODO: Prevent the object that uses a freeId from conflicting with legacy object in the backend.
|
||||
//freeId_.emplace_back(buffer);
|
||||
for (auto& [target, id] : currentBindings_) {
|
||||
if (id == buffer) id = 0;
|
||||
}
|
||||
MG_Util::Debug::LogD("MG_State: Buffer: Delete buffer %u", buffer);
|
||||
}
|
||||
|
||||
GLenum BufferState::DeleteN(GLsizei n, const GLuint* buffers) {
|
||||
MG_Util::Debug::LogD("MG_State: Buffer: DeleteN called with n=%d", n);
|
||||
if (n < 0) return GL_INVALID_VALUE;
|
||||
|
||||
for (GLsizei i = 0; i < n; ++i) {
|
||||
Delete(buffers[i]);
|
||||
}
|
||||
MG_Util::Debug::LogD("MG_State: Buffer: DeleteN deleted buffers successfully");
|
||||
return GL_NO_ERROR;
|
||||
}
|
||||
|
||||
bool BufferState::IsValidTarget_(GLenum target) {
|
||||
MG_Util::Debug::LogD("MG_State: Buffer: IsValidTarget_ called with target=0x%x,result=%d", target, !(MG_Constants::Buffer::VALID_TARGETS.find(target) == MG_Constants::Buffer::VALID_TARGETS.end()));
|
||||
return !(MG_Constants::Buffer::VALID_TARGETS.find(target) == MG_Constants::Buffer::VALID_TARGETS.end());
|
||||
}
|
||||
|
||||
GLenum BufferState::QueryPropertyIntVector(GLenum target, GLenum pname, GLint* params) const {
|
||||
MG_Util::Debug::LogD("MG_State: Buffer: QueryPropertyIntVector called at target 0x%x,param name = 0x%x",target,pname);
|
||||
static const std::set<GLenum> validTargets = {
|
||||
GL_ARRAY_BUFFER, GL_ELEMENT_ARRAY_BUFFER,
|
||||
GL_PIXEL_PACK_BUFFER, GL_PIXEL_UNPACK_BUFFER
|
||||
};
|
||||
if (validTargets.find(target) == validTargets.end()) {
|
||||
return GL_INVALID_ENUM;
|
||||
}
|
||||
|
||||
if (MG_Constants::Buffer::VALID_PARAM_NAMES.find(pname) == MG_Constants::Buffer::VALID_PARAM_NAMES.end()) {
|
||||
return GL_INVALID_ENUM;
|
||||
}
|
||||
|
||||
auto bindingIt = currentBindings_.find(target);
|
||||
if (bindingIt == currentBindings_.end() || bindingIt->second == 0) {
|
||||
return GL_INVALID_OPERATION;
|
||||
}
|
||||
GLuint bufferId = bindingIt->second;
|
||||
auto bufferIt = buffers_.find(bufferId);
|
||||
if (bufferIt == buffers_.end()) {
|
||||
return GL_INVALID_OPERATION;
|
||||
}
|
||||
|
||||
const BufferObject& buffer = bufferIt->second;
|
||||
|
||||
switch (pname) {
|
||||
case GL_BUFFER_ACCESS:
|
||||
*params = static_cast<GLint>(buffer.accessMode);
|
||||
break;
|
||||
case GL_BUFFER_MAPPED:
|
||||
*params = buffer.isMapped ? GL_TRUE : GL_FALSE;
|
||||
break;
|
||||
case GL_BUFFER_SIZE:
|
||||
*params = static_cast<GLint>(buffer.data.size());
|
||||
break;
|
||||
case GL_BUFFER_USAGE:
|
||||
*params = static_cast<GLint>(buffer.usage);
|
||||
break;
|
||||
MG_Util::Debug::LogD("MG_State: Buffer: QueryPropertyIntVector Query info about buffer %u succeed", target);
|
||||
default:
|
||||
return GL_INVALID_ENUM;
|
||||
}
|
||||
return GL_NO_ERROR;
|
||||
}
|
||||
|
||||
|
||||
GLuint BufferState::GetCurrentBinding(GLenum target) const {
|
||||
auto it = currentBindings_.find(target);
|
||||
if (it != currentBindings_.end()) {
|
||||
return it->second;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -1,58 +0,0 @@
|
||||
//
|
||||
// Created by BZLZHH on 2025/5/1.
|
||||
//
|
||||
|
||||
#ifndef MOBILEGL_BUFFERSTATE_H
|
||||
#define MOBILEGL_BUFFERSTATE_H
|
||||
#define MOBILEGL_GLSTATE_H
|
||||
|
||||
#include "../../../Includes.h"
|
||||
|
||||
class BufferState {
|
||||
template <typename K, typename V>
|
||||
using unordered_map = ankerl::unordered_dense::map<K, V>;
|
||||
|
||||
public:
|
||||
struct BufferObject {
|
||||
GLenum usage = GL_STATIC_DRAW;
|
||||
std::vector<GLubyte> data;
|
||||
bool dataValid = false;
|
||||
bool dirty = false; // TODO: encapsulate this with an public API to RHI
|
||||
bool isMapped = false;
|
||||
bool generated = false;
|
||||
GLenum accessMode = GL_READ_WRITE;
|
||||
GLintptr mapOffset = 0;
|
||||
GLsizeiptr mapLength = 0;
|
||||
GLbitfield mapAccessFlags = 0;
|
||||
};
|
||||
|
||||
// Return: the validity of the operation, according to OpenGL 3 standard
|
||||
GLenum GenName(GLuint* buffer);
|
||||
GLenum GenNameN(GLsizei n, GLuint* buffers);
|
||||
GLenum Create(GLuint buffer);
|
||||
GLenum Bind(GLenum target, GLuint buffer);
|
||||
GLenum CommitStorage(GLenum target, GLsizeiptr size, const void* data, GLenum usage);
|
||||
GLenum CommitStorageRegion(GLenum target, GLintptr offset, GLsizeiptr size, const void* data);
|
||||
GLenum AcquireBufferMemoryRange(GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access, void** mappedPointer);
|
||||
GLenum SyncBufferMemory(GLenum target, GLintptr offset, GLsizeiptr length);
|
||||
GLenum CopyBufferRange(GLenum readTarget, GLenum writeTarget, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size);
|
||||
GLenum AcquireBufferMemory(GLenum target, GLenum access, void** mappedPointer);
|
||||
GLenum ReleaseBufferMemory(GLenum target);
|
||||
GLenum QueryPropertyIntVector(GLenum target, GLenum pname, GLint* params) const;
|
||||
GLenum DeleteN(GLsizei n, const GLuint* buffers);
|
||||
|
||||
bool ValidateAllocatedHandle(GLuint buffer);
|
||||
bool ValidateGeneratedName(GLuint buffer);
|
||||
void Delete(GLuint buffer);
|
||||
GLuint GetCurrentBinding(GLenum target) const;
|
||||
|
||||
unordered_map<GLenum, GLuint> currentBindings_;
|
||||
unordered_map<GLuint, BufferObject> buffers_;
|
||||
private:
|
||||
std::vector<GLuint> freeId_;
|
||||
GLuint lastId_ = 1;
|
||||
|
||||
static bool IsValidTarget_(GLenum target);
|
||||
};
|
||||
|
||||
#endif //MOBILEGL_BUFFERSTATE_H
|
||||
@@ -1,158 +0,0 @@
|
||||
//
|
||||
// Created by BZLZHH on 2025/4/30.
|
||||
//
|
||||
|
||||
#include "CommonState.h"
|
||||
|
||||
CommonState::CommonState() {
|
||||
pixelStoreParams[GL_PACK_ALIGNMENT] = 4;
|
||||
pixelStoreParams[GL_UNPACK_ALIGNMENT] = 4;
|
||||
}
|
||||
|
||||
GLenum CommonState::SetPixelStoreInt(GLenum pname, GLint param) {
|
||||
if (MG_Constants::PixelStore::VALID_PARAM_NAMES.find(pname) == MG_Constants::PixelStore::VALID_PARAM_NAMES.end()) {
|
||||
return GL_INVALID_ENUM;
|
||||
}
|
||||
|
||||
switch (pname) {
|
||||
case GL_PACK_SWAP_BYTES:
|
||||
case GL_PACK_LSB_FIRST:
|
||||
case GL_UNPACK_SWAP_BYTES:
|
||||
case GL_UNPACK_LSB_FIRST:
|
||||
break;
|
||||
case GL_PACK_ROW_LENGTH:
|
||||
case GL_PACK_IMAGE_HEIGHT:
|
||||
case GL_PACK_SKIP_ROWS:
|
||||
case GL_PACK_SKIP_PIXELS:
|
||||
case GL_PACK_SKIP_IMAGES:
|
||||
case GL_UNPACK_ROW_LENGTH:
|
||||
case GL_UNPACK_IMAGE_HEIGHT:
|
||||
case GL_UNPACK_SKIP_ROWS:
|
||||
case GL_UNPACK_SKIP_PIXELS:
|
||||
case GL_UNPACK_SKIP_IMAGES:
|
||||
if (param < 0) {
|
||||
return GL_INVALID_VALUE;
|
||||
}
|
||||
break;
|
||||
|
||||
case GL_PACK_ALIGNMENT:
|
||||
case GL_UNPACK_ALIGNMENT:
|
||||
if (param != 1 && param != 2 && param != 4 && param != 8) {
|
||||
return GL_INVALID_VALUE;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
return GL_INVALID_ENUM;
|
||||
}
|
||||
|
||||
pixelStoreParams[pname] = param;
|
||||
return GL_NO_ERROR;
|
||||
}
|
||||
|
||||
GLint CommonState::QueryPixelStoreInt(GLenum pname) {
|
||||
auto it = pixelStoreParams.find(pname);
|
||||
if (it != pixelStoreParams.end()) {
|
||||
return it->second;
|
||||
}
|
||||
|
||||
auto defaultIt = MG_Constants::PixelStore::DEFAULT_VALUES_MAP.find(pname);
|
||||
return (defaultIt != MG_Constants::PixelStore::DEFAULT_VALUES_MAP.end()) ? defaultIt->second : 0;
|
||||
}
|
||||
|
||||
GLenum CommonState::Enable(GLenum cap) {
|
||||
if (MG_Constants::CommonState::VALID_CAPS.find(cap) == MG_Constants::CommonState::VALID_CAPS.end()) {
|
||||
return GL_INVALID_ENUM;
|
||||
}
|
||||
capabilities[cap] = true;
|
||||
return GL_NO_ERROR;
|
||||
}
|
||||
|
||||
GLenum CommonState::Disable(GLenum cap) {
|
||||
if (MG_Constants::CommonState::VALID_CAPS.find(cap) == MG_Constants::CommonState::VALID_CAPS.end()) {
|
||||
return GL_INVALID_ENUM;
|
||||
}
|
||||
capabilities[cap] = false;
|
||||
return GL_NO_ERROR;
|
||||
}
|
||||
|
||||
GLenum CommonState::BlendFunc(GLenum sfactor, GLenum dfactor) {
|
||||
if (MG_Constants::Blend::VALID_FACTORS.find(sfactor) == MG_Constants::Blend::VALID_FACTORS.end() ||
|
||||
MG_Constants::Blend::VALID_FACTORS.find(dfactor) == MG_Constants::Blend::VALID_FACTORS.end()) {
|
||||
return GL_INVALID_ENUM;
|
||||
}
|
||||
|
||||
blendSrcRGB = blendSrcAlpha = sfactor;
|
||||
blendDstRGB = blendDstAlpha = dfactor;
|
||||
return GL_NO_ERROR;
|
||||
}
|
||||
|
||||
GLenum CommonState::BlendFuncSeparate(GLenum srcRGB, GLenum dstRGB,
|
||||
GLenum srcAlpha, GLenum dstAlpha) {
|
||||
if (MG_Constants::Blend::VALID_FACTORS.find(srcRGB) == MG_Constants::Blend::VALID_FACTORS.end() ||
|
||||
MG_Constants::Blend::VALID_FACTORS.find(dstRGB) == MG_Constants::Blend::VALID_FACTORS.end() ||
|
||||
MG_Constants::Blend::VALID_FACTORS.find(srcAlpha) == MG_Constants::Blend::VALID_FACTORS.end() ||
|
||||
MG_Constants::Blend::VALID_FACTORS.find(dstAlpha) == MG_Constants::Blend::VALID_FACTORS.end()) {
|
||||
return GL_INVALID_ENUM;
|
||||
}
|
||||
blendSrcRGB = srcRGB;
|
||||
blendDstRGB = dstRGB;
|
||||
blendSrcAlpha = srcAlpha;
|
||||
blendDstAlpha = dstAlpha;
|
||||
return GL_NO_ERROR;
|
||||
}
|
||||
|
||||
GLenum CommonState::Clear(GLbitfield mask) {
|
||||
const GLbitfield validBits = GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT;
|
||||
if ((mask & ~validBits) != 0) {
|
||||
return GL_INVALID_VALUE;
|
||||
}
|
||||
clearMask = mask;
|
||||
return GL_NO_ERROR;
|
||||
}
|
||||
|
||||
GLenum CommonState::ClearColor(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha) {
|
||||
clearColor[0] = red;
|
||||
clearColor[1] = green;
|
||||
clearColor[2] = blue;
|
||||
clearColor[3] = alpha;
|
||||
return GL_NO_ERROR;
|
||||
}
|
||||
|
||||
GLenum CommonState::ClearDepth(GLfloat depth) {
|
||||
clearDepth = depth;
|
||||
return GL_NO_ERROR;
|
||||
}
|
||||
|
||||
GLenum CommonState::ColorMask(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha) {
|
||||
colorMask[0] = red;
|
||||
colorMask[1] = green;
|
||||
colorMask[2] = blue;
|
||||
colorMask[3] = alpha;
|
||||
return GL_NO_ERROR;
|
||||
}
|
||||
|
||||
GLenum CommonState::DepthFunc(GLenum func) {
|
||||
if (MG_Constants::Depth::VALID_FUNCS.find(func) == MG_Constants::Depth::VALID_FUNCS.end()) {
|
||||
return GL_INVALID_ENUM;
|
||||
}
|
||||
depthFunc = func;
|
||||
return GL_NO_ERROR;
|
||||
}
|
||||
|
||||
GLenum CommonState::DepthMask(GLboolean flag) {
|
||||
depthMask = flag;
|
||||
return GL_NO_ERROR;
|
||||
}
|
||||
|
||||
GLenum CommonState::Viewport(GLint x, GLint y, GLsizei width, GLsizei height) {
|
||||
if (width < 0 || height < 0) {
|
||||
return GL_INVALID_VALUE;
|
||||
}
|
||||
|
||||
viewport[0] = x;
|
||||
viewport[1] = y;
|
||||
viewport[2] = width;
|
||||
viewport[3] = height;
|
||||
return GL_NO_ERROR;
|
||||
}
|
||||
@@ -1,65 +0,0 @@
|
||||
//
|
||||
// Created by BZLZHH on 2025/4/30.
|
||||
//
|
||||
|
||||
#ifndef MOBILEGL_COMMONSTATE_H
|
||||
#define MOBILEGL_COMMONSTATE_H
|
||||
#define MOBILEGL_GLSTATE_H
|
||||
|
||||
#include "../../../Includes.h"
|
||||
|
||||
class CommonState {
|
||||
template <typename K, typename V>
|
||||
using unordered_map = ankerl::unordered_dense::map<K, V>;
|
||||
public:
|
||||
// Viewport
|
||||
GLint viewport[4] = {0, 0, 0, 0};
|
||||
|
||||
// Color mask
|
||||
GLboolean colorMask[4] = {GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE};
|
||||
|
||||
// Pixel storage parameters
|
||||
unordered_map<GLenum, GLint> pixelStoreParams;
|
||||
|
||||
// Blend state
|
||||
GLenum blendSrcRGB = GL_ONE;
|
||||
GLenum blendDstRGB = GL_ZERO;
|
||||
GLenum blendSrcAlpha = GL_ONE;
|
||||
GLenum blendDstAlpha = GL_ZERO;
|
||||
|
||||
// Clear state
|
||||
GLfloat clearColor[4] = {0.0f, 0.0f, 0.0f, 0.0f};
|
||||
GLfloat clearDepth = 1.0f;
|
||||
GLenum clearMask;
|
||||
|
||||
// Depth state
|
||||
GLenum depthFunc = GL_LESS;
|
||||
GLboolean depthMask = GL_TRUE;
|
||||
|
||||
// Capability enables
|
||||
unordered_map<GLenum, bool> capabilities;
|
||||
|
||||
CommonState();
|
||||
|
||||
// Return: the validity of the operation, according to OpenGL 3 standard
|
||||
GLenum SetPixelStoreInt(GLenum pname, GLint param);
|
||||
|
||||
GLenum Enable(GLenum cap);
|
||||
GLenum Disable(GLenum cap);
|
||||
GLenum BlendFunc(GLenum sfactor, GLenum dfactor);
|
||||
GLenum BlendFuncSeparate(GLenum srcRGB, GLenum dstRGB,
|
||||
GLenum srcAlpha, GLenum dstAlpha);
|
||||
GLenum Clear(GLbitfield mask);
|
||||
GLenum ClearColor(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha);
|
||||
GLenum ClearDepth(GLfloat depth);
|
||||
GLenum ColorMask(GLboolean red, GLboolean green,
|
||||
GLboolean blue, GLboolean alpha);
|
||||
GLenum DepthFunc(GLenum func);
|
||||
GLenum DepthMask(GLboolean flag);
|
||||
GLenum Viewport(GLint x, GLint y, GLsizei width, GLsizei height);
|
||||
|
||||
GLint QueryPixelStoreInt(GLenum pname);
|
||||
|
||||
};
|
||||
|
||||
#endif //MOBILEGL_COMMONSTATE_H
|
||||
@@ -1,407 +0,0 @@
|
||||
//
|
||||
// Created by BZLZHH on 2025/4/4.
|
||||
//
|
||||
|
||||
#include "GLState.h"
|
||||
|
||||
std::queue<GLenum> MG_State_T::glErrorQueue;
|
||||
TextureState* MG_State_T::textureState = nullptr;
|
||||
CommonState* MG_State_T::commonState = nullptr;
|
||||
BufferState* MG_State_T::bufferState = nullptr;
|
||||
VertexArrayState* MG_State_T::vertexArrayState = nullptr;
|
||||
ProgramState* MG_State_T::programState = nullptr;
|
||||
FramebufferState* MG_State_T::framebufferState = nullptr;
|
||||
|
||||
namespace MG_State {
|
||||
void Init() {
|
||||
MG_State_T::textureState = new TextureState();
|
||||
MG_State_T::commonState = new CommonState();
|
||||
MG_State_T::bufferState = new BufferState();
|
||||
MG_State_T::vertexArrayState = new VertexArrayState();
|
||||
MG_State_T::programState = new ProgramState();
|
||||
MG_State_T::framebufferState = new FramebufferState();
|
||||
}
|
||||
|
||||
void Destroy() {
|
||||
delete MG_State_T::textureState;
|
||||
delete MG_State_T::commonState;
|
||||
delete MG_State_T::bufferState;
|
||||
delete MG_State_T::vertexArrayState;
|
||||
delete MG_State_T::programState;
|
||||
delete MG_State_T::framebufferState;
|
||||
}
|
||||
|
||||
void SetError(GLenum error) {
|
||||
if (error == GL_NO_ERROR) {
|
||||
return;
|
||||
}
|
||||
MG_State_T::glErrorQueue.push(error);
|
||||
}
|
||||
|
||||
GLenum GetError() {
|
||||
if (MG_State_T::glErrorQueue.empty()) {
|
||||
return GL_NO_ERROR;
|
||||
}
|
||||
GLenum error = MG_State_T::glErrorQueue.front();
|
||||
MG_State_T::glErrorQueue.pop();
|
||||
return error;
|
||||
}
|
||||
|
||||
// TODO: Take these functions apart into multiple files.
|
||||
|
||||
// Texture
|
||||
GLenum BindTextureUnit(GLenum textureUnit) {
|
||||
return MG_State_T::textureState->BindUnit(textureUnit);
|
||||
}
|
||||
|
||||
GLenum CreateTexture(GLuint* texture) {
|
||||
return MG_State_T::textureState->Create(texture);
|
||||
}
|
||||
|
||||
GLenum CreateTextures(GLsizei n, GLuint* textures) {
|
||||
return MG_State_T::textureState->CreateN(n, textures);
|
||||
}
|
||||
|
||||
GLenum BindTexture(GLenum target, GLuint texture) {
|
||||
return MG_State_T::textureState->Bind(target, texture);
|
||||
}
|
||||
|
||||
GLenum UploadTexture2D(GLenum target, GLint level, GLint internalFormat,
|
||||
GLsizei width, GLsizei height, GLint border, GLenum format,
|
||||
GLenum type, const void* data) {
|
||||
return MG_State_T::textureState->Upload2D(target, level, internalFormat, width, height, border, format, type, data);
|
||||
}
|
||||
|
||||
GLenum UpdateTextureRegion2D(GLenum target, GLint level, GLint xoffset,
|
||||
GLint yoffset, GLsizei width, GLsizei height, GLenum format,
|
||||
GLenum type, const GLvoid* data) {
|
||||
return MG_State_T::textureState->UpdateRegion2D(target, level, xoffset, yoffset, width, height, format, type, data);
|
||||
}
|
||||
|
||||
GLenum SetTexturePropertyInt(GLenum target, GLenum pname, GLint param) {
|
||||
return MG_State_T::textureState->SetTexturePropertyInt(target, pname, param);
|
||||
}
|
||||
|
||||
GLenum SetTexturePropertyFloat(GLenum target, GLenum pname, GLfloat param) {
|
||||
return MG_State_T::textureState->SetTexturePropertyFloat(target, pname, param);
|
||||
}
|
||||
|
||||
GLenum DeleteTexture(GLuint texture) {
|
||||
return MG_State_T::textureState->Delete(texture);
|
||||
}
|
||||
|
||||
GLenum DeleteTextures(GLsizei n, const GLuint* textures) {
|
||||
return MG_State_T::textureState->DeleteN(n, textures);
|
||||
}
|
||||
|
||||
GLenum QueryTextureLevelPropertyIntVector(GLenum target, GLint level, GLenum pname, GLint* params) {
|
||||
return MG_State_T::textureState->QueryLevelPropertyIntVector(target, level, pname, params);
|
||||
}
|
||||
|
||||
// Common
|
||||
GLenum SetPixelStoreInt(GLenum pname, GLint param) {
|
||||
return MG_State_T::commonState->SetPixelStoreInt(pname, param);
|
||||
}
|
||||
|
||||
GLint QueryPixelStoreInt(GLenum pname) {
|
||||
return MG_State_T::commonState->QueryPixelStoreInt(pname);
|
||||
}
|
||||
|
||||
GLenum glEnable(GLenum cap) {
|
||||
return MG_State_T::commonState->Enable(cap);
|
||||
}
|
||||
|
||||
GLenum glDisable(GLenum cap) {
|
||||
return MG_State_T::commonState->Disable(cap);
|
||||
}
|
||||
|
||||
GLenum glBlendFunc(GLenum sfactor, GLenum dfactor) {
|
||||
return MG_State_T::commonState->BlendFunc(sfactor, dfactor);
|
||||
}
|
||||
|
||||
GLenum glBlendFuncSeparate(GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha) {
|
||||
return MG_State_T::commonState->BlendFuncSeparate(srcRGB, dstRGB, srcAlpha, dstAlpha);
|
||||
}
|
||||
|
||||
GLenum glClear(GLbitfield mask) {
|
||||
return MG_State_T::commonState->Clear(mask);
|
||||
}
|
||||
|
||||
GLenum glClearColor(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha) {
|
||||
return MG_State_T::commonState->ClearColor(red, green, blue, alpha);
|
||||
}
|
||||
|
||||
GLenum glClearDepth(GLdouble depth) {
|
||||
return MG_State_T::commonState->ClearDepth(static_cast<GLfloat>(depth));
|
||||
}
|
||||
|
||||
GLenum glColorMask(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha) {
|
||||
return MG_State_T::commonState->ColorMask(red, green, blue, alpha);
|
||||
}
|
||||
|
||||
GLenum glDepthFunc(GLenum func) {
|
||||
return MG_State_T::commonState->DepthFunc(func);
|
||||
}
|
||||
|
||||
GLenum glDepthMask(GLboolean flag) {
|
||||
return MG_State_T::commonState->DepthMask(flag);
|
||||
}
|
||||
|
||||
GLenum glViewport(GLint x, GLint y, GLsizei width, GLsizei height) {
|
||||
return MG_State_T::commonState->Viewport(x, y, width, height);
|
||||
}
|
||||
|
||||
// Buffer
|
||||
GLenum AcquireBufferMemory(GLenum target, GLenum access, void** mappedPtr) {
|
||||
return MG_State_T::bufferState->AcquireBufferMemory(target, access, mappedPtr);
|
||||
}
|
||||
|
||||
GLenum AcquireBufferMemoryRange(GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access, void** mappedPointer) {
|
||||
return MG_State_T::bufferState->AcquireBufferMemoryRange(target, offset, length, access, mappedPointer);
|
||||
}
|
||||
|
||||
GLenum SyncBufferMemory(GLenum target, GLintptr offset, GLsizeiptr length) {
|
||||
return MG_State_T::bufferState->SyncBufferMemory(target, offset, length);
|
||||
}
|
||||
|
||||
GLenum CopyBufferRange(GLenum readTarget, GLenum writeTarget, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size) {
|
||||
return MG_State_T::bufferState->CopyBufferRange(readTarget, writeTarget, readOffset,
|
||||
writeOffset, size);
|
||||
}
|
||||
|
||||
GLenum ReleaseBufferMemory(GLenum target) {
|
||||
return MG_State_T::bufferState->ReleaseBufferMemory(target);
|
||||
}
|
||||
|
||||
GLenum CreateBuffer(GLuint buffer) {
|
||||
return MG_State_T::bufferState->Create(buffer);
|
||||
}
|
||||
|
||||
GLenum GenBufferNames(GLsizei n, GLuint* buffers) {
|
||||
return MG_State_T::bufferState->GenNameN(n, buffers);
|
||||
}
|
||||
|
||||
GLenum BindBuffer(GLenum target, GLuint buffer) {
|
||||
if (target == GL_ELEMENT_ARRAY_BUFFER) {
|
||||
auto* vao = MG_State_T::vertexArrayState->GetCurrentVAO();
|
||||
if (!vao) return GL_INVALID_OPERATION;
|
||||
vao->elementBuffer = (GLuint)buffer;
|
||||
vao->eboDirty = true;
|
||||
}
|
||||
return MG_State_T::bufferState->Bind(target, buffer);
|
||||
}
|
||||
|
||||
GLenum CommitBufferStorage(GLenum target, GLsizeiptr size, const void* data, GLenum usage) {
|
||||
return MG_State_T::bufferState->CommitStorage(target, size, data, usage);
|
||||
}
|
||||
|
||||
GLenum CommitBufferStorageRegion(GLenum target, GLintptr offset, GLsizeiptr size, const void* data) {
|
||||
return MG_State_T::bufferState->CommitStorageRegion(target, offset, size, data);
|
||||
}
|
||||
|
||||
bool ValidateAllocatedBufferHandle(GLuint buffer) {
|
||||
return MG_State_T::bufferState->ValidateAllocatedHandle(buffer);
|
||||
}
|
||||
|
||||
bool ValidateGeneratedName(GLuint buffer) {
|
||||
return MG_State_T::bufferState->ValidateGeneratedName(buffer);
|
||||
}
|
||||
|
||||
void DeleteBuffer(GLuint buffer) {
|
||||
return MG_State_T::bufferState->Delete(buffer);
|
||||
}
|
||||
|
||||
GLenum DeleteBuffers(GLsizei n, const GLuint* buffers) {
|
||||
return MG_State_T::bufferState->DeleteN(n, buffers);
|
||||
}
|
||||
|
||||
GLenum QueryBufferPropertyIntVector(GLenum target, GLenum pname, GLint* params) {
|
||||
return MG_State_T::bufferState->QueryPropertyIntVector(target, pname, params);
|
||||
}
|
||||
|
||||
// VertexArray
|
||||
GLenum BindVertexArray(GLuint array) {
|
||||
return MG_State_T::vertexArrayState->Bind(array);
|
||||
}
|
||||
|
||||
GLenum CreateVertexArray(GLuint* array) {
|
||||
return MG_State_T::vertexArrayState->Create(array);
|
||||
}
|
||||
|
||||
GLenum CreateVertexArrays(GLsizei n, GLuint* arrays) {
|
||||
return MG_State_T::vertexArrayState->CreateN(n, arrays);
|
||||
}
|
||||
|
||||
GLenum GenVertexArraysNames(GLsizei n, GLuint* arrays) {
|
||||
return MG_State_T::vertexArrayState->GenNameN(n, arrays);
|
||||
}
|
||||
|
||||
GLenum EnableVertexAttribArray(GLuint index) {
|
||||
return MG_State_T::vertexArrayState->EnableAttrib(index);
|
||||
}
|
||||
|
||||
GLenum DisableVertexAttribArray(GLuint index) {
|
||||
return MG_State_T::vertexArrayState->DisableAttrib(index);
|
||||
}
|
||||
|
||||
GLenum SetVertexAttributeLayout(GLuint index, GLint size, GLenum type,
|
||||
GLboolean normalized, GLsizei stride,
|
||||
const void* pointer) {
|
||||
GLuint currentBuffer = MG_State_T::bufferState->GetCurrentBinding(GL_ARRAY_BUFFER);
|
||||
return MG_State_T::vertexArrayState->SetAttribPointer(
|
||||
index, size, type, normalized, stride, pointer, false, currentBuffer
|
||||
);
|
||||
}
|
||||
|
||||
GLenum SetVertexAttributeLayoutInt(GLuint index, GLint size, GLenum type,
|
||||
GLsizei stride, const void* pointer) {
|
||||
GLuint currentBuffer = MG_State_T::bufferState->GetCurrentBinding(GL_ARRAY_BUFFER);
|
||||
return MG_State_T::vertexArrayState->SetAttribPointer(
|
||||
index, size, type, GL_FALSE, stride, pointer, true, currentBuffer
|
||||
);
|
||||
}
|
||||
|
||||
// Program
|
||||
GLenum CreateShader(GLenum type, GLuint* shader) {
|
||||
return MG_State_T::programState->CreateShader(type, shader);
|
||||
}
|
||||
|
||||
GLenum CreateProgram(GLuint* program) {
|
||||
return MG_State_T::programState->CreateProgram(program);
|
||||
}
|
||||
|
||||
GLenum DeleteShader(GLuint shader) {
|
||||
return MG_State_T::programState->DeleteShader(shader);
|
||||
}
|
||||
|
||||
GLenum DeleteProgram(GLuint program) {
|
||||
return MG_State_T::programState->DeleteProgram(program);
|
||||
}
|
||||
|
||||
GLenum LinkShaderToProgram(GLuint program, GLuint shader) {
|
||||
return MG_State_T::programState->LinkShaderToProgram(program, shader);
|
||||
}
|
||||
|
||||
GLenum UploadShaderSource(GLuint shader, GLsizei count, const GLchar** string, const GLint* length) {
|
||||
return MG_State_T::programState->UploadShaderSource(shader, count, string, length);
|
||||
}
|
||||
|
||||
GLenum BuildShaderStage(GLuint shader) {
|
||||
return MG_State_T::programState->BuildShaderStage(shader);
|
||||
}
|
||||
|
||||
GLenum FinalizeProgramPipeline(GLuint program) {
|
||||
return MG_State_T::programState->FinalizeProgramPipeline(program);
|
||||
}
|
||||
|
||||
GLenum ActivateRenderProgram(GLuint program) {
|
||||
return MG_State_T::programState->ActivateRenderProgram(program);
|
||||
}
|
||||
|
||||
GLenum DefineProgramAttributeBinding(GLuint program, GLuint index, const GLchar* name) {
|
||||
return MG_State_T::programState->DefineProgramAttributeBinding(program, index, name);
|
||||
}
|
||||
|
||||
GLint QueryProgramAttributeBinding(GLuint program, const GLchar* name) {
|
||||
return MG_State_T::programState->QueryProgramAttributeBinding(program, name);
|
||||
}
|
||||
|
||||
GLint QueryProgramUniformLocation(GLuint program, const GLchar* name) {
|
||||
return MG_State_T::programState->QueryProgramUniformLocation(program, name);
|
||||
}
|
||||
|
||||
GLenum QueryProgramStateIntVector(GLuint program, GLenum pname, GLint* params) {
|
||||
return MG_State_T::programState->QueryProgramStateIntVector(program, pname, params);
|
||||
}
|
||||
|
||||
GLenum QueryShaderStateIntVector(GLuint shader, GLenum pname, GLint* params) {
|
||||
return MG_State_T::programState->QueryShaderStateIntVector(shader, pname, params);
|
||||
}
|
||||
|
||||
#define IMPLEMENT_UNIFORM_FUNCTIONS(type, suffix, vecType) \
|
||||
void UpdateProgramUniform##suffix##1(GLint location, type v0) { \
|
||||
MG_State_T::programState->UpdateUniform##suffix##1(location, v0); \
|
||||
} \
|
||||
void UpdateProgramUniform##suffix##2(GLint location, type v0, type v1) { \
|
||||
MG_State_T::programState->UpdateUniform##suffix##2(location, v0, v1); \
|
||||
} \
|
||||
void UpdateProgramUniform##suffix##3(GLint location, type v0, type v1, type v2) { \
|
||||
MG_State_T::programState->UpdateUniform##suffix##3(location, v0, v1, v2); \
|
||||
} \
|
||||
void UpdateProgramUniform##suffix##4(GLint location, type v0, type v1, type v2, type v3) { \
|
||||
MG_State_T::programState->UpdateUniform##suffix##4(location, v0, v1, v2, v3); \
|
||||
} \
|
||||
void UpdateProgramUniform##suffix##Vector1(GLint location, GLsizei count, const type* value) { \
|
||||
MG_State_T::programState->UpdateUniform##suffix##Vector1(location, count,value); \
|
||||
} \
|
||||
void UpdateProgramUniform##suffix##Vector2(GLint location, GLsizei count, const type* value) { \
|
||||
MG_State_T::programState->UpdateUniform##suffix##Vector2(location, count, value); \
|
||||
} \
|
||||
void UpdateProgramUniform##suffix##Vector3(GLint location, GLsizei count, const type* value) { \
|
||||
MG_State_T::programState->UpdateUniform##suffix##Vector3(location, count, value); \
|
||||
} \
|
||||
void UpdateProgramUniform##suffix##Vector4(GLint location, GLsizei count, const type* value) { \
|
||||
MG_State_T::programState->UpdateUniform##suffix##Vector4(location, count, value); \
|
||||
}
|
||||
|
||||
IMPLEMENT_UNIFORM_FUNCTIONS(GLfloat, Float, GL_FLOAT_VEC4)
|
||||
IMPLEMENT_UNIFORM_FUNCTIONS(GLint, Int, GL_INT_VEC4)
|
||||
IMPLEMENT_UNIFORM_FUNCTIONS(GLuint, UInt, GL_UNSIGNED_INT_VEC4)
|
||||
IMPLEMENT_UNIFORM_FUNCTIONS(GLboolean, Bool, GL_BOOL_VEC4)
|
||||
#undef IMPLEMENT_UNIFORM_FUNCTIONS
|
||||
|
||||
#define IMPLEMENT_MATRIX_FUNCTIONS(suffix, matrixType) \
|
||||
void UpdateProgramUniformMatrix##suffix##Vector(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) { \
|
||||
MG_State_T::programState->UpdateUniformMatrix##suffix##Vector(location, count, transpose, value); \
|
||||
}
|
||||
|
||||
IMPLEMENT_MATRIX_FUNCTIONS(2x2, GL_FLOAT_MAT2)
|
||||
IMPLEMENT_MATRIX_FUNCTIONS(3x3, GL_FLOAT_MAT3)
|
||||
IMPLEMENT_MATRIX_FUNCTIONS(4x4, GL_FLOAT_MAT4)
|
||||
IMPLEMENT_MATRIX_FUNCTIONS(2x3, GL_FLOAT_MAT2x3)
|
||||
IMPLEMENT_MATRIX_FUNCTIONS(2x4, GL_FLOAT_MAT2x4)
|
||||
IMPLEMENT_MATRIX_FUNCTIONS(3x2, GL_FLOAT_MAT3x2)
|
||||
IMPLEMENT_MATRIX_FUNCTIONS(3x4, GL_FLOAT_MAT3x4)
|
||||
IMPLEMENT_MATRIX_FUNCTIONS(4x2, GL_FLOAT_MAT4x2)
|
||||
IMPLEMENT_MATRIX_FUNCTIONS(4x3, GL_FLOAT_MAT4x3)
|
||||
#undef IMPLEMENT_MATRIX_FUNCTIONS
|
||||
|
||||
GLuint GetCurrentProgram() {
|
||||
return MG_State_T::programState->GetCurrentProgram();
|
||||
}
|
||||
|
||||
bool SetProgramStatus(GLuint program, GLboolean status) {
|
||||
return MG_State_T::programState->SetProgramStatus(program, status);
|
||||
}
|
||||
|
||||
bool SetShaderStatus(GLuint shader, GLboolean status) {
|
||||
return MG_State_T::programState->SetShaderStatus(shader, status);
|
||||
}
|
||||
|
||||
// Framebuffer
|
||||
GLenum MG_State::CreateFramebuffer(GLuint* framebuffer) {
|
||||
return MG_State_T::framebufferState->Create(framebuffer);
|
||||
}
|
||||
|
||||
GLenum MG_State::CreateFramebuffers(GLsizei n, GLuint* framebuffers) {
|
||||
return MG_State_T::framebufferState->CreateN(n, framebuffers);
|
||||
}
|
||||
|
||||
GLenum MG_State::DeleteFramebuffer(GLuint framebuffer) {
|
||||
return MG_State_T::framebufferState->Delete(framebuffer);
|
||||
}
|
||||
|
||||
GLenum MG_State::BindFramebuffer(GLenum target, GLuint framebuffer) {
|
||||
return MG_State_T::framebufferState->Bind(target, framebuffer);
|
||||
}
|
||||
|
||||
GLenum MG_State::AttachTexture2DToFramebuffer(GLenum target, GLenum attachment, GLenum textarget,
|
||||
GLuint texture, GLint level) {
|
||||
return MG_State_T::framebufferState->AttachTexture2D(target, attachment, textarget,
|
||||
texture, level);
|
||||
}
|
||||
|
||||
GLenum MG_State::ValidateFramebufferCompleteness(GLenum target) {
|
||||
return MG_State_T::framebufferState->ValidateCompleteness(target);
|
||||
}
|
||||
}
|
||||
@@ -1,151 +0,0 @@
|
||||
//
|
||||
// Created by BZLZHH on 2025/4/4.
|
||||
//
|
||||
|
||||
#ifndef MOBILEGL_GLSTATE_H
|
||||
#define MOBILEGL_GLSTATE_H
|
||||
|
||||
#include "../../../Includes.h"
|
||||
|
||||
struct MG_State_T {
|
||||
static std::queue<GLenum> glErrorQueue;
|
||||
static TextureState* textureState;
|
||||
static CommonState* commonState;
|
||||
static BufferState* bufferState;
|
||||
static VertexArrayState* vertexArrayState;
|
||||
static ProgramState* programState;
|
||||
static FramebufferState* framebufferState;
|
||||
};
|
||||
|
||||
namespace MG_State {
|
||||
void Init();
|
||||
void Destroy();
|
||||
void SetError(GLenum error);
|
||||
GLenum GetError();
|
||||
|
||||
//Texture
|
||||
GLenum BindTextureUnit(GLenum textureUnit);
|
||||
GLenum CreateTexture(GLuint* texture);
|
||||
GLenum CreateTextures(GLsizei n, GLuint* textures);
|
||||
GLenum BindTexture(GLenum target, GLuint texture);
|
||||
GLenum UploadTexture2D(GLenum target, GLint level, GLint internalFormat,
|
||||
GLsizei width, GLsizei height, GLint border, GLenum format,
|
||||
GLenum type, const void* data);
|
||||
GLenum UpdateTextureRegion2D(GLenum target, GLint level, GLint xoffset,
|
||||
GLint yoffset, GLsizei width, GLsizei height, GLenum format,
|
||||
GLenum type, const GLvoid* data);
|
||||
GLenum SetTexturePropertyInt(GLenum target, GLenum pname, GLint param);
|
||||
GLenum SetTexturePropertyFloat(GLenum target, GLenum pname, GLfloat param);
|
||||
GLenum DeleteTexture(GLuint texture);
|
||||
GLenum DeleteTextures(GLsizei n, const GLuint* textures);
|
||||
GLenum QueryTextureLevelPropertyIntVector(GLenum target, GLint level, GLenum pname, GLint* params);
|
||||
|
||||
// Common
|
||||
GLenum SetPixelStoreInt(GLenum pname, GLint param);
|
||||
GLint QueryPixelStoreInt(GLenum pname);
|
||||
GLenum glEnable(GLenum cap);
|
||||
GLenum glDisable(GLenum cap);
|
||||
GLenum glBlendFunc(GLenum sfactor, GLenum dfactor);
|
||||
GLenum glBlendFuncSeparate(GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha);
|
||||
GLenum glClear(GLbitfield mask);
|
||||
GLenum glClearColor(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha);
|
||||
GLenum glClearDepth(GLdouble depth);
|
||||
GLenum glColorMask(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha);
|
||||
GLenum glDepthFunc(GLenum func);
|
||||
GLenum glDepthMask(GLboolean flag);
|
||||
GLenum glViewport(GLint x, GLint y, GLsizei width, GLsizei height);
|
||||
|
||||
// Buffer
|
||||
GLenum AcquireBufferMemory(GLenum target, GLenum access, void** mappedPtr);
|
||||
GLenum AcquireBufferMemoryRange(GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access, void** mappedPointer);
|
||||
GLenum SyncBufferMemory(GLenum target, GLintptr offset, GLsizeiptr length);
|
||||
GLenum CopyBufferRange(GLenum readTarget, GLenum writeTarget, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size);
|
||||
GLenum ReleaseBufferMemory(GLenum target);
|
||||
GLenum CreateBuffer(GLuint buffer);
|
||||
GLenum GenBufferNames(GLsizei n, GLuint* buffers);
|
||||
GLenum BindBuffer(GLenum target, GLuint buffer);
|
||||
GLenum CommitBufferStorage(GLenum target, GLsizeiptr size, const void* data, GLenum usage);
|
||||
GLenum CommitBufferStorageRegion(GLenum target, GLintptr offset, GLsizeiptr size, const void* data);
|
||||
bool ValidateAllocatedBufferHandle(GLuint buffer);
|
||||
bool ValidateGeneratedName(GLuint buffer);
|
||||
void DeleteBuffer(GLuint buffer);
|
||||
GLenum DeleteBuffers(GLsizei n, const GLuint* buffers);
|
||||
GLenum QueryBufferPropertyIntVector(GLenum target, GLenum pname, GLint* params);
|
||||
|
||||
// VertexArray
|
||||
GLenum CreateVertexArray(GLuint* array);
|
||||
GLenum CreateVertexArrays(GLsizei n, GLuint* arrays);
|
||||
GLenum GenVertexArraysNames(GLsizei n, GLuint* arrays);
|
||||
GLenum BindVertexArray(GLuint array);
|
||||
GLenum EnableVertexAttribArray(GLuint index);
|
||||
GLenum DisableVertexAttribArray(GLuint index);
|
||||
GLenum SetVertexAttributeLayout(GLuint index, GLint size, GLenum type,
|
||||
GLboolean normalized, GLsizei stride,
|
||||
const void* pointer);
|
||||
GLenum SetVertexAttributeLayoutInt(GLuint index, GLint size, GLenum type,
|
||||
GLsizei stride, const void* pointer);
|
||||
|
||||
// Program
|
||||
GLenum CreateShader(GLenum type, GLuint* shader);
|
||||
GLenum CreateProgram(GLuint* program);
|
||||
GLenum DeleteShader(GLuint shader);
|
||||
GLenum DeleteProgram(GLuint program);
|
||||
GLenum LinkShaderToProgram(GLuint program, GLuint shader);
|
||||
GLenum UploadShaderSource(GLuint shader, GLsizei count, const GLchar** string, const GLint* length);
|
||||
GLenum BuildShaderStage(GLuint shader);
|
||||
GLenum FinalizeProgramPipeline(GLuint program);
|
||||
GLenum ActivateRenderProgram(GLuint program);
|
||||
GLenum DefineProgramAttributeBinding(GLuint program, GLuint index, const GLchar* name);
|
||||
GLint QueryProgramAttributeBinding(GLuint program, const GLchar* name);
|
||||
GLint QueryProgramUniformLocation(GLuint program, const GLchar* name);
|
||||
GLenum QueryProgramStateIntVector(GLuint program, GLenum pname, GLint* params);
|
||||
GLenum QueryShaderStateIntVector(GLuint shader, GLenum pname, GLint* params);
|
||||
template<typename T>
|
||||
GLenum SetUniform(GLuint program, GLint location, GLsizei count, const T* value, GLenum type);
|
||||
|
||||
template<typename T>
|
||||
GLenum SetUniformMatrix(GLuint program, GLint location, GLsizei count, GLboolean transpose, const T* value, GLenum matrixType);
|
||||
|
||||
#define DECLARE_UNIFORM_FUNCTIONS(type, suffix, vecType) \
|
||||
void UpdateProgramUniform##suffix##1(GLint location, type v0); \
|
||||
void UpdateProgramUniform##suffix##2(GLint location, type v0, type v1); \
|
||||
void UpdateProgramUniform##suffix##3(GLint location, type v0, type v1, type v2); \
|
||||
void UpdateProgramUniform##suffix##4(GLint location, type v0, type v1, type v2, type v3); \
|
||||
void UpdateProgramUniform##suffix##Vector1(GLint location, GLsizei count, const type* value); \
|
||||
void UpdateProgramUniform##suffix##Vector2(GLint location, GLsizei count, const type* value); \
|
||||
void UpdateProgramUniform##suffix##Vector3(GLint location, GLsizei count, const type* value); \
|
||||
void UpdateProgramUniform##suffix##Vector4(GLint location, GLsizei count, const type* value);
|
||||
DECLARE_UNIFORM_FUNCTIONS(GLfloat, Float, GL_FLOAT)
|
||||
DECLARE_UNIFORM_FUNCTIONS(GLint, Int, GL_INT)
|
||||
DECLARE_UNIFORM_FUNCTIONS(GLuint, UInt, GL_UNSIGNED_INT)
|
||||
DECLARE_UNIFORM_FUNCTIONS(GLboolean, Bool, GL_BOOL)
|
||||
#undef DECLARE_UNIFORM_FUNCTIONS
|
||||
#define DECLARE_MATRIX_FUNCTIONS(suffix, matrixType) \
|
||||
void UpdateProgramUniformMatrix##suffix##Vector(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value);
|
||||
DECLARE_MATRIX_FUNCTIONS(2x2, GL_FLOAT_MAT2)
|
||||
DECLARE_MATRIX_FUNCTIONS(3x3, GL_FLOAT_MAT3)
|
||||
DECLARE_MATRIX_FUNCTIONS(4x4, GL_FLOAT_MAT4)
|
||||
DECLARE_MATRIX_FUNCTIONS(2x3, GL_FLOAT_MAT2x3)
|
||||
DECLARE_MATRIX_FUNCTIONS(2x4, GL_FLOAT_MAT2x4)
|
||||
DECLARE_MATRIX_FUNCTIONS(3x2, GL_FLOAT_MAT3x2)
|
||||
DECLARE_MATRIX_FUNCTIONS(3x4, GL_FLOAT_MAT3x4)
|
||||
DECLARE_MATRIX_FUNCTIONS(4x2, GL_FLOAT_MAT4x2)
|
||||
DECLARE_MATRIX_FUNCTIONS(4x3, GL_FLOAT_MAT4x3)
|
||||
#undef DECLARE_MATRIX_FUNCTIONS
|
||||
|
||||
GLuint GetCurrentProgram();
|
||||
bool SetProgramStatus(GLuint program, GLboolean status);
|
||||
bool SetShaderStatus(GLuint shader, GLboolean status);
|
||||
|
||||
// Framebuffer
|
||||
GLenum CreateFramebuffer(GLuint* framebuffer);
|
||||
GLenum CreateFramebuffers(GLsizei n, GLuint* framebuffers);
|
||||
GLenum DeleteFramebuffer(GLuint framebuffer);
|
||||
GLenum BindFramebuffer(GLenum target, GLuint framebuffer);
|
||||
GLenum AttachTexture2DToFramebuffer(GLenum target, GLenum attachment, GLenum textarget,
|
||||
GLuint texture, GLint level);
|
||||
GLenum ValidateFramebufferCompleteness(GLenum target);
|
||||
}
|
||||
|
||||
|
||||
#endif //MOBILEGL_GLSTATE_H
|
||||
@@ -1,165 +0,0 @@
|
||||
//
|
||||
// Created by BZLZHH on 2025/5/3.
|
||||
//
|
||||
|
||||
// TODO: Add more gl error check for framebuffer state manager.
|
||||
// TODO: Check if the state machine really meets up to OpenGL 3 standard.
|
||||
|
||||
#include "FramebufferState.h"
|
||||
|
||||
// Re-Include Includes.h, cuz of the absence of GLState.h
|
||||
#undef MOBILEGL_GLSTATE_H
|
||||
#include "../../../Includes.h"
|
||||
|
||||
GLenum FramebufferState::Create(GLuint* framebuffer) {
|
||||
if (!framebuffer) return GL_INVALID_VALUE;
|
||||
GLuint id = freeIds_.empty() ? ++lastId_ : *freeIds_.begin();
|
||||
if (!freeIds_.empty()) freeIds_.erase(freeIds_.begin());
|
||||
*framebuffer = id;
|
||||
framebuffers_[id].generated = true;
|
||||
return GL_NO_ERROR;
|
||||
}
|
||||
|
||||
GLenum FramebufferState::CreateN(GLsizei n, GLuint* framebuffers) {
|
||||
if (n < 0) return GL_INVALID_VALUE;
|
||||
for (GLsizei i = 0; i < n; ++i) {
|
||||
if (GLenum err = Create(&framebuffers[i])) return err;
|
||||
}
|
||||
return GL_NO_ERROR;
|
||||
}
|
||||
|
||||
GLenum FramebufferState::Delete(GLuint framebuffer) {
|
||||
if (framebuffer == 0) return GL_INVALID_VALUE;
|
||||
|
||||
if (framebuffers_.erase(framebuffer)) {
|
||||
// TODO: Prevent the object that uses a freeId from conflicting with legacy object in the backend.
|
||||
//freeIds_.insert(framebuffer);
|
||||
for (auto& [target, id] : currentBindings_) {
|
||||
if (id == framebuffer) id = 0;
|
||||
}
|
||||
}
|
||||
return GL_NO_ERROR;
|
||||
}
|
||||
|
||||
GLenum FramebufferState::Bind(GLenum target, GLuint framebuffer) {
|
||||
if (MG_Constants::Framebuffer::VALID_TARGETS.find(target) == MG_Constants::Framebuffer::VALID_TARGETS.end())
|
||||
return GL_INVALID_ENUM;
|
||||
if (framebuffer != 0 && !ValidateHandle(framebuffer))
|
||||
return GL_INVALID_OPERATION;
|
||||
if (target == GL_FRAMEBUFFER) {
|
||||
currentBindings_[GL_READ_FRAMEBUFFER] = framebuffer;
|
||||
currentBindings_[GL_DRAW_FRAMEBUFFER] = framebuffer;
|
||||
} else {
|
||||
currentBindings_[target] = framebuffer;
|
||||
}
|
||||
return GL_NO_ERROR;
|
||||
}
|
||||
|
||||
GLenum FramebufferState::AttachTexture2D(GLenum target, GLenum attachment,
|
||||
GLenum textarget, GLuint texture, GLint level) {
|
||||
if (MG_Constants::Framebuffer::VALID_ATTACHMENTS.find(attachment) == MG_Constants::Framebuffer::VALID_ATTACHMENTS.end() ||
|
||||
MG_Constants::Texture::VALID_TARGETS.find(textarget) == MG_Constants::Texture::VALID_TARGETS.end())
|
||||
return GL_INVALID_ENUM;
|
||||
if (target == GL_FRAMEBUFFER) target = GL_DRAW_FRAMEBUFFER;
|
||||
FramebufferObject* fbo = GetCurrentFBO(target);
|
||||
if (!fbo) return GL_INVALID_OPERATION;
|
||||
if (texture != 0 && !MG_State_T::textureState->IsTexture(texture))
|
||||
return GL_INVALID_VALUE;
|
||||
FramebufferAttachment att;
|
||||
att.type = GL_TEXTURE_2D;
|
||||
att.handle = texture;
|
||||
att.mipLevel = level;
|
||||
fbo->attachments[attachment] = att;
|
||||
|
||||
if (texture != 0) {
|
||||
GLint params = 0;
|
||||
MG_State_T::textureState->QueryLevelPropertyIntVector(
|
||||
textarget, level, GL_TEXTURE_WIDTH, ¶ms);
|
||||
fbo->width = params;
|
||||
MG_State_T::textureState->QueryLevelPropertyIntVector(
|
||||
textarget, level, GL_TEXTURE_HEIGHT, ¶ms);
|
||||
fbo->height = params;
|
||||
}
|
||||
UpdateCompleteness(*fbo);
|
||||
return GL_NO_ERROR;
|
||||
}
|
||||
|
||||
GLenum FramebufferState::ValidateCompleteness(GLenum target) {
|
||||
if (target == GL_FRAMEBUFFER) target = GL_DRAW_FRAMEBUFFER;
|
||||
FramebufferObject* fbo = GetCurrentFBO(target);
|
||||
if (!fbo) return GL_INVALID_OPERATION;
|
||||
return fbo->status;
|
||||
}
|
||||
|
||||
void FramebufferState::UpdateCompleteness(FramebufferObject& fbo) {
|
||||
if (fbo.attachments.empty()) {
|
||||
fbo.status = GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT;
|
||||
return;
|
||||
}
|
||||
bool hasColor = false;
|
||||
bool hasDepth = false;
|
||||
bool hasStencil = false;
|
||||
GLsizei width = 0, height = 0;
|
||||
for (const auto& [attach, att] : fbo.attachments) {
|
||||
GLsizei attWidth = 0, attHeight = 0;
|
||||
if (att.handle != 0) {
|
||||
GLint params = 0;
|
||||
MG_State_T::textureState->QueryLevelPropertyIntVector(
|
||||
GL_TEXTURE_2D, att.mipLevel, GL_TEXTURE_WIDTH, ¶ms);
|
||||
attWidth = params;
|
||||
MG_State_T::textureState->QueryLevelPropertyIntVector(
|
||||
GL_TEXTURE_2D, att.mipLevel, GL_TEXTURE_HEIGHT, ¶ms);
|
||||
attHeight = params;
|
||||
}
|
||||
if (width == 0) {
|
||||
width = attWidth;
|
||||
height = attHeight;
|
||||
} else if (attWidth != width || attHeight != height) {
|
||||
fbo.status = GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS;
|
||||
return;
|
||||
}
|
||||
|
||||
if (attach == GL_DEPTH_ATTACHMENT) hasDepth = true;
|
||||
if (attach == GL_STENCIL_ATTACHMENT) hasStencil = true;
|
||||
if (attach >= GL_COLOR_ATTACHMENT0 &&
|
||||
attach <= GL_COLOR_ATTACHMENT31) hasColor = true;
|
||||
}
|
||||
|
||||
if (!ValidateAttachmentCombination(fbo)) {
|
||||
fbo.status = GL_FRAMEBUFFER_UNSUPPORTED;
|
||||
return;
|
||||
}
|
||||
fbo.status = GL_FRAMEBUFFER_COMPLETE;
|
||||
}
|
||||
|
||||
bool FramebufferState::ValidateAttachmentCombination(const FramebufferObject& fbo) {
|
||||
bool depthStencilConflict = false;
|
||||
for (const auto& [attach, att] : fbo.attachments) {
|
||||
if (attach == GL_DEPTH_STENCIL_ATTACHMENT) {
|
||||
GLint internalFormat = 0;
|
||||
MG_State_T::textureState->QueryLevelPropertyIntVector(
|
||||
GL_TEXTURE_2D, att.mipLevel, GL_TEXTURE_INTERNAL_FORMAT, &internalFormat);
|
||||
if (internalFormat != GL_DEPTH24_STENCIL8 &&
|
||||
internalFormat != GL_DEPTH32F_STENCIL8) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
FramebufferObject* FramebufferState::GetCurrentFBO(GLenum target) {
|
||||
auto it = currentBindings_.find(target);
|
||||
if (it == currentBindings_.end()) return nullptr;
|
||||
|
||||
GLuint id = it->second;
|
||||
if (id == 0) return nullptr;
|
||||
|
||||
auto fboIt = framebuffers_.find(id);
|
||||
return (fboIt != framebuffers_.end()) ? &fboIt->second : nullptr;
|
||||
}
|
||||
|
||||
bool FramebufferState::ValidateHandle(GLuint framebuffer) {
|
||||
return framebuffers_.count(framebuffer) &&
|
||||
framebuffers_[framebuffer].generated;
|
||||
}
|
||||
@@ -1,49 +0,0 @@
|
||||
//
|
||||
// Created by BZLZHH on 2025/5/3.
|
||||
//
|
||||
|
||||
#ifndef MOBILEGL_FRAMEBUFFERSTATE_H
|
||||
#define MOBILEGL_FRAMEBUFFERSTATE_H
|
||||
#define MOBILEGL_GLSTATE_H
|
||||
|
||||
#include "../../../Includes.h"
|
||||
|
||||
struct FramebufferAttachment {
|
||||
GLenum type = GL_NONE;
|
||||
GLuint handle = 0;
|
||||
GLint mipLevel = 0;
|
||||
GLint zoffset = 0;
|
||||
};
|
||||
|
||||
struct FramebufferObject {
|
||||
bool generated = false;
|
||||
ankerl::unordered_map<GLenum, FramebufferAttachment> attachments;
|
||||
GLenum status = GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT;
|
||||
GLsizei width = 0;
|
||||
GLsizei height = 0;
|
||||
};
|
||||
|
||||
class FramebufferState {
|
||||
public:
|
||||
// Return: the validity of the operation
|
||||
GLenum Create(GLuint* framebuffer);
|
||||
GLenum CreateN(GLsizei n, GLuint* framebuffers);
|
||||
GLenum Delete(GLuint framebuffer);
|
||||
GLenum Bind(GLenum target, GLuint framebuffer);
|
||||
GLenum AttachTexture2D(GLenum target, GLenum attachment,
|
||||
GLenum textarget, GLuint texture, GLint level);
|
||||
GLenum ValidateCompleteness(GLenum target);
|
||||
FramebufferObject* GetCurrentFBO(GLenum target);
|
||||
|
||||
ankerl::unordered_map<GLenum, GLuint> currentBindings_; // READ/DRAW
|
||||
|
||||
private:
|
||||
ankerl::unordered_map<GLuint, FramebufferObject> framebuffers_;
|
||||
std::set<GLuint> freeIds_;
|
||||
GLuint lastId_ = 0;
|
||||
bool ValidateHandle(GLuint framebuffer);
|
||||
static void UpdateCompleteness(FramebufferObject& fbo);
|
||||
static bool ValidateAttachmentCombination(const FramebufferObject& fbo);
|
||||
};
|
||||
|
||||
#endif //MOBILEGL_FRAMEBUFFERSTATE_H
|
||||
@@ -1,577 +0,0 @@
|
||||
//
|
||||
// Created by BZLZHH on 2025/5/1.
|
||||
|
||||
// TODO: Add more gl error check for buffer state manager.
|
||||
// TODO: Check if the state machine really meets up to OpenGL 3 standard.
|
||||
|
||||
#include "ProgramState.h"
|
||||
|
||||
// Re-Include Includes.h, cuz of the absence of Program/DebugTool.h and Program/GLSLTool.cpp.
|
||||
#undef MOBILEGL_GLSLTOOL_H
|
||||
#undef MOBILEGL_PROGRAM_DEBUGTOOL_H
|
||||
#include "../../../Includes.h"
|
||||
|
||||
ProgramState::ProgramState() {
|
||||
glslang::InitializeProcess();
|
||||
}
|
||||
|
||||
ProgramState::~ProgramState() {
|
||||
glslang::FinalizeProcess();
|
||||
}
|
||||
|
||||
GLenum ProgramState::CreateProgram(GLuint* program) {
|
||||
MG_Util::Debug::LogD("MG_State: Program: CreateProgram called, program ptr=%p", program);
|
||||
if (!program) {
|
||||
MG_Util::Debug::LogE("MG_State: Program: CreateProgram error: program pointer is null");
|
||||
return GL_INVALID_VALUE;
|
||||
}
|
||||
|
||||
GLuint id = freeProgramIds_.empty() ? ++lastProgramId_ : *freeProgramIds_.begin();
|
||||
if (!freeProgramIds_.empty())
|
||||
freeProgramIds_.erase(freeProgramIds_.begin());
|
||||
|
||||
ProgramObject obj;
|
||||
obj.linked = {UncertainBool::Unknown, UncertainBool::False};
|
||||
obj.linkStatus = GL_FALSE;
|
||||
obj.markedForDeletion = false;
|
||||
programs_[id] = obj;
|
||||
*program = id;
|
||||
MG_Util::Debug::LogD("MG_State: Program: CreateProgram success, new id=%u", id);
|
||||
return GL_NO_ERROR;
|
||||
}
|
||||
|
||||
GLenum ProgramState::DeleteProgram(GLuint program) {
|
||||
MG_Util::Debug::LogD("MG_State: Program: DeleteProgram called, id=%u", program);
|
||||
if (!ValidateProgram_(program)) {
|
||||
MG_Util::Debug::LogE("MG_State: Program: DeleteProgram error: invalid program id %u", program);
|
||||
return GL_INVALID_VALUE;
|
||||
}
|
||||
|
||||
programs_.erase(program);
|
||||
//freeProgramIds_.insert(program);
|
||||
if (currentProgram_ == program)
|
||||
currentProgram_ = 0;
|
||||
MG_Util::Debug::LogD("MG_State: Program: DeleteProgram success, id=%u", program);
|
||||
return GL_NO_ERROR;
|
||||
}
|
||||
|
||||
GLenum ProgramState::LinkShaderToProgram(GLuint program, GLuint shader) {
|
||||
MG_Util::Debug::LogD("MG_State: Program: LinkShaderToProgram called, program=%u, shader=%u",
|
||||
program, shader);
|
||||
if (!ValidateProgram_(program) || !ValidateShader_(shader)) {
|
||||
MG_Util::Debug::LogE("MG_State: Program: LinkShaderToProgram error: invalid ids program=%u shader=%u",
|
||||
program, shader);
|
||||
return GL_INVALID_VALUE;
|
||||
}
|
||||
|
||||
auto& prog = programs_[program];
|
||||
if (std::find(prog.attachedShaders.begin(),
|
||||
prog.attachedShaders.end(), shader) != prog.attachedShaders.end()) {
|
||||
MG_Util::Debug::LogW("MG_State: Program: LinkShaderToProgram warning: shader %u already attached to program %u",
|
||||
shader, program);
|
||||
return GL_INVALID_OPERATION;
|
||||
}
|
||||
|
||||
prog.attachedShaders.push_back(shader);
|
||||
MG_Util::Debug::LogD("MG_State: Program: LinkShaderToProgram success: shader %u attached to program %u",
|
||||
shader, program);
|
||||
return GL_NO_ERROR;
|
||||
}
|
||||
|
||||
GLenum ProgramState::FinalizeProgramPipeline(GLuint program) {
|
||||
MG_Util::Debug::LogD("MG_State: Program: FinalizeProgramPipeline called, id=%u", program);
|
||||
if (!ValidateProgram_(program)) {
|
||||
MG_Util::Debug::LogE("MG_State: Program: FinalizeProgramPipeline error: invalid program id %u", program);
|
||||
return GL_INVALID_VALUE;
|
||||
}
|
||||
auto& prog = programs_[program];
|
||||
|
||||
for (GLuint shader : prog.attachedShaders) {
|
||||
if (!shaders_[shader].compiled.toBool()) {
|
||||
MG_Util::Debug::LogE("MG_State: Program: FinalizeProgramPipeline error: shader %u not compiled", shader);
|
||||
return GL_INVALID_OPERATION;
|
||||
}
|
||||
}
|
||||
|
||||
prog.infoLog.clear();
|
||||
|
||||
for (GLuint shaderId : prog.attachedShaders) {
|
||||
auto& shader = shaders_[shaderId];
|
||||
if (!shader.compiled.toBool() || shader.compiledSpirv.empty()) {
|
||||
prog.infoLog = "Program linking failed: \n" +
|
||||
MG_Util::Program::GetShaderTypeName(shader.type) + " is not compiled.";
|
||||
prog.linked = UncertainBool::False;
|
||||
prog.linkStatus = GL_FALSE;
|
||||
MG_Util::Debug::LogE("MG_State: Program: FinalizeProgramPipeline error: %s", prog.infoLog.c_str());
|
||||
return GL_INVALID_OPERATION;
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<std::vector<unsigned>> allSpirv =
|
||||
MG_Util::Program::CompileMultipleShadersToSPIRV(*this, prog, prog.infoLog);
|
||||
|
||||
MG_Util::Program::ReflectSPIRVUniforms(allSpirv, prog, prog.infoLog);
|
||||
if (!prog.infoLog.empty()) {
|
||||
prog.linked = UncertainBool::False;
|
||||
prog.linkStatus = GL_FALSE;
|
||||
prog.infoLog = "Program linking failed: " + prog.infoLog;
|
||||
MG_Util::Debug::LogE("MG_State: Program: FinalizeProgramPipeline error: %s", prog.infoLog.c_str());
|
||||
return GL_INVALID_OPERATION;
|
||||
}
|
||||
|
||||
for (auto& [name, index] : prog.attribBindings) {
|
||||
prog.attribLocations[name] = index;
|
||||
}
|
||||
|
||||
prog.linked = {UncertainBool::Unknown, UncertainBool::True};
|
||||
prog.linkStatus = GL_TRUE;
|
||||
|
||||
CleanupShaders_();
|
||||
|
||||
MG_Util::Program::DumpUniforms(*this, program);
|
||||
MG_Util::Debug::LogD("MG_State: Program: FinalizeProgramPipeline success, id=%u", program);
|
||||
return GL_NO_ERROR;
|
||||
}
|
||||
|
||||
GLenum ProgramState::ActivateRenderProgram(GLuint program) {
|
||||
MG_Util::Debug::LogD("MG_State: Program: ActivateRenderProgram called, id=%u", program);
|
||||
if (program != 0 && !ValidateProgram_(program)) {
|
||||
MG_Util::Debug::LogE("MG_State: Program: ActivateRenderProgram error: invalid program id %u", program);
|
||||
return GL_INVALID_VALUE;
|
||||
}
|
||||
|
||||
MG_Util::Program::DumpCurrentUniforms(*this);
|
||||
currentProgram_ = program;
|
||||
MG_Util::Program::DumpCurrentUniforms(*this);
|
||||
MG_Util::Debug::LogD("MG_State: Program: ActivateRenderProgram success, current program=%u", currentProgram_);
|
||||
return GL_NO_ERROR;
|
||||
}
|
||||
|
||||
GLenum ProgramState::DefineProgramAttributeBinding(GLuint program, GLuint index, const GLchar* name) {
|
||||
MG_Util::Debug::LogD("MG_State: Program: DefineProgramAttributeBinding called, program=%u, index=%u, name=%s",
|
||||
program, index, name);
|
||||
if (!ValidateProgram_(program)) {
|
||||
MG_Util::Debug::LogE("MG_State: Program: DefineProgramAttributeBinding error: invalid program id %u", program);
|
||||
return GL_INVALID_VALUE;
|
||||
}
|
||||
if (index >= GL_MAX_VERTEX_ATTRIBS) {
|
||||
MG_Util::Debug::LogE("MG_State: Program: DefineProgramAttributeBinding error: index %u out of range", index);
|
||||
return GL_INVALID_VALUE;
|
||||
}
|
||||
|
||||
programs_[program].attribBindings[name] = index;
|
||||
MG_Util::Debug::LogD("MG_State: Program: DefineProgramAttributeBinding success: %s -> %u", name, index);
|
||||
return GL_NO_ERROR;
|
||||
}
|
||||
|
||||
GLint ProgramState::QueryProgramAttributeBinding(GLuint program, const GLchar* name) {
|
||||
MG_Util::Debug::LogD("MG_State: Program: QueryProgramAttributeBinding called, program=%u, name=%s",
|
||||
program, name);
|
||||
if (!ValidateProgram_(program)) {
|
||||
MG_Util::Debug::LogE("MG_State: Program: QueryProgramAttributeBinding error: invalid program id %u", program);
|
||||
return -1;
|
||||
}
|
||||
|
||||
auto& prog = programs_[program];
|
||||
auto it = prog.attribLocations.find(name);
|
||||
if (it != prog.attribLocations.end()) {
|
||||
GLint loc = it->second;
|
||||
MG_Util::Debug::LogD("MG_State: Program: QueryProgramAttributeBinding success: %s -> %d", name, loc);
|
||||
return loc;
|
||||
}
|
||||
MG_Util::Debug::LogW("MG_State: Program: QueryProgramAttributeBinding warning: name '%s' not found", name);
|
||||
return -1;
|
||||
}
|
||||
|
||||
GLenum ProgramState::QueryProgramStateIntVector(GLuint program, GLenum pname, GLint* params) {
|
||||
MG_Util::Debug::LogD("MG_State: Program: QueryProgramStateIntVector called, program=%u, pname=0x%X",
|
||||
program, pname);
|
||||
if (!ValidateProgram_(program)) {
|
||||
MG_Util::Debug::LogE("MG_State: Program: QueryProgramStateIntVector error: invalid program id %u", program);
|
||||
return GL_INVALID_VALUE;
|
||||
}
|
||||
auto& prog = programs_[program];
|
||||
|
||||
switch (pname) {
|
||||
case GL_LINK_STATUS: *params = prog.linkStatus; break;
|
||||
case GL_DELETE_STATUS: *params = prog.markedForDeletion; break;
|
||||
case GL_ATTACHED_SHADERS:*params = (GLint)prog.attachedShaders.size(); break;
|
||||
default:
|
||||
MG_Util::Debug::LogE("MG_State: Program: QueryProgramStateIntVector error: invalid pname 0x%X", pname);
|
||||
return GL_INVALID_ENUM;
|
||||
}
|
||||
MG_Util::Debug::LogD("MG_State: Program: QueryProgramStateIntVector success: value=%d", *params);
|
||||
return GL_NO_ERROR;
|
||||
}
|
||||
|
||||
GLenum ProgramState::QueryShaderStateIntVector(GLuint shader, GLenum pname, GLint* params) {
|
||||
MG_Util::Debug::LogD("MG_State: Program: QueryShaderStateIntVector called, shader=%u, pname=0x%X",
|
||||
shader, pname);
|
||||
if (!ValidateShader_(shader)) {
|
||||
MG_Util::Debug::LogE("MG_State: Program: QueryShaderStateIntVector error: invalid shader id %u", shader);
|
||||
return GL_INVALID_VALUE;
|
||||
}
|
||||
auto& obj = shaders_[shader];
|
||||
|
||||
switch (pname) {
|
||||
case GL_COMPILE_STATUS: *params = obj.compileStatus; break;
|
||||
case GL_DELETE_STATUS: *params = obj.markedForDeletion; break;
|
||||
case GL_SHADER_TYPE: *params = obj.type; break;
|
||||
default:
|
||||
MG_Util::Debug::LogE("MG_State: Program: QueryShaderStateIntVector error: invalid pname 0x%X", pname);
|
||||
return GL_INVALID_ENUM;
|
||||
}
|
||||
MG_Util::Debug::LogD("MG_State: Program: QueryShaderStateIntVector success: value=%d", *params);
|
||||
return GL_NO_ERROR;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
GLenum ProgramState::SetUniform(GLuint program, GLint location, GLsizei count, const T* value, GLenum type) {
|
||||
MG_Util::Debug::LogD("MG_State: Program: SetUniform called, program=%u, location=%d, count=%d, type=0x%X",
|
||||
program, location, count, type);
|
||||
if (!ValidateProgram_(program)) {
|
||||
MG_Util::Debug::LogE("MG_State: Program: SetUniform error: invalid program id %u", program);
|
||||
return GL_INVALID_VALUE;
|
||||
}
|
||||
if (location < -1) {
|
||||
MG_Util::Debug::LogE("MG_State: Program: SetUniform error: invalid location %d", location);
|
||||
return GL_INVALID_VALUE;
|
||||
}
|
||||
if (count < 0) {
|
||||
MG_Util::Debug::LogE("MG_State: Program: SetUniform error: invalid count %d", count);
|
||||
return GL_INVALID_VALUE;
|
||||
}
|
||||
if (location == -1) {
|
||||
MG_Util::Debug::LogW("MG_State: Program: SetUniform warning: location -1, no-op");
|
||||
return GL_NO_ERROR;
|
||||
}
|
||||
|
||||
ProgramObject& prog = programs_[program];
|
||||
std::string uniformName;
|
||||
for (const auto& pair : prog.uniformLocations) {
|
||||
if (pair.second == location) {
|
||||
uniformName = pair.first;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (uniformName.empty()) {
|
||||
MG_Util::Debug::LogE("MG_State: Program: SetUniform error: no uniform at location %d in program %u",
|
||||
location, program);
|
||||
return GL_INVALID_OPERATION;
|
||||
}
|
||||
|
||||
UniformValue& uniform = prog.uniformValues[uniformName];
|
||||
|
||||
uniform.setData(type, count, value);
|
||||
MG_Util::Debug::LogD("MG_State: Program: SetUniform success: %s set", uniformName.c_str());
|
||||
return GL_NO_ERROR;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
GLenum ProgramState::SetUniformMatrix(GLuint program, GLint location, GLsizei count, GLboolean transpose, const T* value, GLenum matrixType) {
|
||||
MG_Util::Debug::LogD("MG_State: Program: SetUniformMatrix called, program=%u, location=%d, count=%d, matrixType=0x%X",
|
||||
program, location, count, matrixType);
|
||||
(void)transpose;
|
||||
if (!ValidateProgram_(program)) {
|
||||
MG_Util::Debug::LogE("MG_State: Program: SetUniformMatrix error: invalid program id %u", program);
|
||||
return GL_INVALID_VALUE;
|
||||
}
|
||||
if (location < -1) {
|
||||
MG_Util::Debug::LogE("MG_State: Program: SetUniformMatrix error: invalid location %d", location);
|
||||
return GL_INVALID_VALUE;
|
||||
}
|
||||
if (count < 0) {
|
||||
MG_Util::Debug::LogE("MG_State: Program: SetUniformMatrix error: invalid count %d", count);
|
||||
return GL_INVALID_VALUE;
|
||||
}
|
||||
if (location == -1) {
|
||||
MG_Util::Debug::LogW("MG_State: Program: SetUniformMatrix warning: location -1, no-op");
|
||||
return GL_NO_ERROR;
|
||||
}
|
||||
|
||||
ProgramObject& prog = programs_[program];
|
||||
std::string uniformName;
|
||||
for (const auto& pair : prog.uniformLocations) {
|
||||
if (pair.second == location) {
|
||||
uniformName = pair.first;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (uniformName.empty()) {
|
||||
MG_Util::Debug::LogE("MG_State: Program: SetUniformMatrix error: no uniform at location %d in program %u",
|
||||
location, program);
|
||||
return GL_INVALID_OPERATION;
|
||||
}
|
||||
|
||||
UniformValue& uniform = prog.uniformValues[uniformName];
|
||||
uniform.setData(matrixType, count, value);
|
||||
MG_Util::Debug::LogD("MG_State: Program: SetUniformMatrix success: %s set", uniformName.c_str());
|
||||
return GL_NO_ERROR;
|
||||
}
|
||||
|
||||
#define IMPLEMENT_UNIFORM_FUNCTIONS(type, suffix, vecType) \
|
||||
void ProgramState::UpdateUniform##suffix##1(GLint location, type v0) { \
|
||||
MG_Util::Debug::LogD("MG_State: Program: UpdateUniform" #suffix "1 called, location=%d", location); \
|
||||
SetUniform<type>(currentProgram_, location, 1, &v0, vecType); \
|
||||
} \
|
||||
void ProgramState::UpdateUniform##suffix##2(GLint location, type v0, type v1) { \
|
||||
type values[2] = {v0, v1}; \
|
||||
MG_Util::Debug::LogD("MG_State: Program: UpdateUniform" #suffix "2 called, location=%d", location); \
|
||||
SetUniform<type>(currentProgram_, location, 1, values, vecType); \
|
||||
} \
|
||||
void ProgramState::UpdateUniform##suffix##3(GLint location, type v0, type v1, type v2) { \
|
||||
type values[3] = {v0, v1, v2}; \
|
||||
MG_Util::Debug::LogD("MG_State: Program: UpdateUniform" #suffix "3 called, location=%d", location); \
|
||||
SetUniform<type>(currentProgram_, location, 1, values, vecType); \
|
||||
} \
|
||||
void ProgramState::UpdateUniform##suffix##4(GLint location, type v0, type v1, type v2, type v3) { \
|
||||
type values[4] = {v0, v1, v2, v3}; \
|
||||
MG_Util::Debug::LogD("MG_State: Program: UpdateUniform" #suffix "4 called, location=%d", location); \
|
||||
SetUniform<type>(currentProgram_, location, 1, values, vecType); \
|
||||
} \
|
||||
void ProgramState::UpdateUniform##suffix##Vector1(GLint location, GLsizei count, const type* value) { \
|
||||
MG_Util::Debug::LogD("MG_State: Program: UpdateUniform" #suffix "Vector1 called, location=%d, count=%d", location, count); \
|
||||
SetUniform<type>(currentProgram_, location, count, value, vecType); \
|
||||
} \
|
||||
void ProgramState::UpdateUniform##suffix##Vector2(GLint location, GLsizei count, const type* value) { \
|
||||
MG_Util::Debug::LogD("MG_State: Program: UpdateUniform" #suffix "Vector2 called, location=%d, count=%d", location, count); \
|
||||
SetUniform<type>(currentProgram_, location, count, value, vecType); \
|
||||
} \
|
||||
void ProgramState::UpdateUniform##suffix##Vector3(GLint location, GLsizei count, const type* value) { \
|
||||
MG_Util::Debug::LogD("MG_State: Program: UpdateUniform" #suffix "Vector3 called, location=%d, count=%d", location, count); \
|
||||
SetUniform<type>(currentProgram_, location, count, value, vecType); \
|
||||
} \
|
||||
void ProgramState::UpdateUniform##suffix##Vector4(GLint location, GLsizei count, const type* value) { \
|
||||
MG_Util::Debug::LogD("MG_State: Program: UpdateUniform" #suffix "Vector4 called, location=%d, count=%d", location, count); \
|
||||
SetUniform<type>(currentProgram_, location, count, value, vecType); \
|
||||
}
|
||||
|
||||
IMPLEMENT_UNIFORM_FUNCTIONS(GLfloat, Float, GL_FLOAT_VEC4)
|
||||
IMPLEMENT_UNIFORM_FUNCTIONS(GLint, Int, GL_INT_VEC4)
|
||||
IMPLEMENT_UNIFORM_FUNCTIONS(GLuint, UInt, GL_UNSIGNED_INT_VEC4)
|
||||
IMPLEMENT_UNIFORM_FUNCTIONS(GLboolean, Bool, GL_BOOL_VEC4)
|
||||
#undef IMPLEMENT_UNIFORM_FUNCTIONS
|
||||
|
||||
#define IMPLEMENT_MATRIX_FUNCTIONS(suffix, matrixType) \
|
||||
void ProgramState::UpdateUniformMatrix##suffix##Vector(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) { \
|
||||
MG_Util::Debug::LogD("MG_State: Program: UpdateUniformMatrix" #suffix "Vector called, location=%d, count=%d", location, count); \
|
||||
SetUniformMatrix<GLfloat>(currentProgram_, location, count, transpose, value, matrixType); \
|
||||
}
|
||||
|
||||
IMPLEMENT_MATRIX_FUNCTIONS(2x2, GL_FLOAT_MAT2)
|
||||
IMPLEMENT_MATRIX_FUNCTIONS(3x3, GL_FLOAT_MAT3)
|
||||
IMPLEMENT_MATRIX_FUNCTIONS(4x4, GL_FLOAT_MAT4)
|
||||
IMPLEMENT_MATRIX_FUNCTIONS(2x3, GL_FLOAT_MAT2x3)
|
||||
IMPLEMENT_MATRIX_FUNCTIONS(2x4, GL_FLOAT_MAT2x4)
|
||||
IMPLEMENT_MATRIX_FUNCTIONS(3x2, GL_FLOAT_MAT3x2)
|
||||
IMPLEMENT_MATRIX_FUNCTIONS(3x4, GL_FLOAT_MAT3x4)
|
||||
IMPLEMENT_MATRIX_FUNCTIONS(4x2, GL_FLOAT_MAT4x2)
|
||||
IMPLEMENT_MATRIX_FUNCTIONS(4x3, GL_FLOAT_MAT4x3)
|
||||
#undef IMPLEMENT_MATRIX_FUNCTIONS
|
||||
|
||||
GLint ProgramState::QueryProgramUniformLocation(GLuint program, const GLchar* name) {
|
||||
MG_Util::Debug::LogD("MG_State: Program: QueryProgramUniformLocation called, program=%u, name=%s", program, name);
|
||||
if (!ValidateProgram_(program)) {
|
||||
MG_Util::Debug::LogE("MG_State: Program: QueryProgramUniformLocation error: invalid program id %u", program);
|
||||
return -1;
|
||||
}
|
||||
auto& prog = programs_[program];
|
||||
auto it = prog.uniformLocations.find(name);
|
||||
if (it != prog.uniformLocations.end()) {
|
||||
GLint loc = it->second;
|
||||
MG_Util::Debug::LogD("MG_State: Program: QueryProgramUniformLocation success: %s -> %d", name, loc);
|
||||
return loc;
|
||||
}
|
||||
MG_Util::Debug::LogW("MG_State: Program: QueryProgramUniformLocation warning: name '%s' not found", name);
|
||||
return -1;
|
||||
}
|
||||
|
||||
bool ProgramState::SetProgramStatus(GLuint program, GLboolean status) {
|
||||
MG_Util::Debug::LogD("MG_State: Program: SetProgramStatus called, program=%u, status=%d", program, status);
|
||||
if (!ValidateProgram_(program)) {
|
||||
MG_Util::Debug::LogE("MG_State: Program: SetProgramStatus error: invalid program id %u", program);
|
||||
return false;
|
||||
}
|
||||
auto& prog = programs_[program];
|
||||
if (prog.linked.getValue() != UncertainBool::Unknown) {
|
||||
MG_Util::Debug::LogW("MG_State: Program: SetProgramStatus warning: link state already known");
|
||||
return false;
|
||||
}
|
||||
prog.linked = (status == GL_TRUE) ? UncertainBool::True : UncertainBool::False;
|
||||
prog.linkStatus = status;
|
||||
MG_Util::Debug::LogD("MG_State: Program: SetProgramStatus success, status=%d", status);
|
||||
return true;
|
||||
}
|
||||
|
||||
GLuint ProgramState::GetCurrentProgram() const {
|
||||
MG_Util::Debug::LogD("MG_State: Program: GetCurrentProgram called, returning %u", currentProgram_);
|
||||
return currentProgram_;
|
||||
}
|
||||
|
||||
ShaderObject ProgramState::GetShaderObject(GLuint shader) const {
|
||||
MG_Util::Debug::LogD("MG_State: Program: GetShaderObject called, shader=%u", shader);
|
||||
auto it = shaders_.find(shader);
|
||||
if (it == shaders_.end()) {
|
||||
MG_Util::Debug::LogW("MG_State: Program: GetShaderObject warning: invalid shader id %u", shader);
|
||||
return ShaderObject();
|
||||
}
|
||||
MG_Util::Debug::LogD("MG_State: Program: GetShaderObject success, returning object");
|
||||
return it->second;
|
||||
}
|
||||
|
||||
ProgramObject ProgramState::GetProgramObject(GLuint program) const {
|
||||
MG_Util::Debug::LogD("MG_State: Program: GetProgramObject called, program=%u", program);
|
||||
auto it = programs_.find(program);
|
||||
if (it == programs_.end()) {
|
||||
MG_Util::Debug::LogW("MG_State: Program: GetProgramObject warning: invalid program id %u", program);
|
||||
return ProgramObject();
|
||||
}
|
||||
MG_Util::Debug::LogD("MG_State: Program: GetProgramObject success, returning object");
|
||||
return it->second;
|
||||
}
|
||||
|
||||
bool ProgramState::ValidateProgram_(GLuint program) {
|
||||
bool ok = programs_.count(program) && !programs_[program].markedForDeletion;
|
||||
MG_Util::Debug::LogD("MG_State: Program: ValidateProgram_ called, program=%u, result=%d", program, ok);
|
||||
return ok;
|
||||
}
|
||||
|
||||
void ProgramState::CleanupShaders_() {
|
||||
MG_Util::Debug::LogD("MG_State: Program: CleanupShaders_ start");
|
||||
auto it = shaders_.begin();
|
||||
while (it != shaders_.end()) {
|
||||
if (it->second.markedForDeletion) {
|
||||
bool inUse = false;
|
||||
for (auto& [progId, program] : programs_) {
|
||||
if (std::find(program.attachedShaders.begin(),
|
||||
program.attachedShaders.end(), it->first) != program.attachedShaders.end()) {
|
||||
inUse = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!inUse) {
|
||||
MG_Util::Debug::LogD("MG_State: Program: CleanupShaders_ deleting shader %u", it->first);
|
||||
freeShaderIds_.insert(it->first);
|
||||
it = shaders_.erase(it);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
++it;
|
||||
}
|
||||
MG_Util::Debug::LogD("MG_State: Program: CleanupShaders_ end");
|
||||
}
|
||||
|
||||
// UniformValue
|
||||
template<typename T>
|
||||
void UniformValue::setData(GLenum uniformType, GLsizei count_, const T* values) {
|
||||
MG_Util::Debug::LogD("MG_State: Program: UniformValue::setData called, type=0x%X, count=%d", uniformType, count_);
|
||||
//type = uniformType;
|
||||
count = count_;
|
||||
|
||||
floatData.clear();
|
||||
intData.clear();
|
||||
uintData.clear();
|
||||
boolData.clear();
|
||||
|
||||
switch (type) {
|
||||
case GL_FLOAT: numElements = count_ * 1; break;
|
||||
case GL_FLOAT_VEC2: numElements = count_ * 2; break;
|
||||
case GL_FLOAT_VEC3: numElements = count_ * 3; break;
|
||||
case GL_FLOAT_VEC4: numElements = count_ * 4; break;
|
||||
case GL_INT: numElements = count_ * 1; break;
|
||||
case GL_INT_VEC2: numElements = count_ * 2; break;
|
||||
case GL_INT_VEC3: numElements = count_ * 3; break;
|
||||
case GL_INT_VEC4: numElements = count_ * 4; break;
|
||||
case GL_UNSIGNED_INT: numElements = count_ * 1; break;
|
||||
case GL_UNSIGNED_INT_VEC2: numElements = count_ * 2; break;
|
||||
case GL_UNSIGNED_INT_VEC3: numElements = count_ * 3; break;
|
||||
case GL_UNSIGNED_INT_VEC4: numElements = count_ * 4; break;
|
||||
case GL_BOOL: numElements = count_ * 1; break;
|
||||
case GL_BOOL_VEC2: numElements = count_ * 2; break;
|
||||
case GL_BOOL_VEC3: numElements = count_ * 3; break;
|
||||
case GL_BOOL_VEC4: numElements = count_ * 4; break;
|
||||
case GL_FLOAT_MAT2: numElements = count_ * 4; break; // 2x2
|
||||
case GL_FLOAT_MAT3: numElements = count_ * 9; break; // 3x3
|
||||
case GL_FLOAT_MAT4: numElements = count_ * 16; break; // 4x4
|
||||
case GL_FLOAT_MAT2x3: numElements = count_ * 6; break; // 2x3
|
||||
case GL_FLOAT_MAT2x4: numElements = count_ * 8; break; // 2x4
|
||||
case GL_FLOAT_MAT3x2: numElements = count_ * 6; break; // 3x2
|
||||
case GL_FLOAT_MAT3x4: numElements = count_ * 12; break; // 3x4
|
||||
case GL_FLOAT_MAT4x2: numElements = count_ * 8; break; // 4x2
|
||||
case GL_FLOAT_MAT4x3: numElements = count_ * 12; break; // 4x3
|
||||
case GL_SAMPLER_1D:
|
||||
case GL_SAMPLER_2D:
|
||||
case GL_SAMPLER_3D:
|
||||
case GL_SAMPLER_CUBE:
|
||||
case GL_SAMPLER_1D_SHADOW:
|
||||
case GL_SAMPLER_2D_SHADOW:
|
||||
case GL_SAMPLER_CUBE_SHADOW:
|
||||
case GL_SAMPLER_1D_ARRAY:
|
||||
case GL_SAMPLER_2D_ARRAY:
|
||||
case GL_SAMPLER_1D_ARRAY_SHADOW:
|
||||
case GL_SAMPLER_2D_ARRAY_SHADOW:
|
||||
case GL_SAMPLER_BUFFER:
|
||||
case GL_SAMPLER_2D_MULTISAMPLE:
|
||||
case GL_SAMPLER_2D_MULTISAMPLE_ARRAY: numElements = count_ * 1; break;
|
||||
default:
|
||||
MG_Util::Debug::LogW("MG_State: Program: UniformValue::setData warning: unsupported type 0x%X for numElements", uniformType);
|
||||
numElements = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
for (GLsizei i = 0; i < numElements; ++i) {
|
||||
switch (uniformType) {
|
||||
case GL_FLOAT:
|
||||
case GL_FLOAT_VEC2:
|
||||
case GL_FLOAT_VEC3:
|
||||
case GL_FLOAT_VEC4:
|
||||
case GL_FLOAT_MAT2:
|
||||
case GL_FLOAT_MAT3:
|
||||
case GL_FLOAT_MAT4:
|
||||
case GL_FLOAT_MAT2x3:
|
||||
case GL_FLOAT_MAT2x4:
|
||||
case GL_FLOAT_MAT3x2:
|
||||
case GL_FLOAT_MAT3x4:
|
||||
case GL_FLOAT_MAT4x2:
|
||||
case GL_FLOAT_MAT4x3:
|
||||
floatData.push_back(static_cast<GLfloat>(values[i]));
|
||||
break;
|
||||
case GL_INT:
|
||||
case GL_INT_VEC2:
|
||||
case GL_INT_VEC3:
|
||||
case GL_INT_VEC4:
|
||||
case GL_SAMPLER_1D:
|
||||
case GL_SAMPLER_2D:
|
||||
case GL_SAMPLER_3D:
|
||||
case GL_SAMPLER_CUBE:
|
||||
case GL_SAMPLER_1D_SHADOW:
|
||||
case GL_SAMPLER_2D_SHADOW:
|
||||
case GL_SAMPLER_CUBE_SHADOW:
|
||||
case GL_SAMPLER_1D_ARRAY:
|
||||
case GL_SAMPLER_2D_ARRAY:
|
||||
case GL_SAMPLER_1D_ARRAY_SHADOW:
|
||||
case GL_SAMPLER_2D_ARRAY_SHADOW:
|
||||
case GL_SAMPLER_BUFFER:
|
||||
case GL_SAMPLER_2D_MULTISAMPLE:
|
||||
case GL_SAMPLER_2D_MULTISAMPLE_ARRAY:
|
||||
intData.push_back(static_cast<GLint>(values[i]));
|
||||
break;
|
||||
case GL_UNSIGNED_INT:
|
||||
case GL_UNSIGNED_INT_VEC2:
|
||||
case GL_UNSIGNED_INT_VEC3:
|
||||
case GL_UNSIGNED_INT_VEC4:
|
||||
uintData.push_back(static_cast<GLuint>(values[i]));
|
||||
break;
|
||||
case GL_BOOL:
|
||||
case GL_BOOL_VEC2:
|
||||
case GL_BOOL_VEC3:
|
||||
case GL_BOOL_VEC4:
|
||||
boolData.push_back(values[i] ? GL_TRUE : GL_FALSE);
|
||||
break;
|
||||
default:
|
||||
MG_Util::Debug::LogW("MG_State: Program: UniformValue::setData warning: unsupported type 0x%X", uniformType);
|
||||
break;
|
||||
}
|
||||
}
|
||||
MG_Util::Debug::LogD("MG_State: Program: UniformValue::setData end");
|
||||
}
|
||||
@@ -1,126 +0,0 @@
|
||||
//
|
||||
// Created by BZLZHH on 2025/5/1.
|
||||
//
|
||||
|
||||
#ifndef MOBILEGL_PROGRAMSTATE_H
|
||||
#define MOBILEGL_PROGRAMSTATE_H
|
||||
#define MOBILEGL_GLSTATE_H
|
||||
#define MOBILEGL_PROGRAM_DEBUGTOOL_H
|
||||
#define MOBILEGL_GLSLTOOL_H
|
||||
|
||||
#include "../../../Includes.h"
|
||||
|
||||
struct ShaderObject {
|
||||
GLenum type;
|
||||
std::string source;
|
||||
std::vector<unsigned int> compiledSpirv;
|
||||
UncertainBool compiled;
|
||||
GLint compileStatus;
|
||||
std::string infoLog;
|
||||
bool markedForDeletion;
|
||||
};
|
||||
|
||||
struct UniformValue {
|
||||
GLenum type;
|
||||
std::vector<GLfloat> floatData;
|
||||
std::vector<GLint> intData;
|
||||
std::vector<GLuint> uintData;
|
||||
std::vector<GLboolean> boolData;
|
||||
GLsizei count;
|
||||
GLsizei numElements;
|
||||
|
||||
UniformValue() : type(0), count(0) {}
|
||||
|
||||
template<typename T>
|
||||
void setData(GLenum uniformType, GLsizei count_, const T* values);
|
||||
};
|
||||
|
||||
struct ProgramObject {
|
||||
std::vector<GLuint> attachedShaders;
|
||||
UncertainBool linked;
|
||||
bool dirty;
|
||||
GLint linkStatus;
|
||||
std::string infoLog;
|
||||
ankerl::unordered_map<std::string, GLint> attribBindings;
|
||||
ankerl::unordered_map<std::string, GLint> attribLocations;
|
||||
ankerl::unordered_map<std::string, GLint> uniformLocations;
|
||||
ankerl::unordered_map<std::string, UniformValue> uniformValues;
|
||||
bool markedForDeletion;
|
||||
};
|
||||
|
||||
class ProgramState {
|
||||
public:
|
||||
ankerl::unordered_map<GLuint, ShaderObject> shaders_;
|
||||
ankerl::unordered_map<GLuint, ProgramObject> programs_;
|
||||
std::set<GLuint> freeShaderIds_;
|
||||
std::set<GLuint> freeProgramIds_;
|
||||
GLuint lastShaderId_ = 0;
|
||||
GLuint lastProgramId_ = 0;
|
||||
GLuint currentProgram_ = 0;
|
||||
|
||||
ProgramState();
|
||||
~ProgramState();
|
||||
|
||||
// Return: the validity of the operation, according to OpenGL 3 standard
|
||||
GLenum CreateShader(GLenum type, GLuint* shader);
|
||||
GLenum CreateProgram(GLuint* program);
|
||||
GLenum DeleteShader(GLuint shader);
|
||||
GLenum DeleteProgram(GLuint program);
|
||||
GLenum LinkShaderToProgram(GLuint program, GLuint shader);
|
||||
GLenum UploadShaderSource(GLuint shader, GLsizei count, const GLchar** string, const GLint* length);
|
||||
GLenum BuildShaderStage(GLuint shader);
|
||||
GLenum FinalizeProgramPipeline(GLuint program);
|
||||
GLenum ActivateRenderProgram(GLuint program);
|
||||
GLenum DefineProgramAttributeBinding(GLuint program, GLuint index, const GLchar* name);
|
||||
GLint QueryProgramAttributeBinding(GLuint program, const GLchar* name);
|
||||
GLint QueryProgramUniformLocation(GLuint program, const GLchar* name);
|
||||
GLenum QueryProgramStateIntVector(GLuint program, GLenum pname, GLint* params);
|
||||
GLenum QueryShaderStateIntVector(GLuint shader, GLenum pname, GLint* params);
|
||||
|
||||
template<typename T>
|
||||
GLenum SetUniform(GLuint program, GLint location, GLsizei count, const T* value, GLenum type);
|
||||
|
||||
template<typename T>
|
||||
GLenum SetUniformMatrix(GLuint program, GLint location, GLsizei count, GLboolean transpose, const T* value, GLenum matrixType);
|
||||
|
||||
#define DECLARE_UNIFORM_FUNCTIONS(type, suffix, vecType) \
|
||||
void UpdateUniform##suffix##1(GLint location, type v0); \
|
||||
void UpdateUniform##suffix##2(GLint location, type v0, type v1); \
|
||||
void UpdateUniform##suffix##3(GLint location, type v0, type v1, type v2); \
|
||||
void UpdateUniform##suffix##4(GLint location, type v0, type v1, type v2, type v3); \
|
||||
void UpdateUniform##suffix##Vector1(GLint location, GLsizei count, const type* value); \
|
||||
void UpdateUniform##suffix##Vector2(GLint location, GLsizei count, const type* value); \
|
||||
void UpdateUniform##suffix##Vector3(GLint location, GLsizei count, const type* value); \
|
||||
void UpdateUniform##suffix##Vector4(GLint location, GLsizei count, const type* value);
|
||||
DECLARE_UNIFORM_FUNCTIONS(GLfloat, Float, GL_FLOAT)
|
||||
DECLARE_UNIFORM_FUNCTIONS(GLint, Int, GL_INT)
|
||||
DECLARE_UNIFORM_FUNCTIONS(GLuint, UInt, GL_UNSIGNED_INT)
|
||||
DECLARE_UNIFORM_FUNCTIONS(GLboolean, Bool, GL_BOOL)
|
||||
#undef DECLARE_UNIFORM_FUNCTIONS
|
||||
#define DECLARE_MATRIX_FUNCTIONS(suffix, matrixType) \
|
||||
void UpdateUniformMatrix##suffix##Vector(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value);
|
||||
DECLARE_MATRIX_FUNCTIONS(2x2, GL_FLOAT_MAT2)
|
||||
DECLARE_MATRIX_FUNCTIONS(3x3, GL_FLOAT_MAT3)
|
||||
DECLARE_MATRIX_FUNCTIONS(4x4, GL_FLOAT_MAT4)
|
||||
DECLARE_MATRIX_FUNCTIONS(2x3, GL_FLOAT_MAT2x3)
|
||||
DECLARE_MATRIX_FUNCTIONS(2x4, GL_FLOAT_MAT2x4)
|
||||
DECLARE_MATRIX_FUNCTIONS(3x2, GL_FLOAT_MAT3x2)
|
||||
DECLARE_MATRIX_FUNCTIONS(3x4, GL_FLOAT_MAT3x4)
|
||||
DECLARE_MATRIX_FUNCTIONS(4x2, GL_FLOAT_MAT4x2)
|
||||
DECLARE_MATRIX_FUNCTIONS(4x3, GL_FLOAT_MAT4x3)
|
||||
#undef DECLARE_MATRIX_FUNCTIONS
|
||||
|
||||
ProgramObject GetProgramObject(GLuint program) const;
|
||||
ShaderObject GetShaderObject(GLuint program) const;
|
||||
GLuint GetCurrentProgram() const;
|
||||
bool SetProgramStatus(GLuint program, GLboolean status);
|
||||
bool SetShaderStatus(GLuint shader, GLboolean status);
|
||||
|
||||
private:
|
||||
bool ValidateShader_(GLuint shader);
|
||||
bool ValidateProgram_(GLuint program);
|
||||
void CleanupShaders_();
|
||||
GLint GetUniformLocation_(GLuint program, GLint location, const GLchar* name);
|
||||
};
|
||||
|
||||
#endif // MOBILEGL_PROGRAMSTATE_H
|
||||
@@ -1,139 +0,0 @@
|
||||
//
|
||||
// Created by BZLZHH on 2025/5/3.
|
||||
//
|
||||
|
||||
#include "ShaderObject.h"
|
||||
|
||||
// Re-Include Includes.h, cuz of the absence of Program/DebugTool.h and Program/GLSLTool.cpp.
|
||||
#undef MOBILEGL_GLSLTOOL_H
|
||||
#undef MOBILEGL_PROGRAM_DEBUGTOOL_H
|
||||
#include "../../../Includes.h"
|
||||
|
||||
GLenum ProgramState::CreateShader(GLenum type, GLuint* shader) {
|
||||
MG_Util::Debug::LogD("MG_State: Program: CreateShader called, type=0x%X, shader ptr=%p", type, shader);
|
||||
if (!shader) {
|
||||
MG_Util::Debug::LogE("MG_State: Program: CreateShader error: shader pointer is null");
|
||||
return GL_INVALID_VALUE;
|
||||
}
|
||||
if (type != GL_VERTEX_SHADER && type != GL_FRAGMENT_SHADER) {
|
||||
MG_Util::Debug::LogE("MG_State: Program: CreateShader error: invalid shader type 0x%X", type);
|
||||
return GL_INVALID_ENUM;
|
||||
}
|
||||
|
||||
GLuint id = freeShaderIds_.empty() ? ++lastShaderId_ : *freeShaderIds_.begin();
|
||||
if (!freeShaderIds_.empty())
|
||||
freeShaderIds_.erase(freeShaderIds_.begin());
|
||||
|
||||
ShaderObject obj;
|
||||
obj.type = type;
|
||||
obj.compiled = {UncertainBool::Unknown, UncertainBool::False};
|
||||
obj.compiledSpirv = {};
|
||||
obj.markedForDeletion = false;
|
||||
obj.compileStatus = GL_FALSE;
|
||||
shaders_[id] = obj;
|
||||
*shader = id;
|
||||
MG_Util::Debug::LogD("MG_State: Program: CreateShader success, new shader id=%u", id);
|
||||
return GL_NO_ERROR;
|
||||
}
|
||||
|
||||
GLenum ProgramState::DeleteShader(GLuint shader) {
|
||||
MG_Util::Debug::LogD("MG_State: Program: DeleteShader called, shader id=%u", shader);
|
||||
if (!ValidateShader_(shader)) {
|
||||
MG_Util::Debug::LogE("MG_State: Program: DeleteShader error: invalid shader id %u", shader);
|
||||
return GL_INVALID_VALUE;
|
||||
}
|
||||
if (shaders_[shader].markedForDeletion) {
|
||||
MG_Util::Debug::LogW("MG_State: Program: DeleteShader warning: shader %u already marked for deletion", shader);
|
||||
return GL_NO_ERROR;
|
||||
}
|
||||
|
||||
bool inUse = false;
|
||||
for (auto& [progId, program] : programs_) {
|
||||
if (std::find(program.attachedShaders.begin(),
|
||||
program.attachedShaders.end(), shader) != program.attachedShaders.end()) {
|
||||
inUse = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (inUse) {
|
||||
shaders_[shader].markedForDeletion = true;
|
||||
MG_Util::Debug::LogD("MG_State: Program: DeleteShader info: shader %u marked for deferred deletion (in use)", shader);
|
||||
} else {
|
||||
shaders_.erase(shader);
|
||||
// TODO: Prevent the object that uses a freeId from conflicting with legacy object in the backend.
|
||||
//freeShaderIds_.insert(shader);
|
||||
MG_Util::Debug::LogD("MG_State: Program: DeleteShader success: shader %u deleted immediately", shader);
|
||||
}
|
||||
return GL_NO_ERROR;
|
||||
}
|
||||
|
||||
GLenum ProgramState::UploadShaderSource(GLuint shader, GLsizei count,
|
||||
const GLchar** string, const GLint* length) {
|
||||
MG_Util::Debug::LogD("MG_State: Program: UploadShaderSource called, shader id=%u, count=%d", shader, count);
|
||||
if (!ValidateShader_(shader)) {
|
||||
MG_Util::Debug::LogE("MG_State: Program: UploadShaderSource error: invalid shader id %u", shader);
|
||||
return GL_INVALID_VALUE;
|
||||
}
|
||||
if (count < 0) {
|
||||
MG_Util::Debug::LogE("MG_State: Program: UploadShaderSource error: negative count %d", count);
|
||||
return GL_INVALID_VALUE;
|
||||
}
|
||||
|
||||
std::string source;
|
||||
for (GLsizei i = 0; i < count; ++i) {
|
||||
const GLchar* str = string[i];
|
||||
GLint len = (length && length[i] >= 0) ? length[i] : strlen(str);
|
||||
source.append(str, len);
|
||||
}
|
||||
shaders_[shader].source = std::move(source);
|
||||
MG_Util::Debug::LogD("MG_State: Program: UploadShaderSource success: source uploaded (length=%zu)", shaders_[shader].source.size());
|
||||
return GL_NO_ERROR;
|
||||
}
|
||||
|
||||
GLenum ProgramState::BuildShaderStage(GLuint shader) {
|
||||
MG_Util::Debug::LogD("MG_State: Program: BuildShaderStage called, shader id=%u", shader);
|
||||
if (!ValidateShader_(shader)) {
|
||||
MG_Util::Debug::LogE("MG_State: Program: BuildShaderStage error: invalid shader id %u", shader);
|
||||
return GL_INVALID_VALUE;
|
||||
}
|
||||
auto& obj = shaders_[shader];
|
||||
|
||||
std::string compilationLog;
|
||||
auto spirv = MG_Util::Program::CompileGLSLToSPIRV(obj.type, obj.source, compilationLog);
|
||||
if (spirv.empty()) {
|
||||
obj.infoLog = "Shader compilation failed: " + compilationLog;
|
||||
obj.compiled = UncertainBool::False;
|
||||
obj.compileStatus = GL_FALSE;
|
||||
MG_Util::Debug::LogE("MG_State: Program: BuildShaderStage error: %s", compilationLog.c_str());
|
||||
return GL_INVALID_OPERATION;
|
||||
}
|
||||
obj.compiledSpirv = spirv;
|
||||
obj.compiled = {UncertainBool::Unknown, UncertainBool::True};
|
||||
obj.compileStatus = GL_TRUE;
|
||||
obj.infoLog.clear();
|
||||
MG_Util::Debug::LogD("MG_State: Program: BuildShaderStage success: shader %u compiled to SPIR-V (size=%zu bytes)", shader, spirv.size() * sizeof(unsigned));
|
||||
return GL_NO_ERROR;
|
||||
}
|
||||
|
||||
bool ProgramState::SetShaderStatus(GLuint shader, GLboolean status) {
|
||||
MG_Util::Debug::LogD("MG_State: Program: SetShaderStatus called, shader id=%u, status=%d", shader, status);
|
||||
if (!ValidateShader_(shader)) {
|
||||
MG_Util::Debug::LogE("MG_State: Program: SetShaderStatus error: invalid shader id %u", shader);
|
||||
return false;
|
||||
}
|
||||
auto& obj = shaders_[shader];
|
||||
if (obj.compiled.getValue() != UncertainBool::Unknown) {
|
||||
MG_Util::Debug::LogW("MG_State: Program: SetShaderStatus warning: shader %u status already set", shader);
|
||||
return false;
|
||||
}
|
||||
obj.compiled = (status == GL_TRUE) ? UncertainBool::True : UncertainBool::False;
|
||||
obj.compileStatus = status;
|
||||
MG_Util::Debug::LogD("MG_State: Program: SetShaderStatus success: shader %u status=%d", shader, status);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ProgramState::ValidateShader_(GLuint shader) {
|
||||
bool valid = shaders_.count(shader) && !shaders_[shader].markedForDeletion;
|
||||
MG_Util::Debug::LogD("MG_State: Program: ValidateShader_ called, shader id=%u, result=%d", shader, valid);
|
||||
return valid;
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
//
|
||||
// Created by BZLZHH on 2025/5/3.
|
||||
//
|
||||
|
||||
#ifndef MOBILEGL_SHADEROBJECT_H
|
||||
#define MOBILEGL_SHADEROBJECT_H
|
||||
|
||||
#define MOBILEGL_GLSTATE_H
|
||||
|
||||
#include "../../../Includes.h"
|
||||
|
||||
#endif //MOBILEGL_SHADEROBJECT_H
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,117 +0,0 @@
|
||||
//
|
||||
// Created by BZLZHH on 2025/4/4.
|
||||
//
|
||||
|
||||
#ifndef MOBILEGL_TEXTURESTATE_H
|
||||
#define MOBILEGL_TEXTURESTATE_H
|
||||
#define MOBILEGL_GLSTATE_H
|
||||
|
||||
#include "../../../Includes.h"
|
||||
|
||||
struct ComponentSizes {
|
||||
GLint red = 0;
|
||||
GLint green = 0;
|
||||
GLint blue = 0;
|
||||
GLint alpha = 0;
|
||||
GLint depth = 0;
|
||||
GLint stencil = 0;
|
||||
bool isCompressed = false;
|
||||
};
|
||||
|
||||
struct TextureParams {
|
||||
template <typename K, typename V>
|
||||
using unordered_map = ankerl::unordered_dense::map<K, V>;
|
||||
unordered_map<GLenum, GLfloat> texPropertiesFloat;
|
||||
unordered_map<GLenum, GLint> texPropertiesInt;
|
||||
struct MipmapLevel {
|
||||
GLsizei width = 0;
|
||||
GLsizei height = 0;
|
||||
GLenum format = GL_RGBA;
|
||||
GLenum internalFormat = GL_RGBA;
|
||||
GLenum type = GL_UNSIGNED_BYTE;
|
||||
std::vector<GLubyte> pixelData;
|
||||
bool hasData = false;
|
||||
bool dirty = false; // TODO: encapsulate this with an public API to RHI
|
||||
};
|
||||
unordered_map<GLint, MipmapLevel> mipmapData;
|
||||
};
|
||||
|
||||
class TextureObject {
|
||||
public:
|
||||
bool generated = false;
|
||||
GLenum target = GL_NONE;
|
||||
TextureParams params;
|
||||
const void* data = nullptr;
|
||||
bool IsImmutable() const;
|
||||
uint64_t createTimestamp{};
|
||||
};
|
||||
|
||||
class TextureUnitState {
|
||||
template <typename K, typename V>
|
||||
using unordered_map = ankerl::unordered_dense::map<K, V>;
|
||||
private:
|
||||
GLenum activeTarget = GL_TEXTURE_2D;
|
||||
|
||||
public:
|
||||
unordered_map<GLenum, GLuint> boundTextures;
|
||||
void Bind(GLenum target, GLuint texture);
|
||||
GLuint GetBoundTexture(GLenum target);
|
||||
};
|
||||
|
||||
class TextureState {
|
||||
template <typename K, typename V>
|
||||
using unordered_map = ankerl::unordered_dense::map<K, V>;
|
||||
private:
|
||||
|
||||
GLuint lastUsedID_ = 1;
|
||||
// ankerl::unordered_set<GLuint> freeIDs_;
|
||||
std::vector<GLuint> freeID_;
|
||||
|
||||
unordered_map<GLenum, TextureObject> proxyTextures_;
|
||||
|
||||
static GLint GetUnpackParam_(GLenum pname);
|
||||
public:
|
||||
TextureState();
|
||||
|
||||
bool IsTextureGenerated(GLuint texture);
|
||||
bool IsTexture(GLuint texture);
|
||||
unordered_map<GLuint, TextureObject> textures;
|
||||
|
||||
// Return: the validity of the operation, according to OpenGL 3 standard
|
||||
GLenum BindUnit(GLenum textureUnit);
|
||||
GLenum Create(GLuint* texture);
|
||||
GLenum CreateN(GLsizei n, GLuint* textures);
|
||||
GLenum Bind(GLenum target, GLuint texture);
|
||||
GLenum Upload2D(GLenum target, GLint level, GLint internalFormat,
|
||||
GLsizei width, GLsizei height, GLint border, GLenum format,
|
||||
GLenum type, const void* data);
|
||||
GLenum UpdateRegion2D(GLenum target, GLint level, GLint xoffset,
|
||||
GLint yoffset, GLsizei width, GLsizei height, GLenum format,
|
||||
GLenum type, const GLvoid* data);
|
||||
GLenum SetTexturePropertyInt(GLenum target, GLenum pname, GLint param);
|
||||
GLenum SetTexturePropertyFloat(GLenum target, GLenum pname, GLfloat param);
|
||||
GLenum Delete(GLuint texture);
|
||||
GLenum DeleteN(GLsizei n, const GLuint* textures);
|
||||
GLenum QueryLevelPropertyIntVector(GLenum target, GLint level, GLenum pname, GLint* params);
|
||||
|
||||
std::vector<TextureUnitState> textureUnits_;
|
||||
GLuint activeTextureUnit_ = 0;
|
||||
private:
|
||||
size_t CalculatePixelDataSize_(GLenum format, GLenum type, GLsizei width, GLsizei height);
|
||||
void InvalidateTextureInAllUnits_(GLuint texture);
|
||||
static ComponentSizes GetComponentSize_s_(GLenum internalFormat);
|
||||
size_t CalculateBytesPerPixel_(GLenum format, GLenum type);
|
||||
static size_t GetComponentSize_(GLenum type);
|
||||
void SwapBytesForTexture_(GLenum format, GLenum type, const GLubyte* src, GLubyte* dst, GLsizei width);
|
||||
static void ReverseBitOrder_(const GLubyte* src, GLubyte* dst, size_t size);
|
||||
static GLubyte ReverseBits_(GLubyte b);
|
||||
void SwapPixelBytes_(GLenum format, GLenum type, const GLubyte* src, GLubyte* dst);
|
||||
GLenum CheckUploadingTexture2DValidity_(GLenum target, GLint level, GLint internalFormat,
|
||||
GLsizei width, GLsizei height, GLint border, GLenum format,
|
||||
GLenum type, const void* data);
|
||||
GLenum CheckUpdatingTextureRegion2DValidity_(GLenum target, GLint level, GLint xoffset,
|
||||
GLint yoffset, GLsizei width, GLsizei height, GLenum format,
|
||||
GLenum type, const GLvoid* data);
|
||||
};
|
||||
|
||||
#endif //MOBILEGL_TEXTURESTATE_H
|
||||
@@ -1,162 +0,0 @@
|
||||
//
|
||||
// Created by BZLZHH on 2025/5/1.
|
||||
//
|
||||
|
||||
// TODO: Add more gl error check for vertex array state manager.
|
||||
|
||||
#include "VertexArrayState.h"
|
||||
|
||||
VertexArrayState::VertexArrayState() {
|
||||
vaos_[0];
|
||||
}
|
||||
|
||||
GLenum VertexArrayState::GenName(GLuint *array) {
|
||||
MG_Util::Debug::LogD("MG_State: VAO: GenName");
|
||||
if (!array)
|
||||
return GL_INVALID_VALUE;
|
||||
GLuint id;
|
||||
if (freeIds_.empty()) {
|
||||
id = ++lastId_;
|
||||
} else {
|
||||
id = *freeIds_.begin();
|
||||
freeIds_.erase(freeIds_.begin());
|
||||
}
|
||||
*array = id;
|
||||
MG_Util::Debug::LogD("MG_State: VAO: Generated new name %d", id);
|
||||
return GL_NO_ERROR;
|
||||
}
|
||||
|
||||
GLenum VertexArrayState::GenNameN(GLsizei n, GLuint* arrays) {
|
||||
MG_Util::Debug::LogD("MG_State: VAO: GenNameN called with n=%d", n);
|
||||
if (n < 0)
|
||||
return GL_INVALID_VALUE;
|
||||
for (GLsizei i = 0; i < n; ++i) {
|
||||
GLenum result = GenName(&arrays[i]);
|
||||
if (result != GL_NO_ERROR) {
|
||||
MG_Util::Debug::LogE("MG_State: VAO: GenNameN failed at index %d with error 0x%x", i, result);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
MG_Util::Debug::LogD("MG_State: VAO: GenNameN created %d names", n);
|
||||
return GL_NO_ERROR;
|
||||
}
|
||||
|
||||
GLenum VertexArrayState::Create(GLuint* array) {
|
||||
if (array == nullptr) return GL_INVALID_VALUE;
|
||||
|
||||
GLuint id = freeIds_.empty() ? ++lastId_ : *freeIds_.begin();
|
||||
if (!freeIds_.empty()) {
|
||||
freeIds_.erase(freeIds_.begin());
|
||||
}
|
||||
|
||||
*array = id;
|
||||
vaos_[id].generated = true;
|
||||
return GL_NO_ERROR;
|
||||
}
|
||||
|
||||
GLenum VertexArrayState::CreateN(GLsizei n, GLuint* arrays) {
|
||||
if (n < 0) {
|
||||
return GL_INVALID_VALUE;
|
||||
}
|
||||
|
||||
if (n > 0 && arrays == nullptr) {
|
||||
return GL_INVALID_VALUE;
|
||||
}
|
||||
|
||||
for (GLsizei i = 0; i < n; ++i) {
|
||||
if (GLenum error = Create(&arrays[i]); error != GL_NO_ERROR) {
|
||||
return error;
|
||||
}
|
||||
}
|
||||
return GL_NO_ERROR;
|
||||
}
|
||||
|
||||
GLenum VertexArrayState::Bind(GLuint array) {
|
||||
MG_Util::Debug::LogD("MG_State: VAO: Bind called for %u", array);
|
||||
if (array != 0) {
|
||||
if (!ValidateGeneratedName(array)) {
|
||||
MG_Util::Debug::LogE("MG_State: VAO: Bind invalid name %u", array);
|
||||
return GL_INVALID_OPERATION;
|
||||
}
|
||||
auto& vao = vaos_[array];
|
||||
if (!vao.generated) {
|
||||
MG_Util::Debug::LogD("MG_State: VAO: Creating VAO %u during bind", array);
|
||||
vao.generated = true;
|
||||
}
|
||||
}
|
||||
currentVao_ = array;
|
||||
MG_Util::Debug::LogD("MG_State: VAO: Bound to %u", array);
|
||||
return GL_NO_ERROR;
|
||||
}
|
||||
|
||||
bool VertexArrayState::ValidateGeneratedName(GLuint array) {
|
||||
if (array == 0)
|
||||
return true;
|
||||
bool inFreeList = freeIds_.count(array) > 0;
|
||||
bool valid = (array <= lastId_) && !inFreeList;
|
||||
MG_Util::Debug::LogD("MG_State: VAO: ValidateGeneratedName %u: %d", array, valid);
|
||||
return valid;
|
||||
}
|
||||
|
||||
bool VertexArrayState::ValidateAllocatedHandle(GLuint array) {
|
||||
bool exists = vaos_.count(array) && vaos_[array].generated;
|
||||
MG_Util::Debug::LogD("MG_State: VAO: ValidateAllocatedHandle %u: %d", array, exists);
|
||||
return exists;
|
||||
}
|
||||
|
||||
GLenum VertexArrayState::EnableAttrib(GLuint index) {
|
||||
if (!ValidateAllocatedHandle(currentVao_))
|
||||
return GL_INVALID_OPERATION;
|
||||
if (index >= GL_MAX_VERTEX_ATTRIBS) return GL_INVALID_VALUE;
|
||||
GetCurrentVAO()->attribs[index].enabled = true;
|
||||
MG_Util::Debug::LogD("Attrib vaos_[%u].attribs[%u].enabled = %d", currentVao_, index, vaos_[currentVao_].attribs[index].enabled);
|
||||
|
||||
GetCurrentVAO()->attribDirty = true;
|
||||
return GL_NO_ERROR;
|
||||
}
|
||||
|
||||
GLenum VertexArrayState::DisableAttrib(GLuint index) {
|
||||
if (!ValidateAllocatedHandle(currentVao_))
|
||||
return GL_INVALID_OPERATION;
|
||||
if (index >= GL_MAX_VERTEX_ATTRIBS) return GL_INVALID_VALUE;
|
||||
GetCurrentVAO()->attribs[index].enabled = false;
|
||||
MG_Util::Debug::LogD("Attrib vaos_[%u].attribs[%u].enabled = %d", currentVao_, index, vaos_[currentVao_].attribs[index].enabled);
|
||||
|
||||
GetCurrentVAO()->attribDirty = true;
|
||||
return GL_NO_ERROR;
|
||||
}
|
||||
|
||||
GLenum VertexArrayState::SetAttribPointer(GLuint index, GLint size, GLenum type,
|
||||
GLboolean normalized, GLsizei stride,
|
||||
const void* pointer, bool isInteger,
|
||||
GLuint currentArrayBuffer) {
|
||||
if (!ValidateAllocatedHandle(currentVao_))
|
||||
return GL_INVALID_OPERATION;
|
||||
if (index >= GL_MAX_VERTEX_ATTRIBS) return GL_INVALID_VALUE;
|
||||
|
||||
VertexAttribState state;
|
||||
state.size = size;
|
||||
state.type = type;
|
||||
state.normalized = normalized;
|
||||
state.stride = stride;
|
||||
state.pointer = pointer;
|
||||
state.buffer = currentArrayBuffer;
|
||||
state.isInteger = isInteger;
|
||||
if (vaos_[currentVao_].attribs.count(index) && vaos_[currentVao_].attribs[index].enabled)
|
||||
state.enabled = true;
|
||||
|
||||
vaos_[currentVao_].attribs[index] = state;
|
||||
|
||||
GetCurrentVAO()->attribDirty = true;
|
||||
return GL_NO_ERROR;
|
||||
}
|
||||
|
||||
GLuint VertexArrayState::GetBoundElementBuffer() {
|
||||
auto it = vaos_.find(currentVao_);
|
||||
return (it != vaos_.end()) ? it->second.elementBuffer : 0;
|
||||
}
|
||||
|
||||
VertexArrayObject* VertexArrayState::GetCurrentVAO() {
|
||||
auto it = vaos_.find(currentVao_);
|
||||
return (it != vaos_.end()) ? &it->second : &vaos_.at(0);
|
||||
}
|
||||
@@ -1,59 +0,0 @@
|
||||
//
|
||||
// Created by BZLZHH on 2025/5/1.
|
||||
//
|
||||
|
||||
#ifndef MOBILEGL_VERTEXARRAYSTATE_H
|
||||
#define MOBILEGL_VERTEXARRAYSTATE_H
|
||||
#define MOBILEGL_GLSTATE_H
|
||||
|
||||
#include "../../../Includes.h"
|
||||
|
||||
struct VertexAttribState {
|
||||
bool enabled;
|
||||
GLint size = 4;
|
||||
GLenum type = GL_FLOAT;
|
||||
GLboolean normalized = GL_FALSE;
|
||||
GLsizei stride = 0;
|
||||
const GLvoid* pointer = nullptr;
|
||||
GLuint buffer = 0;
|
||||
bool isInteger = false;
|
||||
};
|
||||
|
||||
struct VertexArrayObject {
|
||||
bool generated = false;
|
||||
bool attribDirty = false;
|
||||
bool eboDirty = false;
|
||||
GLuint elementBuffer = 0;
|
||||
ankerl::unordered_map<GLuint, VertexAttribState> attribs;
|
||||
};
|
||||
|
||||
class VertexArrayState {
|
||||
public:
|
||||
VertexArrayState();
|
||||
|
||||
// Return: the validity of the operation, according to OpenGL 3 standard
|
||||
GLenum GenName(GLuint* array);
|
||||
GLenum GenNameN(GLsizei n, GLuint* arrays);
|
||||
GLenum Create(GLuint* array);
|
||||
GLenum CreateN(GLsizei n, GLuint* arrays);
|
||||
GLenum Bind(GLuint array);
|
||||
GLenum EnableAttrib(GLuint index);
|
||||
GLenum DisableAttrib(GLuint index);
|
||||
GLenum SetAttribPointer(GLuint index, GLint size, GLenum type,
|
||||
GLboolean normalized, GLsizei stride,
|
||||
const void* pointer, bool isInteger,
|
||||
GLuint currentArrayBuffer);
|
||||
|
||||
GLuint GetBoundElementBuffer();
|
||||
VertexArrayObject* GetCurrentVAO();
|
||||
bool ValidateGeneratedName(GLuint array);
|
||||
bool ValidateAllocatedHandle(GLuint array);
|
||||
|
||||
GLuint currentVao_ = 0;
|
||||
ankerl::unordered_map<GLuint, VertexArrayObject> vaos_;
|
||||
private:
|
||||
std::set<GLuint> freeIds_;
|
||||
GLuint lastId_ = 0;
|
||||
};
|
||||
|
||||
#endif //MOBILEGL_VERTEXARRAYSTATE_H
|
||||
@@ -1,127 +0,0 @@
|
||||
//
|
||||
// Created by BZLZHH on 2025/5/3.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
#include <initializer_list>
|
||||
#include <stdexcept>
|
||||
#include <utility>
|
||||
|
||||
class UncertainBool {
|
||||
public:
|
||||
enum Value { False = 0, True = 1, Unknown = 2 };
|
||||
|
||||
UncertainBool() : value_(False), default_(false) {}
|
||||
|
||||
explicit UncertainBool(bool b) : value_(b ? True : False), default_(false) {}
|
||||
|
||||
UncertainBool(Value val, bool def) : value_(val), default_(def) {
|
||||
validateValue();
|
||||
}
|
||||
|
||||
UncertainBool(bool val, bool def) : value_(val ? True : False), default_(def) {
|
||||
validateValue();
|
||||
}
|
||||
|
||||
UncertainBool& operator=(Value val) {
|
||||
value_ = val;
|
||||
validateValue();
|
||||
return *this;
|
||||
}
|
||||
|
||||
UncertainBool& operator=(bool b) {
|
||||
value_ = b ? True : False;
|
||||
return *this;
|
||||
}
|
||||
|
||||
UncertainBool& operator=(std::initializer_list<std::pair<bool, bool>> init) {
|
||||
if (init.size() != 1) throw std::invalid_argument("Invalid initializer");
|
||||
value_ = init.begin()->first ? True : False;
|
||||
default_ = init.begin()->second;
|
||||
return *this;
|
||||
}
|
||||
|
||||
explicit operator bool() const {
|
||||
return toBool();
|
||||
}
|
||||
|
||||
bool toBool() const {
|
||||
if (value_ == True) return true;
|
||||
else if (value_ == False) return false;
|
||||
else return default_;
|
||||
}
|
||||
|
||||
UncertainBool operator!() const {
|
||||
return {static_cast<bool>(*this) ? False : True, false};
|
||||
}
|
||||
|
||||
bool operator==(const UncertainBool& rhs) const {
|
||||
return static_cast<bool>(*this) == static_cast<bool>(rhs);
|
||||
}
|
||||
bool operator!=(const UncertainBool& rhs) const { return !(*this == rhs); }
|
||||
|
||||
friend UncertainBool operator&&(const UncertainBool& lhs, const UncertainBool& rhs) {
|
||||
bool actualDefault = lhs.default_ && rhs.default_;
|
||||
if(lhs.value_ == False || rhs.value_ == False) return {False,actualDefault};
|
||||
else if(lhs.value_ == True && rhs.value_ == True) return {True,actualDefault};
|
||||
else return {Unknown, actualDefault};
|
||||
}
|
||||
|
||||
friend UncertainBool operator||(const UncertainBool& lhs, const UncertainBool& rhs) {
|
||||
bool actualDefault = lhs.default_ || rhs.default_;
|
||||
if(lhs.value_ == True || rhs.value_ == True) return {True,actualDefault};
|
||||
else if(lhs.value_ == False && rhs.value_ == False) return {False,actualDefault};
|
||||
else return {Unknown, actualDefault};
|
||||
}
|
||||
|
||||
friend UncertainBool operator&&(bool lhs,const UncertainBool& rhs){
|
||||
return UncertainBool(lhs, lhs) && rhs;
|
||||
}
|
||||
|
||||
friend UncertainBool operator||(bool lhs,const UncertainBool& rhs){
|
||||
return UncertainBool(lhs, lhs) || rhs;
|
||||
}
|
||||
|
||||
UncertainBool& operator&=(const UncertainBool& rhs) {
|
||||
*this = *this && rhs;
|
||||
return *this;
|
||||
}
|
||||
|
||||
UncertainBool& operator|=(const UncertainBool& rhs) {
|
||||
*this = *this || rhs;
|
||||
return *this;
|
||||
}
|
||||
|
||||
UncertainBool& operator=(std::initializer_list<std::pair<Value, bool>> init) {
|
||||
if (init.size() != 1) throw std::invalid_argument("Invalid initializer");
|
||||
value_ = init.begin()->first;
|
||||
default_ = init.begin()->second;
|
||||
validateValue();
|
||||
return *this;
|
||||
}
|
||||
|
||||
Value getValue() const { return value_; }
|
||||
bool getDefault() const { return default_; }
|
||||
|
||||
private:
|
||||
Value value_;
|
||||
bool default_;
|
||||
|
||||
void validateValue() {
|
||||
if (value_ != False && value_ != True && value_ != Unknown) {
|
||||
throw std::invalid_argument("Invalid value");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
inline UncertainBool operator!(const UncertainBool& lhs) {
|
||||
return lhs.operator!();
|
||||
}
|
||||
|
||||
inline bool operator==(bool lhs, const UncertainBool& rhs) {
|
||||
return static_cast<bool>(rhs) == lhs;
|
||||
}
|
||||
|
||||
inline bool operator!=(bool lhs, const UncertainBool& rhs) {
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
@@ -1,234 +0,0 @@
|
||||
//
|
||||
// Created by BZLZHH on 2025/4/26.
|
||||
//
|
||||
|
||||
#include "TestDrawing.h"
|
||||
|
||||
namespace MG_RHI::GLES::Test {
|
||||
constexpr int DISPLAY_COLUMNS = 8;
|
||||
constexpr int DISPLAY_ROWS = 10;
|
||||
constexpr int MAX_DISPLAY_TEXTURES = DISPLAY_COLUMNS * DISPLAY_ROWS;
|
||||
|
||||
bool IsTextureComplete(const TextureObject& tex) {
|
||||
return !tex.params.mipmapData.empty();
|
||||
}
|
||||
|
||||
bool CheckShaderCompileStatus(GLuint shader, const char* type) {
|
||||
GLint success;
|
||||
::GLES::glGetShaderiv(shader, GL_COMPILE_STATUS, &success);
|
||||
if (!success) {
|
||||
GLchar infoLog[512];
|
||||
::GLES::glGetShaderInfoLog(shader, 512, NULL, infoLog);
|
||||
MG_Util::Debug::LogE("Shader compilation error (%s): %s", type, infoLog);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CheckProgramLinkStatus(GLuint program) {
|
||||
GLint success;
|
||||
::GLES::glGetProgramiv(program, GL_LINK_STATUS, &success);
|
||||
if (!success) {
|
||||
GLchar infoLog[512];
|
||||
::GLES::glGetProgramInfoLog(program, 512, NULL, infoLog);
|
||||
MG_Util::Debug::LogE("Program link error: %s", infoLog);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// TODO: Use the textures state from MG_RHI(another state?) rather than directly from MG_State
|
||||
void DrawAllTextures() {
|
||||
::GLES::glClearColor(1,1,1,1);
|
||||
::GLES::glClear(GL_COLOR_BUFFER_BIT);
|
||||
|
||||
struct ScreenResources {
|
||||
GLuint program = 0;
|
||||
GLuint quadVAO = 0;
|
||||
GLuint quadVBO = 0;
|
||||
GLint uTexLoc = -1;
|
||||
GLint uMVPLoc = -1;
|
||||
ankerl::unordered_map<GLuint, GLuint> textureCache;
|
||||
ankerl::unordered_map<GLuint, bool> textureDirty;
|
||||
};
|
||||
|
||||
static ScreenResources sRes;
|
||||
static glm::ivec2 lastScreenSize{0, 0};
|
||||
|
||||
GLint viewport[4];
|
||||
::GLES::glGetIntegerv(GL_VIEWPORT, viewport);
|
||||
|
||||
const glm::ivec2 screenSize(viewport[2], viewport[3]);
|
||||
|
||||
if (screenSize != lastScreenSize) {
|
||||
if (sRes.quadVAO) {
|
||||
::GLES::glDeleteVertexArrays(1, &sRes.quadVAO);
|
||||
::GLES::glDeleteBuffers(1, &sRes.quadVBO);
|
||||
sRes.quadVAO = sRes.quadVBO = 0;
|
||||
}
|
||||
lastScreenSize = screenSize;
|
||||
}
|
||||
|
||||
if (!sRes.program) {
|
||||
const char* vsSrc = R"(#version 320 es
|
||||
layout(location=0) in vec2 aPos;
|
||||
layout(location=1) in vec2 aTexUV;
|
||||
out vec2 vUV;
|
||||
uniform mat4 uMVP;
|
||||
void main() {
|
||||
gl_Position = uMVP * vec4(aPos, 0.0, 1.0);
|
||||
vUV = aTexUV;
|
||||
})";
|
||||
|
||||
const char* fsSrc = R"(#version 320 es
|
||||
precision mediump float;
|
||||
in vec2 vUV;
|
||||
uniform sampler2D uTex;
|
||||
out vec4 FragColor;
|
||||
void main() {
|
||||
FragColor = texture(uTex, vUV);
|
||||
})";
|
||||
|
||||
GLuint vs = ::GLES::glCreateShader(GL_VERTEX_SHADER);
|
||||
::GLES::glShaderSource(vs, 1, &vsSrc, NULL);
|
||||
::GLES::glCompileShader(vs);
|
||||
if (!CheckShaderCompileStatus(vs, "vertex")) return;
|
||||
|
||||
GLuint fs = ::GLES::glCreateShader(GL_FRAGMENT_SHADER);
|
||||
::GLES::glShaderSource(fs, 1, &fsSrc, NULL);
|
||||
::GLES::glCompileShader(fs);
|
||||
if (!CheckShaderCompileStatus(fs, "fragment")) return;
|
||||
|
||||
sRes.program = ::GLES::glCreateProgram();
|
||||
::GLES::glAttachShader(sRes.program, vs);
|
||||
::GLES::glAttachShader(sRes.program, fs);
|
||||
::GLES::glLinkProgram(sRes.program);
|
||||
if (!CheckProgramLinkStatus(sRes.program)) return;
|
||||
|
||||
sRes.uTexLoc = ::GLES::glGetUniformLocation(sRes.program, "uTex");
|
||||
sRes.uMVPLoc = ::GLES::glGetUniformLocation(sRes.program, "uMVP");
|
||||
|
||||
::GLES::glDeleteShader(vs);
|
||||
::GLES::glDeleteShader(fs);
|
||||
}
|
||||
|
||||
if (!sRes.quadVAO) {
|
||||
const float margin = 0.01f;
|
||||
const float gridWidth = (2.0f - 2*margin) / DISPLAY_COLUMNS;
|
||||
const float gridHeight = (2.0f - 2*margin) / DISPLAY_ROWS;
|
||||
|
||||
std::vector<float> vertices;
|
||||
vertices.reserve(MAX_DISPLAY_TEXTURES * 16);
|
||||
|
||||
for (int col = 0; col < DISPLAY_COLUMNS; ++col) {
|
||||
for (int row = 0; row < DISPLAY_ROWS; ++row) {
|
||||
const float xStart = -1.0f + margin + col * gridWidth;
|
||||
const float yStart = -1.0f + margin + row * gridHeight;
|
||||
const float xEnd = xStart + gridWidth - margin;
|
||||
const float yEnd = yStart + gridHeight - margin;
|
||||
|
||||
vertices.insert(vertices.end(), {
|
||||
xStart, yStart, 0.0f, 0.0f,
|
||||
xEnd, yStart, 1.0f, 0.0f,
|
||||
xEnd, yEnd, 1.0f, 1.0f,
|
||||
xStart, yEnd, 0.0f, 1.0f
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
::GLES::glGenVertexArrays(1, &sRes.quadVAO);
|
||||
::GLES::glGenBuffers(1, &sRes.quadVBO);
|
||||
::GLES::glBindVertexArray(sRes.quadVAO);
|
||||
::GLES::glBindBuffer(GL_ARRAY_BUFFER, sRes.quadVBO);
|
||||
::GLES::glBufferData(GL_ARRAY_BUFFER,
|
||||
vertices.size() * sizeof(float),
|
||||
vertices.data(),
|
||||
GL_STATIC_DRAW
|
||||
);
|
||||
|
||||
::GLES::glEnableVertexAttribArray(0);
|
||||
::GLES::glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE,
|
||||
4 * sizeof(float), (void*)0
|
||||
);
|
||||
::GLES::glEnableVertexAttribArray(1);
|
||||
::GLES::glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE,
|
||||
4 * sizeof(float), (void*)(2 * sizeof(float))
|
||||
);
|
||||
::GLES::glBindVertexArray(0);
|
||||
}
|
||||
|
||||
std::vector<std::pair<GLuint, TextureObject*>> sortedTextures;
|
||||
for (auto&& [stateID, texObj] : MG_State_T::textureState->textures) {
|
||||
if (!texObj.generated || texObj.target != GL_TEXTURE_2D) continue;
|
||||
if (texObj.params.mipmapData.empty()) continue;
|
||||
sortedTextures.emplace_back(stateID, &texObj);
|
||||
}
|
||||
std::sort(sortedTextures.begin(), sortedTextures.end(),
|
||||
[](auto& a, auto& b) {
|
||||
return a.second->createTimestamp > b.second->createTimestamp;
|
||||
}
|
||||
);
|
||||
sortedTextures.resize(std::min<size_t>(sortedTextures.size(), MAX_DISPLAY_TEXTURES));
|
||||
|
||||
for (auto&& [stateID, texObj] : sortedTextures) {
|
||||
auto& dirtyFlag = sRes.textureDirty[stateID];
|
||||
bool needCreate = !sRes.textureCache.count(stateID);
|
||||
|
||||
if (needCreate) {
|
||||
GLuint glTexID;
|
||||
::GLES::glGenTextures(1, &glTexID);
|
||||
sRes.textureCache[stateID] = glTexID;
|
||||
dirtyFlag = true;
|
||||
}
|
||||
|
||||
if (dirtyFlag || needCreate) {
|
||||
const auto& mip0 = texObj->params.mipmapData.begin()->second;
|
||||
if (mip0.hasData) {
|
||||
GLuint glTexID = sRes.textureCache[stateID];
|
||||
::GLES::glBindTexture(GL_TEXTURE_2D, glTexID);
|
||||
::GLES::glTexImage2D(GL_TEXTURE_2D, 0, mip0.internalFormat,
|
||||
mip0.width, mip0.height, 0,
|
||||
mip0.format, mip0.type, mip0.pixelData.data()
|
||||
);
|
||||
::GLES::glTexParameteri(GL_TEXTURE_2D,
|
||||
GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
::GLES::glTexParameteri(GL_TEXTURE_2D,
|
||||
GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
::GLES::glTexParameteri(GL_TEXTURE_2D,
|
||||
GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
::GLES::glTexParameteri(GL_TEXTURE_2D,
|
||||
GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
if (texObj->params.mipmapData.size() > 1) {
|
||||
::GLES::glGenerateMipmap(GL_TEXTURE_2D);
|
||||
}
|
||||
dirtyFlag = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GLboolean origDepthTest = ::GLES::glIsEnabled(GL_DEPTH_TEST);
|
||||
GLint origProgram, origViewport[4];
|
||||
::GLES::glGetIntegerv(GL_VIEWPORT, origViewport);
|
||||
::GLES::glGetIntegerv(GL_CURRENT_PROGRAM, &origProgram);
|
||||
|
||||
::GLES::glDisable(GL_DEPTH_TEST);
|
||||
::GLES::glUseProgram(sRes.program);
|
||||
::GLES::glUniformMatrix4fv(sRes.uMVPLoc, 1, GL_FALSE,
|
||||
&glm::mat4(1.0f)[0][0]
|
||||
);
|
||||
::GLES::glUniform1i(sRes.uTexLoc, 0);
|
||||
::GLES::glBindVertexArray(sRes.quadVAO);
|
||||
|
||||
for (size_t i = 0; i < sortedTextures.size(); ++i) {
|
||||
const GLuint glTexID = sRes.textureCache[sortedTextures[i].first];
|
||||
::GLES::glActiveTexture(GL_TEXTURE0);
|
||||
::GLES::glBindTexture(GL_TEXTURE_2D, glTexID);
|
||||
::GLES::glDrawArrays(GL_TRIANGLE_FAN, static_cast<GLint>(i*4), 4);
|
||||
}
|
||||
|
||||
if (origDepthTest) ::GLES::glEnable(GL_DEPTH_TEST);
|
||||
::GLES::glUseProgram(origProgram);
|
||||
::GLES::glViewport(origViewport[0], origViewport[1],
|
||||
origViewport[2], origViewport[3]);
|
||||
}
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
//
|
||||
// Created by BZLZHH on 2025/4/26.
|
||||
//
|
||||
|
||||
#ifndef MOBILEGL_TESTDRAWING_H
|
||||
#define MOBILEGL_TESTDRAWING_H
|
||||
|
||||
#include "../../../Includes.h"
|
||||
|
||||
namespace MG_RHI::GLES::Test {
|
||||
void DrawAllTextures();
|
||||
}
|
||||
|
||||
#endif //MOBILEGL_TESTDRAWING_H
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,31 +0,0 @@
|
||||
//
|
||||
// Created by BZLZHH on 2025/1/26.
|
||||
//
|
||||
|
||||
#ifndef MOBILEGL_DEBUG_H
|
||||
#define MOBILEGL_DEBUG_H
|
||||
|
||||
#include "../../Includes.h"
|
||||
|
||||
#define FORCE_SYNC_WITH_LOG_FILE 0
|
||||
|
||||
namespace MG_Util {
|
||||
namespace Debug {
|
||||
const char* GetOSName();
|
||||
|
||||
void LogD (const char* format, ...);
|
||||
void LogW (const char* format, ...);
|
||||
void LogE (const char* format, ...);
|
||||
void LogI (const char* format, ...);
|
||||
void LogF (const char* format, ...);
|
||||
void LogClear();
|
||||
void LogInit();
|
||||
void LogWrite(const char* format, va_list args);
|
||||
|
||||
const char* GLEnumToString(::GLenum value);
|
||||
}
|
||||
}
|
||||
|
||||
#define MOBILEGL_DEBUG_H
|
||||
|
||||
#endif //MOBILEGL_DEBUG_H
|
||||
@@ -1,150 +0,0 @@
|
||||
//
|
||||
// Created by BZLZHH on 2025/5/3.
|
||||
//
|
||||
|
||||
#include "DebugTool.h"
|
||||
|
||||
namespace MG_Util::Program {
|
||||
std::string GLTypeToString(GLenum type) {
|
||||
switch(type) {
|
||||
case GL_FLOAT: return "float";
|
||||
case GL_FLOAT_VEC2: return "vec2";
|
||||
case GL_FLOAT_VEC3: return "vec3";
|
||||
case GL_FLOAT_VEC4: return "vec4";
|
||||
case GL_INT: return "int";
|
||||
case GL_INT_VEC2: return "ivec2";
|
||||
case GL_INT_VEC3: return "ivec3";
|
||||
case GL_INT_VEC4: return "ivec4";
|
||||
case GL_UNSIGNED_INT: return "uint";
|
||||
case GL_UNSIGNED_INT_VEC2: return "uvec2";
|
||||
case GL_UNSIGNED_INT_VEC3: return "uvec3";
|
||||
case GL_UNSIGNED_INT_VEC4: return "uvec4";
|
||||
case GL_BOOL: return "bool";
|
||||
case GL_BOOL_VEC2: return "bvec2";
|
||||
case GL_BOOL_VEC3: return "bvec3";
|
||||
case GL_BOOL_VEC4: return "bvec4";
|
||||
case GL_FLOAT_MAT2: return "mat2";
|
||||
case GL_FLOAT_MAT3: return "mat3";
|
||||
case GL_FLOAT_MAT4: return "mat4";
|
||||
case GL_FLOAT_MAT2x3: return "mat2x3";
|
||||
case GL_FLOAT_MAT2x4: return "mat2x4";
|
||||
case GL_FLOAT_MAT3x2: return "mat3x2";
|
||||
case GL_FLOAT_MAT3x4: return "mat3x4";
|
||||
case GL_FLOAT_MAT4x2: return "mat4x2";
|
||||
case GL_FLOAT_MAT4x3: return "mat4x3";
|
||||
case GL_SAMPLER_1D: return "sampler1D";
|
||||
case GL_SAMPLER_2D: return "sampler2D";
|
||||
case GL_SAMPLER_3D: return "sampler3D";
|
||||
case GL_SAMPLER_CUBE: return "samplerCube";
|
||||
case GL_SAMPLER_1D_SHADOW: return "sampler1DShadow";
|
||||
case GL_SAMPLER_2D_SHADOW: return "sampler2DShadow";
|
||||
case GL_SAMPLER_CUBE_SHADOW: return "samplerCubeShadow";
|
||||
case GL_SAMPLER_1D_ARRAY: return "sampler1DArray";
|
||||
case GL_SAMPLER_2D_ARRAY: return "sampler2DArray";
|
||||
case GL_SAMPLER_1D_ARRAY_SHADOW: return "sampler1DArrayShadow";
|
||||
case GL_SAMPLER_2D_ARRAY_SHADOW: return "sampler2DArrayShadow";
|
||||
case GL_SAMPLER_BUFFER: return "samplerBuffer";
|
||||
case GL_SAMPLER_2D_MULTISAMPLE: return "sampler2DMS";
|
||||
case GL_SAMPLER_2D_MULTISAMPLE_ARRAY: return "sampler2DMSArray";
|
||||
default: return "UnknownType(0x" + std::to_string(type) + ")";
|
||||
}
|
||||
}
|
||||
|
||||
std::string FormatUniformValue(const UniformValue& value) {
|
||||
std::ostringstream ss;
|
||||
ss << "[";
|
||||
|
||||
const size_t elemCount = std::min<size_t>(value.count, 16);
|
||||
|
||||
switch(value.type) {
|
||||
case GL_FLOAT:
|
||||
case GL_FLOAT_VEC2:
|
||||
case GL_FLOAT_VEC3:
|
||||
case GL_FLOAT_VEC4:
|
||||
case GL_FLOAT_MAT2:
|
||||
case GL_FLOAT_MAT3:
|
||||
case GL_FLOAT_MAT4:
|
||||
case GL_FLOAT_MAT2x3:
|
||||
case GL_FLOAT_MAT2x4:
|
||||
case GL_FLOAT_MAT3x2:
|
||||
case GL_FLOAT_MAT3x4:
|
||||
case GL_FLOAT_MAT4x2:
|
||||
case GL_FLOAT_MAT4x3:
|
||||
for(size_t i=0; i<elemCount; ++i) {
|
||||
if (i > 0) ss << ", ";
|
||||
ss << (i < value.floatData.size() ? value.floatData[i] : 0.0f);
|
||||
}
|
||||
break;
|
||||
|
||||
case GL_INT:
|
||||
case GL_INT_VEC2:
|
||||
case GL_INT_VEC3:
|
||||
case GL_INT_VEC4:
|
||||
for(size_t i=0; i<elemCount; ++i) {
|
||||
if (i > 0) ss << ", ";
|
||||
ss << (i < value.intData.size() ? value.intData[i] : 0);
|
||||
}
|
||||
break;
|
||||
|
||||
case GL_UNSIGNED_INT:
|
||||
case GL_UNSIGNED_INT_VEC2:
|
||||
case GL_UNSIGNED_INT_VEC3:
|
||||
case GL_UNSIGNED_INT_VEC4:
|
||||
for(size_t i=0; i<elemCount; ++i) {
|
||||
if (i > 0) ss << ", ";
|
||||
ss << (i < value.uintData.size() ? value.uintData[i] : 0);
|
||||
}
|
||||
break;
|
||||
|
||||
case GL_BOOL:
|
||||
case GL_BOOL_VEC2:
|
||||
case GL_BOOL_VEC3:
|
||||
case GL_BOOL_VEC4:
|
||||
for(size_t i=0; i<elemCount; ++i) {
|
||||
if (i > 0) ss << ", ";
|
||||
ss << (i < value.boolData.size() ? (value.boolData[i] ? "true" : "false") : "false");
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
ss << "N/A";
|
||||
}
|
||||
|
||||
if (value.count > elemCount) ss << ", ...";
|
||||
ss << "]";
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
void DumpUniforms(const ProgramState& state, GLuint program) {
|
||||
if (MG_Global::Common::LogLevel > MG_Constants::Common::LOG_LEVEL_DEBUG)
|
||||
return;
|
||||
|
||||
auto prog = (ProgramObject)state.GetProgramObject(program);
|
||||
if (!prog.linked.toBool()) {
|
||||
MG_Util::Debug::LogE("Program %u not linked", program);
|
||||
return;
|
||||
}
|
||||
MG_Util::Debug::LogD("=== Dumping uniforms for program %u ===", program);
|
||||
for(const auto& [name, loc] : prog.uniformLocations) {
|
||||
const auto& value = prog.uniformValues.at(name);
|
||||
MG_Util::Debug::LogD("Uniform: %-24s Location: %-4d Type: %-16s Count: %-3d Value: %s",
|
||||
name.c_str(),
|
||||
loc,
|
||||
GLTypeToString(value.type).c_str(),
|
||||
value.count,
|
||||
FormatUniformValue(value).c_str());
|
||||
}
|
||||
}
|
||||
|
||||
void DumpCurrentUniforms(const ProgramState& state) {
|
||||
if (MG_Global::Common::LogLevel > MG_Constants::Common::LOG_LEVEL_DEBUG)
|
||||
return;
|
||||
|
||||
GLuint current = state.GetCurrentProgram();
|
||||
if (current == 0) {
|
||||
MG_Util::Debug::LogE("No active program");
|
||||
return;
|
||||
}
|
||||
DumpUniforms(state, current);
|
||||
}
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
//
|
||||
// Created by BZLZHH on 2025/5/3.
|
||||
//
|
||||
|
||||
#ifndef MOBILEGL_PROGRAM_DEBUGTOOL_H
|
||||
#define MOBILEGL_PROGRAM_DEBUGTOOL_H
|
||||
#include "../../Includes.h"
|
||||
|
||||
namespace MG_Util::Program {
|
||||
std::string GLTypeToString(GLenum type);
|
||||
std::string FormatUniformValue(const UniformValue& value);
|
||||
void DumpUniforms(const ProgramState& state, GLuint program);
|
||||
void DumpCurrentUniforms(const ProgramState& state);
|
||||
}
|
||||
|
||||
#endif //MOBILEGL_PROGRAM_DEBUGTOOL_H
|
||||
@@ -1,438 +0,0 @@
|
||||
//
|
||||
// Created by BZLZHH on 2025/5/3.
|
||||
//
|
||||
|
||||
#include "GLSLTool.h"
|
||||
|
||||
namespace MG_Util::Program {
|
||||
std::string CompileGLSLToTShader(GLenum shaderType, const std::string& source, glslang::TShader *&shader) {
|
||||
std::string infoLog;
|
||||
using namespace glslang;
|
||||
|
||||
int glslVersion = QueryGLSLVersion(source);
|
||||
EShLanguage language = GetEShLanguageByShaderType(shaderType);
|
||||
if (language == EShLanguage::EShLangCount) {
|
||||
infoLog += "Error: [Preprocess] Unsupported shader type: " +
|
||||
std::to_string(shaderType);
|
||||
TShader tmpShader(EShLanguage::EShLangVertex);
|
||||
return infoLog;
|
||||
}
|
||||
|
||||
shader = new TShader(language);
|
||||
const char *src = source.c_str();
|
||||
shader->setStrings(&src, 1);
|
||||
shader->setEnvInput(EShSourceGlsl, language, EShClientVulkan, glslVersion);
|
||||
shader->setEnvClient(EShClientOpenGL, EShTargetOpenGL_450);
|
||||
shader->setEnvTarget(EShTargetSpv, EShTargetSpv_1_6);
|
||||
shader->setAutoMapLocations(true);
|
||||
shader->setAutoMapBindings(true);
|
||||
|
||||
// Is InitResources() really correct?
|
||||
TBuiltInResource resources = InitResources();
|
||||
|
||||
if (!shader->parse(&resources, glslVersion, true, EShMsgDefault)) {
|
||||
infoLog += "Error: [glslang] Cannot compile the " + GetShaderTypeName(shaderType) + ":\n"
|
||||
+ std::to_string(shader->getInfoLog());
|
||||
return infoLog;
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
std::vector<std::vector<unsigned>> CompileMultipleShadersToSPIRV(const ProgramState& state, ProgramObject& prog, std::string& infoLog) {
|
||||
using namespace glslang;
|
||||
|
||||
std::vector<EShLanguage> usedShaderTypes;
|
||||
TProgram program;
|
||||
for (GLuint shaderId : prog.attachedShaders) {
|
||||
auto shaderObject = state.GetShaderObject(shaderId);
|
||||
EShLanguage shLanguage = GetEShLanguageByShaderType(shaderObject.type);
|
||||
TShader* shader = nullptr;
|
||||
std::string infoLogOfShader = CompileGLSLToTShader(shaderObject.type, shaderObject.source, shader);
|
||||
if (!infoLogOfShader.empty()) {
|
||||
infoLog = "Error: [glslang] Cannot compile " + GetShaderTypeName(shaderObject.type) +
|
||||
" :\n" + infoLogOfShader;
|
||||
return {};
|
||||
}
|
||||
program.addShader(shader);
|
||||
usedShaderTypes.push_back(shLanguage);
|
||||
}
|
||||
if (!program.link(EShMsgDefault)) {
|
||||
infoLog = "Error: [glslang] Cannot link the program:\n" + std::to_string(program.getInfoLog());
|
||||
return {};
|
||||
}
|
||||
|
||||
SpvOptions spvOptions;
|
||||
spvOptions.disableOptimizer = false;
|
||||
|
||||
std::vector<std::vector<unsigned>> allSpirv;
|
||||
for(auto type : usedShaderTypes) {
|
||||
std::vector<unsigned> spirv;
|
||||
GlslangToSpv(*program.getIntermediate(type), spirv, &spvOptions);
|
||||
allSpirv.push_back(spirv);
|
||||
}
|
||||
|
||||
return allSpirv;
|
||||
}
|
||||
|
||||
std::vector<unsigned> CompileGLSLToSPIRV(GLenum shaderType, const std::string &source, std::string &infoLog) {
|
||||
using namespace glslang;
|
||||
|
||||
TShader* shader = nullptr;
|
||||
std::string infoLogOfShader = CompileGLSLToTShader(shaderType, source, shader);
|
||||
if (!infoLogOfShader.empty()) {
|
||||
infoLog = "Error: [glslang] Cannot compile " + GetShaderTypeName(shaderType) + ":\n" + infoLogOfShader;
|
||||
return {};
|
||||
}
|
||||
TProgram program;
|
||||
program.addShader(shader);
|
||||
if (!program.link(EShMsgDefault)) {
|
||||
infoLog = "Error: [glslang] Cannot link the program of the single shader:\n" + std::to_string(program.getInfoLog());
|
||||
return {};
|
||||
}
|
||||
std::vector<unsigned> spirv;
|
||||
|
||||
SpvOptions spvOptions;
|
||||
spvOptions.disableOptimizer = false;
|
||||
EShLanguage language = GetEShLanguageByShaderType(shaderType);
|
||||
GlslangToSpv(*program.getIntermediate(language), spirv, &spvOptions);
|
||||
|
||||
return spirv;
|
||||
}
|
||||
|
||||
void ReflectSPIRVUniforms(const std::vector<std::vector<unsigned>>& allSpirv, ProgramObject& prog, std::string& infoLog) {
|
||||
spvc_context context = nullptr;
|
||||
|
||||
if (spvc_context_create(&context) != SPVC_SUCCESS) {
|
||||
infoLog = "Failed to create SPIRV-Cross context";
|
||||
return;
|
||||
}
|
||||
|
||||
ankerl::unordered_set<GLint> used_locations;
|
||||
GLint auto_location = 0;
|
||||
for (auto spirv: allSpirv) {
|
||||
spvc_parsed_ir ir = nullptr;
|
||||
spvc_compiler compiler = nullptr;
|
||||
spvc_resources resources = nullptr;
|
||||
|
||||
spvc_result result = spvc_context_parse_spirv(context, spirv.data(), spirv.size(), &ir);
|
||||
if (result != SPVC_SUCCESS) {
|
||||
infoLog = "SPIR-V parsing failed";
|
||||
spvc_context_destroy(context);
|
||||
return;
|
||||
}
|
||||
|
||||
result = spvc_context_create_compiler(context, SPVC_BACKEND_GLSL, ir,
|
||||
SPVC_CAPTURE_MODE_TAKE_OWNERSHIP, &compiler);
|
||||
if (result != SPVC_SUCCESS) {
|
||||
infoLog = "Failed to create SPIRV-Cross compiler";
|
||||
spvc_context_destroy(context);
|
||||
return;
|
||||
}
|
||||
|
||||
result = spvc_compiler_create_shader_resources(compiler, &resources);
|
||||
if (result != SPVC_SUCCESS) {
|
||||
infoLog = "Failed to get shader resources";
|
||||
spvc_context_destroy(context);
|
||||
return;
|
||||
}
|
||||
|
||||
const spvc_reflected_resource *uniform_buffers = nullptr;
|
||||
const spvc_reflected_resource *uniform_vars = nullptr;
|
||||
const spvc_reflected_resource *sampled_images = nullptr;
|
||||
size_t uniform_buffer_count = 0;
|
||||
size_t uniform_var_count = 0;
|
||||
size_t sampled_image_count = 0;
|
||||
|
||||
spvc_resources_get_resource_list_for_type(resources, SPVC_RESOURCE_TYPE_UNIFORM_BUFFER,
|
||||
&uniform_buffers, &uniform_buffer_count);
|
||||
spvc_resources_get_resource_list_for_type(resources,
|
||||
SPVC_RESOURCE_TYPE_GL_PLAIN_UNIFORM,
|
||||
&uniform_vars, &uniform_var_count);
|
||||
spvc_resources_get_resource_list_for_type(resources, SPVC_RESOURCE_TYPE_SAMPLED_IMAGE,
|
||||
&sampled_images, &sampled_image_count);
|
||||
|
||||
std::vector<const spvc_reflected_resource *> all_resources;
|
||||
for (size_t i = 0; i < uniform_buffer_count; ++i)
|
||||
all_resources.push_back(&uniform_buffers[i]);
|
||||
for (size_t i = 0; i < uniform_var_count; ++i)
|
||||
all_resources.push_back(&uniform_vars[i]);
|
||||
for (size_t i = 0; i < sampled_image_count; ++i)
|
||||
all_resources.push_back(&sampled_images[i]);
|
||||
|
||||
for (const auto res_ptr: all_resources) {
|
||||
const spvc_reflected_resource &res = *res_ptr;
|
||||
const char *name = res.name;
|
||||
if (name[0] == '_') continue;
|
||||
|
||||
unsigned spirv_location = spvc_compiler_get_decoration(compiler, res.id,
|
||||
SpvDecorationLocation);
|
||||
GLint final_location;
|
||||
|
||||
if (spirv_location > 0) {
|
||||
if (used_locations.find(spirv_location) != used_locations.end()) {
|
||||
infoLog += "\nLocation conflict for uniform: " + std::string(name);
|
||||
continue;
|
||||
}
|
||||
final_location = spirv_location;
|
||||
} else {
|
||||
while (used_locations.find(auto_location) != used_locations.end()) {
|
||||
auto_location++;
|
||||
}
|
||||
final_location = auto_location;
|
||||
}
|
||||
|
||||
used_locations.insert(final_location);
|
||||
|
||||
spvc_type_id type_id = res.type_id;
|
||||
spvc_type type = spvc_compiler_get_type_handle(compiler, type_id);
|
||||
spvc_basetype base_type = spvc_type_get_basetype(type);
|
||||
GLenum gl_type = GL_NONE;
|
||||
|
||||
if (base_type == SPVC_BASETYPE_SAMPLED_IMAGE) {
|
||||
SpvDim dim = spvc_type_get_image_dimension(type);
|
||||
bool is_array = spvc_type_get_image_arrayed(type);
|
||||
bool is_shadow = spvc_type_get_image_is_depth(type);
|
||||
bool is_ms = spvc_type_get_image_multisampled(type);
|
||||
|
||||
switch (dim) {
|
||||
case SpvDim1D:
|
||||
gl_type = is_array ? GL_SAMPLER_1D_ARRAY : GL_SAMPLER_1D;
|
||||
if (is_shadow)
|
||||
gl_type = is_array ? GL_SAMPLER_1D_ARRAY_SHADOW
|
||||
: GL_SAMPLER_1D_SHADOW;
|
||||
break;
|
||||
case SpvDim2D:
|
||||
if (is_ms) {
|
||||
gl_type = is_array ? GL_SAMPLER_2D_MULTISAMPLE_ARRAY
|
||||
: GL_SAMPLER_2D_MULTISAMPLE;
|
||||
} else {
|
||||
gl_type = is_array ? GL_SAMPLER_2D_ARRAY : GL_SAMPLER_2D;
|
||||
if (is_shadow)
|
||||
gl_type = is_array ? GL_SAMPLER_2D_ARRAY_SHADOW
|
||||
: GL_SAMPLER_2D_SHADOW;
|
||||
}
|
||||
break;
|
||||
case SpvDim3D:
|
||||
gl_type = GL_SAMPLER_3D;
|
||||
break;
|
||||
case SpvDimCube:
|
||||
gl_type = is_array ? GL_SAMPLER_CUBE_MAP_ARRAY : GL_SAMPLER_CUBE;
|
||||
if (is_shadow)
|
||||
gl_type = is_array ? GL_SAMPLER_CUBE_MAP_ARRAY_SHADOW
|
||||
: GL_SAMPLER_CUBE_SHADOW;
|
||||
break;
|
||||
case SpvDimRect:
|
||||
gl_type = is_shadow ? GL_SAMPLER_2D_RECT_SHADOW : GL_SAMPLER_2D_RECT;
|
||||
break;
|
||||
case SpvDimBuffer:
|
||||
gl_type = GL_SAMPLER_BUFFER;
|
||||
break;
|
||||
default:
|
||||
gl_type = GL_SAMPLER_2D;
|
||||
}
|
||||
|
||||
spvc_basetype sampled_base = spvc_type_get_basetype(type);
|
||||
if (sampled_base == SPVC_BASETYPE_INT32) {
|
||||
switch (gl_type) {
|
||||
case GL_SAMPLER_1D:
|
||||
gl_type = GL_INT_SAMPLER_1D;
|
||||
break;
|
||||
case GL_SAMPLER_2D:
|
||||
gl_type = GL_INT_SAMPLER_2D;
|
||||
break;
|
||||
case GL_SAMPLER_3D:
|
||||
gl_type = GL_INT_SAMPLER_3D;
|
||||
break;
|
||||
case GL_SAMPLER_CUBE:
|
||||
gl_type = GL_INT_SAMPLER_CUBE;
|
||||
break;
|
||||
case GL_SAMPLER_1D_ARRAY:
|
||||
gl_type = GL_INT_SAMPLER_1D_ARRAY;
|
||||
break;
|
||||
case GL_SAMPLER_2D_ARRAY:
|
||||
gl_type = GL_INT_SAMPLER_2D_ARRAY;
|
||||
break;
|
||||
case GL_SAMPLER_CUBE_MAP_ARRAY:
|
||||
gl_type = GL_INT_SAMPLER_CUBE_MAP_ARRAY;
|
||||
break;
|
||||
case GL_SAMPLER_2D_RECT:
|
||||
gl_type = GL_INT_SAMPLER_2D_RECT;
|
||||
break;
|
||||
case GL_SAMPLER_BUFFER:
|
||||
gl_type = GL_INT_SAMPLER_BUFFER;
|
||||
break;
|
||||
case GL_SAMPLER_2D_MULTISAMPLE:
|
||||
gl_type = GL_INT_SAMPLER_2D_MULTISAMPLE;
|
||||
break;
|
||||
case GL_SAMPLER_2D_MULTISAMPLE_ARRAY:
|
||||
gl_type = GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY;
|
||||
break;
|
||||
}
|
||||
} else if (sampled_base == SPVC_BASETYPE_UINT32) {
|
||||
switch (gl_type) {
|
||||
case GL_SAMPLER_1D:
|
||||
gl_type = GL_UNSIGNED_INT_SAMPLER_1D;
|
||||
break;
|
||||
case GL_SAMPLER_2D:
|
||||
gl_type = GL_UNSIGNED_INT_SAMPLER_2D;
|
||||
break;
|
||||
case GL_SAMPLER_3D:
|
||||
gl_type = GL_UNSIGNED_INT_SAMPLER_3D;
|
||||
break;
|
||||
case GL_SAMPLER_CUBE:
|
||||
gl_type = GL_UNSIGNED_INT_SAMPLER_CUBE;
|
||||
break;
|
||||
case GL_SAMPLER_1D_ARRAY:
|
||||
gl_type = GL_UNSIGNED_INT_SAMPLER_1D_ARRAY;
|
||||
break;
|
||||
case GL_SAMPLER_2D_ARRAY:
|
||||
gl_type = GL_UNSIGNED_INT_SAMPLER_2D_ARRAY;
|
||||
break;
|
||||
case GL_SAMPLER_CUBE_MAP_ARRAY:
|
||||
gl_type = GL_UNSIGNED_INT_SAMPLER_CUBE_MAP_ARRAY;
|
||||
break;
|
||||
case GL_SAMPLER_2D_RECT:
|
||||
gl_type = GL_UNSIGNED_INT_SAMPLER_2D_RECT;
|
||||
break;
|
||||
case GL_SAMPLER_BUFFER:
|
||||
gl_type = GL_UNSIGNED_INT_SAMPLER_BUFFER;
|
||||
break;
|
||||
case GL_SAMPLER_2D_MULTISAMPLE:
|
||||
gl_type = GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE;
|
||||
break;
|
||||
case GL_SAMPLER_2D_MULTISAMPLE_ARRAY:
|
||||
gl_type = GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
unsigned vec_size = spvc_type_get_vector_size(type);
|
||||
unsigned columns = spvc_type_get_columns(type);
|
||||
|
||||
switch (base_type) {
|
||||
case SPVC_BASETYPE_FP32:
|
||||
if (columns > 1) {
|
||||
if (vec_size == 2 && columns == 2) gl_type = GL_FLOAT_MAT2;
|
||||
else if (vec_size == 3 && columns == 3) gl_type = GL_FLOAT_MAT3;
|
||||
else if (vec_size == 4 && columns == 4) gl_type = GL_FLOAT_MAT4;
|
||||
else if (vec_size == 3 && columns == 2) gl_type = GL_FLOAT_MAT2x3;
|
||||
else if (vec_size == 4 && columns == 2) gl_type = GL_FLOAT_MAT2x4;
|
||||
else if (vec_size == 2 && columns == 3) gl_type = GL_FLOAT_MAT3x2;
|
||||
else if (vec_size == 4 && columns == 3) gl_type = GL_FLOAT_MAT3x4;
|
||||
else if (vec_size == 2 && columns == 4) gl_type = GL_FLOAT_MAT4x2;
|
||||
else if (vec_size == 3 && columns == 4) gl_type = GL_FLOAT_MAT4x3;
|
||||
} else {
|
||||
switch (vec_size) {
|
||||
case 1:
|
||||
gl_type = GL_FLOAT;
|
||||
break;
|
||||
case 2:
|
||||
gl_type = GL_FLOAT_VEC2;
|
||||
break;
|
||||
case 3:
|
||||
gl_type = GL_FLOAT_VEC3;
|
||||
break;
|
||||
case 4:
|
||||
gl_type = GL_FLOAT_VEC4;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case SPVC_BASETYPE_INT32:
|
||||
switch (vec_size) {
|
||||
case 1:
|
||||
gl_type = GL_INT;
|
||||
break;
|
||||
case 2:
|
||||
gl_type = GL_INT_VEC2;
|
||||
break;
|
||||
case 3:
|
||||
gl_type = GL_INT_VEC3;
|
||||
break;
|
||||
case 4:
|
||||
gl_type = GL_INT_VEC4;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case SPVC_BASETYPE_UINT32:
|
||||
switch (vec_size) {
|
||||
case 1:
|
||||
gl_type = GL_UNSIGNED_INT;
|
||||
break;
|
||||
case 2:
|
||||
gl_type = GL_UNSIGNED_INT_VEC2;
|
||||
break;
|
||||
case 3:
|
||||
gl_type = GL_UNSIGNED_INT_VEC3;
|
||||
break;
|
||||
case 4:
|
||||
gl_type = GL_UNSIGNED_INT_VEC4;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case SPVC_BASETYPE_BOOLEAN:
|
||||
switch (vec_size) {
|
||||
case 1:
|
||||
gl_type = GL_BOOL;
|
||||
break;
|
||||
case 2:
|
||||
gl_type = GL_BOOL_VEC2;
|
||||
break;
|
||||
case 3:
|
||||
gl_type = GL_BOOL_VEC3;
|
||||
break;
|
||||
case 4:
|
||||
gl_type = GL_BOOL_VEC4;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
prog.uniformLocations[name] = final_location;
|
||||
UniformValue uniformValue;
|
||||
uniformValue.type = gl_type;
|
||||
prog.uniformValues[name] = uniformValue;
|
||||
}
|
||||
}
|
||||
spvc_context_destroy(context);
|
||||
}
|
||||
|
||||
std::string CompileSPIRVToGLSL(std::vector<unsigned int> spirv, uint glslVersion, bool isES) {
|
||||
spvc_context context = nullptr;
|
||||
spvc_parsed_ir ir = nullptr;
|
||||
spvc_compiler compiler_glsl = nullptr;
|
||||
spvc_compiler_options options = nullptr;
|
||||
spvc_resources resources = nullptr;
|
||||
const spvc_reflected_resource *list = nullptr;
|
||||
const char *result = nullptr;
|
||||
size_t count;
|
||||
|
||||
const SpvId *p_spirv = spirv.data();
|
||||
size_t word_count = spirv.size();
|
||||
|
||||
spvc_context_create(&context);
|
||||
spvc_context_parse_spirv(context, p_spirv, word_count, &ir);
|
||||
spvc_context_create_compiler(context, SPVC_BACKEND_GLSL, ir, SPVC_CAPTURE_MODE_TAKE_OWNERSHIP, &compiler_glsl);
|
||||
spvc_compiler_create_shader_resources(compiler_glsl, &resources);
|
||||
spvc_resources_get_resource_list_for_type(resources, SPVC_RESOURCE_TYPE_UNIFORM_BUFFER, &list, &count);
|
||||
spvc_compiler_create_compiler_options(compiler_glsl, &options);
|
||||
spvc_compiler_options_set_uint(options, SPVC_COMPILER_OPTION_GLSL_VERSION, glslVersion);
|
||||
spvc_compiler_options_set_bool(options, SPVC_COMPILER_OPTION_GLSL_ES, isES ? SPVC_TRUE : SPVC_FALSE);
|
||||
spvc_compiler_install_compiler_options(compiler_glsl, options);
|
||||
spvc_compiler_compile(compiler_glsl, &result);
|
||||
|
||||
if (!result) {
|
||||
return{};
|
||||
}
|
||||
|
||||
std::string essl = result;
|
||||
|
||||
spvc_context_destroy(context);
|
||||
|
||||
return essl;
|
||||
}
|
||||
}
|
||||
@@ -1,183 +0,0 @@
|
||||
//
|
||||
// Created by BZLZHH on 2025/5/3.
|
||||
//
|
||||
|
||||
#ifndef MOBILEGL_GLSLTOOL_H
|
||||
#define MOBILEGL_GLSLTOOL_H
|
||||
|
||||
#include "../../Includes.h"
|
||||
|
||||
namespace MG_Util::Program {
|
||||
inline static TBuiltInResource InitResources()
|
||||
{
|
||||
TBuiltInResource Resources{};
|
||||
Resources.maxLights = 32;
|
||||
Resources.maxClipPlanes = 6;
|
||||
Resources.maxTextureUnits = 32;
|
||||
Resources.maxTextureCoords = 32;
|
||||
Resources.maxVertexAttribs = 64;
|
||||
Resources.maxVertexUniformComponents = 4096;
|
||||
Resources.maxVaryingFloats = 64;
|
||||
Resources.maxVertexTextureImageUnits = 32;
|
||||
Resources.maxCombinedTextureImageUnits = 80;
|
||||
Resources.maxTextureImageUnits = 32;
|
||||
Resources.maxFragmentUniformComponents = 4096;
|
||||
Resources.maxDrawBuffers = 32;
|
||||
Resources.maxVertexUniformVectors = 128;
|
||||
Resources.maxVaryingVectors = 8;
|
||||
Resources.maxFragmentUniformVectors = 16;
|
||||
Resources.maxVertexOutputVectors = 16;
|
||||
Resources.maxFragmentInputVectors = 15;
|
||||
Resources.minProgramTexelOffset = -8;
|
||||
Resources.maxProgramTexelOffset = 7;
|
||||
Resources.maxClipDistances = 8;
|
||||
Resources.maxComputeWorkGroupCountX = 65535;
|
||||
Resources.maxComputeWorkGroupCountY = 65535;
|
||||
Resources.maxComputeWorkGroupCountZ = 65535;
|
||||
Resources.maxComputeWorkGroupSizeX = 1024;
|
||||
Resources.maxComputeWorkGroupSizeY = 1024;
|
||||
Resources.maxComputeWorkGroupSizeZ = 64;
|
||||
Resources.maxComputeUniformComponents = 1024;
|
||||
Resources.maxComputeTextureImageUnits = 16;
|
||||
Resources.maxComputeImageUniforms = 8;
|
||||
Resources.maxComputeAtomicCounters = 8;
|
||||
Resources.maxComputeAtomicCounterBuffers = 1;
|
||||
Resources.maxVaryingComponents = 60;
|
||||
Resources.maxVertexOutputComponents = 64;
|
||||
Resources.maxGeometryInputComponents = 64;
|
||||
Resources.maxGeometryOutputComponents = 128;
|
||||
Resources.maxFragmentInputComponents = 128;
|
||||
Resources.maxImageUnits = 8;
|
||||
Resources.maxCombinedImageUnitsAndFragmentOutputs = 8;
|
||||
Resources.maxCombinedShaderOutputResources = 8;
|
||||
Resources.maxImageSamples = 0;
|
||||
Resources.maxVertexImageUniforms = 0;
|
||||
Resources.maxTessControlImageUniforms = 0;
|
||||
Resources.maxTessEvaluationImageUniforms = 0;
|
||||
Resources.maxGeometryImageUniforms = 0;
|
||||
Resources.maxFragmentImageUniforms = 8;
|
||||
Resources.maxCombinedImageUniforms = 8;
|
||||
Resources.maxGeometryTextureImageUnits = 16;
|
||||
Resources.maxGeometryOutputVertices = 256;
|
||||
Resources.maxGeometryTotalOutputComponents = 1024;
|
||||
Resources.maxGeometryUniformComponents = 1024;
|
||||
Resources.maxGeometryVaryingComponents = 64;
|
||||
Resources.maxTessControlInputComponents = 128;
|
||||
Resources.maxTessControlOutputComponents = 128;
|
||||
Resources.maxTessControlTextureImageUnits = 16;
|
||||
Resources.maxTessControlUniformComponents = 1024;
|
||||
Resources.maxTessControlTotalOutputComponents = 4096;
|
||||
Resources.maxTessEvaluationInputComponents = 128;
|
||||
Resources.maxTessEvaluationOutputComponents = 128;
|
||||
Resources.maxTessEvaluationTextureImageUnits = 16;
|
||||
Resources.maxTessEvaluationUniformComponents = 1024;
|
||||
Resources.maxTessPatchComponents = 120;
|
||||
Resources.maxPatchVertices = 32;
|
||||
Resources.maxTessGenLevel = 64;
|
||||
Resources.maxViewports = 16;
|
||||
Resources.maxVertexAtomicCounters = 0;
|
||||
Resources.maxTessControlAtomicCounters = 0;
|
||||
Resources.maxTessEvaluationAtomicCounters = 0;
|
||||
Resources.maxGeometryAtomicCounters = 0;
|
||||
Resources.maxFragmentAtomicCounters = 8;
|
||||
Resources.maxCombinedAtomicCounters = 8;
|
||||
Resources.maxAtomicCounterBindings = 1;
|
||||
Resources.maxVertexAtomicCounterBuffers = 0;
|
||||
Resources.maxTessControlAtomicCounterBuffers = 0;
|
||||
Resources.maxTessEvaluationAtomicCounterBuffers = 0;
|
||||
Resources.maxGeometryAtomicCounterBuffers = 0;
|
||||
Resources.maxFragmentAtomicCounterBuffers = 1;
|
||||
Resources.maxCombinedAtomicCounterBuffers = 1;
|
||||
Resources.maxAtomicCounterBufferSize = 16384;
|
||||
Resources.maxTransformFeedbackBuffers = 4;
|
||||
Resources.maxTransformFeedbackInterleavedComponents = 64;
|
||||
Resources.maxCullDistances = 8;
|
||||
Resources.maxCombinedClipAndCullDistances = 8;
|
||||
Resources.maxSamples = 4;
|
||||
Resources.maxMeshOutputVerticesNV = 256;
|
||||
Resources.maxMeshOutputPrimitivesNV = 512;
|
||||
Resources.maxMeshWorkGroupSizeX_NV = 32;
|
||||
Resources.maxMeshWorkGroupSizeY_NV = 1;
|
||||
Resources.maxMeshWorkGroupSizeZ_NV = 1;
|
||||
Resources.maxTaskWorkGroupSizeX_NV = 32;
|
||||
Resources.maxTaskWorkGroupSizeY_NV = 1;
|
||||
Resources.maxTaskWorkGroupSizeZ_NV = 1;
|
||||
Resources.maxMeshViewCountNV = 4;
|
||||
|
||||
Resources.limits.nonInductiveForLoops = true;
|
||||
Resources.limits.whileLoops = true;
|
||||
Resources.limits.doWhileLoops = true;
|
||||
Resources.limits.generalUniformIndexing = true;
|
||||
Resources.limits.generalAttributeMatrixVectorIndexing = true;
|
||||
Resources.limits.generalVaryingIndexing = true;
|
||||
Resources.limits.generalSamplerIndexing = true;
|
||||
Resources.limits.generalVariableIndexing = true;
|
||||
Resources.limits.generalConstantMatrixVectorIndexing = true;
|
||||
|
||||
return Resources;
|
||||
}
|
||||
|
||||
inline int QueryGLSLVersion(const std::string& code) {
|
||||
static std::regex version_pattern(R"(#version\s+(\d{3}))");
|
||||
std::smatch match;
|
||||
if (std::regex_search(code, match, version_pattern)) {
|
||||
return std::stoi(match[1].str());
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
inline GLsizei GetMatrixElementCount(GLenum matrixType) {
|
||||
switch(matrixType) {
|
||||
case GL_FLOAT_MAT2: return 4;
|
||||
case GL_FLOAT_MAT3: return 9;
|
||||
case GL_FLOAT_MAT4: return 16;
|
||||
case GL_FLOAT_MAT2x3: return 6;
|
||||
case GL_FLOAT_MAT2x4: return 8;
|
||||
case GL_FLOAT_MAT3x2: return 6;
|
||||
case GL_FLOAT_MAT3x4: return 12;
|
||||
case GL_FLOAT_MAT4x2: return 8;
|
||||
case GL_FLOAT_MAT4x3: return 12;
|
||||
default: return 0;
|
||||
}
|
||||
}
|
||||
|
||||
inline std::string GetShaderTypeName(GLenum shaderType) {
|
||||
switch(shaderType) {
|
||||
case GL_VERTEX_SHADER: return "Vertex Shader";
|
||||
case GL_FRAGMENT_SHADER: return "Fragment Shader";
|
||||
case GL_GEOMETRY_SHADER: return "Geometry Shader";
|
||||
case GL_TESS_CONTROL_SHADER: return "Tessellation Control Shader";
|
||||
case GL_TESS_EVALUATION_SHADER: return "Tessellation Evaluation Shader";
|
||||
case GL_COMPUTE_SHADER: return "Compute Shader";
|
||||
default: return "Unknown Shader Type (" + std::to_string(shaderType) + ")";
|
||||
}
|
||||
}
|
||||
|
||||
inline EShLanguage GetEShLanguageByShaderType(GLenum shaderType) {
|
||||
switch (shaderType) {
|
||||
case GL_VERTEX_SHADER:
|
||||
return EShLanguage::EShLangVertex;
|
||||
case GL_FRAGMENT_SHADER:
|
||||
return EShLanguage::EShLangFragment;
|
||||
case GL_COMPUTE_SHADER:
|
||||
return EShLanguage::EShLangCompute;
|
||||
case GL_TESS_CONTROL_SHADER:
|
||||
return EShLanguage::EShLangTessControl;
|
||||
case GL_TESS_EVALUATION_SHADER:
|
||||
return EShLanguage::EShLangTessEvaluation;
|
||||
case GL_GEOMETRY_SHADER:
|
||||
return EShLanguage::EShLangGeometry;
|
||||
default:
|
||||
return EShLanguage::EShLangCount;
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<unsigned> CompileGLSLToSPIRV(GLenum shaderType, const std::string& source, std::string& infoLog);
|
||||
std::string CompileGLSLToTShader(GLenum shaderType, const std::string& source, glslang::TShader *&shader);
|
||||
std::vector<std::vector<unsigned>> CompileMultipleShadersToSPIRV(const ProgramState& state, ProgramObject& prog, std::string& infoLog);
|
||||
void ReflectSPIRVUniforms(const std::vector<std::vector<unsigned>>& allSpirv, ProgramObject& prog, std::string& infoLog);
|
||||
std::string CompileSPIRVToGLSL(std::vector<unsigned int> spirv, uint glslVersion, bool isES);
|
||||
}
|
||||
|
||||
#endif //MOBILEGL_GLSLTOOL_H
|
||||
@@ -0,0 +1,22 @@
|
||||
// MobileGL - MobileGL/Config.h
|
||||
// Copyright (c) 2025-2026 MobileGL-Dev
|
||||
// Licensed under the GNU Lesser General Public License v3.0:
|
||||
// https://www.gnu.org/licenses/gpl-3.0.txt
|
||||
// https://www.gnu.org/licenses/lgpl-3.0.txt
|
||||
// SPDX-License-Identifier: LGPL-3.0-only
|
||||
// End of Source File Header
|
||||
|
||||
#pragma once
|
||||
#include <Includes.h>
|
||||
#include <MG_Backend/BackendObjects.h>
|
||||
|
||||
namespace MobileGL::MG_Config {
|
||||
inline const String ProjectName = "MobileGL";
|
||||
inline const String CoreName = "MobileGL Core";
|
||||
inline const String CoreVendor = "MobileGL-Dev (BZLZHH, Swung0x48, Tungsten)";
|
||||
inline const Version CoreVersion = {26, 3, 0, "-dev", VersionType::Development};
|
||||
inline const VersionStringFormatAttrib DefaultVersionStringFormatAttrib = {2, 2, 0, true, true};
|
||||
inline const Uint64 CacheVersion = 0;
|
||||
|
||||
extern BackendType ActiveBackendType;
|
||||
} // namespace MobileGL::MG_Config
|
||||
@@ -0,0 +1,84 @@
|
||||
// MobileGL - MobileGL/ConfigLoader.cpp
|
||||
// Copyright (c) 2025-2026 MobileGL-Dev
|
||||
// Licensed under the GNU Lesser General Public License v3.0:
|
||||
// https://www.gnu.org/licenses/gpl-3.0.txt
|
||||
// https://www.gnu.org/licenses/lgpl-3.0.txt
|
||||
// SPDX-License-Identifier: LGPL-3.0-only
|
||||
// End of Source File Header
|
||||
|
||||
#include "Config.h"
|
||||
|
||||
namespace MobileGL::MG_ConfigLoader {
|
||||
static UniquePtr<UnorderedMap<String, String>> acceptedEnvVariablesMap;
|
||||
|
||||
static Bool IsAcceptedPrefix(const String& key) {
|
||||
return (key.compare(0, 6, "LIBGL_") == 0 || key.compare(0, 9, "MOBILEGL_") == 0);
|
||||
}
|
||||
|
||||
inline void InitializeAcceptedEnvVariables() {
|
||||
if (!acceptedEnvVariablesMap) {
|
||||
acceptedEnvVariablesMap = MakeUnique<UnorderedMap<String, String>>();
|
||||
} else {
|
||||
acceptedEnvVariablesMap->clear();
|
||||
}
|
||||
|
||||
char** envPtr = nullptr;
|
||||
|
||||
#ifdef _WIN32
|
||||
envPtr = _environ;
|
||||
#else // POSIX
|
||||
envPtr = ::environ;
|
||||
#endif
|
||||
|
||||
if (envPtr == nullptr) return;
|
||||
|
||||
for (char** env = envPtr; *env != nullptr; ++env) {
|
||||
String entry(*env);
|
||||
SizeT pos = entry.find('=');
|
||||
if (pos != String::npos) {
|
||||
String key = entry.substr(0, pos);
|
||||
String value = entry.substr(pos + 1);
|
||||
|
||||
if (IsAcceptedPrefix(key)) {
|
||||
(*acceptedEnvVariablesMap)[key] = value;
|
||||
MGLOG_D("Config: Accepted env variable: %s=%s", key.c_str(), value.c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline void QueryEnvVariable(const String& key, String& outValue, const String& defaultValue) {
|
||||
auto it = acceptedEnvVariablesMap->find(key);
|
||||
if (it != acceptedEnvVariablesMap->end()) {
|
||||
outValue = it->second;
|
||||
} else {
|
||||
outValue = defaultValue;
|
||||
}
|
||||
}
|
||||
|
||||
inline void InitBackendType() {
|
||||
String backendTypeStr;
|
||||
QueryEnvVariable("MOBILEGL_BACKEND_TYPE", backendTypeStr, "DirectGLES");
|
||||
#define ENTRY(backendType) \
|
||||
if (backendTypeStr == #backendType) { \
|
||||
MG_Config::ActiveBackendType = BackendType::backendType; \
|
||||
MGLOG_I("Config: Active backend type set to " #backendType); \
|
||||
return; \
|
||||
}
|
||||
ENTRY(DirectGLES)
|
||||
ENTRY(DirectVulkan)
|
||||
ENTRY(Unknown)
|
||||
MG_Config::ActiveBackendType = BackendType::Unknown;
|
||||
#undef ENTRY
|
||||
}
|
||||
|
||||
void Init() {
|
||||
MGLOG_D("Loading configuration from environment variables...");
|
||||
InitializeAcceptedEnvVariables();
|
||||
|
||||
InitBackendType();
|
||||
|
||||
// Destroy the map since we won't need it anymore
|
||||
acceptedEnvVariablesMap.reset();
|
||||
}
|
||||
} // namespace MobileGL::MG_ConfigLoader
|
||||
@@ -0,0 +1,73 @@
|
||||
// MobileGL - MobileGL/Defines.h
|
||||
// Copyright (c) 2025-2026 MobileGL-Dev
|
||||
// Licensed under the GNU Lesser General Public License v3.0:
|
||||
// https://www.gnu.org/licenses/gpl-3.0.txt
|
||||
// https://www.gnu.org/licenses/lgpl-3.0.txt
|
||||
// SPDX-License-Identifier: LGPL-3.0-only
|
||||
// End of Source File Header
|
||||
|
||||
#pragma once
|
||||
|
||||
// ============== Platform-specific definitions and macros ============== //
|
||||
#ifdef __ANDROID__
|
||||
#undef __ANDROID_API__
|
||||
#define __ANDROID_API__ 26 // force Android API level to 26 for compatibility
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
#ifndef NOMINMAX
|
||||
#define NOMINMAX 1 // prevent Windows.h from defining min and max macros
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// ================== MobileGL definitions and macros =================== //
|
||||
#ifdef _WIN32
|
||||
#define MOBILEGL_EXPORT extern "C" __declspec(dllexport)
|
||||
#else
|
||||
#define MOBILEGL_EXPORT extern "C" __attribute__((visibility("default")))
|
||||
#endif
|
||||
|
||||
#define MOBILEGL_API MOBILEGL_EXPORT
|
||||
|
||||
#define MOBILEGL_GLX_API MOBILEGL_API
|
||||
#define MOBILEGL_GL_API MOBILEGL_API
|
||||
#define MOBILEGL_EGL_API MOBILEGL_API
|
||||
|
||||
// ====================== MobileGL configurations ======================= //
|
||||
#define MOBILEGL_LOG_ACTIVE_LEVEL MOBILEGL_LOG_LEVEL_DEBUG
|
||||
|
||||
#define MOBILEGL_LOG_ENABLE_CONSOLE 0
|
||||
#define MOBILEGL_LOG_ENABLE_FILE 1
|
||||
#define MOBILEGL_LOG_ENABLE_ANDROID 1
|
||||
#define MOBILEGL_ENABLE_SCOPE_MARKER 0
|
||||
|
||||
// Require C++23
|
||||
// Clang/Android NDK still doesn't have support for that :(
|
||||
#if __cplusplus >= 202302L && !__ANDROID__
|
||||
#define MOBILEGL_LOG_ENABLE_STACKTRACE 0
|
||||
#endif
|
||||
|
||||
#ifdef __ANDROID__
|
||||
#define MOBILEGL_LOG_FILE_PATH "/sdcard/MG/latest.log"
|
||||
#else
|
||||
#define MOBILEGL_LOG_FILE_PATH ""
|
||||
#endif
|
||||
|
||||
#if defined _MSC_VER or defined __MINGW32__ or defined __MINGW64__
|
||||
#define TRAP assert(false)
|
||||
#elif __clang__
|
||||
#define TRAP __builtin_debugtrap()
|
||||
#else
|
||||
#include <signal.h>
|
||||
#define TRAP raise(SIGTRAP)
|
||||
#endif
|
||||
|
||||
// =============================== Utils ================================ //
|
||||
#define MOBILEGL_ASSERT(condition, ...) \
|
||||
do { \
|
||||
if (!(condition)) { \
|
||||
MGLOG_F("Assertion failed" __VA_OPT__(": ") __VA_ARGS__); \
|
||||
MGLOG_F(" at %s:%d (%s)", __FILE__, __LINE__, __func__); \
|
||||
TRAP; \
|
||||
} \
|
||||
} while (0)
|
||||
@@ -0,0 +1,20 @@
|
||||
// MobileGL - MobileGL/GlobalObjects.cpp
|
||||
// Copyright (c) 2025-2026 MobileGL-Dev
|
||||
// Licensed under the GNU Lesser General Public License v3.0:
|
||||
// https://www.gnu.org/licenses/gpl-3.0.txt
|
||||
// https://www.gnu.org/licenses/lgpl-3.0.txt
|
||||
// SPDX-License-Identifier: LGPL-3.0-only
|
||||
// End of Source File Header
|
||||
|
||||
#include "Config.h"
|
||||
|
||||
namespace MobileGL {
|
||||
namespace MG_Config {
|
||||
BackendType ActiveBackendType;
|
||||
} // namespace MG_Config
|
||||
|
||||
namespace MG_Backend {
|
||||
UniquePtr<BackendObject> pActiveBackendObject;
|
||||
GlobalBackendFunctionsTable gBackendFunctionsTable;
|
||||
} // namespace MG_Backend
|
||||
} // namespace MobileGL
|
||||
@@ -0,0 +1,125 @@
|
||||
// MobileGL - MobileGL/Includes.h
|
||||
// Copyright (c) 2025-2026 MobileGL-Dev
|
||||
// Licensed under the GNU Lesser General Public License v3.0:
|
||||
// https://www.gnu.org/licenses/gpl-3.0.txt
|
||||
// https://www.gnu.org/licenses/lgpl-3.0.txt
|
||||
// SPDX-License-Identifier: LGPL-3.0-only
|
||||
// End of Source File Header
|
||||
|
||||
#pragma once
|
||||
|
||||
// Include significant project headers
|
||||
#include "Defines.h"
|
||||
#include "MG_Util/PlatformStubs.h"
|
||||
|
||||
// Include necessary standard headers
|
||||
#include <bit>
|
||||
#include <map>
|
||||
#include <array>
|
||||
#include <ctime>
|
||||
#include <mutex>
|
||||
#include <queue>
|
||||
#include <regex>
|
||||
#include <atomic>
|
||||
#include <bitset>
|
||||
#include <cctype>
|
||||
#include <chrono>
|
||||
#include <cstdio>
|
||||
#include <format>
|
||||
#include <memory>
|
||||
#include <random>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
#include <vector>
|
||||
#include <cassert>
|
||||
#include <cstdarg>
|
||||
#include <cstring>
|
||||
#include <numeric>
|
||||
#include <expected>
|
||||
#include <iostream>
|
||||
#include <optional>
|
||||
#include <algorithm>
|
||||
#include <stdexcept>
|
||||
#include <functional>
|
||||
#include <string_view>
|
||||
#include <unordered_map>
|
||||
#if __cplusplus >= 202302L && MOBILEGL_LOG_ENABLE_STACKTRACE
|
||||
#include <stacktrace>
|
||||
#endif
|
||||
|
||||
// Include FastSTL
|
||||
#include <FastSTL/UnorderedMap.h>
|
||||
|
||||
// Include xxHash
|
||||
#include <xxhash.h>
|
||||
|
||||
// Include spirv_cross
|
||||
#include <spirv_cross/spirv_cross_c.h>
|
||||
|
||||
// Include OpenGL and EGL headers
|
||||
#ifdef GLAPI
|
||||
#undef GLAPI
|
||||
#endif
|
||||
#include <EGL/egl.h>
|
||||
#define GL_GLEXT_PROTOTYPES
|
||||
#ifndef NO_GL_H
|
||||
#include "GL/gl.h"
|
||||
#endif
|
||||
#include <GL/glcorearb.h>
|
||||
#undef GL_GLEXT_PROTOTYPES
|
||||
|
||||
#include <GL/glext.h>
|
||||
|
||||
#define GL_GLES_PROTOTYPES 0
|
||||
#include <GLES3/gl32.h>
|
||||
#undef GL_GLES_PROTOTYPES
|
||||
|
||||
// Include glslang headers
|
||||
#include <glslang/Include/Types.h>
|
||||
#include <glslang/Public/ShaderLang.h>
|
||||
#include <glslang/SPIRV/GlslangToSpv.h>
|
||||
#include <glslang/Include/intermediate.h>
|
||||
#include <glslang/MachineIndependent/localintermediate.h>
|
||||
|
||||
// Include headers for platform-specific functionality
|
||||
#ifdef __linux__
|
||||
#include <dlfcn.h>
|
||||
#include <pthread.h>
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
#ifndef WIN32_LEAN_AND_MEAN
|
||||
#define WIN32_LEAN_AND_MEAN 1
|
||||
#endif
|
||||
#include <windows.h>
|
||||
#include <processthreadsapi.h>
|
||||
#endif
|
||||
|
||||
#ifdef __ANDROID__
|
||||
#include <unistd.h>
|
||||
#include <pthread.h>
|
||||
#include <android/log.h>
|
||||
#include <android/native_window.h>
|
||||
#endif
|
||||
|
||||
#ifdef __ANDROID__
|
||||
#define VK_USE_PLATFORM_ANDROID_KHR
|
||||
#elif _WIN32
|
||||
#define VK_USE_PLATFORM_WIN32_KHR
|
||||
#elif defined(__APPLE__)
|
||||
#define VK_USE_PLATFORM_METAL_EXT
|
||||
#else
|
||||
#warning "VK_USE_PLATFORM_*_KHR not defined for this platform!"
|
||||
#endif
|
||||
#include <vulkan/vulkan.h>
|
||||
|
||||
#ifdef TRACY_ENABLE
|
||||
#include <tracy/Tracy.hpp>
|
||||
#define TRACY_ZONECOLOR_ENTRY 0xFF0000
|
||||
#define TRACY_ZONECOLOR_FRONTEND 0x00FF00
|
||||
#define TRACY_ZONECOLOR_BACKEND 0x00FF00
|
||||
#endif
|
||||
|
||||
// Post-includes for significant project headers
|
||||
#include "MG_Util/Debug/Log.h"
|
||||
#include "MG_Util/Types.h"
|
||||
@@ -0,0 +1,70 @@
|
||||
// MobileGL - MobileGL/Init.cpp
|
||||
// Copyright (c) 2025-2026 MobileGL-Dev
|
||||
// Licensed under the GNU Lesser General Public License v3.0:
|
||||
// https://www.gnu.org/licenses/gpl-3.0.txt
|
||||
// https://www.gnu.org/licenses/lgpl-3.0.txt
|
||||
// SPDX-License-Identifier: LGPL-3.0-only
|
||||
// End of Source File Header
|
||||
|
||||
#include "Init.h"
|
||||
#include "Config.h"
|
||||
#include <MG_Backend/BackendObjects.h>
|
||||
#include <MG_State/GLState/Core.h>
|
||||
#include <MG_State/EGLState/Core.h>
|
||||
#include <MG_Impl/GLImpl/Texture/ProxyTexture.h>
|
||||
#include <MG_Impl/GLImpl/Framebuffer/GL_Framebuffer.h>
|
||||
|
||||
namespace MobileGL {
|
||||
void Initialize() {
|
||||
MG_Util::Debug::InitFile();
|
||||
MGLOG_I("Initializing MobileGL...");
|
||||
MG_ConfigLoader::Init();
|
||||
MGLOG_I("Config loaded");
|
||||
MG_State::Init();
|
||||
MGLOG_D("MG_State initialized");
|
||||
MG_Backend::Init();
|
||||
MGLOG_D("MG_Backend initialized");
|
||||
MG_Impl::Init();
|
||||
MGLOG_D("MG_Impl initialized");
|
||||
glslang::InitializeProcess();
|
||||
MGLOG_D("glslang initialized");
|
||||
MGLOG_I("MobileGL initialized");
|
||||
}
|
||||
|
||||
void Destroy() {
|
||||
MGLOG_I("MobileGL closing...");
|
||||
glslang::FinalizeProcess();
|
||||
MG_State::pGLContext.reset();
|
||||
MG_State::pEGLContext.reset();
|
||||
MG_Impl::GLImpl::TextureImpl::pProxyTextureManager.reset();
|
||||
MG_Impl::GLImpl::FramebufferImpl::pDefaultFramebufferInfo.reset();
|
||||
MG_Util::Debug::Close();
|
||||
|
||||
// TODO: add and use Destroy functions for other subsystems
|
||||
}
|
||||
|
||||
#if defined(__linux__) || defined(__APPLE__)
|
||||
__attribute__((constructor)) static void AutoInit() {
|
||||
Initialize();
|
||||
}
|
||||
|
||||
__attribute__((destructor)) static void AutoDestroy() {
|
||||
Destroy();
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
BOOL WINAPI DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) {
|
||||
switch (ul_reason_for_call) {
|
||||
case DLL_PROCESS_ATTACH:
|
||||
Initialize();
|
||||
break;
|
||||
|
||||
case DLL_PROCESS_DETACH:
|
||||
Destroy();
|
||||
break;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
#endif
|
||||
} // namespace MobileGL
|
||||
@@ -0,0 +1,31 @@
|
||||
// MobileGL - MobileGL/Init.h
|
||||
// Copyright (c) 2025-2026 MobileGL-Dev
|
||||
// Licensed under the GNU Lesser General Public License v3.0:
|
||||
// https://www.gnu.org/licenses/gpl-3.0.txt
|
||||
// https://www.gnu.org/licenses/lgpl-3.0.txt
|
||||
// SPDX-License-Identifier: LGPL-3.0-only
|
||||
// End of Source File Header
|
||||
|
||||
#pragma once
|
||||
#include "Includes.h"
|
||||
|
||||
namespace MobileGL {
|
||||
void Initialize();
|
||||
void Destroy();
|
||||
|
||||
namespace MG_Util::Debug {
|
||||
void InitFile();
|
||||
} // namespace MG_Util::Debug
|
||||
|
||||
namespace MG_ConfigLoader {
|
||||
void Init();
|
||||
} // namespace MG_ConfigLoader
|
||||
|
||||
namespace MG_Backend {
|
||||
void Init();
|
||||
} // namespace MG_Backend
|
||||
|
||||
namespace MG_Impl {
|
||||
void Init();
|
||||
} // namespace MG_Impl
|
||||
} // namespace MobileGL
|
||||
@@ -0,0 +1,141 @@
|
||||
// MobileGL - MobileGL/MG_Backend/BackendObject.cpp
|
||||
// Copyright (c) 2025-2026 MobileGL-Dev
|
||||
// Licensed under the GNU Lesser General Public License v3.0:
|
||||
// https://www.gnu.org/licenses/gpl-3.0.txt
|
||||
// https://www.gnu.org/licenses/lgpl-3.0.txt
|
||||
// SPDX-License-Identifier: LGPL-3.0-only
|
||||
// End of Source File Header
|
||||
|
||||
#include "BackendObject.h"
|
||||
|
||||
namespace MobileGL::MG_Backend {
|
||||
namespace {
|
||||
Bool IsReleaseCurrentRequest(EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLContext ctx) {
|
||||
return dpy == EGL_NO_DISPLAY && draw == EGL_NO_SURFACE && read == EGL_NO_SURFACE && ctx == EGL_NO_CONTEXT;
|
||||
}
|
||||
|
||||
std::thread::id CurrentThreadKey() {
|
||||
return std::this_thread::get_id();
|
||||
}
|
||||
} // namespace
|
||||
|
||||
Bool BackendObject::InitializeEGLDisplay(EGLDisplay dpy, EGLint* major, EGLint* minor) {
|
||||
const std::lock_guard<std::recursive_mutex> lock(m_eglStateMutex);
|
||||
if (dpy == EGL_NO_DISPLAY) {
|
||||
MGLOG_E("InitializeEGLDisplay failed: invalid EGLDisplay");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (m_eglDisplayInitialized && m_eglDisplay != dpy) {
|
||||
MGLOG_E("InitializeEGLDisplay failed: backend already bound to a different EGLDisplay");
|
||||
return false;
|
||||
}
|
||||
|
||||
m_eglDisplay = dpy;
|
||||
m_eglDisplayInitialized = true;
|
||||
if (major) {
|
||||
*major = 1;
|
||||
}
|
||||
if (minor) {
|
||||
*minor = 5;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
Bool BackendObject::CreateEGLWindowSurface(const WindowHandle& handle) {
|
||||
const std::lock_guard<std::recursive_mutex> lock(m_eglStateMutex);
|
||||
if (!m_eglDisplayInitialized) {
|
||||
MGLOG_E("CreateEGLWindowSurface failed: EGL display is not initialized");
|
||||
return false;
|
||||
}
|
||||
if (handle.Backend == WindowBackend::Unknown || !handle.Handle) {
|
||||
MGLOG_E("CreateEGLWindowSurface failed: invalid native window handle");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (m_eglWindowSurfaceInitialized && m_windowHandle.Backend == handle.Backend && m_windowHandle.Handle == handle.Handle) {
|
||||
return true;
|
||||
}
|
||||
|
||||
SetWindowHandle(handle);
|
||||
if (!InitWindowSurface()) {
|
||||
MGLOG_E("CreateEGLWindowSurface failed: backend InitWindowSurface failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
m_eglWindowSurfaceInitialized = true;
|
||||
m_eglCurrentThreads.clear();
|
||||
m_backendCapabilitiesInitialized = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
Bool BackendObject::MakeEGLCurrent(EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLContext ctx) {
|
||||
const std::lock_guard<std::recursive_mutex> lock(m_eglStateMutex);
|
||||
const auto threadKey = CurrentThreadKey();
|
||||
if (IsReleaseCurrentRequest(dpy, draw, read, ctx)) {
|
||||
m_eglCurrentThreads.erase(threadKey);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!m_eglDisplayInitialized || m_eglDisplay != dpy) {
|
||||
MGLOG_E("MakeEGLCurrent failed: EGL display mismatch or not initialized");
|
||||
return false;
|
||||
}
|
||||
if (!m_eglWindowSurfaceInitialized) {
|
||||
MGLOG_E("MakeEGLCurrent failed: EGL window surface is not initialized");
|
||||
return false;
|
||||
}
|
||||
if (draw == EGL_NO_SURFACE || read == EGL_NO_SURFACE || ctx == EGL_NO_CONTEXT) {
|
||||
MGLOG_E("MakeEGLCurrent failed: draw/read/context is invalid");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!m_backendCapabilitiesInitialized) {
|
||||
if (!InitCapabilities()) {
|
||||
MGLOG_E("MakeEGLCurrent failed: InitCapabilities failed");
|
||||
return false;
|
||||
}
|
||||
m_backendCapabilitiesInitialized = true;
|
||||
}
|
||||
|
||||
m_eglCurrentThreads[threadKey] = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
void BackendObject::ResetEGLRuntimeState() {
|
||||
const std::lock_guard<std::recursive_mutex> lock(m_eglStateMutex);
|
||||
m_eglWindowSurfaceInitialized = false;
|
||||
m_backendCapabilitiesInitialized = false;
|
||||
m_eglCurrentThreads.clear();
|
||||
}
|
||||
|
||||
Bool BackendObject::SwapEGLBuffers(EGLDisplay dpy, EGLSurface draw) {
|
||||
const std::lock_guard<std::recursive_mutex> lock(m_eglStateMutex);
|
||||
if (!m_eglDisplayInitialized || m_eglDisplay != dpy) {
|
||||
MGLOG_E("SwapEGLBuffers failed: EGL display mismatch or not initialized");
|
||||
return false;
|
||||
}
|
||||
if (m_eglCurrentThreads.find(CurrentThreadKey()) == m_eglCurrentThreads.end()) {
|
||||
MGLOG_E("SwapEGLBuffers failed: no current context attached");
|
||||
return false;
|
||||
}
|
||||
if (!m_eglWindowSurfaceInitialized || draw == EGL_NO_SURFACE) {
|
||||
MGLOG_E("SwapEGLBuffers failed: invalid draw surface");
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto& backendFunctions = GetBackendFunctions();
|
||||
if (!backendFunctions.Present) {
|
||||
MGLOG_E("SwapEGLBuffers failed: backend Present function is null");
|
||||
return false;
|
||||
}
|
||||
|
||||
backendFunctions.Present();
|
||||
return true;
|
||||
}
|
||||
|
||||
void BackendObject::SetWindowHandle(const WindowHandle& handle) {
|
||||
const std::lock_guard<std::recursive_mutex> lock(m_eglStateMutex);
|
||||
m_windowHandle = handle;
|
||||
}
|
||||
} // namespace MobileGL::MG_Backend
|
||||
@@ -0,0 +1,122 @@
|
||||
// MobileGL - MobileGL/MG_Backend/BackendObject.h
|
||||
// Copyright (c) 2025-2026 MobileGL-Dev
|
||||
// Licensed under the GNU Lesser General Public License v3.0:
|
||||
// https://www.gnu.org/licenses/gpl-3.0.txt
|
||||
// https://www.gnu.org/licenses/lgpl-3.0.txt
|
||||
// SPDX-License-Identifier: LGPL-3.0-only
|
||||
// End of Source File Header
|
||||
|
||||
#pragma once
|
||||
#include <Includes.h>
|
||||
|
||||
namespace MobileGL {
|
||||
enum class BackendType {
|
||||
DirectGLES,
|
||||
DirectVulkan,
|
||||
BackendTypeCount,
|
||||
Unknown = -1
|
||||
};
|
||||
|
||||
namespace MG_Backend {
|
||||
struct GLFunctionsTable {
|
||||
void (*DrawArrays)(GLenum mode, GLint first, GLsizei count);
|
||||
void (*DrawElements)(GLenum mode, GLsizei count, GLenum type, const void* indices);
|
||||
void (*DrawElementsBaseVertex)(GLenum mode, GLsizei count, GLenum type, const void* indices,
|
||||
GLint basevertex);
|
||||
void (*MultiDrawElements)(GLenum mode, const GLsizei* count, GLenum type, const GLvoid* const* indices,
|
||||
GLsizei drawcount);
|
||||
void (*MultiDrawElementsBaseVertex)(GLenum mode, const GLsizei* count, GLenum type,
|
||||
const GLvoid* const* indices, GLsizei drawcount,
|
||||
const GLint* basevertex);
|
||||
void (*MultiDrawElementsIndirect)(GLenum mode, GLenum type, const void* indirect, GLsizei drawcount,
|
||||
GLsizei stride);
|
||||
void (*MultiDrawArraysIndirect)(GLenum mode, const void* indirect, GLsizei drawcount, GLsizei stride);
|
||||
void (*DrawRangeElementsBaseVertex)(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type,
|
||||
const void* indices, GLint basevertex);
|
||||
void (*DrawRangeElements)(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type,
|
||||
const void* indices);
|
||||
void (*DrawElementsInstancedBaseVertexBaseInstance)(GLenum mode, GLsizei count, GLenum type,
|
||||
const void* indices, GLsizei instancecount,
|
||||
GLint basevertex, GLuint baseinstance);
|
||||
void (*DrawElementsInstancedBaseVertex)(GLenum mode, GLsizei count, GLenum type, const void* indices,
|
||||
GLsizei instancecount, GLint basevertex);
|
||||
void (*DrawElementsInstancedBaseInstance)(GLenum mode, GLsizei count, GLenum type, const void* indices,
|
||||
GLsizei instancecount, GLuint baseinstance);
|
||||
void (*DrawElementsInstanced)(GLenum mode, GLsizei count, GLenum type, const void* indices,
|
||||
GLsizei instancecount);
|
||||
void (*DrawArraysInstancedBaseInstance)(GLenum mode, GLint first, GLsizei count, GLsizei instancecount,
|
||||
GLuint baseinstance);
|
||||
void (*DrawArraysInstanced)(GLenum mode, GLint first, GLsizei count, GLsizei instancecount);
|
||||
void (*DrawElementsIndirect)(GLenum mode, GLenum type, const void* indirect);
|
||||
void (*DrawArraysIndirect)(GLenum mode, const void* indirect);
|
||||
void (*Clear)(GLbitfield mask);
|
||||
void (*ClearBufferfi)(GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil);
|
||||
void (*ClearBufferfv)(GLenum buffer, GLint drawbuffer, const GLfloat* value);
|
||||
void (*ClearBufferuiv)(GLenum buffer, GLint drawbuffer, const GLuint* value);
|
||||
void (*ClearBufferiv)(GLenum buffer, GLint drawbuffer, const GLint* value);
|
||||
void (*BlitFramebuffer)(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0,
|
||||
GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter);
|
||||
void (*CopyTexImage2D)(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width,
|
||||
GLsizei height, GLint border);
|
||||
void (*CopyTexSubImage2D)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y,
|
||||
GLsizei width, GLsizei height);
|
||||
void (*GenerateMipmap)(GLenum target);
|
||||
void (*ReadPixels)(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type,
|
||||
void* pixels);
|
||||
void (*GetTexImage)(GLenum target, GLint level, GLenum format, GLenum type, GLvoid* pixels);
|
||||
};
|
||||
struct GlobalBackendFunctionsTable {
|
||||
GLFunctionsTable GL;
|
||||
void (*Present)();
|
||||
};
|
||||
|
||||
struct DynamicBackendParameters {
|
||||
SizeT UniformBufferOffsetAlignment = 256;
|
||||
};
|
||||
|
||||
enum class WindowBackend {
|
||||
Android,
|
||||
// TODO: X11, Wayland, Windows, macOS, etc.
|
||||
WindowBackendCount,
|
||||
Unknown = -1
|
||||
};
|
||||
|
||||
struct WindowHandle {
|
||||
WindowBackend Backend = WindowBackend::Unknown;
|
||||
void* Handle = nullptr;
|
||||
};
|
||||
|
||||
class BackendObject {
|
||||
public:
|
||||
virtual ~BackendObject() = default;
|
||||
|
||||
virtual void Initialize() = 0;
|
||||
virtual Bool InitCapabilities() = 0;
|
||||
virtual Bool InitWindowSurface() = 0;
|
||||
|
||||
virtual Bool InitializeEGLDisplay(EGLDisplay dpy, EGLint* major, EGLint* minor);
|
||||
virtual Bool CreateEGLWindowSurface(const WindowHandle& handle);
|
||||
virtual Bool MakeEGLCurrent(EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLContext ctx);
|
||||
virtual Bool SwapEGLBuffers(EGLDisplay dpy, EGLSurface draw);
|
||||
|
||||
void SetWindowHandle(const WindowHandle& handle);
|
||||
|
||||
virtual const RendererInfo& GetRendererInfo() const = 0;
|
||||
virtual String GetBackendAPIVersionString() const = 0;
|
||||
virtual const GlobalBackendFunctionsTable& GetBackendFunctions() const = 0;
|
||||
virtual const DynamicBackendParameters& GetDynamicParameters() const = 0;
|
||||
virtual BackendType GetBackendType() const = 0;
|
||||
|
||||
protected:
|
||||
void ResetEGLRuntimeState();
|
||||
|
||||
mutable std::recursive_mutex m_eglStateMutex;
|
||||
WindowHandle m_windowHandle;
|
||||
EGLDisplay m_eglDisplay = EGL_NO_DISPLAY;
|
||||
Bool m_eglDisplayInitialized = false;
|
||||
Bool m_eglWindowSurfaceInitialized = false;
|
||||
Bool m_backendCapabilitiesInitialized = false;
|
||||
UnorderedMap<std::thread::id, Bool> m_eglCurrentThreads;
|
||||
};
|
||||
} // namespace MG_Backend
|
||||
} // namespace MobileGL
|
||||
@@ -0,0 +1,18 @@
|
||||
// MobileGL - MobileGL/MG_Backend/BackendObjects.h
|
||||
// Copyright (c) 2025-2026 MobileGL-Dev
|
||||
// Licensed under the GNU Lesser General Public License v3.0:
|
||||
// https://www.gnu.org/licenses/gpl-3.0.txt
|
||||
// https://www.gnu.org/licenses/lgpl-3.0.txt
|
||||
// SPDX-License-Identifier: LGPL-3.0-only
|
||||
// End of Source File Header
|
||||
|
||||
#pragma once
|
||||
#include <Includes.h>
|
||||
#include "BackendObject.h"
|
||||
#include "DirectGLES/BackendObject_DirectGLES.h"
|
||||
#include "DirectVulkan/BackendObject_DirectVulkan.h"
|
||||
|
||||
namespace MobileGL::MG_Backend {
|
||||
extern UniquePtr<BackendObject> pActiveBackendObject;
|
||||
extern GlobalBackendFunctionsTable gBackendFunctionsTable;
|
||||
} // namespace MobileGL::MG_Backend
|
||||
@@ -0,0 +1,198 @@
|
||||
// MobileGL - MobileGL/MG_Backend/DirectGLES/BackendObject_DirectGLES.cpp
|
||||
// Copyright (c) 2025-2026 MobileGL-Dev
|
||||
// Licensed under the GNU Lesser General Public License v3.0:
|
||||
// https://www.gnu.org/licenses/gpl-3.0.txt
|
||||
// https://www.gnu.org/licenses/lgpl-3.0.txt
|
||||
// SPDX-License-Identifier: LGPL-3.0-only
|
||||
// End of Source File Header
|
||||
|
||||
#include "BackendObject_DirectGLES.h"
|
||||
#include "MG_Backend/BackendObject.h"
|
||||
#include <MG_Backend/DirectGLES/DirectGLES.h>
|
||||
#include <MG_Util/BackendLoaders/OpenGL/Loader.h>
|
||||
#include <format>
|
||||
|
||||
namespace MobileGL::MG_Backend::DirectGLES {
|
||||
namespace {
|
||||
Bool IsReleaseCurrentRequest(EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLContext ctx) {
|
||||
return dpy == EGL_NO_DISPLAY && draw == EGL_NO_SURFACE && read == EGL_NO_SURFACE && ctx == EGL_NO_CONTEXT;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
BackendObject_DirectGLES::~BackendObject_DirectGLES() {
|
||||
DestroyEGLContext();
|
||||
}
|
||||
|
||||
Bool BackendObject_DirectGLES::InitWindowSurface() {
|
||||
// Only use EGL for now
|
||||
auto nativeWindow = reinterpret_cast<NativeWindowType>(m_windowHandle.Handle);
|
||||
if (!DirectGLES::InitWindowSurface(nativeWindow)) {
|
||||
MGLOG_E("Failed to initialize window surface for DirectGLES backend");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void BackendObject_DirectGLES::Initialize() {
|
||||
if (!MG_Util::BackendLoader::AcquireEGLFunctions(m_EGLFunctions)) {
|
||||
MGLOG_E("Failed to acquire EGL functions for DirectGLES backend");
|
||||
return;
|
||||
}
|
||||
if (!MG_Util::BackendLoader::AcquireGLESFunctions(m_GLESFunctions, m_EGLFunctions.eglGetProcAddress)) {
|
||||
MGLOG_E("Failed to acquire GLES functions for DirectGLES backend");
|
||||
return;
|
||||
}
|
||||
m_initialized = true;
|
||||
|
||||
DirectGLES::SetEGLFuncsTable(m_EGLFunctions);
|
||||
DirectGLES::SetGLESFuncsTable(m_GLESFunctions);
|
||||
}
|
||||
|
||||
Bool BackendObject_DirectGLES::InitCapabilities() {
|
||||
if (!m_initialized) {
|
||||
MGLOG_E("DirectGLES backend not initialized");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!MG_Util::BackendLoader::FillInGLESCapabilities(m_GLESCapabilities, m_GLESFunctions)) {
|
||||
MGLOG_E("Failed to fill in GLES capabilities for DirectGLES backend");
|
||||
return false;
|
||||
}
|
||||
DirectGLES::SetGLESCapabilities(m_GLESCapabilities);
|
||||
UpdateDynamicBackendParameters();
|
||||
return true;
|
||||
}
|
||||
|
||||
Bool BackendObject_DirectGLES::InitializeEGLDisplay(EGLDisplay dpy, EGLint* major, EGLint* minor) {
|
||||
if (!m_initialized) {
|
||||
MGLOG_E("DirectGLES backend not initialized");
|
||||
return false;
|
||||
}
|
||||
return BackendObject::InitializeEGLDisplay(dpy, major, minor);
|
||||
}
|
||||
|
||||
Bool BackendObject_DirectGLES::CreateEGLWindowSurface(const WindowHandle& handle) {
|
||||
const std::lock_guard<std::recursive_mutex> lock(m_eglStateMutex);
|
||||
if (!m_initialized) {
|
||||
MGLOG_E("DirectGLES backend not initialized");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (handle.Backend != WindowBackend::Android || !handle.Handle) {
|
||||
MGLOG_E("DirectGLES backend only supports Android native windows");
|
||||
return false;
|
||||
}
|
||||
|
||||
const Bool sameHandle =
|
||||
m_eglWindowSurfaceInitialized && m_windowHandle.Backend == handle.Backend && m_windowHandle.Handle == handle.Handle;
|
||||
if (sameHandle) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (m_eglWindowSurfaceInitialized) {
|
||||
DestroyEGLContext();
|
||||
ResetEGLRuntimeState();
|
||||
}
|
||||
|
||||
return BackendObject::CreateEGLWindowSurface(handle);
|
||||
}
|
||||
|
||||
Bool BackendObject_DirectGLES::MakeEGLCurrent(EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLContext ctx) {
|
||||
if (IsReleaseCurrentRequest(dpy, draw, read, ctx)) {
|
||||
return BackendObject::MakeEGLCurrent(dpy, draw, read, ctx);
|
||||
}
|
||||
|
||||
return BackendObject::MakeEGLCurrent(dpy, draw, read, ctx);
|
||||
}
|
||||
|
||||
Bool BackendObject_DirectGLES::SwapEGLBuffers(EGLDisplay dpy, EGLSurface draw) {
|
||||
return BackendObject::SwapEGLBuffers(dpy, draw);
|
||||
}
|
||||
|
||||
const RendererInfo& BackendObject_DirectGLES::GetRendererInfo() const {
|
||||
static RendererInfo RendererInfo = {
|
||||
.RendererName = "Espryt", // Renderer Name
|
||||
.BackendName = "Direct (OpenGL ES)", // Backend Name
|
||||
.ExtraVendor = Nullopt, // Extra vendor
|
||||
.RendererGLInfo =
|
||||
{
|
||||
.TargetGLVersion = {3, 3, 0}, // Target OpenGL Version
|
||||
.TargetGLSLVersion = {4, 6, 0}, // Target Shading Language Version
|
||||
.Extensions = {V_OpenGL30, V_OpenGL31, V_OpenGL32, // OpenGL Extensions
|
||||
V_OpenGL33, E_GL_ARB_draw_buffers_blend},
|
||||
.IsCompatibilityProfile = false // Is Compatibility Profile
|
||||
},
|
||||
.StaticBackendCapability = {.AllowVSOnlyPrograms = false} // Backend Capability
|
||||
};
|
||||
return RendererInfo;
|
||||
}
|
||||
|
||||
String BackendObject_DirectGLES::GetBackendAPIVersionString() const {
|
||||
if (!m_initialized) {
|
||||
return "<uninitialized DirectGLES backend>";
|
||||
}
|
||||
// Format:
|
||||
// <OpenGL ES Renderer>, OpenGL ES <OpenGL ES Version>
|
||||
String versionString = std::format("{}, OpenGL ES {}.{}", m_GLESCapabilities.GLESRendererString,
|
||||
m_GLESCapabilities.GLESVersion.Major, m_GLESCapabilities.GLESVersion.Minor);
|
||||
return versionString;
|
||||
}
|
||||
|
||||
BackendType BackendObject_DirectGLES::GetBackendType() const {
|
||||
return BackendType::DirectGLES;
|
||||
}
|
||||
|
||||
const GlobalBackendFunctionsTable& BackendObject_DirectGLES::GetBackendFunctions() const {
|
||||
static GlobalBackendFunctionsTable funcsTable;
|
||||
static Bool funcsTableInitialized = false;
|
||||
if (!funcsTableInitialized) {
|
||||
funcsTable.Present = DirectGLES::Present;
|
||||
funcsTable.GL.DrawArrays = DrawArrays;
|
||||
funcsTable.GL.DrawElements = DrawElements;
|
||||
funcsTable.GL.DrawElementsBaseVertex = DrawElementsBaseVertex;
|
||||
funcsTable.GL.MultiDrawElements = MultiDrawElements;
|
||||
funcsTable.GL.MultiDrawElementsBaseVertex = MultiDrawElementsBaseVertex;
|
||||
funcsTable.GL.MultiDrawElementsIndirect = MultiDrawElementsIndirect;
|
||||
funcsTable.GL.MultiDrawArraysIndirect = MultiDrawArraysIndirect;
|
||||
funcsTable.GL.DrawRangeElementsBaseVertex = DrawRangeElementsBaseVertex;
|
||||
funcsTable.GL.DrawRangeElements = DrawRangeElements;
|
||||
funcsTable.GL.DrawElementsInstancedBaseVertexBaseInstance = DrawElementsInstancedBaseVertexBaseInstance;
|
||||
funcsTable.GL.DrawElementsInstancedBaseVertex = DrawElementsInstancedBaseVertex;
|
||||
funcsTable.GL.DrawElementsInstancedBaseInstance = DrawElementsInstancedBaseInstance;
|
||||
funcsTable.GL.DrawElementsInstanced = DrawElementsInstanced;
|
||||
funcsTable.GL.DrawArraysInstancedBaseInstance = DrawArraysInstancedBaseInstance;
|
||||
funcsTable.GL.DrawArraysInstanced = DrawArraysInstanced;
|
||||
funcsTable.GL.DrawElementsIndirect = DrawElementsIndirect;
|
||||
funcsTable.GL.DrawArraysIndirect = DrawArraysIndirect;
|
||||
funcsTable.GL.Clear = Clear;
|
||||
funcsTable.GL.ClearBufferfi = ClearBufferfi;
|
||||
funcsTable.GL.ClearBufferfv = ClearBufferfv;
|
||||
funcsTable.GL.ClearBufferuiv = ClearBufferuiv;
|
||||
funcsTable.GL.ClearBufferiv = ClearBufferiv;
|
||||
funcsTable.GL.BlitFramebuffer = BlitFramebuffer;
|
||||
funcsTable.GL.CopyTexImage2D = CopyTexImage2D;
|
||||
funcsTable.GL.CopyTexSubImage2D = CopyTexSubImage2D;
|
||||
funcsTable.GL.GenerateMipmap = GenerateMipmap;
|
||||
funcsTable.GL.ReadPixels = ReadPixels;
|
||||
funcsTable.GL.GetTexImage = GetTexImage;
|
||||
funcsTableInitialized = true;
|
||||
}
|
||||
return funcsTable;
|
||||
}
|
||||
|
||||
const DynamicBackendParameters& BackendObject_DirectGLES::GetDynamicParameters() const {
|
||||
return m_dynamicParameters;
|
||||
}
|
||||
|
||||
void BackendObject_DirectGLES::UpdateDynamicBackendParameters() {
|
||||
m_dynamicParameters.UniformBufferOffsetAlignment = m_GLESCapabilities.UniformBufferOffsetAlignment;
|
||||
}
|
||||
|
||||
const MG_External::GLESFunctionsTable& BackendObject_DirectGLES::GetGLESFunctions() const {
|
||||
return m_GLESFunctions;
|
||||
}
|
||||
|
||||
const MG_External::EGLFunctionsTable& BackendObject_DirectGLES::GetEGLFunctions() const {
|
||||
return m_EGLFunctions;
|
||||
}
|
||||
} // namespace MobileGL::MG_Backend::DirectGLES
|
||||
@@ -0,0 +1,45 @@
|
||||
// MobileGL - MobileGL/MG_Backend/DirectGLES/BackendObject_DirectGLES.h
|
||||
// Copyright (c) 2025-2026 MobileGL-Dev
|
||||
// Licensed under the GNU Lesser General Public License v3.0:
|
||||
// https://www.gnu.org/licenses/gpl-3.0.txt
|
||||
// https://www.gnu.org/licenses/lgpl-3.0.txt
|
||||
// SPDX-License-Identifier: LGPL-3.0-only
|
||||
// End of Source File Header
|
||||
|
||||
#pragma once
|
||||
#include <Includes.h>
|
||||
#include "../BackendObject.h"
|
||||
#include <MG_Util/BackendLoaders/OpenGL/Loader.h>
|
||||
|
||||
namespace MobileGL::MG_Backend::DirectGLES {
|
||||
class BackendObject_DirectGLES : public BackendObject {
|
||||
public:
|
||||
~BackendObject_DirectGLES() override;
|
||||
|
||||
void Initialize() override;
|
||||
Bool InitCapabilities() override;
|
||||
Bool InitWindowSurface() override;
|
||||
Bool InitializeEGLDisplay(EGLDisplay dpy, EGLint* major, EGLint* minor) override;
|
||||
Bool CreateEGLWindowSurface(const WindowHandle& handle) override;
|
||||
Bool MakeEGLCurrent(EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLContext ctx) override;
|
||||
Bool SwapEGLBuffers(EGLDisplay dpy, EGLSurface draw) override;
|
||||
|
||||
const RendererInfo& GetRendererInfo() const override;
|
||||
String GetBackendAPIVersionString() const override;
|
||||
const GlobalBackendFunctionsTable& GetBackendFunctions() const override;
|
||||
const DynamicBackendParameters& GetDynamicParameters() const override;
|
||||
BackendType GetBackendType() const override;
|
||||
|
||||
const MG_External::GLESFunctionsTable& GetGLESFunctions() const;
|
||||
const MG_External::EGLFunctionsTable& GetEGLFunctions() const;
|
||||
|
||||
private:
|
||||
void UpdateDynamicBackendParameters();
|
||||
|
||||
Bool m_initialized = false;
|
||||
MG_External::EGLFunctionsTable m_EGLFunctions;
|
||||
MG_External::GLESFunctionsTable m_GLESFunctions;
|
||||
MG_External::GLESCapabilities m_GLESCapabilities;
|
||||
DynamicBackendParameters m_dynamicParameters;
|
||||
};
|
||||
} // namespace MobileGL::MG_Backend::DirectGLES
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,69 @@
|
||||
// MobileGL - MobileGL/MG_Backend/DirectGLES/DirectGLES.h
|
||||
// Copyright (c) 2025-2026 MobileGL-Dev
|
||||
// Licensed under the GNU Lesser General Public License v3.0:
|
||||
// https://www.gnu.org/licenses/gpl-3.0.txt
|
||||
// https://www.gnu.org/licenses/lgpl-3.0.txt
|
||||
// SPDX-License-Identifier: LGPL-3.0-only
|
||||
// End of Source File Header
|
||||
|
||||
#pragma once
|
||||
#include <Includes.h>
|
||||
#include <MG_State/GLState/TextureState/TextureState.h>
|
||||
#include <MG_State/GLState/SamplerState/SamplerObject.h>
|
||||
#include <MG_Util/BackendLoaders/OpenGL/Loader.h>
|
||||
|
||||
#define CallAndCheck(operation) \
|
||||
MGLOG_D("Call GLES func: %s", #operation); \
|
||||
operation Utils::CheckGLESError();
|
||||
|
||||
namespace MobileGL::MG_Backend::DirectGLES {
|
||||
void ClearBufferfi(GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil);
|
||||
void ClearBufferfv(GLenum buffer, GLint drawbuffer, const GLfloat* value);
|
||||
void ClearBufferuiv(GLenum buffer, GLint drawbuffer, const GLuint* value);
|
||||
void ClearBufferiv(GLenum buffer, GLint drawbuffer, const GLint* value);
|
||||
void Clear(GLbitfield mask);
|
||||
void DrawElements(GLenum mode, GLsizei count, GLenum type, const void* indices);
|
||||
void DrawArrays(GLenum mode, GLint first, GLsizei count);
|
||||
void DrawElementsBaseVertex(GLenum mode, GLsizei count, GLenum type, const GLvoid* indices, GLint basevertex);
|
||||
void MultiDrawElements(GLenum mode, const GLsizei* count, GLenum type, const GLvoid* const* indices,
|
||||
GLsizei drawcount);
|
||||
void MultiDrawElementsBaseVertex(GLenum mode, const GLsizei* count, GLenum type, const GLvoid* const* indices,
|
||||
GLsizei drawcount, const GLint* basevertex);
|
||||
void MultiDrawElementsIndirect(GLenum mode, GLenum type, const void* indirect, GLsizei drawcount, GLsizei stride);
|
||||
void MultiDrawArraysIndirect(GLenum mode, const void* indirect, GLsizei drawcount, GLsizei stride);
|
||||
void DrawRangeElementsBaseVertex(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type,
|
||||
const void* indices, GLint basevertex);
|
||||
void DrawRangeElements(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void* indices);
|
||||
void DrawElementsInstancedBaseVertexBaseInstance(GLenum mode, GLsizei count, GLenum type, const void* indices,
|
||||
GLsizei instancecount, GLint basevertex, GLuint baseinstance);
|
||||
void DrawElementsInstancedBaseVertex(GLenum mode, GLsizei count, GLenum type, const void* indices,
|
||||
GLsizei instancecount, GLint basevertex);
|
||||
void DrawElementsInstancedBaseInstance(GLenum mode, GLsizei count, GLenum type, const void* indices,
|
||||
GLsizei instancecount, GLuint baseinstance);
|
||||
void DrawElementsInstanced(GLenum mode, GLsizei count, GLenum type, const void* indices, GLsizei instancecount);
|
||||
void DrawElementsIndirect(GLenum mode, GLenum type, const void* indirect);
|
||||
void DrawArraysInstancedBaseInstance(GLenum mode, GLint first, GLsizei count, GLsizei instancecount,
|
||||
GLuint baseinstance);
|
||||
void DrawArraysInstanced(GLenum mode, GLint first, GLsizei count, GLsizei instancecount);
|
||||
void DrawArraysIndirect(GLenum mode, const void* indirect);
|
||||
void BlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1,
|
||||
GLint dstY1, GLbitfield mask, GLenum filter);
|
||||
void CopyTexImage2D(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width,
|
||||
GLsizei height, GLint border);
|
||||
void CopyTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width,
|
||||
GLsizei height);
|
||||
void GenerateMipmap(GLenum target);
|
||||
const GLubyte* GetString(GLenum name);
|
||||
void ReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void* pixels);
|
||||
void GetTexImage(GLenum target, GLint level, GLenum format, GLenum type, GLvoid* pixels);
|
||||
Bool InitWindowSurface(NativeWindowType window);
|
||||
void Present();
|
||||
void SetEGLFuncsTable(const MG_External::EGLFunctionsTable& eglFuncs);
|
||||
void SetGLESFuncsTable(const MG_External::GLESFunctionsTable& glesFuncs);
|
||||
void SetGLESCapabilities(const MG_External::GLESCapabilities& capabilities);
|
||||
void DestroyEGLContext();
|
||||
|
||||
extern MG_External::EGLFunctionsTable g_EGLFuncs;
|
||||
extern MG_External::GLESFunctionsTable g_GLESFuncs;
|
||||
extern MG_External::GLESCapabilities g_GLESCapabilities;
|
||||
} // namespace MobileGL::MG_Backend::DirectGLES
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,317 @@
|
||||
// MobileGL - MobileGL/MG_Backend/DirectGLES/Managers.h
|
||||
// Copyright (c) 2025-2026 MobileGL-Dev
|
||||
// Licensed under the GNU Lesser General Public License v3.0:
|
||||
// https://www.gnu.org/licenses/gpl-3.0.txt
|
||||
// https://www.gnu.org/licenses/lgpl-3.0.txt
|
||||
// SPDX-License-Identifier: LGPL-3.0-only
|
||||
// End of Source File Header
|
||||
|
||||
#pragma once
|
||||
#include <Includes.h>
|
||||
#include "DirectGLES.h"
|
||||
#include "MG_State/GLState/SamplerState/SamplerObject.h"
|
||||
#include "MG_State/GLState/TextureState/TextureEnum.h"
|
||||
#include <MG_State/GLState/TextureState/TextureObject.h>
|
||||
#include <MG_State/GLState/Core.h>
|
||||
|
||||
namespace MobileGL::MG_Backend::DirectGLES {
|
||||
template <typename StateObject, typename BackendObject>
|
||||
class StateBackendObjectRegistry {
|
||||
public:
|
||||
using StatePtr = SharedPtr<StateObject>;
|
||||
using StateWeakPtr = std::weak_ptr<StateObject>;
|
||||
using BackendPtr = SharedPtr<BackendObject>;
|
||||
using BackendMap = UnorderedMap<StateObject*, BackendPtr>;
|
||||
using StateRefMap = UnorderedMap<StateObject*, StateWeakPtr>;
|
||||
using iterator = typename BackendMap::iterator;
|
||||
using const_iterator = typename BackendMap::const_iterator;
|
||||
|
||||
BackendPtr& GetOrCreate(const StatePtr& stateObj) {
|
||||
MOBILEGL_ASSERT(stateObj != nullptr, "State object must not be null");
|
||||
|
||||
auto* key = stateObj.get();
|
||||
auto trackedStateIt = m_stateRefs.find(key);
|
||||
if (trackedStateIt != m_stateRefs.end() && trackedStateIt->second.expired()) {
|
||||
EraseByKey(key);
|
||||
}
|
||||
m_stateRefs[key] = stateObj;
|
||||
return m_backendObjects[key];
|
||||
}
|
||||
|
||||
iterator find(StateObject* stateObj) {
|
||||
if (!IsAlive(stateObj)) {
|
||||
EraseByKey(stateObj);
|
||||
return m_backendObjects.end();
|
||||
}
|
||||
return m_backendObjects.find(stateObj);
|
||||
}
|
||||
|
||||
const_iterator find(StateObject* stateObj) const {
|
||||
return const_cast<StateBackendObjectRegistry*>(this)->find(stateObj);
|
||||
}
|
||||
|
||||
iterator end() { return m_backendObjects.end(); }
|
||||
const_iterator end() const { return m_backendObjects.end(); }
|
||||
|
||||
void CollectGarbageIfNeeded() {
|
||||
++m_gcTick;
|
||||
if (m_gcTick < kGCInterval) {
|
||||
return;
|
||||
}
|
||||
CollectGarbage();
|
||||
m_gcTick = 0;
|
||||
}
|
||||
|
||||
void CollectGarbageNow() { CollectGarbage(); }
|
||||
|
||||
private:
|
||||
bool IsAlive(StateObject* stateObj) const {
|
||||
const auto trackedStateIt = m_stateRefs.find(stateObj);
|
||||
if (trackedStateIt == m_stateRefs.end()) {
|
||||
return false;
|
||||
}
|
||||
return !trackedStateIt->second.expired();
|
||||
}
|
||||
|
||||
void EraseByKey(StateObject* stateObj) {
|
||||
m_stateRefs.erase(stateObj);
|
||||
m_backendObjects.erase(stateObj);
|
||||
}
|
||||
|
||||
void CollectGarbage() {
|
||||
if (m_isCollecting) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_isCollecting = true;
|
||||
|
||||
Vector<StateObject*> staleKeys;
|
||||
staleKeys.reserve(m_stateRefs.size());
|
||||
for (const auto& [stateKey, stateWeakRef] : m_stateRefs) {
|
||||
if (stateWeakRef.expired()) {
|
||||
staleKeys.push_back(stateKey);
|
||||
}
|
||||
}
|
||||
|
||||
for (auto* stateKey : staleKeys) {
|
||||
m_stateRefs.erase(stateKey);
|
||||
m_backendObjects.erase(stateKey);
|
||||
}
|
||||
|
||||
m_isCollecting = false;
|
||||
}
|
||||
|
||||
private:
|
||||
static constexpr Uint32 kGCInterval = 1024;
|
||||
StateRefMap m_stateRefs;
|
||||
BackendMap m_backendObjects;
|
||||
Uint32 m_gcTick = 0;
|
||||
Bool m_isCollecting = false;
|
||||
};
|
||||
|
||||
namespace BufferImpl {
|
||||
const GLenum TempBufferTarget = GL_ARRAY_BUFFER;
|
||||
class BackendBufferObject {
|
||||
public:
|
||||
BackendBufferObject();
|
||||
void SyncToBackend(const SharedPtr<MG_State::GLState::BufferObject>& stateBufferObject);
|
||||
Uint GetBackendBufferId() const { return m_backendBufferId; }
|
||||
void Bind(GLenum target = TempBufferTarget);
|
||||
|
||||
private:
|
||||
void SyncToBackend_glBufferData(const SharedPtr<MG_State::GLState::BufferObject>& stateBufferObject);
|
||||
void SyncToBackend_glBufferSubData(const SharedPtr<MG_State::GLState::BufferObject>& stateBufferObject);
|
||||
void SyncToBackend_glMapBufferRange(const SharedPtr<MG_State::GLState::BufferObject>& stateBufferObject,
|
||||
Bool invalidate = true, Bool unsynchronized = true);
|
||||
|
||||
Uint m_backendBufferId = 0;
|
||||
SizeT m_prevBufferSize = 0;
|
||||
Bool m_isInitialized = false;
|
||||
};
|
||||
|
||||
extern BackendBufferObject* g_boundVertexBufferObject;
|
||||
extern StateBackendObjectRegistry<MG_State::GLState::BufferObject, BackendBufferObject> g_backendBufferObjects;
|
||||
} // namespace BufferImpl
|
||||
|
||||
namespace VertexArrayImpl {
|
||||
class BackendVertexArrayObject {
|
||||
public:
|
||||
BackendVertexArrayObject();
|
||||
void SyncToBackend(const SharedPtr<MG_State::GLState::VertexArrayObject>& stateVAOObject);
|
||||
Uint GetBackendVertexArrayId() const { return m_backendVAOId; }
|
||||
void Bind() const;
|
||||
|
||||
private:
|
||||
Uint m_backendVAOId = 0;
|
||||
Bool m_isInitialized = false;
|
||||
Uint16 m_syncedIndexBufferVersion = 0;
|
||||
Array<MG_State::GLState::VertexAttributeVersion, MG_State::GLState::VertexArrayObject::MAX_VERTEX_ATTRIBS>
|
||||
m_syncedAttributeVersions;
|
||||
};
|
||||
|
||||
extern StateBackendObjectRegistry<MG_State::GLState::VertexArrayObject, BackendVertexArrayObject>
|
||||
g_backendVertexArrayObjects;
|
||||
} // namespace VertexArrayImpl
|
||||
|
||||
namespace TextureImpl {
|
||||
inline Bool IsSupportedTextureTarget(TextureTarget target) {
|
||||
if (target == TextureTarget::Texture1D || target == TextureTarget::TextureRectangle ||
|
||||
target == TextureTarget::Texture2DMultisampleArray || target == TextureTarget::Texture1DArray ||
|
||||
target == TextureTarget::Texture2DMultisample || target == TextureTarget::Texture2DArray)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
struct StateTextureBasicInfo { // Used for tracking texture state changes
|
||||
TextureInternalFormat internalFormat = TextureInternalFormat::Unknown;
|
||||
SizeT width = 0;
|
||||
SizeT height = 0;
|
||||
SizeT depth = 0;
|
||||
SizeT mipmapLevels = 0;
|
||||
Uint bufferExternalIndex = 0;
|
||||
|
||||
bool operator==(const StateTextureBasicInfo& other) const {
|
||||
return internalFormat == other.internalFormat && width == other.width && height == other.height &&
|
||||
depth == other.depth && mipmapLevels == other.mipmapLevels &&
|
||||
bufferExternalIndex == other.bufferExternalIndex;
|
||||
}
|
||||
|
||||
bool operator!=(const StateTextureBasicInfo& other) const { return !(*this == other); }
|
||||
};
|
||||
|
||||
inline const Uint TempTextureUnit = 0;
|
||||
class BackendTextureObject {
|
||||
public:
|
||||
BackendTextureObject();
|
||||
void SyncMipmapsToBackend(const SharedPtr<MG_State::GLState::ITextureObject>& stateTextureObject);
|
||||
void SyncBuiltinSamplerToBackend(const SharedPtr<MG_State::GLState::ITextureObject>& stateTextureObject);
|
||||
void SyncTextureParamsToBackend(const SharedPtr<MG_State::GLState::ITextureObject>& stateTextureObject);
|
||||
void Bind(GLenum target, Uint unit = TempTextureUnit);
|
||||
Uint GetBackendTextureId() const;
|
||||
|
||||
private:
|
||||
Uint m_backendTextureId = 0;
|
||||
Bool m_isInitialized = false;
|
||||
StateTextureBasicInfo m_prevTextureInfo;
|
||||
SamplerParameters m_cacheSamplerParameters;
|
||||
UintVec2 m_cacheLodRange = {0, 1000};
|
||||
FloatVec4 m_cacheBorderColor = {0.0f, 0.0f, 0.0f, 0.0f};
|
||||
Vec4<TextureSwizzleParam> m_cacheSwizzleParams = {TextureSwizzleParam::Red, TextureSwizzleParam::Green,
|
||||
TextureSwizzleParam::Blue, TextureSwizzleParam::Alpha};
|
||||
Uint16 m_syncedSamplerVersion = 0;
|
||||
Uint16 m_syncedTextureParamsVersion = 0;
|
||||
};
|
||||
|
||||
void ActivateTextureUnit(Uint unit);
|
||||
void UnbindTexture(Uint unit, GLenum target);
|
||||
extern StateBackendObjectRegistry<MG_State::GLState::ITextureObject, BackendTextureObject>
|
||||
g_backendTextureObjects;
|
||||
extern Array<Array<BackendTextureObject*, (SizeT)TextureTarget::TextureTargetCount>,
|
||||
MG_State::GLState::TextureState::MAX_TEXTURE_IMAGE_UNITS>
|
||||
g_boundTexturesCache;
|
||||
extern Uint g_activeTextureUnit;
|
||||
} // namespace TextureImpl
|
||||
|
||||
namespace FramebufferImpl {
|
||||
class BackendFramebufferObject {
|
||||
public:
|
||||
BackendFramebufferObject();
|
||||
void SyncToBackend(const SharedPtr<MG_State::GLState::FramebufferObject>& stateFBOObject,
|
||||
FramebufferTarget asTarget);
|
||||
Uint GetBackendFramebufferId() const { return m_backendFBOId; }
|
||||
void Bind(FramebufferTarget target) const;
|
||||
// FramebufferAttachmentType GetCompactedAttachmentTypeAtDrawBufferIndex(Int index);
|
||||
GLenum GetBackendAttachmentType(FramebufferAttachmentType frontendAtt) const;
|
||||
|
||||
private:
|
||||
Uint m_backendFBOId = 0;
|
||||
|
||||
/* this will save buffers in its original form,
|
||||
reversion, absence or not consecutive are all allowed, as long as GL spec allows it
|
||||
i.e. it could be like [COLOR_ATTACHMENT0, COLOR_ATTACHMENT5, NONE, COLOR_ATTACHMENT4]
|
||||
Probably useful to re-link shader output according to this.
|
||||
aka. realizing `glBindFragDataLocation`
|
||||
*/
|
||||
FramebufferAttachmentType m_frontendDrawBuffers[MG_State::GLState::FramebufferObject::MAX_DRAW_BUFFERS] = {
|
||||
FramebufferAttachmentType::None};
|
||||
/* this will save buffers in stricter ES rules
|
||||
reversion, absence or not consecutive are not allowed, according to ES spec
|
||||
i.e. it could be like [COLOR_ATTACHMENT0, COLOR_ATTACHMENT1, NONE, COLOR_ATTACHMENT3, ...]
|
||||
this array could be provided as data directly to ES `glDrawBuffers` function
|
||||
*/
|
||||
GLenum m_backendDrawBuffers[MG_State::GLState::FramebufferObject::MAX_DRAW_BUFFERS] = {GL_NONE};
|
||||
FramebufferAttachmentType m_frontendReadBuffer = FramebufferAttachmentType::Color0;
|
||||
GLenum m_backendReadBuffer = GL_COLOR_ATTACHMENT0;
|
||||
|
||||
using FramebufferObject = MG_State::GLState::FramebufferObject;
|
||||
FramebufferObject::FramebufferAttachmentVersionArray m_syncedFrontendAttachmentVersions = {0};
|
||||
};
|
||||
|
||||
extern StateBackendObjectRegistry<MG_State::GLState::FramebufferObject, BackendFramebufferObject>
|
||||
g_backendFramebufferObjects;
|
||||
extern Array<Uint16, SizeT(FramebufferTarget::FramebufferTargetCount)> g_fboBindVersions;
|
||||
} // namespace FramebufferImpl
|
||||
|
||||
namespace PrgramImpl {
|
||||
class BackendProgramObjectImpl {
|
||||
public:
|
||||
BackendProgramObjectImpl();
|
||||
~BackendProgramObjectImpl();
|
||||
void SyncToBackend(const SharedPtr<MG_State::GLState::ProgramObject>& stateProgramObject);
|
||||
void Use() const;
|
||||
Uint GetBackendProgramId() const { return m_backendProgramId; }
|
||||
Uint GetBackendGlobalUBOId() const { return m_backendGlobalUBOId; }
|
||||
|
||||
private:
|
||||
Uint m_backendProgramId = 0;
|
||||
Uint m_backendGlobalUBOId = 0;
|
||||
Bool m_isInitialized = false;
|
||||
};
|
||||
|
||||
extern StateBackendObjectRegistry<MG_State::GLState::ProgramObject, BackendProgramObjectImpl>
|
||||
g_backendProgramObjects;
|
||||
} // namespace PrgramImpl
|
||||
|
||||
namespace SamplerImpl {
|
||||
class BackendSamplerObject {
|
||||
public:
|
||||
BackendSamplerObject();
|
||||
void SyncToBackend(const SharedPtr<MG_State::GLState::SamplerObject>& stateSamplerObject);
|
||||
void Bind(Uint unit);
|
||||
Uint GetBackendSamplerId() const;
|
||||
|
||||
private:
|
||||
Uint m_backendSamplerId = 0;
|
||||
Bool m_isInitialized = false;
|
||||
SamplerParameters m_cacheSamplerParameters;
|
||||
Uint16 m_syncedSamplerVersion = 0;
|
||||
};
|
||||
|
||||
void UnbindSampler(Uint unit);
|
||||
|
||||
extern Array<BackendSamplerObject*, MG_State::GLState::TextureState::MAX_TEXTURE_IMAGE_UNITS>
|
||||
g_boundSamplersCache;
|
||||
extern StateBackendObjectRegistry<MG_State::GLState::SamplerObject, BackendSamplerObject>
|
||||
g_backendSamplerObjects;
|
||||
} // namespace SamplerImpl
|
||||
|
||||
namespace RenderbufferImpl {
|
||||
class BackendRenderbufferObject {
|
||||
public:
|
||||
BackendRenderbufferObject();
|
||||
void SyncToBackend(const SharedPtr<MG_State::GLState::RenderbufferObject>& stateRBOObject);
|
||||
Uint GetBackendRenderbufferId() const { return m_backendRBOId; }
|
||||
void Bind() const;
|
||||
|
||||
private:
|
||||
Uint m_backendRBOId = 0;
|
||||
Bool m_isInitialized = false;
|
||||
TextureInternalFormat m_cacheInternalFormat = TextureInternalFormat::Unknown;
|
||||
Int m_cacheWidth = 0;
|
||||
Int m_cacheHeight = 0;
|
||||
};
|
||||
|
||||
extern StateBackendObjectRegistry<MG_State::GLState::RenderbufferObject, BackendRenderbufferObject>
|
||||
g_backendRenderbufferObjects;
|
||||
} // namespace RenderbufferImpl
|
||||
} // namespace MobileGL::MG_Backend::DirectGLES
|
||||
@@ -0,0 +1,224 @@
|
||||
// MobileGL - MobileGL/MG_Backend/DirectGLES/Utils.cpp
|
||||
// Copyright (c) 2025-2026 MobileGL-Dev
|
||||
// Licensed under the GNU Lesser General Public License v3.0:
|
||||
// https://www.gnu.org/licenses/gpl-3.0.txt
|
||||
// https://www.gnu.org/licenses/lgpl-3.0.txt
|
||||
// SPDX-License-Identifier: LGPL-3.0-only
|
||||
// End of Source File Header
|
||||
|
||||
#include "DirectGLES.h"
|
||||
#include "Utils.h"
|
||||
#include "Managers.h"
|
||||
#include "MG_Util/Converters/GLToMG/FramebufferEnumConverter.h"
|
||||
#include "MG_Util/Texture/TextureFormatProcessor.h"
|
||||
|
||||
#include <MG_State/GLState/Core.h>
|
||||
#include <MG_Util/BackendLoaders/OpenGL/Loader.h>
|
||||
#include <MG_Util/Converters/GLToStr/GLEnumConverter.h>
|
||||
#include <MG_Util/Converters/MGToGL/TextureEnumConverter.h>
|
||||
#include <MG_Util/Converters/MGToGL/FramebufferEnumConverter.h>
|
||||
|
||||
namespace MobileGL::MG_Backend::DirectGLES {
|
||||
namespace TextureImpl {
|
||||
void GenerateTextureFormatInfo(TextureInternalFormat internalFormat, GLenum* outInternalFormat,
|
||||
GLenum* outFormat, GLenum* outType) {
|
||||
#ifdef TRACY_ENABLE
|
||||
ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
|
||||
#endif
|
||||
using namespace MobileGL::MG_Util::TextureFormatProcessor;
|
||||
auto options = (g_GLESCapabilities.SupportsNorm16Texture) ? PixelFormatNormalizeOptionBit::None
|
||||
: PixelFormatNormalizeOptionBit::NoNorm16;
|
||||
NormalizePixelFormat(MG_Util::ConvertTextureInternalFormatToGLEnum(internalFormat), options,
|
||||
outInternalFormat, outFormat, outType);
|
||||
}
|
||||
} // namespace TextureImpl
|
||||
namespace PrgramImpl {
|
||||
String ProcessOutColorLocations(const String& glslCode) {
|
||||
#ifdef TRACY_ENABLE
|
||||
ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
|
||||
#endif
|
||||
const static std::regex pattern(R"(\n(out highp vec4 outColor)(\d+);)");
|
||||
const String replacement = "\nlayout(location=$2) $1$2;";
|
||||
return std::regex_replace(glslCode, pattern, replacement);
|
||||
}
|
||||
|
||||
String ForceSupporterOutput(const String& glslCode) {
|
||||
#ifdef TRACY_ENABLE
|
||||
ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
|
||||
#endif
|
||||
Bool hasPrecisionFloat =
|
||||
glslCode.find("precision ") != String::npos && glslCode.find("float;") != String::npos;
|
||||
Bool hasPrecisionInt = glslCode.find("precision ") != String::npos && glslCode.find("int;") != String::npos;
|
||||
|
||||
String result = glslCode;
|
||||
String precisionFloat;
|
||||
String precisionInt;
|
||||
|
||||
if (hasPrecisionFloat && hasPrecisionInt) {
|
||||
std::istringstream iss(result);
|
||||
std::vector<String> lines;
|
||||
String line;
|
||||
while (std::getline(iss, line)) {
|
||||
Bool isPrecisionLine = (line.find("precision ") != String::npos) &&
|
||||
(line.find("float;") != String::npos || line.find("int;") != String::npos);
|
||||
if (!isPrecisionLine) {
|
||||
lines.push_back(line);
|
||||
}
|
||||
}
|
||||
result.clear();
|
||||
for (SizeT i = 0; i < lines.size(); ++i) {
|
||||
if (i != 0) result += '\n';
|
||||
result += lines[i];
|
||||
}
|
||||
precisionFloat = "precision highp float;\n";
|
||||
precisionInt = "precision highp int;\n";
|
||||
} else {
|
||||
precisionFloat = hasPrecisionFloat ? "" : "precision highp float;\n";
|
||||
precisionInt = hasPrecisionInt ? "" : "precision highp int;\n";
|
||||
}
|
||||
|
||||
SizeT lastExtensionPos = result.rfind("#extension");
|
||||
SizeT insertionPos = 0;
|
||||
|
||||
if (lastExtensionPos != String::npos) {
|
||||
SizeT nextNewline = result.find('\n', lastExtensionPos);
|
||||
if (nextNewline != String::npos) {
|
||||
insertionPos = nextNewline + 1;
|
||||
} else {
|
||||
insertionPos = result.length();
|
||||
}
|
||||
} else {
|
||||
SizeT firstNewline = result.find('\n');
|
||||
if (firstNewline != String::npos) {
|
||||
insertionPos = firstNewline + 1;
|
||||
} else {
|
||||
result = precisionFloat + precisionInt + result;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
result.insert(insertionPos, precisionFloat + precisionInt);
|
||||
return result;
|
||||
}
|
||||
|
||||
String RemoveLayoutBinding(const String& glslCode) {
|
||||
#ifdef TRACY_ENABLE
|
||||
ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
|
||||
#endif
|
||||
static std::regex bindingRegex(R"(layout\s*\(\s*binding\s*=\s*\d+\s*\)\s*)");
|
||||
String result = std::regex_replace(glslCode, bindingRegex, "");
|
||||
static std::regex bindingRegex2(R"(layout\s*\(\s*binding\s*=\s*\d+\s*,)");
|
||||
result = std::regex_replace(result, bindingRegex2, "layout(");
|
||||
return result;
|
||||
}
|
||||
} // namespace PrgramImpl
|
||||
|
||||
namespace Utils {
|
||||
void CheckGLESError() {
|
||||
#ifdef TRACY_ENABLE
|
||||
ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
|
||||
#endif
|
||||
while (GLenum err = g_GLESFuncs.glGetError() != GL_NO_ERROR) {
|
||||
MGLOG_E("-> GLES Error: %s", MG_Util::ConvertGLEnumToString(err).c_str());
|
||||
}
|
||||
}
|
||||
|
||||
GLenum GetBindingQuery(GLenum target, bool isTexture) {
|
||||
#ifdef TRACY_ENABLE
|
||||
ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
|
||||
#endif
|
||||
switch (target) {
|
||||
case GL_TEXTURE_BUFFER:
|
||||
return isTexture ? GL_TEXTURE_BINDING_BUFFER : GL_TEXTURE_BUFFER_BINDING;
|
||||
|
||||
case GL_ARRAY_BUFFER:
|
||||
return GL_ARRAY_BUFFER_BINDING;
|
||||
case GL_ATOMIC_COUNTER_BUFFER:
|
||||
return GL_ATOMIC_COUNTER_BUFFER_BINDING;
|
||||
case GL_COPY_READ_BUFFER:
|
||||
return GL_COPY_READ_BUFFER_BINDING;
|
||||
case GL_COPY_WRITE_BUFFER:
|
||||
return GL_COPY_WRITE_BUFFER_BINDING;
|
||||
case GL_DISPATCH_INDIRECT_BUFFER:
|
||||
return GL_DISPATCH_INDIRECT_BUFFER_BINDING;
|
||||
case GL_DRAW_INDIRECT_BUFFER:
|
||||
return GL_DRAW_INDIRECT_BUFFER_BINDING;
|
||||
case GL_ELEMENT_ARRAY_BUFFER:
|
||||
return GL_ELEMENT_ARRAY_BUFFER_BINDING;
|
||||
case GL_PIXEL_PACK_BUFFER:
|
||||
return GL_PIXEL_PACK_BUFFER_BINDING;
|
||||
case GL_PIXEL_UNPACK_BUFFER:
|
||||
return GL_PIXEL_UNPACK_BUFFER_BINDING;
|
||||
case GL_QUERY_BUFFER:
|
||||
return GL_QUERY_BUFFER_BINDING;
|
||||
case GL_SHADER_STORAGE_BUFFER:
|
||||
return GL_SHADER_STORAGE_BUFFER_BINDING;
|
||||
case GL_TRANSFORM_FEEDBACK_BUFFER:
|
||||
return GL_TRANSFORM_FEEDBACK_BUFFER_BINDING;
|
||||
case GL_UNIFORM_BUFFER:
|
||||
return GL_UNIFORM_BUFFER_BINDING;
|
||||
|
||||
case GL_FRAMEBUFFER:
|
||||
case GL_DRAW_FRAMEBUFFER:
|
||||
return GL_DRAW_FRAMEBUFFER_BINDING;
|
||||
case GL_READ_FRAMEBUFFER:
|
||||
return GL_READ_FRAMEBUFFER_BINDING;
|
||||
|
||||
case GL_RENDERBUFFER:
|
||||
return GL_RENDERBUFFER_BINDING;
|
||||
|
||||
case GL_VERTEX_ARRAY:
|
||||
case GL_VERTEX_ARRAY_BINDING:
|
||||
return GL_VERTEX_ARRAY_BINDING;
|
||||
|
||||
case GL_PROGRAM_PIPELINE:
|
||||
return GL_PROGRAM_PIPELINE_BINDING;
|
||||
|
||||
case GL_PROGRAM:
|
||||
return GL_CURRENT_PROGRAM;
|
||||
|
||||
case GL_SAMPLER:
|
||||
return GL_SAMPLER_BINDING;
|
||||
|
||||
case GL_TEXTURE:
|
||||
return GL_TEXTURE_BINDING_2D;
|
||||
case GL_TEXTURE_1D:
|
||||
return GL_TEXTURE_BINDING_1D;
|
||||
case GL_TEXTURE_1D_ARRAY:
|
||||
return GL_TEXTURE_BINDING_1D_ARRAY;
|
||||
case GL_TEXTURE_2D:
|
||||
return GL_TEXTURE_BINDING_2D;
|
||||
case GL_TEXTURE_2D_ARRAY:
|
||||
return GL_TEXTURE_BINDING_2D_ARRAY;
|
||||
case GL_TEXTURE_2D_MULTISAMPLE:
|
||||
return GL_TEXTURE_BINDING_2D_MULTISAMPLE;
|
||||
case GL_TEXTURE_2D_MULTISAMPLE_ARRAY:
|
||||
return GL_TEXTURE_BINDING_2D_MULTISAMPLE_ARRAY;
|
||||
case GL_TEXTURE_3D:
|
||||
return GL_TEXTURE_BINDING_3D;
|
||||
case GL_TEXTURE_CUBE_MAP:
|
||||
return GL_TEXTURE_BINDING_CUBE_MAP;
|
||||
case GL_TEXTURE_CUBE_MAP_ARRAY:
|
||||
return GL_TEXTURE_BINDING_CUBE_MAP_ARRAY;
|
||||
case GL_TEXTURE_RECTANGLE:
|
||||
return GL_TEXTURE_BINDING_RECTANGLE;
|
||||
|
||||
case GL_TRANSFORM_FEEDBACK:
|
||||
return GL_TRANSFORM_FEEDBACK_BINDING;
|
||||
|
||||
case GL_SAMPLES_PASSED:
|
||||
return GL_SAMPLES_PASSED;
|
||||
case GL_PRIMITIVES_GENERATED:
|
||||
return GL_PRIMITIVES_GENERATED;
|
||||
|
||||
case GL_DEBUG_OUTPUT:
|
||||
return GL_DEBUG_OUTPUT;
|
||||
case GL_DEBUG_OUTPUT_SYNCHRONOUS:
|
||||
return GL_DEBUG_OUTPUT_SYNCHRONOUS;
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
} // namespace Utils
|
||||
} // namespace MobileGL::MG_Backend::DirectGLES
|
||||
@@ -0,0 +1,53 @@
|
||||
// MobileGL - MobileGL/MG_Backend/DirectGLES/Utils.h
|
||||
// Copyright (c) 2025-2026 MobileGL-Dev
|
||||
// Licensed under the GNU Lesser General Public License v3.0:
|
||||
// https://www.gnu.org/licenses/gpl-3.0.txt
|
||||
// https://www.gnu.org/licenses/lgpl-3.0.txt
|
||||
// SPDX-License-Identifier: LGPL-3.0-only
|
||||
// End of Source File Header
|
||||
|
||||
#pragma once
|
||||
#include <Includes.h>
|
||||
#include <MG_State/GLState/Core.h>
|
||||
|
||||
namespace MobileGL::MG_Backend::DirectGLES {
|
||||
namespace DebugImpl {
|
||||
class ErrorLopper {
|
||||
public:
|
||||
static void Loop(const std::function<void(GLenum)>&);
|
||||
static void Clear();
|
||||
ErrorLopper();
|
||||
~ErrorLopper();
|
||||
};
|
||||
|
||||
class OpenGLScopeMarker {
|
||||
public:
|
||||
explicit OpenGLScopeMarker(const String& scopeName);
|
||||
~OpenGLScopeMarker();
|
||||
};
|
||||
} // namespace DebugImpl
|
||||
|
||||
namespace BufferImpl {} // namespace BufferImpl
|
||||
|
||||
namespace VertexArrayImpl {
|
||||
GLenum GetBindingQuery(GLenum target, bool isTexture);
|
||||
} // namespace VertexArrayImpl
|
||||
|
||||
namespace TextureImpl {
|
||||
void GenerateTextureFormatInfo(TextureInternalFormat internalFormat, GLenum* outInternalFormat,
|
||||
GLenum* outFormat, GLenum* outType);
|
||||
} // namespace TextureImpl
|
||||
|
||||
namespace FramebufferImpl {} // namespace FramebufferImpl
|
||||
|
||||
namespace PrgramImpl {
|
||||
String ProcessOutColorLocations(const String& glslCode);
|
||||
String ForceSupporterOutput(const String& glslCode);
|
||||
String RemoveLayoutBinding(const String& glslCode);
|
||||
} // namespace PrgramImpl
|
||||
|
||||
namespace Utils {
|
||||
void CheckGLESError();
|
||||
GLenum GetBindingQuery(GLenum target, bool isTexture);
|
||||
} // namespace Utils
|
||||
} // namespace MobileGL::MG_Backend::DirectGLES
|
||||
@@ -0,0 +1,187 @@
|
||||
// MobileGL - MobileGL/MG_Backend/DirectVulkan/BackendObject_DirectVulkan.cpp
|
||||
// Copyright (c) 2025-2026 MobileGL-Dev
|
||||
// Licensed under the GNU Lesser General Public License v3.0:
|
||||
// https://www.gnu.org/licenses/gpl-3.0.txt
|
||||
// https://www.gnu.org/licenses/lgpl-3.0.txt
|
||||
// SPDX-License-Identifier: LGPL-3.0-only
|
||||
// End of Source File Header
|
||||
|
||||
#include "BackendObject_DirectVulkan.h"
|
||||
#include "MG_Backend/BackendObject.h"
|
||||
#include "DirectVulkan.h"
|
||||
|
||||
namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
namespace {
|
||||
Bool IsReleaseCurrentRequest(EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLContext ctx) {
|
||||
return dpy == EGL_NO_DISPLAY && draw == EGL_NO_SURFACE && read == EGL_NO_SURFACE && ctx == EGL_NO_CONTEXT;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
BackendObject_DirectVulkan::~BackendObject_DirectVulkan() = default;
|
||||
|
||||
Bool BackendObject_DirectVulkan::InitWindowSurface() {
|
||||
if (!m_windowHandle.Handle) {
|
||||
MGLOG_E("Cannot initialize DirectVulkan window surface: native window handle is null");
|
||||
return false;
|
||||
}
|
||||
|
||||
auto nativeWindow = reinterpret_cast<NativeWindowType>(m_windowHandle.Handle);
|
||||
|
||||
pVulkanRenderer = MakeUnique<MG_Backend::DirectVulkan::VulkanRenderer>(nativeWindow);
|
||||
MOBILEGL_ASSERT(pVulkanRenderer != nullptr, "InitWindowSurface: VulkanRenderer creation failed");
|
||||
pVulkanRenderer->Initialize();
|
||||
return true;
|
||||
}
|
||||
|
||||
void BackendObject_DirectVulkan::Initialize() {
|
||||
m_initialized = true;
|
||||
}
|
||||
|
||||
Bool BackendObject_DirectVulkan::InitCapabilities() {
|
||||
if (!m_initialized) {
|
||||
MGLOG_E("Cannot initialize capabilities before backend is initialized");
|
||||
return false;
|
||||
}
|
||||
if (!pVulkanRenderer) {
|
||||
MGLOG_E("Cannot initialize capabilities: Vulkan renderer has not been created");
|
||||
return false;
|
||||
}
|
||||
|
||||
MG_Util::BackendLoader::FillInVulkanCapabilities(m_vulkanCaps, pVulkanRenderer->GetPhysicalDevice().properties);
|
||||
UpdateDynamicBackendParameters();
|
||||
return true;
|
||||
}
|
||||
|
||||
Bool BackendObject_DirectVulkan::InitializeEGLDisplay(EGLDisplay dpy, EGLint* major, EGLint* minor) {
|
||||
if (!m_initialized) {
|
||||
MGLOG_E("DirectVulkan backend not initialized");
|
||||
return false;
|
||||
}
|
||||
return BackendObject::InitializeEGLDisplay(dpy, major, minor);
|
||||
}
|
||||
|
||||
Bool BackendObject_DirectVulkan::CreateEGLWindowSurface(const WindowHandle& handle) {
|
||||
const std::lock_guard<std::recursive_mutex> lock(m_eglStateMutex);
|
||||
if (!m_initialized) {
|
||||
MGLOG_E("DirectVulkan backend not initialized");
|
||||
return false;
|
||||
}
|
||||
if (handle.Backend != WindowBackend::Android || !handle.Handle) {
|
||||
MGLOG_E("DirectVulkan backend only supports Android native windows");
|
||||
return false;
|
||||
}
|
||||
|
||||
const Bool sameHandle =
|
||||
m_eglWindowSurfaceInitialized && m_windowHandle.Backend == handle.Backend && m_windowHandle.Handle == handle.Handle;
|
||||
if (sameHandle) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (m_eglWindowSurfaceInitialized || pVulkanRenderer) {
|
||||
pVulkanRenderer.reset();
|
||||
ResetEGLRuntimeState();
|
||||
}
|
||||
|
||||
return BackendObject::CreateEGLWindowSurface(handle);
|
||||
}
|
||||
|
||||
Bool BackendObject_DirectVulkan::MakeEGLCurrent(EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLContext ctx) {
|
||||
const std::lock_guard<std::recursive_mutex> lock(m_eglStateMutex);
|
||||
if (IsReleaseCurrentRequest(dpy, draw, read, ctx)) {
|
||||
return BackendObject::MakeEGLCurrent(dpy, draw, read, ctx);
|
||||
}
|
||||
if (!pVulkanRenderer) {
|
||||
MGLOG_E("DirectVulkan renderer is not initialized");
|
||||
return false;
|
||||
}
|
||||
return BackendObject::MakeEGLCurrent(dpy, draw, read, ctx);
|
||||
}
|
||||
|
||||
Bool BackendObject_DirectVulkan::SwapEGLBuffers(EGLDisplay dpy, EGLSurface draw) {
|
||||
const std::lock_guard<std::recursive_mutex> lock(m_eglStateMutex);
|
||||
if (!pVulkanRenderer) {
|
||||
MGLOG_E("DirectVulkan renderer is not initialized");
|
||||
return false;
|
||||
}
|
||||
return BackendObject::SwapEGLBuffers(dpy, draw);
|
||||
}
|
||||
|
||||
const RendererInfo& BackendObject_DirectVulkan::GetRendererInfo() const {
|
||||
static RendererInfo RendererInfo = {
|
||||
.RendererName = "Magma", // Renderer Name
|
||||
.BackendName = "Direct (Vulkan)", // Backend Name
|
||||
.ExtraVendor = Nullopt, // Extra vendor
|
||||
.RendererGLInfo =
|
||||
{
|
||||
.TargetGLVersion = {3, 3, 0}, // Target OpenGL Version
|
||||
.TargetGLSLVersion = {4, 6, 0}, // Target Shading Language Version
|
||||
.Extensions = {V_OpenGL30, V_OpenGL31, V_OpenGL32, // OpenGL Extensions
|
||||
V_OpenGL33},
|
||||
.IsCompatibilityProfile = false // Is Compatibility Profile
|
||||
},
|
||||
.StaticBackendCapability = {.AllowVSOnlyPrograms = false} // Backend Capability
|
||||
};
|
||||
return RendererInfo;
|
||||
}
|
||||
|
||||
String BackendObject_DirectVulkan::GetBackendAPIVersionString() const {
|
||||
if (!m_initialized) {
|
||||
return "<uninitialized DirectVulkan backend>";
|
||||
}
|
||||
// Format:
|
||||
// <GPU Name>, Vulkan <Vulkan Version>, Driver <Driver Version>
|
||||
String str = m_vulkanCaps.DeviceName + ", Vulkan " + m_vulkanCaps.VulkanAPIVersion.toString() + ", Driver " +
|
||||
m_vulkanCaps.DriverVersionString;
|
||||
return str;
|
||||
}
|
||||
|
||||
BackendType BackendObject_DirectVulkan::GetBackendType() const {
|
||||
return BackendType::DirectVulkan;
|
||||
}
|
||||
|
||||
const GlobalBackendFunctionsTable& BackendObject_DirectVulkan::GetBackendFunctions() const {
|
||||
static GlobalBackendFunctionsTable funcsTable;
|
||||
static Bool funcsTableInitialized = false;
|
||||
if (!funcsTableInitialized) {
|
||||
funcsTable.Present = Present;
|
||||
funcsTable.GL.DrawArrays = DrawArrays;
|
||||
funcsTable.GL.DrawElements = DrawElements;
|
||||
funcsTable.GL.DrawElementsBaseVertex = DrawElementsBaseVertex;
|
||||
funcsTable.GL.MultiDrawElements = MultiDrawElements;
|
||||
funcsTable.GL.MultiDrawElementsBaseVertex = MultiDrawElementsBaseVertex;
|
||||
funcsTable.GL.MultiDrawElementsIndirect = MultiDrawElementsIndirect;
|
||||
funcsTable.GL.MultiDrawArraysIndirect = MultiDrawArraysIndirect;
|
||||
funcsTable.GL.DrawRangeElementsBaseVertex = DrawRangeElementsBaseVertex;
|
||||
funcsTable.GL.DrawRangeElements = DrawRangeElements;
|
||||
funcsTable.GL.DrawElementsInstancedBaseVertexBaseInstance = DrawElementsInstancedBaseVertexBaseInstance;
|
||||
funcsTable.GL.DrawElementsInstancedBaseVertex = DrawElementsInstancedBaseVertex;
|
||||
funcsTable.GL.DrawElementsInstancedBaseInstance = DrawElementsInstancedBaseInstance;
|
||||
funcsTable.GL.DrawElementsInstanced = DrawElementsInstanced;
|
||||
funcsTable.GL.DrawArraysInstancedBaseInstance = DrawArraysInstancedBaseInstance;
|
||||
funcsTable.GL.DrawArraysInstanced = DrawArraysInstanced;
|
||||
funcsTable.GL.DrawElementsIndirect = DrawElementsIndirect;
|
||||
funcsTable.GL.DrawArraysIndirect = DrawArraysIndirect;
|
||||
funcsTable.GL.Clear = Clear;
|
||||
funcsTable.GL.ClearBufferfi = ClearBufferfi;
|
||||
funcsTable.GL.ClearBufferfv = ClearBufferfv;
|
||||
funcsTable.GL.ClearBufferuiv = ClearBufferuiv;
|
||||
funcsTable.GL.ClearBufferiv = ClearBufferiv;
|
||||
funcsTable.GL.BlitFramebuffer = BlitFramebuffer;
|
||||
funcsTable.GL.CopyTexImage2D = CopyTexImage2D;
|
||||
funcsTable.GL.CopyTexSubImage2D = CopyTexSubImage2D;
|
||||
funcsTable.GL.GenerateMipmap = GenerateMipmap;
|
||||
funcsTable.GL.ReadPixels = ReadPixels;
|
||||
funcsTable.GL.GetTexImage = GetTexImage;
|
||||
funcsTableInitialized = true;
|
||||
}
|
||||
return funcsTable;
|
||||
}
|
||||
|
||||
const DynamicBackendParameters& BackendObject_DirectVulkan::GetDynamicParameters() const {
|
||||
return m_dynamicParameters;
|
||||
}
|
||||
|
||||
void BackendObject_DirectVulkan::UpdateDynamicBackendParameters() {
|
||||
m_dynamicParameters.UniformBufferOffsetAlignment = m_vulkanCaps.UniformBufferOffsetAlignment;
|
||||
}
|
||||
} // namespace MobileGL::MG_Backend::DirectVulkan
|
||||
@@ -0,0 +1,40 @@
|
||||
// MobileGL - MobileGL/MG_Backend/DirectVulkan/BackendObject_DirectVulkan.h
|
||||
// Copyright (c) 2025-2026 MobileGL-Dev
|
||||
// Licensed under the GNU Lesser General Public License v3.0:
|
||||
// https://www.gnu.org/licenses/gpl-3.0.txt
|
||||
// https://www.gnu.org/licenses/lgpl-3.0.txt
|
||||
// SPDX-License-Identifier: LGPL-3.0-only
|
||||
// End of Source File Header
|
||||
|
||||
#pragma once
|
||||
#include <Includes.h>
|
||||
#include "../BackendObject.h"
|
||||
#include <MG_Util/BackendLoaders/Vulkan/Loader.h>
|
||||
|
||||
namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
class BackendObject_DirectVulkan : public BackendObject {
|
||||
public:
|
||||
~BackendObject_DirectVulkan() override;
|
||||
|
||||
void Initialize() override;
|
||||
Bool InitWindowSurface() override;
|
||||
Bool InitCapabilities() override;
|
||||
Bool InitializeEGLDisplay(EGLDisplay dpy, EGLint* major, EGLint* minor) override;
|
||||
Bool CreateEGLWindowSurface(const WindowHandle& handle) override;
|
||||
Bool MakeEGLCurrent(EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLContext ctx) override;
|
||||
Bool SwapEGLBuffers(EGLDisplay dpy, EGLSurface draw) override;
|
||||
|
||||
const RendererInfo& GetRendererInfo() const override;
|
||||
String GetBackendAPIVersionString() const override;
|
||||
const GlobalBackendFunctionsTable& GetBackendFunctions() const override;
|
||||
const DynamicBackendParameters& GetDynamicParameters() const override;
|
||||
BackendType GetBackendType() const override;
|
||||
|
||||
private:
|
||||
void UpdateDynamicBackendParameters();
|
||||
|
||||
Bool m_initialized = false;
|
||||
DynamicBackendParameters m_dynamicParameters;
|
||||
MG_External::VulkanCapabilities m_vulkanCaps;
|
||||
};
|
||||
} // namespace MobileGL::MG_Backend::DirectVulkan
|
||||
@@ -0,0 +1,171 @@
|
||||
// MobileGL - MobileGL/MG_Backend/DirectVulkan/DirectVulkan.cpp
|
||||
// Copyright (c) 2025-2026 MobileGL-Dev
|
||||
// Licensed under the GNU Lesser General Public License v3.0:
|
||||
// https://www.gnu.org/licenses/gpl-3.0.txt
|
||||
// https://www.gnu.org/licenses/lgpl-3.0.txt
|
||||
// SPDX-License-Identifier: LGPL-3.0-only
|
||||
// End of Source File Header
|
||||
|
||||
#include "DirectVulkan.h"
|
||||
#include "MG_State/GLState/Core.h"
|
||||
#include "MG_Impl/GLImpl/Framebuffer/GL_Framebuffer.h"
|
||||
|
||||
namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
UniquePtr<VulkanRenderer> pVulkanRenderer = nullptr;
|
||||
|
||||
void ClearBufferfi(GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil) {}
|
||||
void ClearBufferfv(GLenum buffer, GLint drawbuffer, const GLfloat* value) {}
|
||||
void ClearBufferuiv(GLenum buffer, GLint drawbuffer, const GLuint* value) {}
|
||||
void ClearBufferiv(GLenum buffer, GLint drawbuffer, const GLint* value) {}
|
||||
|
||||
void MultiDrawElementsIndirect(GLenum mode, GLenum type, const void* indirect, GLsizei drawcount, GLsizei stride) {}
|
||||
void MultiDrawArraysIndirect(GLenum mode, const void* indirect, GLsizei drawcount, GLsizei stride) {}
|
||||
void DrawRangeElementsBaseVertex(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type,
|
||||
const void* indices, GLint basevertex) {}
|
||||
void DrawRangeElements(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void* indices) {}
|
||||
void DrawElementsInstancedBaseVertexBaseInstance(GLenum mode, GLsizei count, GLenum type, const void* indices,
|
||||
GLsizei instancecount, GLint basevertex, GLuint baseinstance) {}
|
||||
void DrawElementsInstancedBaseVertex(GLenum mode, GLsizei count, GLenum type, const void* indices,
|
||||
GLsizei instancecount, GLint basevertex) {}
|
||||
void DrawElementsInstancedBaseInstance(GLenum mode, GLsizei count, GLenum type, const void* indices,
|
||||
GLsizei instancecount, GLuint baseinstance) {}
|
||||
void DrawElementsInstanced(GLenum mode, GLsizei count, GLenum type, const void* indices, GLsizei instancecount) {}
|
||||
void DrawElementsIndirect(GLenum mode, GLenum type, const void* indirect) {}
|
||||
void DrawArraysInstancedBaseInstance(GLenum mode, GLint first, GLsizei count, GLsizei instancecount,
|
||||
GLuint baseinstance) {}
|
||||
void DrawArraysInstanced(GLenum mode, GLint first, GLsizei count, GLsizei instancecount) {}
|
||||
void DrawArraysIndirect(GLenum mode, const void* indirect) {}
|
||||
void CopyTexImage2D(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width,
|
||||
GLsizei height, GLint border) {}
|
||||
void CopyTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width,
|
||||
GLsizei height) {}
|
||||
void GenerateMipmap(GLenum target) {}
|
||||
void ReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void* pixels) {}
|
||||
void GetTexImage(GLenum target, GLint level, GLenum format, GLenum type, GLvoid* pixels) {}
|
||||
|
||||
void Clear(GLbitfield mask) {
|
||||
MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::Clear called with null VulkanRenderer");
|
||||
MOBILEGL_ASSERT(MG_State::pGLContext, "DirectVulkan::Clear called with null GL context");
|
||||
pVulkanRenderer->Clear(mask);
|
||||
}
|
||||
|
||||
void DrawArrays(GLenum mode, GLint first, GLsizei count) {
|
||||
MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::DrawArrays called with null VulkanRenderer");
|
||||
MOBILEGL_ASSERT(MG_State::pGLContext, "DirectVulkan::DrawArrays called with null GL context");
|
||||
|
||||
DrawCmd payload{};
|
||||
payload.mode = mode;
|
||||
payload.params.firstVertex = first;
|
||||
payload.params.vertexCount = count;
|
||||
|
||||
pVulkanRenderer->DrawArrays(payload);
|
||||
}
|
||||
|
||||
void DrawElements(GLenum mode, GLsizei count, GLenum type, const void* indices) {
|
||||
MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::DrawElements called with null VulkanRenderer");
|
||||
MOBILEGL_ASSERT(MG_State::pGLContext, "DirectVulkan::DrawElements called with null GL context");
|
||||
|
||||
DrawIndexedCmd payload{};
|
||||
payload.mode = mode;
|
||||
payload.indexBufferView.indexType = type;
|
||||
payload.indexBufferView.indexByteOffset = reinterpret_cast<SizeT>(indices);
|
||||
payload.indexBufferView.indexByteSize = count * MG_Util::GetGLTypeSize(type);
|
||||
payload.params.indexCount = count;
|
||||
payload.params.instanceCount = 1;
|
||||
|
||||
pVulkanRenderer->DrawElements(payload);
|
||||
}
|
||||
|
||||
void MultiDrawElements(GLenum mode, const GLsizei* count, GLenum type, const GLvoid* const* indices,
|
||||
GLsizei drawcount) {
|
||||
MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::MultiDrawElements called with null VulkanRenderer");
|
||||
MOBILEGL_ASSERT(MG_State::pGLContext, "DirectVulkan::MultiDrawElements called with null GL context");
|
||||
|
||||
// Vector<DrawElementCmd> cmds;
|
||||
// cmds.reserve(static_cast<SizeT>(drawcount));
|
||||
// for (GLsizei i = 0; i < drawcount; ++i) {
|
||||
// if (count[i] == 0) {
|
||||
// continue;
|
||||
// }
|
||||
//
|
||||
// DrawElementCmd payload{};
|
||||
// payload.mode = mode;
|
||||
// payload.firstVertex = 0;
|
||||
// payload.indexCount = count[i];
|
||||
// payload.indexType = type;
|
||||
// payload.indexByteOffset = reinterpret_cast<SizeT>(indices[i]);
|
||||
// cmds.push_back(payload);
|
||||
// }
|
||||
//
|
||||
// if (cmds.empty()) {
|
||||
// return;
|
||||
// }
|
||||
// pVulkanRenderer->MultiDrawElements(cmds);
|
||||
}
|
||||
|
||||
void DrawElementsBaseVertex(GLenum mode, GLsizei count, GLenum type, const GLvoid* indices, GLint basevertex) {
|
||||
MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::DrawElementsBaseVertex called with null VulkanRenderer");
|
||||
MOBILEGL_ASSERT(MG_State::pGLContext, "DirectVulkan::DrawElementsBaseVertex called with null GL context");
|
||||
DrawIndexedCmd payload{};
|
||||
payload.mode = mode;
|
||||
payload.indexBufferView.indexType = type;
|
||||
payload.indexBufferView.indexByteOffset = reinterpret_cast<SizeT>(indices);
|
||||
payload.indexBufferView.indexByteSize = count * MG_Util::GetGLTypeSize(type);
|
||||
payload.params.indexCount = count;
|
||||
payload.params.instanceCount = 1;
|
||||
payload.params.firstIndex = 0;
|
||||
payload.params.vertexOffset = basevertex;
|
||||
payload.params.firstInstance = 0;
|
||||
pVulkanRenderer->DrawElements(payload);
|
||||
}
|
||||
|
||||
void MultiDrawElementsBaseVertex(GLenum mode, const GLsizei* count, GLenum type, const GLvoid* const* indices,
|
||||
GLsizei drawcount, const GLint* basevertex) {
|
||||
MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::MultiDrawElements called with null VulkanRenderer");
|
||||
MOBILEGL_ASSERT(MG_State::pGLContext, "DirectVulkan::MultiDrawElements called with null GL context");
|
||||
MultiDrawIndexedCmd payload{};
|
||||
payload.mode = mode;
|
||||
payload.indexBufferView.indexType = type;
|
||||
|
||||
// TODO: allocate draw cmd buf elsewhere
|
||||
static Vector<DrawIndexedCmdParam> params;
|
||||
params.clear();
|
||||
params.resize(drawcount);
|
||||
|
||||
for (GLsizei i = 0; i < drawcount; ++i) {
|
||||
if (count[i] == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// TODO: this index view needs a redesign, now there's a lotta redundant uploads
|
||||
|
||||
payload.indexBufferView.indexByteOffset = 0;
|
||||
payload.indexBufferView.indexByteSize =
|
||||
std::max(reinterpret_cast<SizeT>(indices[i]) + count[i] * MG_Util::GetGLTypeSize(type),
|
||||
payload.indexBufferView.indexByteSize);
|
||||
|
||||
auto& param = params[i];
|
||||
|
||||
param.indexCount = count[i];
|
||||
param.instanceCount = 1;
|
||||
param.firstIndex = reinterpret_cast<SizeT>(indices[i]) / MG_Util::GetGLTypeSize(type);
|
||||
param.vertexOffset = basevertex[i];
|
||||
param.firstInstance = 0;
|
||||
}
|
||||
payload.drawCount = drawcount;
|
||||
payload.pParams = params.data();
|
||||
pVulkanRenderer->MultiDrawElements(payload);
|
||||
}
|
||||
|
||||
void BlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1,
|
||||
GLint dstY1, GLbitfield mask, GLenum filter) {
|
||||
MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::BlitFramebuffer called with null VulkanRenderer");
|
||||
MOBILEGL_ASSERT(MG_State::pGLContext, "DirectVulkan::BlitFramebuffer called with null GL context");
|
||||
pVulkanRenderer->BlitFramebuffer(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter);
|
||||
}
|
||||
|
||||
void Present() {
|
||||
MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::Present called with null VulkanRenderer");
|
||||
pVulkanRenderer->Present();
|
||||
}
|
||||
} // namespace MobileGL::MG_Backend::DirectVulkan
|
||||
@@ -0,0 +1,55 @@
|
||||
// MobileGL - MobileGL/MG_Backend/DirectVulkan/DirectVulkan.h
|
||||
// Copyright (c) 2025-2026 MobileGL-Dev
|
||||
// Licensed under the GNU Lesser General Public License v3.0:
|
||||
// https://www.gnu.org/licenses/gpl-3.0.txt
|
||||
// https://www.gnu.org/licenses/lgpl-3.0.txt
|
||||
// SPDX-License-Identifier: LGPL-3.0-only
|
||||
// End of Source File Header
|
||||
|
||||
#pragma once
|
||||
#include <Includes.h>
|
||||
#include "Renderer/VulkanRenderer.h"
|
||||
|
||||
namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
extern UniquePtr<VulkanRenderer> pVulkanRenderer;
|
||||
|
||||
void ClearBufferfi(GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil);
|
||||
void ClearBufferfv(GLenum buffer, GLint drawbuffer, const GLfloat* value);
|
||||
void ClearBufferuiv(GLenum buffer, GLint drawbuffer, const GLuint* value);
|
||||
void ClearBufferiv(GLenum buffer, GLint drawbuffer, const GLint* value);
|
||||
void Clear(GLbitfield mask);
|
||||
void DrawElements(GLenum mode, GLsizei count, GLenum type, const void* indices);
|
||||
void DrawArrays(GLenum mode, GLint first, GLsizei count);
|
||||
void DrawElementsBaseVertex(GLenum mode, GLsizei count, GLenum type, const GLvoid* indices, GLint basevertex);
|
||||
void MultiDrawElements(GLenum mode, const GLsizei* count, GLenum type, const GLvoid* const* indices,
|
||||
GLsizei drawcount);
|
||||
void MultiDrawElementsBaseVertex(GLenum mode, const GLsizei* count, GLenum type, const GLvoid* const* indices,
|
||||
GLsizei drawcount, const GLint* basevertex);
|
||||
void MultiDrawElementsIndirect(GLenum mode, GLenum type, const void* indirect, GLsizei drawcount, GLsizei stride);
|
||||
void MultiDrawArraysIndirect(GLenum mode, const void* indirect, GLsizei drawcount, GLsizei stride);
|
||||
void DrawRangeElementsBaseVertex(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type,
|
||||
const void* indices, GLint basevertex);
|
||||
void DrawRangeElements(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void* indices);
|
||||
void DrawElementsInstancedBaseVertexBaseInstance(GLenum mode, GLsizei count, GLenum type, const void* indices,
|
||||
GLsizei instancecount, GLint basevertex, GLuint baseinstance);
|
||||
void DrawElementsInstancedBaseVertex(GLenum mode, GLsizei count, GLenum type, const void* indices,
|
||||
GLsizei instancecount, GLint basevertex);
|
||||
void DrawElementsInstancedBaseInstance(GLenum mode, GLsizei count, GLenum type, const void* indices,
|
||||
GLsizei instancecount, GLuint baseinstance);
|
||||
void DrawElementsInstanced(GLenum mode, GLsizei count, GLenum type, const void* indices, GLsizei instancecount);
|
||||
void DrawElementsIndirect(GLenum mode, GLenum type, const void* indirect);
|
||||
void DrawArraysInstancedBaseInstance(GLenum mode, GLint first, GLsizei count, GLsizei instancecount,
|
||||
GLuint baseinstance);
|
||||
void DrawArraysInstanced(GLenum mode, GLint first, GLsizei count, GLsizei instancecount);
|
||||
void DrawArraysIndirect(GLenum mode, const void* indirect);
|
||||
void BlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1,
|
||||
GLint dstY1, GLbitfield mask, GLenum filter);
|
||||
void CopyTexImage2D(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width,
|
||||
GLsizei height, GLint border);
|
||||
void CopyTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width,
|
||||
GLsizei height);
|
||||
void GenerateMipmap(GLenum target);
|
||||
void ReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void* pixels);
|
||||
void GetTexImage(GLenum target, GLint level, GLenum format, GLenum type, GLvoid* pixels);
|
||||
void Present();
|
||||
} // namespace MobileGL::MG_Backend::DirectVulkan
|
||||
@@ -0,0 +1,138 @@
|
||||
// MobileGL - MobileGL/MG_Backend/DirectVulkan/Renderer/BufferArena.cpp
|
||||
// Copyright (c) 2025-2026 MobileGL-Dev
|
||||
// Licensed under the GNU Lesser General Public License v3.0:
|
||||
// https://www.gnu.org/licenses/gpl-3.0.txt
|
||||
// https://www.gnu.org/licenses/lgpl-3.0.txt
|
||||
// SPDX-License-Identifier: LGPL-3.0-only
|
||||
// End of Source File Header
|
||||
|
||||
#include "BufferArena.h"
|
||||
|
||||
namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
Bool BufferArena::Initialize(const BufferArenaDesc& desc) {
|
||||
Shutdown();
|
||||
|
||||
MOBILEGL_ASSERT(desc.allocator != nullptr, "BufferArena::Initialize requires valid allocator");
|
||||
MOBILEGL_ASSERT(desc.frameCount > 0, "BufferArena::Initialize requires non-zero frame count");
|
||||
MOBILEGL_ASSERT(desc.usage != 0, "BufferArena::Initialize requires non-zero buffer usage");
|
||||
|
||||
m_desc = desc;
|
||||
m_frames.clear();
|
||||
m_frames.resize(desc.frameCount);
|
||||
m_deferredReleases.resize(desc.frameCount);
|
||||
return true;
|
||||
}
|
||||
|
||||
void BufferArena::Shutdown() {
|
||||
for (auto& frame : m_frames) {
|
||||
frame.buffer.Destroy();
|
||||
frame.writeCursor = 0;
|
||||
}
|
||||
m_frames.clear();
|
||||
m_deferredReleases.clear();
|
||||
m_desc = {};
|
||||
}
|
||||
|
||||
void BufferArena::BeginFrame(Uint32 frameIndex) {
|
||||
CollectDeferredReleases(frameIndex);
|
||||
ResetFrame(frameIndex);
|
||||
}
|
||||
|
||||
void BufferArena::ResetFrame(Uint32 frameIndex) {
|
||||
AssertValidFrameIndex(frameIndex);
|
||||
m_frames[frameIndex].writeCursor = 0;
|
||||
}
|
||||
|
||||
void BufferArena::CollectDeferredReleases(Uint32 frameIndex) {
|
||||
AssertValidFrameIndex(frameIndex);
|
||||
m_deferredReleases[frameIndex].clear();
|
||||
}
|
||||
|
||||
Bool BufferArena::Allocate(Uint32 frameIndex, VkDeviceSize size, VkDeviceSize alignment, BufferSlice& outSlice) {
|
||||
AssertValidFrameIndex(frameIndex);
|
||||
MOBILEGL_ASSERT(size > 0, "BufferArena::Allocate requires non-zero size");
|
||||
|
||||
auto& frame = m_frames[frameIndex];
|
||||
const VkDeviceSize resolvedAlignment = alignment > 0 ? alignment : 1;
|
||||
const VkDeviceSize offset = (frame.writeCursor + resolvedAlignment - 1) & ~(resolvedAlignment - 1);
|
||||
const VkDeviceSize endOffset = offset + size;
|
||||
|
||||
if (!EnsureCapacity(frameIndex, endOffset)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
frame.writeCursor = endOffset;
|
||||
outSlice = frame.buffer.GetSlice(offset, size);
|
||||
return outSlice.IsValid();
|
||||
}
|
||||
|
||||
Bool BufferArena::Upload(Uint32 frameIndex, const void* data, VkDeviceSize size, VkDeviceSize alignment,
|
||||
BufferSlice& outSlice) {
|
||||
MOBILEGL_ASSERT(data != nullptr || size == 0, "BufferArena::Upload data pointer is null");
|
||||
if (!Allocate(frameIndex, size, alignment, outSlice)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (outSlice.mapped != nullptr) {
|
||||
Memcpy(outSlice.mapped, data, static_cast<SizeT>(size));
|
||||
return true;
|
||||
}
|
||||
|
||||
return m_frames[frameIndex].buffer.Upload(data, size, outSlice.offset);
|
||||
}
|
||||
|
||||
VkDeviceSize BufferArena::GetWriteCursor(Uint32 frameIndex) const {
|
||||
AssertValidFrameIndex(frameIndex);
|
||||
return m_frames[frameIndex].writeCursor;
|
||||
}
|
||||
|
||||
Uint32 BufferArena::GetFrameCount() const {
|
||||
return static_cast<Uint32>(m_frames.size());
|
||||
}
|
||||
|
||||
Bool BufferArena::EnsureCapacity(Uint32 frameIndex, VkDeviceSize requiredEndOffset) {
|
||||
AssertValidFrameIndex(frameIndex);
|
||||
auto& frame = m_frames[frameIndex];
|
||||
auto& buffer = frame.buffer;
|
||||
|
||||
if (buffer.IsValid() && buffer.GetSize() >= requiredEndOffset) {
|
||||
return true;
|
||||
}
|
||||
|
||||
VkDeviceSize newCapacity = buffer.IsValid() ? buffer.GetSize() : 0;
|
||||
if (newCapacity < m_desc.minBufferSize) {
|
||||
newCapacity = m_desc.minBufferSize;
|
||||
}
|
||||
if (newCapacity == 0) {
|
||||
newCapacity = requiredEndOffset;
|
||||
}
|
||||
while (newCapacity < requiredEndOffset) {
|
||||
newCapacity *= 2;
|
||||
}
|
||||
|
||||
if (buffer.IsValid()) {
|
||||
m_deferredReleases[frameIndex].push_back(std::move(buffer));
|
||||
}
|
||||
|
||||
VkBufferObjectDesc bufferDesc{};
|
||||
bufferDesc.allocator = m_desc.allocator;
|
||||
bufferDesc.size = newCapacity;
|
||||
bufferDesc.usage = m_desc.usage;
|
||||
bufferDesc.memoryUsage = m_desc.memoryUsage;
|
||||
bufferDesc.allocationFlags = m_desc.allocationFlags;
|
||||
if (!buffer.Create(bufferDesc)) {
|
||||
return false;
|
||||
}
|
||||
if (m_desc.persistentlyMapped && buffer.Map() == nullptr) {
|
||||
buffer.Destroy();
|
||||
return false;
|
||||
}
|
||||
|
||||
frame.writeCursor = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
void BufferArena::AssertValidFrameIndex(Uint32 frameIndex) const {
|
||||
MOBILEGL_ASSERT(frameIndex < m_frames.size(), "BufferArena frame index out of range");
|
||||
}
|
||||
} // namespace MobileGL::MG_Backend::DirectVulkan
|
||||
@@ -0,0 +1,56 @@
|
||||
// MobileGL - MobileGL/MG_Backend/DirectVulkan/Renderer/BufferArena.h
|
||||
// Copyright (c) 2025-2026 MobileGL-Dev
|
||||
// Licensed under the GNU Lesser General Public License v3.0:
|
||||
// https://www.gnu.org/licenses/gpl-3.0.txt
|
||||
// https://www.gnu.org/licenses/lgpl-3.0.txt
|
||||
// SPDX-License-Identifier: LGPL-3.0-only
|
||||
// End of Source File Header
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "BufferSlice.h"
|
||||
#include "VkBufferObject.h"
|
||||
#include "../VkIncludes.h"
|
||||
#include <Includes.h>
|
||||
#include <vk_mem_alloc.h>
|
||||
|
||||
namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
struct BufferArenaDesc {
|
||||
VmaAllocator allocator = nullptr;
|
||||
Uint32 frameCount = 0;
|
||||
VkBufferUsageFlags usage = 0;
|
||||
VmaMemoryUsage memoryUsage = VMA_MEMORY_USAGE_AUTO;
|
||||
VmaAllocationCreateFlags allocationFlags = 0;
|
||||
VkDeviceSize minBufferSize = 0;
|
||||
Bool persistentlyMapped = false;
|
||||
};
|
||||
|
||||
class BufferArena {
|
||||
public:
|
||||
Bool Initialize(const BufferArenaDesc& desc);
|
||||
void Shutdown();
|
||||
|
||||
void BeginFrame(Uint32 frameIndex);
|
||||
void ResetFrame(Uint32 frameIndex);
|
||||
void CollectDeferredReleases(Uint32 frameIndex);
|
||||
|
||||
Bool Allocate(Uint32 frameIndex, VkDeviceSize size, VkDeviceSize alignment, BufferSlice& outSlice);
|
||||
Bool Upload(Uint32 frameIndex, const void* data, VkDeviceSize size, VkDeviceSize alignment, BufferSlice& outSlice);
|
||||
|
||||
VkDeviceSize GetWriteCursor(Uint32 frameIndex) const;
|
||||
Uint32 GetFrameCount() const;
|
||||
|
||||
private:
|
||||
struct FrameResources {
|
||||
VkBufferObject buffer;
|
||||
VkDeviceSize writeCursor = 0;
|
||||
};
|
||||
|
||||
Bool EnsureCapacity(Uint32 frameIndex, VkDeviceSize requiredEndOffset);
|
||||
void AssertValidFrameIndex(Uint32 frameIndex) const;
|
||||
|
||||
BufferArenaDesc m_desc{};
|
||||
Vector<FrameResources> m_frames;
|
||||
Vector<Vector<VkBufferObject>> m_deferredReleases;
|
||||
};
|
||||
} // namespace MobileGL::MG_Backend::DirectVulkan
|
||||
@@ -0,0 +1,23 @@
|
||||
// MobileGL - MobileGL/MG_Backend/DirectVulkan/Renderer/BufferSlice.h
|
||||
// Copyright (c) 2025-2026 MobileGL-Dev
|
||||
// Licensed under the GNU Lesser General Public License v3.0:
|
||||
// https://www.gnu.org/licenses/gpl-3.0.txt
|
||||
// https://www.gnu.org/licenses/lgpl-3.0.txt
|
||||
// SPDX-License-Identifier: LGPL-3.0-only
|
||||
// End of Source File Header
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../VkIncludes.h"
|
||||
#include <Includes.h>
|
||||
|
||||
namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
struct BufferSlice {
|
||||
VkBuffer buffer = VK_NULL_HANDLE;
|
||||
VkDeviceSize offset = 0;
|
||||
VkDeviceSize size = 0;
|
||||
void* mapped = nullptr;
|
||||
|
||||
Bool IsValid() const { return buffer != VK_NULL_HANDLE; }
|
||||
};
|
||||
} // namespace MobileGL::MG_Backend::DirectVulkan
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user