Compare commits
686
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
563c32b95b | ||
|
|
af48bc3c74 | ||
|
|
65dfac9637 | ||
|
|
9e119937af | ||
|
|
3e644b25f0 | ||
|
|
fadd5eb953 | ||
|
|
b48b6136ba | ||
|
|
ca0f98c513 | ||
|
|
70b87510a2 | ||
|
|
31b836282d | ||
|
|
cdd9c4aebe | ||
|
|
f3a61f100c | ||
|
|
0774ce6b5e | ||
|
|
60db518b75 | ||
|
|
3c5316f1e9 | ||
|
|
1f33a6efd2 | ||
|
|
4127f619e1 | ||
|
|
b3cc4d11b8 | ||
|
|
8523f4e970 | ||
|
|
6b7450dc0b | ||
|
|
7b384fb5e8 | ||
|
|
20dc6d479b | ||
|
|
0736f3c3b3 | ||
|
|
6a7767f4e4 | ||
|
|
628d387cbd | ||
|
|
75a1c6d7a8 | ||
|
|
8c76370e2d | ||
|
|
bdc15a5c2d | ||
|
|
acfe9298d9 | ||
|
|
57f6e5371b | ||
|
|
9fa3cbfcde | ||
|
|
c81ece5c3c | ||
|
|
aae48c1121 | ||
|
|
918ce935b8 | ||
|
|
6f37e07dba | ||
|
|
171b3279e0 | ||
|
|
b3a1cfe7c9 | ||
|
|
d273838e07 | ||
|
|
a1de8c924d | ||
|
|
72765a5b0a | ||
|
|
e1beabaa98 | ||
|
|
ebaee14b8b | ||
|
|
d4f08dafbb | ||
|
|
753fb102c4 | ||
|
|
b219113a55 | ||
|
|
9140d44b29 | ||
|
|
8b0d65768a | ||
|
|
349bf7be38 | ||
|
|
a01d282f14 | ||
|
|
3c3296a114 | ||
|
|
61501ba122 | ||
|
|
99ba40e965 | ||
|
|
4116af7971 | ||
|
|
2fab93faff | ||
|
|
b92c5cab07 | ||
|
|
8ed9678cbe | ||
|
|
731e52a3c1 | ||
|
|
687b6da800 | ||
|
|
64f4c097ac | ||
|
|
0191e1fe46 | ||
|
|
21093067db | ||
|
|
1b10e7d4f3 | ||
|
|
5b2d3ac225 | ||
|
|
422dfcc1e6 | ||
|
|
0d304393f4 | ||
|
|
57aa99e964 | ||
|
|
cfc133fcf1 | ||
|
|
8eade6be1f | ||
|
|
2250664e58 | ||
|
|
8a27cc8b7f | ||
|
|
d786d59ea1 | ||
|
|
79116905aa | ||
|
|
763950ec18 | ||
|
|
13571868de | ||
|
|
0f2c89b140 | ||
|
|
f8b70e8ec5 | ||
|
|
7abdea5a2e | ||
|
|
cb3e808e8d | ||
|
|
b2e0b97bad | ||
|
|
9c0cbed214 | ||
|
|
c531a9c077 | ||
|
|
2a1f762e23 | ||
|
|
4dd98e63e4 | ||
|
|
1b7187f427 | ||
|
|
0dddd94eab | ||
|
|
2ef0244266 | ||
|
|
0774bf9501 | ||
|
|
8f5b2fd230 | ||
|
|
274191036f | ||
|
|
13afbc2876 | ||
|
|
a7bb0a60fb | ||
|
|
0650b13358 | ||
|
|
6cd851e77e | ||
|
|
87a8cb3872 | ||
|
|
a4869eaf19 | ||
|
|
1740220f6a | ||
|
|
5deccffdce | ||
|
|
a76eacba67 | ||
|
|
ee31ca6fc0 | ||
|
|
7dd6686087 | ||
|
|
fdffd93949 | ||
|
|
f0a0a9b2e1 | ||
|
|
e743e9243f | ||
|
|
8e13d53b1e | ||
|
|
ff274c8387 | ||
|
|
e08e1c209b | ||
|
|
de310ed9ad | ||
|
|
d01b29fa01 | ||
|
|
8cba3d4366 | ||
|
|
be1e51ad91 | ||
|
|
29ce1cad84 | ||
|
|
6a967ad007 | ||
|
|
fe2bb3d9a4 | ||
|
|
cd7973bdcf | ||
|
|
e6384e0e92 | ||
|
|
e63dc17f54 | ||
|
|
af338cf2ec | ||
|
|
f1d8a04337 | ||
|
|
b13497e2a0 | ||
|
|
175c9f9966 | ||
|
|
1a50420b46 | ||
|
|
bbad75a012 | ||
|
|
25c08f19e3 | ||
|
|
59063fb7b4 | ||
|
|
71f60de0ad | ||
|
|
743661109d | ||
|
|
5014cbb023 | ||
|
|
4142e7a1cf | ||
|
|
a721e648b7 | ||
|
|
358e89ef08 | ||
|
|
e023e90e7a | ||
|
|
a5b5b0c3a7 | ||
|
|
b7b4d3c295 | ||
|
|
a445c4e156 | ||
|
|
1432c59499 | ||
|
|
4c7c10fad0 | ||
|
|
7c8a0d1967 | ||
|
|
11fbacea20 | ||
|
|
8cd70454c3 | ||
|
|
1d988182fc | ||
|
|
dba49f00df | ||
|
|
89c0b44da9 | ||
|
|
4f450fd5c4 | ||
|
|
f0943cfca2 | ||
|
|
9aa52b79d4 | ||
|
|
a82125dbbd | ||
|
|
24fcb299b5 | ||
|
|
753aa9ca61 | ||
|
|
a33eada7ec | ||
|
|
676a2be874 | ||
|
|
c95d466cdd | ||
|
|
3d8ac384ad | ||
|
|
57424cc7e9 | ||
|
|
78fe4ba547 | ||
|
|
a3d25cd22b | ||
|
|
56bf841bac | ||
|
|
dfdf0db794 | ||
|
|
bf6bd4eca8 | ||
|
|
36c69dda9c | ||
|
|
f14fdc11f5 | ||
|
|
0157487b1f | ||
|
|
1716c856c3 | ||
|
|
31521c70c2 | ||
|
|
8cac90d81e | ||
|
|
388b4f5efb | ||
|
|
f9b5a7f301 | ||
|
|
00c78cc225 | ||
|
|
2bdb8b560c | ||
|
|
a974fddd4c | ||
|
|
83a3e243da | ||
|
|
f286e308bf | ||
|
|
29af3be2e3 | ||
|
|
6623dcbebf | ||
|
|
89dc43f361 | ||
|
|
b77aac43ea | ||
|
|
0d63fa02ee | ||
|
|
e187bc442d | ||
|
|
d62268fbfb | ||
|
|
3b73e3de60 | ||
|
|
7685736d6c | ||
|
|
b8a3a7f221 | ||
|
|
732628acf5 | ||
|
|
7bd00d2b30 | ||
|
|
0759797e61 | ||
|
|
fddc5160c7 | ||
|
|
2a579c460f | ||
|
|
efdc801cff | ||
|
|
dd654c575a | ||
|
|
0c2599b6ca | ||
|
|
979d6742e0 | ||
|
|
4a7a033d04 | ||
|
|
5c2bbcb4a1 | ||
|
|
dec903a0ee | ||
|
|
e9475b322b | ||
|
|
d9aead8aac | ||
|
|
ce148ebeb1 | ||
|
|
e1315fbaa7 | ||
|
|
1690549392 | ||
|
|
c73710e343 | ||
|
|
092a0489da | ||
|
|
1c6279366f | ||
|
|
2ac85049a9 | ||
|
|
ea428a27d1 | ||
|
|
3bef718238 | ||
|
|
e9daaa0503 | ||
|
|
6d3ea21993 | ||
|
|
f39127605d | ||
|
|
db476f00f7 | ||
|
|
e54d8ec0a4 | ||
|
|
b95ac854b4 | ||
|
|
96443f6dac | ||
|
|
e5e3dff9fa | ||
|
|
31d9da38fd | ||
|
|
c5a59bb6b1 | ||
|
|
e6854148d7 | ||
|
|
001daf0350 | ||
|
|
d26c48110d | ||
|
|
15a070f0c9 | ||
|
|
93230b06cf | ||
|
|
4c55fc3c48 | ||
|
|
a4797a631e | ||
|
|
5868e857aa | ||
|
|
32ba063bd7 | ||
|
|
02f0839f9b | ||
|
|
e50f3c4c91 | ||
|
|
7ca15bfc16 | ||
|
|
b7b7afb62a | ||
|
|
b8ff6a9ad9 | ||
|
|
a1dcb4f259 | ||
|
|
c3501393fd | ||
|
|
a03de75a4e | ||
|
|
0c3d59aba3 | ||
|
|
ce1987f291 | ||
|
|
7eae926ed7 | ||
|
|
606af52eda | ||
|
|
8ea30aea80 | ||
|
|
72dea695ba | ||
|
|
1c0cf56ed0 | ||
|
|
bcb4eb35cd | ||
|
|
bce2676335 | ||
|
|
510097d722 | ||
|
|
5784118a12 | ||
|
|
b5de0f2d23 | ||
|
|
04df3f4dad | ||
|
|
093ca4d623 | ||
|
|
a3ed1558d3 | ||
|
|
fe379070ae | ||
|
|
ead0a2f597 | ||
|
|
5dbc593f90 | ||
|
|
d47dc12bf0 | ||
|
|
4392f63e57 | ||
|
|
f64b7aca79 | ||
|
|
3762ec5750 | ||
|
|
4591fdd9c0 | ||
|
|
d3068d2a0e | ||
|
|
ca0a4bc23a | ||
|
|
433c163c61 | ||
|
|
c867fda883 | ||
|
|
566540ae6d | ||
|
|
759f490dae | ||
|
|
867d4d44f5 | ||
|
|
65747d5877 | ||
|
|
bd357f6076 | ||
|
|
9e960b7d45 | ||
|
|
0c54d4a6a1 | ||
|
|
526e846a81 | ||
|
|
8bcfa373d4 | ||
|
|
db9a0f2c1f | ||
|
|
646b1e2193 | ||
|
|
41bd30f81d | ||
|
|
bd626aea27 | ||
|
|
8a03f75485 | ||
|
|
dc9594fbdf | ||
|
|
fad0b533c0 | ||
|
|
4d773e9453 | ||
|
|
e0c610b013 | ||
|
|
0da4f36c33 | ||
|
|
11d17e1db3 | ||
|
|
b8c318d923 | ||
|
|
e563cc6f5e | ||
|
|
cb8914ab96 | ||
|
|
2fecda7bdc | ||
|
|
543d8efb25 | ||
|
|
396b1079a7 | ||
|
|
eedcd9f8cb | ||
|
|
ab252b210c | ||
|
|
1071b8ea90 | ||
|
|
a9c5bbf185 | ||
|
|
8dd4bff7a7 | ||
|
|
77c54446af | ||
|
|
4a0bc0af57 | ||
|
|
a171e75e70 | ||
|
|
f5ffa092fe | ||
|
|
8de5fdd551 | ||
|
|
ecca3abe98 | ||
|
|
8570e35224 | ||
|
|
84df9f9a03 | ||
|
|
5f93fb9613 | ||
|
|
75f77fdbdd | ||
|
|
7825d582c2 | ||
|
|
5deb0ba933 | ||
|
|
18e917aaf2 | ||
|
|
a165f3890a | ||
|
|
f88b6d9c97 | ||
|
|
db8ecd9952 | ||
|
|
b5ec06c2d2 | ||
|
|
dfbac8385e | ||
|
|
eaab737b2c | ||
|
|
45991cda0a | ||
|
|
09a016bb6f | ||
|
|
31607d355d | ||
|
|
a67d50b9e2 | ||
|
|
8d42f53c80 | ||
|
|
5e21a55bce | ||
|
|
85930ea2e8 | ||
|
|
4b3cde8b39 | ||
|
|
eedfa85355 | ||
|
|
bb54c6c807 | ||
|
|
c23f905858 | ||
|
|
8c7be0a1d0 | ||
|
|
878497b3d5 | ||
|
|
a155561769 | ||
|
|
8b86a0ed2e | ||
|
|
26f9a9b122 | ||
|
|
6e5f6978fb | ||
|
|
0d31d7b2de | ||
|
|
dd862b7e0a | ||
|
|
52065f2cbd | ||
|
|
77c02d5831 | ||
|
|
f7e4c8d16d | ||
|
|
b7410474ff | ||
|
|
384cc4ebf6 | ||
|
|
7c0643f122 | ||
|
|
58abae3067 | ||
|
|
4742693869 | ||
|
|
6c39e474ea | ||
|
|
5c8977c906 | ||
|
|
6b3cc2e2f3 | ||
|
|
76b2edd6ea | ||
|
|
8ebb37d011 | ||
|
|
3366db83ef | ||
|
|
5415254aac | ||
|
|
caacc61602 | ||
|
|
e902df19b2 | ||
|
|
40b372dda7 | ||
|
|
fd330a98aa | ||
|
|
90c23a7d5d | ||
|
|
5710304114 | ||
|
|
0f684820bc | ||
|
|
e1d2d6ade6 | ||
|
|
e0b6f2ca71 | ||
|
|
2a35ee279b | ||
|
|
5abf780360 | ||
|
|
181f158ea9 | ||
|
|
f4087fc81d | ||
|
|
82793f9b82 | ||
|
|
537576e84a | ||
|
|
375d1f55e3 | ||
|
|
597218963f | ||
|
|
0d29b3ddc8 | ||
|
|
e0e3b42623 | ||
|
|
0995ca6614 | ||
|
|
3d741fc8d4 | ||
|
|
c20772b458 | ||
|
|
4a6b659098 | ||
|
|
2b93f08ca5 | ||
|
|
fca62b8fff | ||
|
|
dee6d9de2c | ||
|
|
574e3e7521 | ||
|
|
29fdf82ac5 | ||
|
|
c8cf2a54e8 | ||
|
|
bfd32e67d4 | ||
|
|
95915367fa | ||
|
|
b769cfda62 | ||
|
|
40ac88dfed | ||
|
|
6d96082f07 | ||
|
|
21f913db1c | ||
|
|
699a578966 | ||
|
|
babbfa1394 | ||
|
|
73f0d58e10 | ||
|
|
9cb4b74bbd | ||
|
|
f2c8456971 | ||
|
|
e571600c30 | ||
|
|
e84c94d3eb | ||
|
|
e791d4818f | ||
|
|
cdadb43e50 | ||
|
|
edaff60fbf | ||
|
|
3f64e46557 | ||
|
|
32dab23bc6 | ||
|
|
362de7dd31 | ||
|
|
6b01fbb903 | ||
|
|
4934d9f7bc | ||
|
|
ed73955b00 | ||
|
|
3f1f2726c4 | ||
|
|
1a7bd7ea8d | ||
|
|
946ea43436 | ||
|
|
7f42385f5f | ||
|
|
8845ac2b75 | ||
|
|
da85001d4d | ||
|
|
8d15079937 | ||
|
|
adc542b5cd | ||
|
|
72feb044a3 | ||
|
|
c0ba260ddf | ||
|
|
2da215e8e7 | ||
|
|
4d0368b5f1 | ||
|
|
d11c78857d | ||
|
|
e829d90c4a | ||
|
|
a8006acd33 | ||
|
|
86ec502040 | ||
|
|
b19a73cc50 | ||
|
|
a99c695932 | ||
|
|
8cd720b53a | ||
|
|
04df79e58f | ||
|
|
a4b3717762 | ||
|
|
1035e442ee | ||
|
|
60d3638f15 | ||
|
|
3e7d3c9035 | ||
|
|
eb360be2ad | ||
|
|
485ac8704d | ||
|
|
dc74540423 | ||
|
|
96219c22db | ||
|
|
f3b7048775 | ||
|
|
aaed6fb376 | ||
|
|
35a5d3310f | ||
|
|
9da79a1d2d | ||
|
|
595b355d1b | ||
|
|
3a67d769f4 | ||
|
|
6fb536a937 | ||
|
|
bb460d78d8 | ||
|
|
838835a715 | ||
|
|
63acd53e23 | ||
|
|
fcd2d0457b | ||
|
|
58fc26461b | ||
|
|
fd82f6b04e | ||
|
|
cef3200533 | ||
|
|
634500c398 | ||
|
|
b3e294ac54 | ||
|
|
2bf7535ad0 | ||
|
|
3315f75de9 | ||
|
|
bbe7dbfa92 | ||
|
|
5697922a65 | ||
|
|
4da83df2b9 | ||
|
|
8f156d6588 | ||
|
|
cec0871c11 | ||
|
|
41a809368b | ||
|
|
ea53eb9290 | ||
|
|
05875057c9 | ||
|
|
44125926d1 | ||
|
|
60734349de | ||
|
|
fbfd5ec0ec | ||
|
|
a74a95cc65 | ||
|
|
bc0ea16ff0 | ||
|
|
b2dc8aa84c | ||
|
|
9987e8b6ab | ||
|
|
0d9bdcc008 | ||
|
|
b5c634045e | ||
|
|
1f05531d53 | ||
|
|
88f382f0e3 | ||
|
|
3e59925900 | ||
|
|
ea404f8d4f | ||
|
|
602a550d93 | ||
|
|
12abbe2d23 | ||
|
|
fb0ee97588 | ||
|
|
56ef48c9c3 | ||
|
|
47c3dd3dd1 | ||
|
|
c181648bfa | ||
|
|
0cf78b3abe | ||
|
|
22889a7ad9 | ||
|
|
a14451d0ac | ||
|
|
5dfdab10b7 | ||
|
|
d6f2e3b8e9 | ||
|
|
df30517743 | ||
|
|
8f80643c1a | ||
|
|
5aea9be2fb | ||
|
|
ad02e483d0 | ||
|
|
f463d53036 | ||
|
|
b8d4408524 | ||
|
|
fef70be848 | ||
|
|
bdb12d9b24 | ||
|
|
43ad283a83 | ||
|
|
2e4936afc4 | ||
|
|
891ffabd11 | ||
|
|
e2c19498b4 | ||
|
|
c32630b265 | ||
|
|
bf21e78d02 | ||
|
|
525d4e08a3 | ||
|
|
2e9bf6d694 | ||
|
|
e845f01d85 | ||
|
|
bef48be7b4 | ||
|
|
b54fdc9e6e | ||
|
|
cedbf2e30b | ||
|
|
592f8d1b0d | ||
|
|
29612a684e | ||
|
|
e6d5807399 | ||
|
|
fa2553251f | ||
|
|
7387718852 | ||
|
|
a503a6209a | ||
|
|
ce3e5f74e8 | ||
|
|
f37112358e | ||
|
|
f368b14621 | ||
|
|
6960b1148a | ||
|
|
3cc23aac25 | ||
|
|
11dc8740f2 | ||
|
|
4b797cff88 | ||
|
|
fe1c1736cd | ||
|
|
4058ef5f09 | ||
|
|
d25ca01624 | ||
|
|
d96f87dbbf | ||
|
|
8a2e31023f | ||
|
|
1ea8e171d9 | ||
|
|
e2be3dd0ac | ||
|
|
1c51164e7b | ||
|
|
f190f03530 | ||
|
|
055fc7cbc1 | ||
|
|
9073fc3dc3 | ||
|
|
2409dc9bc4 | ||
|
|
6586c8d70b | ||
|
|
ac0c94da69 | ||
|
|
d19d6a72b0 | ||
|
|
c81b5d98ef | ||
|
|
756866675f | ||
|
|
ebcd4925f7 | ||
|
|
13bed4fdf9 | ||
|
|
1dae5c6b6c | ||
|
|
8e6663e4b0 | ||
|
|
ba804444b8 | ||
|
|
58cfb85004 | ||
|
|
ab46481b45 | ||
|
|
4296782399 | ||
|
|
ef375a7103 | ||
|
|
fd258b7765 | ||
|
|
147de8d372 | ||
|
|
eb2a1928b6 | ||
|
|
35b033102f | ||
|
|
7bc65421a9 | ||
|
|
736514cf37 | ||
|
|
db0158dae8 | ||
|
|
e706695ed1 | ||
|
|
e8877ffe2d | ||
|
|
1fd5d9dae6 | ||
|
|
cd48089318 | ||
|
|
6379ab22c9 | ||
|
|
0bf02b75d5 | ||
|
|
c4259b5598 | ||
|
|
6b3c1179bc | ||
|
|
c1a0e61e8e | ||
|
|
fc06298ed4 | ||
|
|
4ca87b188c | ||
|
|
f1f60c3e0d | ||
|
|
76d21b56af | ||
|
|
0ab0e50a4f | ||
|
|
34f4c06a5c | ||
|
|
6de36f1e53 | ||
|
|
2a9a3b1ac2 | ||
|
|
84b73a3770 | ||
|
|
662a10e273 | ||
|
|
ecce02502e | ||
|
|
d17875aea1 | ||
|
|
b8897a68f9 | ||
|
|
84efd4871e | ||
|
|
85ea5a6b70 | ||
|
|
77891acb92 | ||
|
|
74fe102035 | ||
|
|
25cc554925 | ||
|
|
d787a521b5 | ||
|
|
46e52c71e1 | ||
|
|
1dad27a172 | ||
|
|
60d230b380 | ||
|
|
d7cb38e706 | ||
|
|
ce00cca6ee | ||
|
|
d627d57bad | ||
|
|
8ffc776f1c | ||
|
|
be032b52c1 | ||
|
|
4388e81e5f | ||
|
|
71a185d139 | ||
|
|
d2cf5985ac | ||
|
|
debcbb8e5c | ||
|
|
b9dd62c7d3 | ||
|
|
dc2b430f34 | ||
|
|
e5ef4e8868 | ||
|
|
c0d6cd3ac3 | ||
|
|
b63ab2dc19 | ||
|
|
5d8dad561c | ||
|
|
8933be1ae2 | ||
|
|
6b66b48b1d | ||
|
|
9c23eb6e33 | ||
|
|
baea54a3fc | ||
|
|
d9f800454c | ||
|
|
f9ee0de07a | ||
|
|
2786d0a9f7 | ||
|
|
491e8032e6 | ||
|
|
ef3f13f5d3 | ||
|
|
bcb5b2d790 | ||
|
|
02de3f2e2a | ||
|
|
0e7bb53c07 | ||
|
|
759109d478 | ||
|
|
54d5af6edf | ||
|
|
38fbe47ced | ||
|
|
f066c925ba | ||
|
|
994fdf4e1d | ||
|
|
50b50d65e3 | ||
|
|
0aaa985649 | ||
|
|
29564f8eae | ||
|
|
c15db68a5b | ||
|
|
3452fb3e56 | ||
|
|
35eb8e7be1 | ||
|
|
834b774128 | ||
|
|
5aa0eb9f9d | ||
|
|
d9a6e2e649 | ||
|
|
cb823b16a1 | ||
|
|
0bd41e877e | ||
|
|
ecc3e73967 | ||
|
|
464b4c24f9 | ||
|
|
32367516e8 | ||
|
|
1709a55606 | ||
|
|
58b4455979 | ||
|
|
ea1dede19c | ||
|
|
20ea3381fa | ||
|
|
7aa6fccd7c | ||
|
|
adbd54f4f8 | ||
|
|
9d54261f18 | ||
|
|
a97757c9ae | ||
|
|
7c79d9f89d | ||
|
|
bf0914f813 | ||
|
|
b96bc30fbd | ||
|
|
62b50eb8ba | ||
|
|
b4932e384a | ||
|
|
5e68dc5f8d | ||
|
|
f222f1b925 | ||
|
|
22e4a54782 | ||
|
|
1289922c5f | ||
|
|
2839c352b8 | ||
|
|
6a01cbc312 | ||
|
|
6193156556 | ||
|
|
fe23aa917d | ||
|
|
eb8a29a332 | ||
|
|
0626902530 | ||
|
|
042bfe2597 | ||
|
|
97133f3591 | ||
|
|
d06cc4390e | ||
|
|
6047d3235f | ||
|
|
2cda6e35bd | ||
|
|
8f8d51e17b | ||
|
|
6919e3b274 | ||
|
|
10bf944410 | ||
|
|
9a2f6fdb53 | ||
|
|
761977d385 | ||
|
|
21248f15b5 | ||
|
|
4f32817f6d | ||
|
|
cc9e05e711 | ||
|
|
419d68d4db | ||
|
|
8450232448 | ||
|
|
cc51726590 | ||
|
|
318e22af51 | ||
|
|
68ac87dc24 | ||
|
|
acb8f00075 | ||
|
|
06d9183aaa | ||
|
|
75af25419d | ||
|
|
f6b90d2a31 | ||
|
|
a3822f4af0 | ||
|
|
bcdad769ff | ||
|
|
be4fb4fdbb | ||
|
|
65394f6301 | ||
|
|
b0beee03bc | ||
|
|
fe1de41b8e | ||
|
|
a37b431e87 | ||
|
|
98107016b9 | ||
|
|
8bccfc2863 | ||
|
|
f54a0a3452 | ||
|
|
6778ab0624 | ||
|
|
269d636785 | ||
|
|
39862c91ce | ||
|
|
523f4026b4 | ||
|
|
a6bf162431 | ||
|
|
826e8d181c | ||
|
|
16dfadbba0 | ||
|
|
5cbb97551f | ||
|
|
defee767c3 | ||
|
|
9560318521 | ||
|
|
ef09feb048 | ||
|
|
39f323fe09 | ||
|
|
11b95304ea | ||
|
|
b7c30a7916 | ||
|
|
4cae48fc77 | ||
|
|
d1a93f0557 | ||
|
|
b93059fad7 |
@@ -13,7 +13,7 @@ jobs:
|
||||
runs-on: macos-14
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4.1.6
|
||||
- uses: actions/checkout@v3.3.0
|
||||
- uses: actions/setup-java@v3
|
||||
with:
|
||||
distribution: 'temurin'
|
||||
|
||||
@@ -13,7 +13,7 @@ jobs:
|
||||
runs-on: macos-14
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4.1.6
|
||||
- uses: actions/checkout@v3.3.0
|
||||
- name: Run build script
|
||||
run: |
|
||||
cd build/ios && printf "y" | ./build.sh continuous
|
||||
|
||||
@@ -13,7 +13,7 @@ jobs:
|
||||
runs-on: ubuntu-22.04
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4.1.6
|
||||
- uses: actions/checkout@v3.3.0
|
||||
- name: Run build script
|
||||
run: |
|
||||
cd build/linux && printf "y" | ./build.sh continuous
|
||||
|
||||
@@ -13,7 +13,7 @@ jobs:
|
||||
runs-on: macos-14
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4.1.6
|
||||
- uses: actions/checkout@v3.3.0
|
||||
- name: Run build script
|
||||
run: |
|
||||
cd build/mac && printf "y" | ./build.sh continuous
|
||||
|
||||
@@ -13,7 +13,7 @@ jobs:
|
||||
name: npm-deploy
|
||||
runs-on: macos-14
|
||||
steps:
|
||||
- uses: actions/checkout@v4.1.6
|
||||
- uses: actions/checkout@v3.3.0
|
||||
with:
|
||||
ref: ${{ github.event.inputs.release_tag }}
|
||||
# Setup .npmrc file to publish to npm
|
||||
|
||||
@@ -18,7 +18,7 @@ jobs:
|
||||
os: [macos-14, ubuntu-22.04]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4.1.6
|
||||
- uses: actions/checkout@v3.3.0
|
||||
- name: Run build script
|
||||
run: |
|
||||
WORKFLOW_OS=`echo \`uname\` | sed "s/Darwin/mac/" | tr [:upper:] [:lower:]`
|
||||
@@ -32,7 +32,7 @@ jobs:
|
||||
runs-on: windows-2019
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4.1.6
|
||||
- uses: actions/checkout@v3.3.0
|
||||
- name: Run build script
|
||||
run: |
|
||||
build\windows\build-github.bat presubmit
|
||||
@@ -43,7 +43,7 @@ jobs:
|
||||
runs-on: macos-14
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4.1.6
|
||||
- uses: actions/checkout@v3.3.0
|
||||
- uses: actions/setup-java@v3
|
||||
with:
|
||||
distribution: 'temurin'
|
||||
@@ -57,7 +57,7 @@ jobs:
|
||||
runs-on: macos-14
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4.1.6
|
||||
- uses: actions/checkout@v3.3.0
|
||||
- name: Run build script
|
||||
run: |
|
||||
cd build/ios && printf "y" | ./build.sh presubmit
|
||||
@@ -70,7 +70,7 @@ jobs:
|
||||
runs-on: macos-14
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4.1.6
|
||||
- uses: actions/checkout@v3.3.0
|
||||
- name: Run build script
|
||||
run: |
|
||||
cd build/web && printf "y" | ./build.sh presubmit
|
||||
|
||||
@@ -41,7 +41,7 @@ jobs:
|
||||
TAG=${REF##*/}
|
||||
echo "ref=${REF}" >> $GITHUB_OUTPUT
|
||||
echo "tag=${TAG}" >> $GITHUB_OUTPUT
|
||||
- uses: actions/checkout@v4.1.6
|
||||
- uses: actions/checkout@v3.3.0
|
||||
with:
|
||||
ref: ${{ steps.git_ref.outputs.ref }}
|
||||
- name: Run build script
|
||||
@@ -76,7 +76,7 @@ jobs:
|
||||
TAG=${REF##*/}
|
||||
echo "ref=${REF}" >> $GITHUB_OUTPUT
|
||||
echo "tag=${TAG}" >> $GITHUB_OUTPUT
|
||||
- uses: actions/checkout@v4.1.6
|
||||
- uses: actions/checkout@v3.3.0
|
||||
with:
|
||||
ref: ${{ steps.git_ref.outputs.ref }}
|
||||
- name: Run build script
|
||||
@@ -109,7 +109,7 @@ jobs:
|
||||
TAG=${REF##*/}
|
||||
echo "ref=${REF}" >> $GITHUB_OUTPUT
|
||||
echo "tag=${TAG}" >> $GITHUB_OUTPUT
|
||||
- uses: actions/checkout@v4.1.6
|
||||
- uses: actions/checkout@v3.3.0
|
||||
with:
|
||||
ref: ${{ steps.git_ref.outputs.ref }}
|
||||
- uses: actions/setup-java@v3
|
||||
@@ -163,7 +163,7 @@ jobs:
|
||||
TAG=${REF##*/}
|
||||
echo "ref=${REF}" >> $GITHUB_OUTPUT
|
||||
echo "tag=${TAG}" >> $GITHUB_OUTPUT
|
||||
- uses: actions/checkout@v4.1.6
|
||||
- uses: actions/checkout@v3.3.0
|
||||
with:
|
||||
ref: ${{ steps.git_ref.outputs.ref }}
|
||||
- name: Run build script
|
||||
@@ -197,7 +197,7 @@ jobs:
|
||||
echo "ref=${REF}" >> $GITHUB_OUTPUT
|
||||
echo "tag=${TAG}" >> $GITHUB_OUTPUT
|
||||
shell: bash
|
||||
- uses: actions/checkout@v4.1.6
|
||||
- uses: actions/checkout@v3.3.0
|
||||
with:
|
||||
ref: ${{ steps.git_ref.outputs.ref }}
|
||||
- name: Run build script
|
||||
@@ -205,7 +205,7 @@ jobs:
|
||||
TAG: ${{ steps.git_ref.outputs.tag }}
|
||||
run: |
|
||||
build\windows\build-github.bat release
|
||||
move out\filament-windows.tgz out\filament-%TAG%-windows.tgz
|
||||
move out\filament-windows.tgz out\filament-$Env:TAG-windows.tgz
|
||||
shell: cmd
|
||||
- uses: actions/github-script@v6
|
||||
env:
|
||||
|
||||
@@ -13,7 +13,7 @@ jobs:
|
||||
runs-on: macos-14
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4.1.6
|
||||
- uses: actions/checkout@v3.3.0
|
||||
- name: Run build script
|
||||
run: |
|
||||
cd build/web && printf "y" | ./build.sh continuous
|
||||
|
||||
@@ -13,7 +13,7 @@ jobs:
|
||||
runs-on: windows-2019
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4.1.6
|
||||
- uses: actions/checkout@v3.3.0
|
||||
- name: Run build script
|
||||
run: |
|
||||
build\windows\build-github.bat continuous
|
||||
|
||||
+16
-45
@@ -73,6 +73,7 @@ The following CMake options are boolean options specific to Filament:
|
||||
- `FILAMENT_SUPPORTS_VULKAN`: Include the Vulkan backend
|
||||
- `FILAMENT_INSTALL_BACKEND_TEST`: Install the backend test library so it can be consumed on iOS
|
||||
- `FILAMENT_USE_EXTERNAL_GLES3`: Experimental: Compile Filament against OpenGL ES 3
|
||||
- `FILAMENT_USE_SWIFTSHADER`: Compile Filament against SwiftShader
|
||||
- `FILAMENT_SKIP_SAMPLES`: Don't build sample apps
|
||||
|
||||
To turn an option on or off:
|
||||
@@ -425,7 +426,7 @@ value is the desired roughness between 0 and 1.
|
||||
|
||||
## Generating C++ documentation
|
||||
|
||||
To generate the documentation you must first install `doxygen` and `graphviz`, then run the
|
||||
To generate the documentation you must first install `doxygen` and `graphviz`, then run the
|
||||
following commands:
|
||||
|
||||
```shell
|
||||
@@ -435,62 +436,32 @@ doxygen docs/doxygen/filament.doxygen
|
||||
|
||||
Finally simply open `docs/html/index.html` in your web browser.
|
||||
|
||||
## Software Rasterization
|
||||
## SwiftShader
|
||||
|
||||
We have tested swiftshader and Mesa for software rasterization on the Vulkan/GL backends.
|
||||
|
||||
To use this for Vulkan, please first make sure that the [Vulkan SDK](https://www.lunarg.com/vulkan-sdk/) is
|
||||
installed on your machine. If you are doing a manual installation of the SDK on Linux, you will have
|
||||
to source `setup-env.sh` in the SDK's root folder to make sure the Vulkan loader is the first lib loaded.
|
||||
|
||||
### Swiftshader (Vulkan) [tested on macOS and Linux]
|
||||
|
||||
First, build SwiftShader
|
||||
To try out Filament's Vulkan support with SwiftShader, first build SwiftShader and set the
|
||||
`SWIFTSHADER_LD_LIBRARY_PATH` variable to the folder that contains `libvk_swiftshader.dylib`:
|
||||
|
||||
```shell
|
||||
git clone https://github.com/google/swiftshader.git
|
||||
cd swiftshader/build
|
||||
cmake .. && make -j
|
||||
export SWIFTSHADER_LD_LIBRARY_PATH=`pwd`
|
||||
```
|
||||
|
||||
and then set `VK_ICD_FILENAMES` to the ICD json produced in the build. For example,
|
||||
```shell
|
||||
export VK_ICD_FILENAMES=/Users/user/swiftshader/build/Darwin/vk_swiftshader_icd.json
|
||||
```
|
||||
Next, go to your Filament repo and use the [easy build](#easy-build) script with `-t`.
|
||||
|
||||
Build and run Filament as usual and specify the Vulkan backend when creating the Engine.
|
||||
## SwiftShader for CI
|
||||
|
||||
### Mesa's LLVMPipe (GL) and Lavapipe (Vulkan) [tested on Linux]
|
||||
|
||||
We will only cover steps that build Mesa from source. The official documentation of Mesa mentioned
|
||||
that in general precompiled libraries [are **not** made available](https://docs.mesa3d.org/precompiled.html).
|
||||
|
||||
Download the repo and make sure you have the build depedencies. For example (assuming an Ubuntu/Debian distro),
|
||||
```shell
|
||||
git clone https://gitlab.freedesktop.org/mesa/mesa.git
|
||||
sudo apt-get build-dep mesa
|
||||
```
|
||||
|
||||
To build both the GL and Vulkan rasterizers,
|
||||
Continuous testing turnaround can be quite slow if you need to build SwiftShader from scratch, so we
|
||||
provide an Ubuntu-based Docker image that has it already built. The Docker image also includes
|
||||
everything necessary for building Filament. You can fetch and run the image as follows:
|
||||
|
||||
```shell
|
||||
cd mesa
|
||||
mkdir -p out
|
||||
meson setup builddir/ -Dprefix=$(pwd)/out -Dglx=xlib -Dgallium-drivers=swrast -Dvulkan-drivers=swrast
|
||||
meson install -C builddir/
|
||||
docker pull ghcr.io/filament-assets/swiftshader
|
||||
docker run -it ghcr.io/filament-assets/swiftshader
|
||||
```
|
||||
|
||||
For GL, we need to ensure that we load the GL lib from the mesa output directory. For example, to run
|
||||
the debug `gltf_viewer`, we would execute
|
||||
```shell
|
||||
LD_LIBRARY_PATH=/Users/user/mesa/out/lib/x86_64-linux-gnu \
|
||||
./out/cmake-debug/samples/gltf_viewer -a opengl
|
||||
```
|
||||
To do more with the container, see the helper script at `build/swiftshader/test.sh`.
|
||||
|
||||
For Vulkan, we need to set the path to the ICD json, which tells the loader where to find the driver
|
||||
library. To run `gltf_viewer`, we would execute
|
||||
```shell
|
||||
VK_ICD_FILENAMES=/Users/user/mesa/out/share/vulkan/icd.d/lvp_icd.x86_64.json \
|
||||
./out/cmake-debug/samples/gltf_viewer -a vulkan
|
||||
|
||||
```
|
||||
If you are a team member, you can update the public image to the latest SwiftShader by
|
||||
following the instructions at the top of `build/swiftshader/Dockerfile`.
|
||||
|
||||
+38
-40
@@ -21,6 +21,8 @@ project(TNT)
|
||||
# ==================================================================================================
|
||||
option(FILAMENT_USE_EXTERNAL_GLES3 "Experimental: Compile Filament against OpenGL ES 3" OFF)
|
||||
|
||||
option(FILAMENT_USE_SWIFTSHADER "Compile Filament against SwiftShader" OFF)
|
||||
|
||||
option(FILAMENT_ENABLE_LTO "Enable link-time optimizations if supported by the compiler" OFF)
|
||||
|
||||
option(FILAMENT_SKIP_SAMPLES "Don't build samples" OFF)
|
||||
@@ -43,8 +45,6 @@ option(FILAMENT_ENABLE_TSAN "Enable Thread Sanitizer" OFF)
|
||||
|
||||
option(FILAMENT_ENABLE_FEATURE_LEVEL_0 "Enable Feature Level 0" ON)
|
||||
|
||||
option(FILAMENT_ENABLE_MULTIVIEW "Enable multiview for Filament" OFF)
|
||||
|
||||
set(FILAMENT_NDK_VERSION "" CACHE STRING
|
||||
"Android NDK version or version prefix to be used when building for Android."
|
||||
)
|
||||
@@ -69,10 +69,6 @@ set(FILAMENT_METAL_HANDLE_ARENA_SIZE_IN_MB "8" CACHE STRING
|
||||
"Size of the Metal handle arena, default 8."
|
||||
)
|
||||
|
||||
set(FILAMENT_BACKEND_DEBUG_FLAG "" CACHE STRING
|
||||
"A debug flag meant for enabling/disabling backend debugging paths"
|
||||
)
|
||||
|
||||
# Enable exceptions by default in spirv-cross.
|
||||
set(SPIRV_CROSS_EXCEPTIONS_TO_ASSERTIONS OFF)
|
||||
|
||||
@@ -143,6 +139,11 @@ if (LINUX)
|
||||
add_definitions(-DFILAMENT_SUPPORTS_XCB)
|
||||
endif()
|
||||
|
||||
# Default Swiftshader build does not enable the xlib extension
|
||||
if (FILAMENT_SUPPORTS_XLIB AND FILAMENT_USE_SWIFTSHADER)
|
||||
set(FILAMENT_SUPPORTS_XLIB OFF)
|
||||
endif()
|
||||
|
||||
if (FILAMENT_SUPPORTS_XLIB)
|
||||
add_definitions(-DFILAMENT_SUPPORTS_XLIB)
|
||||
endif()
|
||||
@@ -166,6 +167,15 @@ if (NOT ANDROID AND NOT WEBGL AND NOT IOS AND NOT FILAMENT_LINUX_IS_MOBILE)
|
||||
set(IS_HOST_PLATFORM TRUE)
|
||||
endif()
|
||||
|
||||
if (IOS)
|
||||
# Remove the headerpad_max_install_names linker flag on iOS. It causes warnings when linking
|
||||
# executables with bitcode.
|
||||
string(REPLACE "-Wl,-headerpad_max_install_names" "" CMAKE_C_LINK_FLAGS ${CMAKE_C_LINK_FLAGS})
|
||||
string(REPLACE "-Wl,-headerpad_max_install_names" "" CMAKE_CXX_LINK_FLAGS ${CMAKE_CXX_LINK_FLAGS})
|
||||
string(REPLACE "-Wl,-headerpad_max_install_names" "" CMAKE_SHARED_LIBRARY_CREATE_C_FLAGS ${CMAKE_SHARED_LIBRARY_CREATE_C_FLAGS})
|
||||
string(REPLACE "-Wl,-headerpad_max_install_names" "" CMAKE_SHARED_LIBRARY_CREATE_CXX_FLAGS ${CMAKE_SHARED_LIBRARY_CREATE_CXX_FLAGS})
|
||||
endif()
|
||||
|
||||
if (WIN32)
|
||||
# Link statically against c/c++ lib to avoid missing redistriburable such as
|
||||
# "VCRUNTIME140.dll not found. Try reinstalling the app.", but give users
|
||||
@@ -320,6 +330,10 @@ if (FILAMENT_SUPPORTS_EGL_ON_LINUX)
|
||||
set(EGL TRUE)
|
||||
endif()
|
||||
|
||||
if (FILAMENT_USE_SWIFTSHADER)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DFILAMENT_USE_SWIFTSHADER")
|
||||
endif()
|
||||
|
||||
if (WIN32)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -D_USE_MATH_DEFINES=1")
|
||||
endif()
|
||||
@@ -373,9 +387,8 @@ endif()
|
||||
if (NOT MSVC AND NOT IOS)
|
||||
# Omitting stack frame pointers prevents the generation of readable stack traces in crash reports on iOS
|
||||
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -fomit-frame-pointer")
|
||||
endif()
|
||||
|
||||
if (NOT MSVC)
|
||||
# These aren't compatible with -fembed-bitcode (and seem to have no effect on Apple platforms anyway)
|
||||
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -ffunction-sections -fdata-sections")
|
||||
endif()
|
||||
|
||||
@@ -440,13 +453,8 @@ endif()
|
||||
if (NOT WEBGL)
|
||||
set(GC_SECTIONS "-Wl,--gc-sections")
|
||||
endif()
|
||||
|
||||
set(B_SYMBOLIC_FUNCTIONS "-Wl,-Bsymbolic-functions")
|
||||
|
||||
if (ANDROID)
|
||||
set(BINARY_ALIGNMENT "-Wl,-z,max-page-size=16384")
|
||||
endif()
|
||||
|
||||
if (APPLE)
|
||||
set(GC_SECTIONS "-Wl,-dead_strip")
|
||||
set(B_SYMBOLIC_FUNCTIONS "")
|
||||
@@ -460,7 +468,7 @@ if (APPLE)
|
||||
endif()
|
||||
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${GC_SECTIONS}")
|
||||
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} ${GC_SECTIONS} ${B_SYMBOLIC_FUNCTIONS} ${BINARY_ALIGNMENT}")
|
||||
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} ${GC_SECTIONS} ${B_SYMBOLIC_FUNCTIONS}")
|
||||
|
||||
if (WEBGL_PTHREADS)
|
||||
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -pthread")
|
||||
@@ -523,29 +531,6 @@ else()
|
||||
option(FILAMENT_DISABLE_MATOPT "Disable material optimizations" ON)
|
||||
endif()
|
||||
|
||||
# This only affects the prebuilt shader files in gltfio and samples, not filament library.
|
||||
# The value can be either "instanced", "multiview", or "none"
|
||||
set(FILAMENT_SAMPLES_STEREO_TYPE "none" CACHE STRING
|
||||
"Stereoscopic type that shader files in gltfio and samples are built for."
|
||||
)
|
||||
string(TOLOWER "${FILAMENT_SAMPLES_STEREO_TYPE}" FILAMENT_SAMPLES_STEREO_TYPE)
|
||||
if (NOT FILAMENT_SAMPLES_STEREO_TYPE STREQUAL "instanced"
|
||||
AND NOT FILAMENT_SAMPLES_STEREO_TYPE STREQUAL "multiview"
|
||||
AND NOT FILAMENT_SAMPLES_STEREO_TYPE STREQUAL "none")
|
||||
message(FATAL_ERROR "Invalid stereo type: \"${FILAMENT_SAMPLES_STEREO_TYPE}\" choose either \"instanced\", \"multiview\", or \"none\" ")
|
||||
endif ()
|
||||
|
||||
# Compiling samples for multiview implies enabling multiview feature as well.
|
||||
if (FILAMENT_SAMPLES_STEREO_TYPE STREQUAL "multiview")
|
||||
set(FILAMENT_ENABLE_MULTIVIEW ON)
|
||||
endif ()
|
||||
|
||||
# Define backend flag for debug only
|
||||
if (CMAKE_BUILD_TYPE STREQUAL "Debug" AND NOT FILAMENT_BACKEND_DEBUG_FLAG STREQUAL "")
|
||||
add_definitions(-DFILAMENT_BACKEND_DEBUG_FLAG=${FILAMENT_BACKEND_DEBUG_FLAG})
|
||||
unset(FILAMENT_BACKEND_DEBUG_FLAG)
|
||||
endif()
|
||||
|
||||
# ==================================================================================================
|
||||
# Material compilation flags
|
||||
# ==================================================================================================
|
||||
@@ -674,6 +659,21 @@ else()
|
||||
set(IMPORT_EXECUTABLES ${FILAMENT}/${IMPORT_EXECUTABLES_DIR}/ImportExecutables-${CMAKE_BUILD_TYPE}.cmake)
|
||||
endif()
|
||||
|
||||
# ==================================================================================================
|
||||
# Try to find Vulkan if the SDK is installed, otherwise fall back to the bundled version.
|
||||
# This needs to stay in our top-level CMakeLists because it sets up variables that are used by the
|
||||
# "bluevk" and "samples" targets.
|
||||
# ==================================================================================================
|
||||
|
||||
if (FILAMENT_USE_SWIFTSHADER)
|
||||
if (NOT FILAMENT_SUPPORTS_VULKAN)
|
||||
message(ERROR "SwiftShader is only useful when Vulkan is enabled.")
|
||||
endif()
|
||||
find_library(SWIFTSHADER_VK NAMES vk_swiftshader HINTS "$ENV{SWIFTSHADER_LD_LIBRARY_PATH}")
|
||||
message(STATUS "Found SwiftShader VK library in: ${SWIFTSHADER_VK}.")
|
||||
add_definitions(-DFILAMENT_VKLIBRARY_PATH=\"${SWIFTSHADER_VK}\")
|
||||
endif()
|
||||
|
||||
# ==================================================================================================
|
||||
# Common Functions
|
||||
# ==================================================================================================
|
||||
@@ -735,6 +735,7 @@ add_subdirectory(${FILAMENT}/filament)
|
||||
add_subdirectory(${FILAMENT}/shaders)
|
||||
add_subdirectory(${EXTERNAL}/basisu/tnt)
|
||||
add_subdirectory(${EXTERNAL}/civetweb/tnt)
|
||||
add_subdirectory(${EXTERNAL}/hat-trie/tnt)
|
||||
add_subdirectory(${EXTERNAL}/imgui/tnt)
|
||||
add_subdirectory(${EXTERNAL}/robin-map/tnt)
|
||||
add_subdirectory(${EXTERNAL}/smol-v/tnt)
|
||||
@@ -801,9 +802,6 @@ if (IS_HOST_PLATFORM)
|
||||
add_subdirectory(${TOOLS}/glslminifier)
|
||||
add_subdirectory(${TOOLS}/matc)
|
||||
add_subdirectory(${TOOLS}/matinfo)
|
||||
if (NOT WIN32) # matedit not yet supported on Windows
|
||||
add_subdirectory(${TOOLS}/matedit)
|
||||
endif()
|
||||
add_subdirectory(${TOOLS}/mipgen)
|
||||
add_subdirectory(${TOOLS}/normal-blending)
|
||||
add_subdirectory(${TOOLS}/resgen)
|
||||
|
||||
@@ -7,5 +7,3 @@ for next branch cut* header.
|
||||
appropriate header in [RELEASE_NOTES.md](./RELEASE_NOTES.md).
|
||||
|
||||
## Release notes for next branch cut
|
||||
|
||||
- Add a `name` API to Filament objects for debugging handle use-after-free assertions
|
||||
|
||||
@@ -31,7 +31,7 @@ repositories {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation 'com.google.android.filament:filament-android:1.54.0'
|
||||
implementation 'com.google.android.filament:filament-android:1.50.4'
|
||||
}
|
||||
```
|
||||
|
||||
@@ -51,7 +51,7 @@ Here are all the libraries available in the group `com.google.android.filament`:
|
||||
iOS projects can use CocoaPods to install the latest release:
|
||||
|
||||
```shell
|
||||
pod 'Filament', '~> 1.54.0'
|
||||
pod 'Filament', '~> 1.50.4'
|
||||
```
|
||||
|
||||
### Snapshots
|
||||
@@ -176,7 +176,6 @@ steps:
|
||||
- [x] KHR_materials_unlit
|
||||
- [x] KHR_materials_variants
|
||||
- [x] KHR_materials_volume
|
||||
- [x] KHR_materials_specular
|
||||
- [x] KHR_mesh_quantization
|
||||
- [x] KHR_texture_basisu
|
||||
- [x] KHR_texture_transform
|
||||
|
||||
@@ -7,101 +7,6 @@ A new header is inserted each time a *tag* is created.
|
||||
Instead, if you are authoring a PR for the main branch, add your release note to
|
||||
[NEW_RELEASE_NOTES.md](./NEW_RELEASE_NOTES.md).
|
||||
|
||||
## v1.54.1
|
||||
|
||||
|
||||
## v1.54.0
|
||||
|
||||
- materials: add a new `stereoscopicType` material parameter. [⚠️ **New Material Version**]
|
||||
- Fix a crash when compiling shaders on IMG devices
|
||||
|
||||
## v1.53.5
|
||||
|
||||
- engine: Fix bug causing certain sampler parameters to not be applied correctly in GLES 2.0 and on
|
||||
certain GLES 3.0 drivers.
|
||||
|
||||
## v1.53.4
|
||||
|
||||
|
||||
## v1.53.3
|
||||
|
||||
- Add drag and drop support for IBL files for desktop gltf_viewer.
|
||||
|
||||
## v1.53.2
|
||||
|
||||
|
||||
## v1.53.1
|
||||
|
||||
|
||||
## v1.53.0
|
||||
|
||||
- engine: fix skinning normals with large transforms (b/342459864) [⚠️ **New Material Version**]
|
||||
|
||||
## v1.52.3
|
||||
|
||||
|
||||
## v1.52.2
|
||||
|
||||
|
||||
## v1.52.1
|
||||
|
||||
- Add instructions for using Mesa for software rasterization
|
||||
|
||||
## v1.51.9
|
||||
|
||||
|
||||
## v1.51.8
|
||||
|
||||
- filagui: Fix regression which broke WebGL
|
||||
- Add a new Engine::Config setting to control preferred shader language
|
||||
- Add `getEyeIndex` vertex API
|
||||
- ios: Remove bitcode from iOS builds
|
||||
|
||||
## v1.51.7
|
||||
|
||||
- Add new matedit tool
|
||||
- filagui: Support rendering `GL_TEXTURE_EXTERNAL_OES` textures.
|
||||
- `setFrameScheduledCallback` now takes a `utils::Invocable`.
|
||||
- engine: Add `isPaused()`
|
||||
|
||||
## v1.51.6
|
||||
|
||||
- Add new matedit tool
|
||||
- filagui: Support rendering `GL_TEXTURE_EXTERNAL_OES` textures.
|
||||
|
||||
## v1.51.5
|
||||
|
||||
|
||||
## v1.51.4
|
||||
|
||||
|
||||
## v1.51.3
|
||||
|
||||
|
||||
## v1.51.2
|
||||
|
||||
- engine: Add experimental APIs `Engine::builder::paused()` and `Engine::setPaused()`
|
||||
|
||||
## v1.51.1
|
||||
|
||||
|
||||
## v1.51.0
|
||||
|
||||
- materials: add support for post-lighting mix factor (b/328498606) [⚠️ **New Material Version**]
|
||||
|
||||
## v1.50.6
|
||||
|
||||
- Add new API `SwapChain::getFrameScheduledCallback`
|
||||
- vulkan: fixed validation error VUID-vkAcquireNextImageKHR-semaphore-01779
|
||||
- opengl: Add support for protected content swapchains and contexts
|
||||
|
||||
## v1.50.5
|
||||
|
||||
- android: NDK 26.1.10909125 is used by default
|
||||
- android: Minimum API level on Android is now API 21 instead of API 19. This allows the use of OpenGL ES 3.1
|
||||
- rendering: New PBR Neutral tone mapper, designed to preserve materials color appearance
|
||||
- android: Change default frameRateOptions.interval to 1.0
|
||||
|
||||
## v1.50.4
|
||||
|
||||
|
||||
|
||||
@@ -80,15 +80,15 @@ buildscript {
|
||||
|
||||
ext.versions = [
|
||||
'jdk': 17,
|
||||
'minSdk': 21,
|
||||
'minSdk': 19,
|
||||
'targetSdk': 34,
|
||||
'compileSdk': 34,
|
||||
'kotlin': '2.0.0',
|
||||
'kotlin_coroutines': '1.9.0-RC',
|
||||
'kotlin': '1.9.21',
|
||||
'kotlin_coroutines': '1.7.3',
|
||||
'buildTools': '34.0.0',
|
||||
'ndk': '27.0.11718014',
|
||||
'androidx_core': '1.13.1',
|
||||
'androidx_annotations': '1.8.0'
|
||||
'ndk': '26.1.10909125',
|
||||
'androidx_core': '1.12.0',
|
||||
'androidx_annotations': '1.7.0'
|
||||
]
|
||||
|
||||
ext.deps = [
|
||||
@@ -104,7 +104,7 @@ buildscript {
|
||||
]
|
||||
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:8.4.1'
|
||||
classpath 'com.android.tools.build:gradle:8.2.0'
|
||||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:${versions.kotlin}"
|
||||
}
|
||||
|
||||
|
||||
@@ -38,7 +38,6 @@ set(FILAMAT_INCLUDE_DIRS
|
||||
include_directories(${FILAMENT_DIR}/include)
|
||||
|
||||
set(CMAKE_SHARED_LINKER_FLAGS_RELEASE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE} -Wl,--version-script=${CMAKE_SOURCE_DIR}/libfilamat-jni.map")
|
||||
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,-z,max-page-size=16384")
|
||||
|
||||
add_library(filamat-jni SHARED src/main/cpp/MaterialBuilder.cpp)
|
||||
target_include_directories(filamat-jni PRIVATE ${FILAMAT_INCLUDE_DIRS})
|
||||
|
||||
@@ -59,7 +59,6 @@ endif()
|
||||
|
||||
set(VERSION_SCRIPT "${CMAKE_CURRENT_SOURCE_DIR}/libfilament-jni.map")
|
||||
set(CMAKE_SHARED_LINKER_FLAGS_RELEASE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE} -Wl,--version-script=${VERSION_SCRIPT}")
|
||||
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,-z,max-page-size=16384")
|
||||
|
||||
add_library(filament-jni SHARED
|
||||
src/main/cpp/BufferObject.cpp
|
||||
|
||||
@@ -342,21 +342,6 @@ Java_com_google_android_filament_Engine_nIsValidMaterial(JNIEnv*, jclass,
|
||||
return (jboolean)engine->isValid((Material*)nativeMaterial);
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT jboolean JNICALL
|
||||
Java_com_google_android_filament_Engine_nIsValidMaterialInstance(JNIEnv*, jclass,
|
||||
jlong nativeEngine, jlong nativeMaterial, jlong nativeMaterialInstance) {
|
||||
Engine* engine = (Engine *)nativeEngine;
|
||||
return (jboolean)engine->isValid((Material*)nativeMaterial,
|
||||
(MaterialInstance*)nativeMaterialInstance);
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT jboolean JNICALL
|
||||
Java_com_google_android_filament_Engine_nIsValidExpensiveMaterialInstance(JNIEnv*, jclass,
|
||||
jlong nativeEngine, jlong nativeMaterialInstance) {
|
||||
Engine* engine = (Engine *)nativeEngine;
|
||||
return (jboolean)engine->isValidExpensive((MaterialInstance*)nativeMaterialInstance);
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT jboolean JNICALL
|
||||
Java_com_google_android_filament_Engine_nIsValidSkybox(JNIEnv*, jclass,
|
||||
jlong nativeEngine, jlong nativeSkybox) {
|
||||
@@ -406,27 +391,6 @@ Java_com_google_android_filament_Engine_nFlush(JNIEnv*, jclass,
|
||||
engine->flush();
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT jboolean JNICALL
|
||||
Java_com_google_android_filament_Engine_nIsPaused(JNIEnv*, jclass,
|
||||
jlong nativeEngine) {
|
||||
Engine* engine = (Engine*) nativeEngine;
|
||||
return (jboolean)engine->isPaused();
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT void JNICALL
|
||||
Java_com_google_android_filament_Engine_nSetPaused(JNIEnv*, jclass,
|
||||
jlong nativeEngine, jboolean paused) {
|
||||
Engine* engine = (Engine*) nativeEngine;
|
||||
engine->setPaused(paused);
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT void JNICALL
|
||||
Java_com_google_android_filament_Engine_nUnprotected(JNIEnv*, jclass,
|
||||
jlong nativeEngine, jboolean paused) {
|
||||
Engine* engine = (Engine*) nativeEngine;
|
||||
engine->unprotected();
|
||||
}
|
||||
|
||||
// Managers...
|
||||
|
||||
extern "C" JNIEXPORT jlong JNICALL
|
||||
@@ -523,10 +487,7 @@ extern "C" JNIEXPORT void JNICALL Java_com_google_android_filament_Engine_nSetBu
|
||||
jlong jobSystemThreadCount,
|
||||
jlong textureUseAfterFreePoolSize, jboolean disableParallelShaderCompile,
|
||||
jint stereoscopicType, jlong stereoscopicEyeCount,
|
||||
jlong resourceAllocatorCacheSizeMB, jlong resourceAllocatorCacheMaxAge,
|
||||
jboolean disableHandleUseAfterFreeCheck,
|
||||
jint preferredShaderLanguage,
|
||||
jboolean forceGLES2Context) {
|
||||
jlong resourceAllocatorCacheSizeMB, jlong resourceAllocatorCacheMaxAge) {
|
||||
Engine::Builder* builder = (Engine::Builder*) nativeBuilder;
|
||||
Engine::Config config = {
|
||||
.commandBufferSizeMB = (uint32_t) commandBufferSizeMB,
|
||||
@@ -541,9 +502,6 @@ extern "C" JNIEXPORT void JNICALL Java_com_google_android_filament_Engine_nSetBu
|
||||
.stereoscopicEyeCount = (uint8_t) stereoscopicEyeCount,
|
||||
.resourceAllocatorCacheSizeMB = (uint32_t) resourceAllocatorCacheSizeMB,
|
||||
.resourceAllocatorCacheMaxAge = (uint8_t) resourceAllocatorCacheMaxAge,
|
||||
.disableHandleUseAfterFreeCheck = (bool) disableHandleUseAfterFreeCheck,
|
||||
.preferredShaderLanguage = (Engine::Config::ShaderLanguage) preferredShaderLanguage,
|
||||
.forceGLES2Context = (bool) forceGLES2Context,
|
||||
};
|
||||
builder->config(&config);
|
||||
}
|
||||
@@ -560,20 +518,8 @@ extern "C" JNIEXPORT void JNICALL Java_com_google_android_filament_Engine_nSetBu
|
||||
builder->sharedContext((void*) sharedContext);
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT void JNICALL Java_com_google_android_filament_Engine_nSetBuilderPaused(
|
||||
JNIEnv*, jclass, jlong nativeBuilder, jboolean paused) {
|
||||
Engine::Builder* builder = (Engine::Builder*) nativeBuilder;
|
||||
builder->paused((bool) paused);
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT jlong JNICALL
|
||||
Java_com_google_android_filament_Engine_nBuilderBuild(JNIEnv*, jclass, jlong nativeBuilder) {
|
||||
Engine::Builder* builder = (Engine::Builder*) nativeBuilder;
|
||||
return (jlong) builder->build();
|
||||
}
|
||||
|
||||
extern "C"
|
||||
JNIEXPORT jlong JNICALL
|
||||
Java_com_google_android_filament_Engine_getSteadyClockTimeNano(JNIEnv *env, jclass clazz) {
|
||||
return (jlong)Engine::getSteadyClockTimeNano();
|
||||
}
|
||||
|
||||
@@ -25,17 +25,12 @@ using namespace filament;
|
||||
|
||||
extern "C" JNIEXPORT jlong JNICALL
|
||||
Java_com_google_android_filament_Material_nBuilderBuild(JNIEnv *env, jclass,
|
||||
jlong nativeEngine, jobject buffer_, jint size, jint shBandCount) {
|
||||
jlong nativeEngine, jobject buffer_, jint size) {
|
||||
Engine* engine = (Engine*) nativeEngine;
|
||||
AutoBuffer buffer(env, buffer_, size);
|
||||
auto builder = Material::Builder();
|
||||
if (shBandCount) {
|
||||
builder.sphericalHarmonicsBandCount(shBandCount);
|
||||
}
|
||||
Material* material = builder
|
||||
Material* material = Material::Builder()
|
||||
.package(buffer.getData(), buffer.getSize())
|
||||
.build(*engine);
|
||||
|
||||
return (jlong) material;
|
||||
}
|
||||
|
||||
|
||||
@@ -104,14 +104,6 @@ Java_com_google_android_filament_RenderableManager_nBuilderGeometry__JIIJJIIII(J
|
||||
(size_t) count);
|
||||
}
|
||||
|
||||
extern "C"
|
||||
JNIEXPORT void JNICALL
|
||||
Java_com_google_android_filament_RenderableManager_nBuilderGeometryType(JNIEnv*, jclass,
|
||||
jlong nativeBuilder, int type) {
|
||||
RenderableManager::Builder *builder = (RenderableManager::Builder *) nativeBuilder;
|
||||
builder->geometryType((RenderableManager::Builder::GeometryType)type);
|
||||
}
|
||||
|
||||
extern "C"
|
||||
JNIEXPORT void JNICALL
|
||||
Java_com_google_android_filament_RenderableManager_nBuilderMaterial(JNIEnv*, jclass,
|
||||
@@ -245,18 +237,12 @@ Java_com_google_android_filament_RenderableManager_nBuilderMorphing(JNIEnv*, jcl
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT void JNICALL
|
||||
Java_com_google_android_filament_RenderableManager_nBuilderMorphingStandard(JNIEnv*, jclass,
|
||||
jlong nativeBuilder, jlong nativeMorphTargetBuffer) {
|
||||
Java_com_google_android_filament_RenderableManager_nBuilderSetMorphTargetBufferAt(JNIEnv*, jclass,
|
||||
jlong nativeBuilder, int level, int primitiveIndex, jlong nativeMorphTargetBuffer,
|
||||
int offset, int count) {
|
||||
RenderableManager::Builder *builder = (RenderableManager::Builder *) nativeBuilder;
|
||||
MorphTargetBuffer *morphTargetBuffer = (MorphTargetBuffer *) nativeMorphTargetBuffer;
|
||||
builder->morphing(morphTargetBuffer);
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT void JNICALL
|
||||
Java_com_google_android_filament_RenderableManager_nBuilderSetMorphTargetBufferOffsetAt(JNIEnv*, jclass,
|
||||
jlong nativeBuilder, int level, int primitiveIndex, int offset) {
|
||||
RenderableManager::Builder *builder = (RenderableManager::Builder *) nativeBuilder;
|
||||
builder->morphing(level, primitiveIndex, offset);
|
||||
builder->morphing(level, primitiveIndex, morphTargetBuffer, offset, count);
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT void JNICALL
|
||||
@@ -328,12 +314,13 @@ Java_com_google_android_filament_RenderableManager_nSetMorphWeights(JNIEnv* env,
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT void JNICALL
|
||||
Java_com_google_android_filament_RenderableManager_nSetMorphTargetBufferOffsetAt(JNIEnv*,
|
||||
Java_com_google_android_filament_RenderableManager_nSetMorphTargetBufferAt(JNIEnv*,
|
||||
jclass, jlong nativeRenderableManager, jint i, int level, jint primitiveIndex,
|
||||
jlong, jint offset) {
|
||||
jlong nativeMorphTargetBuffer, jint offset, jint count) {
|
||||
RenderableManager *rm = (RenderableManager *) nativeRenderableManager;
|
||||
rm->setMorphTargetBufferOffsetAt((RenderableManager::Instance) i, (uint8_t) level,
|
||||
(size_t) primitiveIndex, (size_t) offset);
|
||||
MorphTargetBuffer *morphTargetBuffer = (MorphTargetBuffer *) nativeMorphTargetBuffer;
|
||||
rm->setMorphTargetBufferAt((RenderableManager::Instance) i, (uint8_t) level,
|
||||
(size_t) primitiveIndex, morphTargetBuffer, (size_t) offset, (size_t) count);
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT jint JNICALL
|
||||
|
||||
@@ -28,14 +28,6 @@
|
||||
using namespace filament;
|
||||
using namespace backend;
|
||||
|
||||
|
||||
extern "C" JNIEXPORT void JNICALL
|
||||
Java_com_google_android_filament_Renderer_nSkipFrame(JNIEnv *, jclass, jlong nativeRenderer,
|
||||
jlong vsyncSteadyClockTimeNano) {
|
||||
Renderer *renderer = (Renderer *) nativeRenderer;
|
||||
renderer->skipFrame(uint64_t(vsyncSteadyClockTimeNano));
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT jboolean JNICALL
|
||||
Java_com_google_android_filament_Renderer_nBeginFrame(JNIEnv *, jclass, jlong nativeRenderer,
|
||||
jlong nativeSwapChain, jlong frameTimeNanos) {
|
||||
@@ -195,10 +187,3 @@ Java_com_google_android_filament_Renderer_nSetPresentationTime(JNIEnv *, jclass
|
||||
Renderer *renderer = (Renderer *) nativeRenderer;
|
||||
renderer->setPresentationTime(monotonicClockNanos);
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT void JNICALL
|
||||
Java_com_google_android_filament_Renderer_nSetVsyncTime(JNIEnv *, jclass,
|
||||
jlong nativeRenderer, jlong steadyClockTimeNano) {
|
||||
Renderer *renderer = (Renderer *) nativeRenderer;
|
||||
renderer->setVsyncTime(steadyClockTimeNano);
|
||||
}
|
||||
|
||||
@@ -34,15 +34,7 @@ Java_com_google_android_filament_SwapChain_nSetFrameCompletedCallback(JNIEnv* en
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT jboolean JNICALL
|
||||
Java_com_google_android_filament_SwapChain_nIsSRGBSwapChainSupported(
|
||||
JNIEnv *, jclass, jlong nativeEngine) {
|
||||
Java_com_google_android_filament_SwapChain_nIsSRGBSwapChainSupported(JNIEnv *, jclass, jlong nativeEngine) {
|
||||
Engine* engine = (Engine*) nativeEngine;
|
||||
return (jboolean)SwapChain::isSRGBSwapChainSupported(*engine);
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT jboolean JNICALL
|
||||
Java_com_google_android_filament_SwapChain_nIsProtectedContentSupported(
|
||||
JNIEnv *, jclass, jlong nativeEngine) {
|
||||
Engine* engine = (Engine*) nativeEngine;
|
||||
return (jboolean)SwapChain::isProtectedContentSupported(*engine);
|
||||
return (bool)SwapChain::isSRGBSwapChainSupported(*engine);
|
||||
}
|
||||
|
||||
@@ -47,11 +47,6 @@ Java_com_google_android_filament_ToneMapper_nCreateFilmicToneMapper(JNIEnv*, jcl
|
||||
return (jlong) new FilmicToneMapper();
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT jlong JNICALL
|
||||
Java_com_google_android_filament_ToneMapper_nCreatePBRNeutralToneMapper(JNIEnv*, jclass) {
|
||||
return (jlong) new PBRNeutralToneMapper();
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT jlong JNICALL
|
||||
Java_com_google_android_filament_ToneMapper_nCreateAgxToneMapper(JNIEnv*, jclass, jint look) {
|
||||
return (jlong) new AgxToneMapper(AgxToneMapper::AgxLook(look));
|
||||
|
||||
@@ -49,12 +49,6 @@ Java_com_google_android_filament_View_nSetCamera(JNIEnv*, jclass,
|
||||
view->setCamera(camera);
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT jboolean JNICALL
|
||||
Java_com_google_android_filament_View_nHasCamera(JNIEnv*, jclass, jlong nativeView) {
|
||||
View* view = (View*) nativeView;
|
||||
return (jboolean)view->hasCamera();
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT void JNICALL
|
||||
Java_com_google_android_filament_View_nSetColorGrading(JNIEnv*, jclass,
|
||||
jlong nativeView, jlong nativeColorGrading) {
|
||||
@@ -531,12 +525,3 @@ Java_com_google_android_filament_View_nGetFogEntity(JNIEnv *env, jclass clazz,
|
||||
View *view = (View *) nativeView;
|
||||
return (jint)view->getFogEntity().getId();
|
||||
}
|
||||
|
||||
extern "C"
|
||||
JNIEXPORT void JNICALL
|
||||
Java_com_google_android_filament_View_nClearFrameHistory(JNIEnv *env, jclass clazz,
|
||||
jlong nativeView, jlong nativeEngine) {
|
||||
View *view = (View *) nativeView;
|
||||
Engine *engine = (Engine *) nativeEngine;
|
||||
view->clearFrameHistory(*engine);
|
||||
}
|
||||
|
||||
@@ -159,12 +159,9 @@ public class Engine {
|
||||
};
|
||||
|
||||
/**
|
||||
* The type of technique for stereoscopic rendering. (Note that the materials used will need to be
|
||||
* compatible with the chosen technique.)
|
||||
* The type of technique for stereoscopic rendering
|
||||
*/
|
||||
public enum StereoscopicType {
|
||||
/** No stereoscopic rendering. */
|
||||
NONE,
|
||||
/** Stereoscopic rendering is performed using instanced rendering technique. */
|
||||
INSTANCED,
|
||||
/** Stereoscopic rendering is performed using the multiview feature from the graphics backend. */
|
||||
@@ -227,10 +224,7 @@ public class Engine {
|
||||
config.jobSystemThreadCount,
|
||||
config.textureUseAfterFreePoolSize, config.disableParallelShaderCompile,
|
||||
config.stereoscopicType.ordinal(), config.stereoscopicEyeCount,
|
||||
config.resourceAllocatorCacheSizeMB, config.resourceAllocatorCacheMaxAge,
|
||||
config.disableHandleUseAfterFreeCheck,
|
||||
config.preferredShaderLanguage.ordinal(),
|
||||
config.forceGLES2Context);
|
||||
config.resourceAllocatorCacheSizeMB, config.resourceAllocatorCacheMaxAge);
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -245,20 +239,6 @@ public class Engine {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the initial paused state of the rendering thread.
|
||||
*
|
||||
* <p>Warning: This is an experimental API. See {@link Engine#setPaused(boolean)} for
|
||||
* caveats.
|
||||
*
|
||||
* @param paused Whether to start the rendering thread paused.
|
||||
* @return A reference to this Builder for chaining calls.
|
||||
*/
|
||||
public Builder paused(boolean paused) {
|
||||
nSetBuilderPaused(mNativeBuilder, paused);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an instance of Engine
|
||||
*
|
||||
@@ -408,7 +388,7 @@ public class Engine {
|
||||
*
|
||||
* @see View#setStereoscopicOptions
|
||||
*/
|
||||
public StereoscopicType stereoscopicType = StereoscopicType.NONE;
|
||||
public StereoscopicType stereoscopicType = StereoscopicType.INSTANCED;
|
||||
|
||||
/**
|
||||
* The number of eyes to render when stereoscopic rendering is enabled. Supported values are
|
||||
@@ -420,51 +400,16 @@ public class Engine {
|
||||
public long stereoscopicEyeCount = 2;
|
||||
|
||||
/*
|
||||
* @Deprecated This value is no longer used.
|
||||
* Size in MiB of the frame graph texture cache. This should be adjusted based on the
|
||||
* size of used render targets (typically the screen).
|
||||
*/
|
||||
public long resourceAllocatorCacheSizeMB = 64;
|
||||
|
||||
/*
|
||||
* This value determines how many frames texture entries are kept for in the cache. This
|
||||
* is a soft limit, meaning some texture older than this are allowed to stay in the cache.
|
||||
* Typically only one texture is evicted per frame.
|
||||
* The default is 1.
|
||||
* This value determines for how many frames are texture entries kept in the cache.
|
||||
* The default value of 30 corresponds to about half a second at 60 fps.
|
||||
*/
|
||||
public long resourceAllocatorCacheMaxAge = 1;
|
||||
|
||||
/*
|
||||
* Disable backend handles use-after-free checks.
|
||||
*/
|
||||
public boolean disableHandleUseAfterFreeCheck = false;
|
||||
|
||||
/*
|
||||
* Sets a preferred shader language for Filament to use.
|
||||
*
|
||||
* The Metal backend supports two shader languages: MSL (Metal Shading Language) and
|
||||
* METAL_LIBRARY (precompiled .metallib). This option controls which shader language is
|
||||
* used when materials contain both.
|
||||
*
|
||||
* By default, when preferredShaderLanguage is unset, Filament will prefer METAL_LIBRARY
|
||||
* shaders if present within a material, falling back to MSL. Setting
|
||||
* preferredShaderLanguage to ShaderLanguage::MSL will instead instruct Filament to check
|
||||
* for the presence of MSL in a material first, falling back to METAL_LIBRARY if MSL is not
|
||||
* present.
|
||||
*
|
||||
* When using a non-Metal backend, setting this has no effect.
|
||||
*/
|
||||
public enum ShaderLanguage {
|
||||
DEFAULT,
|
||||
MSL,
|
||||
METAL_LIBRARY,
|
||||
};
|
||||
public ShaderLanguage preferredShaderLanguage = ShaderLanguage.DEFAULT;
|
||||
|
||||
/*
|
||||
* When the OpenGL ES backend is used, setting this value to true will force a GLES2.0
|
||||
* context if supported by the Platform, or if not, will have the backend pretend
|
||||
* it's a GLES2 context. Ignored on other backends.
|
||||
*/
|
||||
public boolean forceGLES2Context = false;
|
||||
public long resourceAllocatorCacheMaxAge = 30;
|
||||
}
|
||||
|
||||
private Engine(long nativeEngine, Config config) {
|
||||
@@ -711,7 +656,7 @@ public class Engine {
|
||||
*/
|
||||
@NonNull
|
||||
public SwapChain createSwapChain(@NonNull Object surface) {
|
||||
return createSwapChain(surface, SwapChainFlags.CONFIG_DEFAULT);
|
||||
return createSwapChain(surface, SwapChain.CONFIG_DEFAULT);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -719,15 +664,15 @@ public class Engine {
|
||||
*
|
||||
* @param surface on Android, <b>must be</b> an instance of {@link android.view.Surface}
|
||||
*
|
||||
* @param flags configuration flags, see {@link SwapChainFlags}
|
||||
* @param flags configuration flags, see {@link SwapChain}
|
||||
*
|
||||
* @return a newly created {@link SwapChain} object
|
||||
*
|
||||
* @exception IllegalStateException can be thrown if the SwapChain couldn't be created
|
||||
*
|
||||
* @see SwapChainFlags#CONFIG_DEFAULT
|
||||
* @see SwapChainFlags#CONFIG_TRANSPARENT
|
||||
* @see SwapChainFlags#CONFIG_READABLE
|
||||
* @see SwapChain#CONFIG_DEFAULT
|
||||
* @see SwapChain#CONFIG_TRANSPARENT
|
||||
* @see SwapChain#CONFIG_READABLE
|
||||
*
|
||||
*/
|
||||
@NonNull
|
||||
@@ -745,22 +690,21 @@ public class Engine {
|
||||
*
|
||||
* @param width width of the rendering buffer
|
||||
* @param height height of the rendering buffer
|
||||
* @param flags configuration flags, see {@link SwapChainFlags}
|
||||
* @param flags configuration flags, see {@link SwapChain}
|
||||
*
|
||||
* @return a newly created {@link SwapChain} object
|
||||
*
|
||||
* @exception IllegalStateException can be thrown if the SwapChain couldn't be created
|
||||
*
|
||||
* @see SwapChainFlags#CONFIG_DEFAULT
|
||||
* @see SwapChainFlags#CONFIG_TRANSPARENT
|
||||
* @see SwapChainFlags#CONFIG_READABLE
|
||||
* @see SwapChain#CONFIG_DEFAULT
|
||||
* @see SwapChain#CONFIG_TRANSPARENT
|
||||
* @see SwapChain#CONFIG_READABLE
|
||||
*
|
||||
*/
|
||||
@NonNull
|
||||
public SwapChain createSwapChain(int width, int height, long flags) {
|
||||
if (width >= 0 && height >= 0) {
|
||||
long nativeSwapChain =
|
||||
nCreateSwapChainHeadless(getNativeObject(), width, height, flags);
|
||||
long nativeSwapChain = nCreateSwapChainHeadless(getNativeObject(), width, height, flags);
|
||||
if (nativeSwapChain == 0) throw new IllegalStateException("Couldn't create SwapChain");
|
||||
return new SwapChain(nativeSwapChain, null);
|
||||
}
|
||||
@@ -772,12 +716,11 @@ public class Engine {
|
||||
*
|
||||
* @param surface a properly initialized {@link NativeSurface}
|
||||
*
|
||||
* @param flags configuration flags, see {@link SwapChainFlags}
|
||||
* @param flags configuration flags, see {@link SwapChain}
|
||||
*
|
||||
* @return a newly created {@link SwapChain} object
|
||||
*
|
||||
* @exception IllegalStateException can be thrown if the {@link SwapChainFlags} couldn't be
|
||||
* created
|
||||
* @exception IllegalStateException can be thrown if the {@link SwapChain} couldn't be created
|
||||
*/
|
||||
@NonNull
|
||||
public SwapChain createSwapChainFromNativeSurface(@NonNull NativeSurface surface, long flags) {
|
||||
@@ -886,24 +829,6 @@ public class Engine {
|
||||
return nIsValidMaterial(getNativeObject(), object.getNativeObject());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the object is valid.
|
||||
* @param object Object to check for validity
|
||||
* @return returns true if the specified object is valid.
|
||||
*/
|
||||
public boolean isValidMaterialInstance(@NonNull Material ma, MaterialInstance mi) {
|
||||
return nIsValidMaterialInstance(getNativeObject(), ma.getNativeObject(), mi.getNativeObject());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the object is valid.
|
||||
* @param object Object to check for validity
|
||||
* @return returns true if the specified object is valid.
|
||||
*/
|
||||
public boolean isValidExpensiveMaterialInstance(@NonNull MaterialInstance object) {
|
||||
return nIsValidExpensiveMaterialInstance(getNativeObject(), object.getNativeObject());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the object is valid.
|
||||
* @param object Object to check for validity
|
||||
@@ -1264,51 +1189,6 @@ public class Engine {
|
||||
nFlush(getNativeObject());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get paused state of rendering thread.
|
||||
*
|
||||
* <p>Warning: This is an experimental API.
|
||||
*
|
||||
* @see #setPaused
|
||||
*/
|
||||
public boolean isPaused() {
|
||||
return nIsPaused(getNativeObject());
|
||||
}
|
||||
|
||||
/**
|
||||
* Pause or resume the rendering thread.
|
||||
*
|
||||
* <p>Warning: This is an experimental API. In particular, note the following caveats.
|
||||
*
|
||||
* <ul><li>
|
||||
* Buffer callbacks will never be called as long as the rendering thread is paused.
|
||||
* Do not rely on a buffer callback to unpause the thread.
|
||||
* </li><li>
|
||||
* While the rendering thread is paused, rendering commands will continue to be queued until the
|
||||
* buffer limit is reached. When the limit is reached, the program will abort.
|
||||
* </li></ul>
|
||||
*/
|
||||
public void setPaused(boolean paused) {
|
||||
nSetPaused(getNativeObject(), paused);
|
||||
}
|
||||
|
||||
/**
|
||||
* Switch the command queue to unprotected mode. Protected mode can be activated via
|
||||
* Renderer::beginFrame() using a protected SwapChain.
|
||||
* @see Renderer
|
||||
* @see SwapChain
|
||||
*/
|
||||
public void unprotected() {
|
||||
nUnprotected(getNativeObject());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current time. This is a convenience function that simply returns the
|
||||
* time in nanosecond since epoch of std::chrono::steady_clock.
|
||||
* @return current time in nanosecond since epoch of std::chrono::steady_clock.
|
||||
* @see Renderer#beginFrame
|
||||
*/
|
||||
public static native long getSteadyClockTimeNano();
|
||||
|
||||
@UsedByReflection("TextureHelper.java")
|
||||
public long getNativeObject() {
|
||||
@@ -1375,8 +1255,6 @@ public class Engine {
|
||||
private static native boolean nIsValidSkinningBuffer(long nativeEngine, long nativeSkinningBuffer);
|
||||
private static native boolean nIsValidIndirectLight(long nativeEngine, long nativeIndirectLight);
|
||||
private static native boolean nIsValidMaterial(long nativeEngine, long nativeMaterial);
|
||||
private static native boolean nIsValidMaterialInstance(long nativeEngine, long nativeMaterial, long nativeMaterialInstance);
|
||||
private static native boolean nIsValidExpensiveMaterialInstance(long nativeEngine, long nativeMaterialInstance);
|
||||
private static native boolean nIsValidSkybox(long nativeEngine, long nativeSkybox);
|
||||
private static native boolean nIsValidColorGrading(long nativeEngine, long nativeColorGrading);
|
||||
private static native boolean nIsValidTexture(long nativeEngine, long nativeTexture);
|
||||
@@ -1385,9 +1263,6 @@ public class Engine {
|
||||
private static native void nDestroyEntity(long nativeEngine, int entity);
|
||||
private static native void nFlushAndWait(long nativeEngine);
|
||||
private static native void nFlush(long nativeEngine);
|
||||
private static native boolean nIsPaused(long nativeEngine);
|
||||
private static native void nSetPaused(long nativeEngine, boolean paused);
|
||||
private static native void nUnprotected(long nativeEngine);
|
||||
private static native long nGetTransformManager(long nativeEngine);
|
||||
private static native long nGetLightManager(long nativeEngine);
|
||||
private static native long nGetRenderableManager(long nativeEngine);
|
||||
@@ -1408,12 +1283,8 @@ public class Engine {
|
||||
long minCommandBufferSizeMB, long perFrameCommandsSizeMB, long jobSystemThreadCount,
|
||||
long textureUseAfterFreePoolSize, boolean disableParallelShaderCompile,
|
||||
int stereoscopicType, long stereoscopicEyeCount,
|
||||
long resourceAllocatorCacheSizeMB, long resourceAllocatorCacheMaxAge,
|
||||
boolean disableHandleUseAfterFreeCheck,
|
||||
int preferredShaderLanguage,
|
||||
boolean forceGLES2Context);
|
||||
long resourceAllocatorCacheSizeMB, long resourceAllocatorCacheMaxAge);
|
||||
private static native void nSetBuilderFeatureLevel(long nativeBuilder, int ordinal);
|
||||
private static native void nSetBuilderSharedContext(long nativeBuilder, long sharedContext);
|
||||
private static native void nSetBuilderPaused(long nativeBuilder, boolean paused);
|
||||
private static native long nBuilderBuild(long nativeBuilder);
|
||||
}
|
||||
|
||||
@@ -346,7 +346,6 @@ public class Material {
|
||||
public static class Builder {
|
||||
private Buffer mBuffer;
|
||||
private int mSize;
|
||||
private int mShBandCount = 0;
|
||||
|
||||
/**
|
||||
* Specifies the material data. The material data is a binary blob produced by
|
||||
@@ -362,22 +361,6 @@ public class Material {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the quality of the indirect lights computations. This is only taken into account
|
||||
* if this material is lit and in the surface domain. This setting will affect the
|
||||
* IndirectLight computation if one is specified on the Scene and Spherical Harmonics
|
||||
* are used for the irradiance.
|
||||
*
|
||||
* @param shBandCount Number of spherical harmonic bands. Must be 1, 2 or 3 (default).
|
||||
* @return Reference to this Builder for chaining calls.
|
||||
* @see IndirectLight
|
||||
*/
|
||||
@NonNull
|
||||
public Builder sphericalHarmonicsBandCount(@IntRange(from = 0) int shBandCount) {
|
||||
mShBandCount = shBandCount;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates and returns the Material object.
|
||||
*
|
||||
@@ -389,8 +372,7 @@ public class Material {
|
||||
*/
|
||||
@NonNull
|
||||
public Material build(@NonNull Engine engine) {
|
||||
long nativeMaterial = nBuilderBuild(engine.getNativeObject(),
|
||||
mBuffer, mSize, mShBandCount);
|
||||
long nativeMaterial = nBuilderBuild(engine.getNativeObject(), mBuffer, mSize);
|
||||
if (nativeMaterial == 0) throw new IllegalStateException("Couldn't create Material");
|
||||
return new Material(nativeMaterial);
|
||||
}
|
||||
@@ -1041,7 +1023,7 @@ public class Material {
|
||||
mNativeObject = 0;
|
||||
}
|
||||
|
||||
private static native long nBuilderBuild(long nativeEngine, @NonNull Buffer buffer, int size, int shBandCount);
|
||||
private static native long nBuilderBuild(long nativeEngine, @NonNull Buffer buffer, int size);
|
||||
private static native long nCreateInstance(long nativeMaterial);
|
||||
private static native long nCreateInstanceWithName(long nativeMaterial, @NonNull String name);
|
||||
private static native long nGetDefaultInstance(long nativeMaterial);
|
||||
|
||||
+1
-1
@@ -74,7 +74,7 @@ public class MorphTargetBuffer {
|
||||
*
|
||||
* @exception IllegalStateException if the MorphTargetBuffer could not be created
|
||||
*
|
||||
* @see #setMorphTargetBufferOffsetAt
|
||||
* @see #setMorphTargetBufferAt
|
||||
*/
|
||||
@NonNull
|
||||
public MorphTargetBuffer build(@NonNull Engine engine) {
|
||||
|
||||
+48
-52
@@ -175,32 +175,6 @@ public class RenderableManager {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Type of geometry for a Renderable
|
||||
*/
|
||||
public enum GeometryType {
|
||||
/** dynamic gemoetry has no restriction */
|
||||
DYNAMIC,
|
||||
/** bounds and world space transform are immutable */
|
||||
STATIC_BOUNDS,
|
||||
/** skinning/morphing not allowed and Vertex/IndexBuffer immutables */
|
||||
STATIC
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify whether this renderable has static bounds. In this context his means that
|
||||
* the renderable's bounding box cannot change and that the renderable's transform is
|
||||
* assumed immutable. Changing the renderable's transform via the TransformManager
|
||||
* can lead to corrupted graphics. Note that skinning and morphing are not forbidden.
|
||||
* Disabled by default.
|
||||
* @param enable whether this renderable has static bounds. false by default.
|
||||
*/
|
||||
@NonNull
|
||||
public Builder geometryType(GeometryType type) {
|
||||
nBuilderGeometryType(mNativeBuilder, type.ordinal());
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Binds a material instance to the specified primitive.
|
||||
*
|
||||
@@ -524,7 +498,14 @@ public class RenderableManager {
|
||||
}
|
||||
|
||||
/**
|
||||
* Controls if the renderable has legacy vertex morphing targets, zero by default.
|
||||
* Controls if the renderable has vertex morphing targets, zero by default. This is
|
||||
* required to enable GPU morphing.
|
||||
*
|
||||
* <p>Filament supports two morphing modes: standard (default) and legacy.</p>
|
||||
*
|
||||
* <p>For standard morphing, A {@link MorphTargetBuffer} must be created and provided via
|
||||
* {@link RenderableManager#setMorphTargetBufferAt}. Standard morphing supports up to
|
||||
* <code>CONFIG_MAX_MORPH_TARGET_COUNT</code> morph targets.</p>
|
||||
*
|
||||
* For legacy morphing, the attached {@link VertexBuffer} must provide data in the
|
||||
* appropriate {@link VertexBuffer.VertexAttribute} slots (<code>MORPH_POSITION_0</code> etc).
|
||||
@@ -542,22 +523,6 @@ public class RenderableManager {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Controls if the renderable has vertex morphing targets, zero by default.
|
||||
*
|
||||
* <p>For standard morphing, A {@link MorphTargetBuffer} must be provided.
|
||||
* Standard morphing supports up to
|
||||
* <code>CONFIG_MAX_MORPH_TARGET_COUNT</code> morph targets.</p>
|
||||
*
|
||||
* <p>See also {@link RenderableManager#setMorphWeights}, which can be called on a per-frame basis
|
||||
* to advance the animation.</p>
|
||||
*/
|
||||
@NonNull
|
||||
public Builder morphing(@NonNull MorphTargetBuffer morphTargetBuffer) {
|
||||
nBuilderMorphingStandard(mNativeBuilder, morphTargetBuffer.getNativeObject());
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specifies the morph target buffer for a primitive.
|
||||
*
|
||||
@@ -569,13 +534,31 @@ public class RenderableManager {
|
||||
*
|
||||
* @param level the level of detail (lod), only 0 can be specified
|
||||
* @param primitiveIndex zero-based index of the primitive, must be less than the count passed to Builder constructor
|
||||
* @param morphTargetBuffer specifies the morph target buffer
|
||||
* @param offset specifies where in the morph target buffer to start reading (expressed as a number of vertices)
|
||||
* @param count number of vertices in the morph target buffer to read, must equal the geometry's count (for triangles, this should be a multiple of 3)
|
||||
*/
|
||||
@NonNull
|
||||
public Builder morphing(@IntRange(from = 0) int level,
|
||||
@IntRange(from = 0) int primitiveIndex,
|
||||
@IntRange(from = 0) int offset) {
|
||||
nBuilderSetMorphTargetBufferOffsetAt(mNativeBuilder, level, primitiveIndex, offset);
|
||||
@NonNull MorphTargetBuffer morphTargetBuffer,
|
||||
@IntRange(from = 0) int offset,
|
||||
@IntRange(from = 0) int count) {
|
||||
nBuilderSetMorphTargetBufferAt(mNativeBuilder, level, primitiveIndex,
|
||||
morphTargetBuffer.getNativeObject(), offset, count);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility method to specify morph target buffer for a primitive.
|
||||
* For details, see the {@link RenderableManager.Builder#morphing}.
|
||||
*/
|
||||
@NonNull
|
||||
public Builder morphing(@IntRange(from = 0) int level,
|
||||
@IntRange(from = 0) int primitiveIndex,
|
||||
@NonNull MorphTargetBuffer morphTargetBuffer) {
|
||||
nBuilderSetMorphTargetBufferAt(mNativeBuilder, level, primitiveIndex,
|
||||
morphTargetBuffer.getNativeObject(), 0, morphTargetBuffer.getVertexCount());
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -678,11 +661,26 @@ public class RenderableManager {
|
||||
*
|
||||
* @see Builder#morphing
|
||||
*/
|
||||
public void setMorphTargetBufferOffsetAt(@EntityInstance int i,
|
||||
public void setMorphTargetBufferAt(@EntityInstance int i,
|
||||
@IntRange(from = 0) int level,
|
||||
@IntRange(from = 0) int primitiveIndex,
|
||||
@IntRange(from = 0) int offset) {
|
||||
nSetMorphTargetBufferOffsetAt(mNativeObject, i, level, primitiveIndex, 0, offset);
|
||||
@NonNull MorphTargetBuffer morphTargetBuffer,
|
||||
@IntRange(from = 0) int offset,
|
||||
@IntRange(from = 0) int count) {
|
||||
nSetMorphTargetBufferAt(mNativeObject, i, level, primitiveIndex,
|
||||
morphTargetBuffer.getNativeObject(), offset, count);
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility method to change morph target buffer for the given primitive.
|
||||
* For details, see the {@link RenderableManager#setMorphTargetBufferAt}.
|
||||
*/
|
||||
public void setMorphTargetBufferAt(@EntityInstance int i,
|
||||
@IntRange(from = 0) int level,
|
||||
@IntRange(from = 0) int primitiveIndex,
|
||||
@NonNull MorphTargetBuffer morphTargetBuffer) {
|
||||
nSetMorphTargetBufferAt(mNativeObject, i, level, primitiveIndex,
|
||||
morphTargetBuffer.getNativeObject(), 0, morphTargetBuffer.getVertexCount());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -966,7 +964,6 @@ public class RenderableManager {
|
||||
private static native void nBuilderGeometry(long nativeBuilder, int index, int value, long nativeVertexBuffer, long nativeIndexBuffer);
|
||||
private static native void nBuilderGeometry(long nativeBuilder, int index, int value, long nativeVertexBuffer, long nativeIndexBuffer, int offset, int count);
|
||||
private static native void nBuilderGeometry(long nativeBuilder, int index, int value, long nativeVertexBuffer, long nativeIndexBuffer, int offset, int minIndex, int maxIndex, int count);
|
||||
private static native void nBuilderGeometryType(long nativeBuilder, int type);
|
||||
private static native void nBuilderMaterial(long nativeBuilder, int index, long nativeMaterialInstance);
|
||||
private static native void nBuilderBlendOrder(long nativeBuilder, int index, int blendOrder);
|
||||
private static native void nBuilderGlobalBlendOrderEnabled(long nativeBuilder, int index, boolean enabled);
|
||||
@@ -982,8 +979,7 @@ public class RenderableManager {
|
||||
private static native int nBuilderSkinningBones(long nativeBuilder, int boneCount, Buffer bones, int remaining);
|
||||
private static native void nBuilderSkinningBuffer(long nativeBuilder, long nativeSkinningBuffer, int boneCount, int offset);
|
||||
private static native void nBuilderMorphing(long nativeBuilder, int targetCount);
|
||||
private static native void nBuilderMorphingStandard(long nativeBuilder, long nativeMorphTargetBuffer);
|
||||
private static native void nBuilderSetMorphTargetBufferOffsetAt(long nativeBuilder, int level, int primitiveIndex, int offset);
|
||||
private static native void nBuilderSetMorphTargetBufferAt(long nativeBuilder, int level, int primitiveIndex, long nativeMorphTargetBuffer, int offset, int count);
|
||||
private static native void nBuilderEnableSkinningBuffers(long nativeBuilder, boolean enabled);
|
||||
private static native void nBuilderFog(long nativeBuilder, boolean enabled);
|
||||
private static native void nBuilderLightChannel(long nativeRenderableManager, int channel, boolean enable);
|
||||
@@ -993,7 +989,7 @@ public class RenderableManager {
|
||||
private static native int nSetBonesAsMatrices(long nativeObject, int i, Buffer matrices, int remaining, int boneCount, int offset);
|
||||
private static native int nSetBonesAsQuaternions(long nativeObject, int i, Buffer quaternions, int remaining, int boneCount, int offset);
|
||||
private static native void nSetMorphWeights(long nativeObject, int instance, float[] weights, int offset);
|
||||
private static native void nSetMorphTargetBufferOffsetAt(long nativeObject, int i, int level, int primitiveIndex, long nativeMorphTargetBuffer, int offset);
|
||||
private static native void nSetMorphTargetBufferAt(long nativeObject, int i, int level, int primitiveIndex, long nativeMorphTargetBuffer, int offset, int count);
|
||||
private static native int nGetMorphTargetCount(long nativeObject, int i);
|
||||
private static native void nSetAxisAlignedBoundingBox(long nativeRenderableManager, int i, float cx, float cy, float cz, float ex, float ey, float ez);
|
||||
private static native void nSetLayerMask(long nativeRenderableManager, int i, int select, int value);
|
||||
|
||||
@@ -101,7 +101,7 @@ public class Renderer {
|
||||
/**
|
||||
* Desired frame interval in unit of 1 / DisplayInfo.refreshRate.
|
||||
*/
|
||||
public float interval = 1.0f;
|
||||
public float interval = 1.0f / 60.0f;
|
||||
|
||||
/**
|
||||
* Additional headroom for the GPU as a ratio of the targetFrameTime.
|
||||
@@ -284,33 +284,6 @@ public class Renderer {
|
||||
nSetPresentationTime(getNativeObject(), monotonicClockNanos);
|
||||
}
|
||||
|
||||
/**
|
||||
* The use of this method is optional. It sets the VSYNC time expressed as the duration in
|
||||
* nanosecond since epoch of std::chrono::steady_clock.
|
||||
* If called, passing 0 to frameTimeNanos in Renderer.BeginFrame will use this
|
||||
* time instead.
|
||||
* @param steadyClockTimeNano duration in nanosecond since epoch of std::chrono::steady_clock
|
||||
* @see Engine#getSteadyClockTimeNano
|
||||
* @see Renderer#beginFrame
|
||||
*/
|
||||
public void setVsyncTime(long steadyClockTimeNano) {
|
||||
nSetVsyncTime(getNativeObject(), steadyClockTimeNano);
|
||||
}
|
||||
|
||||
/**
|
||||
* Call skipFrame when momentarily skipping frames, for instance if the content of the
|
||||
* scene doesn't change.
|
||||
*
|
||||
* @param vsyncSteadyClockTimeNano The time in nanoseconds when the frame started being rendered,
|
||||
* in the {@link System#nanoTime()} timebase. Divide this value by 1000000 to
|
||||
* convert it to the {@link android.os.SystemClock#uptimeMillis()}
|
||||
* time base. This typically comes from
|
||||
* {@link android.view.Choreographer.FrameCallback}.
|
||||
*/
|
||||
public void skipFrame(long vsyncSteadyClockTimeNano) {
|
||||
nSkipFrame(getNativeObject(), vsyncSteadyClockTimeNano);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets up a frame for this <code>Renderer</code>.
|
||||
* <p><code>beginFrame</code> manages frame pacing, and returns whether or not a frame should be
|
||||
@@ -729,8 +702,6 @@ public class Renderer {
|
||||
}
|
||||
|
||||
private static native void nSetPresentationTime(long nativeObject, long monotonicClockNanos);
|
||||
private static native void nSetVsyncTime(long nativeObject, long steadyClockTimeNano);
|
||||
private static native void nSkipFrame(long nativeObject, long vsyncSteadyClockTimeNano);
|
||||
private static native boolean nBeginFrame(long nativeRenderer, long nativeSwapChain, long frameTimeNanos);
|
||||
private static native void nEndFrame(long nativeRenderer);
|
||||
private static native void nRender(long nativeRenderer, long nativeView);
|
||||
|
||||
@@ -68,30 +68,77 @@ public class SwapChain {
|
||||
private final Object mSurface;
|
||||
private long mNativeObject;
|
||||
|
||||
public static final long CONFIG_DEFAULT = 0x0;
|
||||
|
||||
/**
|
||||
* This flag indicates that the <code>SwapChain</code> must be allocated with an
|
||||
* alpha-channel.
|
||||
*/
|
||||
public static final long CONFIG_TRANSPARENT = 0x1;
|
||||
|
||||
/**
|
||||
* This flag indicates that the <code>SwapChain</code> may be used as a source surface
|
||||
* for reading back render results. This config must be set when creating
|
||||
* any <code>SwapChain</code> that will be used as the source for a blit operation.
|
||||
*
|
||||
* @see Renderer#copyFrame
|
||||
*/
|
||||
public static final long CONFIG_READABLE = 0x2;
|
||||
|
||||
/**
|
||||
* Indicates that the native X11 window is an XCB window rather than an XLIB window.
|
||||
* This is ignored on non-Linux platforms and in builds that support only one X11 API.
|
||||
*/
|
||||
public static final long CONFIG_ENABLE_XCB = 0x4;
|
||||
|
||||
/**
|
||||
* Indicates that the SwapChain must automatically perform linear to sRGB encoding.
|
||||
*
|
||||
* This flag is ignored if isSRGBSwapChainSupported() is false.
|
||||
*
|
||||
* When using this flag, post-processing should be disabled.
|
||||
*
|
||||
* @see SwapChain#isSRGBSwapChainSupported
|
||||
* @see View#setPostProcessingEnabled
|
||||
*/
|
||||
public static final long CONFIG_SRGB_COLORSPACE = 0x10;
|
||||
|
||||
/**
|
||||
* Indicates that this SwapChain should allocate a stencil buffer in addition to a depth buffer.
|
||||
*
|
||||
* This flag is necessary when using View::setStencilBufferEnabled and rendering directly into
|
||||
* the SwapChain (when post-processing is disabled).
|
||||
*
|
||||
* The specific format of the stencil buffer depends on platform support. The following pixel
|
||||
* formats are tried, in order of preference:
|
||||
*
|
||||
* Depth only (without CONFIG_HAS_STENCIL_BUFFER):
|
||||
* - DEPTH32F
|
||||
* - DEPTH24
|
||||
*
|
||||
* Depth + stencil (with CONFIG_HAS_STENCIL_BUFFER):
|
||||
* - DEPTH32F_STENCIL8
|
||||
* - DEPTH24F_STENCIL8
|
||||
*
|
||||
* Note that enabling the stencil buffer may hinder depth precision and should only be used if
|
||||
* necessary.
|
||||
*
|
||||
* @see View#setStencilBufferEnabled
|
||||
* @see View#setPostProcessingEnabled
|
||||
*/
|
||||
public static final long CONFIG_HAS_STENCIL_BUFFER = 0x20;
|
||||
|
||||
SwapChain(long nativeSwapChain, Object surface) {
|
||||
mNativeObject = nativeSwapChain;
|
||||
mSurface = surface;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether createSwapChain supports the CONFIG_PROTECTED_CONTENT flag.
|
||||
* Return whether createSwapChain supports the SWAP_CHAIN_CONFIG_SRGB_COLORSPACE flag.
|
||||
* The default implementation returns false.
|
||||
*
|
||||
* @param engine A reference to the filament Engine
|
||||
* @return true if CONFIG_PROTECTED_CONTENT is supported, false otherwise.
|
||||
* @see SwapChainFlags#CONFIG_PROTECTED_CONTENT
|
||||
*/
|
||||
public static boolean isProtectedContentSupported(@NonNull Engine engine) {
|
||||
return nIsProtectedContentSupported(engine.getNativeObject());
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether createSwapChain supports the CONFIG_SRGB_COLORSPACE flag.
|
||||
* The default implementation returns false.
|
||||
*
|
||||
* @param engine A reference to the filament Engine
|
||||
* @return true if CONFIG_SRGB_COLORSPACE is supported, false otherwise.
|
||||
* @see SwapChainFlags#CONFIG_SRGB_COLORSPACE
|
||||
* @return true if SWAP_CHAIN_CONFIG_SRGB_COLORSPACE is supported, false otherwise.
|
||||
*/
|
||||
public static boolean isSRGBSwapChainSupported(@NonNull Engine engine) {
|
||||
return nIsSRGBSwapChainSupported(engine.getNativeObject());
|
||||
@@ -139,5 +186,4 @@ public class SwapChain {
|
||||
|
||||
private static native void nSetFrameCompletedCallback(long nativeSwapChain, Object handler, Runnable callback);
|
||||
private static native boolean nIsSRGBSwapChainSupported(long nativeEngine);
|
||||
private static native boolean nIsProtectedContentSupported(long nativeEngine);
|
||||
}
|
||||
|
||||
-97
@@ -1,97 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2024 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.google.android.filament;
|
||||
|
||||
// Note: SwapChainFlags is kept separate from SwapChain so that UiHelper does not need to depend
|
||||
// on SwapChain. This allows clients to use UiHelper without requiring all of Filament's Java
|
||||
// classes.
|
||||
|
||||
/**
|
||||
* Flags that a <code>SwapChain</code> can be created with to control behavior.
|
||||
*
|
||||
* @see Engine#createSwapChain
|
||||
* @see Engine#createSwapChainFromNativeSurface
|
||||
*/
|
||||
public final class SwapChainFlags {
|
||||
|
||||
public static final long CONFIG_DEFAULT = 0x0;
|
||||
|
||||
/**
|
||||
* This flag indicates that the <code>SwapChain</code> must be allocated with an
|
||||
* alpha-channel.
|
||||
*/
|
||||
public static final long CONFIG_TRANSPARENT = 0x1;
|
||||
|
||||
/**
|
||||
* This flag indicates that the <code>SwapChain</code> may be used as a source surface
|
||||
* for reading back render results. This config must be set when creating
|
||||
* any <code>SwapChain</code> that will be used as the source for a blit operation.
|
||||
*
|
||||
* @see Renderer#copyFrame
|
||||
*/
|
||||
public static final long CONFIG_READABLE = 0x2;
|
||||
|
||||
/**
|
||||
* Indicates that the native X11 window is an XCB window rather than an XLIB window.
|
||||
* This is ignored on non-Linux platforms and in builds that support only one X11 API.
|
||||
*/
|
||||
public static final long CONFIG_ENABLE_XCB = 0x4;
|
||||
|
||||
/**
|
||||
* Indicates that the SwapChain must automatically perform linear to sRGB encoding.
|
||||
*
|
||||
* This flag is ignored if isSRGBSwapChainSupported() is false.
|
||||
*
|
||||
* When using this flag, post-processing should be disabled.
|
||||
*
|
||||
* @see SwapChain#isSRGBSwapChainSupported
|
||||
* @see View#setPostProcessingEnabled
|
||||
*/
|
||||
public static final long CONFIG_SRGB_COLORSPACE = 0x10;
|
||||
|
||||
/**
|
||||
* Indicates that this SwapChain should allocate a stencil buffer in addition to a depth buffer.
|
||||
*
|
||||
* This flag is necessary when using View::setStencilBufferEnabled and rendering directly into
|
||||
* the SwapChain (when post-processing is disabled).
|
||||
*
|
||||
* The specific format of the stencil buffer depends on platform support. The following pixel
|
||||
* formats are tried, in order of preference:
|
||||
*
|
||||
* Depth only (without CONFIG_HAS_STENCIL_BUFFER):
|
||||
* - DEPTH32F
|
||||
* - DEPTH24
|
||||
*
|
||||
* Depth + stencil (with CONFIG_HAS_STENCIL_BUFFER):
|
||||
* - DEPTH32F_STENCIL8
|
||||
* - DEPTH24F_STENCIL8
|
||||
*
|
||||
* Note that enabling the stencil buffer may hinder depth precision and should only be used if
|
||||
* necessary.
|
||||
*
|
||||
* @see View#setStencilBufferEnabled
|
||||
* @see View#setPostProcessingEnabled
|
||||
*/
|
||||
public static final long CONFIG_HAS_STENCIL_BUFFER = 0x20;
|
||||
|
||||
/**
|
||||
* The SwapChain contains protected content. Only supported when isProtectedContentSupported()
|
||||
* is true.
|
||||
*/
|
||||
public static final long CONFIG_PROTECTED_CONTENT = 0x40;
|
||||
}
|
||||
|
||||
@@ -16,14 +16,12 @@ package com.google.android.filament;
|
||||
* <li>Configurable tone mapping operators</li>
|
||||
* <ul>
|
||||
* <li>GenericToneMapper</li>
|
||||
* <li>AgXToneMapper</li>
|
||||
* </ul>
|
||||
* <li>Fixed-aesthetic tone mapping operators</li>
|
||||
* <ul>
|
||||
* <li>ACESToneMapper</li>
|
||||
* <li>ACESLegacyToneMapper</li>
|
||||
* <li>FilmicToneMapper</li>
|
||||
* <li>PBRNeutralToneMapper</li>
|
||||
* </ul>
|
||||
* <li>Debug/validation tone mapping operators</li>
|
||||
* <ul>
|
||||
@@ -102,21 +100,11 @@ public class ToneMapper {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Khronos PBR Neutral tone mapping operator. This tone mapper was designed
|
||||
* to preserve the appearance of materials across lighting conditions while
|
||||
* avoiding artifacts in the highlights in high dynamic range conditions.
|
||||
*/
|
||||
public static class PBRNeutralToneMapper extends ToneMapper {
|
||||
public PBRNeutralToneMapper() {
|
||||
super(nCreatePBRNeutralToneMapper());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* AgX tone mapping operator.
|
||||
*/
|
||||
public static class Agx extends ToneMapper {
|
||||
|
||||
public enum AgxLook {
|
||||
/**
|
||||
* Base contrast with no look applied
|
||||
@@ -245,7 +233,6 @@ public class ToneMapper {
|
||||
private static native long nCreateACESToneMapper();
|
||||
private static native long nCreateACESLegacyToneMapper();
|
||||
private static native long nCreateFilmicToneMapper();
|
||||
private static native long nCreatePBRNeutralToneMapper();
|
||||
private static native long nCreateAgxToneMapper(int look);
|
||||
private static native long nCreateGenericToneMapper(
|
||||
float contrast, float midGrayIn, float midGrayOut, float hdrMax);
|
||||
|
||||
@@ -241,15 +241,6 @@ public class View {
|
||||
nSetCamera(getNativeObject(), camera == null ? 0 : camera.getNativeObject());
|
||||
}
|
||||
|
||||
/**
|
||||
* Query whether a camera is set.
|
||||
* @return true if a camera is set, false otherwise
|
||||
* @see #setCamera
|
||||
*/
|
||||
public boolean hasCamera() {
|
||||
return nHasCamera(getNativeObject());
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets this View's associated Camera, or null if none has been assigned.
|
||||
*
|
||||
@@ -1233,18 +1224,6 @@ public class View {
|
||||
return nGetFogEntity(getNativeObject());
|
||||
}
|
||||
|
||||
/**
|
||||
* When certain temporal features are used (e.g.: TAA or Screen-space reflections), the view
|
||||
* keeps a history of previous frame renders associated with the Renderer the view was last
|
||||
* used with. When switching Renderer, it may be necessary to clear that history by calling
|
||||
* this method. Similarly, if the whole content of the screen change, like when a cut-scene
|
||||
* starts, clearing the history might be needed to avoid artifacts due to the previous frame
|
||||
* being very different.
|
||||
*/
|
||||
public void clearFrameHistory(Engine engine) {
|
||||
nClearFrameHistory(getNativeObject(), engine.getNativeObject());
|
||||
}
|
||||
|
||||
public long getNativeObject() {
|
||||
if (mNativeObject == 0) {
|
||||
throw new IllegalStateException("Calling method on destroyed View");
|
||||
@@ -1259,7 +1238,6 @@ public class View {
|
||||
private static native void nSetName(long nativeView, String name);
|
||||
private static native void nSetScene(long nativeView, long nativeScene);
|
||||
private static native void nSetCamera(long nativeView, long nativeCamera);
|
||||
private static native boolean nHasCamera(long nativeView);
|
||||
private static native void nSetViewport(long nativeView, int left, int bottom, int width, int height);
|
||||
private static native void nSetVisibleLayers(long nativeView, int select, int value);
|
||||
private static native void nSetShadowingEnabled(long nativeView, boolean enabled);
|
||||
@@ -1306,7 +1284,7 @@ public class View {
|
||||
private static native void nSetMaterialGlobal(long nativeView, int index, float x, float y, float z, float w);
|
||||
private static native void nGetMaterialGlobal(long nativeView, int index, float[] out);
|
||||
private static native int nGetFogEntity(long nativeView);
|
||||
private static native void nClearFrameHistory(long nativeView, long nativeEngine);
|
||||
|
||||
|
||||
/**
|
||||
* List of available ambient occlusion techniques.
|
||||
|
||||
+2
-2
@@ -27,7 +27,7 @@ import android.view.SurfaceHolder;
|
||||
import android.view.SurfaceView;
|
||||
import android.view.TextureView;
|
||||
|
||||
import com.google.android.filament.SwapChainFlags;
|
||||
import com.google.android.filament.SwapChain;
|
||||
|
||||
/**
|
||||
* UiHelper is a simple class that can manage either a SurfaceView, TextureView, or a SurfaceHolder
|
||||
@@ -538,7 +538,7 @@ public class UiHelper {
|
||||
* the options set on this UiHelper.
|
||||
*/
|
||||
public long getSwapChainFlags() {
|
||||
return isOpaque() ? SwapChainFlags.CONFIG_DEFAULT : SwapChainFlags.CONFIG_TRANSPARENT;
|
||||
return isOpaque() ? SwapChain.CONFIG_DEFAULT : SwapChain.CONFIG_TRANSPARENT;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -31,7 +31,6 @@ set_target_properties(iblprefilter PROPERTIES IMPORTED_LOCATION
|
||||
${FILAMENT_DIR}/lib/${ANDROID_ABI}/libfilament-iblprefilter.a)
|
||||
|
||||
set(CMAKE_SHARED_LINKER_FLAGS_RELEASE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE} -Wl,--version-script=${CMAKE_CURRENT_SOURCE_DIR}/libfilament-utils-jni.map")
|
||||
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,-z,max-page-size=16384")
|
||||
|
||||
add_library(filament-utils-jni SHARED
|
||||
src/main/cpp/AutomationEngine.cpp
|
||||
|
||||
@@ -125,11 +125,6 @@ extern "C" JNIEXPORT void Java_com_google_android_filament_utils_Manipulator_nBu
|
||||
builder->groundPlane(a, b, c, d);
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT void Java_com_google_android_filament_utils_Manipulator_nBuilderPanning(JNIEnv*, jclass, jlong nativeBuilder, jboolean enabled) {
|
||||
Builder* builder = (Builder*) nativeBuilder;
|
||||
builder->panning(enabled);
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT long Java_com_google_android_filament_utils_Manipulator_nBuilderBuild(JNIEnv*, jclass, jlong nativeBuilder, jint mode) {
|
||||
Builder* builder = (Builder*) nativeBuilder;
|
||||
return (jlong) builder->build((Mode) mode);
|
||||
|
||||
-12
@@ -274,17 +274,6 @@ public class Manipulator {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether panning is enabled in the manipulator.
|
||||
*
|
||||
* @return this <code>Builder</code> object for chaining calls
|
||||
*/
|
||||
@NonNull
|
||||
public Builder panning(Boolean enabled) {
|
||||
nBuilderPanning(mNativeBuilder, enabled);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates and returns the <code>Manipulator</code> object.
|
||||
*
|
||||
@@ -494,7 +483,6 @@ public class Manipulator {
|
||||
private static native void nBuilderFlightPanSpeed(long nativeBuilder, float x, float y);
|
||||
private static native void nBuilderFlightMoveDamping(long nativeBuilder, float damping);
|
||||
private static native void nBuilderGroundPlane(long nativeBuilder, float a, float b, float c, float d);
|
||||
private static native void nBuilderPanning(long nativeBuilder, Boolean enabled);
|
||||
private static native long nBuilderBuild(long nativeBuilder, int mode);
|
||||
|
||||
private static native void nDestroyManipulator(long nativeManip);
|
||||
|
||||
@@ -44,7 +44,6 @@ set_target_properties(uberarchive PROPERTIES IMPORTED_LOCATION
|
||||
${FILAMENT_DIR}/lib/${ANDROID_ABI}/libuberarchive.a)
|
||||
|
||||
set(CMAKE_SHARED_LINKER_FLAGS_RELEASE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE} -Wl,--version-script=${CMAKE_CURRENT_SOURCE_DIR}/libgltfio-jni.map")
|
||||
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,-z,max-page-size=16384")
|
||||
|
||||
set(GLTFIO_SRCS
|
||||
${GLTFIO_DIR}/include/gltfio/Animator.h
|
||||
@@ -82,20 +81,9 @@ set(GLTFIO_SRCS
|
||||
${GLTFIO_DIR}/src/TangentsJob.cpp
|
||||
${GLTFIO_DIR}/src/TangentsJob.h
|
||||
${GLTFIO_DIR}/src/UbershaderProvider.cpp
|
||||
${GLTFIO_DIR}/src/Utility.cpp
|
||||
${GLTFIO_DIR}/src/Utility.h
|
||||
${GLTFIO_DIR}/src/Wireframe.cpp
|
||||
${GLTFIO_DIR}/src/Wireframe.h
|
||||
${GLTFIO_DIR}/src/downcast.h
|
||||
${GLTFIO_DIR}/src/extended/AssetLoaderExtended.cpp
|
||||
${GLTFIO_DIR}/src/extended/AssetLoaderExtended.h
|
||||
${GLTFIO_DIR}/src/extended/ResourceLoaderExtended.cpp
|
||||
${GLTFIO_DIR}/src/extended/ResourceLoaderExtended.h
|
||||
${GLTFIO_DIR}/src/extended/TangentsJobExtended.cpp
|
||||
${GLTFIO_DIR}/src/extended/TangentsJobExtended.h
|
||||
${GLTFIO_DIR}/src/extended/TangentSpaceMeshWrapper.cpp
|
||||
${GLTFIO_DIR}/src/extended/TangentSpaceMeshWrapper.h
|
||||
|
||||
|
||||
src/main/cpp/Animator.cpp
|
||||
src/main/cpp/AssetLoader.cpp
|
||||
@@ -120,6 +108,7 @@ set(GLTFIO_INCLUDE_DIRS
|
||||
../../third_party/cgltf
|
||||
../../third_party/meshoptimizer/src
|
||||
../../third_party/robin-map
|
||||
../../third_party/hat-trie
|
||||
../../third_party/stb
|
||||
../../libs/utils/include
|
||||
../../libs/ktxreader/include
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
GROUP=com.google.android.filament
|
||||
VERSION_NAME=1.54.0
|
||||
VERSION_NAME=1.50.4
|
||||
|
||||
POM_DESCRIPTION=Real-time physically based rendering engine for Android.
|
||||
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
#Wed Nov 17 10:40:18 PST 2021
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.6-bin.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.2-bin.zip
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
|
||||
@@ -30,7 +30,7 @@ android {
|
||||
compileSdkVersion versions.compileSdk
|
||||
defaultConfig {
|
||||
applicationId "com.google.android.filament.gltf"
|
||||
minSdkVersion versions.minSdk
|
||||
minSdkVersion 19
|
||||
targetSdkVersion versions.targetSdk
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -321,7 +321,7 @@ class MainActivity : Activity() {
|
||||
var flags = uiHelper.swapChainFlags
|
||||
if (engine.activeFeatureLevel == Engine.FeatureLevel.FEATURE_LEVEL_0) {
|
||||
if (SwapChain.isSRGBSwapChainSupported(engine)) {
|
||||
flags = flags or SwapChainFlags.CONFIG_SRGB_COLORSPACE
|
||||
flags = flags or SwapChain.CONFIG_SRGB_COLORSPACE
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -44,6 +44,8 @@ function print_help {
|
||||
echo " Exclude Vulkan support from the Android build."
|
||||
echo " -s"
|
||||
echo " Add iOS simulator support to the iOS build."
|
||||
echo " -t"
|
||||
echo " Enable SwiftShader support for Vulkan in desktop builds."
|
||||
echo " -e"
|
||||
echo " Enable EGL on Linux support for desktop builds."
|
||||
echo " -l"
|
||||
@@ -59,14 +61,6 @@ function print_help {
|
||||
echo " -b"
|
||||
echo " Enable Address and Undefined Behavior Sanitizers (asan/ubsan) for debugging."
|
||||
echo " This is only for the desktop build."
|
||||
echo " -x value"
|
||||
echo " Define a preprocessor flag FILAMENT_BACKEND_DEBUG_FLAG with [value]. This is useful for"
|
||||
echo " enabling debug paths in the backend from the build script. For example, make a"
|
||||
echo " systrace-enabled build without directly changing #defines. Remember to add -f when"
|
||||
echo " changing this option."
|
||||
echo " -S type"
|
||||
echo " Enable stereoscopic rendering where type is one of [instanced|multiview]. This is only"
|
||||
echo " meant for building the samples."
|
||||
echo ""
|
||||
echo "Build types:"
|
||||
echo " release"
|
||||
@@ -166,6 +160,8 @@ INSTALL_COMMAND=
|
||||
VULKAN_ANDROID_OPTION="-DFILAMENT_SUPPORTS_VULKAN=ON"
|
||||
VULKAN_ANDROID_GRADLE_OPTION=""
|
||||
|
||||
SWIFTSHADER_OPTION="-DFILAMENT_USE_SWIFTSHADER=OFF"
|
||||
|
||||
EGL_ON_LINUX_OPTION="-DFILAMENT_SUPPORTS_EGL_ON_LINUX=OFF"
|
||||
|
||||
MATDBG_OPTION="-DFILAMENT_ENABLE_MATDBG=OFF"
|
||||
@@ -176,10 +172,6 @@ MATOPT_GRADLE_OPTION=""
|
||||
|
||||
ASAN_UBSAN_OPTION=""
|
||||
|
||||
BACKEND_DEBUG_FLAG_OPTION=""
|
||||
|
||||
STEREOSCOPIC_OPTION=""
|
||||
|
||||
IOS_BUILD_SIMULATOR=false
|
||||
BUILD_UNIVERSAL_LIBRARIES=false
|
||||
|
||||
@@ -234,12 +226,11 @@ function build_desktop_target {
|
||||
-DIMPORT_EXECUTABLES_DIR=out \
|
||||
-DCMAKE_BUILD_TYPE="$1" \
|
||||
-DCMAKE_INSTALL_PREFIX="../${lc_target}/filament" \
|
||||
${SWIFTSHADER_OPTION} \
|
||||
${EGL_ON_LINUX_OPTION} \
|
||||
${MATDBG_OPTION} \
|
||||
${MATOPT_OPTION} \
|
||||
${ASAN_UBSAN_OPTION} \
|
||||
${BACKEND_DEBUG_FLAG_OPTION} \
|
||||
${STEREOSCOPIC_OPTION} \
|
||||
${architectures} \
|
||||
../..
|
||||
ln -sf "out/cmake-${lc_target}/compile_commands.json" \
|
||||
@@ -298,7 +289,6 @@ function build_webgl_with_target {
|
||||
-DCMAKE_BUILD_TYPE="$1" \
|
||||
-DCMAKE_INSTALL_PREFIX="../webgl-${lc_target}/filament" \
|
||||
-DWEBGL=1 \
|
||||
${BACKEND_DEBUG_FLAG_OPTION} \
|
||||
../..
|
||||
ln -sf "out/cmake-webgl-${lc_target}/compile_commands.json" \
|
||||
../../compile_commands.json
|
||||
@@ -373,8 +363,6 @@ function build_android_target {
|
||||
${MATDBG_OPTION} \
|
||||
${MATOPT_OPTION} \
|
||||
${VULKAN_ANDROID_OPTION} \
|
||||
${BACKEND_DEBUG_FLAG_OPTION} \
|
||||
${STEREOSCOPIC_OPTION} \
|
||||
../..
|
||||
ln -sf "out/cmake-android-${lc_target}-${arch}/compile_commands.json" \
|
||||
../../compile_commands.json
|
||||
@@ -528,7 +516,7 @@ function build_android {
|
||||
if [[ "${BUILD_ANDROID_SAMPLES}" == "true" ]]; then
|
||||
for sample in ${ANDROID_SAMPLES}; do
|
||||
echo "Installing out/${sample}-debug.apk"
|
||||
cp samples/${sample}/build/outputs/apk/debug/${sample}-debug.apk \
|
||||
cp samples/${sample}/build/outputs/apk/debug/${sample}-debug-unsigned.apk \
|
||||
../out/${sample}-debug.apk
|
||||
done
|
||||
fi
|
||||
@@ -609,7 +597,6 @@ function build_ios_target {
|
||||
-DCMAKE_TOOLCHAIN_FILE=../../third_party/clang/iOS.cmake \
|
||||
${MATDBG_OPTION} \
|
||||
${MATOPT_OPTION} \
|
||||
${STEREOSCOPIC_OPTION} \
|
||||
../..
|
||||
ln -sf "out/cmake-ios-${lc_target}-${arch}/compile_commands.json" \
|
||||
../../compile_commands.json
|
||||
@@ -743,13 +730,6 @@ function validate_build_command {
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
# Make sure FILAMENT_BACKEND_DEBUG_FLAG is only meant for debug builds
|
||||
if [[ "${ISSUE_DEBUG_BUILD}" != "true" ]] && [[ ! -z "${BACKEND_DEBUG_FLAG_OPTION}" ]]; then
|
||||
echo "Error: cannot specify FILAMENT_BACKEND_DEBUG_FLAG in non-debug build"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
set -e
|
||||
}
|
||||
|
||||
@@ -796,7 +776,7 @@ function check_debug_release_build {
|
||||
|
||||
pushd "$(dirname "$0")" > /dev/null
|
||||
|
||||
while getopts ":hacCfgijmp:q:uvslwedk:bx:S:" opt; do
|
||||
while getopts ":hacCfgijmp:q:uvslwtedk:b" opt; do
|
||||
case ${opt} in
|
||||
h)
|
||||
print_help
|
||||
@@ -860,7 +840,7 @@ while getopts ":hacCfgijmp:q:uvslwedk:bx:S:" opt; do
|
||||
echo "Platform must be one of [desktop|android|ios|webgl|all]"
|
||||
echo ""
|
||||
exit 1
|
||||
;;
|
||||
;;
|
||||
esac
|
||||
done
|
||||
;;
|
||||
@@ -915,6 +895,10 @@ while getopts ":hacCfgijmp:q:uvslwedk:bx:S:" opt; do
|
||||
IOS_BUILD_SIMULATOR=true
|
||||
echo "iOS simulator support enabled."
|
||||
;;
|
||||
t)
|
||||
SWIFTSHADER_OPTION="-DFILAMENT_USE_SWIFTSHADER=ON"
|
||||
echo "SwiftShader support enabled."
|
||||
;;
|
||||
e)
|
||||
EGL_ON_LINUX_OPTION="-DFILAMENT_SUPPORTS_EGL_ON_LINUX=ON -DFILAMENT_SKIP_SDL2=ON -DFILAMENT_SKIP_SAMPLES=ON"
|
||||
echo "EGL on Linux support enabled; skipping SDL2."
|
||||
@@ -934,22 +918,6 @@ while getopts ":hacCfgijmp:q:uvslwedk:bx:S:" opt; do
|
||||
b) ASAN_UBSAN_OPTION="-DFILAMENT_ENABLE_ASAN_UBSAN=ON"
|
||||
echo "Enabled ASAN/UBSAN"
|
||||
;;
|
||||
x) BACKEND_DEBUG_FLAG_OPTION="-DFILAMENT_BACKEND_DEBUG_FLAG=${OPTARG}"
|
||||
;;
|
||||
S) case $(echo "${OPTARG}" | tr '[:upper:]' '[:lower:]') in
|
||||
instanced)
|
||||
STEREOSCOPIC_OPTION="-DFILAMENT_SAMPLES_STEREO_TYPE=instanced"
|
||||
;;
|
||||
multiview)
|
||||
STEREOSCOPIC_OPTION="-DFILAMENT_SAMPLES_STEREO_TYPE=multiview"
|
||||
;;
|
||||
*)
|
||||
echo "Unknown stereoscopic type ${OPTARG}"
|
||||
echo "Type must be one of [instanced|multiview]"
|
||||
echo ""
|
||||
exit 1
|
||||
esac
|
||||
;;
|
||||
\?)
|
||||
echo "Invalid option: -${OPTARG}" >&2
|
||||
echo ""
|
||||
|
||||
@@ -57,8 +57,7 @@ FILAMENT_NDK_VERSION=${FILAMENT_NDK_VERSION:-$(cat `dirname $0`/ndk.version)}
|
||||
|
||||
# Install the required NDK version specifically (if not present)
|
||||
if [[ ! -d "${ANDROID_HOME}/ndk/$FILAMENT_NDK_VERSION" ]]; then
|
||||
yes | ${ANDROID_HOME}/cmdline-tools/latest/bin/sdkmanager --licenses
|
||||
${ANDROID_HOME}/cmdline-tools/latest/bin/sdkmanager "ndk;$FILAMENT_NDK_VERSION"
|
||||
${ANDROID_HOME}/cmdline-tools/latest/bin/sdkmanager "ndk;$FILAMENT_NDK_VERSION" > /dev/null
|
||||
fi
|
||||
|
||||
# Only build 1 64 bit target during presubmit to cut down build times during presubmit
|
||||
|
||||
@@ -1 +1 @@
|
||||
27.0.11718014
|
||||
25.1.8937393
|
||||
@@ -0,0 +1,53 @@
|
||||
# Build the image:
|
||||
# docker build --no-cache --tag ssfilament -f build/swiftshader/Dockerfile .
|
||||
# docker tag ssfilament ghcr.io/filament-assets/swiftshader
|
||||
#
|
||||
# Publish the image:
|
||||
# docker login ghcr.io --username <user> --password <token>
|
||||
# docker push ghcr.io/filament-assets/swiftshader
|
||||
#
|
||||
# Run the image and mount the current directory:
|
||||
# docker run -it -v `pwd`:/trees/filament -t ssfilament
|
||||
|
||||
FROM ubuntu:focal
|
||||
WORKDIR /trees
|
||||
ARG DEBIAN_FRONTEND=noninteractive
|
||||
ENV SWIFTSHADER_LD_LIBRARY_PATH=/trees/swiftshader/build
|
||||
ENV CXXFLAGS='-fno-builtin -Wno-pass-failed'
|
||||
|
||||
RUN apt-get update && \
|
||||
apt-get --no-install-recommends install -y \
|
||||
apt-transport-https \
|
||||
apt-utils \
|
||||
build-essential \
|
||||
cmake \
|
||||
ca-certificates \
|
||||
git \
|
||||
ninja-build \
|
||||
python \
|
||||
python3 \
|
||||
xorg-dev \
|
||||
clang-7 \
|
||||
libc++-7-dev \
|
||||
libc++abi-7-dev \
|
||||
lldb
|
||||
|
||||
# Ensure that clang is used instead of gcc.
|
||||
RUN set -eux ;\
|
||||
update-alternatives --install /usr/bin/clang clang /usr/bin/clang-7 100 ;\
|
||||
update-alternatives --install /usr/bin/clang++ clang++ /usr/bin/clang++-7 100 ;\
|
||||
update-alternatives --install /usr/bin/cc cc /usr/bin/clang 100 ;\
|
||||
update-alternatives --install /usr/bin/c++ c++ /usr/bin/clang++ 100
|
||||
|
||||
# Get patch files from the local Filament tree.
|
||||
COPY build/swiftshader/*.diff .
|
||||
|
||||
# Clone SwiftShader, apply patches, and build it.
|
||||
RUN set -eux ;\
|
||||
git clone https://swiftshader.googlesource.com/SwiftShader swiftshader ;\
|
||||
cd swiftshader ;\
|
||||
git checkout 139f5c3 ;\
|
||||
git apply /trees/*.diff ;\
|
||||
cd build ;\
|
||||
cmake .. -GNinja -DCMAKE_BUILD_TYPE=Release ;\
|
||||
ninja
|
||||
Executable
+56
@@ -0,0 +1,56 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
from pathlib import Path
|
||||
import os
|
||||
|
||||
spath = os.path.dirname(os.path.realpath(__file__))
|
||||
|
||||
path = Path(spath)
|
||||
|
||||
folder = "../../results/"
|
||||
|
||||
images = list(path.glob(folder + '*.png'))
|
||||
|
||||
images.sort()
|
||||
|
||||
gallery = open(path.absolute().joinpath(folder + 'index.html'), 'w')
|
||||
|
||||
gallery.write("""<html>
|
||||
<head>
|
||||
<script type="module" src="https://unpkg.com/img-comparison-slider@latest/dist/component/component.esm.js"></script>
|
||||
<script nomodule="" src="https://unpkg.com/img-comparison-slider@latest/dist/component/component.js"></script>
|
||||
<link rel="stylesheet" href="https://unpkg.com/img-comparison-slider@latest/dist/collection/styles/initial.css"/>
|
||||
<style>
|
||||
h2 {
|
||||
font-weight: normal;
|
||||
margin-top: 150px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
a {
|
||||
text-decoration: none;
|
||||
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
|
||||
color: blue;
|
||||
}
|
||||
a:hover {
|
||||
font-weight: bold;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
""")
|
||||
|
||||
tag = ''
|
||||
|
||||
for image in images:
|
||||
group = image.stem.rstrip('0123456789')
|
||||
before = f'https://filament-assets.github.io/golden/{group}/{image.name}'
|
||||
after = image.name
|
||||
gallery.write('\n')
|
||||
gallery.write(f'<h2><a href="{image.stem}.json">{image.stem}.json</a></h2>\n')
|
||||
gallery.write('<img-comparison-slider>\n')
|
||||
gallery.write(f'<img slot="before" src="{before}" /> <img slot="after" src="{after}" />\n')
|
||||
gallery.write('</img-comparison-slider>\n')
|
||||
|
||||
gallery.write("""</body>
|
||||
</html>
|
||||
""")
|
||||
@@ -0,0 +1,62 @@
|
||||
diff --git a/src/Vulkan/VkPipeline.cpp b/src/Vulkan/VkPipeline.cpp
|
||||
index 86913ec72..3b35345af 100644
|
||||
--- a/src/Vulkan/VkPipeline.cpp
|
||||
+++ b/src/Vulkan/VkPipeline.cpp
|
||||
@@ -71,7 +71,56 @@ std::vector<uint32_t> preprocessSpirv(
|
||||
if(optimize)
|
||||
{
|
||||
// Full optimization list taken from spirv-opt.
|
||||
- opt.RegisterPerformancePasses();
|
||||
+
|
||||
+ // We have removed CreateRedundancyEliminationPass because it segfaults when encountering:
|
||||
+ // %389 = OpCompositeConstruct %7 %386 %387 %388 %86
|
||||
+ // When inserting an entry into instruction_to_value_ (which is an unordered_map)
|
||||
+ // This could perhaps be investigated further with help from asan.
|
||||
+
|
||||
+ using namespace spvtools;
|
||||
+ opt.RegisterPass(CreateWrapOpKillPass())
|
||||
+ .RegisterPass(CreateDeadBranchElimPass())
|
||||
+ .RegisterPass(CreateMergeReturnPass())
|
||||
+ .RegisterPass(CreateInlineExhaustivePass())
|
||||
+ .RegisterPass(CreateAggressiveDCEPass())
|
||||
+ .RegisterPass(CreatePrivateToLocalPass())
|
||||
+ .RegisterPass(CreateLocalSingleBlockLoadStoreElimPass())
|
||||
+ .RegisterPass(CreateLocalSingleStoreElimPass())
|
||||
+ .RegisterPass(CreateAggressiveDCEPass())
|
||||
+ .RegisterPass(CreateScalarReplacementPass())
|
||||
+ .RegisterPass(CreateLocalAccessChainConvertPass())
|
||||
+ .RegisterPass(CreateLocalSingleBlockLoadStoreElimPass())
|
||||
+ .RegisterPass(CreateLocalSingleStoreElimPass())
|
||||
+ .RegisterPass(CreateAggressiveDCEPass())
|
||||
+ .RegisterPass(CreateLocalMultiStoreElimPass())
|
||||
+ .RegisterPass(CreateAggressiveDCEPass())
|
||||
+ .RegisterPass(CreateCCPPass())
|
||||
+ .RegisterPass(CreateAggressiveDCEPass())
|
||||
+ .RegisterPass(CreateLoopUnrollPass(true))
|
||||
+ .RegisterPass(CreateDeadBranchElimPass())
|
||||
+ .RegisterPass(CreateRedundancyEliminationPass()) // workaround for SEGFAULT
|
||||
+ .RegisterPass(CreateCombineAccessChainsPass())
|
||||
+ .RegisterPass(CreateSimplificationPass())
|
||||
+ .RegisterPass(CreateScalarReplacementPass())
|
||||
+ .RegisterPass(CreateLocalAccessChainConvertPass())
|
||||
+ .RegisterPass(CreateLocalSingleBlockLoadStoreElimPass())
|
||||
+ .RegisterPass(CreateLocalSingleStoreElimPass())
|
||||
+ .RegisterPass(CreateAggressiveDCEPass())
|
||||
+ .RegisterPass(CreateSSARewritePass())
|
||||
+ .RegisterPass(CreateAggressiveDCEPass())
|
||||
+ .RegisterPass(CreateVectorDCEPass())
|
||||
+ .RegisterPass(CreateDeadInsertElimPass())
|
||||
+ .RegisterPass(CreateDeadBranchElimPass())
|
||||
+ .RegisterPass(CreateSimplificationPass())
|
||||
+ .RegisterPass(CreateIfConversionPass())
|
||||
+ .RegisterPass(CreateCopyPropagateArraysPass())
|
||||
+ .RegisterPass(CreateReduceLoadSizePass())
|
||||
+ .RegisterPass(CreateAggressiveDCEPass())
|
||||
+ .RegisterPass(CreateBlockMergePass())
|
||||
+ .RegisterPass(CreateRedundancyEliminationPass()) // workaround for SEGFAULT
|
||||
+ .RegisterPass(CreateDeadBranchElimPass())
|
||||
+ .RegisterPass(CreateBlockMergePass())
|
||||
+ .RegisterPass(CreateSimplificationPass());
|
||||
}
|
||||
|
||||
std::vector<uint32_t> optimized;
|
||||
Executable
+127
@@ -0,0 +1,127 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
function print_help {
|
||||
local self_name=$(basename "$0")
|
||||
echo "This script issues docker commands for testing Filament with SwiftShader."
|
||||
echo "The usual sequence of commands is: fetch, start, build filament release, and run."
|
||||
echo ""
|
||||
echo "Usage:"
|
||||
echo " $self_name [command]"
|
||||
echo ""
|
||||
echo "Commands:"
|
||||
echo " build filament [debug | release]"
|
||||
echo " Use the container to build Filament."
|
||||
echo " build swiftshader [debug | release]"
|
||||
echo " Use the container to do a clean rebuild of SwiftShader."
|
||||
echo " (Note that the container already has SwiftShader built.)"
|
||||
echo " fetch"
|
||||
echo " Download the docker image from the central repository."
|
||||
echo " help"
|
||||
echo " Print this help message."
|
||||
echo " logs"
|
||||
echo " Print messages from the container's kernel ring buffer."
|
||||
echo " This is useful for diagnosing OOM issues."
|
||||
echo " run [lldb]"
|
||||
echo " Launch a test inside the container, optionally via lldb."
|
||||
echo " shell"
|
||||
echo " Interact with a bash prompt in the container."
|
||||
echo " start"
|
||||
echo " Start a container from the image."
|
||||
echo " stop"
|
||||
echo " Stop the container."
|
||||
echo ""
|
||||
}
|
||||
|
||||
# Change the current working directory to the Filament root.
|
||||
pushd "$(dirname "$0")/../.." > /dev/null
|
||||
|
||||
if [[ "$1" == "build" ]] && [[ "$2" == "filament" ]]; then
|
||||
docker exec runner filament/build.sh -t $3 gltf_viewer
|
||||
exit $?
|
||||
fi
|
||||
|
||||
if [[ "$1" == "build" ]] && [[ "$2" == "swiftshader" ]]; then
|
||||
BUILD_TYPE="$3"
|
||||
BUILD_TYPE="$(tr '[:lower:]' '[:upper:]' <<< ${BUILD_TYPE:0:1})${BUILD_TYPE:1}"
|
||||
docker exec --workdir /trees/swiftshader runner rm -rf build
|
||||
docker exec --workdir /trees/swiftshader runner mkdir build
|
||||
docker exec --workdir /trees/swiftshader/build runner cmake -GNinja -DCMAKE_BUILD_TYPE="$BUILD_TYPE" ..
|
||||
docker exec --workdir /trees/swiftshader/build runner ninja
|
||||
exit $?
|
||||
fi
|
||||
|
||||
if [[ "$1" == "fetch" ]]; then
|
||||
docker pull ghcr.io/filament-assets/swiftshader:latest
|
||||
docker tag ghcr.io/filament-assets/swiftshader:latest ssfilament
|
||||
exit $?
|
||||
fi
|
||||
|
||||
if [[ "$1" == "help" ]]; then
|
||||
print_help
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if [[ "$1" == "logs" ]]; then
|
||||
docker exec runner dmesg --human --read-clear
|
||||
exit $?
|
||||
fi
|
||||
|
||||
if [[ "$1" == "run" ]] && [[ "$2" == "lldb" ]]; then
|
||||
docker exec -i --workdir /trees/filament/results runner \
|
||||
lldb --batch -o run -o bt -- \
|
||||
../out/cmake-release/samples/gltf_viewer \
|
||||
--headless \
|
||||
--batch ../libs/viewer/tests/basic.json \
|
||||
--api vulkan
|
||||
docker exec runner /trees/filament/build/swiftshader/gallery.py
|
||||
exit $?
|
||||
fi
|
||||
|
||||
if [[ "$1" == "run" ]]; then
|
||||
docker exec --tty --workdir /trees/filament/results runner \
|
||||
/usr/bin/catchsegv \
|
||||
../out/cmake-release/samples/gltf_viewer \
|
||||
--headless \
|
||||
--batch ../libs/viewer/tests/basic.json \
|
||||
--api vulkan
|
||||
docker exec runner /trees/filament/build/swiftshader/gallery.py
|
||||
exit $?
|
||||
fi
|
||||
|
||||
if [[ "$1" == "shell" ]]; then
|
||||
docker exec --interactive --tty runner /bin/bash
|
||||
exit $?
|
||||
fi
|
||||
|
||||
# Notes on options being passed to docker's run command:
|
||||
#
|
||||
# - The memory constraint seems to prevent an OOM signal in GitHub Actions.
|
||||
# - The cap / security args allow use of lldb and creation of core dumps.
|
||||
# - The privileged arg allows use of dmesg for examining OOM logs.
|
||||
#
|
||||
# Currently, a GitHub Actions VM has 2 CPUs, 7 GB RAM, and 14 GB of SSD disk space.
|
||||
#
|
||||
# Please be aware that Docker Desktop might impose additional resource constraints, and that those
|
||||
# settings can only be controlled with its GUI. We recommend at least 7 GB of memory and 2 GB swap.
|
||||
if [[ "$1" == "start" ]]; then
|
||||
mkdir -p results
|
||||
docker run --tty --rm --detach --privileged \
|
||||
--memory 6.5g \
|
||||
--name runner \
|
||||
--cap-add=SYS_PTRACE \
|
||||
--security-opt seccomp=unconfined \
|
||||
--security-opt apparmor=unconfined \
|
||||
--volume `pwd`:/trees/filament \
|
||||
--workdir /trees \
|
||||
ssfilament
|
||||
exit $?
|
||||
fi
|
||||
|
||||
if [[ "$1" == "stop" ]]; then
|
||||
docker container rm runner --force
|
||||
exit $?
|
||||
fi
|
||||
|
||||
print_help
|
||||
exit 1
|
||||
@@ -21,7 +21,7 @@ set(CMAKE_SYSTEM_NAME Linux)
|
||||
set(CMAKE_SYSTEM_VERSION 1)
|
||||
|
||||
# android
|
||||
set(API_LEVEL 21)
|
||||
set(API_LEVEL 19)
|
||||
|
||||
# architecture
|
||||
set(ARCH armv7a-linux-androideabi)
|
||||
|
||||
@@ -21,7 +21,7 @@ set(CMAKE_SYSTEM_NAME Linux)
|
||||
set(CMAKE_SYSTEM_VERSION 1)
|
||||
|
||||
# android
|
||||
set(API_LEVEL 21)
|
||||
set(API_LEVEL 19)
|
||||
|
||||
# architecture
|
||||
set(ARCH i686-linux-android)
|
||||
|
||||
+2
-2
@@ -476,7 +476,7 @@ Energy conservation is one of the key components of a good BRDF for physically b
|
||||
<p>
|
||||
|
||||
|
||||
For the specular term, \(f_r\) is a mirror BRDF that can be modeled with the Fresnel law, noted \(F\) in the Cook-Torrance approximation of the microfacet model integration:
|
||||
For the specular term, \(f_m\) is a mirror BRDF that can be modeled with the Fresnel law, noted \(F\) in the Cook-Torrance approximation of the microfacet model integration:
|
||||
|
||||
</p><p>
|
||||
|
||||
@@ -857,7 +857,7 @@ The full GLSL implementation of the standard model is shown in <a href="#listing
|
||||
<span class="line"> <span class="hljs-comment">// perceptually linear roughness to roughness (see parameterization)</span></span>
|
||||
<span class="line"> <span class="hljs-type">float</span> roughness = perceptualRoughness * perceptualRoughness;</span>
|
||||
<span class="line"></span>
|
||||
<span class="line"> <span class="hljs-type">float</span> D = D_GGX(NoH, roughness);</span>
|
||||
<span class="line"> <span class="hljs-type">float</span> D = D_GGX(NoH, a);</span>
|
||||
<span class="line"> <span class="hljs-type">vec3</span> F = F_Schlick(LoH, f0);</span>
|
||||
<span class="line"> <span class="hljs-type">float</span> V = V_SmithGGXCorrelated(NoV, NoL, roughness);</span>
|
||||
<span class="line"></span>
|
||||
|
||||
+53
-141
File diff suppressed because one or more lines are too long
+3
-44
@@ -1308,12 +1308,7 @@ Description
|
||||
declare a variable called `eyeDirection` you can access it in the fragment shader using
|
||||
`variable_eyeDirection`. In the vertex shader, the interpolant name is simply a member of
|
||||
the `MaterialVertexInputs` structure (`material.eyeDirection` in your example). Each
|
||||
interpolant is of type `float4` (`vec4`) in the shaders. By default the precision of the
|
||||
interpolant is `highp` in *both* the vertex and fragment shaders.
|
||||
An alternate syntax can be used to specify both the name and precision of the interpolant.
|
||||
In this case the specified precision is used as-is in both fragment and vertex stages, in
|
||||
particular if `default` is specified the default precision is used is the fragment shader
|
||||
(`mediump`) and in the vertex shader (`highp`).
|
||||
interpolant is of type `float4` (`vec4`) in the shaders.
|
||||
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ JSON
|
||||
material {
|
||||
@@ -1325,11 +1320,7 @@ material {
|
||||
}
|
||||
],
|
||||
variables : [
|
||||
eyeDirection,
|
||||
{
|
||||
name : eyeColor,
|
||||
precision : medium
|
||||
}
|
||||
eyeDirection
|
||||
],
|
||||
vertexDomain : device,
|
||||
depthWrite : false,
|
||||
@@ -1406,7 +1397,7 @@ Type
|
||||
: `string`
|
||||
|
||||
Value
|
||||
: Any of `opaque`, `transparent`, `fade`, `add`, `masked`, `multiply`, `screen`, `custom`. Defaults to `opaque`.
|
||||
: Any of `opaque`, `transparent`, `fade`, `add`, `masked`, `multiply`, `screen`. Defaults to `opaque`.
|
||||
|
||||
Description
|
||||
: Defines how/if the rendered object is blended with the content of the render target.
|
||||
@@ -1429,7 +1420,6 @@ Description
|
||||
of the material's output defines whether a fragment is discarded or not. Additionally,
|
||||
ALPHA_TO_COVERAGE is enabled for non-translucent views. See the maskThreshold section for more
|
||||
information.
|
||||
- **Custom**: blending is enabled. But the blending function is user specified. See `blendFunction`.
|
||||
|
||||
!!! Note
|
||||
When `blending` is set to `masked`, alpha to coverage is automatically enabled for the material.
|
||||
@@ -1442,36 +1432,6 @@ material {
|
||||
}
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
### Blending and transparency: blendFunction
|
||||
|
||||
Type
|
||||
: `object`
|
||||
|
||||
Fields
|
||||
: `srcRGB`, `srcA`, `dstRGB`, `dstA`
|
||||
|
||||
Description
|
||||
: - *srcRGB*: source function applied to the RGB channels
|
||||
- *srcA*: source function applied to the alpha channel
|
||||
- *srcRGB*: destination function applied to the RGB channels
|
||||
- *srcRGB*: destination function applied to the alpha channel
|
||||
The values possible for each functions are one of `zero`, `one`, `srcColor`, `oneMinusSrcColor`,
|
||||
`dstColor`, `oneMinusDstColor`, `srcAlpha`, `oneMinusSrcAlpha`, `dstAlpha`,
|
||||
`oneMinusDstAlpha`, `srcAlphaSaturate`
|
||||
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ JSON
|
||||
material {
|
||||
blending : custom,
|
||||
blendFunction :
|
||||
{
|
||||
srcRGB: one,
|
||||
srcA: one,
|
||||
dstRGB: oneMinusSrcColor,
|
||||
dstA: oneMinusSrcAlpha
|
||||
}
|
||||
}
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
### Blending and transparency: postLightingBlending
|
||||
|
||||
Type
|
||||
@@ -2434,7 +2394,6 @@ The following APIs are only available from the vertex block:
|
||||
**getWorldFromModelMatrix()** | float4x4 | Matrix that converts from model (object) space to world space
|
||||
**getWorldFromModelNormalMatrix()** | float3x3 | Matrix that converts normals from model (object) space to world space
|
||||
**getVertexIndex()** | int | Index of the current vertex
|
||||
**getEyeIndex()** | int | Index of the eye being rendered, starting at 0
|
||||
|
||||
### Fragment only
|
||||
|
||||
|
||||
File diff suppressed because one or more lines are too long
Binary file not shown.
@@ -43,7 +43,7 @@ filament-viewer::part(canvas) {
|
||||
</p>
|
||||
|
||||
</main>
|
||||
<script src="https://unpkg.com/filament@1.51.6/filament.js"></script>
|
||||
<script src="https://unpkg.com/filament@1.44.0/filament.js"></script>
|
||||
<script src="https://unpkg.com/gltumble"></script>
|
||||
<script src="filament-viewer.js" type="module"></script>
|
||||
</body>
|
||||
|
||||
+21
-47
@@ -61,13 +61,11 @@ set(SRCS
|
||||
src/Engine.cpp
|
||||
src/Exposure.cpp
|
||||
src/Fence.cpp
|
||||
src/FilamentBuilder.cpp
|
||||
src/FrameInfo.cpp
|
||||
src/FrameSkipper.cpp
|
||||
src/Froxelizer.cpp
|
||||
src/Frustum.cpp
|
||||
src/HwRenderPrimitiveFactory.cpp
|
||||
src/HwVertexBufferInfoFactory.cpp
|
||||
src/IndexBuffer.cpp
|
||||
src/IndirectLight.cpp
|
||||
src/InstanceBuffer.cpp
|
||||
@@ -139,7 +137,6 @@ set(SRCS
|
||||
|
||||
set(PRIVATE_HDRS
|
||||
src/Allocators.h
|
||||
src/Bimap.h
|
||||
src/BufferPoolAllocator.h
|
||||
src/ColorSpaceUtils.h
|
||||
src/Culler.h
|
||||
@@ -150,7 +147,6 @@ set(PRIVATE_HDRS
|
||||
src/FrameSkipper.h
|
||||
src/Froxelizer.h
|
||||
src/HwRenderPrimitiveFactory.h
|
||||
src/HwVertexBufferInfoFactory.h
|
||||
src/Intersections.h
|
||||
src/MaterialParser.h
|
||||
src/PerViewUniforms.h
|
||||
@@ -164,7 +160,6 @@ set(PRIVATE_HDRS
|
||||
src/ResourceList.h
|
||||
src/ShadowMap.h
|
||||
src/ShadowMapManager.h
|
||||
src/SharedHandle.h
|
||||
src/TypedUniformBuffer.h
|
||||
src/UniformBuffer.h
|
||||
src/components/CameraManager.h
|
||||
@@ -216,9 +211,7 @@ set(PRIVATE_HDRS
|
||||
set(MATERIAL_SRCS
|
||||
src/materials/antiAliasing/fxaa.mat
|
||||
src/materials/antiAliasing/taa.mat
|
||||
src/materials/blitDepth.mat
|
||||
src/materials/blitLow.mat
|
||||
src/materials/blitArray.mat
|
||||
src/materials/bloom/bloomDownsample.mat
|
||||
src/materials/bloom/bloomDownsample2x.mat
|
||||
src/materials/bloom/bloomDownsample9.mat
|
||||
@@ -255,13 +248,8 @@ set(MATERIAL_SRCS
|
||||
)
|
||||
|
||||
set(MATERIAL_FL0_SRCS
|
||||
src/materials/defaultMaterial.mat
|
||||
src/materials/skybox.mat
|
||||
)
|
||||
|
||||
set(MATERIAL_MULTIVIEW_SRCS
|
||||
src/materials/defaultMaterial.mat
|
||||
src/materials/skybox.mat
|
||||
src/materials/defaultMaterial0.mat
|
||||
src/materials/skybox0.mat
|
||||
)
|
||||
|
||||
# Embed the binary resource blob for materials.
|
||||
@@ -293,11 +281,6 @@ if (FILAMENT_ENABLE_FEATURE_LEVEL_0)
|
||||
add_definitions(-DFILAMENT_ENABLE_FEATURE_LEVEL_0)
|
||||
endif()
|
||||
|
||||
# Whether to include MULTIVIEW materials.
|
||||
if (FILAMENT_ENABLE_MULTIVIEW)
|
||||
add_definitions(-DFILAMENT_ENABLE_MULTIVIEW)
|
||||
endif()
|
||||
|
||||
# ==================================================================================================
|
||||
# Definitions
|
||||
# ==================================================================================================
|
||||
@@ -328,43 +311,34 @@ foreach (mat_src ${MATERIAL_SRCS})
|
||||
get_filename_component(localname "${mat_src}" NAME_WE)
|
||||
get_filename_component(fullname "${mat_src}" ABSOLUTE)
|
||||
set(output_path "${MATERIAL_DIR}/${localname}.filamat")
|
||||
|
||||
add_custom_command(
|
||||
OUTPUT ${output_path}
|
||||
COMMAND matc ${MATC_BASE_FLAGS} -o ${output_path} ${fullname}
|
||||
MAIN_DEPENDENCY ${fullname}
|
||||
DEPENDS matc
|
||||
COMMENT "Compiling material ${fullname} to ${output_path}"
|
||||
COMMENT "Compiling material ${mat_src} to ${output_path}"
|
||||
)
|
||||
list(APPEND MATERIAL_BINS ${output_path})
|
||||
|
||||
list(FIND MATERIAL_FL0_SRCS ${mat_src} index)
|
||||
if (${index} GREATER -1 AND FILAMENT_ENABLE_FEATURE_LEVEL_0)
|
||||
string(REGEX REPLACE "[.]filamat$" "_fl0.filamat" output_path_fl0 ${output_path})
|
||||
add_custom_command(
|
||||
OUTPUT ${output_path_fl0}
|
||||
COMMAND matc ${MATC_BASE_FLAGS} -PfeatureLevel=0 -o ${output_path_fl0} ${fullname}
|
||||
MAIN_DEPENDENCY ${fullname}
|
||||
DEPENDS matc
|
||||
COMMENT "Compiling material ${fullname} to ${output_path_fl0}"
|
||||
)
|
||||
list(APPEND MATERIAL_BINS ${output_path_fl0})
|
||||
endif ()
|
||||
|
||||
list(FIND MATERIAL_MULTIVIEW_SRCS ${mat_src} index)
|
||||
if (${index} GREATER -1 AND FILAMENT_ENABLE_MULTIVIEW)
|
||||
string(REGEX REPLACE "[.]filamat$" "_multiview.filamat" output_path_multiview ${output_path})
|
||||
add_custom_command(
|
||||
OUTPUT ${output_path_multiview}
|
||||
COMMAND matc ${MATC_BASE_FLAGS} -PstereoscopicType=multiview -o ${output_path_multiview} ${fullname}
|
||||
MAIN_DEPENDENCY ${fullname}
|
||||
DEPENDS matc
|
||||
COMMENT "Compiling material ${fullname} to ${output_path_multiview}"
|
||||
)
|
||||
list(APPEND MATERIAL_BINS ${output_path_multiview})
|
||||
endif ()
|
||||
|
||||
endforeach()
|
||||
|
||||
if (FILAMENT_ENABLE_FEATURE_LEVEL_0)
|
||||
foreach (mat_src ${MATERIAL_FL0_SRCS})
|
||||
get_filename_component(localname "${mat_src}" NAME_WE)
|
||||
get_filename_component(fullname "${mat_src}" ABSOLUTE)
|
||||
set(output_path "${MATERIAL_DIR}/${localname}.filamat")
|
||||
|
||||
add_custom_command(
|
||||
OUTPUT ${output_path}
|
||||
COMMAND matc ${MATC_BASE_FLAGS} -o ${output_path} ${fullname}
|
||||
MAIN_DEPENDENCY ${fullname}
|
||||
DEPENDS matc
|
||||
COMMENT "Compiling material ${mat_src} to ${output_path}"
|
||||
)
|
||||
list(APPEND MATERIAL_BINS ${output_path})
|
||||
endforeach ()
|
||||
endif ()
|
||||
|
||||
# Additional dependencies on included files for materials
|
||||
|
||||
add_custom_command(
|
||||
|
||||
@@ -66,13 +66,11 @@ set(PRIVATE_HDRS
|
||||
# OpenGL / OpenGL ES Sources
|
||||
# ==================================================================================================
|
||||
|
||||
if (FILAMENT_SUPPORTS_OPENGL AND NOT FILAMENT_USE_EXTERNAL_GLES3)
|
||||
if (FILAMENT_SUPPORTS_OPENGL AND NOT FILAMENT_USE_EXTERNAL_GLES3 AND NOT FILAMENT_USE_SWIFTSHADER)
|
||||
list(APPEND SRCS
|
||||
include/backend/platforms/OpenGLPlatform.h
|
||||
src/opengl/gl_headers.cpp
|
||||
src/opengl/gl_headers.h
|
||||
src/opengl/GLBufferObject.h
|
||||
src/opengl/GLTexture.h
|
||||
src/opengl/GLUtils.cpp
|
||||
src/opengl/GLUtils.h
|
||||
src/opengl/OpenGLBlobCache.cpp
|
||||
@@ -168,10 +166,6 @@ endif()
|
||||
if (FILAMENT_SUPPORTS_VULKAN)
|
||||
list(APPEND SRCS
|
||||
include/backend/platforms/VulkanPlatform.h
|
||||
src/vulkan/caching/VulkanDescriptorSetManager.cpp
|
||||
src/vulkan/caching/VulkanDescriptorSetManager.h
|
||||
src/vulkan/caching/VulkanPipelineLayoutCache.cpp
|
||||
src/vulkan/caching/VulkanPipelineLayoutCache.h
|
||||
src/vulkan/platform/VulkanPlatform.cpp
|
||||
src/vulkan/platform/VulkanPlatformSwapChainImpl.cpp
|
||||
src/vulkan/platform/VulkanPlatformSwapChainImpl.h
|
||||
@@ -417,9 +411,7 @@ if (APPLE OR LINUX)
|
||||
test/test_MissingRequiredAttributes.cpp
|
||||
test/test_ReadPixels.cpp
|
||||
test/test_BufferUpdates.cpp
|
||||
test/test_Callbacks.cpp
|
||||
test/test_MRT.cpp
|
||||
test/test_PushConstants.cpp
|
||||
test/test_LoadImage.cpp
|
||||
test/test_StencilBuffer.cpp
|
||||
test/test_Scissor.cpp
|
||||
@@ -480,10 +472,6 @@ if (APPLE)
|
||||
# linker from removing "unused" symbols.
|
||||
target_link_libraries(backend_test_mac PRIVATE -force_load backend_test)
|
||||
set_target_properties(backend_test_mac PROPERTIES FOLDER Tests)
|
||||
|
||||
# This is needed after XCode 15.3
|
||||
set_target_properties(backend_test_mac PROPERTIES BUILD_WITH_INSTALL_RPATH TRUE)
|
||||
set_target_properties(backend_test_mac PROPERTIES INSTALL_RPATH /usr/local/lib)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
|
||||
@@ -22,17 +22,14 @@
|
||||
#include <utils/BitmaskEnum.h>
|
||||
#include <utils/unwindows.h> // Because we define ERROR in the FenceStatus enum.
|
||||
|
||||
#include <backend/Platform.h>
|
||||
#include <backend/PresentCallable.h>
|
||||
|
||||
#include <utils/Invocable.h>
|
||||
#include <utils/ostream.h>
|
||||
|
||||
#include <math/vec4.h>
|
||||
|
||||
#include <array> // FIXME: STL headers are not allowed in public headers
|
||||
#include <type_traits> // FIXME: STL headers are not allowed in public headers
|
||||
#include <variant> // FIXME: STL headers are not allowed in public headers
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
@@ -84,24 +81,14 @@ static constexpr uint64_t SWAP_CHAIN_CONFIG_SRGB_COLORSPACE = 0x10;
|
||||
/**
|
||||
* Indicates that the SwapChain should also contain a stencil component.
|
||||
*/
|
||||
static constexpr uint64_t SWAP_CHAIN_CONFIG_HAS_STENCIL_BUFFER = 0x20;
|
||||
static constexpr uint64_t SWAP_CHAIN_HAS_STENCIL_BUFFER = SWAP_CHAIN_CONFIG_HAS_STENCIL_BUFFER;
|
||||
static constexpr uint64_t SWAP_CHAIN_HAS_STENCIL_BUFFER = 0x20;
|
||||
|
||||
/**
|
||||
* The SwapChain contains protected content. Currently only supported by OpenGLPlatform and
|
||||
* only when OpenGLPlatform::isProtectedContextSupported() is true.
|
||||
*/
|
||||
static constexpr uint64_t SWAP_CHAIN_CONFIG_PROTECTED_CONTENT = 0x40;
|
||||
|
||||
static constexpr size_t MAX_VERTEX_ATTRIBUTE_COUNT = 16; // This is guaranteed by OpenGL ES.
|
||||
static constexpr size_t MAX_SAMPLER_COUNT = 62; // Maximum needed at feature level 3.
|
||||
static constexpr size_t MAX_VERTEX_BUFFER_COUNT = 16; // Max number of bound buffer objects.
|
||||
static constexpr size_t MAX_SSBO_COUNT = 4; // This is guaranteed by OpenGL ES.
|
||||
|
||||
static constexpr size_t MAX_PUSH_CONSTANT_COUNT = 32; // Vulkan 1.1 spec allows for 128-byte
|
||||
// of push constant (we assume 4-byte
|
||||
// types).
|
||||
|
||||
// Per feature level caps
|
||||
// Use (int)FeatureLevel to index this array
|
||||
static constexpr struct {
|
||||
@@ -118,7 +105,7 @@ static_assert(MAX_VERTEX_BUFFER_COUNT <= MAX_VERTEX_ATTRIBUTE_COUNT,
|
||||
"The number of buffer objects that can be attached to a VertexBuffer must be "
|
||||
"less than or equal to the maximum number of vertex attributes.");
|
||||
|
||||
static constexpr size_t CONFIG_UNIFORM_BINDING_COUNT = 9; // This is guaranteed by OpenGL ES.
|
||||
static constexpr size_t CONFIG_UNIFORM_BINDING_COUNT = 10; // This is guaranteed by OpenGL ES.
|
||||
static constexpr size_t CONFIG_SAMPLER_BINDING_COUNT = 4; // This is guaranteed by OpenGL ES.
|
||||
|
||||
/**
|
||||
@@ -142,12 +129,6 @@ enum class Backend : uint8_t {
|
||||
NOOP = 4, //!< Selects the no-op driver for testing purposes.
|
||||
};
|
||||
|
||||
enum class TimerQueryResult : int8_t {
|
||||
ERROR = -1, // an error occurred, result won't be available
|
||||
NOT_READY = 0, // result to ready yet
|
||||
AVAILABLE = 1, // result is available
|
||||
};
|
||||
|
||||
static constexpr const char* backendToString(Backend backend) {
|
||||
switch (backend) {
|
||||
case Backend::NOOP:
|
||||
@@ -164,16 +145,14 @@ static constexpr const char* backendToString(Backend backend) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines the shader language. Similar to the above backend enum, with some differences:
|
||||
* - The OpenGL backend can select between two shader languages: ESSL 1.0 and ESSL 3.0.
|
||||
* - The Metal backend can prefer precompiled Metal libraries, while falling back to MSL.
|
||||
* Defines the shader language. Similar to the above backend enum, but the OpenGL backend can select
|
||||
* between two shader languages: ESSL 1.0 and ESSL 3.0.
|
||||
*/
|
||||
enum class ShaderLanguage {
|
||||
ESSL1 = 0,
|
||||
ESSL3 = 1,
|
||||
SPIRV = 2,
|
||||
MSL = 3,
|
||||
METAL_LIBRARY = 4,
|
||||
};
|
||||
|
||||
static constexpr const char* shaderLanguageToString(ShaderLanguage shaderLanguage) {
|
||||
@@ -186,8 +165,6 @@ static constexpr const char* shaderLanguageToString(ShaderLanguage shaderLanguag
|
||||
return "SPIR-V";
|
||||
case ShaderLanguage::MSL:
|
||||
return "MSL";
|
||||
case ShaderLanguage::METAL_LIBRARY:
|
||||
return "Metal precompiled library";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -337,7 +314,7 @@ enum class UniformType : uint8_t {
|
||||
/**
|
||||
* Supported constant parameter types
|
||||
*/
|
||||
enum class ConstantType : uint8_t {
|
||||
enum class ConstantType : uint8_t {
|
||||
INT,
|
||||
FLOAT,
|
||||
BOOL
|
||||
@@ -682,17 +659,16 @@ enum class TextureFormat : uint16_t {
|
||||
};
|
||||
|
||||
//! Bitmask describing the intended Texture Usage
|
||||
enum class TextureUsage : uint16_t {
|
||||
NONE = 0x0000,
|
||||
COLOR_ATTACHMENT = 0x0001, //!< Texture can be used as a color attachment
|
||||
DEPTH_ATTACHMENT = 0x0002, //!< Texture can be used as a depth attachment
|
||||
STENCIL_ATTACHMENT = 0x0004, //!< Texture can be used as a stencil attachment
|
||||
UPLOADABLE = 0x0008, //!< Data can be uploaded into this texture (default)
|
||||
SAMPLEABLE = 0x0010, //!< Texture can be sampled (default)
|
||||
SUBPASS_INPUT = 0x0020, //!< Texture can be used as a subpass input
|
||||
BLIT_SRC = 0x0040, //!< Texture can be used the source of a blit()
|
||||
BLIT_DST = 0x0080, //!< Texture can be used the destination of a blit()
|
||||
PROTECTED = 0x0100, //!< Texture can be used for protected content
|
||||
enum class TextureUsage : uint8_t {
|
||||
NONE = 0x00,
|
||||
COLOR_ATTACHMENT = 0x01, //!< Texture can be used as a color attachment
|
||||
DEPTH_ATTACHMENT = 0x02, //!< Texture can be used as a depth attachment
|
||||
STENCIL_ATTACHMENT = 0x04, //!< Texture can be used as a stencil attachment
|
||||
UPLOADABLE = 0x08, //!< Data can be uploaded into this texture (default)
|
||||
SAMPLEABLE = 0x10, //!< Texture can be sampled (default)
|
||||
SUBPASS_INPUT = 0x20, //!< Texture can be used as a subpass input
|
||||
BLIT_SRC = 0x40, //!< Texture can be used the source of a blit()
|
||||
BLIT_DST = 0x80, //!< Texture can be used the destination of a blit()
|
||||
DEFAULT = UPLOADABLE | SAMPLEABLE //!< Default texture usage
|
||||
};
|
||||
|
||||
@@ -1196,27 +1172,11 @@ struct StencilState {
|
||||
|
||||
//! Stencil operations for front-facing polygons
|
||||
StencilOperations front = {
|
||||
.stencilFunc = StencilFunction::A,
|
||||
.stencilOpStencilFail = StencilOperation::KEEP,
|
||||
.padding0 = 0,
|
||||
.stencilOpDepthFail = StencilOperation::KEEP,
|
||||
.stencilOpDepthStencilPass = StencilOperation::KEEP,
|
||||
.padding1 = 0,
|
||||
.ref = 0,
|
||||
.readMask = 0xff,
|
||||
.writeMask = 0xff };
|
||||
.stencilFunc = StencilFunction::A, .ref = 0, .readMask = 0xff, .writeMask = 0xff };
|
||||
|
||||
//! Stencil operations for back-facing polygons
|
||||
StencilOperations back = {
|
||||
.stencilFunc = StencilFunction::A,
|
||||
.stencilOpStencilFail = StencilOperation::KEEP,
|
||||
.padding0 = 0,
|
||||
.stencilOpDepthFail = StencilOperation::KEEP,
|
||||
.stencilOpDepthStencilPass = StencilOperation::KEEP,
|
||||
.padding1 = 0,
|
||||
.ref = 0,
|
||||
.readMask = 0xff,
|
||||
.writeMask = 0xff };
|
||||
.stencilFunc = StencilFunction::A, .ref = 0, .readMask = 0xff, .writeMask = 0xff };
|
||||
|
||||
//! Whether stencil-buffer writes are enabled
|
||||
bool stencilWrite = false;
|
||||
@@ -1224,15 +1184,13 @@ struct StencilState {
|
||||
uint8_t padding = 0;
|
||||
};
|
||||
|
||||
using PushConstantVariant = std::variant<int32_t, float, bool>;
|
||||
|
||||
static_assert(sizeof(StencilState::StencilOperations) == 5u,
|
||||
"StencilOperations size not what was intended");
|
||||
|
||||
static_assert(sizeof(StencilState) == 12u,
|
||||
"StencilState size not what was intended");
|
||||
|
||||
using FrameScheduledCallback = utils::Invocable<void(backend::PresentCallable)>;
|
||||
using FrameScheduledCallback = void(*)(PresentCallable callable, void* user);
|
||||
|
||||
enum class Workaround : uint16_t {
|
||||
// The EASU pass must split because shader compiler flattens early-exit branch
|
||||
@@ -1244,14 +1202,23 @@ enum class Workaround : uint16_t {
|
||||
ADRENO_UNIFORM_ARRAY_CRASH,
|
||||
// Workaround a Metal pipeline compilation error with the message:
|
||||
// "Could not statically determine the target of a texture". See light_indirect.fs
|
||||
METAL_STATIC_TEXTURE_TARGET_ERROR,
|
||||
A8X_STATIC_TEXTURE_TARGET_ERROR,
|
||||
// Adreno drivers sometimes aren't able to blit into a layer of a texture array.
|
||||
DISABLE_BLIT_INTO_TEXTURE_ARRAY,
|
||||
// Multiple workarounds needed for PowerVR GPUs
|
||||
POWER_VR_SHADER_WORKAROUNDS,
|
||||
// The driver has some threads pinned, and we can't easily know on which core, it can hurt
|
||||
// performance more if we end-up pinned on the same one.
|
||||
DISABLE_THREAD_AFFINITY
|
||||
};
|
||||
|
||||
using StereoscopicType = backend::Platform::StereoscopicType;
|
||||
//! The type of technique for stereoscopic rendering
|
||||
enum class StereoscopicType : uint8_t {
|
||||
// Stereoscopic rendering is performed using instanced rendering technique.
|
||||
INSTANCED,
|
||||
// Stereoscopic rendering is performed using the multiview feature from the graphics backend.
|
||||
MULTIVIEW,
|
||||
};
|
||||
|
||||
} // namespace filament::backend
|
||||
|
||||
|
||||
@@ -39,7 +39,6 @@ struct HwStream;
|
||||
struct HwSwapChain;
|
||||
struct HwTexture;
|
||||
struct HwTimerQuery;
|
||||
struct HwVertexBufferInfo;
|
||||
struct HwVertexBuffer;
|
||||
|
||||
/*
|
||||
@@ -75,19 +74,6 @@ protected:
|
||||
HandleBase(HandleBase const& rhs) noexcept = default;
|
||||
HandleBase& operator=(HandleBase const& rhs) noexcept = default;
|
||||
|
||||
HandleBase(HandleBase&& rhs) noexcept
|
||||
: object(rhs.object) {
|
||||
rhs.object = nullid;
|
||||
}
|
||||
|
||||
HandleBase& operator=(HandleBase&& rhs) noexcept {
|
||||
if (this != &rhs) {
|
||||
object = rhs.object;
|
||||
rhs.object = nullid;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
private:
|
||||
HandleId object;
|
||||
};
|
||||
@@ -102,10 +88,8 @@ struct Handle : public HandleBase {
|
||||
Handle() noexcept = default;
|
||||
|
||||
Handle(Handle const& rhs) noexcept = default;
|
||||
Handle(Handle&& rhs) noexcept = default;
|
||||
|
||||
Handle& operator=(Handle const& rhs) noexcept = default;
|
||||
Handle& operator=(Handle&& rhs) noexcept = default;
|
||||
|
||||
explicit Handle(HandleId id) noexcept : HandleBase(id) { }
|
||||
|
||||
@@ -130,19 +114,18 @@ private:
|
||||
|
||||
// Types used by the command stream
|
||||
// (we use this renaming because the macro-system doesn't deal well with "<" and ">")
|
||||
using BufferObjectHandle = Handle<HwBufferObject>;
|
||||
using FenceHandle = Handle<HwFence>;
|
||||
using IndexBufferHandle = Handle<HwIndexBuffer>;
|
||||
using ProgramHandle = Handle<HwProgram>;
|
||||
using RenderPrimitiveHandle = Handle<HwRenderPrimitive>;
|
||||
using RenderTargetHandle = Handle<HwRenderTarget>;
|
||||
using SamplerGroupHandle = Handle<HwSamplerGroup>;
|
||||
using StreamHandle = Handle<HwStream>;
|
||||
using SwapChainHandle = Handle<HwSwapChain>;
|
||||
using TextureHandle = Handle<HwTexture>;
|
||||
using TimerQueryHandle = Handle<HwTimerQuery>;
|
||||
using VertexBufferHandle = Handle<HwVertexBuffer>;
|
||||
using VertexBufferInfoHandle = Handle<HwVertexBufferInfo>;
|
||||
using BufferObjectHandle = Handle<HwBufferObject>;
|
||||
using FenceHandle = Handle<HwFence>;
|
||||
using IndexBufferHandle = Handle<HwIndexBuffer>;
|
||||
using ProgramHandle = Handle<HwProgram>;
|
||||
using RenderPrimitiveHandle = Handle<HwRenderPrimitive>;
|
||||
using RenderTargetHandle = Handle<HwRenderTarget>;
|
||||
using SamplerGroupHandle = Handle<HwSamplerGroup>;
|
||||
using StreamHandle = Handle<HwStream>;
|
||||
using SwapChainHandle = Handle<HwSwapChain>;
|
||||
using TextureHandle = Handle<HwTexture>;
|
||||
using TimerQueryHandle = Handle<HwTimerQuery>;
|
||||
using VertexBufferHandle = Handle<HwVertexBuffer>;
|
||||
|
||||
} // namespace filament::backend
|
||||
|
||||
|
||||
@@ -29,13 +29,11 @@ namespace filament::backend {
|
||||
//! \privatesection
|
||||
|
||||
struct PipelineState {
|
||||
Handle<HwProgram> program; // 4
|
||||
Handle<HwVertexBufferInfo> vertexBufferInfo; // 4
|
||||
RasterState rasterState; // 4
|
||||
StencilState stencilState; // 12
|
||||
PolygonOffset polygonOffset; // 8
|
||||
PrimitiveType primitiveType = PrimitiveType::TRIANGLES; // 1
|
||||
uint8_t padding[3] = {}; // 3
|
||||
Handle<HwProgram> program;
|
||||
RasterState rasterState;
|
||||
StencilState stencilState;
|
||||
PolygonOffset polygonOffset;
|
||||
Viewport scissor{ 0, 0, (uint32_t)INT32_MAX, (uint32_t)INT32_MAX };
|
||||
};
|
||||
|
||||
} // namespace filament::backend
|
||||
|
||||
@@ -23,7 +23,6 @@
|
||||
#include <utils/Invocable.h>
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
namespace filament::backend {
|
||||
|
||||
@@ -41,26 +40,6 @@ public:
|
||||
struct Fence {};
|
||||
struct Stream {};
|
||||
|
||||
/**
|
||||
* The type of technique for stereoscopic rendering. (Note that the materials used will need to
|
||||
* be compatible with the chosen technique.)
|
||||
*/
|
||||
enum class StereoscopicType : uint8_t {
|
||||
/**
|
||||
* No stereoscopic rendering
|
||||
*/
|
||||
NONE,
|
||||
/**
|
||||
* Stereoscopic rendering is performed using instanced rendering technique.
|
||||
*/
|
||||
INSTANCED,
|
||||
/**
|
||||
* Stereoscopic rendering is performed using the multiview feature from the graphics
|
||||
* backend.
|
||||
*/
|
||||
MULTIVIEW,
|
||||
};
|
||||
|
||||
struct DriverConfig {
|
||||
/**
|
||||
* Size of handle arena in bytes. Setting to 0 indicates default value is to be used.
|
||||
@@ -75,29 +54,11 @@ public:
|
||||
*/
|
||||
size_t textureUseAfterFreePoolSize = 0;
|
||||
|
||||
size_t metalUploadBufferSizeBytes = 512 * 1024;
|
||||
|
||||
/**
|
||||
* Set to `true` to forcibly disable parallel shader compilation in the backend.
|
||||
* Currently only honored by the GL and Metal backends.
|
||||
* Currently only honored by the GL backend.
|
||||
*/
|
||||
bool disableParallelShaderCompile = false;
|
||||
|
||||
/**
|
||||
* Disable backend handles use-after-free checks.
|
||||
*/
|
||||
bool disableHandleUseAfterFreeCheck = false;
|
||||
|
||||
/**
|
||||
* Force GLES2 context if supported, or pretend the context is ES2. Only meaningful on
|
||||
* GLES 3.x backends.
|
||||
*/
|
||||
bool forceGLES2Context = false;
|
||||
|
||||
/**
|
||||
* Sets the technique for stereoscopic rendering.
|
||||
*/
|
||||
StereoscopicType stereoscopicType = StereoscopicType::NONE;
|
||||
};
|
||||
|
||||
Platform() noexcept;
|
||||
@@ -227,40 +188,9 @@ public:
|
||||
size_t retrieveBlob(const void* UTILS_NONNULL key, size_t keySize,
|
||||
void* UTILS_NONNULL value, size_t valueSize);
|
||||
|
||||
using DebugUpdateStatFunc = utils::Invocable<void(const char* UTILS_NONNULL key, uint64_t value)>;
|
||||
|
||||
/**
|
||||
* Sets the callback function that the backend can use to update backend-specific statistics
|
||||
* to aid with debugging. This callback is guaranteed to be called on the Filament driver
|
||||
* thread.
|
||||
*
|
||||
* @param debugUpdateStat an Invocable that updates debug statistics
|
||||
*/
|
||||
void setDebugUpdateStatFunc(DebugUpdateStatFunc&& debugUpdateStat) noexcept;
|
||||
|
||||
/**
|
||||
* @return true if debugUpdateStat is valid.
|
||||
*/
|
||||
bool hasDebugUpdateStatFunc() const noexcept;
|
||||
|
||||
/**
|
||||
* To track backend-specific statistics, the backend implementation can call the
|
||||
* application-provided callback function debugUpdateStatFunc to associate or update a value
|
||||
* with a given key. It is possible for this function to be called multiple times with the
|
||||
* same key, in which case newer values should overwrite older values.
|
||||
*
|
||||
* This function is guaranteed to be called only on a single thread, the Filament driver
|
||||
* thread.
|
||||
*
|
||||
* @param key a null-terminated C-string with the key of the debug statistic
|
||||
* @param value the updated value of key
|
||||
*/
|
||||
void debugUpdateStat(const char* UTILS_NONNULL key, uint64_t value);
|
||||
|
||||
private:
|
||||
InsertBlobFunc mInsertBlob;
|
||||
RetrieveBlobFunc mRetrieveBlob;
|
||||
DebugUpdateStatFunc mDebugUpdateStat;
|
||||
};
|
||||
|
||||
} // namespace filament
|
||||
|
||||
@@ -48,7 +48,7 @@ namespace filament::backend {
|
||||
* and optional user data:
|
||||
*
|
||||
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
* swapChain->setFrameScheduledCallback(nullptr, myFrameScheduledCallback);
|
||||
* swapChain->setFrameScheduledCallback(myFrameScheduledCallback, nullptr);
|
||||
* if (renderer->beginFrame(swapChain)) {
|
||||
* renderer->render(view);
|
||||
* renderer->endFrame();
|
||||
@@ -58,6 +58,8 @@ namespace filament::backend {
|
||||
* @remark Only Filament's Metal backend supports PresentCallables and frame callbacks. Other
|
||||
* backends ignore the callback (which will never be called) and proceed normally.
|
||||
*
|
||||
* @remark The SwapChain::FrameScheduledCallback is called on an arbitrary thread.
|
||||
*
|
||||
* Applications *must* call each PresentCallable they receive. Each PresentCallable represents a
|
||||
* frame that is waiting to be presented. If an application fails to call a PresentCallable, a
|
||||
* memory leak could occur. To "cancel" the presentation of a frame, pass false to the
|
||||
|
||||
@@ -84,9 +84,6 @@ public:
|
||||
// null terminating character.
|
||||
Program& shader(ShaderStage shader, void const* data, size_t size);
|
||||
|
||||
// sets the language of the shader sources provided with shader() (defaults to ESSL3)
|
||||
Program& shaderLanguage(ShaderLanguage shaderLanguage);
|
||||
|
||||
// Note: This is only needed for GLES3.0 backends, because the layout(binding=) syntax is
|
||||
// not permitted in glsl. The backend needs a way to associate a uniform block
|
||||
// to a binding point.
|
||||
@@ -117,18 +114,8 @@ public:
|
||||
Program& specializationConstants(
|
||||
utils::FixedCapacityVector<SpecializationConstant> specConstants) noexcept;
|
||||
|
||||
struct PushConstant {
|
||||
utils::CString name;
|
||||
ConstantType type;
|
||||
};
|
||||
|
||||
Program& pushConstants(ShaderStage stage,
|
||||
utils::FixedCapacityVector<PushConstant> constants) noexcept;
|
||||
|
||||
Program& cacheId(uint64_t cacheId) noexcept;
|
||||
|
||||
Program& multiview(bool multiview) noexcept;
|
||||
|
||||
ShaderSource const& getShadersSource() const noexcept { return mShadersSource; }
|
||||
ShaderSource& getShadersSource() noexcept { return mShadersSource; }
|
||||
|
||||
@@ -147,8 +134,6 @@ public:
|
||||
utils::CString const& getName() const noexcept { return mName; }
|
||||
utils::CString& getName() noexcept { return mName; }
|
||||
|
||||
auto const& getShaderLanguage() const { return mShaderLanguage; }
|
||||
|
||||
utils::FixedCapacityVector<SpecializationConstant> const& getSpecializationConstants() const noexcept {
|
||||
return mSpecializationConstants;
|
||||
}
|
||||
@@ -156,19 +141,8 @@ public:
|
||||
return mSpecializationConstants;
|
||||
}
|
||||
|
||||
utils::FixedCapacityVector<PushConstant> const& getPushConstants(
|
||||
ShaderStage stage) const noexcept {
|
||||
return mPushConstants[static_cast<uint8_t>(stage)];
|
||||
}
|
||||
|
||||
utils::FixedCapacityVector<PushConstant>& getPushConstants(ShaderStage stage) noexcept {
|
||||
return mPushConstants[static_cast<uint8_t>(stage)];
|
||||
}
|
||||
|
||||
uint64_t getCacheId() const noexcept { return mCacheId; }
|
||||
|
||||
bool isMultiview() const noexcept { return mMultiview; }
|
||||
|
||||
CompilerPriorityQueue getPriorityQueue() const noexcept { return mPriorityQueue; }
|
||||
|
||||
private:
|
||||
@@ -177,20 +151,13 @@ private:
|
||||
UniformBlockInfo mUniformBlocks = {};
|
||||
SamplerGroupInfo mSamplerGroups = {};
|
||||
ShaderSource mShadersSource;
|
||||
ShaderLanguage mShaderLanguage = ShaderLanguage::ESSL3;
|
||||
utils::CString mName;
|
||||
uint64_t mCacheId{};
|
||||
utils::Invocable<utils::io::ostream&(utils::io::ostream& out)> mLogger;
|
||||
utils::FixedCapacityVector<SpecializationConstant> mSpecializationConstants;
|
||||
std::array<utils::FixedCapacityVector<PushConstant>, SHADER_TYPE_COUNT> mPushConstants;
|
||||
utils::FixedCapacityVector<std::pair<utils::CString, uint8_t>> mAttributes;
|
||||
std::array<UniformInfo, Program::UNIFORM_BINDING_COUNT> mBindingUniformInfo;
|
||||
CompilerPriorityQueue mPriorityQueue = CompilerPriorityQueue::HIGH;
|
||||
// Indicates the current engine was initialized with multiview stereo, and the variant for this
|
||||
// program contains STE flag. This will be referred later for the OpenGL shader compiler to
|
||||
// determine whether shader code replacement for the num_views should be performed.
|
||||
// This variable could be promoted as a more generic variable later if other similar needs occur.
|
||||
bool mMultiview = false;
|
||||
};
|
||||
|
||||
} // namespace filament::backend
|
||||
|
||||
@@ -29,36 +29,13 @@ namespace filament::backend {
|
||||
//! \privatesection
|
||||
|
||||
struct TargetBufferInfo {
|
||||
// note: the parameters of this constructor are not in the order of this structure's fields
|
||||
TargetBufferInfo(Handle<HwTexture> handle, uint8_t level, uint16_t layer, uint8_t baseViewIndex) noexcept
|
||||
: handle(handle), baseViewIndex(baseViewIndex), level(level), layer(layer) {
|
||||
}
|
||||
|
||||
TargetBufferInfo(Handle<HwTexture> handle, uint8_t level, uint16_t layer) noexcept
|
||||
: handle(handle), level(level), layer(layer) {
|
||||
}
|
||||
|
||||
TargetBufferInfo(Handle<HwTexture> handle, uint8_t level) noexcept
|
||||
: handle(handle), level(level) {
|
||||
}
|
||||
|
||||
TargetBufferInfo(Handle<HwTexture> handle) noexcept // NOLINT(*-explicit-constructor)
|
||||
: handle(handle) {
|
||||
}
|
||||
|
||||
TargetBufferInfo() noexcept = default;
|
||||
|
||||
// texture to be used as render target
|
||||
Handle<HwTexture> handle;
|
||||
|
||||
// Starting layer index for multiview. This value is only used when the `layerCount` for the
|
||||
// render target is greater than 1.
|
||||
uint8_t baseViewIndex = 0;
|
||||
|
||||
// level to be used
|
||||
uint8_t level = 0;
|
||||
|
||||
// For cubemaps and 3D textures. See TextureCubemapFace for the face->layer mapping
|
||||
// for cubemaps and 3D textures. See TextureCubemapFace for the face->layer mapping
|
||||
uint16_t layer = 0;
|
||||
};
|
||||
|
||||
@@ -83,7 +60,7 @@ public:
|
||||
|
||||
MRT() noexcept = default;
|
||||
|
||||
MRT(TargetBufferInfo const& color) noexcept // NOLINT(hicpp-explicit-conversions, *-explicit-constructor)
|
||||
MRT(TargetBufferInfo const& color) noexcept // NOLINT(hicpp-explicit-conversions)
|
||||
: mInfos{ color } {
|
||||
}
|
||||
|
||||
@@ -103,7 +80,7 @@ public:
|
||||
|
||||
// this is here for backward compatibility
|
||||
MRT(Handle<HwTexture> handle, uint8_t level, uint16_t layer) noexcept
|
||||
: mInfos{{ handle, level, layer, 0 }} {
|
||||
: mInfos{{ handle, level, layer }} {
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -22,9 +22,7 @@
|
||||
#include <backend/Platform.h>
|
||||
|
||||
#include <utils/compiler.h>
|
||||
#include <utils/Invocable.h>
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
namespace filament::backend {
|
||||
@@ -64,22 +62,6 @@ public:
|
||||
*/
|
||||
virtual void terminate() noexcept = 0;
|
||||
|
||||
/**
|
||||
* Return whether createSwapChain supports the SWAP_CHAIN_CONFIG_SRGB_COLORSPACE flag.
|
||||
* The default implementation returns false.
|
||||
*
|
||||
* @return true if SWAP_CHAIN_CONFIG_SRGB_COLORSPACE is supported, false otherwise.
|
||||
*/
|
||||
virtual bool isSRGBSwapChainSupported() const noexcept;
|
||||
|
||||
/**
|
||||
* Return whether protected contexts are supported by this backend.
|
||||
* If protected context are supported, the SWAP_CHAIN_CONFIG_PROTECTED_CONTENT flag can be
|
||||
* used when creating a SwapChain.
|
||||
* The default implementation returns false.
|
||||
*/
|
||||
virtual bool isProtectedContextSupported() const noexcept;
|
||||
|
||||
/**
|
||||
* Called by the driver to create a SwapChain for this driver.
|
||||
*
|
||||
@@ -89,9 +71,17 @@ public:
|
||||
* @return The driver's SwapChain object.
|
||||
*
|
||||
*/
|
||||
virtual SwapChain* UTILS_NULLABLE createSwapChain(
|
||||
virtual SwapChain* UTILS_NONNULL createSwapChain(
|
||||
void* UTILS_NULLABLE nativeWindow, uint64_t flags) noexcept = 0;
|
||||
|
||||
/**
|
||||
* Return whether createSwapChain supports the SWAP_CHAIN_CONFIG_SRGB_COLORSPACE flag.
|
||||
* The default implementation returns false.
|
||||
*
|
||||
* @return true if SWAP_CHAIN_CONFIG_SRGB_COLORSPACE is supported, false otherwise.
|
||||
*/
|
||||
virtual bool isSRGBSwapChainSupported() const noexcept;
|
||||
|
||||
/**
|
||||
* Called by the driver create a headless SwapChain.
|
||||
*
|
||||
@@ -125,94 +115,21 @@ public:
|
||||
*/
|
||||
virtual TargetBufferFlags getPreservedFlags(SwapChain* UTILS_NONNULL swapChain) noexcept;
|
||||
|
||||
/**
|
||||
* Returns true if the swapchain is protected
|
||||
*/
|
||||
virtual bool isSwapChainProtected(Platform::SwapChain* UTILS_NONNULL swapChain) noexcept;
|
||||
|
||||
/**
|
||||
* Called by the driver to establish the default FBO. The default implementation returns 0.
|
||||
*
|
||||
* This method can be called either on the regular or protected OpenGL contexts and can return
|
||||
* a different or identical name, since these names exist in different namespaces.
|
||||
*
|
||||
* @return a GLuint casted to a uint32_t that is an OpenGL framebuffer object.
|
||||
* @return a GLuint casted to a uint32_t that is an OpenGL framebuffer object.
|
||||
*/
|
||||
virtual uint32_t getDefaultFramebufferObject() noexcept;
|
||||
|
||||
/**
|
||||
* Called by the backend when a frame starts.
|
||||
* @param steady_clock_ns vsync time point on the monotonic clock
|
||||
* @param refreshIntervalNs refresh interval in nanosecond
|
||||
* @param frameId a frame id
|
||||
*/
|
||||
virtual void beginFrame(
|
||||
int64_t monotonic_clock_ns,
|
||||
int64_t refreshIntervalNs,
|
||||
uint32_t frameId) noexcept;
|
||||
|
||||
/**
|
||||
* Called by the backend when a frame ends.
|
||||
* @param frameId the frame id used in beginFrame
|
||||
*/
|
||||
virtual void endFrame(
|
||||
uint32_t frameId) noexcept;
|
||||
|
||||
/**
|
||||
* Type of contexts available
|
||||
*/
|
||||
enum class ContextType {
|
||||
NONE, //!< No current context
|
||||
UNPROTECTED, //!< current context is unprotected
|
||||
PROTECTED //!< current context supports protected content
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the type of the context currently in use. This value is updated by makeCurrent()
|
||||
* and therefore can be cached between calls. ContextType::PROTECTED can only be returned
|
||||
* if isProtectedContextSupported() is true.
|
||||
* @return ContextType
|
||||
*/
|
||||
virtual ContextType getCurrentContextType() const noexcept;
|
||||
|
||||
/**
|
||||
* Binds the requested context to the current thread and drawSwapChain to the default FBO
|
||||
* returned by getDefaultFramebufferObject().
|
||||
*
|
||||
* @param type type of context to bind to the current thread.
|
||||
* @param drawSwapChain SwapChain to draw to. It must be bound to the default FBO.
|
||||
* @param readSwapChain SwapChain to read from (for operation like `glBlitFramebuffer`)
|
||||
* @return true on success, false on error.
|
||||
*/
|
||||
virtual bool makeCurrent(ContextType type,
|
||||
SwapChain* UTILS_NONNULL drawSwapChain,
|
||||
SwapChain* UTILS_NONNULL readSwapChain) noexcept = 0;
|
||||
virtual uint32_t createDefaultRenderTarget() noexcept;
|
||||
|
||||
/**
|
||||
* Called by the driver to make the OpenGL context active on the calling thread and bind
|
||||
* the drawSwapChain to the default FBO returned by getDefaultFramebufferObject().
|
||||
* The context used is either the default context or the protected context. When a context
|
||||
* change is necessary, the preContextChange and postContextChange callbacks are called,
|
||||
* before and after the context change respectively. postContextChange is given the index
|
||||
* of the new context (0 for default and 1 for protected).
|
||||
* The default implementation just calls makeCurrent(getCurrentContextType(), SwapChain*, SwapChain*).
|
||||
*
|
||||
* the drawSwapChain to the default render target (FBO) created with createDefaultRenderTarget.
|
||||
* @param drawSwapChain SwapChain to draw to. It must be bound to the default FBO.
|
||||
* @param readSwapChain SwapChain to read from (for operation like `glBlitFramebuffer`)
|
||||
* @param preContextChange called before the context changes
|
||||
* @param postContextChange called after the context changes
|
||||
*/
|
||||
virtual void makeCurrent(
|
||||
SwapChain* UTILS_NONNULL drawSwapChain,
|
||||
SwapChain* UTILS_NONNULL readSwapChain,
|
||||
utils::Invocable<void()> preContextChange,
|
||||
utils::Invocable<void(size_t index)> postContextChange) noexcept;
|
||||
|
||||
/**
|
||||
* Called by the backend just before calling commit()
|
||||
* @see commit()
|
||||
*/
|
||||
virtual void preCommit() noexcept;
|
||||
SwapChain* UTILS_NONNULL readSwapChain) noexcept = 0;
|
||||
|
||||
/**
|
||||
* Called by the driver once the current frame finishes drawing. Typically, this should present
|
||||
|
||||
@@ -57,7 +57,7 @@ protected:
|
||||
SwapChain* createSwapChain(void* nativewindow, uint64_t flags) noexcept override;
|
||||
SwapChain* createSwapChain(uint32_t width, uint32_t height, uint64_t flags) noexcept override;
|
||||
void destroySwapChain(SwapChain* swapChain) noexcept override;
|
||||
bool makeCurrent(ContextType type, SwapChain* drawSwapChain, SwapChain* readSwapChain) noexcept override;
|
||||
void makeCurrent(SwapChain* drawSwapChain, SwapChain* readSwapChain) noexcept override;
|
||||
void commit(SwapChain* swapChain) noexcept override;
|
||||
OpenGLPlatform::ExternalTexture* createExternalImageTexture() noexcept override;
|
||||
void destroyExternalImage(ExternalTexture* texture) noexcept override;
|
||||
|
||||
@@ -45,7 +45,7 @@ public:
|
||||
|
||||
void terminate() noexcept override;
|
||||
|
||||
uint32_t getDefaultFramebufferObject() noexcept override;
|
||||
uint32_t createDefaultRenderTarget() noexcept override;
|
||||
|
||||
bool isExtraContextSupported() const noexcept override;
|
||||
void createContext(bool shared) override;
|
||||
@@ -53,7 +53,7 @@ public:
|
||||
SwapChain* createSwapChain(void* nativewindow, uint64_t flags) noexcept override;
|
||||
SwapChain* createSwapChain(uint32_t width, uint32_t height, uint64_t flags) noexcept override;
|
||||
void destroySwapChain(SwapChain* swapChain) noexcept override;
|
||||
bool makeCurrent(ContextType type, SwapChain* drawSwapChain, SwapChain* readSwapChain) noexcept override;
|
||||
void makeCurrent(SwapChain* drawSwapChain, SwapChain* readSwapChain) noexcept override;
|
||||
void commit(SwapChain* swapChain) noexcept override;
|
||||
|
||||
OpenGLPlatform::ExternalTexture* createExternalImageTexture() noexcept override;
|
||||
|
||||
@@ -25,8 +25,6 @@
|
||||
#include <EGL/eglext.h>
|
||||
#include <EGL/eglplatform.h>
|
||||
|
||||
#include <utils/Invocable.h>
|
||||
|
||||
#include <initializer_list>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
@@ -43,11 +41,15 @@ class PlatformEGL : public OpenGLPlatform {
|
||||
public:
|
||||
|
||||
PlatformEGL() noexcept;
|
||||
bool isExtraContextSupported() const noexcept override;
|
||||
void createContext(bool shared) override;
|
||||
void releaseContext() noexcept override;
|
||||
|
||||
// Return true if we're on an OpenGL platform (as opposed to OpenGL ES). false by default.
|
||||
virtual bool isOpenGL() const noexcept;
|
||||
|
||||
protected:
|
||||
|
||||
// --------------------------------------------------------------------------------------------
|
||||
// Helper for EGL configs and attributes parameters
|
||||
|
||||
@@ -87,30 +89,13 @@ protected:
|
||||
// --------------------------------------------------------------------------------------------
|
||||
// OpenGLPlatform Interface
|
||||
|
||||
bool isExtraContextSupported() const noexcept override;
|
||||
void createContext(bool shared) override;
|
||||
void releaseContext() noexcept override;
|
||||
|
||||
void terminate() noexcept override;
|
||||
|
||||
bool isProtectedContextSupported() const noexcept override;
|
||||
|
||||
bool isSRGBSwapChainSupported() const noexcept override;
|
||||
SwapChain* createSwapChain(void* nativewindow, uint64_t flags) noexcept override;
|
||||
SwapChain* createSwapChain(uint32_t width, uint32_t height, uint64_t flags) noexcept override;
|
||||
void destroySwapChain(SwapChain* swapChain) noexcept override;
|
||||
bool isSwapChainProtected(SwapChain* swapChain) noexcept override;
|
||||
|
||||
ContextType getCurrentContextType() const noexcept override;
|
||||
|
||||
bool makeCurrent(ContextType type,
|
||||
SwapChain* drawSwapChain,
|
||||
SwapChain* readSwapChain) noexcept override;
|
||||
|
||||
void makeCurrent(SwapChain* drawSwapChain, SwapChain* readSwapChain,
|
||||
utils::Invocable<void()> preContextChange,
|
||||
utils::Invocable<void(size_t index)> postContextChange) noexcept override;
|
||||
|
||||
void makeCurrent(SwapChain* drawSwapChain, SwapChain* readSwapChain) noexcept override;
|
||||
void commit(SwapChain* swapChain) noexcept override;
|
||||
|
||||
bool canCreateFence() noexcept override;
|
||||
@@ -137,27 +122,16 @@ protected:
|
||||
static void clearGlError() noexcept;
|
||||
|
||||
/**
|
||||
* Always use this instead of eglMakeCurrent(), as it tracks some state.
|
||||
* Always use this instead of eglMakeCurrent().
|
||||
*/
|
||||
|
||||
EGLContext getContextForType(ContextType type) const noexcept;
|
||||
|
||||
// makes the draw and read surface current without changing the current context
|
||||
EGLBoolean makeCurrent(EGLSurface drawSurface, EGLSurface readSurface) noexcept {
|
||||
return egl.makeCurrent(drawSurface, readSurface);
|
||||
}
|
||||
|
||||
// makes context current and set draw and read surfaces to EGL_NO_SURFACE
|
||||
EGLBoolean makeCurrent(EGLContext context) noexcept {
|
||||
return egl.makeCurrent(context, mEGLDummySurface, mEGLDummySurface);
|
||||
}
|
||||
EGLBoolean makeCurrent(EGLSurface drawSurface, EGLSurface readSurface) noexcept;
|
||||
|
||||
// TODO: this should probably use getters instead.
|
||||
EGLDisplay mEGLDisplay = EGL_NO_DISPLAY;
|
||||
EGLContext mEGLContext = EGL_NO_CONTEXT;
|
||||
EGLContext mEGLContextProtected = EGL_NO_CONTEXT;
|
||||
EGLSurface mCurrentDrawSurface = EGL_NO_SURFACE;
|
||||
EGLSurface mCurrentReadSurface = EGL_NO_SURFACE;
|
||||
EGLSurface mEGLDummySurface = EGL_NO_SURFACE;
|
||||
ContextType mCurrentContextType = ContextType::NONE;
|
||||
// mEGLConfig is valid only if ext.egl.KHR_no_config_context is false
|
||||
EGLConfig mEGLConfig = EGL_NO_CONFIG_KHR;
|
||||
Config mContextAttribs;
|
||||
@@ -174,38 +148,13 @@ protected:
|
||||
bool KHR_gl_colorspace = false;
|
||||
bool KHR_no_config_context = false;
|
||||
bool KHR_surfaceless_context = false;
|
||||
bool EXT_protected_content = false;
|
||||
} egl;
|
||||
} ext;
|
||||
|
||||
struct SwapChainEGL : public Platform::SwapChain {
|
||||
EGLSurface sur = EGL_NO_SURFACE;
|
||||
Config attribs{};
|
||||
EGLNativeWindowType nativeWindow{};
|
||||
EGLConfig config{};
|
||||
uint64_t flags{};
|
||||
};
|
||||
|
||||
void initializeGlExtensions() noexcept;
|
||||
|
||||
protected:
|
||||
EGLConfig findSwapChainConfig(uint64_t flags, bool window, bool pbuffer) const;
|
||||
|
||||
private:
|
||||
class EGL {
|
||||
EGLDisplay& mEGLDisplay;
|
||||
EGLSurface mCurrentDrawSurface = EGL_NO_SURFACE;
|
||||
EGLSurface mCurrentReadSurface = EGL_NO_SURFACE;
|
||||
EGLContext mCurrentContext = EGL_NO_CONTEXT;
|
||||
public:
|
||||
explicit EGL(EGLDisplay& dpy) : mEGLDisplay(dpy) {}
|
||||
EGLBoolean makeCurrent(EGLContext context,
|
||||
EGLSurface drawSurface, EGLSurface readSurface) noexcept;
|
||||
|
||||
EGLBoolean makeCurrent(EGLSurface drawSurface, EGLSurface readSurface) noexcept {
|
||||
return makeCurrent(mCurrentContext, drawSurface, readSurface);
|
||||
}
|
||||
} egl{ mEGLDisplay };
|
||||
};
|
||||
|
||||
} // namespace filament::backend
|
||||
|
||||
@@ -22,10 +22,6 @@
|
||||
#include <backend/platforms/OpenGLPlatform.h>
|
||||
#include <backend/platforms/PlatformEGL.h>
|
||||
|
||||
#include <utils/android/PerformanceHintManager.h>
|
||||
|
||||
#include <chrono>
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
@@ -62,13 +58,6 @@ protected:
|
||||
|
||||
void terminate() noexcept override;
|
||||
|
||||
void beginFrame(
|
||||
int64_t monotonic_clock_ns,
|
||||
int64_t refreshIntervalNs,
|
||||
uint32_t frameId) noexcept override;
|
||||
|
||||
void preCommit() noexcept override;
|
||||
|
||||
/**
|
||||
* Set the presentation time using `eglPresentationTimeANDROID`
|
||||
* @param presentationTimeInNanosecond
|
||||
@@ -90,18 +79,8 @@ protected:
|
||||
AcquiredImage transformAcquiredImage(AcquiredImage source) noexcept override;
|
||||
|
||||
private:
|
||||
struct InitializeJvmForPerformanceManagerIfNeeded {
|
||||
InitializeJvmForPerformanceManagerIfNeeded();
|
||||
};
|
||||
|
||||
int mOSVersion;
|
||||
ExternalStreamManagerAndroid& mExternalStreamManager;
|
||||
InitializeJvmForPerformanceManagerIfNeeded const mInitializeJvmForPerformanceManagerIfNeeded;
|
||||
utils::PerformanceHintManager mPerformanceHintManager;
|
||||
utils::PerformanceHintManager::Session mPerformanceHintSession;
|
||||
|
||||
using clock = std::chrono::high_resolution_clock;
|
||||
clock::time_point mStartTimeOfActualWork;
|
||||
};
|
||||
|
||||
} // namespace filament::backend
|
||||
|
||||
@@ -51,7 +51,7 @@ protected:
|
||||
SwapChain* createSwapChain(void* nativewindow, uint64_t flags) noexcept override;
|
||||
SwapChain* createSwapChain(uint32_t width, uint32_t height, uint64_t flags) noexcept override;
|
||||
void destroySwapChain(SwapChain* swapChain) noexcept override;
|
||||
bool makeCurrent(ContextType type, SwapChain* drawSwapChain, SwapChain* readSwapChain) noexcept override;
|
||||
void makeCurrent(SwapChain* drawSwapChain, SwapChain* readSwapChain) noexcept override;
|
||||
void commit(SwapChain* swapChain) noexcept override;
|
||||
|
||||
private:
|
||||
|
||||
@@ -53,7 +53,7 @@ protected:
|
||||
SwapChain* createSwapChain(void* nativewindow, uint64_t flags) noexcept override;
|
||||
SwapChain* createSwapChain(uint32_t width, uint32_t height, uint64_t flags) noexcept override;
|
||||
void destroySwapChain(SwapChain* swapChain) noexcept override;
|
||||
bool makeCurrent(ContextType type, SwapChain* drawSwapChain, SwapChain* readSwapChain) noexcept override;
|
||||
void makeCurrent(SwapChain* drawSwapChain, SwapChain* readSwapChain) noexcept override;
|
||||
void commit(SwapChain* swapChain) noexcept override;
|
||||
|
||||
protected:
|
||||
|
||||
@@ -46,7 +46,7 @@ protected:
|
||||
SwapChain* createSwapChain(void* nativewindow, uint64_t flags) noexcept override;
|
||||
SwapChain* createSwapChain(uint32_t width, uint32_t height, uint64_t flags) noexcept override;
|
||||
void destroySwapChain(SwapChain* swapChain) noexcept override;
|
||||
bool makeCurrent(ContextType type, SwapChain* drawSwapChain, SwapChain* readSwapChain) noexcept override;
|
||||
void makeCurrent(SwapChain* drawSwapChain, SwapChain* readSwapChain) noexcept override;
|
||||
void commit(SwapChain* swapChain) noexcept override;
|
||||
};
|
||||
|
||||
|
||||
@@ -23,9 +23,9 @@
|
||||
|
||||
#include <utils/CString.h>
|
||||
#include <utils/FixedCapacityVector.h>
|
||||
#include <utils/Hash.h>
|
||||
#include <utils/PrivateImplementation.h>
|
||||
|
||||
#include <string_view>
|
||||
#include <tuple>
|
||||
#include <unordered_set>
|
||||
|
||||
@@ -47,14 +47,6 @@ struct VulkanPlatformPrivate;
|
||||
class VulkanPlatform : public Platform, utils::PrivateImplementation<VulkanPlatformPrivate> {
|
||||
public:
|
||||
|
||||
struct ExtensionHashFn {
|
||||
std::size_t operator()(utils::CString const& s) const noexcept {
|
||||
return std::hash<std::string>{}(s.data());
|
||||
}
|
||||
};
|
||||
// Utility for managing device or instance extensions during initialization.
|
||||
using ExtensionSet = std::unordered_set<utils::CString, ExtensionHashFn>;
|
||||
|
||||
/**
|
||||
* A collection of handles to objects and metadata that comprises a Vulkan context. The client
|
||||
* can instantiate this struct and pass to Engine::Builder::sharedContext if they wishes to
|
||||
@@ -90,20 +82,6 @@ public:
|
||||
VkExtent2D extent = {0, 0};
|
||||
};
|
||||
|
||||
struct ImageSyncData {
|
||||
static constexpr uint32_t INVALID_IMAGE_INDEX = UINT32_MAX;
|
||||
|
||||
// The index of the next image as returned by vkAcquireNextImage or equivalent.
|
||||
uint32_t imageIndex = INVALID_IMAGE_INDEX;
|
||||
|
||||
// Semaphore to be signaled once the image is available.
|
||||
VkSemaphore imageReadySemaphore = VK_NULL_HANDLE;
|
||||
|
||||
// A function called right before vkQueueSubmit. After this call, the image must be
|
||||
// available. This pointer can be null if imageReadySemaphore is not VK_NULL_HANDLE.
|
||||
std::function<void(SwapChainPtr handle)> explicitImageReadyWait = nullptr;
|
||||
};
|
||||
|
||||
VulkanPlatform();
|
||||
|
||||
~VulkanPlatform() override;
|
||||
@@ -141,12 +119,6 @@ public:
|
||||
* before recreating the swapchain. Default is true.
|
||||
*/
|
||||
bool flushAndWaitOnWindowResize = true;
|
||||
|
||||
/**
|
||||
* Whether the swapchain image should be transitioned to a layout suitable for
|
||||
* presentation. Default is true.
|
||||
*/
|
||||
bool transitionSwapChainImageLayoutForPresent = true;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -175,10 +147,13 @@ public:
|
||||
* corresponding VkImage will be used as the output color attachment. The client should signal
|
||||
* the `clientSignal` semaphore when the image is ready to be used by the backend.
|
||||
* @param handle The handle returned by createSwapChain()
|
||||
* @param outImageSyncData The synchronization data used for image readiness
|
||||
* @param clientSignal The semaphore that the client will signal to indicate that the backend
|
||||
* may render into the image.
|
||||
* @param index Pointer to memory that will be filled with the index that corresponding
|
||||
* to an image in the `SwapChainBundle.colors` array.
|
||||
* @return Result of acquire
|
||||
*/
|
||||
virtual VkResult acquire(SwapChainPtr handle, ImageSyncData* outImageSyncData);
|
||||
virtual VkResult acquire(SwapChainPtr handle, VkSemaphore clientSignal, uint32_t* index);
|
||||
|
||||
/**
|
||||
* Present the image corresponding to `index` to the display. The client should wait on
|
||||
@@ -217,13 +192,6 @@ public:
|
||||
virtual SwapChainPtr createSwapChain(void* nativeWindow, uint64_t flags = 0,
|
||||
VkExtent2D extent = {0, 0});
|
||||
|
||||
/**
|
||||
* Allows implementers to provide instance extensions that they'd like to include in the
|
||||
* instance creation.
|
||||
* @return A set of extensions to enable for the instance.
|
||||
*/
|
||||
virtual ExtensionSet getRequiredInstanceExtensions() { return {}; }
|
||||
|
||||
/**
|
||||
* Destroy the swapchain.
|
||||
* @param handle The handle returned by createSwapChain()
|
||||
@@ -268,9 +236,10 @@ public:
|
||||
VkQueue getGraphicsQueue() const noexcept;
|
||||
|
||||
private:
|
||||
static ExtensionSet getSwapchainInstanceExtensions();
|
||||
|
||||
// Platform dependent helper methods
|
||||
using ExtensionSet = std::unordered_set<std::string_view>;
|
||||
static ExtensionSet getRequiredInstanceExtensions();
|
||||
|
||||
using SurfaceBundle = std::tuple<VkSurfaceKHR, VkExtent2D>;
|
||||
static SurfaceBundle createVkSurfaceKHR(void* nativeWindow, VkInstance instance,
|
||||
uint64_t flags) noexcept;
|
||||
|
||||
@@ -50,13 +50,12 @@ class CommandBufferQueue {
|
||||
size_t mFreeSpace = 0;
|
||||
size_t mHighWatermark = 0;
|
||||
uint32_t mExitRequested = 0;
|
||||
bool mPaused = false;
|
||||
|
||||
static constexpr uint32_t EXIT_REQUESTED = 0x31415926;
|
||||
|
||||
public:
|
||||
// requiredSize: guaranteed available space after flush()
|
||||
CommandBufferQueue(size_t requiredSize, size_t bufferSize, bool paused);
|
||||
CommandBufferQueue(size_t requiredSize, size_t bufferSize);
|
||||
~CommandBufferQueue();
|
||||
|
||||
CircularBuffer& getCircularBuffer() noexcept { return mCircularBuffer; }
|
||||
@@ -81,10 +80,6 @@ public:
|
||||
// returns from waitForCommands() immediately.
|
||||
void requestExit();
|
||||
|
||||
// suspend or unsuspend the queue.
|
||||
bool isPaused() const noexcept;
|
||||
void setPaused(bool paused);
|
||||
|
||||
bool isExitRequested() const;
|
||||
};
|
||||
|
||||
|
||||
@@ -134,7 +134,7 @@ struct CommandType<void (Driver::*)(ARGS...)> {
|
||||
|
||||
public:
|
||||
template<typename M, typename D>
|
||||
static inline void execute(M&& method, D&& driver, CommandBase* base, intptr_t* next) {
|
||||
static inline void execute(M&& method, D&& driver, CommandBase* base, intptr_t* next) noexcept {
|
||||
Command* self = static_cast<Command*>(base);
|
||||
*next = align(sizeof(Command));
|
||||
#if DEBUG_COMMAND_STREAM
|
||||
@@ -168,7 +168,7 @@ struct CommandType<void (Driver::*)(ARGS...)> {
|
||||
|
||||
class CustomCommand : public CommandBase {
|
||||
std::function<void()> mCommand;
|
||||
static void execute(Driver&, CommandBase* base, intptr_t* next);
|
||||
static void execute(Driver&, CommandBase* base, intptr_t* next) noexcept;
|
||||
public:
|
||||
inline CustomCommand(CustomCommand&& rhs) = default;
|
||||
inline explicit CustomCommand(std::function<void()> cmd)
|
||||
|
||||
@@ -76,7 +76,7 @@ public:
|
||||
// the fn function will execute a batch of driver commands
|
||||
// this gives the driver a chance to wrap their execution in a meaningful manner
|
||||
// the default implementation simply calls fn
|
||||
virtual void execute(std::function<void(void)> const& fn);
|
||||
virtual void execute(std::function<void(void)> const& fn) noexcept;
|
||||
|
||||
// This is called on debug build, or when enabled manually on the backend thread side.
|
||||
virtual void debugCommandBegin(CommandStream* cmds,
|
||||
|
||||
@@ -133,18 +133,18 @@ DECL_DRIVER_API_0(tick)
|
||||
|
||||
DECL_DRIVER_API_N(beginFrame,
|
||||
int64_t, monotonic_clock_ns,
|
||||
int64_t, refreshIntervalNs,
|
||||
uint32_t, frameId)
|
||||
|
||||
DECL_DRIVER_API_N(setFrameScheduledCallback,
|
||||
backend::SwapChainHandle, sch,
|
||||
backend::CallbackHandler*, handler,
|
||||
backend::FrameScheduledCallback&&, callback)
|
||||
backend::FrameScheduledCallback, callback,
|
||||
void*, user)
|
||||
|
||||
DECL_DRIVER_API_N(setFrameCompletedCallback,
|
||||
backend::SwapChainHandle, sch,
|
||||
backend::CallbackHandler*, handler,
|
||||
utils::Invocable<void(void)>&&, callback)
|
||||
backend::CallbackHandler::Callback, callback,
|
||||
void*, user)
|
||||
|
||||
DECL_DRIVER_API_N(setPresentationTime,
|
||||
int64_t, monotonic_clock_ns)
|
||||
@@ -162,23 +162,16 @@ DECL_DRIVER_API_0(finish)
|
||||
// reset state tracking, if the driver does any state tracking (e.g. GL)
|
||||
DECL_DRIVER_API_0(resetState)
|
||||
|
||||
DECL_DRIVER_API_N(setDebugTag,
|
||||
backend::HandleBase::HandleId, handleId,
|
||||
utils::CString, tag)
|
||||
|
||||
/*
|
||||
* Creating driver objects
|
||||
* -----------------------
|
||||
*/
|
||||
|
||||
DECL_DRIVER_API_R_N(backend::VertexBufferInfoHandle, createVertexBufferInfo,
|
||||
DECL_DRIVER_API_R_N(backend::VertexBufferHandle, createVertexBuffer,
|
||||
uint8_t, bufferCount,
|
||||
uint8_t, attributeCount,
|
||||
backend::AttributeArray, attributes)
|
||||
|
||||
DECL_DRIVER_API_R_N(backend::VertexBufferHandle, createVertexBuffer,
|
||||
uint32_t, vertexCount,
|
||||
backend::VertexBufferInfoHandle, vbih)
|
||||
backend::AttributeArray, attributes)
|
||||
|
||||
DECL_DRIVER_API_R_N(backend::IndexBufferHandle, createIndexBuffer,
|
||||
backend::ElementType, elementType,
|
||||
@@ -231,7 +224,11 @@ DECL_DRIVER_API_R_N(backend::SamplerGroupHandle, createSamplerGroup,
|
||||
DECL_DRIVER_API_R_N(backend::RenderPrimitiveHandle, createRenderPrimitive,
|
||||
backend::VertexBufferHandle, vbh,
|
||||
backend::IndexBufferHandle, ibh,
|
||||
backend::PrimitiveType, pt)
|
||||
backend::PrimitiveType, pt,
|
||||
uint32_t, offset,
|
||||
uint32_t, minIndex,
|
||||
uint32_t, maxIndex,
|
||||
uint32_t, count)
|
||||
|
||||
DECL_DRIVER_API_R_N(backend::ProgramHandle, createProgram,
|
||||
backend::Program&&, program)
|
||||
@@ -243,7 +240,6 @@ DECL_DRIVER_API_R_N(backend::RenderTargetHandle, createRenderTarget,
|
||||
uint32_t, width,
|
||||
uint32_t, height,
|
||||
uint8_t, samples,
|
||||
uint8_t, layerCount,
|
||||
backend::MRT, color,
|
||||
backend::TargetBufferInfo, depth,
|
||||
backend::TargetBufferInfo, stencil)
|
||||
@@ -268,7 +264,6 @@ DECL_DRIVER_API_R_0(backend::TimerQueryHandle, createTimerQuery)
|
||||
*/
|
||||
|
||||
DECL_DRIVER_API_N(destroyVertexBuffer, backend::VertexBufferHandle, vbh)
|
||||
DECL_DRIVER_API_N(destroyVertexBufferInfo,backend::VertexBufferInfoHandle, vbih)
|
||||
DECL_DRIVER_API_N(destroyIndexBuffer, backend::IndexBufferHandle, ibh)
|
||||
DECL_DRIVER_API_N(destroyBufferObject, backend::BufferObjectHandle, ibh)
|
||||
DECL_DRIVER_API_N(destroyRenderPrimitive, backend::RenderPrimitiveHandle, rph)
|
||||
@@ -303,17 +298,14 @@ DECL_DRIVER_API_SYNCHRONOUS_0(bool, isFrameBufferFetchMultiSampleSupported)
|
||||
DECL_DRIVER_API_SYNCHRONOUS_0(bool, isFrameTimeSupported)
|
||||
DECL_DRIVER_API_SYNCHRONOUS_0(bool, isAutoDepthResolveSupported)
|
||||
DECL_DRIVER_API_SYNCHRONOUS_0(bool, isSRGBSwapChainSupported)
|
||||
DECL_DRIVER_API_SYNCHRONOUS_0(bool, isProtectedContentSupported)
|
||||
DECL_DRIVER_API_SYNCHRONOUS_0(bool, isStereoSupported)
|
||||
DECL_DRIVER_API_SYNCHRONOUS_0(bool, isParallelShaderCompileSupported)
|
||||
DECL_DRIVER_API_SYNCHRONOUS_0(bool, isDepthStencilResolveSupported)
|
||||
DECL_DRIVER_API_SYNCHRONOUS_N(bool, isDepthStencilBlitSupported, backend::TextureFormat, format)
|
||||
DECL_DRIVER_API_SYNCHRONOUS_0(bool, isProtectedTexturesSupported)
|
||||
DECL_DRIVER_API_SYNCHRONOUS_0(uint8_t, getMaxDrawBuffers)
|
||||
DECL_DRIVER_API_SYNCHRONOUS_0(size_t, getMaxUniformBufferSize)
|
||||
DECL_DRIVER_API_SYNCHRONOUS_0(math::float2, getClipSpaceParams)
|
||||
DECL_DRIVER_API_SYNCHRONOUS_N(void, setupExternalImage, void*, image)
|
||||
DECL_DRIVER_API_SYNCHRONOUS_N(backend::TimerQueryResult, getTimerQueryValue, backend::TimerQueryHandle, query, uint64_t*, elapsedTime)
|
||||
DECL_DRIVER_API_SYNCHRONOUS_N(bool, getTimerQueryValue, backend::TimerQueryHandle, query, uint64_t*, elapsedTime)
|
||||
DECL_DRIVER_API_SYNCHRONOUS_N(bool, isWorkaroundNeeded, backend::Workaround, workaround)
|
||||
DECL_DRIVER_API_SYNCHRONOUS_0(backend::FeatureLevel, getFeatureLevel)
|
||||
|
||||
@@ -437,11 +429,6 @@ DECL_DRIVER_API_N(bindSamplers,
|
||||
uint32_t, index,
|
||||
backend::SamplerGroupHandle, sbh)
|
||||
|
||||
DECL_DRIVER_API_N(setPushConstant,
|
||||
backend::ShaderStage, stage,
|
||||
uint8_t, index,
|
||||
backend::PushConstantVariant, value)
|
||||
|
||||
DECL_DRIVER_API_N(insertEventMarker,
|
||||
const char*, string,
|
||||
uint32_t, len = 0)
|
||||
@@ -504,32 +491,15 @@ DECL_DRIVER_API_N(blit,
|
||||
math::uint2, srcOrigin,
|
||||
math::uint2, size)
|
||||
|
||||
DECL_DRIVER_API_N(bindPipeline,
|
||||
backend::PipelineState const&, state)
|
||||
|
||||
DECL_DRIVER_API_N(bindRenderPrimitive,
|
||||
backend::RenderPrimitiveHandle, rph)
|
||||
|
||||
DECL_DRIVER_API_N(draw2,
|
||||
uint32_t, indexOffset,
|
||||
uint32_t, indexCount,
|
||||
uint32_t, instanceCount)
|
||||
|
||||
DECL_DRIVER_API_N(draw,
|
||||
backend::PipelineState, state,
|
||||
backend::RenderPrimitiveHandle, rph,
|
||||
uint32_t, indexOffset,
|
||||
uint32_t, indexCount,
|
||||
uint32_t, instanceCount)
|
||||
|
||||
|
||||
DECL_DRIVER_API_N(dispatchCompute,
|
||||
backend::ProgramHandle, program,
|
||||
math::uint3, workGroupCount)
|
||||
|
||||
DECL_DRIVER_API_N(scissor,
|
||||
Viewport, scissor)
|
||||
|
||||
|
||||
#pragma clang diagnostic pop
|
||||
|
||||
|
||||
@@ -20,12 +20,11 @@
|
||||
#include <backend/Handle.h>
|
||||
|
||||
#include <utils/Allocator.h>
|
||||
#include <utils/CString.h>
|
||||
#include <utils/Log.h>
|
||||
#include <utils/Panic.h>
|
||||
#include <utils/compiler.h>
|
||||
#include <utils/debug.h>
|
||||
#include <utils/ostream.h>
|
||||
#include <utils/Panic.h>
|
||||
|
||||
#include <tsl/robin_map.h>
|
||||
|
||||
@@ -38,9 +37,9 @@
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#define HandleAllocatorGL HandleAllocator<32, 64, 136> // ~4520 / pool / MiB
|
||||
#define HandleAllocatorVK HandleAllocator<64, 160, 312> // ~1820 / pool / MiB
|
||||
#define HandleAllocatorMTL HandleAllocator<32, 64, 552> // ~1660 / pool / MiB
|
||||
#define HandleAllocatorGL HandleAllocator<16, 64, 208> // ~3640 / pool / MiB
|
||||
#define HandleAllocatorVK HandleAllocator<80, 176, 320> // ~1820 / pool / MiB
|
||||
#define HandleAllocatorMTL HandleAllocator<48, 160, 592> // ~1310 / pool / MiB
|
||||
|
||||
namespace filament::backend {
|
||||
|
||||
@@ -50,7 +49,7 @@ namespace filament::backend {
|
||||
template<size_t P0, size_t P1, size_t P2>
|
||||
class HandleAllocator {
|
||||
public:
|
||||
HandleAllocator(const char* name, size_t size, bool disableUseAfterFreeCheck) noexcept;
|
||||
HandleAllocator(const char* name, size_t size) noexcept;
|
||||
HandleAllocator(HandleAllocator const& rhs) = delete;
|
||||
HandleAllocator& operator=(HandleAllocator const& rhs) = delete;
|
||||
~HandleAllocator();
|
||||
@@ -66,7 +65,7 @@ public:
|
||||
*
|
||||
*/
|
||||
template<typename D, typename ... ARGS>
|
||||
Handle<D> allocateAndConstruct(ARGS&& ... args) {
|
||||
Handle<D> allocateAndConstruct(ARGS&& ... args) noexcept {
|
||||
Handle<D> h{ allocateHandle<D>() };
|
||||
D* addr = handle_cast<D*>(h);
|
||||
new(addr) D(std::forward<ARGS>(args)...);
|
||||
@@ -98,7 +97,7 @@ public:
|
||||
*/
|
||||
template<typename D, typename B, typename ... ARGS>
|
||||
typename std::enable_if_t<std::is_base_of_v<B, D>, D>*
|
||||
destroyAndConstruct(Handle<B> const& handle, ARGS&& ... args) {
|
||||
destroyAndConstruct(Handle<B> const& handle, ARGS&& ... args) noexcept {
|
||||
assert_invariant(handle);
|
||||
D* addr = handle_cast<D*>(const_cast<Handle<B>&>(handle));
|
||||
assert_invariant(addr);
|
||||
@@ -164,73 +163,30 @@ public:
|
||||
inline typename std::enable_if_t<
|
||||
std::is_pointer_v<Dp> &&
|
||||
std::is_base_of_v<B, typename std::remove_pointer_t<Dp>>, Dp>
|
||||
handle_cast(Handle<B>& handle) {
|
||||
handle_cast(Handle<B>& handle) noexcept {
|
||||
assert_invariant(handle);
|
||||
auto [p, tag] = handleToPointer(handle.getId());
|
||||
|
||||
if (isPoolHandle(handle.getId())) {
|
||||
// check for use after free
|
||||
if (UTILS_UNLIKELY(!mUseAfterFreeCheckDisabled)) {
|
||||
uint8_t const age = (tag & HANDLE_AGE_MASK) >> HANDLE_AGE_SHIFT;
|
||||
auto const pNode = static_cast<typename Allocator::Node*>(p);
|
||||
uint8_t const expectedAge = pNode[-1].age;
|
||||
// getHandleTag() is only called if the check fails.
|
||||
FILAMENT_CHECK_POSTCONDITION(expectedAge == age)
|
||||
<< "use-after-free of Handle with id=" << handle.getId()
|
||||
<< ", tag=" << getHandleTag(handle.getId()).c_str_safe();
|
||||
}
|
||||
}
|
||||
|
||||
return static_cast<Dp>(p);
|
||||
}
|
||||
|
||||
template<typename B>
|
||||
bool is_valid(Handle<B>& handle) {
|
||||
if (handle && isPoolHandle(handle.getId())) {
|
||||
auto [p, tag] = handleToPointer(handle.getId());
|
||||
uint8_t const age = (tag & HANDLE_AGE_MASK) >> HANDLE_AGE_SHIFT;
|
||||
auto const pNode = static_cast<typename Allocator::Node*>(p);
|
||||
uint8_t const expectedAge = pNode[-1].age;
|
||||
return expectedAge == age;
|
||||
ASSERT_POSTCONDITION(expectedAge == age,
|
||||
"use-after-free of Handle with id=%d", handle.getId());
|
||||
}
|
||||
return true;
|
||||
|
||||
return static_cast<Dp>(p);
|
||||
}
|
||||
|
||||
template<typename Dp, typename B>
|
||||
inline typename std::enable_if_t<
|
||||
std::is_pointer_v<Dp> &&
|
||||
std::is_base_of_v<B, typename std::remove_pointer_t<Dp>>, Dp>
|
||||
handle_cast(Handle<B> const& handle) {
|
||||
handle_cast(Handle<B> const& handle) noexcept {
|
||||
return handle_cast<Dp>(const_cast<Handle<B>&>(handle));
|
||||
}
|
||||
|
||||
void associateTagToHandle(HandleBase::HandleId id, utils::CString&& tag) noexcept {
|
||||
// TODO: for now, only pool handles check for use-after-free, so we only keep tags for
|
||||
// those
|
||||
if (isPoolHandle(id)) {
|
||||
// Truncate the tag's age to N bits.
|
||||
constexpr uint8_t N = 2; // support a history of 4 tags
|
||||
constexpr uint8_t mask = (1 << N) - 1;
|
||||
|
||||
uint8_t const age = (id & HANDLE_AGE_MASK) >> HANDLE_AGE_SHIFT;
|
||||
uint8_t const newAge = age & mask;
|
||||
uint32_t const key = (id & ~HANDLE_AGE_MASK) | (newAge << HANDLE_AGE_SHIFT);
|
||||
|
||||
// This line is the costly part. In the future, we could potentially use a custom
|
||||
// allocator.
|
||||
mDebugTags[key] = std::move(tag);
|
||||
}
|
||||
}
|
||||
|
||||
utils::CString getHandleTag(HandleBase::HandleId id) const noexcept {
|
||||
if (!isPoolHandle(id)) {
|
||||
return "(no tag)";
|
||||
}
|
||||
if (auto pos = mDebugTags.find(id); pos != mDebugTags.end()) {
|
||||
return pos->second;
|
||||
}
|
||||
return "(no tag)";
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
@@ -254,9 +210,8 @@ private:
|
||||
Pool<P1> mPool1;
|
||||
Pool<P2> mPool2;
|
||||
UTILS_UNUSED_IN_RELEASE const utils::AreaPolicy::HeapArea& mArea;
|
||||
bool mUseAfterFreeCheckDisabled;
|
||||
public:
|
||||
explicit Allocator(const utils::AreaPolicy::HeapArea& area, bool disableUseAfterFreeCheck);
|
||||
explicit Allocator(const utils::AreaPolicy::HeapArea& area);
|
||||
|
||||
static constexpr size_t getAlignment() noexcept { return MIN_ALIGNMENT; }
|
||||
|
||||
@@ -282,10 +237,8 @@ private:
|
||||
// check for double-free
|
||||
Node* const pNode = static_cast<Node*>(p);
|
||||
uint8_t& expectedAge = pNode[-1].age;
|
||||
if (UTILS_UNLIKELY(!mUseAfterFreeCheckDisabled)) {
|
||||
FILAMENT_CHECK_POSTCONDITION(expectedAge == age) <<
|
||||
"double-free of Handle of size " << size << " at " << p;
|
||||
}
|
||||
ASSERT_POSTCONDITION(expectedAge == age,
|
||||
"double-free of Handle of size %d at %p", size, p);
|
||||
expectedAge = (expectedAge + 1) & 0xF; // fixme
|
||||
|
||||
if (size <= mPool0.getSize()) { mPool0.free(p); return; }
|
||||
@@ -360,7 +313,7 @@ private:
|
||||
return (id & HANDLE_HEAP_FLAG) == 0u;
|
||||
}
|
||||
|
||||
HandleBase::HandleId allocateHandleSlow(size_t size);
|
||||
HandleBase::HandleId allocateHandleSlow(size_t size) noexcept;
|
||||
void deallocateHandleSlow(HandleBase::HandleId id, size_t size) noexcept;
|
||||
|
||||
// We inline this because it's just 4 instructions in the fast case
|
||||
@@ -394,9 +347,7 @@ private:
|
||||
// Below is only used when running out of space in the HandleArena
|
||||
mutable utils::Mutex mLock;
|
||||
tsl::robin_map<HandleBase::HandleId, void*> mOverflowMap;
|
||||
tsl::robin_map<HandleBase::HandleId, utils::CString> mDebugTags;
|
||||
HandleBase::HandleId mId = 0;
|
||||
bool mUseAfterFreeCheckDisabled = false;
|
||||
};
|
||||
|
||||
} // namespace filament::backend
|
||||
|
||||
@@ -27,8 +27,8 @@ PresentCallable::PresentCallable(PresentFn fn, void* user) noexcept
|
||||
}
|
||||
|
||||
void PresentCallable::operator()(bool presentFrame) noexcept {
|
||||
FILAMENT_CHECK_PRECONDITION(mPresentFn) << "This PresentCallable was already called. "
|
||||
"PresentCallables should be called exactly once.";
|
||||
ASSERT_PRECONDITION(mPresentFn, "This PresentCallable was already called. " \
|
||||
"PresentCallables should be called exactly once.");
|
||||
mPresentFn(presentFrame, mUser);
|
||||
// Set mPresentFn to nullptr to denote that the callable has been called.
|
||||
mPresentFn = nullptr;
|
||||
|
||||
@@ -32,11 +32,10 @@
|
||||
# define HAS_MMAP 0
|
||||
#endif
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
using namespace utils;
|
||||
|
||||
@@ -82,9 +81,6 @@ void* CircularBuffer::alloc(size_t size) noexcept {
|
||||
// map the circular buffer once...
|
||||
vaddr = mmap(reserve_vaddr, size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
|
||||
if (vaddr != MAP_FAILED) {
|
||||
// populate the address space with pages (because this is a circular buffer,
|
||||
// all the pages will be allocated eventually, might as well do it now)
|
||||
memset(vaddr, 0, size);
|
||||
// and map the circular buffer again, behind the previous copy...
|
||||
vaddr_shadow = mmap((char*)vaddr + size, size,
|
||||
PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
|
||||
@@ -105,7 +101,7 @@ void* CircularBuffer::alloc(size_t size) noexcept {
|
||||
if (UTILS_UNLIKELY(mAshmemFd < 0)) {
|
||||
// ashmem failed
|
||||
if (vaddr_guard != MAP_FAILED) {
|
||||
munmap(vaddr_guard, BLOCK_SIZE);
|
||||
munmap(vaddr_guard, size);
|
||||
}
|
||||
|
||||
if (vaddr_shadow != MAP_FAILED) {
|
||||
@@ -123,11 +119,12 @@ void* CircularBuffer::alloc(size_t size) noexcept {
|
||||
data = mmap(nullptr, size * 2 + BLOCK_SIZE,
|
||||
PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
||||
|
||||
FILAMENT_CHECK_POSTCONDITION(data != MAP_FAILED) <<
|
||||
"couldn't allocate " << (size * 2 / 1024) <<
|
||||
" KiB of virtual address space for the command buffer";
|
||||
ASSERT_POSTCONDITION(data,
|
||||
"couldn't allocate %u KiB of virtual address space for the command buffer",
|
||||
(size * 2 / 1024));
|
||||
|
||||
slog.w << "Using 'soft' CircularBuffer (" << (size * 2 / 1024) << " KiB)" << io::endl;
|
||||
slog.d << "WARNING: Using soft CircularBuffer (" << (size * 2 / 1024) << " KiB)"
|
||||
<< io::endl;
|
||||
|
||||
// guard page at the end
|
||||
void* guard = (void*)(uintptr_t(data) + size * 2);
|
||||
|
||||
@@ -39,11 +39,10 @@ using namespace utils;
|
||||
|
||||
namespace filament::backend {
|
||||
|
||||
CommandBufferQueue::CommandBufferQueue(size_t requiredSize, size_t bufferSize, bool paused)
|
||||
CommandBufferQueue::CommandBufferQueue(size_t requiredSize, size_t bufferSize)
|
||||
: mRequiredSize((requiredSize + (CircularBuffer::getBlockSize() - 1u)) & ~(CircularBuffer::getBlockSize() -1u)),
|
||||
mCircularBuffer(bufferSize),
|
||||
mFreeSpace(mCircularBuffer.size()),
|
||||
mPaused(paused) {
|
||||
mFreeSpace(mCircularBuffer.size()) {
|
||||
assert_invariant(mCircularBuffer.size() > requiredSize);
|
||||
}
|
||||
|
||||
@@ -57,23 +56,10 @@ void CommandBufferQueue::requestExit() {
|
||||
mCondition.notify_one();
|
||||
}
|
||||
|
||||
bool CommandBufferQueue::isPaused() const noexcept {
|
||||
std::lock_guard<utils::Mutex> const lock(mLock);
|
||||
return mPaused;
|
||||
}
|
||||
|
||||
void CommandBufferQueue::setPaused(bool paused) {
|
||||
std::lock_guard<utils::Mutex> const lock(mLock);
|
||||
if (paused) {
|
||||
mPaused = true;
|
||||
} else {
|
||||
mPaused = false;
|
||||
mCondition.notify_one();
|
||||
}
|
||||
}
|
||||
|
||||
bool CommandBufferQueue::isExitRequested() const {
|
||||
std::lock_guard<utils::Mutex> const lock(mLock);
|
||||
ASSERT_PRECONDITION( mExitRequested == 0 || mExitRequested == EXIT_REQUESTED,
|
||||
"mExitRequested is corrupted (value = 0x%08x)!", mExitRequested);
|
||||
return (bool)mExitRequested;
|
||||
}
|
||||
|
||||
@@ -101,23 +87,22 @@ void CommandBufferQueue::flush() noexcept {
|
||||
size_t const used = std::distance(
|
||||
static_cast<char const*>(begin), static_cast<char const*>(end));
|
||||
|
||||
|
||||
std::unique_lock<utils::Mutex> lock(mLock);
|
||||
|
||||
// circular buffer is too small, we corrupted the stream
|
||||
FILAMENT_CHECK_POSTCONDITION(used <= mFreeSpace) <<
|
||||
"Backend CommandStream overflow. Commands are corrupted and unrecoverable.\n"
|
||||
"Please increase minCommandBufferSizeMB inside the Config passed to Engine::create.\n"
|
||||
"Space used at this time: " << used <<
|
||||
" bytes, overflow: " << used - mFreeSpace << " bytes";
|
||||
|
||||
mFreeSpace -= used;
|
||||
mCommandBuffersToExecute.push_back({ begin, end });
|
||||
mCondition.notify_one();
|
||||
|
||||
// circular buffer is too small, we corrupted the stream
|
||||
ASSERT_POSTCONDITION(used <= mFreeSpace,
|
||||
"Backend CommandStream overflow. Commands are corrupted and unrecoverable.\n"
|
||||
"Please increase minCommandBufferSizeMB inside the Config passed to Engine::create.\n"
|
||||
"Space used at this time: %u bytes, overflow: %u bytes",
|
||||
(unsigned)used, unsigned(used - mFreeSpace));
|
||||
|
||||
// wait until there is enough space in the buffer
|
||||
mFreeSpace -= used;
|
||||
if (UTILS_UNLIKELY(mFreeSpace < requiredSize)) {
|
||||
|
||||
|
||||
#ifndef NDEBUG
|
||||
size_t const totalUsed = circularBuffer.size() - mFreeSpace;
|
||||
slog.d << "CommandStream used too much space (will block): "
|
||||
@@ -130,11 +115,6 @@ void CommandBufferQueue::flush() noexcept {
|
||||
#endif
|
||||
|
||||
SYSTRACE_NAME("waiting: CircularBuffer::flush()");
|
||||
|
||||
FILAMENT_CHECK_POSTCONDITION(!mPaused) <<
|
||||
"CommandStream is full, but since the rendering thread is paused, "
|
||||
"the buffer cannot flush and we will deadlock. Instead, abort.";
|
||||
|
||||
mCondition.wait(lock, [this, requiredSize]() -> bool {
|
||||
// TODO: on macOS, we need to call pumpEvents from time to time
|
||||
return mFreeSpace >= requiredSize;
|
||||
@@ -147,17 +127,19 @@ std::vector<CommandBufferQueue::Range> CommandBufferQueue::waitForCommands() con
|
||||
return std::move(mCommandBuffersToExecute);
|
||||
}
|
||||
std::unique_lock<utils::Mutex> lock(mLock);
|
||||
while ((mCommandBuffersToExecute.empty() || mPaused) && !mExitRequested) {
|
||||
while (mCommandBuffersToExecute.empty() && !mExitRequested) {
|
||||
mCondition.wait(lock);
|
||||
}
|
||||
|
||||
ASSERT_PRECONDITION( mExitRequested == 0 || mExitRequested == EXIT_REQUESTED,
|
||||
"mExitRequested is corrupted (value = 0x%08x)!", mExitRequested);
|
||||
|
||||
return std::move(mCommandBuffersToExecute);
|
||||
}
|
||||
|
||||
void CommandBufferQueue::releaseBuffer(CommandBufferQueue::Range const& buffer) {
|
||||
size_t const used = std::distance(
|
||||
static_cast<char const*>(buffer.begin), static_cast<char const*>(buffer.end));
|
||||
std::lock_guard<utils::Mutex> const lock(mLock);
|
||||
mFreeSpace += used;
|
||||
mFreeSpace += uintptr_t(buffer.end) - uintptr_t(buffer.begin);
|
||||
mCondition.notify_one();
|
||||
}
|
||||
|
||||
|
||||
@@ -149,7 +149,7 @@ void CommandType<void (Driver::*)(ARGS...)>::Command<METHOD>::log() noexcept {
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
|
||||
void CustomCommand::execute(Driver&, CommandBase* base, intptr_t* next) {
|
||||
void CustomCommand::execute(Driver&, CommandBase* base, intptr_t* next) noexcept {
|
||||
*next = CustomCommand::align(sizeof(CustomCommand));
|
||||
static_cast<CustomCommand*>(base)->mCommand();
|
||||
static_cast<CustomCommand*>(base)->~CustomCommand();
|
||||
|
||||
@@ -214,7 +214,7 @@ size_t Driver::getElementTypeSize(ElementType type) noexcept {
|
||||
|
||||
Driver::~Driver() noexcept = default;
|
||||
|
||||
void Driver::execute(std::function<void(void)> const& fn) {
|
||||
void Driver::execute(std::function<void(void)> const& fn) noexcept {
|
||||
fn();
|
||||
}
|
||||
|
||||
|
||||
@@ -49,25 +49,21 @@ struct AcquiredImage;
|
||||
struct HwBase {
|
||||
};
|
||||
|
||||
|
||||
struct HwVertexBufferInfo : public HwBase {
|
||||
struct HwVertexBuffer : public HwBase {
|
||||
AttributeArray attributes{}; // 8 * MAX_VERTEX_ATTRIBUTE_COUNT
|
||||
uint32_t vertexCount{}; // 4
|
||||
uint8_t bufferCount{}; // 1
|
||||
uint8_t attributeCount{}; // 1
|
||||
bool padding[2]{}; // 2
|
||||
HwVertexBufferInfo() noexcept = default;
|
||||
HwVertexBufferInfo(uint8_t bufferCount, uint8_t attributeCount) noexcept
|
||||
: bufferCount(bufferCount),
|
||||
attributeCount(attributeCount) {
|
||||
}
|
||||
};
|
||||
bool padding{}; // 1
|
||||
uint8_t bufferObjectsVersion{}; // 1 -> total struct is 136 bytes
|
||||
|
||||
struct HwVertexBuffer : public HwBase {
|
||||
uint32_t vertexCount{}; // 4
|
||||
uint8_t bufferObjectsVersion{0xff}; // 1
|
||||
bool padding[3]{}; // 2
|
||||
HwVertexBuffer() noexcept = default;
|
||||
explicit HwVertexBuffer(uint32_t vertextCount) noexcept
|
||||
: vertexCount(vertextCount) {
|
||||
HwVertexBuffer(uint8_t bufferCount, uint8_t attributeCount, uint32_t elementCount,
|
||||
AttributeArray const& attributes) noexcept
|
||||
: attributes(attributes),
|
||||
vertexCount(elementCount),
|
||||
bufferCount(bufferCount),
|
||||
attributeCount(attributeCount) {
|
||||
}
|
||||
};
|
||||
|
||||
@@ -92,6 +88,11 @@ struct HwIndexBuffer : public HwBase {
|
||||
};
|
||||
|
||||
struct HwRenderPrimitive : public HwBase {
|
||||
uint32_t offset{};
|
||||
uint32_t minIndex{};
|
||||
uint32_t maxIndex{};
|
||||
uint32_t count{};
|
||||
uint32_t maxVertexCount{};
|
||||
PrimitiveType type = PrimitiveType::TRIANGLES;
|
||||
};
|
||||
|
||||
@@ -113,9 +114,7 @@ struct HwTexture : public HwBase {
|
||||
uint8_t levels : 4; // This allows up to 15 levels (max texture size of 32768 x 32768)
|
||||
uint8_t samples : 4; // Sample count per pixel (should always be a power of 2)
|
||||
TextureFormat format{};
|
||||
uint8_t reserved0 = 0;
|
||||
TextureUsage usage{};
|
||||
uint16_t reserved1 = 0;
|
||||
HwStream* hwStream = nullptr;
|
||||
|
||||
HwTexture() noexcept : levels{}, samples{} {}
|
||||
|
||||
@@ -39,10 +39,8 @@ using namespace utils;
|
||||
|
||||
template <size_t P0, size_t P1, size_t P2>
|
||||
UTILS_NOINLINE
|
||||
HandleAllocator<P0, P1, P2>::Allocator::Allocator(AreaPolicy::HeapArea const& area,
|
||||
bool disableUseAfterFreeCheck)
|
||||
: mArea(area),
|
||||
mUseAfterFreeCheckDisabled(disableUseAfterFreeCheck) {
|
||||
HandleAllocator<P0, P1, P2>::Allocator::Allocator(AreaPolicy::HeapArea const& area)
|
||||
: mArea(area) {
|
||||
|
||||
// The largest handle this allocator can generate currently depends on the architecture's
|
||||
// min alignment, typically 8 or 16 bytes.
|
||||
@@ -76,13 +74,8 @@ HandleAllocator<P0, P1, P2>::Allocator::Allocator(AreaPolicy::HeapArea const& ar
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
|
||||
template <size_t P0, size_t P1, size_t P2>
|
||||
HandleAllocator<P0, P1, P2>::HandleAllocator(const char* name, size_t size,
|
||||
bool disableUseAfterFreeCheck) noexcept
|
||||
: mHandleArena(name, size, disableUseAfterFreeCheck),
|
||||
mUseAfterFreeCheckDisabled(disableUseAfterFreeCheck) {
|
||||
// Reserve initial space for debug tags. This prevents excessive calls to malloc when the first
|
||||
// few tags are set.
|
||||
mDebugTags.reserve(512);
|
||||
HandleAllocator<P0, P1, P2>::HandleAllocator(const char* name, size_t size) noexcept
|
||||
: mHandleArena(name, size) {
|
||||
}
|
||||
|
||||
template <size_t P0, size_t P1, size_t P2>
|
||||
@@ -110,15 +103,15 @@ void* HandleAllocator<P0, P1, P2>::handleToPointerSlow(HandleBase::HandleId id)
|
||||
}
|
||||
|
||||
template <size_t P0, size_t P1, size_t P2>
|
||||
HandleBase::HandleId HandleAllocator<P0, P1, P2>::allocateHandleSlow(size_t size) {
|
||||
HandleBase::HandleId HandleAllocator<P0, P1, P2>::allocateHandleSlow(size_t size) noexcept {
|
||||
void* p = ::malloc(size);
|
||||
std::unique_lock lock(mLock);
|
||||
|
||||
HandleBase::HandleId id = (++mId) | HANDLE_HEAP_FLAG;
|
||||
|
||||
FILAMENT_CHECK_POSTCONDITION(mId < HANDLE_HEAP_FLAG) <<
|
||||
ASSERT_POSTCONDITION(mId < HANDLE_HEAP_FLAG,
|
||||
"No more Handle ids available! This can happen if HandleAllocator arena has been full"
|
||||
" for a while. Please increase FILAMENT_OPENGL_HANDLE_ARENA_SIZE_IN_MB";
|
||||
" for a while. Please increase FILAMENT_OPENGL_HANDLE_ARENA_SIZE_IN_MB");
|
||||
|
||||
mOverflowMap.emplace(id, p);
|
||||
lock.unlock();
|
||||
|
||||
@@ -53,18 +53,4 @@ size_t Platform::retrieveBlob(void const* key, size_t keySize, void* value, size
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Platform::setDebugUpdateStatFunc(DebugUpdateStatFunc&& debugUpdateStat) noexcept {
|
||||
mDebugUpdateStat = std::move(debugUpdateStat);
|
||||
}
|
||||
|
||||
bool Platform::hasDebugUpdateStatFunc() const noexcept {
|
||||
return bool(mDebugUpdateStat);
|
||||
}
|
||||
|
||||
void Platform::debugUpdateStat(const char* key, uint64_t value) {
|
||||
if (mDebugUpdateStat) {
|
||||
mDebugUpdateStat(key, value);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace filament::backend
|
||||
|
||||
@@ -29,21 +29,21 @@
|
||||
#include "backend/platforms/PlatformCocoaTouchGL.h"
|
||||
#endif
|
||||
#elif defined(__APPLE__)
|
||||
#if defined(FILAMENT_SUPPORTS_OPENGL) && !defined(FILAMENT_USE_EXTERNAL_GLES3)
|
||||
#if defined(FILAMENT_SUPPORTS_OPENGL) && !defined(FILAMENT_USE_EXTERNAL_GLES3) && !defined(FILAMENT_USE_SWIFTSHADER)
|
||||
#include <backend/platforms/PlatformCocoaGL.h>
|
||||
#endif
|
||||
#elif defined(__linux__)
|
||||
#if defined(FILAMENT_SUPPORTS_X11)
|
||||
#if defined(FILAMENT_SUPPORTS_OPENGL) && !defined(FILAMENT_USE_EXTERNAL_GLES3)
|
||||
#if defined(FILAMENT_SUPPORTS_OPENGL) && !defined(FILAMENT_USE_EXTERNAL_GLES3) && !defined(FILAMENT_USE_SWIFTSHADER)
|
||||
#include "backend/platforms/PlatformGLX.h"
|
||||
#endif
|
||||
#elif defined(FILAMENT_SUPPORTS_EGL_ON_LINUX)
|
||||
#if defined(FILAMENT_SUPPORTS_OPENGL) && !defined(FILAMENT_USE_EXTERNAL_GLES3)
|
||||
#if defined(FILAMENT_SUPPORTS_OPENGL) && !defined(FILAMENT_USE_EXTERNAL_GLES3) && !defined(FILAMENT_USE_SWIFTSHADER)
|
||||
#include "backend/platforms/PlatformEGLHeadless.h"
|
||||
#endif
|
||||
#endif
|
||||
#elif defined(WIN32)
|
||||
#if defined(FILAMENT_SUPPORTS_OPENGL) && !defined(FILAMENT_USE_EXTERNAL_GLES3)
|
||||
#if defined(FILAMENT_SUPPORTS_OPENGL) && !defined(FILAMENT_USE_EXTERNAL_GLES3) && !defined(FILAMENT_USE_SWIFTSHADER)
|
||||
#include "backend/platforms/PlatformWGL.h"
|
||||
#endif
|
||||
#elif defined(__EMSCRIPTEN__)
|
||||
@@ -111,7 +111,8 @@ Platform* PlatformFactory::create(Backend* backend) noexcept {
|
||||
}
|
||||
assert_invariant(*backend == Backend::OPENGL);
|
||||
#if defined(FILAMENT_SUPPORTS_OPENGL)
|
||||
#if defined(FILAMENT_USE_EXTERNAL_GLES3)
|
||||
#if defined(FILAMENT_USE_EXTERNAL_GLES3) || defined(FILAMENT_USE_SWIFTSHADER)
|
||||
// Swiftshader OpenGLES support is deprecated and incomplete
|
||||
return nullptr;
|
||||
#elif defined(__ANDROID__)
|
||||
return new PlatformEGLAndroid();
|
||||
|
||||
@@ -21,7 +21,7 @@ namespace filament::backend {
|
||||
using namespace utils;
|
||||
|
||||
// We want these in the .cpp file, so they're not inlined (not worth it)
|
||||
Program::Program() noexcept { // NOLINT(modernize-use-equals-default)
|
||||
Program::Program() noexcept { // NOLINT(modernize-use-equals-default)
|
||||
}
|
||||
|
||||
Program::Program(Program&& rhs) noexcept = default;
|
||||
@@ -47,11 +47,6 @@ Program& Program::shader(ShaderStage shader, void const* data, size_t size) {
|
||||
return *this;
|
||||
}
|
||||
|
||||
Program& Program::shaderLanguage(ShaderLanguage shaderLanguage) {
|
||||
mShaderLanguage = shaderLanguage;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Program& Program::uniformBlockBindings(
|
||||
FixedCapacityVector<std::pair<utils::CString, uint8_t>> const& uniformBlockBindings) noexcept {
|
||||
for (auto const& item : uniformBlockBindings) {
|
||||
@@ -91,22 +86,11 @@ Program& Program::specializationConstants(
|
||||
return *this;
|
||||
}
|
||||
|
||||
Program& Program::pushConstants(ShaderStage stage,
|
||||
utils::FixedCapacityVector<PushConstant> constants) noexcept {
|
||||
mPushConstants[static_cast<uint8_t>(stage)] = std::move(constants);
|
||||
return *this;
|
||||
}
|
||||
|
||||
Program& Program::cacheId(uint64_t cacheId) noexcept {
|
||||
mCacheId = cacheId;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Program& Program::multiview(bool multiview) noexcept {
|
||||
mMultiview = multiview;
|
||||
return *this;
|
||||
}
|
||||
|
||||
io::ostream& operator<<(io::ostream& out, const Program& builder) {
|
||||
out << "Program{";
|
||||
builder.mLogger(out);
|
||||
|
||||
@@ -16,23 +16,13 @@
|
||||
|
||||
#include "private/backend/VirtualMachineEnv.h"
|
||||
|
||||
#include <utils/compiler.h>
|
||||
#include <utils/debug.h>
|
||||
|
||||
#include <jni.h>
|
||||
|
||||
namespace filament {
|
||||
|
||||
JavaVM* VirtualMachineEnv::sVirtualMachine = nullptr;
|
||||
|
||||
/*
|
||||
* This is typically called by filament_jni.so when it is loaded. If filament_jni.so is not used,
|
||||
* then this must be called manually -- however, this is a problem because VirtualMachineEnv.h
|
||||
* is currently private and part of backend.
|
||||
* For now, we authorize this usage, but we will need to fix it; by making a proper public
|
||||
* API for this.
|
||||
*/
|
||||
UTILS_PUBLIC
|
||||
// This is called when the library is loaded. We need this to get a reference to the global VM
|
||||
UTILS_NOINLINE
|
||||
jint VirtualMachineEnv::JNI_OnLoad(JavaVM* vm) noexcept {
|
||||
JNIEnv* env = nullptr;
|
||||
|
||||
@@ -109,8 +109,9 @@ inline bool MTLSizeEqual(T a, T b) noexcept {
|
||||
MetalBlitter::MetalBlitter(MetalContext& context) noexcept : mContext(context) { }
|
||||
|
||||
void MetalBlitter::blit(id<MTLCommandBuffer> cmdBuffer, const BlitArgs& args, const char* label) {
|
||||
FILAMENT_CHECK_PRECONDITION(args.source.region.size.depth == args.destination.region.size.depth)
|
||||
<< "Blitting requires the source and destination regions to have the same depth.";
|
||||
|
||||
ASSERT_PRECONDITION(args.source.region.size.depth == args.destination.region.size.depth,
|
||||
"Blitting requires the source and destination regions to have the same depth.");
|
||||
|
||||
// Determine if the blit for color or depth are eligible to use a MTLBlitCommandEncoder.
|
||||
// blitFastPath returns true upon success.
|
||||
@@ -326,8 +327,7 @@ id<MTLFunction> MetalBlitter::compileFragmentFunction(BlitFunctionKey key) const
|
||||
utils::slog.e << description << utils::io::endl;
|
||||
}
|
||||
}
|
||||
FILAMENT_CHECK_POSTCONDITION(library && function)
|
||||
<< "Unable to compile fragment shader for MetalBlitter.";
|
||||
ASSERT_POSTCONDITION(library && function, "Unable to compile fragment shader for MetalBlitter.");
|
||||
|
||||
return function;
|
||||
}
|
||||
@@ -352,8 +352,7 @@ id<MTLFunction> MetalBlitter::getBlitVertexFunction() {
|
||||
utils::slog.e << description << utils::io::endl;
|
||||
}
|
||||
}
|
||||
FILAMENT_CHECK_POSTCONDITION(library && function)
|
||||
<< "Unable to compile vertex shader for MetalBlitter.";
|
||||
ASSERT_POSTCONDITION(library && function, "Unable to compile vertex shader for MetalBlitter.");
|
||||
|
||||
mVertexFunction = function;
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
#define TNT_FILAMENT_DRIVER_METALBUFFER_H
|
||||
|
||||
#include "MetalContext.h"
|
||||
#include "MetalPlatform.h"
|
||||
#include "MetalBufferPool.h"
|
||||
|
||||
#include <backend/DriverEnums.h>
|
||||
|
||||
@@ -28,131 +28,9 @@
|
||||
|
||||
#include <utility>
|
||||
#include <memory>
|
||||
#include <atomic>
|
||||
#include <chrono>
|
||||
|
||||
namespace filament::backend {
|
||||
|
||||
class ScopedAllocationTimer {
|
||||
public:
|
||||
ScopedAllocationTimer(const char* name) : mBeginning(clock_t::now()), mName(name) {}
|
||||
~ScopedAllocationTimer() {
|
||||
using namespace std::literals::chrono_literals;
|
||||
static constexpr std::chrono::seconds LONG_TIME_THRESHOLD = 10s;
|
||||
|
||||
auto end = clock_t::now();
|
||||
std::chrono::duration<double, std::micro> allocationTimeMicroseconds = end - mBeginning;
|
||||
|
||||
if (UTILS_UNLIKELY(allocationTimeMicroseconds > LONG_TIME_THRESHOLD)) {
|
||||
if (platform && platform->hasDebugUpdateStatFunc()) {
|
||||
char buffer[64];
|
||||
snprintf(buffer, sizeof(buffer), "filament.metal.long_buffer_allocation_time.%s",
|
||||
mName);
|
||||
platform->debugUpdateStat(
|
||||
buffer, static_cast<uint64_t>(allocationTimeMicroseconds.count()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void setPlatform(MetalPlatform* p) { platform = p; }
|
||||
|
||||
private:
|
||||
typedef std::chrono::steady_clock clock_t;
|
||||
|
||||
static MetalPlatform* platform;
|
||||
|
||||
std::chrono::time_point<clock_t> mBeginning;
|
||||
const char* mName;
|
||||
};
|
||||
|
||||
class TrackedMetalBuffer {
|
||||
public:
|
||||
|
||||
static constexpr size_t EXCESS_BUFFER_COUNT = 30000;
|
||||
|
||||
enum class Type {
|
||||
NONE = 0,
|
||||
GENERIC = 1,
|
||||
RING = 2,
|
||||
STAGING = 3,
|
||||
};
|
||||
static constexpr size_t TypeCount = 3;
|
||||
|
||||
static constexpr auto toIndex(Type t) {
|
||||
assert_invariant(t != Type::NONE);
|
||||
switch (t) {
|
||||
case Type::NONE:
|
||||
case Type::GENERIC:
|
||||
return 0;
|
||||
case Type::RING:
|
||||
return 1;
|
||||
case Type::STAGING:
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
|
||||
TrackedMetalBuffer() noexcept : mBuffer(nil) {}
|
||||
TrackedMetalBuffer(nullptr_t) noexcept : mBuffer(nil) {}
|
||||
TrackedMetalBuffer(id<MTLBuffer> buffer, Type type) : mBuffer(buffer), mType(type) {
|
||||
assert_invariant(type != Type::NONE);
|
||||
if (buffer) {
|
||||
aliveBuffers[toIndex(type)]++;
|
||||
mType = type;
|
||||
if (getAliveBuffers() >= EXCESS_BUFFER_COUNT) {
|
||||
if (platform && platform->hasDebugUpdateStatFunc()) {
|
||||
platform->debugUpdateStat("filament.metal.excess_buffers_allocated",
|
||||
TrackedMetalBuffer::getAliveBuffers());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
~TrackedMetalBuffer() {
|
||||
if (mBuffer) {
|
||||
assert_invariant(mType != Type::NONE);
|
||||
aliveBuffers[toIndex(mType)]--;
|
||||
}
|
||||
}
|
||||
|
||||
TrackedMetalBuffer(TrackedMetalBuffer&&) = delete;
|
||||
TrackedMetalBuffer(TrackedMetalBuffer const&) = delete;
|
||||
TrackedMetalBuffer& operator=(TrackedMetalBuffer const&) = delete;
|
||||
|
||||
TrackedMetalBuffer& operator=(TrackedMetalBuffer&& rhs) noexcept {
|
||||
swap(rhs);
|
||||
return *this;
|
||||
}
|
||||
|
||||
id<MTLBuffer> get() const noexcept { return mBuffer; }
|
||||
operator bool() const noexcept { return bool(mBuffer); }
|
||||
|
||||
static uint64_t getAliveBuffers() {
|
||||
uint64_t sum = 0;
|
||||
for (const auto& v : aliveBuffers) {
|
||||
sum += v;
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
|
||||
static uint64_t getAliveBuffers(Type type) {
|
||||
assert_invariant(type != Type::NONE);
|
||||
return aliveBuffers[toIndex(type)];
|
||||
}
|
||||
static void setPlatform(MetalPlatform* p) { platform = p; }
|
||||
|
||||
private:
|
||||
void swap(TrackedMetalBuffer& other) noexcept {
|
||||
std::swap(mBuffer, other.mBuffer);
|
||||
std::swap(mType, other.mType);
|
||||
}
|
||||
|
||||
id<MTLBuffer> mBuffer;
|
||||
Type mType = Type::NONE;
|
||||
|
||||
static MetalPlatform* platform;
|
||||
static std::array<uint64_t, TypeCount> aliveBuffers;
|
||||
};
|
||||
|
||||
class MetalBuffer {
|
||||
public:
|
||||
|
||||
@@ -204,16 +82,7 @@ public:
|
||||
|
||||
private:
|
||||
|
||||
enum class UploadStrategy {
|
||||
POOL,
|
||||
BUMP_ALLOCATOR,
|
||||
};
|
||||
|
||||
void uploadWithPoolBuffer(void* src, size_t size, size_t byteOffset) const;
|
||||
void uploadWithBumpAllocator(void* src, size_t size, size_t byteOffset) const;
|
||||
|
||||
UploadStrategy mUploadStrategy;
|
||||
TrackedMetalBuffer mBuffer;
|
||||
id<MTLBuffer> mBuffer = nil;
|
||||
size_t mBufferSize = 0;
|
||||
void* mCpuBuffer = nullptr;
|
||||
MetalContext& mContext;
|
||||
@@ -262,9 +131,7 @@ public:
|
||||
mBufferOptions(options),
|
||||
mSlotSizeBytes(computeSlotSize(layout)),
|
||||
mSlotCount(slotCount) {
|
||||
ScopedAllocationTimer timer("ring");
|
||||
mBuffer = { [device newBufferWithLength:mSlotSizeBytes * mSlotCount options:mBufferOptions],
|
||||
TrackedMetalBuffer::Type::RING };
|
||||
mBuffer = [device newBufferWithLength:mSlotSizeBytes * mSlotCount options:mBufferOptions];
|
||||
assert_invariant(mBuffer);
|
||||
}
|
||||
|
||||
@@ -282,13 +149,9 @@ public:
|
||||
// If we already have an aux buffer, it will get freed here, unless it has been retained
|
||||
// by a MTLCommandBuffer. In that case, it will be freed when the command buffer
|
||||
// finishes executing.
|
||||
{
|
||||
ScopedAllocationTimer timer("ring");
|
||||
mAuxBuffer = { [mDevice newBufferWithLength:mSlotSizeBytes options:mBufferOptions],
|
||||
TrackedMetalBuffer::Type::RING };
|
||||
}
|
||||
mAuxBuffer = [mDevice newBufferWithLength:mSlotSizeBytes options:mBufferOptions];
|
||||
assert_invariant(mAuxBuffer);
|
||||
return { mAuxBuffer.get(), 0 };
|
||||
return {mAuxBuffer, 0};
|
||||
}
|
||||
mCurrentSlot = (mCurrentSlot + 1) % mSlotCount;
|
||||
mOccupiedSlots->fetch_add(1, std::memory_order_relaxed);
|
||||
@@ -317,9 +180,9 @@ public:
|
||||
*/
|
||||
std::pair<id<MTLBuffer>, NSUInteger> getCurrentAllocation() const {
|
||||
if (UTILS_UNLIKELY(mAuxBuffer)) {
|
||||
return { mAuxBuffer.get(), 0 };
|
||||
return { mAuxBuffer, 0 };
|
||||
}
|
||||
return { mBuffer.get(), mCurrentSlot * mSlotSizeBytes };
|
||||
return { mBuffer, mCurrentSlot * mSlotSizeBytes };
|
||||
}
|
||||
|
||||
bool canAccomodateLayout(MTLSizeAndAlign layout) const {
|
||||
@@ -328,8 +191,8 @@ public:
|
||||
|
||||
private:
|
||||
id<MTLDevice> mDevice;
|
||||
TrackedMetalBuffer mBuffer;
|
||||
TrackedMetalBuffer mAuxBuffer;
|
||||
id<MTLBuffer> mBuffer;
|
||||
id<MTLBuffer> mAuxBuffer;
|
||||
|
||||
MTLResourceOptions mBufferOptions;
|
||||
|
||||
|
||||
@@ -15,28 +15,14 @@
|
||||
*/
|
||||
|
||||
#include "MetalBuffer.h"
|
||||
#include "MetalBufferPool.h"
|
||||
|
||||
#include "MetalContext.h"
|
||||
|
||||
namespace filament {
|
||||
namespace backend {
|
||||
|
||||
std::array<uint64_t, TrackedMetalBuffer::TypeCount> TrackedMetalBuffer::aliveBuffers = { 0 };
|
||||
MetalPlatform* TrackedMetalBuffer::platform = nullptr;
|
||||
MetalPlatform* ScopedAllocationTimer::platform = nullptr;
|
||||
|
||||
MetalBuffer::MetalBuffer(MetalContext& context, BufferObjectBinding bindingType, BufferUsage usage,
|
||||
size_t size, bool forceGpuBuffer)
|
||||
: mBufferSize(size), mContext(context) {
|
||||
const MetalBumpAllocator& allocator = *mContext.bumpAllocator;
|
||||
// VERTEX is also used for index buffers
|
||||
if (allocator.getCapacity() > 0 && bindingType == BufferObjectBinding::VERTEX) {
|
||||
mUploadStrategy = UploadStrategy::BUMP_ALLOCATOR;
|
||||
} else {
|
||||
mUploadStrategy = UploadStrategy::POOL;
|
||||
}
|
||||
|
||||
size_t size, bool forceGpuBuffer) : mBufferSize(size), mContext(context) {
|
||||
// If the buffer is less than 4K in size and is updated frequently, we don't use an explicit
|
||||
// buffer. Instead, we use immediate command encoder methods like setVertexBytes:length:atIndex:.
|
||||
// This won't work for SSBOs, since they are read/write.
|
||||
@@ -48,13 +34,8 @@ MetalBuffer::MetalBuffer(MetalContext& context, BufferObjectBinding bindingType,
|
||||
}
|
||||
|
||||
// Otherwise, we allocate a private GPU buffer.
|
||||
{
|
||||
ScopedAllocationTimer timer("generic");
|
||||
mBuffer = { [context.device newBufferWithLength:size options:MTLResourceStorageModePrivate],
|
||||
TrackedMetalBuffer::Type::GENERIC };
|
||||
}
|
||||
FILAMENT_CHECK_POSTCONDITION(mBuffer)
|
||||
<< "Could not allocate Metal buffer of size " << size << ".";
|
||||
mBuffer = [context.device newBufferWithLength:size options:MTLResourceStorageModePrivate];
|
||||
ASSERT_POSTCONDITION(mBuffer, "Could not allocate Metal buffer of size %zu.", size);
|
||||
}
|
||||
|
||||
MetalBuffer::~MetalBuffer() {
|
||||
@@ -67,26 +48,37 @@ void MetalBuffer::copyIntoBuffer(void* src, size_t size, size_t byteOffset) {
|
||||
if (size <= 0) {
|
||||
return;
|
||||
}
|
||||
FILAMENT_CHECK_PRECONDITION(size + byteOffset <= mBufferSize)
|
||||
<< "Attempting to copy " << size << " bytes into a buffer of size " << mBufferSize
|
||||
<< " at offset " << byteOffset;
|
||||
// The copy blit requires that byteOffset be a multiple of 4.
|
||||
FILAMENT_CHECK_PRECONDITION(!(byteOffset & 0x3)) << "byteOffset must be a multiple of 4";
|
||||
ASSERT_PRECONDITION(size + byteOffset <= mBufferSize,
|
||||
"Attempting to copy %zu bytes into a buffer of size %zu at offset %zu",
|
||||
size, mBufferSize, byteOffset);
|
||||
|
||||
// If we have a cpu buffer, we can directly copy into it.
|
||||
// Either copy into the Metal buffer or into our cpu buffer.
|
||||
if (mCpuBuffer) {
|
||||
memcpy(static_cast<uint8_t*>(mCpuBuffer) + byteOffset, src, size);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (mUploadStrategy) {
|
||||
case UploadStrategy::BUMP_ALLOCATOR:
|
||||
uploadWithBumpAllocator(src, size, byteOffset);
|
||||
break;
|
||||
case UploadStrategy::POOL:
|
||||
uploadWithPoolBuffer(src, size, byteOffset);
|
||||
break;
|
||||
}
|
||||
// Acquire a staging buffer to hold the contents of this update.
|
||||
MetalBufferPool* bufferPool = mContext.bufferPool;
|
||||
const MetalBufferPoolEntry* const staging = bufferPool->acquireBuffer(size);
|
||||
memcpy(staging->buffer.contents, src, size);
|
||||
|
||||
// The blit below requires that byteOffset be a multiple of 4.
|
||||
ASSERT_PRECONDITION(!(byteOffset & 0x3u), "byteOffset must be a multiple of 4");
|
||||
|
||||
// Encode a blit from the staging buffer into the private GPU buffer.
|
||||
id<MTLCommandBuffer> cmdBuffer = getPendingCommandBuffer(&mContext);
|
||||
id<MTLBlitCommandEncoder> blitEncoder = [cmdBuffer blitCommandEncoder];
|
||||
blitEncoder.label = @"Buffer upload blit";
|
||||
[blitEncoder copyFromBuffer:staging->buffer
|
||||
sourceOffset:0
|
||||
toBuffer:mBuffer
|
||||
destinationOffset:byteOffset
|
||||
size:size];
|
||||
[blitEncoder endEncoding];
|
||||
[cmdBuffer addCompletedHandler:^(id<MTLCommandBuffer> cb) {
|
||||
bufferPool->releaseBuffer(staging);
|
||||
}];
|
||||
}
|
||||
|
||||
void MetalBuffer::copyIntoBufferUnsynchronized(void* src, size_t size, size_t byteOffset) {
|
||||
@@ -101,7 +93,7 @@ id<MTLBuffer> MetalBuffer::getGpuBufferForDraw(id<MTLCommandBuffer> cmdBuffer) n
|
||||
return nil;
|
||||
}
|
||||
assert_invariant(mBuffer);
|
||||
return mBuffer.get();
|
||||
return mBuffer;
|
||||
}
|
||||
|
||||
void MetalBuffer::bindBuffers(id<MTLCommandBuffer> cmdBuffer, id<MTLCommandEncoder> encoder,
|
||||
@@ -197,42 +189,5 @@ void MetalBuffer::bindBuffers(id<MTLCommandBuffer> cmdBuffer, id<MTLCommandEncod
|
||||
}
|
||||
}
|
||||
|
||||
void MetalBuffer::uploadWithPoolBuffer(void* src, size_t size, size_t byteOffset) const {
|
||||
MetalBufferPool* bufferPool = mContext.bufferPool;
|
||||
const MetalBufferPoolEntry* const staging = bufferPool->acquireBuffer(size);
|
||||
memcpy(staging->buffer.get().contents, src, size);
|
||||
|
||||
// Encode a blit from the staging buffer into the private GPU buffer.
|
||||
id<MTLCommandBuffer> cmdBuffer = getPendingCommandBuffer(&mContext);
|
||||
id<MTLBlitCommandEncoder> blitEncoder = [cmdBuffer blitCommandEncoder];
|
||||
blitEncoder.label = @"Buffer upload blit - pool buffer";
|
||||
[blitEncoder copyFromBuffer:staging->buffer.get()
|
||||
sourceOffset:0
|
||||
toBuffer:mBuffer.get()
|
||||
destinationOffset:byteOffset
|
||||
size:size];
|
||||
[blitEncoder endEncoding];
|
||||
[cmdBuffer addCompletedHandler:^(id<MTLCommandBuffer> cb) {
|
||||
bufferPool->releaseBuffer(staging);
|
||||
}];
|
||||
}
|
||||
|
||||
void MetalBuffer::uploadWithBumpAllocator(void* src, size_t size, size_t byteOffset) const {
|
||||
MetalBumpAllocator& allocator = *mContext.bumpAllocator;
|
||||
auto [buffer, offset] = allocator.allocateStagingArea(size);
|
||||
memcpy(static_cast<char*>(buffer.contents) + offset, src, size);
|
||||
|
||||
// Encode a blit from the staging buffer into the private GPU buffer.
|
||||
id<MTLCommandBuffer> cmdBuffer = getPendingCommandBuffer(&mContext);
|
||||
id<MTLBlitCommandEncoder> blitEncoder = [cmdBuffer blitCommandEncoder];
|
||||
blitEncoder.label = @"Buffer upload blit - bump allocator";
|
||||
[blitEncoder copyFromBuffer:buffer
|
||||
sourceOffset:offset
|
||||
toBuffer:mBuffer.get()
|
||||
destinationOffset:byteOffset
|
||||
size:size];
|
||||
[blitEncoder endEncoding];
|
||||
}
|
||||
|
||||
} // namespace backend
|
||||
} // namespace filament
|
||||
|
||||
@@ -19,8 +19,6 @@
|
||||
|
||||
#include <Metal/Metal.h>
|
||||
|
||||
#include "MetalBuffer.h"
|
||||
|
||||
#include <map>
|
||||
#include <mutex>
|
||||
#include <unordered_set>
|
||||
@@ -32,34 +30,12 @@ struct MetalContext;
|
||||
|
||||
// Immutable POD representing a shared CPU-GPU buffer.
|
||||
struct MetalBufferPoolEntry {
|
||||
TrackedMetalBuffer buffer;
|
||||
id<MTLBuffer> buffer;
|
||||
size_t capacity;
|
||||
mutable uint64_t lastAccessed;
|
||||
mutable uint32_t referenceCount;
|
||||
};
|
||||
|
||||
class MetalBumpAllocator {
|
||||
public:
|
||||
MetalBumpAllocator(id<MTLDevice> device, size_t capacity);
|
||||
|
||||
/**
|
||||
* Allocates a staging area of the given size. Returns a pair of the buffer and the offset
|
||||
* within the buffer. The buffer is guaranteed to be at least the given size, but may be larger.
|
||||
* Clients must not write to the buffer beyond the returned offset + size.
|
||||
* Clients are responsible for holding a reference to the returned buffer.
|
||||
* Allocations are guaranteed to be aligned to 4 bytes.
|
||||
*/
|
||||
std::pair<id<MTLBuffer>, size_t> allocateStagingArea(size_t size);
|
||||
|
||||
size_t getCapacity() const noexcept { return mCapacity; }
|
||||
|
||||
private:
|
||||
id<MTLDevice> mDevice;
|
||||
TrackedMetalBuffer mCurrentUploadBuffer = nil;
|
||||
size_t mHead = 0;
|
||||
size_t mCapacity;
|
||||
};
|
||||
|
||||
// Manages a pool of Metal buffers, periodically releasing ones that have been unused for awhile.
|
||||
class MetalBufferPool {
|
||||
public:
|
||||
|
||||
@@ -42,20 +42,15 @@ MetalBufferPoolEntry const* MetalBufferPool::acquireBuffer(size_t numBytes) {
|
||||
}
|
||||
|
||||
// We were not able to find a sufficiently large stage, so create a new one.
|
||||
id<MTLBuffer> buffer = nil;
|
||||
{
|
||||
ScopedAllocationTimer timer("staging");
|
||||
buffer = [mContext.device newBufferWithLength:numBytes
|
||||
options:MTLResourceStorageModeShared];
|
||||
}
|
||||
FILAMENT_CHECK_POSTCONDITION(buffer)
|
||||
<< "Could not allocate Metal staging buffer of size " << numBytes << ".";
|
||||
MetalBufferPoolEntry* stage = new MetalBufferPoolEntry {
|
||||
.buffer = { buffer, TrackedMetalBuffer::Type::STAGING },
|
||||
id<MTLBuffer> buffer = [mContext.device newBufferWithLength:numBytes
|
||||
options:MTLResourceStorageModeShared];
|
||||
ASSERT_POSTCONDITION(buffer, "Could not allocate Metal staging buffer of size %zu.", numBytes);
|
||||
MetalBufferPoolEntry* stage = new MetalBufferPoolEntry({
|
||||
.buffer = buffer,
|
||||
.capacity = numBytes,
|
||||
.lastAccessed = mCurrentFrame,
|
||||
.referenceCount = 1
|
||||
};
|
||||
});
|
||||
mUsedStages.insert(stage);
|
||||
|
||||
return stage;
|
||||
@@ -116,39 +111,5 @@ void MetalBufferPool::reset() noexcept {
|
||||
mFreeStages.clear();
|
||||
}
|
||||
|
||||
MetalBumpAllocator::MetalBumpAllocator(id<MTLDevice> device, size_t capacity)
|
||||
: mDevice(device), mCapacity(capacity) {
|
||||
if (mCapacity > 0) {
|
||||
mCurrentUploadBuffer = { [device newBufferWithLength:capacity options:MTLStorageModeShared],
|
||||
TrackedMetalBuffer::Type::STAGING };
|
||||
}
|
||||
}
|
||||
|
||||
std::pair<id<MTLBuffer>, size_t> MetalBumpAllocator::allocateStagingArea(size_t size) {
|
||||
if (size == 0) {
|
||||
return { nil, 0 };
|
||||
}
|
||||
if (size > mCapacity) {
|
||||
return { [mDevice newBufferWithLength:size options:MTLStorageModeShared], 0 };
|
||||
}
|
||||
assert_invariant(mCurrentUploadBuffer);
|
||||
|
||||
// Align the head to a 4-byte boundary.
|
||||
mHead = (mHead + 3) & ~3;
|
||||
|
||||
if (UTILS_LIKELY(mHead + size <= mCapacity)) {
|
||||
const size_t oldHead = mHead;
|
||||
mHead += size;
|
||||
return { mCurrentUploadBuffer.get(), oldHead };
|
||||
}
|
||||
|
||||
// We're finished with the current allocation.
|
||||
mCurrentUploadBuffer = { [mDevice newBufferWithLength:mCapacity options:MTLStorageModeShared],
|
||||
TrackedMetalBuffer::Type::STAGING };
|
||||
mHead = size;
|
||||
|
||||
return { mCurrentUploadBuffer.get(), 0 };
|
||||
}
|
||||
|
||||
} // namespace backend
|
||||
} // namespace filament
|
||||
|
||||
@@ -44,7 +44,6 @@ namespace backend {
|
||||
class MetalDriver;
|
||||
class MetalBlitter;
|
||||
class MetalBufferPool;
|
||||
class MetalBumpAllocator;
|
||||
class MetalRenderTarget;
|
||||
class MetalSamplerGroup;
|
||||
class MetalSwapChain;
|
||||
@@ -56,18 +55,6 @@ struct MetalVertexBuffer;
|
||||
|
||||
constexpr static uint8_t MAX_SAMPLE_COUNT = 8; // Metal devices support at most 8 MSAA samples
|
||||
|
||||
class MetalPushConstantBuffer {
|
||||
public:
|
||||
void setPushConstant(PushConstantVariant value, uint8_t index);
|
||||
bool isDirty() const { return mDirty; }
|
||||
void setBytes(id<MTLCommandEncoder> encoder, ShaderStage stage);
|
||||
void clear();
|
||||
|
||||
private:
|
||||
std::vector<PushConstantVariant> mPushConstants;
|
||||
bool mDirty = false;
|
||||
};
|
||||
|
||||
struct MetalContext {
|
||||
explicit MetalContext(size_t metalFreedTextureListSize)
|
||||
: texturesToDestroy(metalFreedTextureListSize) {}
|
||||
@@ -93,7 +80,7 @@ struct MetalContext {
|
||||
} highestSupportedGpuFamily;
|
||||
|
||||
struct {
|
||||
bool staticTextureTargetError;
|
||||
bool a8xStaticTextureTargetError;
|
||||
} bugs;
|
||||
|
||||
// sampleCountLookup[requestedSamples] gives a <= sample count supported by the device.
|
||||
@@ -112,7 +99,6 @@ struct MetalContext {
|
||||
std::array<BufferState, MAX_SSBO_COUNT> ssboState;
|
||||
CullModeStateTracker cullModeState;
|
||||
WindingStateTracker windingState;
|
||||
Handle<HwRenderPrimitive> currentRenderPrimitive;
|
||||
|
||||
// State caches.
|
||||
DepthStencilStateCache depthStencilStateCache;
|
||||
@@ -122,8 +108,6 @@ struct MetalContext {
|
||||
|
||||
PolygonOffset currentPolygonOffset = {0.0f, 0.0f};
|
||||
|
||||
std::array<MetalPushConstantBuffer, Program::SHADER_TYPE_COUNT> currentPushConstants;
|
||||
|
||||
MetalSamplerGroup* samplerBindings[Program::SAMPLER_BINDING_COUNT] = {};
|
||||
|
||||
// Keeps track of sampler groups we've finalized for the current render pass.
|
||||
@@ -142,7 +126,6 @@ struct MetalContext {
|
||||
utils::FixedCircularBuffer<Handle<HwTexture>> texturesToDestroy;
|
||||
|
||||
MetalBufferPool* bufferPool;
|
||||
MetalBumpAllocator* bumpAllocator;
|
||||
|
||||
MetalSwapChain* currentDrawSwapChain = nil;
|
||||
MetalSwapChain* currentReadSwapChain = nil;
|
||||
|
||||
@@ -113,8 +113,7 @@ id<MTLCommandBuffer> getPendingCommandBuffer(MetalContext* context) {
|
||||
}
|
||||
}
|
||||
}];
|
||||
FILAMENT_CHECK_POSTCONDITION(context->pendingCommandBuffer)
|
||||
<< "Could not obtain command buffer.";
|
||||
ASSERT_POSTCONDITION(context->pendingCommandBuffer, "Could not obtain command buffer.");
|
||||
return context->pendingCommandBuffer;
|
||||
}
|
||||
|
||||
@@ -154,68 +153,5 @@ bool isInRenderPass(MetalContext* context) {
|
||||
return context->currentRenderPassEncoder != nil;
|
||||
}
|
||||
|
||||
void MetalPushConstantBuffer::setPushConstant(PushConstantVariant value, uint8_t index) {
|
||||
if (mPushConstants.size() <= index) {
|
||||
mPushConstants.resize(index + 1);
|
||||
mDirty = true;
|
||||
}
|
||||
if (UTILS_LIKELY(mPushConstants[index] != value)) {
|
||||
mDirty = true;
|
||||
mPushConstants[index] = value;
|
||||
}
|
||||
}
|
||||
|
||||
void MetalPushConstantBuffer::setBytes(id<MTLCommandEncoder> encoder, ShaderStage stage) {
|
||||
constexpr size_t PUSH_CONSTANT_SIZE_BYTES = 4;
|
||||
constexpr size_t PUSH_CONSTANT_BUFFER_INDEX = 26;
|
||||
|
||||
static char buffer[MAX_PUSH_CONSTANT_COUNT * PUSH_CONSTANT_SIZE_BYTES];
|
||||
assert_invariant(mPushConstants.size() <= MAX_PUSH_CONSTANT_COUNT);
|
||||
|
||||
size_t bufferSize = PUSH_CONSTANT_SIZE_BYTES * mPushConstants.size();
|
||||
for (size_t i = 0; i < mPushConstants.size(); i++) {
|
||||
const auto& constant = mPushConstants[i];
|
||||
std::visit(
|
||||
[i](auto arg) {
|
||||
if constexpr (std::is_same_v<decltype(arg), bool>) {
|
||||
// bool push constants are converted to uints in MSL.
|
||||
// We must ensure we write all the bytes for boolean values to work
|
||||
// correctly.
|
||||
uint32_t boolAsUint = arg ? 0x00000001 : 0x00000000;
|
||||
*(reinterpret_cast<uint32_t*>(buffer + PUSH_CONSTANT_SIZE_BYTES * i)) =
|
||||
boolAsUint;
|
||||
} else {
|
||||
*(decltype(arg)*)(buffer + PUSH_CONSTANT_SIZE_BYTES * i) = arg;
|
||||
}
|
||||
},
|
||||
constant);
|
||||
}
|
||||
|
||||
switch (stage) {
|
||||
case ShaderStage::VERTEX:
|
||||
[(id<MTLRenderCommandEncoder>)encoder setVertexBytes:buffer
|
||||
length:bufferSize
|
||||
atIndex:PUSH_CONSTANT_BUFFER_INDEX];
|
||||
break;
|
||||
case ShaderStage::FRAGMENT:
|
||||
[(id<MTLRenderCommandEncoder>)encoder setFragmentBytes:buffer
|
||||
length:bufferSize
|
||||
atIndex:PUSH_CONSTANT_BUFFER_INDEX];
|
||||
break;
|
||||
case ShaderStage::COMPUTE:
|
||||
[(id<MTLComputeCommandEncoder>)encoder setBytes:buffer
|
||||
length:bufferSize
|
||||
atIndex:PUSH_CONSTANT_BUFFER_INDEX];
|
||||
break;
|
||||
}
|
||||
|
||||
mDirty = false;
|
||||
}
|
||||
|
||||
void MetalPushConstantBuffer::clear() {
|
||||
mPushConstants.clear();
|
||||
mDirty = false;
|
||||
}
|
||||
|
||||
} // namespace backend
|
||||
} // namespace filament
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
#ifndef TNT_FILAMENT_DRIVER_METALDRIVER_H
|
||||
#define TNT_FILAMENT_DRIVER_METALDRIVER_H
|
||||
|
||||
#include <backend/DriverEnums.h>
|
||||
#include "private/backend/Driver.h"
|
||||
#include "DriverBase.h"
|
||||
|
||||
@@ -134,14 +133,16 @@ private:
|
||||
mHandleAllocator.deallocate(handle, p);
|
||||
}
|
||||
|
||||
inline void setRenderPrimitiveBuffer(Handle<HwRenderPrimitive> rph, PrimitiveType pt,
|
||||
inline void setRenderPrimitiveBuffer(Handle<HwRenderPrimitive> rph,
|
||||
Handle<HwVertexBuffer> vbh, Handle<HwIndexBuffer> ibh);
|
||||
|
||||
inline void setRenderPrimitiveRange(Handle<HwRenderPrimitive> rph, PrimitiveType pt,
|
||||
uint32_t offset, uint32_t minIndex, uint32_t maxIndex, uint32_t count);
|
||||
|
||||
void finalizeSamplerGroup(MetalSamplerGroup* sg);
|
||||
void enumerateBoundBuffers(BufferObjectBinding bindingType,
|
||||
const std::function<void(const BufferState&, MetalBuffer*, uint32_t)>& f);
|
||||
|
||||
backend::StereoscopicType const mStereoscopicType;
|
||||
};
|
||||
|
||||
} // namespace backend
|
||||
|
||||
@@ -20,7 +20,6 @@
|
||||
#include "metal/MetalDriver.h"
|
||||
|
||||
#include "MetalBlitter.h"
|
||||
#include "MetalBufferPool.h"
|
||||
#include "MetalContext.h"
|
||||
#include "MetalDriverFactory.h"
|
||||
#include "MetalEnums.h"
|
||||
@@ -37,7 +36,6 @@
|
||||
|
||||
#include <utils/Log.h>
|
||||
#include <utils/Panic.h>
|
||||
#include <utils/sstream.h>
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
@@ -50,26 +48,24 @@ Driver* MetalDriverFactory::create(MetalPlatform* const platform, const Platform
|
||||
// For reference on a 64-bits machine in Release mode:
|
||||
// MetalTimerQuery : 16 few
|
||||
// HwStream : 24 few
|
||||
// MetalRenderPrimitive : 24 many
|
||||
// MetalVertexBuffer : 32 moderate
|
||||
// -- less than or equal 32 bytes
|
||||
// MetalIndexBuffer : 40 moderate
|
||||
// MetalFence : 48 few
|
||||
// MetalIndexBuffer : 56 moderate
|
||||
// MetalBufferObject : 64 many
|
||||
// -- less than or equal 64 bytes
|
||||
// MetalBufferObject : 48 many
|
||||
// -- less than or equal 48 bytes
|
||||
// MetalSamplerGroup : 112 few
|
||||
// MetalProgram : 152 moderate
|
||||
// MetalProgram : 144 moderate
|
||||
// MetalTexture : 152 moderate
|
||||
// MetalSwapChain : 208 few
|
||||
// MetalVertexBuffer : 152 moderate
|
||||
// -- less than or equal 160 bytes
|
||||
// MetalSwapChain : 184 few
|
||||
// MetalRenderTarget : 272 few
|
||||
// MetalVertexBufferInfo : 552 moderate
|
||||
// -- less than or equal to 552 bytes
|
||||
// MetalRenderPrimitive : 584 many
|
||||
// -- less than or equal to 592 bytes
|
||||
|
||||
utils::slog.d
|
||||
<< "\nMetalSwapChain: " << sizeof(MetalSwapChain)
|
||||
<< "\nMetalBufferObject: " << sizeof(MetalBufferObject)
|
||||
<< "\nMetalVertexBuffer: " << sizeof(MetalVertexBuffer)
|
||||
<< "\nMetalVertexBufferInfo: " << sizeof(MetalVertexBufferInfo)
|
||||
<< "\nMetalIndexBuffer: " << sizeof(MetalIndexBuffer)
|
||||
<< "\nMetalSamplerGroup: " << sizeof(MetalSamplerGroup)
|
||||
<< "\nMetalRenderPrimitive: " << sizeof(MetalRenderPrimitive)
|
||||
@@ -100,15 +96,9 @@ Dispatcher MetalDriver::getDispatcher() const noexcept {
|
||||
MetalDriver::MetalDriver(MetalPlatform* platform, const Platform::DriverConfig& driverConfig) noexcept
|
||||
: mPlatform(*platform),
|
||||
mContext(new MetalContext(driverConfig.textureUseAfterFreePoolSize)),
|
||||
mHandleAllocator("Handles",
|
||||
driverConfig.handleArenaSize,
|
||||
driverConfig.disableHandleUseAfterFreeCheck),
|
||||
mStereoscopicType(driverConfig.stereoscopicType) {
|
||||
mHandleAllocator("Handles", driverConfig.handleArenaSize) {
|
||||
mContext->driver = this;
|
||||
|
||||
TrackedMetalBuffer::setPlatform(platform);
|
||||
ScopedAllocationTimer::setPlatform(platform);
|
||||
|
||||
mContext->device = mPlatform.createDevice();
|
||||
assert_invariant(mContext->device);
|
||||
|
||||
@@ -162,10 +152,8 @@ MetalDriver::MetalDriver(MetalPlatform* platform, const Platform::DriverConfig&
|
||||
sc[s] = [mContext->device supportsTextureSampleCount:s] ? s : sc[s - 1];
|
||||
}
|
||||
|
||||
mContext->bugs.staticTextureTargetError =
|
||||
[mContext->device.name containsString:@"Apple A8X GPU"] ||
|
||||
[mContext->device.name containsString:@"Apple A8 GPU"] ||
|
||||
[mContext->device.name containsString:@"Apple A7 GPU"];
|
||||
mContext->bugs.a8xStaticTextureTargetError =
|
||||
[mContext->device.name containsString:@"Apple A8X GPU"];
|
||||
|
||||
mContext->commandQueue = mPlatform.createCommandQueue(mContext->device);
|
||||
mContext->pipelineStateCache.setDevice(mContext->device);
|
||||
@@ -173,8 +161,6 @@ MetalDriver::MetalDriver(MetalPlatform* platform, const Platform::DriverConfig&
|
||||
mContext->samplerStateCache.setDevice(mContext->device);
|
||||
mContext->argumentEncoderCache.setDevice(mContext->device);
|
||||
mContext->bufferPool = new MetalBufferPool(*mContext);
|
||||
mContext->bumpAllocator =
|
||||
new MetalBumpAllocator(mContext->device, driverConfig.metalUploadBufferSizeBytes);
|
||||
mContext->blitter = new MetalBlitter(*mContext);
|
||||
|
||||
if (@available(iOS 12, *)) {
|
||||
@@ -185,18 +171,14 @@ MetalDriver::MetalDriver(MetalPlatform* platform, const Platform::DriverConfig&
|
||||
|
||||
CVReturn success = CVMetalTextureCacheCreate(kCFAllocatorDefault, nullptr, mContext->device,
|
||||
nullptr, &mContext->textureCache);
|
||||
FILAMENT_CHECK_POSTCONDITION(success == kCVReturnSuccess)
|
||||
<< "Could not create Metal texture cache.";
|
||||
ASSERT_POSTCONDITION(success == kCVReturnSuccess, "Could not create Metal texture cache.");
|
||||
|
||||
if (@available(iOS 12, *)) {
|
||||
dispatch_queue_t queue = dispatch_get_global_queue(QOS_CLASS_DEFAULT, 0);
|
||||
mContext->eventListener = [[MTLSharedEventListener alloc] initWithDispatchQueue:queue];
|
||||
}
|
||||
|
||||
const MetalShaderCompiler::Mode compilerMode = driverConfig.disableParallelShaderCompile
|
||||
? MetalShaderCompiler::Mode::SYNCHRONOUS
|
||||
: MetalShaderCompiler::Mode::ASYNCHRONOUS;
|
||||
mContext->shaderCompiler = new MetalShaderCompiler(mContext->device, *this, compilerMode);
|
||||
mContext->shaderCompiler = new MetalShaderCompiler(mContext->device, *this);
|
||||
mContext->shaderCompiler->init();
|
||||
|
||||
#if defined(FILAMENT_METAL_PROFILING)
|
||||
@@ -207,13 +189,10 @@ MetalDriver::MetalDriver(MetalPlatform* platform, const Platform::DriverConfig&
|
||||
}
|
||||
|
||||
MetalDriver::~MetalDriver() noexcept {
|
||||
TrackedMetalBuffer::setPlatform(nullptr);
|
||||
ScopedAllocationTimer::setPlatform(nullptr);
|
||||
mContext->device = nil;
|
||||
mContext->emptyTexture = nil;
|
||||
CFRelease(mContext->textureCache);
|
||||
delete mContext->bufferPool;
|
||||
delete mContext->bumpAllocator;
|
||||
delete mContext->blitter;
|
||||
delete mContext->timerQueryImpl;
|
||||
delete mContext->shaderCompiler;
|
||||
@@ -224,32 +203,22 @@ void MetalDriver::tick(int) {
|
||||
executeTickOps();
|
||||
}
|
||||
|
||||
void MetalDriver::beginFrame(int64_t monotonic_clock_ns,
|
||||
int64_t refreshIntervalNs, uint32_t frameId) {
|
||||
void MetalDriver::beginFrame(int64_t monotonic_clock_ns, uint32_t frameId) {
|
||||
#if defined(FILAMENT_METAL_PROFILING)
|
||||
os_signpost_interval_begin(mContext->log, mContext->signpostId, "Frame encoding", "%{public}d", frameId);
|
||||
#endif
|
||||
if (mPlatform.hasDebugUpdateStatFunc()) {
|
||||
mPlatform.debugUpdateStat("filament.metal.alive_buffers", TrackedMetalBuffer::getAliveBuffers());
|
||||
mPlatform.debugUpdateStat("filament.metal.alive_buffers.generic",
|
||||
TrackedMetalBuffer::getAliveBuffers(TrackedMetalBuffer::Type::GENERIC));
|
||||
mPlatform.debugUpdateStat("filament.metal.alive_buffers.ring",
|
||||
TrackedMetalBuffer::getAliveBuffers(TrackedMetalBuffer::Type::RING));
|
||||
mPlatform.debugUpdateStat("filament.metal.alive_buffers.staging",
|
||||
TrackedMetalBuffer::getAliveBuffers(TrackedMetalBuffer::Type::STAGING));
|
||||
}
|
||||
}
|
||||
|
||||
void MetalDriver::setFrameScheduledCallback(
|
||||
Handle<HwSwapChain> sch, CallbackHandler* handler, FrameScheduledCallback&& callback) {
|
||||
void MetalDriver::setFrameScheduledCallback(Handle<HwSwapChain> sch,
|
||||
FrameScheduledCallback callback, void* user) {
|
||||
auto* swapChain = handle_cast<MetalSwapChain>(sch);
|
||||
swapChain->setFrameScheduledCallback(handler, std::move(callback));
|
||||
swapChain->setFrameScheduledCallback(callback, user);
|
||||
}
|
||||
|
||||
void MetalDriver::setFrameCompletedCallback(
|
||||
Handle<HwSwapChain> sch, CallbackHandler* handler, utils::Invocable<void(void)>&& callback) {
|
||||
void MetalDriver::setFrameCompletedCallback(Handle<HwSwapChain> sch,
|
||||
CallbackHandler* handler, CallbackHandler::Callback callback, void* user) {
|
||||
auto* swapChain = handle_cast<MetalSwapChain>(sch);
|
||||
swapChain->setFrameCompletedCallback(handler, std::move(callback));
|
||||
swapChain->setFrameCompletedCallback(handler, callback, user);
|
||||
}
|
||||
|
||||
void MetalDriver::execute(std::function<void(void)> const& fn) noexcept {
|
||||
@@ -295,14 +264,14 @@ void MetalDriver::endFrame(uint32_t frameId) {
|
||||
}
|
||||
|
||||
void MetalDriver::flush(int) {
|
||||
FILAMENT_CHECK_PRECONDITION(!isInRenderPass(mContext))
|
||||
<< "flush must be called outside of a render pass.";
|
||||
ASSERT_PRECONDITION(!isInRenderPass(mContext),
|
||||
"flush must be called outside of a render pass.");
|
||||
submitPendingCommands(mContext);
|
||||
}
|
||||
|
||||
void MetalDriver::finish(int) {
|
||||
FILAMENT_CHECK_PRECONDITION(!isInRenderPass(mContext))
|
||||
<< "finish must be called outside of a render pass.";
|
||||
ASSERT_PRECONDITION(!isInRenderPass(mContext),
|
||||
"finish must be called outside of a render pass.");
|
||||
// Wait for all frames to finish by submitting and waiting on a dummy command buffer.
|
||||
submitPendingCommands(mContext);
|
||||
id<MTLCommandBuffer> oneOffBuffer = [mContext->commandQueue commandBuffer];
|
||||
@@ -310,16 +279,10 @@ void MetalDriver::finish(int) {
|
||||
[oneOffBuffer waitUntilCompleted];
|
||||
}
|
||||
|
||||
void MetalDriver::createVertexBufferInfoR(Handle<HwVertexBufferInfo> vbih, uint8_t bufferCount,
|
||||
uint8_t attributeCount, AttributeArray attributes) {
|
||||
construct_handle<MetalVertexBufferInfo>(vbih, *mContext,
|
||||
bufferCount, attributeCount, attributes);
|
||||
}
|
||||
|
||||
void MetalDriver::createVertexBufferR(Handle<HwVertexBuffer> vbh,
|
||||
uint32_t vertexCount, Handle<HwVertexBufferInfo> vbih) {
|
||||
MetalVertexBufferInfo const* const vbi = handle_cast<const MetalVertexBufferInfo>(vbih);
|
||||
construct_handle<MetalVertexBuffer>(vbh, *mContext, vertexCount, vbi->bufferCount, vbih);
|
||||
void MetalDriver::createVertexBufferR(Handle<HwVertexBuffer> vbh, uint8_t bufferCount,
|
||||
uint8_t attributeCount, uint32_t vertexCount, AttributeArray attributes) {
|
||||
construct_handle<MetalVertexBuffer>(vbh, *mContext, bufferCount,
|
||||
attributeCount, vertexCount, attributes);
|
||||
}
|
||||
|
||||
void MetalDriver::createIndexBufferR(Handle<HwIndexBuffer> ibh, ElementType elementType,
|
||||
@@ -363,19 +326,19 @@ void MetalDriver::importTextureR(Handle<HwTexture> th, intptr_t i,
|
||||
TextureFormat format, uint8_t samples, uint32_t width, uint32_t height,
|
||||
uint32_t depth, TextureUsage usage) {
|
||||
id<MTLTexture> metalTexture = (id<MTLTexture>) CFBridgingRelease((void*) i);
|
||||
FILAMENT_CHECK_PRECONDITION(metalTexture.width == width)
|
||||
<< "Imported id<MTLTexture> width (" << metalTexture.width
|
||||
<< ") != Filament texture width (" << width << ")";
|
||||
FILAMENT_CHECK_PRECONDITION(metalTexture.height == height)
|
||||
<< "Imported id<MTLTexture> height (" << metalTexture.height
|
||||
<< ") != Filament texture height (" << height << ")";
|
||||
FILAMENT_CHECK_PRECONDITION(metalTexture.mipmapLevelCount == levels)
|
||||
<< "Imported id<MTLTexture> levels (" << metalTexture.mipmapLevelCount
|
||||
<< ") != Filament texture levels (" << levels << ")";
|
||||
ASSERT_PRECONDITION(metalTexture.width == width,
|
||||
"Imported id<MTLTexture> width (%d) != Filament texture width (%d)",
|
||||
metalTexture.width, width);
|
||||
ASSERT_PRECONDITION(metalTexture.height == height,
|
||||
"Imported id<MTLTexture> height (%d) != Filament texture height (%d)",
|
||||
metalTexture.height, height);
|
||||
ASSERT_PRECONDITION(metalTexture.mipmapLevelCount == levels,
|
||||
"Imported id<MTLTexture> levels (%d) != Filament texture levels (%d)",
|
||||
metalTexture.mipmapLevelCount, levels);
|
||||
MTLTextureType filamentMetalType = getMetalType(target);
|
||||
FILAMENT_CHECK_PRECONDITION(metalTexture.textureType == filamentMetalType)
|
||||
<< "Imported id<MTLTexture> type (" << metalTexture.textureType
|
||||
<< ") != Filament texture type (" << filamentMetalType << ")";
|
||||
ASSERT_PRECONDITION(metalTexture.textureType == filamentMetalType,
|
||||
"Imported id<MTLTexture> type (%d) != Filament texture type (%d)",
|
||||
metalTexture.textureType, filamentMetalType);
|
||||
mContext->textures.insert(construct_handle<MetalTexture>(th, *mContext,
|
||||
target, levels, format, samples, width, height, depth, usage, metalTexture));
|
||||
}
|
||||
@@ -387,9 +350,11 @@ void MetalDriver::createSamplerGroupR(
|
||||
|
||||
void MetalDriver::createRenderPrimitiveR(Handle<HwRenderPrimitive> rph,
|
||||
Handle<HwVertexBuffer> vbh, Handle<HwIndexBuffer> ibh,
|
||||
PrimitiveType pt) {
|
||||
PrimitiveType pt, uint32_t offset,
|
||||
uint32_t minIndex, uint32_t maxIndex, uint32_t count) {
|
||||
construct_handle<MetalRenderPrimitive>(rph);
|
||||
MetalDriver::setRenderPrimitiveBuffer(rph, pt, vbh, ibh);
|
||||
MetalDriver::setRenderPrimitiveBuffer(rph, vbh, ibh);
|
||||
MetalDriver::setRenderPrimitiveRange(rph, pt, offset, minIndex, maxIndex, count);
|
||||
}
|
||||
|
||||
void MetalDriver::createProgramR(Handle<HwProgram> rph, Program&& program) {
|
||||
@@ -402,10 +367,10 @@ void MetalDriver::createDefaultRenderTargetR(Handle<HwRenderTarget> rth, int dum
|
||||
|
||||
void MetalDriver::createRenderTargetR(Handle<HwRenderTarget> rth,
|
||||
TargetBufferFlags targetBufferFlags, uint32_t width, uint32_t height,
|
||||
uint8_t samples, uint8_t layerCount, MRT color,
|
||||
uint8_t samples, MRT color,
|
||||
TargetBufferInfo depth, TargetBufferInfo stencil) {
|
||||
FILAMENT_CHECK_PRECONDITION(!isInRenderPass(mContext))
|
||||
<< "createRenderTarget must be called outside of a render pass.";
|
||||
ASSERT_PRECONDITION(!isInRenderPass(mContext),
|
||||
"createRenderTarget must be called outside of a render pass.");
|
||||
// Clamp sample count to what the device supports.
|
||||
auto& sc = mContext->sampleCountLookup;
|
||||
samples = sc[std::min(MAX_SAMPLE_COUNT, samples)];
|
||||
@@ -416,33 +381,33 @@ void MetalDriver::createRenderTargetR(Handle<HwRenderTarget> rth,
|
||||
continue;
|
||||
}
|
||||
const auto& buffer = color[i];
|
||||
FILAMENT_CHECK_PRECONDITION(buffer.handle)
|
||||
<< "The COLOR" << i << " flag was specified, but invalid color handle provided.";
|
||||
ASSERT_PRECONDITION(buffer.handle,
|
||||
"The COLOR%u flag was specified, but invalid color handle provided.", i);
|
||||
auto colorTexture = handle_cast<MetalTexture>(buffer.handle);
|
||||
FILAMENT_CHECK_PRECONDITION(colorTexture->getMtlTextureForWrite())
|
||||
<< "Color texture passed to render target has no texture allocation";
|
||||
ASSERT_PRECONDITION(colorTexture->getMtlTextureForWrite(),
|
||||
"Color texture passed to render target has no texture allocation");
|
||||
colorTexture->extendLodRangeTo(buffer.level);
|
||||
colorAttachments[i] = { colorTexture, color[i].level, color[i].layer };
|
||||
}
|
||||
|
||||
MetalRenderTarget::Attachment depthAttachment = {};
|
||||
if (any(targetBufferFlags & TargetBufferFlags::DEPTH)) {
|
||||
FILAMENT_CHECK_PRECONDITION(depth.handle)
|
||||
<< "The DEPTH flag was specified, but invalid depth handle provided.";
|
||||
ASSERT_PRECONDITION(depth.handle,
|
||||
"The DEPTH flag was specified, but invalid depth handle provided.");
|
||||
auto depthTexture = handle_cast<MetalTexture>(depth.handle);
|
||||
FILAMENT_CHECK_PRECONDITION(depthTexture->getMtlTextureForWrite())
|
||||
<< "Depth texture passed to render target has no texture allocation.";
|
||||
ASSERT_PRECONDITION(depthTexture->getMtlTextureForWrite(),
|
||||
"Depth texture passed to render target has no texture allocation.");
|
||||
depthTexture->extendLodRangeTo(depth.level);
|
||||
depthAttachment = { depthTexture, depth.level, depth.layer };
|
||||
}
|
||||
|
||||
MetalRenderTarget::Attachment stencilAttachment = {};
|
||||
if (any(targetBufferFlags & TargetBufferFlags::STENCIL)) {
|
||||
FILAMENT_CHECK_PRECONDITION(stencil.handle)
|
||||
<< "The STENCIL flag was specified, but invalid stencil handle provided.";
|
||||
ASSERT_PRECONDITION(stencil.handle,
|
||||
"The STENCIL flag was specified, but invalid stencil handle provided.");
|
||||
auto stencilTexture = handle_cast<MetalTexture>(stencil.handle);
|
||||
FILAMENT_CHECK_PRECONDITION(stencilTexture->getMtlTextureForWrite())
|
||||
<< "Stencil texture passed to render target has no texture allocation.";
|
||||
ASSERT_PRECONDITION(stencilTexture->getMtlTextureForWrite(),
|
||||
"Stencil texture passed to render target has no texture allocation.");
|
||||
stencilTexture->extendLodRangeTo(stencil.level);
|
||||
stencilAttachment = { stencilTexture, stencil.level, stencil.layer };
|
||||
}
|
||||
@@ -475,10 +440,6 @@ void MetalDriver::createTimerQueryR(Handle<HwTimerQuery> tqh, int) {
|
||||
// nothing to do, timer query was constructed in createTimerQueryS
|
||||
}
|
||||
|
||||
Handle<HwVertexBufferInfo> MetalDriver::createVertexBufferInfoS() noexcept {
|
||||
return alloc_handle<MetalVertexBufferInfo>();
|
||||
}
|
||||
|
||||
Handle<HwVertexBuffer> MetalDriver::createVertexBufferS() noexcept {
|
||||
return alloc_handle<MetalVertexBuffer>();
|
||||
}
|
||||
@@ -543,12 +504,6 @@ Handle<HwTimerQuery> MetalDriver::createTimerQueryS() noexcept {
|
||||
return alloc_and_construct_handle<MetalTimerQuery, HwTimerQuery>();
|
||||
}
|
||||
|
||||
void MetalDriver::destroyVertexBufferInfo(Handle<HwVertexBufferInfo> vbih) {
|
||||
if (vbih) {
|
||||
destruct_handle<MetalVertexBufferInfo>(vbih);
|
||||
}
|
||||
}
|
||||
|
||||
void MetalDriver::destroyVertexBuffer(Handle<HwVertexBuffer> vbh) {
|
||||
if (vbh) {
|
||||
destruct_handle<MetalVertexBuffer>(vbh);
|
||||
@@ -801,36 +756,15 @@ bool MetalDriver::isSRGBSwapChainSupported() {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool MetalDriver::isProtectedContentSupported() {
|
||||
// the SWAP_CHAIN_CONFIG_PROTECTED_CONTENT flag is not supported
|
||||
return false;
|
||||
}
|
||||
|
||||
bool MetalDriver::isStereoSupported() {
|
||||
switch (mStereoscopicType) {
|
||||
case backend::StereoscopicType::INSTANCED:
|
||||
return true;
|
||||
case backend::StereoscopicType::MULTIVIEW:
|
||||
// TODO: implement multiview feature in Metal.
|
||||
return false;
|
||||
case backend::StereoscopicType::NONE:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool MetalDriver::isParallelShaderCompileSupported() {
|
||||
return mContext->shaderCompiler->isParallelShaderCompileSupported();
|
||||
}
|
||||
|
||||
bool MetalDriver::isDepthStencilResolveSupported() {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool MetalDriver::isDepthStencilBlitSupported(TextureFormat format) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MetalDriver::isProtectedTexturesSupported() {
|
||||
bool MetalDriver::isParallelShaderCompileSupported() {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MetalDriver::isDepthStencilResolveSupported() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -842,8 +776,8 @@ bool MetalDriver::isWorkaroundNeeded(Workaround workaround) {
|
||||
return true;
|
||||
case Workaround::ADRENO_UNIFORM_ARRAY_CRASH:
|
||||
return false;
|
||||
case Workaround::METAL_STATIC_TEXTURE_TARGET_ERROR:
|
||||
return mContext->bugs.staticTextureTargetError;
|
||||
case Workaround::A8X_STATIC_TEXTURE_TARGET_ERROR:
|
||||
return mContext->bugs.a8xStaticTextureTargetError;
|
||||
case Workaround::DISABLE_BLIT_INTO_TEXTURE_ARRAY:
|
||||
return false;
|
||||
default:
|
||||
@@ -887,8 +821,8 @@ void MetalDriver::updateIndexBuffer(Handle<HwIndexBuffer> ibh, BufferDescriptor&
|
||||
|
||||
void MetalDriver::updateBufferObject(Handle<HwBufferObject> boh, BufferDescriptor&& data,
|
||||
uint32_t byteOffset) {
|
||||
FILAMENT_CHECK_PRECONDITION(!isInRenderPass(mContext))
|
||||
<< "updateBufferObject must be called outside of a render pass.";
|
||||
ASSERT_PRECONDITION(!isInRenderPass(mContext),
|
||||
"updateBufferObject must be called outside of a render pass.");
|
||||
auto* bo = handle_cast<MetalBufferObject>(boh);
|
||||
bo->updateBuffer(data.buffer, data.size, byteOffset);
|
||||
scheduleDestroy(std::move(data));
|
||||
@@ -927,8 +861,8 @@ void MetalDriver::update3DImage(Handle<HwTexture> th, uint32_t level,
|
||||
uint32_t xoffset, uint32_t yoffset, uint32_t zoffset,
|
||||
uint32_t width, uint32_t height, uint32_t depth,
|
||||
PixelBufferDescriptor&& data) {
|
||||
FILAMENT_CHECK_PRECONDITION(!isInRenderPass(mContext))
|
||||
<< "update3DImage must be called outside of a render pass.";
|
||||
ASSERT_PRECONDITION(!isInRenderPass(mContext),
|
||||
"update3DImage must be called outside of a render pass.");
|
||||
auto tex = handle_cast<MetalTexture>(th);
|
||||
tex->loadImage(level, MTLRegionMake3D(xoffset, yoffset, zoffset, width, height, depth), data);
|
||||
scheduleDestroy(std::move(data));
|
||||
@@ -944,15 +878,15 @@ void MetalDriver::setupExternalImage(void* image) {
|
||||
}
|
||||
|
||||
void MetalDriver::setExternalImage(Handle<HwTexture> th, void* image) {
|
||||
FILAMENT_CHECK_PRECONDITION(!isInRenderPass(mContext))
|
||||
<< "setExternalImage must be called outside of a render pass.";
|
||||
ASSERT_PRECONDITION(!isInRenderPass(mContext),
|
||||
"setExternalImage must be called outside of a render pass.");
|
||||
auto texture = handle_cast<MetalTexture>(th);
|
||||
texture->externalImage.set((CVPixelBufferRef) image);
|
||||
}
|
||||
|
||||
void MetalDriver::setExternalImagePlane(Handle<HwTexture> th, void* image, uint32_t plane) {
|
||||
FILAMENT_CHECK_PRECONDITION(!isInRenderPass(mContext))
|
||||
<< "setExternalImagePlane must be called outside of a render pass.";
|
||||
ASSERT_PRECONDITION(!isInRenderPass(mContext),
|
||||
"setExternalImagePlane must be called outside of a render pass.");
|
||||
auto texture = handle_cast<MetalTexture>(th);
|
||||
texture->externalImage.set((CVPixelBufferRef) image, plane);
|
||||
}
|
||||
@@ -960,22 +894,21 @@ void MetalDriver::setExternalImagePlane(Handle<HwTexture> th, void* image, uint3
|
||||
void MetalDriver::setExternalStream(Handle<HwTexture> th, Handle<HwStream> sh) {
|
||||
}
|
||||
|
||||
TimerQueryResult MetalDriver::getTimerQueryValue(Handle<HwTimerQuery> tqh, uint64_t* elapsedTime) {
|
||||
bool MetalDriver::getTimerQueryValue(Handle<HwTimerQuery> tqh, uint64_t* elapsedTime) {
|
||||
auto* tq = handle_cast<MetalTimerQuery>(tqh);
|
||||
return mContext->timerQueryImpl->getQueryResult(tq, elapsedTime) ?
|
||||
TimerQueryResult::AVAILABLE : TimerQueryResult::NOT_READY;
|
||||
return mContext->timerQueryImpl->getQueryResult(tq, elapsedTime);
|
||||
}
|
||||
|
||||
void MetalDriver::generateMipmaps(Handle<HwTexture> th) {
|
||||
FILAMENT_CHECK_PRECONDITION(!isInRenderPass(mContext))
|
||||
<< "generateMipmaps must be called outside of a render pass.";
|
||||
ASSERT_PRECONDITION(!isInRenderPass(mContext),
|
||||
"generateMipmaps must be called outside of a render pass.");
|
||||
auto tex = handle_cast<MetalTexture>(th);
|
||||
tex->generateMipmaps();
|
||||
}
|
||||
|
||||
void MetalDriver::updateSamplerGroup(Handle<HwSamplerGroup> sbh, BufferDescriptor&& data) {
|
||||
FILAMENT_CHECK_PRECONDITION(!isInRenderPass(mContext))
|
||||
<< "updateSamplerGroup must be called outside of a render pass.";
|
||||
ASSERT_PRECONDITION(!isInRenderPass(mContext),
|
||||
"updateSamplerGroup must be called outside of a render pass.");
|
||||
|
||||
auto sb = handle_cast<MetalSamplerGroup>(sbh);
|
||||
assert_invariant(sb->size == data.size / sizeof(SamplerDescriptor));
|
||||
@@ -1114,10 +1047,6 @@ void MetalDriver::beginRenderPass(Handle<HwRenderTarget> rth,
|
||||
mContext->currentPolygonOffset = {0.0f, 0.0f};
|
||||
|
||||
mContext->finalizedSamplerGroups.clear();
|
||||
|
||||
for (auto& pc : mContext->currentPushConstants) {
|
||||
pc.clear();
|
||||
}
|
||||
}
|
||||
|
||||
void MetalDriver::nextSubpass(int dummy) {}
|
||||
@@ -1134,14 +1063,23 @@ void MetalDriver::endRenderPass(int dummy) {
|
||||
mContext->currentRenderPassEncoder = nil;
|
||||
}
|
||||
|
||||
void MetalDriver::setRenderPrimitiveBuffer(Handle<HwRenderPrimitive> rph, PrimitiveType pt,
|
||||
void MetalDriver::setRenderPrimitiveBuffer(Handle<HwRenderPrimitive> rph,
|
||||
Handle<HwVertexBuffer> vbh, Handle<HwIndexBuffer> ibh) {
|
||||
auto primitive = handle_cast<MetalRenderPrimitive>(rph);
|
||||
auto vertexBuffer = handle_cast<MetalVertexBuffer>(vbh);
|
||||
auto indexBuffer = handle_cast<MetalIndexBuffer>(ibh);
|
||||
MetalVertexBufferInfo const* const vbi = handle_cast<MetalVertexBufferInfo>(vertexBuffer->vbih);
|
||||
primitive->setBuffers(vbi, vertexBuffer, indexBuffer);
|
||||
primitive->setBuffers(vertexBuffer, indexBuffer);
|
||||
}
|
||||
|
||||
void MetalDriver::setRenderPrimitiveRange(Handle<HwRenderPrimitive> rph,
|
||||
PrimitiveType pt, uint32_t offset, uint32_t minIndex, uint32_t maxIndex,
|
||||
uint32_t count) {
|
||||
auto primitive = handle_cast<MetalRenderPrimitive>(rph);
|
||||
primitive->type = pt;
|
||||
primitive->offset = offset * primitive->indexBuffer->elementSize;
|
||||
primitive->count = count;
|
||||
primitive->minIndex = minIndex;
|
||||
primitive->maxIndex = maxIndex > minIndex ? maxIndex : primitive->maxVertexCount - 1;
|
||||
}
|
||||
|
||||
void MetalDriver::makeCurrent(Handle<HwSwapChain> schDraw, Handle<HwSwapChain> schRead) {
|
||||
@@ -1265,16 +1203,6 @@ void MetalDriver::bindSamplers(uint32_t index, Handle<HwSamplerGroup> sbh) {
|
||||
mContext->samplerBindings[index] = sb;
|
||||
}
|
||||
|
||||
void MetalDriver::setPushConstant(backend::ShaderStage stage, uint8_t index,
|
||||
backend::PushConstantVariant value) {
|
||||
FILAMENT_CHECK_PRECONDITION(isInRenderPass(mContext))
|
||||
<< "setPushConstant must be called inside a render pass.";
|
||||
assert_invariant(static_cast<size_t>(stage) < mContext->currentPushConstants.size());
|
||||
MetalPushConstantBuffer& pushConstants =
|
||||
mContext->currentPushConstants[static_cast<size_t>(stage)];
|
||||
pushConstants.setPushConstant(value, index);
|
||||
}
|
||||
|
||||
void MetalDriver::insertEventMarker(const char* string, uint32_t len) {
|
||||
|
||||
}
|
||||
@@ -1325,8 +1253,8 @@ void MetalDriver::stopCapture(int) {
|
||||
|
||||
void MetalDriver::readPixels(Handle<HwRenderTarget> src, uint32_t x, uint32_t y, uint32_t width,
|
||||
uint32_t height, PixelBufferDescriptor&& data) {
|
||||
FILAMENT_CHECK_PRECONDITION(!isInRenderPass(mContext))
|
||||
<< "readPixels must be called outside of a render pass.";
|
||||
ASSERT_PRECONDITION(!isInRenderPass(mContext),
|
||||
"readPixels must be called outside of a render pass.");
|
||||
|
||||
auto srcTarget = handle_cast<MetalRenderTarget>(src);
|
||||
// We always readPixels from the COLOR0 attachment.
|
||||
@@ -1340,19 +1268,17 @@ void MetalDriver::readPixels(Handle<HwRenderTarget> src, uint32_t x, uint32_t y,
|
||||
width = std::min(static_cast<uint32_t>(srcTextureSize.width), width);
|
||||
|
||||
const MTLPixelFormat format = getMetalFormat(data.format, data.type);
|
||||
FILAMENT_CHECK_PRECONDITION(format != MTLPixelFormatInvalid)
|
||||
<< "The chosen combination of PixelDataFormat (" << (int)data.format
|
||||
<< ") and PixelDataType (" << (int)data.type
|
||||
<< ") is not supported for "
|
||||
"readPixels.";
|
||||
ASSERT_PRECONDITION(format != MTLPixelFormatInvalid,
|
||||
"The chosen combination of PixelDataFormat (%d) and PixelDataType (%d) is not supported for "
|
||||
"readPixels.", (int) data.format, (int) data.type);
|
||||
|
||||
const bool formatConversionNecessary = srcTexture.pixelFormat != format;
|
||||
|
||||
// TODO: MetalBlitter does not currently support format conversions to integer types.
|
||||
// The format and type must match the source pixel format exactly.
|
||||
FILAMENT_CHECK_PRECONDITION(!formatConversionNecessary || !isMetalFormatInteger(format))
|
||||
<< "readPixels does not support integer format conversions from MTLPixelFormat ("
|
||||
<< (int)srcTexture.pixelFormat << ") to (" << (int)format << ").";
|
||||
ASSERT_PRECONDITION(!formatConversionNecessary || !isMetalFormatInteger(format),
|
||||
"readPixels does not support integer format conversions from MTLPixelFormat (%d) to (%d).",
|
||||
(int) srcTexture.pixelFormat, (int) format);
|
||||
|
||||
MTLTextureDescriptor* textureDescriptor =
|
||||
[MTLTextureDescriptor texture2DDescriptorWithPixelFormat:format
|
||||
@@ -1418,31 +1344,31 @@ void MetalDriver::resolve(
|
||||
assert_invariant(srcTexture);
|
||||
assert_invariant(dstTexture);
|
||||
|
||||
FILAMENT_CHECK_PRECONDITION(mContext->currentRenderPassEncoder == nil)
|
||||
<< "resolve() cannot be invoked inside a render pass.";
|
||||
ASSERT_PRECONDITION(mContext->currentRenderPassEncoder == nil,
|
||||
"resolve() cannot be invoked inside a render pass.");
|
||||
|
||||
FILAMENT_CHECK_PRECONDITION(
|
||||
dstTexture->width == srcTexture->width && dstTexture->height == srcTexture->height)
|
||||
<< "invalid resolve: src and dst sizes don't match";
|
||||
ASSERT_PRECONDITION(
|
||||
dstTexture->width == srcTexture->width && dstTexture->height == srcTexture->height,
|
||||
"invalid resolve: src and dst sizes don't match");
|
||||
|
||||
FILAMENT_CHECK_PRECONDITION(srcTexture->samples > 1 && dstTexture->samples == 1)
|
||||
<< "invalid resolve: src.samples=" << +srcTexture->samples
|
||||
<< ", dst.samples=" << +dstTexture->samples;
|
||||
ASSERT_PRECONDITION(srcTexture->samples > 1 && dstTexture->samples == 1,
|
||||
"invalid resolve: src.samples=%u, dst.samples=%u",
|
||||
+srcTexture->samples, +dstTexture->samples);
|
||||
|
||||
FILAMENT_CHECK_PRECONDITION(srcTexture->format == dstTexture->format)
|
||||
<< "src and dst texture format don't match";
|
||||
ASSERT_PRECONDITION(srcTexture->format == dstTexture->format,
|
||||
"src and dst texture format don't match");
|
||||
|
||||
FILAMENT_CHECK_PRECONDITION(!isDepthFormat(srcTexture->format))
|
||||
<< "can't resolve depth formats";
|
||||
ASSERT_PRECONDITION(!isDepthFormat(srcTexture->format),
|
||||
"can't resolve depth formats");
|
||||
|
||||
FILAMENT_CHECK_PRECONDITION(!isStencilFormat(srcTexture->format))
|
||||
<< "can't resolve stencil formats";
|
||||
ASSERT_PRECONDITION(!isStencilFormat(srcTexture->format),
|
||||
"can't resolve stencil formats");
|
||||
|
||||
FILAMENT_CHECK_PRECONDITION(any(dstTexture->usage & TextureUsage::BLIT_DST))
|
||||
<< "texture doesn't have BLIT_DST";
|
||||
ASSERT_PRECONDITION(any(dstTexture->usage & TextureUsage::BLIT_DST),
|
||||
"texture doesn't have BLIT_DST");
|
||||
|
||||
FILAMENT_CHECK_PRECONDITION(any(srcTexture->usage & TextureUsage::BLIT_SRC))
|
||||
<< "texture doesn't have BLIT_SRC";
|
||||
ASSERT_PRECONDITION(any(srcTexture->usage & TextureUsage::BLIT_SRC),
|
||||
"texture doesn't have BLIT_SRC");
|
||||
|
||||
// FIXME: on metal the blit() call below always take the slow path (using a shader)
|
||||
|
||||
@@ -1467,22 +1393,21 @@ void MetalDriver::blit(
|
||||
assert_invariant(srcTexture);
|
||||
assert_invariant(dstTexture);
|
||||
|
||||
FILAMENT_CHECK_PRECONDITION(mContext->currentRenderPassEncoder == nil)
|
||||
<< "blit() cannot be invoked inside a render pass.";
|
||||
ASSERT_PRECONDITION(mContext->currentRenderPassEncoder == nil,
|
||||
"blit() cannot be invoked inside a render pass.");
|
||||
|
||||
FILAMENT_CHECK_PRECONDITION(any(dstTexture->usage & TextureUsage::BLIT_DST))
|
||||
<< "texture doesn't have BLIT_DST";
|
||||
ASSERT_PRECONDITION(any(dstTexture->usage & TextureUsage::BLIT_DST),
|
||||
"texture doesn't have BLIT_DST");
|
||||
|
||||
FILAMENT_CHECK_PRECONDITION(any(srcTexture->usage & TextureUsage::BLIT_SRC))
|
||||
<< "texture doesn't have BLIT_SRC";
|
||||
ASSERT_PRECONDITION(any(srcTexture->usage & TextureUsage::BLIT_SRC),
|
||||
"texture doesn't have BLIT_SRC");
|
||||
|
||||
FILAMENT_CHECK_PRECONDITION(srcTexture->format == dstTexture->format)
|
||||
<< "src and dst texture format don't match";
|
||||
ASSERT_PRECONDITION(srcTexture->format == dstTexture->format,
|
||||
"src and dst texture format don't match");
|
||||
|
||||
FILAMENT_CHECK_PRECONDITION(
|
||||
isBlitableTextureType(srcTexture->getMtlTextureForRead().textureType) &&
|
||||
isBlitableTextureType(dstTexture->getMtlTextureForWrite().textureType))
|
||||
<< "Metal does not support blitting to/from non-2D textures.";
|
||||
ASSERT_PRECONDITION(isBlitableTextureType(srcTexture->getMtlTextureForRead().textureType) &&
|
||||
isBlitableTextureType(dstTexture->getMtlTextureForWrite().textureType),
|
||||
"Metal does not support blitting to/from non-2D textures.");
|
||||
|
||||
MetalBlitter::BlitArgs args{};
|
||||
args.filter = SamplerMagFilter::NEAREST;
|
||||
@@ -1520,18 +1445,18 @@ void MetalDriver::blitDEPRECATED(TargetBufferFlags buffers,
|
||||
// It is called between beginFrame and endFrame, but should never be called in the middle of
|
||||
// a render pass.
|
||||
|
||||
FILAMENT_CHECK_PRECONDITION(mContext->currentRenderPassEncoder == nil)
|
||||
<< "blitDEPRECATED() cannot be invoked inside a render pass.";
|
||||
ASSERT_PRECONDITION(mContext->currentRenderPassEncoder == nil,
|
||||
"blitDEPRECATED() cannot be invoked inside a render pass.");
|
||||
|
||||
auto srcTarget = handle_cast<MetalRenderTarget>(src);
|
||||
auto dstTarget = handle_cast<MetalRenderTarget>(dst);
|
||||
|
||||
FILAMENT_CHECK_PRECONDITION(buffers == TargetBufferFlags::COLOR0)
|
||||
<< "blitDEPRECATED only supports COLOR0";
|
||||
ASSERT_PRECONDITION(buffers == TargetBufferFlags::COLOR0,
|
||||
"blitDEPRECATED only supports COLOR0");
|
||||
|
||||
FILAMENT_CHECK_PRECONDITION(
|
||||
srcRect.left >= 0 && srcRect.bottom >= 0 && dstRect.left >= 0 && dstRect.bottom >= 0)
|
||||
<< "Source and destination rects must be positive.";
|
||||
ASSERT_PRECONDITION(srcRect.left >= 0 && srcRect.bottom >= 0 &&
|
||||
dstRect.left >= 0 && dstRect.bottom >= 0,
|
||||
"Source and destination rects must be positive.");
|
||||
|
||||
auto isBlitableTextureType = [](MTLTextureType t) {
|
||||
return t == MTLTextureType2D || t == MTLTextureType2DMultisample ||
|
||||
@@ -1543,10 +1468,9 @@ void MetalDriver::blitDEPRECATED(TargetBufferFlags buffers,
|
||||
MetalRenderTarget::Attachment const dstColorAttachment = dstTarget->getDrawColorAttachment(0);
|
||||
|
||||
if (srcColorAttachment && dstColorAttachment) {
|
||||
FILAMENT_CHECK_PRECONDITION(
|
||||
isBlitableTextureType(srcColorAttachment.getTexture().textureType) &&
|
||||
isBlitableTextureType(dstColorAttachment.getTexture().textureType))
|
||||
<< "Metal does not support blitting to/from non-2D textures.";
|
||||
ASSERT_PRECONDITION(isBlitableTextureType(srcColorAttachment.getTexture().textureType) &&
|
||||
isBlitableTextureType(dstColorAttachment.getTexture().textureType),
|
||||
"Metal does not support blitting to/from non-2D textures.");
|
||||
|
||||
MetalBlitter::BlitArgs args{};
|
||||
args.filter = filter;
|
||||
@@ -1657,13 +1581,10 @@ void MetalDriver::finalizeSamplerGroup(MetalSamplerGroup* samplerGroup) {
|
||||
}
|
||||
}
|
||||
|
||||
void MetalDriver::bindPipeline(PipelineState const& ps) {
|
||||
FILAMENT_CHECK_PRECONDITION(mContext->currentRenderPassEncoder != nullptr)
|
||||
<< "bindPipeline() without a valid command encoder.";
|
||||
|
||||
MetalVertexBufferInfo const* const vbi =
|
||||
handle_cast<MetalVertexBufferInfo>(ps.vertexBufferInfo);
|
||||
|
||||
void MetalDriver::draw(PipelineState ps, Handle<HwRenderPrimitive> rph, uint32_t instanceCount) {
|
||||
ASSERT_PRECONDITION(mContext->currentRenderPassEncoder != nullptr,
|
||||
"Attempted to draw without a valid command encoder.");
|
||||
auto primitive = handle_cast<MetalRenderPrimitive>(rph);
|
||||
auto program = handle_cast<MetalProgram>(ps.program);
|
||||
const auto& rs = ps.rasterState;
|
||||
|
||||
@@ -1677,7 +1598,7 @@ void MetalDriver::bindPipeline(PipelineState const& ps) {
|
||||
return;
|
||||
}
|
||||
|
||||
functions.validate();
|
||||
ASSERT_PRECONDITION(bool(functions), "Attempting to draw with an invalid Metal program.");
|
||||
|
||||
auto [fragment, vertex] = functions.getRasterFunctions();
|
||||
|
||||
@@ -1704,7 +1625,7 @@ void MetalDriver::bindPipeline(PipelineState const& ps) {
|
||||
MetalPipelineState const pipelineState {
|
||||
.vertexFunction = vertex,
|
||||
.fragmentFunction = fragment,
|
||||
.vertexDescription = vbi->vertexDescription,
|
||||
.vertexDescription = primitive->vertexDescription,
|
||||
.colorAttachmentPixelFormat = {
|
||||
colorPixelFormat[0],
|
||||
colorPixelFormat[1],
|
||||
@@ -1798,6 +1719,50 @@ void MetalDriver::bindPipeline(PipelineState const& ps) {
|
||||
mContext->currentPolygonOffset = ps.polygonOffset;
|
||||
}
|
||||
|
||||
// Set scissor-rectangle.
|
||||
// In order to do this, we compute the intersection between:
|
||||
// 1. the scissor rectangle
|
||||
// 2. the render target attachment dimensions (important, as the scissor can't be set larger)
|
||||
// fmax/min are used below to guard against NaN and because the MTLViewport/MTLRegion
|
||||
// coordinates are doubles.
|
||||
MTLRegion scissor = mContext->currentRenderTarget->getRegionFromClientRect(ps.scissor);
|
||||
const float sleft = scissor.origin.x, sright = scissor.origin.x + scissor.size.width;
|
||||
const float stop = scissor.origin.y, sbottom = scissor.origin.y + scissor.size.height;
|
||||
|
||||
// Attachment extent
|
||||
const auto attachmentSize = mContext->currentRenderTarget->getAttachmentSize();
|
||||
const float aleft = 0.0f, atop = 0.0f;
|
||||
const float aright = static_cast<float>(attachmentSize.x);
|
||||
const float abottom = static_cast<float>(attachmentSize.y);
|
||||
|
||||
const auto left = std::fmax(sleft, aleft);
|
||||
const auto right = std::fmin(sright, aright);
|
||||
const auto top = std::fmax(stop, atop);
|
||||
const auto bottom = std::fmin(sbottom, abottom);
|
||||
|
||||
MTLScissorRect scissorRect = {
|
||||
.x = static_cast<NSUInteger>(left),
|
||||
.y = static_cast<NSUInteger>(top),
|
||||
.width = static_cast<NSUInteger>(right - left),
|
||||
.height = static_cast<NSUInteger>(bottom - top)
|
||||
};
|
||||
|
||||
[mContext->currentRenderPassEncoder setScissorRect:scissorRect];
|
||||
|
||||
// Bind uniform buffers.
|
||||
MetalBuffer* uniformsToBind[Program::UNIFORM_BINDING_COUNT] = { nil };
|
||||
NSUInteger offsets[Program::UNIFORM_BINDING_COUNT] = { 0 };
|
||||
|
||||
enumerateBoundBuffers(BufferObjectBinding::UNIFORM,
|
||||
[&uniformsToBind, &offsets](const BufferState& state, MetalBuffer* buffer,
|
||||
uint32_t index) {
|
||||
uniformsToBind[index] = buffer;
|
||||
offsets[index] = state.offset;
|
||||
});
|
||||
MetalBuffer::bindBuffers(getPendingCommandBuffer(mContext), mContext->currentRenderPassEncoder,
|
||||
UNIFORM_BUFFER_BINDING_START, MetalBuffer::Stage::VERTEX | MetalBuffer::Stage::FRAGMENT,
|
||||
uniformsToBind, offsets, Program::UNIFORM_BINDING_COUNT);
|
||||
|
||||
// Bind sampler groups (argument buffers).
|
||||
for (size_t s = 0; s < Program::SAMPLER_BINDING_COUNT; s++) {
|
||||
MetalSamplerGroup* const samplerGroup = mContext->samplerBindings[s];
|
||||
@@ -1828,29 +1793,19 @@ void MetalDriver::bindPipeline(PipelineState const& ps) {
|
||||
atIndex:(SAMPLER_GROUP_BINDING_START + s)];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MetalDriver::bindRenderPrimitive(Handle<HwRenderPrimitive> rph) {
|
||||
FILAMENT_CHECK_PRECONDITION(mContext->currentRenderPassEncoder != nullptr)
|
||||
<< "bindRenderPrimitive() without a valid command encoder.";
|
||||
|
||||
// Bind the user vertex buffers.
|
||||
|
||||
MetalBuffer* vertexBuffers[MAX_VERTEX_BUFFER_COUNT] = {};
|
||||
size_t vertexBufferOffsets[MAX_VERTEX_BUFFER_COUNT] = {};
|
||||
size_t maxBufferIndex = 0;
|
||||
|
||||
MetalRenderPrimitive const* const primitive = handle_cast<MetalRenderPrimitive>(rph);
|
||||
MetalVertexBufferInfo const* const vbi =
|
||||
handle_cast<MetalVertexBufferInfo>(primitive->vertexBuffer->vbih);
|
||||
|
||||
mContext->currentRenderPrimitive = rph;
|
||||
|
||||
auto vb = primitive->vertexBuffer;
|
||||
for (auto m : vbi->bufferMapping) {
|
||||
for (auto m : primitive->bufferMapping) {
|
||||
assert_invariant(
|
||||
m.bufferArgumentIndex >= USER_VERTEX_BUFFER_BINDING_START &&
|
||||
m.bufferArgumentIndex < USER_VERTEX_BUFFER_BINDING_START + MAX_VERTEX_BUFFER_COUNT);
|
||||
size_t const vertexBufferIndex = m.bufferArgumentIndex - USER_VERTEX_BUFFER_BINDING_START;
|
||||
size_t vertexBufferIndex = m.bufferArgumentIndex - USER_VERTEX_BUFFER_BINDING_START;
|
||||
vertexBuffers[vertexBufferIndex] = vb->buffers[m.sourceBufferIndex];
|
||||
maxBufferIndex = std::max(maxBufferIndex, vertexBufferIndex);
|
||||
}
|
||||
@@ -1865,61 +1820,22 @@ void MetalDriver::bindRenderPrimitive(Handle<HwRenderPrimitive> rph) {
|
||||
[mContext->currentRenderPassEncoder setVertexBytes:bytes
|
||||
length:16
|
||||
atIndex:ZERO_VERTEX_BUFFER_BINDING];
|
||||
}
|
||||
|
||||
void MetalDriver::draw2(uint32_t indexOffset, uint32_t indexCount, uint32_t instanceCount) {
|
||||
FILAMENT_CHECK_PRECONDITION(mContext->currentRenderPassEncoder != nullptr)
|
||||
<< "draw() without a valid command encoder.";
|
||||
|
||||
// Bind uniform buffers.
|
||||
MetalBuffer* uniformsToBind[Program::UNIFORM_BINDING_COUNT] = { nil };
|
||||
NSUInteger offsets[Program::UNIFORM_BINDING_COUNT] = { 0 };
|
||||
|
||||
enumerateBoundBuffers(BufferObjectBinding::UNIFORM,
|
||||
[&uniformsToBind, &offsets](const BufferState& state, MetalBuffer* buffer,
|
||||
uint32_t index) {
|
||||
uniformsToBind[index] = buffer;
|
||||
offsets[index] = state.offset;
|
||||
});
|
||||
MetalBuffer::bindBuffers(getPendingCommandBuffer(mContext), mContext->currentRenderPassEncoder,
|
||||
UNIFORM_BUFFER_BINDING_START, MetalBuffer::Stage::VERTEX | MetalBuffer::Stage::FRAGMENT,
|
||||
uniformsToBind, offsets, Program::UNIFORM_BINDING_COUNT);
|
||||
|
||||
// Update push constants.
|
||||
for (size_t i = 0; i < Program::SHADER_TYPE_COUNT; i++) {
|
||||
auto& pushConstants = mContext->currentPushConstants[i];
|
||||
if (UTILS_UNLIKELY(pushConstants.isDirty())) {
|
||||
pushConstants.setBytes(mContext->currentRenderPassEncoder, static_cast<ShaderStage>(i));
|
||||
}
|
||||
}
|
||||
|
||||
auto primitive = handle_cast<MetalRenderPrimitive>(mContext->currentRenderPrimitive);
|
||||
|
||||
MetalIndexBuffer* indexBuffer = primitive->indexBuffer;
|
||||
|
||||
id<MTLCommandBuffer> cmdBuffer = getPendingCommandBuffer(mContext);
|
||||
id<MTLBuffer> metalIndexBuffer = indexBuffer->buffer.getGpuBufferForDraw(cmdBuffer);
|
||||
[mContext->currentRenderPassEncoder drawIndexedPrimitives:getMetalPrimitiveType(primitive->type)
|
||||
indexCount:indexCount
|
||||
indexCount:primitive->count
|
||||
indexType:getIndexType(indexBuffer->elementSize)
|
||||
indexBuffer:metalIndexBuffer
|
||||
indexBufferOffset:indexOffset * primitive->indexBuffer->elementSize
|
||||
indexBufferOffset:primitive->offset
|
||||
instanceCount:instanceCount];
|
||||
}
|
||||
|
||||
void MetalDriver::draw(PipelineState ps, Handle<HwRenderPrimitive> rph,
|
||||
uint32_t const indexOffset, uint32_t const indexCount, uint32_t const instanceCount) {
|
||||
MetalRenderPrimitive const* const rp = handle_cast<MetalRenderPrimitive>(rph);
|
||||
ps.primitiveType = rp->type;
|
||||
ps.vertexBufferInfo = rp->vertexBuffer->vbih;
|
||||
bindPipeline(ps);
|
||||
bindRenderPrimitive(rph);
|
||||
draw2(indexOffset, indexCount, instanceCount);
|
||||
}
|
||||
|
||||
void MetalDriver::dispatchCompute(Handle<HwProgram> program, math::uint3 workGroupCount) {
|
||||
FILAMENT_CHECK_PRECONDITION(!isInRenderPass(mContext))
|
||||
<< "dispatchCompute must be called outside of a render pass.";
|
||||
ASSERT_PRECONDITION(!isInRenderPass(mContext),
|
||||
"dispatchCompute must be called outside of a render pass.");
|
||||
|
||||
auto mtlProgram = handle_cast<MetalProgram>(program);
|
||||
|
||||
@@ -1986,48 +1902,16 @@ void MetalDriver::dispatchCompute(Handle<HwProgram> program, math::uint3 workGro
|
||||
[computeEncoder endEncoding];
|
||||
}
|
||||
|
||||
void MetalDriver::scissor(Viewport scissorBox) {
|
||||
// Set scissor-rectangle.
|
||||
// In order to do this, we compute the intersection between:
|
||||
// 1. the scissor rectangle
|
||||
// 2. the render target attachment dimensions (important, as the scissor can't be set larger)
|
||||
// fmax/min are used below to guard against NaN and because the MTLViewport/MTLRegion
|
||||
// coordinates are doubles.
|
||||
MTLRegion scissor = mContext->currentRenderTarget->getRegionFromClientRect(scissorBox);
|
||||
const float sleft = scissor.origin.x, sright = scissor.origin.x + scissor.size.width;
|
||||
const float stop = scissor.origin.y, sbottom = scissor.origin.y + scissor.size.height;
|
||||
|
||||
// Attachment extent
|
||||
const auto attachmentSize = mContext->currentRenderTarget->getAttachmentSize();
|
||||
const float aleft = 0.0f, atop = 0.0f;
|
||||
const float aright = static_cast<float>(attachmentSize.x);
|
||||
const float abottom = static_cast<float>(attachmentSize.y);
|
||||
|
||||
const auto left = std::fmax(sleft, aleft);
|
||||
const auto right = std::fmin(sright, aright);
|
||||
const auto top = std::fmax(stop, atop);
|
||||
const auto bottom = std::fmin(sbottom, abottom);
|
||||
|
||||
MTLScissorRect scissorRect = {
|
||||
.x = static_cast<NSUInteger>(left),
|
||||
.y = static_cast<NSUInteger>(top),
|
||||
.width = static_cast<NSUInteger>(right - left),
|
||||
.height = static_cast<NSUInteger>(bottom - top)
|
||||
};
|
||||
|
||||
[mContext->currentRenderPassEncoder setScissorRect:scissorRect];
|
||||
}
|
||||
|
||||
void MetalDriver::beginTimerQuery(Handle<HwTimerQuery> tqh) {
|
||||
FILAMENT_CHECK_PRECONDITION(!isInRenderPass(mContext))
|
||||
<< "beginTimerQuery must be called outside of a render pass.";
|
||||
ASSERT_PRECONDITION(!isInRenderPass(mContext),
|
||||
"beginTimerQuery must be called outside of a render pass.");
|
||||
auto* tq = handle_cast<MetalTimerQuery>(tqh);
|
||||
mContext->timerQueryImpl->beginTimeElapsedQuery(tq);
|
||||
}
|
||||
|
||||
void MetalDriver::endTimerQuery(Handle<HwTimerQuery> tqh) {
|
||||
FILAMENT_CHECK_PRECONDITION(!isInRenderPass(mContext))
|
||||
<< "endTimerQuery must be called outside of a render pass.";
|
||||
ASSERT_PRECONDITION(!isInRenderPass(mContext),
|
||||
"endTimerQuery must be called outside of a render pass.");
|
||||
auto* tq = handle_cast<MetalTimerQuery>(tqh);
|
||||
mContext->timerQueryImpl->endTimeElapsedQuery(tq);
|
||||
}
|
||||
@@ -2061,10 +1945,6 @@ void MetalDriver::enumerateBoundBuffers(BufferObjectBinding bindingType,
|
||||
void MetalDriver::resetState(int) {
|
||||
}
|
||||
|
||||
void MetalDriver::setDebugTag(HandleBase::HandleId handleId, utils::CString tag) {
|
||||
mHandleAllocator.associateTagToHandle(handleId, std::move(tag));
|
||||
}
|
||||
|
||||
void MetalDriver::runAtNextTick(const std::function<void()>& fn) noexcept {
|
||||
std::lock_guard<std::mutex> const lock(mTickOpsLock);
|
||||
mTickOps.push_back(fn);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user