mirror of
https://github.com/MobileGL-Dev/MobileGL
synced 2026-09-08 04:08:32 +09:00
Compare commits
999
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d22d2d64f2 | ||
|
|
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 | ||
|
|
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 | ||
|
|
832fc56a1b | ||
|
|
e77b56c9ad | ||
|
|
ac4cb2217e | ||
|
|
cc2177e36c | ||
|
|
ac6827fdd8 | ||
|
|
3c30d3aba9 | ||
|
|
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 | ||
|
|
2466897531 | ||
|
|
604482d55c | ||
|
|
906323f219 | ||
|
|
13022c79bf |
@@ -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
|
||||||
+144
@@ -0,0 +1,144 @@
|
|||||||
|
#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-lambda-function-name,
|
||||||
|
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-pro-type-static-cast-downcast,
|
||||||
|
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
|
||||||
+16
@@ -3,3 +3,19 @@
|
|||||||
################################################################################
|
################################################################################
|
||||||
|
|
||||||
/build
|
/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*
|
||||||
+21
@@ -0,0 +1,21 @@
|
|||||||
|
[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
|
||||||
+1
Submodule 3rdparty/DiligentCore added at f36e638805
+1
Submodule 3rdparty/SPIRV-Cross added at 072444287f
+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
+354
-97
@@ -2,123 +2,380 @@ cmake_minimum_required(VERSION 3.22.1)
|
|||||||
|
|
||||||
project("MobileGL")
|
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)
|
enable_language(CXX)
|
||||||
|
|
||||||
set(CMAKE_CXX_STANDARD 20)
|
set(CMAKE_CXX_STANDARD 23)
|
||||||
|
|
||||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
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)
|
||||||
|
|
||||||
|
# add_subdirectory(3rdparty/DiligentCore)
|
||||||
|
add_subdirectory(3rdparty/glslang)
|
||||||
|
add_subdirectory(3rdparty/SPIRV-Cross)
|
||||||
|
add_subdirectory(3rdparty/VulkanMemoryAllocator)
|
||||||
|
|
||||||
|
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/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/UniformDescriptorBinder.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/VkFramebufferManager.cpp
|
||||||
|
MobileGL/MG_Backend/DirectVulkan/Renderer/VkRenderPassManager.cpp
|
||||||
|
MobileGL/MG_Backend/DirectVulkan/Renderer/VkTextureSamplerManager.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
|
||||||
|
)
|
||||||
|
|
||||||
|
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
|
add_library(${CMAKE_PROJECT_NAME} SHARED
|
||||||
MG/Init.cpp
|
${SOURCE_FILES}
|
||||||
|
|
||||||
# MG_GL/Implementations/GLX
|
|
||||||
MG/MG_GL/Implementations/GLX/GLXFuncsDefinitions/GLXFuncsDefinitions.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
|
|
||||||
)
|
)
|
||||||
|
|
||||||
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}
|
target_link_libraries(${CMAKE_PROJECT_NAME}
|
||||||
${CMAKE_SOURCE_DIR}/library/arm64-v8a/libglslang.a
|
PUBLIC
|
||||||
${CMAKE_SOURCE_DIR}/library/arm64-v8a/libspirv-cross-c-shared.so
|
${MOBILEGL_LINK_LIBRARIES}
|
||||||
#${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
|
|
||||||
)
|
)
|
||||||
|
|
||||||
target_include_directories(MobileGL PUBLIC
|
target_compile_definitions(${CMAKE_PROJECT_NAME}
|
||||||
${CMAKE_SOURCE_DIR}/include
|
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)
|
target_link_libraries(${CMAKE_PROJECT_NAME}_s
|
||||||
find_package(Threads)
|
PUBLIC
|
||||||
include_directories(${CMAKE_SOURCE_DIR}/3rdparty/perfetto/sdk)
|
${MOBILEGL_LINK_LIBRARIES}
|
||||||
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_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()
|
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
|
This project is licensed under the GNU Lesser General Public License v3.0.
|
||||||
Version 2.1, February 1999
|
See COPYING and COPYING.LESSER for the full text of the LGPLv3 license.
|
||||||
|
|
||||||
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.
|
|
||||||
|
|||||||
-192
@@ -1,192 +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 constexpr int LOG_LEVEL_DEBUG = 0x0010;
|
|
||||||
inline constexpr int LOG_LEVEL_WARN = 0x0011;
|
|
||||||
inline constexpr int LOG_LEVEL_ERROR = 0x0012;
|
|
||||||
inline constexpr int LOG_LEVEL_INFO = 0x0013;
|
|
||||||
inline constexpr int LOG_LEVEL_FATAL = 0x0014;
|
|
||||||
|
|
||||||
|
|
||||||
inline constexpr int LOG_TARGET_NONE = 0x00;
|
|
||||||
inline constexpr int LOG_TARGET_CONSOLE = 0x01;
|
|
||||||
inline constexpr int LOG_TARGET_FILE = 0x02;
|
|
||||||
inline constexpr int LOG_TARGET_ANDROID = 0x04; // Android logcat
|
|
||||||
inline constexpr int LOG_TARGET_ALL = LOG_TARGET_CONSOLE | LOG_TARGET_FILE | LOG_TARGET_ANDROID;
|
|
||||||
}
|
|
||||||
|
|
||||||
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
|
|
||||||
-41
@@ -1,41 +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 = "-Dev";
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
inline constexpr int LogTarget = MG_Constants::Common::LOG_TARGET_ALL;
|
|
||||||
|
|
||||||
#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
|
|
||||||
-140
@@ -1,140 +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"
|
|
||||||
|
|
||||||
#ifdef _WIN32
|
|
||||||
#include <Windows.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#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>
|
|
||||||
-46
@@ -1,46 +0,0 @@
|
|||||||
//
|
|
||||||
// Created by BZLZHH on 2025/3/15.
|
|
||||||
//
|
|
||||||
|
|
||||||
#include "Includes.h"
|
|
||||||
|
|
||||||
void MG_Initialize() {
|
|
||||||
MG_Util::Debug::LogInit();
|
|
||||||
MG_Util::Debug::LogI("MobileGL Initializing...");
|
|
||||||
MG_State::Init();
|
|
||||||
MG_GL::BackendLoader::Init();
|
|
||||||
}
|
|
||||||
|
|
||||||
void MG_Destroy() {
|
|
||||||
MG_Util::Debug::LogI("MobileGL Exiting...");
|
|
||||||
MG_State::Destroy();
|
|
||||||
}
|
|
||||||
|
|
||||||
#if defined(__linux__) || defined(__APPLE__)
|
|
||||||
__attribute__((constructor)) static void AutoInit() {
|
|
||||||
MG_Initialize();
|
|
||||||
}
|
|
||||||
|
|
||||||
__attribute__((destructor)) static void AutoDestroy() {
|
|
||||||
MG_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:
|
|
||||||
MG_Initialize();
|
|
||||||
break;
|
|
||||||
|
|
||||||
case DLL_PROCESS_DETACH:
|
|
||||||
MG_Destroy();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
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,113 +0,0 @@
|
|||||||
//
|
|
||||||
// Created by BZLZHH on 2025/3/15.
|
|
||||||
//
|
|
||||||
|
|
||||||
#include "GL_Common.h"
|
|
||||||
|
|
||||||
namespace MG_GL::GL {
|
|
||||||
void Clear(GLbitfield mask) {
|
|
||||||
MG_Util::Debug::LogD("glClear, mask: 0x%X", mask);
|
|
||||||
GLenum result = MG_State::glClear(mask);
|
|
||||||
if (result == GL_NO_ERROR) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
MG_State::SetError(result);
|
|
||||||
MG_Util::Debug::LogE("Error clearing buffers: %s", MG_Util::Debug::GLEnumToString(result));
|
|
||||||
}
|
|
||||||
|
|
||||||
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
|
|
||||||
@@ -1,31 +0,0 @@
|
|||||||
//
|
|
||||||
// Created by BZLZHH on 2025/3/15.
|
|
||||||
//
|
|
||||||
|
|
||||||
#include "GL_Drawing.h"
|
|
||||||
|
|
||||||
namespace MG_GL::GL {
|
|
||||||
void DrawElements(GLenum mode, GLsizei count, GLenum type, const void *indices) {
|
|
||||||
// TODO
|
|
||||||
}
|
|
||||||
|
|
||||||
void DrawArrays(GLenum mode, GLint first, GLsizei count) {
|
|
||||||
// TODO
|
|
||||||
}
|
|
||||||
|
|
||||||
void DrawElementsBaseVertex(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices, GLint basevertex) {
|
|
||||||
// TODO
|
|
||||||
}
|
|
||||||
|
|
||||||
void MultiDrawElements(GLenum mode, const GLsizei *count, GLenum type, const GLvoid *const *indices, GLsizei drawcount) {
|
|
||||||
// TODO
|
|
||||||
}
|
|
||||||
|
|
||||||
void MultiDrawElementsBaseVertex(GLenum mode, const GLsizei *count, GLenum type, const GLvoid *const *indices, GLsizei drawcount, const GLint *basevertex) {
|
|
||||||
// TODO
|
|
||||||
}
|
|
||||||
|
|
||||||
void DrawBuffer(GLenum buf) {
|
|
||||||
// TODO
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,18 +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,73 +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;
|
|
||||||
}
|
|
||||||
|
|
||||||
void BlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
|
|
||||||
GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter) {
|
|
||||||
// TODO
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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,13 +0,0 @@
|
|||||||
//
|
|
||||||
// Created by Swung 0x48 on 2025/6/20.
|
|
||||||
//
|
|
||||||
|
|
||||||
#include "GLXFuncsDefinitions.h"
|
|
||||||
|
|
||||||
MG_EXPORT void* glXGetProcAddress(const char *name) {
|
|
||||||
return MG_GL::GLX::GetProcAddress(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
MG_EXPORT void* glXGetProcAddressARB(const char *name) {
|
|
||||||
return MG_GL::GLX::GetProcAddressARB(name);
|
|
||||||
}
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
//
|
|
||||||
// Created by Swung 0x48 on 2025/6/20.
|
|
||||||
//
|
|
||||||
|
|
||||||
#ifndef MOBILEGL_GLX_FUNCS_DEFINITIONS_H
|
|
||||||
#define MOBILEGL_GLX_FUNCS_DEFINITIONS_H
|
|
||||||
|
|
||||||
#include "../../../../Includes.h"
|
|
||||||
|
|
||||||
#endif //MOBILEGL_GLX_FUNCS_DEFINITIONS_H
|
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
//
|
|
||||||
// Created by BZLZHH on 2025/3/15.
|
|
||||||
//
|
|
||||||
|
|
||||||
#include "LookUp.h"
|
|
||||||
|
|
||||||
#include "../../../../Includes.h"
|
|
||||||
|
|
||||||
namespace MG_GL::GLX {
|
|
||||||
void* GetProcAddress(const char *name) {
|
|
||||||
MG_Util::Debug::LogD("glXGetProcAddress(\"%s\")", 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, 2, 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_INFO
|
||||||
|
|
||||||
|
#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();
|
||||||
|
delete MG_State::pGLContext;
|
||||||
|
delete MG_State::pEGLContext;
|
||||||
|
delete MG_Impl::GLImpl::TextureImpl::pProxyTextureManager;
|
||||||
|
delete MG_Impl::GLImpl::FramebufferImpl::pDefaultFramebufferInfo;
|
||||||
|
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,229 @@
|
|||||||
|
// 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 {
|
||||||
|
namespace BufferImpl {
|
||||||
|
const GLenum TempBufferTarget = GL_ARRAY_BUFFER;
|
||||||
|
class BackendBufferObject {
|
||||||
|
public:
|
||||||
|
BackendBufferObject();
|
||||||
|
void SyncToBackend(SharedPtr<MG_State::GLState::BufferObject>& stateBufferObject);
|
||||||
|
Uint GetBackendBufferId() { return m_backendBufferId; }
|
||||||
|
void Bind(GLenum target = TempBufferTarget);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void SyncToBackend_glBufferData(SharedPtr<MG_State::GLState::BufferObject>& stateBufferObject);
|
||||||
|
void SyncToBackend_glBufferSubData(SharedPtr<MG_State::GLState::BufferObject>& stateBufferObject);
|
||||||
|
void SyncToBackend_glMapBufferRange(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 UnorderedMap<SharedPtr<MG_State::GLState::BufferObject>, SharedPtr<BackendBufferObject>>
|
||||||
|
g_backendBufferObjects;
|
||||||
|
} // namespace BufferImpl
|
||||||
|
|
||||||
|
namespace VertexArrayImpl {
|
||||||
|
class BackendVertexArrayObject {
|
||||||
|
public:
|
||||||
|
BackendVertexArrayObject();
|
||||||
|
void SyncToBackend(SharedPtr<MG_State::GLState::VertexArrayObject>& stateVAOObject);
|
||||||
|
Uint GetBackendVertexArrayId() { return m_backendVAOId; }
|
||||||
|
void Bind();
|
||||||
|
|
||||||
|
private:
|
||||||
|
void BindAttributeBuffer(Uint index, const MG_State::GLState::VertexAttribute& attrib);
|
||||||
|
|
||||||
|
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 UnorderedMap<SharedPtr<MG_State::GLState::VertexArrayObject>, SharedPtr<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(SharedPtr<MG_State::GLState::ITextureObject>& stateTextureObject);
|
||||||
|
void SyncBuiltinSamplerToBackend(SharedPtr<MG_State::GLState::ITextureObject>& stateTextureObject);
|
||||||
|
void SyncTextureParamsToBackend(SharedPtr<MG_State::GLState::ITextureObject>& stateTextureObject);
|
||||||
|
void Bind(GLenum target, Uint unit = TempTextureUnit);
|
||||||
|
Uint GetBackendTextureId();
|
||||||
|
|
||||||
|
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 UnorderedMap<SharedPtr<MG_State::GLState::ITextureObject>, SharedPtr<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(SharedPtr<MG_State::GLState::FramebufferObject>& stateFBOObject,
|
||||||
|
FramebufferTarget asTarget);
|
||||||
|
Uint GetBackendFramebufferId() { return m_backendFBOId; }
|
||||||
|
void Bind(FramebufferTarget target);
|
||||||
|
bool SyncAttachmentObject(GLenum glFBOTarget,
|
||||||
|
const MG_State::GLState::FramebufferAttachmentObject& attachmentObject,
|
||||||
|
GLenum glBackendAttachment);
|
||||||
|
// 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 UnorderedMap<SharedPtr<MG_State::GLState::FramebufferObject>, SharedPtr<BackendFramebufferObject>>
|
||||||
|
g_backendFramebufferObjects;
|
||||||
|
extern Array<Uint16, SizeT(FramebufferTarget::FramebufferTargetCount)> g_fboBindVersions;
|
||||||
|
} // namespace FramebufferImpl
|
||||||
|
|
||||||
|
namespace PrgramImpl {
|
||||||
|
class BackendProgramObjectImpl {
|
||||||
|
public:
|
||||||
|
BackendProgramObjectImpl();
|
||||||
|
~BackendProgramObjectImpl();
|
||||||
|
void SyncToBackend(SharedPtr<MG_State::GLState::ProgramObject>& stateProgramObject);
|
||||||
|
void Use();
|
||||||
|
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 UnorderedMap<SharedPtr<MG_State::GLState::ProgramObject>, SharedPtr<BackendProgramObjectImpl>>
|
||||||
|
g_backendProgramObjects;
|
||||||
|
} // namespace PrgramImpl
|
||||||
|
|
||||||
|
namespace SamplerImpl {
|
||||||
|
class BackendSamplerObject {
|
||||||
|
public:
|
||||||
|
BackendSamplerObject();
|
||||||
|
void SyncToBackend(SharedPtr<MG_State::GLState::SamplerObject>& stateSamplerObject);
|
||||||
|
void Bind(Uint unit);
|
||||||
|
Uint GetBackendSamplerId();
|
||||||
|
|
||||||
|
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 UnorderedMap<SharedPtr<MG_State::GLState::SamplerObject>, SharedPtr<BackendSamplerObject>>
|
||||||
|
g_backendSamplerObjects;
|
||||||
|
} // namespace SamplerImpl
|
||||||
|
|
||||||
|
namespace RenderbufferImpl {
|
||||||
|
class BackendRenderbufferObject {
|
||||||
|
public:
|
||||||
|
BackendRenderbufferObject();
|
||||||
|
void SyncToBackend(const SharedPtr<MG_State::GLState::RenderbufferObject>& stateRBOObject);
|
||||||
|
Uint GetBackendRenderbufferId() { return m_backendRBOId; }
|
||||||
|
void Bind();
|
||||||
|
|
||||||
|
private:
|
||||||
|
Uint m_backendRBOId = 0;
|
||||||
|
Bool m_isInitialized = false;
|
||||||
|
TextureInternalFormat m_cacheInternalFormat = TextureInternalFormat::Unknown;
|
||||||
|
Int m_cacheWidth = 0;
|
||||||
|
Int m_cacheHeight = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern UnorderedMap<SharedPtr<MG_State::GLState::RenderbufferObject>, SharedPtr<BackendRenderbufferObject>>
|
||||||
|
g_backendRenderbufferObjects;
|
||||||
|
} // namespace RenderbufferImpl
|
||||||
|
} // namespace MobileGL::MG_Backend::DirectGLES
|
||||||
@@ -0,0 +1,233 @@
|
|||||||
|
// 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 BufferImpl {} // namespace BufferImpl
|
||||||
|
|
||||||
|
namespace VertexArrayImpl {} // namespace VertexArrayImpl
|
||||||
|
|
||||||
|
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 FramebufferImpl {} // namespace FramebufferImpl
|
||||||
|
|
||||||
|
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:
|
||||||
|
return GL_FRAMEBUFFER_BINDING;
|
||||||
|
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:
|
||||||
|
return GL_VERTEX_ARRAY_BINDING;
|
||||||
|
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:
|
||||||
|
void Loop(std::function<void(GLenum)>);
|
||||||
|
void Clear();
|
||||||
|
ErrorLopper();
|
||||||
|
~ErrorLopper();
|
||||||
|
};
|
||||||
|
|
||||||
|
class OpenGLScopeMarker {
|
||||||
|
public:
|
||||||
|
explicit OpenGLScopeMarker(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,186 @@
|
|||||||
|
// 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);
|
||||||
|
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,460 @@
|
|||||||
|
// 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 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");
|
||||||
|
|
||||||
|
if (count < 0) {
|
||||||
|
MGLOG_W("DrawElementsBaseVertex skipped: count (%d) must be non-negative", count);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (count == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (mode != GL_TRIANGLES) {
|
||||||
|
MGLOG_W("DrawElementsBaseVertex skipped: primitive mode %u is not supported yet", mode);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
SizeT indexSize = 0;
|
||||||
|
switch (type) {
|
||||||
|
case GL_UNSIGNED_SHORT:
|
||||||
|
indexSize = sizeof(Uint16);
|
||||||
|
break;
|
||||||
|
case GL_UNSIGNED_INT:
|
||||||
|
indexSize = sizeof(Uint32);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
MGLOG_W("DrawElementsBaseVertex skipped: index type %u is not supported yet", type);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto vao = MG_State::pGLContext->GetBoundVertexArray();
|
||||||
|
if (!vao) {
|
||||||
|
MGLOG_W("DrawElementsBaseVertex skipped: no bound VAO");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto indexBuffer = vao->GetIndexBufferBindingSlot().GetBoundObject();
|
||||||
|
if (!indexBuffer) {
|
||||||
|
MGLOG_W("DrawElementsBaseVertex skipped: no bound ELEMENT_ARRAY_BUFFER");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto indexData = indexBuffer->GetDataReadOnly();
|
||||||
|
if (!indexData || indexData->empty()) {
|
||||||
|
MGLOG_W("DrawElementsBaseVertex skipped: ELEMENT_ARRAY_BUFFER has no data");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const SizeT byteOffset = reinterpret_cast<SizeT>(indices);
|
||||||
|
const SizeT requiredBytes = static_cast<SizeT>(count) * indexSize;
|
||||||
|
if (byteOffset + requiredBytes > indexBuffer->GetSize()) {
|
||||||
|
MGLOG_W("DrawElementsBaseVertex skipped: index range out of bounds (offset=%zu, size=%zu, buffer=%zu)",
|
||||||
|
byteOffset, requiredBytes, indexBuffer->GetSize());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
DrawElementPayload payload{};
|
||||||
|
payload.drawArray.mode = mode;
|
||||||
|
payload.drawArray.first = 0;
|
||||||
|
payload.drawArray.count = count;
|
||||||
|
const auto currentProgram = MG_State::pGLContext->GetCurrentProgram();
|
||||||
|
payload.drawArray.program = currentProgram ? currentProgram.get() : nullptr;
|
||||||
|
payload.drawArray.vertexArray = vao.get();
|
||||||
|
payload.indexType = type;
|
||||||
|
payload.indexByteOffset = byteOffset;
|
||||||
|
payload.baseVertex = basevertex;
|
||||||
|
|
||||||
|
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::MultiDrawElementsBaseVertex called with null VulkanRenderer");
|
||||||
|
MOBILEGL_ASSERT(MG_State::pGLContext, "DirectVulkan::MultiDrawElementsBaseVertex called with null GL context");
|
||||||
|
|
||||||
|
if (drawcount < 0) {
|
||||||
|
MGLOG_W("MultiDrawElementsBaseVertex skipped: drawcount (%d) must be non-negative", drawcount);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (drawcount == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!count || !indices || !basevertex) {
|
||||||
|
MGLOG_W("MultiDrawElementsBaseVertex skipped: count/indices/basevertex pointer is null");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (mode != GL_TRIANGLES) {
|
||||||
|
MGLOG_W("MultiDrawElementsBaseVertex skipped: primitive mode %u is not supported yet", mode);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
SizeT indexSize = 0;
|
||||||
|
switch (type) {
|
||||||
|
case GL_UNSIGNED_SHORT:
|
||||||
|
indexSize = sizeof(Uint16);
|
||||||
|
break;
|
||||||
|
case GL_UNSIGNED_INT:
|
||||||
|
indexSize = sizeof(Uint32);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
MGLOG_W("MultiDrawElementsBaseVertex skipped: index type %u is not supported yet", type);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto vao = MG_State::pGLContext->GetBoundVertexArray();
|
||||||
|
if (!vao) {
|
||||||
|
MGLOG_W("MultiDrawElementsBaseVertex skipped: no bound VAO");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto indexBuffer = vao->GetIndexBufferBindingSlot().GetBoundObject();
|
||||||
|
if (!indexBuffer) {
|
||||||
|
MGLOG_W("MultiDrawElementsBaseVertex skipped: no bound ELEMENT_ARRAY_BUFFER");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto indexData = indexBuffer->GetDataReadOnly();
|
||||||
|
if (!indexData || indexData->empty()) {
|
||||||
|
MGLOG_W("MultiDrawElementsBaseVertex skipped: ELEMENT_ARRAY_BUFFER has no data");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto currentProgram = MG_State::pGLContext->GetCurrentProgram();
|
||||||
|
Vector<DrawElementPayload> payloads;
|
||||||
|
payloads.reserve(static_cast<SizeT>(drawcount));
|
||||||
|
for (GLsizei i = 0; i < drawcount; ++i) {
|
||||||
|
if (count[i] < 0) {
|
||||||
|
MGLOG_W("MultiDrawElementsBaseVertex skipped: count[%d] (%d) must be non-negative", i, count[i]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (count[i] == 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const SizeT byteOffset = reinterpret_cast<SizeT>(indices[i]);
|
||||||
|
const SizeT requiredBytes = static_cast<SizeT>(count[i]) * indexSize;
|
||||||
|
if (byteOffset + requiredBytes > indexBuffer->GetSize()) {
|
||||||
|
MGLOG_W("MultiDrawElementsBaseVertex skipped: draw[%d] index range out of bounds (offset=%zu, "
|
||||||
|
"size=%zu, buffer=%zu)",
|
||||||
|
i, byteOffset, requiredBytes, indexBuffer->GetSize());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
DrawElementPayload payload{};
|
||||||
|
payload.drawArray.mode = mode;
|
||||||
|
payload.drawArray.first = 0;
|
||||||
|
payload.drawArray.count = count[i];
|
||||||
|
payload.drawArray.program = currentProgram ? currentProgram.get() : nullptr;
|
||||||
|
payload.drawArray.vertexArray = vao.get();
|
||||||
|
payload.indexType = type;
|
||||||
|
payload.indexByteOffset = byteOffset;
|
||||||
|
payload.baseVertex = basevertex[i];
|
||||||
|
payloads.push_back(payload);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (payloads.empty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
pVulkanRenderer->MultiDrawElements(payloads);
|
||||||
|
}
|
||||||
|
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 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");
|
||||||
|
|
||||||
|
if (drawcount < 0) {
|
||||||
|
MGLOG_W("MultiDrawElements skipped: drawcount (%d) must be non-negative", drawcount);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (drawcount == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!count || !indices) {
|
||||||
|
MGLOG_W("MultiDrawElements skipped: count/indices pointer is null");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (mode != GL_TRIANGLES) {
|
||||||
|
MGLOG_W("MultiDrawElements skipped: primitive mode %u is not supported yet", mode);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
SizeT indexSize = 0;
|
||||||
|
switch (type) {
|
||||||
|
case GL_UNSIGNED_SHORT:
|
||||||
|
indexSize = sizeof(Uint16);
|
||||||
|
break;
|
||||||
|
case GL_UNSIGNED_INT:
|
||||||
|
indexSize = sizeof(Uint32);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
MGLOG_W("MultiDrawElements skipped: index type %u is not supported yet", type);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto vao = MG_State::pGLContext->GetBoundVertexArray();
|
||||||
|
if (!vao) {
|
||||||
|
MGLOG_W("MultiDrawElements skipped: no bound VAO");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto indexBuffer = vao->GetIndexBufferBindingSlot().GetBoundObject();
|
||||||
|
if (!indexBuffer) {
|
||||||
|
MGLOG_W("MultiDrawElements skipped: no bound ELEMENT_ARRAY_BUFFER");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto indexData = indexBuffer->GetDataReadOnly();
|
||||||
|
if (!indexData || indexData->empty()) {
|
||||||
|
MGLOG_W("MultiDrawElements skipped: ELEMENT_ARRAY_BUFFER has no data");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto currentProgram = MG_State::pGLContext->GetCurrentProgram();
|
||||||
|
Vector<DrawElementPayload> payloads;
|
||||||
|
payloads.reserve(static_cast<SizeT>(drawcount));
|
||||||
|
for (GLsizei i = 0; i < drawcount; ++i) {
|
||||||
|
if (count[i] < 0) {
|
||||||
|
MGLOG_W("MultiDrawElements skipped: count[%d] (%d) must be non-negative", i, count[i]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (count[i] == 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto byteOffset = reinterpret_cast<SizeT>(indices[i]);
|
||||||
|
const SizeT requiredBytes = static_cast<SizeT>(count[i]) * indexSize;
|
||||||
|
if (byteOffset + requiredBytes > indexBuffer->GetSize()) {
|
||||||
|
MGLOG_W("MultiDrawElements skipped: draw[%d] index range out of bounds (offset=%zu, size=%zu, "
|
||||||
|
"buffer=%zu)",
|
||||||
|
i, byteOffset, requiredBytes, indexBuffer->GetSize());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
DrawElementPayload payload{};
|
||||||
|
payload.drawArray.mode = mode;
|
||||||
|
payload.drawArray.first = 0;
|
||||||
|
payload.drawArray.count = count[i];
|
||||||
|
payload.drawArray.program = currentProgram ? currentProgram.get() : nullptr;
|
||||||
|
payload.drawArray.vertexArray = vao.get();
|
||||||
|
payload.indexType = type;
|
||||||
|
payload.indexByteOffset = byteOffset;
|
||||||
|
payloads.push_back(payload);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (payloads.empty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
pVulkanRenderer->MultiDrawElements(payloads);
|
||||||
|
}
|
||||||
|
|
||||||
|
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");
|
||||||
|
|
||||||
|
const auto& drawFboSlot = MG_State::pGLContext->GetFramebufferBindingSlot(FramebufferTarget::Draw);
|
||||||
|
const auto drawFbo = drawFboSlot.GetBoundObject();
|
||||||
|
const auto defaultFboInfo = MG_Impl::GLImpl::FramebufferImpl::pDefaultFramebufferInfo;
|
||||||
|
const auto defaultFbo = defaultFboInfo ? defaultFboInfo->defaultFBO : nullptr;
|
||||||
|
const Bool isDefaultFboTarget = (drawFbo == defaultFbo) || (drawFbo == nullptr && defaultFbo != nullptr);
|
||||||
|
Uint drawFboExternalIndex = 0;
|
||||||
|
if (drawFbo) {
|
||||||
|
drawFboExternalIndex = drawFbo->GetExternalIndex();
|
||||||
|
} else if (defaultFbo) {
|
||||||
|
drawFboExternalIndex = defaultFbo->GetExternalIndex();
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto& clearColor = MG_State::pGLContext->GetClearColor();
|
||||||
|
const auto clearDepth = MG_State::pGLContext->GetClearDepth();
|
||||||
|
const auto clearStencil = static_cast<Uint32>(MG_State::pGLContext->GetClearStencil());
|
||||||
|
pVulkanRenderer->RequestClear(mask, clearColor, clearDepth, clearStencil, drawFboExternalIndex,
|
||||||
|
isDefaultFboTarget);
|
||||||
|
}
|
||||||
|
|
||||||
|
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");
|
||||||
|
|
||||||
|
if (count < 0) {
|
||||||
|
MGLOG_W("DrawElements skipped: count (%d) must be non-negative", count);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (count == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mode != GL_TRIANGLES) {
|
||||||
|
MGLOG_W("DrawElements skipped: primitive mode %u is not supported yet", mode);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
SizeT indexSize = 0;
|
||||||
|
switch (type) {
|
||||||
|
case GL_UNSIGNED_SHORT:
|
||||||
|
indexSize = sizeof(Uint16);
|
||||||
|
break;
|
||||||
|
case GL_UNSIGNED_INT:
|
||||||
|
indexSize = sizeof(Uint32);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
MGLOG_W("DrawElements skipped: index type %u is not supported yet", type);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto vao = MG_State::pGLContext->GetBoundVertexArray();
|
||||||
|
if (!vao) {
|
||||||
|
MGLOG_W("DrawElements skipped: no bound VAO");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto indexBuffer = vao->GetIndexBufferBindingSlot().GetBoundObject();
|
||||||
|
if (!indexBuffer) {
|
||||||
|
MGLOG_W("DrawElements skipped: no bound ELEMENT_ARRAY_BUFFER");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto indexData = indexBuffer->GetDataReadOnly();
|
||||||
|
if (!indexData || indexData->empty()) {
|
||||||
|
MGLOG_W("DrawElements skipped: ELEMENT_ARRAY_BUFFER has no data");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto byteOffset = reinterpret_cast<SizeT>(indices);
|
||||||
|
const SizeT requiredBytes = static_cast<SizeT>(count) * indexSize;
|
||||||
|
if (byteOffset + requiredBytes > indexBuffer->GetSize()) {
|
||||||
|
MGLOG_W("DrawElements skipped: index range out of bounds (offset=%zu, size=%zu, buffer=%zu)", byteOffset,
|
||||||
|
requiredBytes, indexBuffer->GetSize());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
DrawElementPayload payload{};
|
||||||
|
payload.drawArray.mode = mode;
|
||||||
|
payload.drawArray.first = 0;
|
||||||
|
payload.drawArray.count = count;
|
||||||
|
const auto currentProgram = MG_State::pGLContext->GetCurrentProgram();
|
||||||
|
payload.drawArray.program = currentProgram ? currentProgram.get() : nullptr;
|
||||||
|
payload.drawArray.vertexArray = vao.get();
|
||||||
|
payload.indexType = type;
|
||||||
|
payload.indexByteOffset = byteOffset;
|
||||||
|
|
||||||
|
pVulkanRenderer->DrawElements(payload);
|
||||||
|
}
|
||||||
|
|
||||||
|
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");
|
||||||
|
|
||||||
|
if (first < 0) {
|
||||||
|
MGLOG_W("DrawArrays skipped: first (%d) must be non-negative", first);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (count < 0) {
|
||||||
|
MGLOG_W("DrawArrays skipped: count (%d) must be non-negative", count);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (count == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mode != GL_TRIANGLES) {
|
||||||
|
MGLOG_W("DrawArrays skipped: primitive mode %u is not supported yet", mode);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
DrawArrayPayload payload{};
|
||||||
|
payload.mode = mode;
|
||||||
|
payload.first = first;
|
||||||
|
payload.count = count;
|
||||||
|
const auto currentProgram = MG_State::pGLContext->GetCurrentProgram();
|
||||||
|
payload.program = currentProgram ? currentProgram.get() : nullptr;
|
||||||
|
|
||||||
|
const auto vao = MG_State::pGLContext->GetBoundVertexArray();
|
||||||
|
payload.vertexArray = vao ? vao.get() : nullptr;
|
||||||
|
|
||||||
|
pVulkanRenderer->DrawArrays(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");
|
||||||
|
|
||||||
|
const auto& readFboSlot = MG_State::pGLContext->GetFramebufferBindingSlot(FramebufferTarget::Read);
|
||||||
|
const auto& drawFboSlot = MG_State::pGLContext->GetFramebufferBindingSlot(FramebufferTarget::Draw);
|
||||||
|
const auto readFbo = readFboSlot.GetBoundObject();
|
||||||
|
const auto drawFbo = drawFboSlot.GetBoundObject();
|
||||||
|
const auto defaultFboInfo = MG_Impl::GLImpl::FramebufferImpl::pDefaultFramebufferInfo;
|
||||||
|
const auto defaultFbo = defaultFboInfo ? defaultFboInfo->defaultFBO : nullptr;
|
||||||
|
|
||||||
|
const Bool readIsDefault = (readFbo == defaultFbo) || (readFbo == nullptr && defaultFbo != nullptr);
|
||||||
|
const Bool drawIsDefault = (drawFbo == defaultFbo) || (drawFbo == nullptr && defaultFbo != nullptr);
|
||||||
|
|
||||||
|
Uint readFboExternalIndex = 0;
|
||||||
|
if (readFbo) {
|
||||||
|
readFboExternalIndex = readFbo->GetExternalIndex();
|
||||||
|
} else if (defaultFbo) {
|
||||||
|
readFboExternalIndex = defaultFbo->GetExternalIndex();
|
||||||
|
}
|
||||||
|
|
||||||
|
Uint drawFboExternalIndex = 0;
|
||||||
|
if (drawFbo) {
|
||||||
|
drawFboExternalIndex = drawFbo->GetExternalIndex();
|
||||||
|
} else if (defaultFbo) {
|
||||||
|
drawFboExternalIndex = defaultFbo->GetExternalIndex();
|
||||||
|
}
|
||||||
|
|
||||||
|
pVulkanRenderer->BlitFramebuffer(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter,
|
||||||
|
readFboExternalIndex, drawFboExternalIndex, readIsDefault, drawIsDefault);
|
||||||
|
}
|
||||||
|
|
||||||
|
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,281 @@
|
|||||||
|
// MobileGL - MobileGL/MG_Backend/DirectVulkan/Renderer/FrameContext.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 "FrameContext.h"
|
||||||
|
|
||||||
|
namespace MobileGL::MG_Backend::DirectVulkan {
|
||||||
|
VkResult FrameContext::Initialize(VkDevice device, VkCommandPool commandPool, Uint32 frameCount) {
|
||||||
|
Destroy(device, commandPool);
|
||||||
|
m_frames.assign(frameCount, {});
|
||||||
|
currentFrameIndex = 0;
|
||||||
|
|
||||||
|
Vector<VkCommandBuffer> commandBuffers(frameCount, VK_NULL_HANDLE);
|
||||||
|
VkCommandBufferAllocateInfo allocInfo{};
|
||||||
|
allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
|
||||||
|
allocInfo.commandPool = commandPool;
|
||||||
|
allocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
|
||||||
|
allocInfo.commandBufferCount = frameCount;
|
||||||
|
VkResult result = vkAllocateCommandBuffers(device, &allocInfo, commandBuffers.data());
|
||||||
|
if (result != VK_SUCCESS) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
for (Uint32 i = 0; i < frameCount; ++i) {
|
||||||
|
m_frames[i].commandBuffer = commandBuffers[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
VkSemaphoreCreateInfo semaphoreInfo{VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO};
|
||||||
|
VkFenceCreateInfo fenceInfo{VK_STRUCTURE_TYPE_FENCE_CREATE_INFO};
|
||||||
|
fenceInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT;
|
||||||
|
|
||||||
|
for (Uint32 i = 0; i < frameCount; ++i) {
|
||||||
|
result = CreateSyncObjectsForFrame(device, i, semaphoreInfo, fenceInfo);
|
||||||
|
if (result != VK_SUCCESS) {
|
||||||
|
Destroy(device, commandPool);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return VK_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FrameContext::Destroy(VkDevice device, VkCommandPool commandPool) {
|
||||||
|
const Uint32 frameCount = static_cast<Uint32>(m_frames.size());
|
||||||
|
Vector<VkCommandBuffer> commandBuffers(frameCount, VK_NULL_HANDLE);
|
||||||
|
for (Uint32 i = 0; i < frameCount; ++i) {
|
||||||
|
commandBuffers[i] = m_frames[i].commandBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (Uint32 i = 0; i < frameCount; ++i) {
|
||||||
|
DestroySyncObjectsForFrame(device, i);
|
||||||
|
}
|
||||||
|
DestroySwapchainSemaphores(device);
|
||||||
|
if (device != VK_NULL_HANDLE && commandPool != VK_NULL_HANDLE && !m_frames.empty()) {
|
||||||
|
vkFreeCommandBuffers(device, commandPool, frameCount, commandBuffers.data());
|
||||||
|
}
|
||||||
|
m_frames.clear();
|
||||||
|
currentFrameIndex = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
FrameContext::FrameData& FrameContext::GetCurrent() {
|
||||||
|
MOBILEGL_ASSERT(!m_frames.empty(), "FrameContext is not initialized");
|
||||||
|
return m_frames[currentFrameIndex];
|
||||||
|
}
|
||||||
|
|
||||||
|
const FrameContext::FrameData& FrameContext::GetCurrent() const {
|
||||||
|
MOBILEGL_ASSERT(!m_frames.empty(), "FrameContext is not initialized");
|
||||||
|
return m_frames[currentFrameIndex];
|
||||||
|
}
|
||||||
|
|
||||||
|
Bool FrameContext::IsCommandRecording() const {
|
||||||
|
return GetCurrent().isCommandRecording;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FrameContext::AdvanceToNext() {
|
||||||
|
MOBILEGL_ASSERT(!m_frames.empty(), "FrameContext is not initialized");
|
||||||
|
currentFrameIndex = (currentFrameIndex + 1) % static_cast<Uint32>(m_frames.size());
|
||||||
|
GetCurrent().isCommandRecording = false;
|
||||||
|
GetCurrent().hasCommandBufferRecorded = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
VkCommandBuffer& FrameContext::BeginCommandRecording(VkCommandBufferUsageFlags flags,
|
||||||
|
const VkCommandBufferInheritanceInfo* pInheritanceInfo) {
|
||||||
|
auto& frame = GetCurrent();
|
||||||
|
MOBILEGL_ASSERT(!frame.isCommandRecording, "BeginCommandRecording called while command buffer is already recording");
|
||||||
|
|
||||||
|
frame.hasCommandBufferRecorded = false;
|
||||||
|
VK_VERIFY(vkResetCommandBuffer(frame.commandBuffer, 0), "BeginCommandRecording, vkResetCommandBuffer");
|
||||||
|
|
||||||
|
VkCommandBufferBeginInfo beginInfo{};
|
||||||
|
beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
|
||||||
|
beginInfo.flags = flags;
|
||||||
|
beginInfo.pInheritanceInfo = pInheritanceInfo;
|
||||||
|
VK_VERIFY(vkBeginCommandBuffer(frame.commandBuffer, &beginInfo), "BeginCommandRecording, vkBeginCommandBuffer");
|
||||||
|
|
||||||
|
frame.isCommandRecording = true;
|
||||||
|
return frame.commandBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FrameContext::EndCommandRecording() {
|
||||||
|
auto& frame = GetCurrent();
|
||||||
|
MOBILEGL_ASSERT(frame.isCommandRecording, "EndCommandRecording called without active command buffer recording");
|
||||||
|
VK_VERIFY(vkEndCommandBuffer(frame.commandBuffer), "EndCommandRecording, vkEndCommandBuffer");
|
||||||
|
frame.isCommandRecording = false;
|
||||||
|
frame.hasCommandBufferRecorded = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
VkResult FrameContext::InitializeSwapchainSemaphores(VkDevice device, Uint32 swapchainImageCount) {
|
||||||
|
DestroySwapchainSemaphores(device);
|
||||||
|
if (swapchainImageCount == 0) {
|
||||||
|
return VK_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_swapchainImageRenderFinishedSemaphores.assign(swapchainImageCount, VK_NULL_HANDLE);
|
||||||
|
VkSemaphoreCreateInfo semaphoreInfo{VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO};
|
||||||
|
for (Uint32 imageIndex = 0; imageIndex < swapchainImageCount; ++imageIndex) {
|
||||||
|
VkResult result =
|
||||||
|
vkCreateSemaphore(device, &semaphoreInfo, nullptr, &m_swapchainImageRenderFinishedSemaphores[imageIndex]);
|
||||||
|
if (result != VK_SUCCESS) {
|
||||||
|
DestroySwapchainSemaphores(device);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return VK_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FrameContext::DestroySwapchainSemaphores(VkDevice device) {
|
||||||
|
if (device != VK_NULL_HANDLE) {
|
||||||
|
for (auto semaphore : m_swapchainImageRenderFinishedSemaphores) {
|
||||||
|
if (semaphore != VK_NULL_HANDLE) {
|
||||||
|
vkDestroySemaphore(device, semaphore, nullptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
m_swapchainImageRenderFinishedSemaphores.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
Bool FrameContext::TransitionToPresent(VkImage image, VkImageLayout oldLayout, VkImageLayout presentLayout) {
|
||||||
|
auto& frame = GetCurrent();
|
||||||
|
if (frame.hasCommandBufferRecorded || frame.isCommandRecording || oldLayout == presentLayout ||
|
||||||
|
oldLayout == VK_IMAGE_LAYOUT_SHARED_PRESENT_KHR) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto& commandBuffer = BeginCommandRecording();
|
||||||
|
|
||||||
|
VkImageMemoryBarrier presentBarrier{};
|
||||||
|
presentBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
|
||||||
|
presentBarrier.srcAccessMask = 0;
|
||||||
|
presentBarrier.dstAccessMask = 0;
|
||||||
|
presentBarrier.oldLayout = oldLayout;
|
||||||
|
presentBarrier.newLayout = presentLayout;
|
||||||
|
presentBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
||||||
|
presentBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
||||||
|
presentBarrier.image = image;
|
||||||
|
presentBarrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||||
|
presentBarrier.subresourceRange.baseMipLevel = 0;
|
||||||
|
presentBarrier.subresourceRange.levelCount = 1;
|
||||||
|
presentBarrier.subresourceRange.baseArrayLayer = 0;
|
||||||
|
presentBarrier.subresourceRange.layerCount = 1;
|
||||||
|
vkCmdPipelineBarrier(commandBuffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, 0, 0,
|
||||||
|
nullptr, 0, nullptr, 1, &presentBarrier);
|
||||||
|
|
||||||
|
EndCommandRecording();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
FrameContext::SubmitInfoPacket FrameContext::GetSubmitInfo(Bool shouldSubmitCommandBuffer,
|
||||||
|
Uint32 swapchainImageIndex) const {
|
||||||
|
const auto& frame = GetCurrent();
|
||||||
|
MOBILEGL_ASSERT(!frame.isCommandRecording, "GetSubmitInfo called while command buffer recording is still active");
|
||||||
|
AssertValidSwapchainImageIndex(swapchainImageIndex);
|
||||||
|
SubmitInfoPacket packet{};
|
||||||
|
packet.waitSemaphore = frame.imageAvailableSemaphore;
|
||||||
|
packet.signalSemaphore = m_swapchainImageRenderFinishedSemaphores[swapchainImageIndex];
|
||||||
|
packet.commandBuffer = frame.commandBuffer;
|
||||||
|
|
||||||
|
packet.submitInfo.waitSemaphoreCount = 1;
|
||||||
|
packet.submitInfo.pWaitSemaphores = &packet.waitSemaphore;
|
||||||
|
packet.submitInfo.pWaitDstStageMask = &packet.waitDstStageMask;
|
||||||
|
packet.submitInfo.commandBufferCount = shouldSubmitCommandBuffer ? 1U : 0U;
|
||||||
|
packet.submitInfo.pCommandBuffers = shouldSubmitCommandBuffer ? &packet.commandBuffer : nullptr;
|
||||||
|
packet.submitInfo.signalSemaphoreCount = 1;
|
||||||
|
packet.submitInfo.pSignalSemaphores = &packet.signalSemaphore;
|
||||||
|
return packet;
|
||||||
|
}
|
||||||
|
|
||||||
|
FrameContext::PresentInfoPacket FrameContext::GetPresentInfo(VkSwapchainKHR swapchain, const Uint32& imageIndex) const {
|
||||||
|
AssertValidSwapchainImageIndex(imageIndex);
|
||||||
|
PresentInfoPacket packet{};
|
||||||
|
packet.waitSemaphore = m_swapchainImageRenderFinishedSemaphores[imageIndex];
|
||||||
|
packet.swapchain = swapchain;
|
||||||
|
packet.imageIndex = &imageIndex;
|
||||||
|
|
||||||
|
packet.presentInfo.waitSemaphoreCount = 1;
|
||||||
|
packet.presentInfo.pWaitSemaphores = &packet.waitSemaphore;
|
||||||
|
packet.presentInfo.swapchainCount = 1;
|
||||||
|
packet.presentInfo.pSwapchains = &packet.swapchain;
|
||||||
|
packet.presentInfo.pImageIndices = packet.imageIndex;
|
||||||
|
packet.presentInfo.pResults = nullptr;
|
||||||
|
return packet;
|
||||||
|
}
|
||||||
|
|
||||||
|
VkResult FrameContext::WaitAndAcquireNextImage(VkDevice device, VkSwapchainKHR swapchain, Uint32& outImageIndex,
|
||||||
|
Uint64 timeout, VkFence acquireFence) {
|
||||||
|
auto& frame = GetCurrent();
|
||||||
|
VkResult result = vkWaitForFences(device, 1, &frame.imageInFlightFence, VK_TRUE, timeout);
|
||||||
|
if (result != VK_SUCCESS) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
result = vkResetFences(device, 1, &frame.imageInFlightFence);
|
||||||
|
if (result != VK_SUCCESS) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
return vkAcquireNextImageKHR(device, swapchain, timeout, frame.imageAvailableSemaphore, acquireFence,
|
||||||
|
&outImageIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
Uint32 FrameContext::GetCurrentFrameIndex() const {
|
||||||
|
return currentFrameIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
Uint32 FrameContext::GetFrameCount() const {
|
||||||
|
return static_cast<Uint32>(m_frames.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
void FrameContext::AssertValidFrameIndex(Uint32 frameIndex) const {
|
||||||
|
MOBILEGL_ASSERT(frameIndex < m_frames.size(), "FrameContext index out of range");
|
||||||
|
}
|
||||||
|
|
||||||
|
void FrameContext::AssertValidSwapchainImageIndex(Uint32 imageIndex) const {
|
||||||
|
MOBILEGL_ASSERT(imageIndex < m_swapchainImageRenderFinishedSemaphores.size(),
|
||||||
|
"FrameContext swapchain image index out of range");
|
||||||
|
}
|
||||||
|
|
||||||
|
VkResult FrameContext::CreateSyncObjectsForFrame(VkDevice device, Uint32 frameIndex,
|
||||||
|
const VkSemaphoreCreateInfo& semaphoreInfo,
|
||||||
|
const VkFenceCreateInfo& fenceInfo) {
|
||||||
|
AssertValidFrameIndex(frameIndex);
|
||||||
|
DestroySyncObjectsForFrame(device, frameIndex);
|
||||||
|
|
||||||
|
auto& frame = m_frames[frameIndex];
|
||||||
|
VkResult result =
|
||||||
|
vkCreateSemaphore(device, &semaphoreInfo, nullptr, &frame.imageAvailableSemaphore);
|
||||||
|
if (result != VK_SUCCESS) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
result = vkCreateFence(device, &fenceInfo, nullptr, &frame.imageInFlightFence);
|
||||||
|
if (result != VK_SUCCESS) {
|
||||||
|
vkDestroySemaphore(device, frame.imageAvailableSemaphore, nullptr);
|
||||||
|
frame.imageAvailableSemaphore = VK_NULL_HANDLE;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
frame.hasCommandBufferRecorded = false;
|
||||||
|
frame.isCommandRecording = false;
|
||||||
|
return VK_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FrameContext::DestroySyncObjectsForFrame(VkDevice device, Uint32 frameIndex) {
|
||||||
|
AssertValidFrameIndex(frameIndex);
|
||||||
|
auto& frame = m_frames[frameIndex];
|
||||||
|
if (device != VK_NULL_HANDLE && frame.imageInFlightFence != VK_NULL_HANDLE) {
|
||||||
|
vkDestroyFence(device, frame.imageInFlightFence, nullptr);
|
||||||
|
}
|
||||||
|
frame.imageInFlightFence = VK_NULL_HANDLE;
|
||||||
|
|
||||||
|
if (device != VK_NULL_HANDLE && frame.imageAvailableSemaphore != VK_NULL_HANDLE) {
|
||||||
|
vkDestroySemaphore(device, frame.imageAvailableSemaphore, nullptr);
|
||||||
|
}
|
||||||
|
frame.imageAvailableSemaphore = VK_NULL_HANDLE;
|
||||||
|
frame.isCommandRecording = false;
|
||||||
|
frame.hasCommandBufferRecorded = false;
|
||||||
|
}
|
||||||
|
} // namespace MobileGL::MG_Backend::DirectVulkan
|
||||||
@@ -0,0 +1,76 @@
|
|||||||
|
// MobileGL - MobileGL/MG_Backend/DirectVulkan/Renderer/FrameContext.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 {
|
||||||
|
class FrameContext {
|
||||||
|
public:
|
||||||
|
struct SubmitInfoPacket {
|
||||||
|
VkPipelineStageFlags waitDstStageMask = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
|
||||||
|
VkSemaphore waitSemaphore = VK_NULL_HANDLE;
|
||||||
|
VkSemaphore signalSemaphore = VK_NULL_HANDLE;
|
||||||
|
VkCommandBuffer commandBuffer = VK_NULL_HANDLE;
|
||||||
|
VkSubmitInfo submitInfo{VK_STRUCTURE_TYPE_SUBMIT_INFO};
|
||||||
|
};
|
||||||
|
|
||||||
|
struct PresentInfoPacket {
|
||||||
|
VkSemaphore waitSemaphore = VK_NULL_HANDLE;
|
||||||
|
VkSwapchainKHR swapchain = VK_NULL_HANDLE;
|
||||||
|
const Uint32* imageIndex = nullptr;
|
||||||
|
VkPresentInfoKHR presentInfo{VK_STRUCTURE_TYPE_PRESENT_INFO_KHR};
|
||||||
|
};
|
||||||
|
|
||||||
|
struct FrameData {
|
||||||
|
VkCommandBuffer commandBuffer = VK_NULL_HANDLE;
|
||||||
|
VkSemaphore imageAvailableSemaphore = VK_NULL_HANDLE;
|
||||||
|
VkFence imageInFlightFence = VK_NULL_HANDLE;
|
||||||
|
Bool isCommandRecording = false;
|
||||||
|
Bool hasCommandBufferRecorded = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
VkResult Initialize(VkDevice device, VkCommandPool commandPool, Uint32 frameCount);
|
||||||
|
void Destroy(VkDevice device, VkCommandPool commandPool);
|
||||||
|
|
||||||
|
// Lifecycle functions
|
||||||
|
FrameData& GetCurrent();
|
||||||
|
const FrameData& GetCurrent() const;
|
||||||
|
Bool IsCommandRecording() const;
|
||||||
|
void AdvanceToNext();
|
||||||
|
VkCommandBuffer& BeginCommandRecording(VkCommandBufferUsageFlags flags = 0,
|
||||||
|
const VkCommandBufferInheritanceInfo* pInheritanceInfo = nullptr);
|
||||||
|
void EndCommandRecording();
|
||||||
|
VkResult InitializeSwapchainSemaphores(VkDevice device, Uint32 swapchainImageCount);
|
||||||
|
void DestroySwapchainSemaphores(VkDevice device);
|
||||||
|
Bool TransitionToPresent(VkImage image, VkImageLayout oldLayout,
|
||||||
|
VkImageLayout presentLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR);
|
||||||
|
SubmitInfoPacket GetSubmitInfo(Bool shouldSubmitCommandBuffer, Uint32 swapchainImageIndex) const;
|
||||||
|
PresentInfoPacket GetPresentInfo(VkSwapchainKHR swapchain, const Uint32& imageIndex) const;
|
||||||
|
VkResult WaitAndAcquireNextImage(VkDevice device, VkSwapchainKHR swapchain, Uint32& outImageIndex,
|
||||||
|
Uint64 timeout = UINT64_MAX, VkFence acquireFence = VK_NULL_HANDLE);
|
||||||
|
|
||||||
|
Uint32 GetCurrentFrameIndex() const;
|
||||||
|
Uint32 GetFrameCount() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void AssertValidFrameIndex(Uint32 frameIndex) const;
|
||||||
|
void AssertValidSwapchainImageIndex(Uint32 imageIndex) const;
|
||||||
|
|
||||||
|
VkResult CreateSyncObjectsForFrame(VkDevice device, Uint32 frameIndex,
|
||||||
|
const VkSemaphoreCreateInfo& semaphoreInfo,
|
||||||
|
const VkFenceCreateInfo& fenceInfo);
|
||||||
|
void DestroySyncObjectsForFrame(VkDevice device, Uint32 frameIndex);
|
||||||
|
|
||||||
|
Vector<FrameData> m_frames;
|
||||||
|
Vector<VkSemaphore> m_swapchainImageRenderFinishedSemaphores;
|
||||||
|
Uint32 currentFrameIndex = 0;
|
||||||
|
};
|
||||||
|
} // namespace MobileGL::MG_Backend::DirectVulkan
|
||||||
@@ -0,0 +1,129 @@
|
|||||||
|
// MobileGL - MobileGL/MG_Backend/DirectVulkan/Renderer/PipelineFactory.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 "PipelineFactory.h"
|
||||||
|
|
||||||
|
namespace MobileGL::MG_Backend::DirectVulkan {
|
||||||
|
PipelineFactory::~PipelineFactory() {
|
||||||
|
DestroyAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
PipelineFactory::HashType PipelineFactory::ComputeHash(const PipelineCreatePayload& payload) const {
|
||||||
|
XXHASH_VERIFY(XXH64_reset(m_hashState, m_config.CacheVersion));
|
||||||
|
XXHASH_VERIFY(XXH64_update(m_hashState, &payload.programHash, sizeof(payload.programHash)));
|
||||||
|
XXHASH_VERIFY(XXH64_update(m_hashState, &payload.vertexInputHash, sizeof(payload.vertexInputHash)));
|
||||||
|
XXHASH_VERIFY(XXH64_update(m_hashState, &payload.pipelineLayout, sizeof(payload.pipelineLayout)));
|
||||||
|
XXHASH_VERIFY(XXH64_update(m_hashState, &payload.renderPass, sizeof(payload.renderPass)));
|
||||||
|
XXHASH_VERIFY(XXH64_update(m_hashState, &payload.subpass, sizeof(payload.subpass)));
|
||||||
|
XXHASH_VERIFY(XXH64_update(m_hashState, &payload.topology, sizeof(payload.topology)));
|
||||||
|
XXHASH_VERIFY(XXH64_update(m_hashState, &payload.depthTestEnable, sizeof(payload.depthTestEnable)));
|
||||||
|
XXHASH_VERIFY(XXH64_update(m_hashState, &payload.depthWriteEnable, sizeof(payload.depthWriteEnable)));
|
||||||
|
XXHASH_VERIFY(XXH64_update(m_hashState, &payload.depthCompareOp, sizeof(payload.depthCompareOp)));
|
||||||
|
XXHASH_VERIFY(XXH64_update(m_hashState, &payload.blendEnable, sizeof(payload.blendEnable)));
|
||||||
|
XXHASH_VERIFY(XXH64_update(m_hashState, &payload.srcColorBlendFactor, sizeof(payload.srcColorBlendFactor)));
|
||||||
|
XXHASH_VERIFY(XXH64_update(m_hashState, &payload.dstColorBlendFactor, sizeof(payload.dstColorBlendFactor)));
|
||||||
|
XXHASH_VERIFY(XXH64_update(m_hashState, &payload.srcAlphaBlendFactor, sizeof(payload.srcAlphaBlendFactor)));
|
||||||
|
XXHASH_VERIFY(XXH64_update(m_hashState, &payload.dstAlphaBlendFactor, sizeof(payload.dstAlphaBlendFactor)));
|
||||||
|
XXHASH_VERIFY(XXH64_update(m_hashState, &payload.colorWriteMask, sizeof(payload.colorWriteMask)));
|
||||||
|
return XXH64_digest(m_hashState);
|
||||||
|
}
|
||||||
|
|
||||||
|
VkPipeline PipelineFactory::GetOrCreatePipeline(const PipelineCreatePayload& payload) {
|
||||||
|
const HashType hash = ComputeHash(payload);
|
||||||
|
auto it = m_cache.find(hash);
|
||||||
|
if (it != m_cache.end()) {
|
||||||
|
return it->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
VkPipeline pipeline = CreatePipeline(payload);
|
||||||
|
m_cache.emplace(hash, pipeline);
|
||||||
|
return pipeline;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PipelineFactory::DestroyAll() {
|
||||||
|
for (auto& pair : m_cache) {
|
||||||
|
if (pair.second != VK_NULL_HANDLE) {
|
||||||
|
vkDestroyPipeline(m_device, pair.second, nullptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
m_cache.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
VkPipeline PipelineFactory::CreatePipeline(const PipelineCreatePayload& payload) const {
|
||||||
|
MOBILEGL_ASSERT(payload.stages != nullptr && !payload.stages->empty(), "PipelineFactory: stages are empty");
|
||||||
|
MOBILEGL_ASSERT(payload.vertexInputState != nullptr, "PipelineFactory: vertexInputState is null");
|
||||||
|
MOBILEGL_ASSERT(payload.pipelineLayout != VK_NULL_HANDLE, "PipelineFactory: pipelineLayout is null");
|
||||||
|
MOBILEGL_ASSERT(payload.renderPass != VK_NULL_HANDLE, "PipelineFactory: renderPass is null");
|
||||||
|
|
||||||
|
static constexpr VkDynamicState kDynamicStates[] = {
|
||||||
|
VK_DYNAMIC_STATE_VIEWPORT,
|
||||||
|
VK_DYNAMIC_STATE_SCISSOR
|
||||||
|
};
|
||||||
|
|
||||||
|
VkPipelineDynamicStateCreateInfo dynamicState{};
|
||||||
|
dynamicState.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO;
|
||||||
|
dynamicState.dynamicStateCount = static_cast<uint32_t>(std::size(kDynamicStates));
|
||||||
|
dynamicState.pDynamicStates = kDynamicStates;
|
||||||
|
|
||||||
|
VkPipelineInputAssemblyStateCreateInfo ia{VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO};
|
||||||
|
ia.topology = payload.topology;
|
||||||
|
|
||||||
|
VkPipelineViewportStateCreateInfo vpci{VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO};
|
||||||
|
vpci.viewportCount = 1;
|
||||||
|
vpci.scissorCount = 1;
|
||||||
|
|
||||||
|
VkPipelineRasterizationStateCreateInfo raster{VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO};
|
||||||
|
raster.polygonMode = VK_POLYGON_MODE_FILL;
|
||||||
|
raster.cullMode = VK_CULL_MODE_NONE;
|
||||||
|
raster.frontFace = VK_FRONT_FACE_CLOCKWISE;
|
||||||
|
raster.lineWidth = 1.0f;
|
||||||
|
|
||||||
|
VkPipelineMultisampleStateCreateInfo ms{VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO};
|
||||||
|
ms.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
|
||||||
|
|
||||||
|
VkPipelineDepthStencilStateCreateInfo depthStencil{VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO};
|
||||||
|
depthStencil.depthTestEnable = payload.depthTestEnable ? VK_TRUE : VK_FALSE;
|
||||||
|
depthStencil.depthWriteEnable = payload.depthWriteEnable ? VK_TRUE : VK_FALSE;
|
||||||
|
depthStencil.depthCompareOp = payload.depthCompareOp;
|
||||||
|
depthStencil.depthBoundsTestEnable = VK_FALSE;
|
||||||
|
depthStencil.stencilTestEnable = VK_FALSE;
|
||||||
|
|
||||||
|
VkPipelineColorBlendAttachmentState colorAttach{};
|
||||||
|
colorAttach.colorWriteMask = payload.colorWriteMask;
|
||||||
|
colorAttach.blendEnable = payload.blendEnable ? VK_TRUE : VK_FALSE;
|
||||||
|
colorAttach.srcColorBlendFactor = payload.srcColorBlendFactor;
|
||||||
|
colorAttach.dstColorBlendFactor = payload.dstColorBlendFactor;
|
||||||
|
colorAttach.colorBlendOp = VK_BLEND_OP_ADD;
|
||||||
|
colorAttach.srcAlphaBlendFactor = payload.srcAlphaBlendFactor;
|
||||||
|
colorAttach.dstAlphaBlendFactor = payload.dstAlphaBlendFactor;
|
||||||
|
colorAttach.alphaBlendOp = VK_BLEND_OP_ADD;
|
||||||
|
VkPipelineColorBlendStateCreateInfo blend{VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO};
|
||||||
|
blend.attachmentCount = 1;
|
||||||
|
blend.pAttachments = &colorAttach;
|
||||||
|
|
||||||
|
VkGraphicsPipelineCreateInfo gpi{VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO};
|
||||||
|
gpi.stageCount = static_cast<Uint32>(payload.stages->size());
|
||||||
|
gpi.pStages = payload.stages->data();
|
||||||
|
gpi.pVertexInputState = payload.vertexInputState;
|
||||||
|
gpi.pInputAssemblyState = &ia;
|
||||||
|
gpi.pViewportState = &vpci;
|
||||||
|
gpi.pRasterizationState = &raster;
|
||||||
|
gpi.pMultisampleState = &ms;
|
||||||
|
gpi.pDepthStencilState = &depthStencil;
|
||||||
|
gpi.pColorBlendState = &blend;
|
||||||
|
gpi.pDynamicState = &dynamicState;
|
||||||
|
gpi.layout = payload.pipelineLayout;
|
||||||
|
gpi.renderPass = payload.renderPass;
|
||||||
|
gpi.subpass = payload.subpass;
|
||||||
|
|
||||||
|
VkPipeline pipeline = VK_NULL_HANDLE;
|
||||||
|
VK_VERIFY(vkCreateGraphicsPipelines(m_device, VK_NULL_HANDLE, 1, &gpi, nullptr, &pipeline),
|
||||||
|
"vkCreateGraphicsPipelines");
|
||||||
|
return pipeline;
|
||||||
|
}
|
||||||
|
} // namespace MobileGL::MG_Backend::DirectVulkan
|
||||||
@@ -0,0 +1,59 @@
|
|||||||
|
// MobileGL - MobileGL/MG_Backend/DirectVulkan/Renderer/PipelineFactory.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 "Config.h"
|
||||||
|
#include "../VkIncludes.h"
|
||||||
|
#include <Includes.h>
|
||||||
|
|
||||||
|
namespace MobileGL::MG_Backend::DirectVulkan {
|
||||||
|
class PipelineFactory {
|
||||||
|
public:
|
||||||
|
using HashType = Uint64;
|
||||||
|
|
||||||
|
struct PipelineCreatePayload {
|
||||||
|
HashType programHash = 0;
|
||||||
|
HashType vertexInputHash = 0;
|
||||||
|
VkPipelineLayout pipelineLayout = VK_NULL_HANDLE;
|
||||||
|
VkRenderPass renderPass = VK_NULL_HANDLE;
|
||||||
|
Uint32 subpass = 0;
|
||||||
|
VkPrimitiveTopology topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
|
||||||
|
Bool depthTestEnable = false;
|
||||||
|
Bool depthWriteEnable = false;
|
||||||
|
VkCompareOp depthCompareOp = VK_COMPARE_OP_ALWAYS;
|
||||||
|
Bool blendEnable = false;
|
||||||
|
VkBlendFactor srcColorBlendFactor = VK_BLEND_FACTOR_ONE;
|
||||||
|
VkBlendFactor dstColorBlendFactor = VK_BLEND_FACTOR_ZERO;
|
||||||
|
VkBlendFactor srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE;
|
||||||
|
VkBlendFactor dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO;
|
||||||
|
VkColorComponentFlags colorWriteMask =
|
||||||
|
VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT |
|
||||||
|
VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
|
||||||
|
const Vector<VkPipelineShaderStageCreateInfo>* stages = nullptr;
|
||||||
|
const VkPipelineVertexInputStateCreateInfo* vertexInputState = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
explicit PipelineFactory(VkDevice device, const VulkanRendererConfig& config):
|
||||||
|
m_device(device), m_config(config) {}
|
||||||
|
~PipelineFactory();
|
||||||
|
PipelineFactory(const PipelineFactory&) = delete;
|
||||||
|
|
||||||
|
HashType ComputeHash(const PipelineCreatePayload& payload) const;
|
||||||
|
VkPipeline GetOrCreatePipeline(const PipelineCreatePayload& payload);
|
||||||
|
void DestroyAll();
|
||||||
|
|
||||||
|
private:
|
||||||
|
VkPipeline CreatePipeline(const PipelineCreatePayload& payload) const;
|
||||||
|
|
||||||
|
VkDevice m_device = VK_NULL_HANDLE;
|
||||||
|
const VulkanRendererConfig& m_config;
|
||||||
|
UnorderedMap<HashType, VkPipeline> m_cache;
|
||||||
|
static inline XXH64_state_t* m_hashState = XXH64_createState();
|
||||||
|
};
|
||||||
|
} // 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