Compare commits
877
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
dee94b56db | ||
|
|
046d90be1c | ||
|
|
7fda028191 | ||
|
|
00445918ff | ||
|
|
f32ae2c900 | ||
|
|
0be7fa77a6 | ||
|
|
2765269e46 | ||
|
|
4a45db21b4 | ||
|
|
49ad01fa64 | ||
|
|
be0b7373e9 | ||
|
|
d6338fd927 | ||
|
|
6a1e3c54ec | ||
|
|
60132845ed | ||
|
|
e96a302e79 | ||
|
|
a4dd357781 | ||
|
|
009fb0e121 | ||
|
|
2779c00ec4 | ||
|
|
43d6909939 | ||
|
|
4eb669d59a | ||
|
|
3681fe9657 | ||
|
|
1dcc141e26 | ||
|
|
d8b994bef1 | ||
|
|
e057844742 | ||
|
|
6aa20312e5 | ||
|
|
082da86ca8 | ||
|
|
dd51e1dd96 | ||
|
|
b204b92e35 | ||
|
|
0a5b85f740 | ||
|
|
01318588d5 | ||
|
|
71b193a192 | ||
|
|
07324d63b6 | ||
|
|
3387f5bf33 | ||
|
|
18d7cf980b | ||
|
|
031981a72c | ||
|
|
a495d90110 | ||
|
|
9686b3e294 | ||
|
|
69a327c7e7 | ||
|
|
d5bcc31c71 | ||
|
|
95894f9634 | ||
|
|
4695e93633 | ||
|
|
b332bf376f | ||
|
|
aaac6e7662 | ||
|
|
8ef8b345ae | ||
|
|
2cc375e4cc | ||
|
|
592c91f20e | ||
|
|
04b62960de | ||
|
|
e2492dfde8 | ||
|
|
60ce48e327 | ||
|
|
7588189874 | ||
|
|
b6a69fba18 | ||
|
|
a3bfad95ab | ||
|
|
cf7360bf8b | ||
|
|
2a9dcd7c40 | ||
|
|
e726964b85 | ||
|
|
003e500571 | ||
|
|
72ae60fa64 | ||
|
|
06106b7a00 | ||
|
|
c7319ac559 | ||
|
|
66abb75bc4 | ||
|
|
e4b1f0413b | ||
|
|
9e1ee2f290 | ||
|
|
1d0c23a3f7 | ||
|
|
b8f43e4bc8 | ||
|
|
22bb67e0b0 | ||
|
|
9bd994e6a4 | ||
|
|
c3c9fe1b06 | ||
|
|
e9e7911506 | ||
|
|
0689e79441 | ||
|
|
40a6510710 | ||
|
|
d6b1efd5e4 | ||
|
|
6d0ab5a593 | ||
|
|
b2153e0ef6 | ||
|
|
0e4d35b9fd | ||
|
|
6cc4ae0ee8 | ||
|
|
01711f47d9 | ||
|
|
65aed719d7 | ||
|
|
3e556588fc | ||
|
|
429fd7acc6 | ||
|
|
32b0625f36 | ||
|
|
bb1d1c7349 | ||
|
|
c967fb7860 | ||
|
|
422fcea2cf | ||
|
|
b0d3f14243 | ||
|
|
f5f1e56123 | ||
|
|
bce91c56dd | ||
|
|
f743bedef9 | ||
|
|
eb12e06387 | ||
|
|
40ce15cfbd | ||
|
|
aa5f36e1e3 | ||
|
|
c1a3450d9c | ||
|
|
4396a1a776 | ||
|
|
d88ab8d527 | ||
|
|
a109a52f3d | ||
|
|
a7b4b9d3a6 | ||
|
|
e253051867 | ||
|
|
44d082049c | ||
|
|
239b43e34d | ||
|
|
1888c97245 | ||
|
|
c43c58af5d | ||
|
|
6b43762dc7 | ||
|
|
c3f1a4c94d | ||
|
|
1fef82a826 | ||
|
|
bef004e1b0 | ||
|
|
936d0a7b1d | ||
|
|
2b651d4946 | ||
|
|
d6ab9f1c0b | ||
|
|
786b7ec7ae | ||
|
|
55173efc2c | ||
|
|
7fc8e339e7 | ||
|
|
0395df3689 | ||
|
|
64f03b3832 | ||
|
|
982b159b3e | ||
|
|
bbd4177dd0 | ||
|
|
6e3cccf30c | ||
|
|
5d5f53e6e3 | ||
|
|
ec44c4a157 | ||
|
|
74751a0971 | ||
|
|
28069e43dc | ||
|
|
3603202cc5 | ||
|
|
a8596ae9c9 | ||
|
|
3fb9521c10 | ||
|
|
17f32d198a | ||
|
|
11ecaa2fbf | ||
|
|
d56f769d4d | ||
|
|
a46ca78f41 | ||
|
|
7ba437b2c6 | ||
|
|
b4c33d2ab2 | ||
|
|
455025349d | ||
|
|
3fa4aab02a | ||
|
|
5485ef238f | ||
|
|
a5541de84d | ||
|
|
2d184f5077 | ||
|
|
c2e3a97705 | ||
|
|
0d22805342 | ||
|
|
aeb0c14ce1 | ||
|
|
144d99df57 | ||
|
|
268e204a9f | ||
|
|
a13aa728bf | ||
|
|
c0ee1e2874 | ||
|
|
1b9d2c6fa6 | ||
|
|
7489c55532 | ||
|
|
2d157e8fe1 | ||
|
|
3ba082da13 | ||
|
|
7ae2773222 | ||
|
|
b7eb12bd0c | ||
|
|
305bfb36d8 | ||
|
|
880b454702 | ||
|
|
996e2a206e | ||
|
|
b57fbfb128 | ||
|
|
2f36df8d93 | ||
|
|
76a8f18700 | ||
|
|
53af1fd052 | ||
|
|
cb88e7555f | ||
|
|
35fa79ec23 | ||
|
|
d9cba80bcf | ||
|
|
ed4154ee0e | ||
|
|
65f2df7776 | ||
|
|
1b1c03814a | ||
|
|
b89a0173ef | ||
|
|
1fec588fb1 | ||
|
|
de1edbdf25 | ||
|
|
d468303bc9 | ||
|
|
81658541a1 | ||
|
|
d0eb56ff20 | ||
|
|
85589a7d16 | ||
|
|
d476c7fa1b | ||
|
|
3ed008c0b6 | ||
|
|
66ec81187d | ||
|
|
0efd94a769 | ||
|
|
1801def1ee | ||
|
|
61155644d5 | ||
|
|
b3ec8b188e | ||
|
|
dbf0cde330 | ||
|
|
072562c571 | ||
|
|
780799f30b | ||
|
|
cf0c1f74dc | ||
|
|
d3ca32efbe | ||
|
|
de6df6dc0e | ||
|
|
6dd85c6530 | ||
|
|
5ca7f41513 | ||
|
|
4ad07e25d4 | ||
|
|
89a191c2e9 | ||
|
|
f63296fc18 | ||
|
|
ca27bb58bf | ||
|
|
86d2e11801 | ||
|
|
cd528e57ab | ||
|
|
4a465450f1 | ||
|
|
4e648b224f | ||
|
|
04c7f84c6f | ||
|
|
8c31f46683 | ||
|
|
563c32b95b | ||
|
|
ab0063bc6b | ||
|
|
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 |
@@ -1,68 +0,0 @@
|
||||
BasedOnStyle: LLVM
|
||||
AccessModifierOffset: -4
|
||||
AlignAfterOpenBracket: DontAlign
|
||||
AlignConsecutiveAssignments: None
|
||||
AlignOperands: Align
|
||||
AllowAllArgumentsOnNextLine: false
|
||||
AllowAllConstructorInitializersOnNextLine: false
|
||||
AllowAllParametersOfDeclarationOnNextLine: true
|
||||
AllowShortBlocksOnASingleLine: false
|
||||
AllowShortCaseLabelsOnASingleLine: false
|
||||
AllowShortFunctionsOnASingleLine: All
|
||||
AllowShortIfStatementsOnASingleLine: Always
|
||||
AllowShortLambdasOnASingleLine: All
|
||||
AllowShortLoopsOnASingleLine: true
|
||||
AlwaysBreakAfterReturnType: None
|
||||
AlwaysBreakTemplateDeclarations: Yes
|
||||
BreakBeforeBraces: Custom
|
||||
BracedInitializerIndentWidth: 4
|
||||
BraceWrapping:
|
||||
AfterCaseLabel: false
|
||||
AfterClass: false
|
||||
AfterControlStatement: Never
|
||||
AfterEnum: false
|
||||
AfterFunction: false
|
||||
AfterNamespace: false
|
||||
AfterUnion: false
|
||||
BeforeCatch: false
|
||||
BeforeElse: false
|
||||
IndentBraces: false
|
||||
SplitEmptyFunction: false
|
||||
SplitEmptyRecord: true
|
||||
BreakBeforeBinaryOperators: None
|
||||
BreakBeforeTernaryOperators: true
|
||||
BreakConstructorInitializers: BeforeColon
|
||||
BreakInheritanceList: BeforeColon
|
||||
ColumnLimit: 100
|
||||
CompactNamespaces: false
|
||||
ContinuationIndentWidth: 8
|
||||
Cpp11BracedListStyle: false
|
||||
IndentCaseLabels: true
|
||||
IndentPPDirectives: None
|
||||
IndentWidth: 4
|
||||
KeepEmptyLinesAtTheStartOfBlocks: true
|
||||
MaxEmptyLinesToKeep: 2
|
||||
NamespaceIndentation: None
|
||||
ObjCSpaceAfterProperty: false
|
||||
ObjCSpaceBeforeProtocolList: true
|
||||
PointerAlignment: Left
|
||||
ReflowComments: true
|
||||
SpaceAfterCStyleCast: true
|
||||
SpaceAfterLogicalNot: false
|
||||
SpaceAfterTemplateKeyword: false
|
||||
SpaceBeforeAssignmentOperators: true
|
||||
SpaceBeforeCpp11BracedList: false
|
||||
SpaceBeforeCtorInitializerColon: true
|
||||
SpaceBeforeInheritanceColon: true
|
||||
SpaceBeforeParens: ControlStatements
|
||||
SpaceBeforeRangeBasedForLoopColon: false
|
||||
SpaceInEmptyParentheses: false
|
||||
SpacesBeforeTrailingComments: 0
|
||||
SpacesInAngles: false
|
||||
SpacesInCStyleCastParentheses: false
|
||||
SpacesInContainerLiterals: false
|
||||
SpacesInParentheses: false
|
||||
SpacesInSquareBrackets: false
|
||||
TabWidth: 4
|
||||
UseTab: Never
|
||||
PackConstructorInitializers: Never
|
||||
@@ -92,27 +92,15 @@ jobs:
|
||||
|
||||
test-renderdiff:
|
||||
name: test-renderdiff
|
||||
runs-on: ubuntu-22.04-4core
|
||||
runs-on: ubuntu-22.04-16core
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4.1.6
|
||||
- uses: ./.github/actions/ubuntu-apt-add-src
|
||||
- name: Run script
|
||||
run: |
|
||||
echo "Disabled renderdiff due to Mesa -> Currently planned outage: 2025-03-16 -> 2025-03-22"
|
||||
# source ./build/linux/ci-common.sh && bash test/renderdiff/test.sh
|
||||
source ./build/linux/ci-common.sh && bash test/renderdiff/test.sh
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: presubmit-renderdiff-result
|
||||
path: ./out/renderdiff_tests
|
||||
|
||||
validate-wgsl-pipeline:
|
||||
name: validate-wgsl-pipeline
|
||||
runs-on: ubuntu-22.04-4core
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4.1.6
|
||||
- name: Run build script
|
||||
run: source ./build/linux/ci-common.sh && ./build.sh -W debug test_filamat
|
||||
- name: Run test
|
||||
run: ./out/cmake-debug/libs/filamat/test_filamat --gtest_filter=MaterialCompiler.Wgsl*
|
||||
@@ -9,11 +9,6 @@ name: Release
|
||||
env:
|
||||
RELEASE_TAG: ${{ github.event.inputs.release_tag }}
|
||||
|
||||
# The default GITHUB_TOKEN does not have write permissions, which is needed to upload release
|
||||
# assets.
|
||||
permissions:
|
||||
contents: write
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
|
||||
@@ -601,14 +601,6 @@ if (FILAMENT_SUPPORTS_METAL)
|
||||
set(MATC_API_FLAGS ${MATC_API_FLAGS} -a metal)
|
||||
endif()
|
||||
|
||||
# With WebGPU, push constants are not supported. Skinning uses them.
|
||||
# WebGPU has a proposal to add push constants at https://github.com/gpuweb/gpuweb/blob/main/proposals/push-constants.md
|
||||
# With WebGPU, Tint does not support ClipDistance which is used in Stereo. Mentioned in comment
|
||||
# https://github.com/google/dawn/blob/855d17b08abdf02f9142bf5a8f14d0ea088810a4/src/tint/lang/spirv/reader/ast_parser/function.cc#L4434
|
||||
if (FILAMENT_SUPPORTS_WEBGPU)
|
||||
set(MATC_API_FLAGS ${MATC_API_FLAGS} -a webgpu --variant-filter=skinning,stereo)
|
||||
endif()
|
||||
|
||||
# Disable ESSL 1.0 code generation.
|
||||
if (NOT FILAMENT_ENABLE_FEATURE_LEVEL_0)
|
||||
set(MATC_API_FLAGS ${MATC_API_FLAGS} -1)
|
||||
|
||||
@@ -7,3 +7,4 @@ for next branch cut* header.
|
||||
appropriate header in [RELEASE_NOTES.md](./RELEASE_NOTES.md).
|
||||
|
||||
## Release notes for next branch cut
|
||||
- materials: add an optional `transformName` field to sampler material parameters. [⚠️ **New Material Version**]
|
||||
|
||||
@@ -7,13 +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.58.1
|
||||
|
||||
|
||||
## v1.58.0
|
||||
|
||||
- materials: add an optional `transformName` field to sampler material parameters. [⚠️ **New Material Version**]
|
||||
|
||||
## v1.57.3
|
||||
|
||||
- android: breaking changes to API KTX1Loader::createIndirectLight and KTX1Loader::createSkybox
|
||||
|
||||
@@ -71,9 +71,10 @@ buildscript {
|
||||
.gradleProperty("com.google.android.filament.include-webgpu")
|
||||
.isPresent()
|
||||
|
||||
def fgviewer = providers
|
||||
.gradleProperty("com.google.android.filament.fgviewer")
|
||||
.isPresent()
|
||||
// TODO: Uncomment below when fgviewer is ready
|
||||
// def fgviewer = providers
|
||||
// .gradleProperty("com.google.android.filament.fgviewer")
|
||||
// .isPresent()
|
||||
|
||||
def matdbg = providers
|
||||
.gradleProperty("com.google.android.filament.matdbg")
|
||||
@@ -130,7 +131,8 @@ buildscript {
|
||||
"-DFILAMENT_DIST_DIR=${filamentPath}".toString(),
|
||||
"-DFILAMENT_SUPPORTS_VULKAN=${excludeVulkan ? 'OFF' : 'ON'}".toString(),
|
||||
"-DFILAMENT_SUPPORTS_WEBGPU=${includeWebGPU ? 'ON' : 'OFF'}".toString(),
|
||||
"-DFILAMENT_ENABLE_FGVIEWER=${fgviewer ? 'ON' : 'OFF'}".toString(),
|
||||
// TODO: Uncomment below when fgviewer is ready
|
||||
// "-DFILAMENT_ENABLE_FGVIEWER=${fgviewer ? 'ON' : 'OFF'}".toString(),
|
||||
"-DFILAMENT_ENABLE_MATDBG=${matdbg ? 'ON' : 'OFF'}".toString(),
|
||||
"-DFILAMENT_DISABLE_MATOPT=${matnopt ? 'ON' : 'OFF'}".toString()
|
||||
]
|
||||
|
||||
@@ -11,13 +11,6 @@ if (FILAMENT_SUPPORTS_VULKAN)
|
||||
message("Library filamat ignores Vulkan settings")
|
||||
endif()
|
||||
|
||||
if (FILAMENT_SUPPORTS_WEBGPU)
|
||||
# See third_party/dawn/tnt/CMakeLists.txt and libs/filamat/CMakeLists.txt
|
||||
add_library(tint STATIC IMPORTED)
|
||||
set_target_properties(tint PROPERTIES IMPORTED_LOCATION
|
||||
${FILAMENT_DIR}/lib/${ANDROID_ABI}/libtint_combined.a)
|
||||
endif()
|
||||
|
||||
add_library(${FILAMAT_FLAVOR} STATIC IMPORTED)
|
||||
set_target_properties(${FILAMAT_FLAVOR} PROPERTIES IMPORTED_LOCATION
|
||||
${FILAMENT_DIR}/lib/${ANDROID_ABI}/lib${FILAMAT_FLAVOR}.a)
|
||||
@@ -57,5 +50,4 @@ target_link_libraries(filamat-jni
|
||||
utils
|
||||
log
|
||||
smol-v
|
||||
$<$<STREQUAL:${FILAMENT_SUPPORTS_WEBGPU},ON>:tint>
|
||||
)
|
||||
|
||||
@@ -2,7 +2,8 @@ cmake_minimum_required(VERSION 3.19)
|
||||
project(filament-android)
|
||||
|
||||
option(FILAMENT_SUPPORTS_VULKAN "Enables Vulkan on Android" OFF)
|
||||
option(FILAMENT_ENABLE_FGVIEWER "Enables Frame Graph Viewer" OFF)
|
||||
# TODO: Uncomment below when fgviewer is ready
|
||||
# option(FILAMENT_ENABLE_FGVIEWER "Enables Frame Graph Viewer" OFF)
|
||||
option(FILAMENT_ENABLE_MATDBG "Enables Material debugger" OFF)
|
||||
option(FILAMENT_DISABLE_MATOPT "Disables material optimizations" OFF)
|
||||
option(FILAMENT_SUPPORTS_WEBGPU "Enables WebGPU on Android" OFF)
|
||||
@@ -29,6 +30,10 @@ add_library(filaflat STATIC IMPORTED)
|
||||
set_target_properties(filaflat PROPERTIES IMPORTED_LOCATION
|
||||
${FILAMENT_DIR}/lib/${ANDROID_ABI}/libfilaflat.a)
|
||||
|
||||
add_library(filamat STATIC IMPORTED)
|
||||
set_target_properties(filamat PROPERTIES IMPORTED_LOCATION
|
||||
${FILAMENT_DIR}/lib/${ANDROID_ABI}/libfilamat.a)
|
||||
|
||||
add_library(geometry STATIC IMPORTED)
|
||||
set_target_properties(geometry PROPERTIES IMPORTED_LOCATION
|
||||
${FILAMENT_DIR}/lib/${ANDROID_ABI}/libgeometry.a)
|
||||
@@ -55,11 +60,12 @@ add_library(smol-v STATIC IMPORTED)
|
||||
set_target_properties(smol-v PROPERTIES IMPORTED_LOCATION
|
||||
${FILAMENT_DIR}/lib/${ANDROID_ABI}/libsmol-v.a)
|
||||
|
||||
if (FILAMENT_ENABLE_FGVIEWER)
|
||||
add_library(fgviewer STATIC IMPORTED)
|
||||
set_target_properties(fgviewer PROPERTIES IMPORTED_LOCATION
|
||||
${FILAMENT_DIR}/lib/${ANDROID_ABI}/libfgviewer.a)
|
||||
endif()
|
||||
# TODO: Uncomment below when fgviewer is ready
|
||||
# if (FILAMENT_ENABLE_FGVIEWER)
|
||||
# add_library(fgviewer STATIC IMPORTED)
|
||||
# set_target_properties(fgviewer PROPERTIES IMPORTED_LOCATION
|
||||
# ${FILAMENT_DIR}/lib/${ANDROID_ABI}/libfgviewer.a)
|
||||
# endif()
|
||||
|
||||
if (FILAMENT_ENABLE_MATDBG)
|
||||
add_library(matdbg STATIC IMPORTED)
|
||||
@@ -127,7 +133,8 @@ target_link_libraries(filament-jni
|
||||
# libgeometry is PUBLIC because gltfio uses it.
|
||||
PUBLIC geometry
|
||||
|
||||
$<$<STREQUAL:${FILAMENT_ENABLE_FGVIEWER},ON>:fgviewer>
|
||||
# TODO: Uncomment below when fgviewer is ready
|
||||
# $<$<STREQUAL:${FILAMENT_ENABLE_FGVIEWER},ON>:fgviewer>
|
||||
$<$<STREQUAL:${FILAMENT_ENABLE_MATDBG},ON>:matdbg>
|
||||
$<$<STREQUAL:${FILAMENT_ENABLE_MATDBG},ON>:filamat>
|
||||
$<$<STREQUAL:${FILAMENT_SUPPORTS_VULKAN},ON>:bluevk>
|
||||
|
||||
@@ -68,21 +68,6 @@ Java_com_google_android_filament_Texture_nIsTextureSwizzleSupported(JNIEnv*, jcl
|
||||
return (jboolean) Texture::isTextureSwizzleSupported(*engine);
|
||||
}
|
||||
|
||||
|
||||
extern "C" JNIEXPORT jint JNICALL
|
||||
Java_com_google_android_filament_Texture_nGetMaxTextureSize(JNIEnv *, jclass,
|
||||
jlong nativeEngine, jint sampler) {
|
||||
Engine *engine = (Engine *) nativeEngine;
|
||||
return Texture::getMaxTextureSize(*engine, (Texture::Sampler)sampler);
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT jint JNICALL
|
||||
Java_com_google_android_filament_Texture_nGetMaxArrayTextureLayers(JNIEnv *, jclass,
|
||||
jlong nativeEngine) {
|
||||
Engine *engine = (Engine *) nativeEngine;
|
||||
return Texture::getMaxArrayTextureLayers(*engine);
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT jboolean JNICALL
|
||||
Java_com_google_android_filament_Texture_nValidatePixelFormatAndType(JNIEnv*, jclass,
|
||||
jint internalFormat, jint pixelDataFormat, jint pixelDataType) {
|
||||
|
||||
@@ -691,24 +691,6 @@ public class Texture {
|
||||
pixelDataType.ordinal());
|
||||
}
|
||||
|
||||
/**
|
||||
* @param engine {@link Engine}
|
||||
* @param type Texture sampler type
|
||||
* @return The maximum size in texels of a texture of type \p type. At least 2048 for
|
||||
* 2D textures, 256 for 3D textures
|
||||
*/
|
||||
public static int getMaxTextureSize(@NonNull Engine engine, Sampler type) {
|
||||
return nGetMaxTextureSize(engine.getNativeObject(), type.ordinal());
|
||||
}
|
||||
|
||||
/**
|
||||
* @param engine {@link Engine}
|
||||
* @return The maximum number of layers supported by texture arrays. At least 256.
|
||||
*/
|
||||
public static int getMaxArrayTextureLayers(@NonNull Engine engine) {
|
||||
return nGetMaxArrayTextureLayers(engine.getNativeObject());
|
||||
}
|
||||
|
||||
/**
|
||||
* Use <code>Builder</code> to construct a <code>Texture</code> object instance.
|
||||
*/
|
||||
@@ -1307,8 +1289,6 @@ public class Texture {
|
||||
private static native boolean nIsTextureFormatSupported(long nativeEngine, int internalFormat);
|
||||
private static native boolean nIsTextureFormatMipmappable(long nativeEngine, int internalFormat);
|
||||
private static native boolean nIsTextureSwizzleSupported(long nativeEngine);
|
||||
private static native int nGetMaxTextureSize(long nativeObject, int ordinal);
|
||||
private static native int nGetMaxArrayTextureLayers(long nativeObject);
|
||||
|
||||
private static native boolean nValidatePixelFormatAndType(int internalFormat, int pixelDataFormat,
|
||||
int pixelDataType);
|
||||
|
||||
@@ -30,5 +30,4 @@ com.google.android.filament.abis=all
|
||||
#com.google.android.filament.include-webgpu
|
||||
|
||||
#com.google.android.filament.matdbg
|
||||
#com.google.android.filament.fgviewer
|
||||
#com.google.android.filament.matnopt
|
||||
|
||||
@@ -541,7 +541,6 @@ function build_android {
|
||||
./gradlew \
|
||||
-Pcom.google.android.filament.dist-dir=../out/android-debug/filament \
|
||||
-Pcom.google.android.filament.abis=${ABI_GRADLE_OPTION} \
|
||||
${WEBGPU_ANDROID_GRADLE_OPTION} \
|
||||
:filamat-android:assembleDebug
|
||||
|
||||
if [[ "${BUILD_ANDROID_SAMPLES}" == "true" ]]; then
|
||||
@@ -592,7 +591,6 @@ function build_android {
|
||||
./gradlew \
|
||||
-Pcom.google.android.filament.dist-dir=../out/android-release/filament \
|
||||
-Pcom.google.android.filament.abis=${ABI_GRADLE_OPTION} \
|
||||
${WEBGPU_ANDROID_GRADLE_OPTION} \
|
||||
:filamat-android:assembleRelease
|
||||
|
||||
if [[ "${BUILD_ANDROID_SAMPLES}" == "true" ]]; then
|
||||
|
||||
@@ -30,9 +30,6 @@ if [[ "$GITHUB_WORKFLOW" ]]; then
|
||||
sudo apt-get install clang-$GITHUB_CLANG_VERSION libc++-$GITHUB_CLANG_VERSION-dev libc++abi-$GITHUB_CLANG_VERSION-dev
|
||||
sudo apt-get install mesa-common-dev libxi-dev libxxf86vm-dev
|
||||
|
||||
# For dawn
|
||||
sudo apt-get install libxrandr-dev libxinerama-dev libxcursor-dev libxi-dev
|
||||
|
||||
sudo update-alternatives --install /usr/bin/cc cc /usr/bin/clang-${GITHUB_CLANG_VERSION} 100
|
||||
sudo update-alternatives --install /usr/bin/c++ c++ /usr/bin/clang++-${GITHUB_CLANG_VERSION} 100
|
||||
fi
|
||||
|
||||
@@ -233,44 +233,17 @@ if (FILAMENT_SUPPORTS_VULKAN)
|
||||
elseif (APPLE OR IOS)
|
||||
list(APPEND SRCS src/vulkan/platform/VulkanPlatformApple.mm)
|
||||
elseif (ANDROID)
|
||||
list(APPEND SRCS
|
||||
include/backend/platforms/VulkanPlatformAndroid.h
|
||||
src/vulkan/platform/VulkanPlatformAndroid.cpp
|
||||
)
|
||||
list(APPEND SRCS src/vulkan/platform/VulkanPlatformAndroid.cpp)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if (FILAMENT_SUPPORTS_WEBGPU)
|
||||
list(APPEND SRCS
|
||||
include/backend/platforms/WebGPUPlatform.h
|
||||
src/webgpu/platform/WebGPUPlatform.cpp
|
||||
src/webgpu/WebGPUConstants.h
|
||||
src/webgpu/WebGPUDriver.cpp
|
||||
src/webgpu/WebGPUDriver.h
|
||||
src/webgpu/WebGPUPlatform.cpp
|
||||
src/webgpu/WebGPUPlatform.h
|
||||
)
|
||||
if (WIN32)
|
||||
list(APPEND SRCS src/webgpu/platform/WebGPUPlatformWindows.cpp)
|
||||
elseif (LINUX)
|
||||
list(APPEND SRCS src/webgpu/platform/WebGPUPlatformLinux.cpp)
|
||||
elseif (APPLE OR IOS)
|
||||
list(APPEND SRCS src/webgpu/platform/WebGPUPlatformApple.mm)
|
||||
elseif (ANDROID)
|
||||
list(APPEND SRCS src/webgpu/platform/WebGPUPlatformAndroid.cpp)
|
||||
endif()
|
||||
|
||||
if (TNT_DEV)
|
||||
set(FILAMENT_WEBGPU_IMMEDIATE_ERROR_HANDLING_DEFAULT ON)
|
||||
else()
|
||||
set(FILAMENT_WEBGPU_IMMEDIATE_ERROR_HANDLING_DEFAULT OFF)
|
||||
endif()
|
||||
|
||||
option(FILAMENT_WEBGPU_IMMEDIATE_ERROR_HANDLING
|
||||
"Enable immediate_error_handling for the WebGPU backend Dawn implementation"
|
||||
${FILAMENT_WEBGPU_IMMEDIATE_ERROR_HANDLING_DEFAULT})
|
||||
endif()
|
||||
|
||||
if (ANDROID)
|
||||
list(APPEND SRCS src/BackendUtilsAndroid.cpp)
|
||||
endif()
|
||||
|
||||
# ==================================================================================================
|
||||
@@ -453,10 +426,6 @@ if (FILAMENT_SUPPORTS_METAL)
|
||||
target_compile_definitions(${TARGET} PRIVATE $<$<BOOL:${FILAMENT_METAL_PROFILING}>:FILAMENT_METAL_PROFILING>)
|
||||
endif()
|
||||
|
||||
if (FILAMENT_SUPPORTS_WEBGPU)
|
||||
target_compile_definitions(${TARGET} PRIVATE $<$<BOOL:${FILAMENT_WEBGPU_IMMEDIATE_ERROR_HANDLING}>:FILAMENT_WEBGPU_IMMEDIATE_ERROR_HANDLING>)
|
||||
endif()
|
||||
|
||||
target_link_libraries(${TARGET} PRIVATE
|
||||
${OSMESA_LINKER_FLAGS}
|
||||
$<$<AND:$<PLATFORM_ID:Linux>,$<CONFIG:Release>>:${LINUX_LINKER_OPTIMIZATION_FLAGS}>
|
||||
@@ -485,7 +454,6 @@ if (APPLE OR LINUX)
|
||||
test/ShaderGenerator.cpp
|
||||
test/TrianglePrimitive.cpp
|
||||
test/Arguments.cpp
|
||||
test/Lifetimes.cpp
|
||||
test/test_FeedbackLoops.cpp
|
||||
test/test_Blit.cpp
|
||||
test/test_MissingRequiredAttributes.cpp
|
||||
|
||||
@@ -126,10 +126,6 @@ static_assert(MAX_VERTEX_BUFFER_COUNT <= MAX_VERTEX_ATTRIBUTE_COUNT,
|
||||
static constexpr size_t CONFIG_UNIFORM_BINDING_COUNT = 9; // This is guaranteed by OpenGL ES.
|
||||
static constexpr size_t CONFIG_SAMPLER_BINDING_COUNT = 4; // This is guaranteed by OpenGL ES.
|
||||
|
||||
static constexpr uint8_t EXTERNAL_SAMPLER_DATA_INDEX_UNUSED =
|
||||
uint8_t(-1);// Case where the descriptor set binding isnt using any external sampler state
|
||||
// and therefore doesn't have a valid entry.
|
||||
|
||||
/**
|
||||
* Defines the backend's feature levels.
|
||||
*/
|
||||
@@ -186,7 +182,6 @@ enum class ShaderLanguage {
|
||||
SPIRV = 2,
|
||||
MSL = 3,
|
||||
METAL_LIBRARY = 4,
|
||||
WGSL = 5,
|
||||
};
|
||||
|
||||
static constexpr const char* shaderLanguageToString(ShaderLanguage shaderLanguage) {
|
||||
@@ -201,8 +196,6 @@ static constexpr const char* shaderLanguageToString(ShaderLanguage shaderLanguag
|
||||
return "MSL";
|
||||
case ShaderLanguage::METAL_LIBRARY:
|
||||
return "Metal precompiled library";
|
||||
case ShaderLanguage::WGSL:
|
||||
return "WGSL";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -256,19 +249,21 @@ struct DescriptorSetLayoutBinding {
|
||||
DescriptorFlags flags = DescriptorFlags::NONE;
|
||||
uint16_t count = 0;
|
||||
|
||||
uint8_t externalSamplerDataIndex = EXTERNAL_SAMPLER_DATA_INDEX_UNUSED;
|
||||
|
||||
friend inline bool operator==(
|
||||
DescriptorSetLayoutBinding const& lhs,
|
||||
DescriptorSetLayoutBinding const& rhs) noexcept {
|
||||
return lhs.type == rhs.type &&
|
||||
lhs.flags == rhs.flags &&
|
||||
lhs.count == rhs.count &&
|
||||
lhs.stageFlags == rhs.stageFlags &&
|
||||
lhs.externalSamplerDataIndex == rhs.externalSamplerDataIndex;
|
||||
lhs.stageFlags == rhs.stageFlags;
|
||||
}
|
||||
};
|
||||
|
||||
struct DescriptorSetLayout {
|
||||
utils::FixedCapacityVector<DescriptorSetLayoutBinding> bindings;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Bitmask for selecting render buffers
|
||||
*/
|
||||
@@ -812,33 +807,6 @@ static constexpr bool isStencilFormat(TextureFormat format) noexcept {
|
||||
}
|
||||
}
|
||||
|
||||
inline constexpr bool isColorFormat(TextureFormat format) noexcept {
|
||||
switch (format) {
|
||||
// Standard color formats
|
||||
case TextureFormat::R8:
|
||||
case TextureFormat::RG8:
|
||||
case TextureFormat::RGBA8:
|
||||
case TextureFormat::R16F:
|
||||
case TextureFormat::RG16F:
|
||||
case TextureFormat::RGBA16F:
|
||||
case TextureFormat::R32F:
|
||||
case TextureFormat::RG32F:
|
||||
case TextureFormat::RGBA32F:
|
||||
case TextureFormat::RGB10_A2:
|
||||
case TextureFormat::R11F_G11F_B10F:
|
||||
case TextureFormat::SRGB8:
|
||||
case TextureFormat::SRGB8_A8:
|
||||
case TextureFormat::RGB8:
|
||||
case TextureFormat::RGB565:
|
||||
case TextureFormat::RGB5_A1:
|
||||
case TextureFormat::RGBA4:
|
||||
return true;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static constexpr bool isUnsignedIntFormat(TextureFormat format) {
|
||||
switch (format) {
|
||||
case TextureFormat::R8UI:
|
||||
@@ -970,28 +938,8 @@ enum class SamplerCompareFunc : uint8_t {
|
||||
N //!< Never. The depth / stencil test always fails.
|
||||
};
|
||||
|
||||
//! this API is copied from (and only applies to) the Vulkan spec.
|
||||
//! These specify YUV to RGB conversions.
|
||||
enum class SamplerYcbcrModelConversion : uint8_t {
|
||||
RGB_IDENTITY = 0,
|
||||
YCBCR_IDENTITY = 1,
|
||||
YCBCR_709 = 2,
|
||||
YCBCR_601 = 3,
|
||||
YCBCR_2020 = 4,
|
||||
};
|
||||
|
||||
enum class SamplerYcbcrRange : uint8_t {
|
||||
ITU_FULL = 0,
|
||||
ITU_NARROW = 1,
|
||||
};
|
||||
|
||||
enum class ChromaLocation : uint8_t {
|
||||
COSITED_EVEN = 0,
|
||||
MIDPOINT = 1,
|
||||
};
|
||||
|
||||
//! Sampler parameters
|
||||
struct SamplerParams { // NOLINT
|
||||
struct SamplerParams { // NOLINT
|
||||
SamplerMagFilter filterMag : 1; //!< magnification filter (NEAREST)
|
||||
SamplerMinFilter filterMin : 3; //!< minification filter (NEAREST)
|
||||
SamplerWrapMode wrapS : 2; //!< s-coordinate wrap mode (CLAMP_TO_EDGE)
|
||||
@@ -1046,7 +994,6 @@ private:
|
||||
return SamplerParams::LessThan{}(lhs, rhs);
|
||||
}
|
||||
};
|
||||
|
||||
static_assert(sizeof(SamplerParams) == 4);
|
||||
|
||||
// The limitation to 64-bits max comes from how we store a SamplerParams in our JNI code
|
||||
@@ -1054,93 +1001,6 @@ static_assert(sizeof(SamplerParams) == 4);
|
||||
static_assert(sizeof(SamplerParams) <= sizeof(uint64_t),
|
||||
"SamplerParams must be no more than 64 bits");
|
||||
|
||||
//! Sampler parameters
|
||||
struct SamplerYcbcrConversion {// NOLINT
|
||||
SamplerYcbcrModelConversion ycbcrModel : 4;
|
||||
TextureSwizzle r : 4;
|
||||
TextureSwizzle g : 4;
|
||||
TextureSwizzle b : 4;
|
||||
TextureSwizzle a : 4;
|
||||
SamplerYcbcrRange ycbcrRange : 1;
|
||||
ChromaLocation xChromaOffset : 1;
|
||||
ChromaLocation yChromaOffset : 1;
|
||||
SamplerMagFilter chromaFilter : 1;
|
||||
uint8_t padding;
|
||||
|
||||
struct Hasher {
|
||||
size_t operator()(const SamplerYcbcrConversion p) const noexcept {
|
||||
// we don't use std::hash<> here, so we don't have to include <functional>
|
||||
return *reinterpret_cast<uint32_t const*>(reinterpret_cast<char const*>(&p));
|
||||
}
|
||||
};
|
||||
|
||||
struct EqualTo {
|
||||
bool operator()(SamplerYcbcrConversion lhs, SamplerYcbcrConversion rhs) const noexcept {
|
||||
assert_invariant(lhs.padding == 0);
|
||||
auto* pLhs = reinterpret_cast<uint32_t const*>(reinterpret_cast<char const*>(&lhs));
|
||||
auto* pRhs = reinterpret_cast<uint32_t const*>(reinterpret_cast<char const*>(&rhs));
|
||||
return *pLhs == *pRhs;
|
||||
}
|
||||
};
|
||||
|
||||
struct LessThan {
|
||||
bool operator()(SamplerYcbcrConversion lhs, SamplerYcbcrConversion rhs) const noexcept {
|
||||
assert_invariant(lhs.padding == 0);
|
||||
auto* pLhs = reinterpret_cast<uint32_t const*>(reinterpret_cast<char const*>(&lhs));
|
||||
auto* pRhs = reinterpret_cast<uint32_t const*>(reinterpret_cast<char const*>(&rhs));
|
||||
return *pLhs < *pRhs;
|
||||
}
|
||||
};
|
||||
|
||||
private:
|
||||
friend inline bool operator == (SamplerYcbcrConversion lhs, SamplerYcbcrConversion rhs)
|
||||
noexcept {
|
||||
return SamplerYcbcrConversion::EqualTo{}(lhs, rhs);
|
||||
}
|
||||
friend inline bool operator != (SamplerYcbcrConversion lhs, SamplerYcbcrConversion rhs)
|
||||
noexcept {
|
||||
return !SamplerYcbcrConversion::EqualTo{}(lhs, rhs);
|
||||
}
|
||||
friend inline bool operator < (SamplerYcbcrConversion lhs, SamplerYcbcrConversion rhs)
|
||||
noexcept {
|
||||
return SamplerYcbcrConversion::LessThan{}(lhs, rhs);
|
||||
}
|
||||
};
|
||||
|
||||
static_assert(sizeof(SamplerYcbcrConversion) == 4);
|
||||
|
||||
static_assert(sizeof(SamplerYcbcrConversion) <= sizeof(uint64_t),
|
||||
"SamplerYcbcrConversion must be no more than 64 bits");
|
||||
|
||||
struct ExternalSamplerDatum {
|
||||
ExternalSamplerDatum(SamplerYcbcrConversion ycbcr, SamplerParams spm, uint32_t extFmt)
|
||||
: YcbcrConversion(ycbcr),
|
||||
samplerParams(spm),
|
||||
externalFormat(extFmt) {}
|
||||
bool operator==(ExternalSamplerDatum const& rhs) const {
|
||||
return (YcbcrConversion == rhs.YcbcrConversion && samplerParams == rhs.samplerParams &&
|
||||
externalFormat == rhs.externalFormat);
|
||||
}
|
||||
struct EqualTo {
|
||||
bool operator()(const ExternalSamplerDatum& lhs,
|
||||
const ExternalSamplerDatum& rhs) const noexcept {
|
||||
return (lhs.YcbcrConversion == rhs.YcbcrConversion &&
|
||||
lhs.samplerParams == rhs.samplerParams &&
|
||||
lhs.externalFormat == rhs.externalFormat);
|
||||
}
|
||||
};
|
||||
SamplerYcbcrConversion YcbcrConversion;
|
||||
SamplerParams samplerParams;
|
||||
uint32_t externalFormat;
|
||||
};
|
||||
// No implicit padding allowed due to it being a hash key.
|
||||
static_assert(sizeof(ExternalSamplerDatum) == 12);
|
||||
|
||||
struct DescriptorSetLayout {
|
||||
utils::FixedCapacityVector<DescriptorSetLayoutBinding> bindings;
|
||||
utils::FixedCapacityVector<ExternalSamplerDatum> externalSamplerData;
|
||||
};
|
||||
|
||||
//! blending equation function
|
||||
enum class BlendEquation : uint8_t {
|
||||
ADD, //!< the fragment is added to the color buffer
|
||||
|
||||
@@ -18,7 +18,6 @@
|
||||
#define TNT_FILAMENT_BACKEND_PLATFORMS_VULKANPLATFORM_H
|
||||
|
||||
#include <backend/Platform.h>
|
||||
#include <backend/DriverEnums.h>
|
||||
|
||||
#include <bluevk/BlueVK.h>
|
||||
|
||||
@@ -318,11 +317,6 @@ public:
|
||||
*/
|
||||
uint32_t layers;
|
||||
|
||||
/**
|
||||
* The numbers of samples per texel
|
||||
*/
|
||||
VkSampleCountFlagBits samples;
|
||||
|
||||
/**
|
||||
* The format of the external image
|
||||
*/
|
||||
@@ -353,37 +347,18 @@ public:
|
||||
*/
|
||||
uint32_t memoryTypeBits;
|
||||
};
|
||||
virtual ExternalImageMetadata getExternalImageMetadata(ExternalImageHandleRef externalImage);
|
||||
virtual ExternalImageMetadata getExternalImageMetadata(void* externalImage);
|
||||
|
||||
using ImageData = std::pair<VkImage, VkDeviceMemory>;
|
||||
virtual ImageData createExternalImageData(ExternalImageHandleRef externalImage,
|
||||
const ExternalImageMetadata& metadata, uint32_t memoryTypeIndex,
|
||||
VkImageUsageFlags usage);
|
||||
|
||||
virtual VkSampler createExternalSampler(SamplerYcbcrConversion chroma,
|
||||
SamplerParams sampler,
|
||||
uint32_t internalFormat);
|
||||
|
||||
virtual VkImageView createExternalImageView(SamplerYcbcrConversion chroma,
|
||||
uint32_t internalFormat, VkImage image, VkImageSubresourceRange range,
|
||||
VkImageViewType viewType, VkComponentMapping swizzle);
|
||||
virtual ImageData createExternalImage(void* externalImage,
|
||||
const ExternalImageMetadata& metadata);
|
||||
|
||||
private:
|
||||
static ExtensionSet getSwapchainInstanceExtensions();
|
||||
|
||||
static ExternalImageMetadata getExternalImageMetadataImpl(ExternalImageHandleRef externalImage,
|
||||
static ExternalImageMetadata getExternalImageMetadataImpl(void* externalImage,
|
||||
VkDevice device);
|
||||
|
||||
static ImageData createExternalImageDataImpl(ExternalImageHandleRef externalImage,
|
||||
VkDevice device, const ExternalImageMetadata& metadata, uint32_t memoryTypeIndex,
|
||||
VkImageUsageFlags usage);
|
||||
static VkSampler createExternalSamplerImpl(VkDevice device,
|
||||
SamplerYcbcrConversion chroma, SamplerParams sampler,
|
||||
uint32_t internalFormat);
|
||||
static VkImageView createExternalImageViewImpl(VkDevice device,
|
||||
SamplerYcbcrConversion chroma, uint32_t internalFormat, VkImage image,
|
||||
VkImageSubresourceRange range, VkImageViewType viewType,
|
||||
VkComponentMapping swizzle);
|
||||
static ImageData createExternalImageImpl(void* externalImage, VkDevice device,
|
||||
const VkAllocationCallbacks* allocator, const ExternalImageMetadata& metadata);
|
||||
|
||||
// Platform dependent helper methods
|
||||
using SurfaceBundle = std::tuple<VkSurfaceKHR, VkExtent2D>;
|
||||
|
||||
@@ -1,43 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2025 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.
|
||||
*/
|
||||
|
||||
#ifndef TNT_FILAMENT_BACKEND_PLATFORMS_VULKAN_PLATFORM_ANDROID_H
|
||||
#define TNT_FILAMENT_BACKEND_PLATFORMS_VULKAN_PLATFORM_ANDROID_H
|
||||
|
||||
#include <backend/Platform.h>
|
||||
|
||||
#include <android/hardware_buffer.h>
|
||||
|
||||
namespace filament::backend::fvkandroid {
|
||||
|
||||
struct ExternalImageVulkanAndroid : public Platform::ExternalImage {
|
||||
AHardwareBuffer* aHardwareBuffer = nullptr;
|
||||
bool sRGB = false;
|
||||
unsigned int width; // Texture width
|
||||
unsigned int height; // Texture height
|
||||
TextureFormat format; // Texture format
|
||||
TextureUsage usage; // Texture usage flags
|
||||
|
||||
protected:
|
||||
~ExternalImageVulkanAndroid() override;
|
||||
};
|
||||
|
||||
Platform::ExternalImageHandle createExternalImage(AHardwareBuffer const* buffer,
|
||||
bool sRGB) noexcept;
|
||||
|
||||
} // namespace filament::backend::fvkandroid
|
||||
|
||||
#endif // TNT_FILAMENT_BACKEND_PLATFORMS_VULKAN_PLATFORM_ANDROID_H
|
||||
@@ -1,59 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2025 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.
|
||||
*/
|
||||
|
||||
#ifndef TNT_FILAMENT_BACKEND_PLATFORMS_WEBGPUPLATFORM_H
|
||||
#define TNT_FILAMENT_BACKEND_PLATFORMS_WEBGPUPLATFORM_H
|
||||
|
||||
#include <backend/Platform.h>
|
||||
|
||||
#include <webgpu/webgpu_cpp.h>
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace filament::backend {
|
||||
|
||||
/**
|
||||
* A Platform interface, handling the environment-specific concerns, e.g. OS, for creating a WebGPU
|
||||
* driver (backend).
|
||||
*/
|
||||
class WebGPUPlatform final : public Platform {
|
||||
public:
|
||||
WebGPUPlatform();
|
||||
~WebGPUPlatform() override = default;
|
||||
|
||||
[[nodiscard]] int getOSVersion() const noexcept final { return 0; }
|
||||
|
||||
[[nodiscard]] wgpu::Instance& getInstance() noexcept { return mInstance; }
|
||||
|
||||
// either returns a valid surface or panics
|
||||
[[nodiscard]] wgpu::Surface createSurface(void* nativeWindow, uint64_t flags);
|
||||
// either returns a valid adapter or panics
|
||||
[[nodiscard]] wgpu::Adapter requestAdapter(wgpu::Surface const& surface);
|
||||
// either returns a valid device or panics
|
||||
[[nodiscard]] wgpu::Device requestDevice(wgpu::Adapter const& adapter);
|
||||
|
||||
protected:
|
||||
[[nodiscard]] Driver* createDriver(void* sharedContext,
|
||||
const Platform::DriverConfig& driverConfig) noexcept override;
|
||||
|
||||
private:
|
||||
// we may consider having the driver own this in the future
|
||||
wgpu::Instance mInstance;
|
||||
};
|
||||
|
||||
}// namespace filament::backend
|
||||
|
||||
#endif// TNT_FILAMENT_BACKEND_PLATFORMS_WEBGPUPLATFORM_H
|
||||
@@ -362,8 +362,6 @@ DECL_DRIVER_API_SYNCHRONOUS_0(bool, isProtectedTexturesSupported)
|
||||
DECL_DRIVER_API_SYNCHRONOUS_0(bool, isDepthClampSupported)
|
||||
DECL_DRIVER_API_SYNCHRONOUS_0(uint8_t, getMaxDrawBuffers)
|
||||
DECL_DRIVER_API_SYNCHRONOUS_0(size_t, getMaxUniformBufferSize)
|
||||
DECL_DRIVER_API_SYNCHRONOUS_N(size_t, getMaxTextureSize, backend::SamplerType, target)
|
||||
DECL_DRIVER_API_SYNCHRONOUS_0(size_t, getMaxArrayTextureLayers)
|
||||
DECL_DRIVER_API_SYNCHRONOUS_0(math::float2, getClipSpaceParams)
|
||||
DECL_DRIVER_API_SYNCHRONOUS_N(void, setupExternalImage2, backend::Platform::ExternalImageHandleRef, image)
|
||||
DECL_DRIVER_API_SYNCHRONOUS_N(void, setupExternalImage, void*, image)
|
||||
|
||||
@@ -1,98 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2025 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.
|
||||
*/
|
||||
|
||||
#include "private/backend/BackendUtilsAndroid.h"
|
||||
|
||||
#include <android/hardware_buffer.h>
|
||||
|
||||
namespace filament::backend {
|
||||
|
||||
TextureFormat mapToFilamentFormat(unsigned int format, bool isSrgbTransfer) noexcept {
|
||||
if (isSrgbTransfer) {
|
||||
switch (format) {
|
||||
case AHARDWAREBUFFER_FORMAT_R8G8B8_UNORM:
|
||||
return TextureFormat::SRGB8;
|
||||
default:
|
||||
return TextureFormat::SRGB8_A8;
|
||||
}
|
||||
}
|
||||
switch (format) {
|
||||
case AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM:
|
||||
case AHARDWAREBUFFER_FORMAT_R8G8B8X8_UNORM:
|
||||
return TextureFormat::RGBA8;
|
||||
case AHARDWAREBUFFER_FORMAT_R8G8B8_UNORM:
|
||||
case AHARDWAREBUFFER_FORMAT_Y8Cb8Cr8_420:
|
||||
return TextureFormat::RGB8;
|
||||
case AHARDWAREBUFFER_FORMAT_R5G6B5_UNORM:
|
||||
return TextureFormat::RGB565;
|
||||
case AHARDWAREBUFFER_FORMAT_R16G16B16A16_FLOAT:
|
||||
return TextureFormat::RGBA16F;
|
||||
case AHARDWAREBUFFER_FORMAT_R10G10B10A2_UNORM:
|
||||
return TextureFormat::RGB10_A2;
|
||||
case AHARDWAREBUFFER_FORMAT_D16_UNORM:
|
||||
return TextureFormat::DEPTH16;
|
||||
case AHARDWAREBUFFER_FORMAT_D24_UNORM:
|
||||
return TextureFormat::DEPTH24;
|
||||
case AHARDWAREBUFFER_FORMAT_D24_UNORM_S8_UINT:
|
||||
return TextureFormat::DEPTH24_STENCIL8;
|
||||
case AHARDWAREBUFFER_FORMAT_D32_FLOAT:
|
||||
return TextureFormat::DEPTH32F;
|
||||
case AHARDWAREBUFFER_FORMAT_D32_FLOAT_S8_UINT:
|
||||
return TextureFormat::DEPTH32F_STENCIL8;
|
||||
case AHARDWAREBUFFER_FORMAT_S8_UINT:
|
||||
return TextureFormat::STENCIL8;
|
||||
case AHARDWAREBUFFER_FORMAT_R8_UNORM:
|
||||
return TextureFormat::R8;
|
||||
default:
|
||||
return TextureFormat::UNUSED;
|
||||
}
|
||||
}
|
||||
|
||||
TextureUsage mapToFilamentUsage(unsigned int usage, TextureFormat format) noexcept {
|
||||
TextureUsage usageFlags = TextureUsage::NONE;
|
||||
|
||||
if (usage & AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE) {
|
||||
usageFlags |= TextureUsage::SAMPLEABLE;
|
||||
}
|
||||
|
||||
if (usage & AHARDWAREBUFFER_USAGE_GPU_FRAMEBUFFER) {
|
||||
if (isDepthFormat(format)) {
|
||||
usageFlags |= TextureUsage::DEPTH_ATTACHMENT;
|
||||
}
|
||||
if (isStencilFormat(format)) {
|
||||
usageFlags |= TextureUsage::STENCIL_ATTACHMENT;
|
||||
}
|
||||
if (isColorFormat(format)) {
|
||||
usageFlags |= TextureUsage::COLOR_ATTACHMENT;
|
||||
}
|
||||
}
|
||||
|
||||
if (usage & AHARDWAREBUFFER_USAGE_GPU_DATA_BUFFER) {
|
||||
usageFlags |= TextureUsage::UPLOADABLE;
|
||||
}
|
||||
|
||||
if (usage & AHARDWAREBUFFER_USAGE_PROTECTED_CONTENT) {
|
||||
usageFlags |= TextureUsage::PROTECTED;
|
||||
}
|
||||
|
||||
if (usageFlags == TextureUsage::NONE) {
|
||||
usageFlags = TextureUsage::COLOR_ATTACHMENT | TextureUsage::SAMPLEABLE;
|
||||
}
|
||||
|
||||
return usageFlags;
|
||||
}
|
||||
|
||||
} // namespace backend::filament
|
||||
@@ -66,7 +66,7 @@ filament::backend::Platform* createDefaultMetalPlatform();
|
||||
|
||||
#include "noop/PlatformNoop.h"
|
||||
#if defined(FILAMENT_SUPPORTS_WEBGPU)
|
||||
#include "backend/platforms/WebGPUPlatform.h"
|
||||
#include "webgpu/WebGPUPlatform.h"
|
||||
#endif
|
||||
|
||||
namespace filament::backend {
|
||||
|
||||
@@ -1177,16 +1177,6 @@ size_t MetalDriver::getMaxUniformBufferSize() {
|
||||
return 256 * 1024 * 1024; // TODO: return the actual size instead of hardcoding the minspec
|
||||
}
|
||||
|
||||
size_t MetalDriver::getMaxTextureSize(SamplerType) {
|
||||
// TODO: return the actual size instead of hardcoding the minspec
|
||||
return 2048;
|
||||
}
|
||||
|
||||
size_t MetalDriver::getMaxArrayTextureLayers() {
|
||||
// TODO: return the actual size instead of hardcoding the minspec
|
||||
return 256;
|
||||
}
|
||||
|
||||
void MetalDriver::updateIndexBuffer(Handle<HwIndexBuffer> ibh, BufferDescriptor&& data,
|
||||
uint32_t byteOffset) {
|
||||
FILAMENT_CHECK_PRECONDITION(data.buffer)
|
||||
|
||||
@@ -138,7 +138,6 @@ bool MetalShaderCompiler::isParallelShaderCompileSupported() const noexcept {
|
||||
case ShaderLanguage::ESSL1:
|
||||
case ShaderLanguage::ESSL3:
|
||||
case ShaderLanguage::SPIRV:
|
||||
case ShaderLanguage::WGSL:
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
@@ -240,14 +240,6 @@ size_t NoopDriver::getMaxUniformBufferSize() {
|
||||
return 16384u;
|
||||
}
|
||||
|
||||
size_t NoopDriver::getMaxTextureSize(SamplerType target) {
|
||||
return 2048u;
|
||||
}
|
||||
|
||||
size_t NoopDriver::getMaxArrayTextureLayers() {
|
||||
return 256u;
|
||||
}
|
||||
|
||||
void NoopDriver::updateIndexBuffer(Handle<HwIndexBuffer> ibh, BufferDescriptor&& p,
|
||||
uint32_t byteOffset) {
|
||||
scheduleDestroy(std::move(p));
|
||||
|
||||
@@ -94,22 +94,18 @@ OpenGLContext::OpenGLContext(OpenGLPlatform& platform,
|
||||
}
|
||||
#endif
|
||||
|
||||
initExtensions(&ext, state.major, state.minor);
|
||||
OpenGLContext::initExtensions(&ext, state.major, state.minor);
|
||||
|
||||
initProcs(&procs, ext, state.major, state.minor);
|
||||
OpenGLContext::initProcs(&procs, ext, state.major, state.minor);
|
||||
|
||||
initBugs(&bugs, ext, state.major, state.minor,
|
||||
OpenGLContext::initBugs(&bugs, ext, state.major, state.minor,
|
||||
state.vendor, state.renderer, state.version, state.shader);
|
||||
|
||||
glGetIntegerv(GL_MAX_RENDERBUFFER_SIZE, &gets.max_renderbuffer_size);
|
||||
glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &gets.max_texture_image_units);
|
||||
glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &gets.max_combined_texture_image_units);
|
||||
glGetIntegerv(GL_MAX_TEXTURE_SIZE, &gets.max_texture_size);
|
||||
glGetIntegerv(GL_MAX_CUBE_MAP_TEXTURE_SIZE, &gets.max_cubemap_texture_size);
|
||||
glGetIntegerv(GL_MAX_3D_TEXTURE_SIZE, &gets.max_3d_texture_size);
|
||||
glGetIntegerv(GL_MAX_ARRAY_TEXTURE_LAYERS, &gets.max_array_texture_layers);
|
||||
|
||||
mFeatureLevel = resolveFeatureLevel(state.major, state.minor, ext, gets, bugs);
|
||||
mFeatureLevel = OpenGLContext::resolveFeatureLevel(state.major, state.minor, ext, gets, bugs);
|
||||
|
||||
#ifdef BACKEND_OPENGL_VERSION_GLES
|
||||
mShaderModel = ShaderModel::MOBILE;
|
||||
@@ -181,14 +177,6 @@ OpenGLContext::OpenGLContext(OpenGLPlatform& platform,
|
||||
<< gets.max_anisotropy << '\n'
|
||||
<< "GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS = "
|
||||
<< gets.max_combined_texture_image_units << '\n'
|
||||
<< "GL_MAX_TEXTURE_SIZE = "
|
||||
<< gets.max_texture_size << '\n'
|
||||
<< "GL_MAX_CUBE_MAP_TEXTURE_SIZE = "
|
||||
<< gets.max_cubemap_texture_size << '\n'
|
||||
<< "GL_MAX_3D_TEXTURE_SIZE = "
|
||||
<< gets.max_3d_texture_size << '\n'
|
||||
<< "GL_MAX_ARRAY_TEXTURE_LAYERS = "
|
||||
<< gets.max_array_texture_layers << '\n'
|
||||
<< "GL_MAX_DRAW_BUFFERS = "
|
||||
<< gets.max_draw_buffers << '\n'
|
||||
<< "GL_MAX_RENDERBUFFER_SIZE = "
|
||||
|
||||
@@ -203,10 +203,6 @@ public:
|
||||
GLint max_renderbuffer_size;
|
||||
GLint max_samples;
|
||||
GLint max_texture_image_units;
|
||||
GLint max_texture_size;
|
||||
GLint max_cubemap_texture_size;
|
||||
GLint max_3d_texture_size;
|
||||
GLint max_array_texture_layers;
|
||||
GLint max_transform_feedback_separate_attribs;
|
||||
GLint max_uniform_block_size;
|
||||
GLint max_uniform_buffer_bindings;
|
||||
|
||||
@@ -2460,26 +2460,6 @@ size_t OpenGLDriver::getMaxUniformBufferSize() {
|
||||
return mContext.gets.max_uniform_block_size;
|
||||
}
|
||||
|
||||
size_t OpenGLDriver::getMaxTextureSize(SamplerType target) {
|
||||
switch (target) {
|
||||
case SamplerType::SAMPLER_2D:
|
||||
case SamplerType::SAMPLER_2D_ARRAY:
|
||||
case SamplerType::SAMPLER_EXTERNAL:
|
||||
return mContext.gets.max_texture_size;
|
||||
case SamplerType::SAMPLER_CUBEMAP:
|
||||
return mContext.gets.max_cubemap_texture_size;
|
||||
case SamplerType::SAMPLER_3D:
|
||||
return mContext.gets.max_3d_texture_size;
|
||||
case SamplerType::SAMPLER_CUBEMAP_ARRAY:
|
||||
return mContext.gets.max_cubemap_texture_size;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t OpenGLDriver::getMaxArrayTextureLayers() {
|
||||
return mContext.gets.max_array_texture_layers;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Swap chains
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
|
||||
@@ -22,10 +22,6 @@
|
||||
#include <dlfcn.h>
|
||||
#include <memory>
|
||||
|
||||
// This is to ensure that linking during compilation will not fail even if
|
||||
// OSMesaGetProcAddress is not linked.
|
||||
__attribute__((weak)) OSMESAproc OSMesaGetProcAddress(char const*);
|
||||
|
||||
namespace filament::backend {
|
||||
|
||||
using namespace backend;
|
||||
@@ -55,10 +51,10 @@ private:
|
||||
using GetProcAddressFunc = OSMESAproc (*)(const char* funcName);
|
||||
|
||||
public:
|
||||
CreateContextFunc fOSMesaCreateContext;
|
||||
DestroyContextFunc fOSMesaDestroyContext;
|
||||
MakeCurrentFunc fOSMesaMakeCurrent;
|
||||
GetProcAddressFunc fOSMesaGetProcAddress;
|
||||
CreateContextFunc OSMesaCreateContext;
|
||||
DestroyContextFunc OSMesaDestroyContext;
|
||||
MakeCurrentFunc OSMesaMakeCurrent;
|
||||
GetProcAddressFunc OSMesaGetProcAddress;
|
||||
|
||||
OSMesaAPI() {
|
||||
constexpr char const* libraryNames[] = {"libOSMesa.so", "libosmesa.so"};
|
||||
@@ -69,25 +65,18 @@ public:
|
||||
}
|
||||
}
|
||||
if (mLib) {
|
||||
// Loading from a libosmesa.os
|
||||
fOSMesaGetProcAddress = (GetProcAddressFunc) dlsym(mLib, "OSMesaGetProcAddress");
|
||||
OSMesaGetProcAddress = (GetProcAddressFunc) dlsym(mLib, "OSMesaGetProcAddress");
|
||||
} else {
|
||||
// Filament is built into a .so
|
||||
fOSMesaGetProcAddress = (GetProcAddressFunc) dlsym(RTLD_LOCAL, "OSMesaGetProcAddress");
|
||||
OSMesaGetProcAddress = (GetProcAddressFunc) dlsym(RTLD_LOCAL, "OSMesaGetProcAddress");
|
||||
}
|
||||
|
||||
if (!fOSMesaGetProcAddress) {
|
||||
// Statically linking osmesa
|
||||
fOSMesaGetProcAddress = OSMesaGetProcAddress;
|
||||
}
|
||||
FILAMENT_CHECK_PRECONDITION(OSMesaGetProcAddress)
|
||||
<< "Unable to against libOSMesa to create a software GL context";
|
||||
|
||||
FILAMENT_CHECK_PRECONDITION(fOSMesaGetProcAddress)
|
||||
<< "Unable to link against libOSMesa to create a software GL context";
|
||||
|
||||
fOSMesaCreateContext = (CreateContextFunc) fOSMesaGetProcAddress("OSMesaCreateContext");
|
||||
fOSMesaDestroyContext =
|
||||
(DestroyContextFunc) fOSMesaGetProcAddress("OSMesaDestroyContext");
|
||||
fOSMesaMakeCurrent = (MakeCurrentFunc) fOSMesaGetProcAddress("OSMesaMakeCurrent");
|
||||
OSMesaCreateContext = (CreateContextFunc) OSMesaGetProcAddress("OSMesaCreateContext");
|
||||
OSMesaDestroyContext =
|
||||
(DestroyContextFunc) OSMesaGetProcAddress("OSMesaDestroyContext");
|
||||
OSMesaMakeCurrent = (MakeCurrentFunc) OSMesaGetProcAddress("OSMesaMakeCurrent");
|
||||
}
|
||||
|
||||
~OSMesaAPI() {
|
||||
@@ -108,7 +97,7 @@ Driver* PlatformOSMesa::createDriver(void* const sharedGLContext,
|
||||
|
||||
FILAMENT_CHECK_PRECONDITION(sharedGLContext == nullptr)
|
||||
<< "shared GL context is not supported with PlatformOSMesa";
|
||||
mContext = api->fOSMesaCreateContext(GL_RGBA, NULL);
|
||||
mContext = api->OSMesaCreateContext(GL_RGBA, NULL);
|
||||
|
||||
// We need to do a no-op makecurrent here so that the context will be in a correct state before
|
||||
// any GL calls.
|
||||
@@ -124,7 +113,7 @@ Driver* PlatformOSMesa::createDriver(void* const sharedGLContext,
|
||||
|
||||
void PlatformOSMesa::terminate() noexcept {
|
||||
OSMesaAPI* api = (OSMesaAPI*) mOsMesaApi;
|
||||
api->fOSMesaDestroyContext(mContext);
|
||||
api->OSMesaDestroyContext(mContext);
|
||||
delete api;
|
||||
mOsMesaApi = nullptr;
|
||||
|
||||
@@ -152,7 +141,7 @@ bool PlatformOSMesa::makeCurrent(ContextType type, SwapChain* drawSwapChain,
|
||||
OSMesaAPI* api = (OSMesaAPI*) mOsMesaApi;
|
||||
OSMesaSwapchain* impl = (OSMesaSwapchain*) drawSwapChain;
|
||||
|
||||
auto result = api->fOSMesaMakeCurrent(mContext, (BackingType*) impl->buffer.get(),
|
||||
auto result = api->OSMesaMakeCurrent(mContext, (BackingType*) impl->buffer.get(),
|
||||
BACKING_GL_TYPE, impl->width, impl->height);
|
||||
FILAMENT_CHECK_POSTCONDITION(result == GL_TRUE) << "OSMesaMakeCurrent failed!";
|
||||
|
||||
|
||||
@@ -554,45 +554,13 @@ void VulkanDriver::createTextureViewSwizzleR(Handle<HwTexture> th, Handle<HwText
|
||||
texture.inc();
|
||||
}
|
||||
|
||||
void VulkanDriver::createTextureExternalImage2R(Handle<HwTexture> th, backend::SamplerType target,
|
||||
backend::TextureFormat format, uint32_t width, uint32_t height, backend::TextureUsage usage,
|
||||
void VulkanDriver::createTextureExternalImage2R(Handle<HwTexture> th,
|
||||
backend::SamplerType target, backend::TextureFormat format,
|
||||
uint32_t width, uint32_t height, backend::TextureUsage usage,
|
||||
Platform::ExternalImageHandleRef externalImage) {
|
||||
FVK_SYSTRACE_SCOPE();
|
||||
const auto& metadata = mPlatform->getExternalImageMetadata(externalImage);
|
||||
if (metadata.isProtected) {
|
||||
usage |= backend::TextureUsage::PROTECTED;
|
||||
}
|
||||
|
||||
VkImageUsageFlags vkUsage = metadata.usage;
|
||||
if (any(usage & TextureUsage::BLIT_SRC)) {
|
||||
vkUsage |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
|
||||
}
|
||||
|
||||
if (any(usage & (TextureUsage::BLIT_DST & TextureUsage::UPLOADABLE))) {
|
||||
vkUsage |= VK_IMAGE_USAGE_TRANSFER_DST_BIT;
|
||||
}
|
||||
|
||||
assert_invariant(width == metadata.width);
|
||||
assert_invariant(height == metadata.height);
|
||||
assert_invariant(fvkutils::getVkFormat(format) == metadata.format);
|
||||
|
||||
VkMemoryPropertyFlags const requiredMemoryFlags = any(usage & TextureUsage::UPLOADABLE)
|
||||
? VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT
|
||||
: VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
|
||||
uint32_t const memoryTypeIndex =
|
||||
mContext.selectMemoryType(metadata.memoryTypeBits, requiredMemoryFlags);
|
||||
FILAMENT_CHECK_POSTCONDITION(memoryTypeIndex != VK_MAX_MEMORY_TYPES)
|
||||
<< "failed to find a valid memory type for external image memory.";
|
||||
|
||||
const auto& data =
|
||||
mPlatform->createExternalImageData(externalImage, metadata, memoryTypeIndex, vkUsage);
|
||||
|
||||
auto texture = resource_ptr<VulkanTexture>::make(&mResourceManager, th, mPlatform->getDevice(),
|
||||
mAllocator, &mResourceManager, &mCommands, data.first, data.second, metadata.format,
|
||||
metadata.samples, metadata.width, metadata.height, metadata.layerCount, usage,
|
||||
mStagePool);
|
||||
|
||||
texture.inc();
|
||||
// FIXME: implement createTextureExternalImage2R
|
||||
}
|
||||
|
||||
void VulkanDriver::createTextureExternalImageR(Handle<HwTexture> th, backend::SamplerType target,
|
||||
@@ -600,7 +568,22 @@ void VulkanDriver::createTextureExternalImageR(Handle<HwTexture> th, backend::Sa
|
||||
void* externalImage) {
|
||||
FVK_SYSTRACE_SCOPE();
|
||||
|
||||
// not supported in this backend
|
||||
const auto& metadata = mPlatform->getExternalImageMetadata(externalImage);
|
||||
if (metadata.isProtected) {
|
||||
usage |= backend::TextureUsage::PROTECTED;
|
||||
}
|
||||
|
||||
assert_invariant(width == metadata.width);
|
||||
assert_invariant(height == metadata.height);
|
||||
assert_invariant(fvkutils::getVkFormat(format) == metadata.format);
|
||||
|
||||
const auto& data = mPlatform->createExternalImage(externalImage, metadata);
|
||||
|
||||
auto texture = resource_ptr<VulkanTexture>::make(&mResourceManager, th, mPlatform->getDevice(),
|
||||
mAllocator, &mResourceManager, &mCommands, data.first, data.second, metadata.format,
|
||||
1, metadata.width, metadata.height, /*depth=*/1, usage, mStagePool);
|
||||
|
||||
texture.inc();
|
||||
}
|
||||
|
||||
void VulkanDriver::createTextureExternalImagePlaneR(Handle<HwTexture> th,
|
||||
@@ -1147,16 +1130,6 @@ size_t VulkanDriver::getMaxUniformBufferSize() {
|
||||
return 32768;
|
||||
}
|
||||
|
||||
size_t VulkanDriver::getMaxTextureSize(SamplerType) {
|
||||
// TODO: return the actual size instead of hardcoded value
|
||||
return 2048;
|
||||
}
|
||||
|
||||
size_t VulkanDriver::getMaxArrayTextureLayers() {
|
||||
// TODO: return the actual size instead of hardcoded value
|
||||
return 256;
|
||||
}
|
||||
|
||||
void VulkanDriver::setVertexBufferObject(Handle<HwVertexBuffer> vbh, uint32_t index,
|
||||
Handle<HwBufferObject> boh) {
|
||||
auto vb = resource_ptr<VulkanVertexBuffer>::cast(&mResourceManager, vbh);
|
||||
@@ -1293,9 +1266,10 @@ void VulkanDriver::generateMipmaps(Handle<HwTexture> th) {
|
||||
mBlitter.blit(VK_FILTER_LINEAR, dst, dstOffsets, src, srcOffsets);
|
||||
}
|
||||
|
||||
level++;
|
||||
srcw = dstw;
|
||||
srch = dsth;
|
||||
} while ((srcw > 1 || srch > 1) && ++level < t->levels - 1);
|
||||
} while ((srcw > 1 || srch > 1) && level < t->levels);
|
||||
}
|
||||
|
||||
void VulkanDriver::compilePrograms(CompilerPriorityQueue priority,
|
||||
|
||||
@@ -23,6 +23,79 @@ using namespace bluevk;
|
||||
|
||||
namespace filament::backend {
|
||||
|
||||
constexpr inline VkSamplerAddressMode getWrapMode(SamplerWrapMode mode) noexcept {
|
||||
switch (mode) {
|
||||
case SamplerWrapMode::REPEAT:
|
||||
return VK_SAMPLER_ADDRESS_MODE_REPEAT;
|
||||
case SamplerWrapMode::CLAMP_TO_EDGE:
|
||||
return VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
|
||||
case SamplerWrapMode::MIRRORED_REPEAT:
|
||||
return VK_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT;
|
||||
}
|
||||
}
|
||||
|
||||
constexpr inline VkFilter getFilter(SamplerMinFilter filter) noexcept {
|
||||
switch (filter) {
|
||||
case SamplerMinFilter::NEAREST:
|
||||
return VK_FILTER_NEAREST;
|
||||
case SamplerMinFilter::LINEAR:
|
||||
return VK_FILTER_LINEAR;
|
||||
case SamplerMinFilter::NEAREST_MIPMAP_NEAREST:
|
||||
return VK_FILTER_NEAREST;
|
||||
case SamplerMinFilter::LINEAR_MIPMAP_NEAREST:
|
||||
return VK_FILTER_LINEAR;
|
||||
case SamplerMinFilter::NEAREST_MIPMAP_LINEAR:
|
||||
return VK_FILTER_NEAREST;
|
||||
case SamplerMinFilter::LINEAR_MIPMAP_LINEAR:
|
||||
return VK_FILTER_LINEAR;
|
||||
}
|
||||
}
|
||||
|
||||
constexpr inline VkFilter getFilter(SamplerMagFilter filter) noexcept {
|
||||
switch (filter) {
|
||||
case SamplerMagFilter::NEAREST:
|
||||
return VK_FILTER_NEAREST;
|
||||
case SamplerMagFilter::LINEAR:
|
||||
return VK_FILTER_LINEAR;
|
||||
}
|
||||
}
|
||||
|
||||
constexpr inline VkSamplerMipmapMode getMipmapMode(SamplerMinFilter filter) noexcept {
|
||||
switch (filter) {
|
||||
case SamplerMinFilter::NEAREST:
|
||||
return VK_SAMPLER_MIPMAP_MODE_NEAREST;
|
||||
case SamplerMinFilter::LINEAR:
|
||||
return VK_SAMPLER_MIPMAP_MODE_NEAREST;
|
||||
case SamplerMinFilter::NEAREST_MIPMAP_NEAREST:
|
||||
return VK_SAMPLER_MIPMAP_MODE_NEAREST;
|
||||
case SamplerMinFilter::LINEAR_MIPMAP_NEAREST:
|
||||
return VK_SAMPLER_MIPMAP_MODE_NEAREST;
|
||||
case SamplerMinFilter::NEAREST_MIPMAP_LINEAR:
|
||||
return VK_SAMPLER_MIPMAP_MODE_LINEAR;
|
||||
case SamplerMinFilter::LINEAR_MIPMAP_LINEAR:
|
||||
return VK_SAMPLER_MIPMAP_MODE_LINEAR;
|
||||
}
|
||||
}
|
||||
|
||||
constexpr inline float getMaxLod(SamplerMinFilter filter) noexcept {
|
||||
switch (filter) {
|
||||
case SamplerMinFilter::NEAREST:
|
||||
case SamplerMinFilter::LINEAR:
|
||||
// The Vulkan spec recommends a max LOD of 0.25 to "disable" mipmapping.
|
||||
// See "Mapping of OpenGL to Vulkan filter modes" in the VK Spec.
|
||||
return 0.25f;
|
||||
case SamplerMinFilter::NEAREST_MIPMAP_NEAREST:
|
||||
case SamplerMinFilter::LINEAR_MIPMAP_NEAREST:
|
||||
case SamplerMinFilter::NEAREST_MIPMAP_LINEAR:
|
||||
case SamplerMinFilter::LINEAR_MIPMAP_LINEAR:
|
||||
return VK_LOD_CLAMP_NONE;
|
||||
}
|
||||
}
|
||||
|
||||
constexpr inline VkBool32 getCompareEnable(SamplerCompareMode mode) noexcept {
|
||||
return mode == SamplerCompareMode::NONE ? VK_FALSE : VK_TRUE;
|
||||
}
|
||||
|
||||
VulkanSamplerCache::VulkanSamplerCache(VkDevice device)
|
||||
: mDevice(device) {}
|
||||
|
||||
@@ -33,18 +106,18 @@ VkSampler VulkanSamplerCache::getSampler(SamplerParams params) noexcept {
|
||||
}
|
||||
VkSamplerCreateInfo samplerInfo {
|
||||
.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO,
|
||||
.magFilter = fvkutils::getFilter(params.filterMag),
|
||||
.minFilter = fvkutils::getFilter(params.filterMin),
|
||||
.mipmapMode = fvkutils::getMipmapMode(params.filterMin),
|
||||
.addressModeU = fvkutils::getWrapMode(params.wrapS),
|
||||
.addressModeV = fvkutils::getWrapMode(params.wrapT),
|
||||
.addressModeW = fvkutils::getWrapMode(params.wrapR),
|
||||
.anisotropyEnable = params.anisotropyLog2 == 0 ? VK_FALSE : VK_TRUE,
|
||||
.magFilter = getFilter(params.filterMag),
|
||||
.minFilter = getFilter(params.filterMin),
|
||||
.mipmapMode = getMipmapMode(params.filterMin),
|
||||
.addressModeU = getWrapMode(params.wrapS),
|
||||
.addressModeV = getWrapMode(params.wrapT),
|
||||
.addressModeW = getWrapMode(params.wrapR),
|
||||
.anisotropyEnable = params.anisotropyLog2 == 0 ? 0u : 1u,
|
||||
.maxAnisotropy = (float)(1u << params.anisotropyLog2),
|
||||
.compareEnable = fvkutils::getCompareEnable(params.compareMode),
|
||||
.compareEnable = getCompareEnable(params.compareMode),
|
||||
.compareOp = fvkutils::getCompareOp(params.compareFunc),
|
||||
.minLod = 0.0f,
|
||||
.maxLod = fvkutils::getMaxLod(params.filterMin),
|
||||
.maxLod = getMaxLod(params.filterMin),
|
||||
.borderColor = VK_BORDER_COLOR_INT_OPAQUE_BLACK,
|
||||
.unnormalizedCoordinates = VK_FALSE
|
||||
};
|
||||
|
||||
@@ -978,28 +978,15 @@ VkQueue VulkanPlatform::getProtectedGraphicsQueue() const noexcept {
|
||||
}
|
||||
|
||||
VulkanPlatform::ExternalImageMetadata VulkanPlatform::getExternalImageMetadata(
|
||||
ExternalImageHandleRef externalImage) {
|
||||
void* externalImage) {
|
||||
return getExternalImageMetadataImpl(externalImage, mImpl->mDevice);
|
||||
}
|
||||
|
||||
VulkanPlatform::ImageData VulkanPlatform::createExternalImageData(
|
||||
ExternalImageHandleRef externalImage, const ExternalImageMetadata& metadata,
|
||||
uint32_t memoryTypeIndex, VkImageUsageFlags usage) {
|
||||
return createExternalImageDataImpl(externalImage, mImpl->mDevice, metadata, memoryTypeIndex,
|
||||
usage);
|
||||
VulkanPlatform::ImageData VulkanPlatform::createExternalImage(void* externalImage,
|
||||
const ExternalImageMetadata& metadata) {
|
||||
return createExternalImageImpl(externalImage, mImpl->mDevice, nullptr, metadata);
|
||||
}
|
||||
|
||||
VkSampler VulkanPlatform::createExternalSampler(SamplerYcbcrConversion chroma,
|
||||
SamplerParams sampler, uint32_t internalFormat) {
|
||||
return createExternalSamplerImpl(mImpl->mDevice, chroma, sampler, internalFormat);
|
||||
}
|
||||
|
||||
VkImageView VulkanPlatform::createExternalImageView(SamplerYcbcrConversion chroma,
|
||||
uint32_t internalFormat, VkImage image, VkImageSubresourceRange range,
|
||||
VkImageViewType viewType, VkComponentMapping swizzle) {
|
||||
return createExternalImageViewImpl(mImpl->mDevice, chroma, internalFormat, image, range,
|
||||
viewType, swizzle);
|
||||
}
|
||||
#undef SWAPCHAIN_RET_FUNC
|
||||
|
||||
}// namespace filament::backend
|
||||
|
||||
@@ -15,59 +15,26 @@
|
||||
*/
|
||||
#include <backend/platforms/VulkanPlatform.h>
|
||||
|
||||
#include <backend/DriverEnums.h>
|
||||
#include <backend/platforms/VulkanPlatformAndroid.h>
|
||||
#include <private/backend/BackendUtilsAndroid.h>
|
||||
|
||||
#include "vulkan/VulkanConstants.h"
|
||||
|
||||
#include <utils/Panic.h>
|
||||
#include "vulkan/utils/Image.h"
|
||||
#include "vulkan/utils/Conversion.h"
|
||||
|
||||
#include <bluevk/BlueVK.h>
|
||||
|
||||
#include <android/hardware_buffer.h>
|
||||
#include <android/native_window.h>
|
||||
|
||||
#include <utility>
|
||||
|
||||
using namespace bluevk;
|
||||
|
||||
namespace filament::backend {
|
||||
|
||||
namespace {
|
||||
|
||||
VkFormat transformVkFormat(VkFormat format, bool sRGB) {
|
||||
if (!sRGB) {
|
||||
return format;
|
||||
}
|
||||
|
||||
switch (format) {
|
||||
case VK_FORMAT_R8G8B8A8_UNORM:
|
||||
format = VK_FORMAT_R8G8B8A8_SRGB;
|
||||
break;
|
||||
case VK_FORMAT_R8G8B8_UNORM:
|
||||
format = VK_FORMAT_R8G8B8_SRGB;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return format;
|
||||
}
|
||||
|
||||
bool isProtectedFromUsage(uint64_t usage) {
|
||||
return (usage & AHARDWAREBUFFER_USAGE_PROTECTED_CONTENT) ? true : false;
|
||||
}
|
||||
|
||||
std::pair<VkFormat, VkImageUsageFlags> getVKFormatAndUsage(const AHardwareBuffer_Desc& desc,
|
||||
bool sRGB) {
|
||||
VkFormat format = VK_FORMAT_UNDEFINED;
|
||||
VkImageUsageFlags usage = 0;
|
||||
void getVKFormatAndUsage(const AHardwareBuffer_Desc& desc, VkFormat& format,
|
||||
VkImageUsageFlags& usage, bool& isProtected) {
|
||||
// Refer to "11.2.17. External Memory Handle Types" in the spec, and
|
||||
// Tables 13/14 for how the following derivation works.
|
||||
bool isDepthFormat = false;
|
||||
isProtected = false;
|
||||
switch (desc.format) {
|
||||
case AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM:
|
||||
format = VK_FORMAT_R8G8B8A8_UNORM;
|
||||
@@ -115,8 +82,6 @@ std::pair<VkFormat, VkImageUsageFlags> getVKFormatAndUsage(const AHardwareBuffer
|
||||
format = VK_FORMAT_UNDEFINED;
|
||||
}
|
||||
|
||||
format = transformVkFormat(format, sRGB);
|
||||
|
||||
// The following only concern usage flags derived from Table 14.
|
||||
usage = 0;
|
||||
if (desc.usage & AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE) {
|
||||
@@ -133,14 +98,16 @@ std::pair<VkFormat, VkImageUsageFlags> getVKFormatAndUsage(const AHardwareBuffer
|
||||
if (desc.usage & AHARDWAREBUFFER_USAGE_GPU_DATA_BUFFER) {
|
||||
usage = VK_IMAGE_USAGE_STORAGE_BIT;
|
||||
}
|
||||
|
||||
return { format, usage };
|
||||
if (desc.usage & AHARDWAREBUFFER_USAGE_PROTECTED_CONTENT) {
|
||||
isProtected = true;
|
||||
}
|
||||
}
|
||||
|
||||
VulkanPlatform::ImageData allocateExternalImage(AHardwareBuffer* buffer, VkDevice device,
|
||||
VulkanPlatform::ExternalImageMetadata const& metadata, uint32_t memoryTypeIndex,
|
||||
VkImageUsageFlags usage) {
|
||||
VulkanPlatform::ImageData allocateExternalImage(void* externalBuffer,
|
||||
VkDevice device, const VkAllocationCallbacks* allocator,
|
||||
VulkanPlatform::ExternalImageMetadata const& metadata) {
|
||||
VulkanPlatform::ImageData data;
|
||||
AHardwareBuffer* buffer = static_cast<AHardwareBuffer*>(externalBuffer);
|
||||
|
||||
// if external format we need to specifiy it in the allocation
|
||||
const bool useExternalFormat = metadata.format == VK_FORMAT_UNDEFINED;
|
||||
@@ -148,8 +115,8 @@ VulkanPlatform::ImageData allocateExternalImage(AHardwareBuffer* buffer, VkDevic
|
||||
const VkExternalFormatANDROID externalFormat = {
|
||||
.sType = VK_STRUCTURE_TYPE_EXTERNAL_FORMAT_ANDROID,
|
||||
.pNext = nullptr,
|
||||
// pass down the format (external means we don't have it VK defined)
|
||||
.externalFormat = metadata.externalFormat,
|
||||
.externalFormat = metadata
|
||||
.externalFormat,// pass down the format (external means we don't have it VK defined)
|
||||
};
|
||||
const VkExternalMemoryImageCreateInfo externalCreateInfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO,
|
||||
@@ -168,10 +135,12 @@ VulkanPlatform::ImageData allocateExternalImage(AHardwareBuffer* buffer, VkDevic
|
||||
};
|
||||
imageInfo.mipLevels = 1;
|
||||
imageInfo.arrayLayers = metadata.layers;
|
||||
imageInfo.samples = metadata.samples;
|
||||
imageInfo.usage = usage;
|
||||
imageInfo.usage = metadata.usage;
|
||||
// In the unprotected case add R/W capabilities
|
||||
if (metadata.isProtected == false)
|
||||
imageInfo.usage |= VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
|
||||
|
||||
VkResult result = vkCreateImage(device, &imageInfo, VKALLOC, &data.first);
|
||||
VkResult result = vkCreateImage(device, &imageInfo, allocator, &data.first);
|
||||
FILAMENT_CHECK_POSTCONDITION(result == VK_SUCCESS)
|
||||
<< "vkCreateImage failed with error=" << static_cast<int32_t>(result);
|
||||
|
||||
@@ -187,66 +156,36 @@ VulkanPlatform::ImageData allocateExternalImage(AHardwareBuffer* buffer, VkDevic
|
||||
.image = data.first,
|
||||
.buffer = VK_NULL_HANDLE,
|
||||
};
|
||||
VkMemoryAllocateInfo allocInfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
|
||||
VkMemoryAllocateInfo allocInfo = {.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
|
||||
.pNext = &memoryDedicatedAllocateInfo,
|
||||
.allocationSize = metadata.allocationSize,
|
||||
.memoryTypeIndex = memoryTypeIndex,
|
||||
};
|
||||
result = vkAllocateMemory(device, &allocInfo, VKALLOC, &data.second);
|
||||
.memoryTypeIndex = metadata.memoryTypeBits};
|
||||
result = vkAllocateMemory(device, &allocInfo, allocator, &data.second);
|
||||
FILAMENT_CHECK_POSTCONDITION(result == VK_SUCCESS)
|
||||
<< "vkAllocateMemory failed with error=" << static_cast<int32_t>(result);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace fvkandroid {
|
||||
|
||||
ExternalImageVulkanAndroid::~ExternalImageVulkanAndroid() = default;
|
||||
|
||||
Platform::ExternalImageHandle createExternalImage(AHardwareBuffer const* buffer,
|
||||
bool sRGB) noexcept {
|
||||
if (__builtin_available(android 26, *)) {
|
||||
AHardwareBuffer_Desc hardwareBufferDescription = {};
|
||||
AHardwareBuffer_describe(buffer, &hardwareBufferDescription);
|
||||
|
||||
auto* const p = new (std::nothrow) ExternalImageVulkanAndroid;
|
||||
p->aHardwareBuffer = const_cast<AHardwareBuffer*>(buffer);
|
||||
p->sRGB = sRGB;
|
||||
p->height = hardwareBufferDescription.height;
|
||||
p->width = hardwareBufferDescription.width;
|
||||
TextureFormat textureFormat = mapToFilamentFormat(hardwareBufferDescription.format, sRGB);
|
||||
p->format = textureFormat;
|
||||
p->usage = mapToFilamentUsage(hardwareBufferDescription.usage, textureFormat);
|
||||
return Platform::ExternalImageHandle{ p };
|
||||
}
|
||||
|
||||
return Platform::ExternalImageHandle{};
|
||||
}
|
||||
|
||||
} // namespace fvkandroid
|
||||
|
||||
VulkanPlatform::ExternalImageMetadata VulkanPlatform::getExternalImageMetadataImpl(
|
||||
ExternalImageHandleRef externalImage, VkDevice device) {
|
||||
auto const* fvkExternalImage =
|
||||
static_cast<fvkandroid::ExternalImageVulkanAndroid const*>(externalImage.get());
|
||||
}// namespace
|
||||
|
||||
VulkanPlatform::ExternalImageMetadata VulkanPlatform::getExternalImageMetadataImpl(void* externalImage,
|
||||
VkDevice device) {
|
||||
ExternalImageMetadata metadata;
|
||||
AHardwareBuffer* buffer = fvkExternalImage->aHardwareBuffer;
|
||||
AHardwareBuffer* buffer = static_cast<AHardwareBuffer*>(externalImage);
|
||||
if (__builtin_available(android 26, *)) {
|
||||
AHardwareBuffer_Desc bufferDesc;
|
||||
AHardwareBuffer_describe(buffer, &bufferDesc);
|
||||
metadata.width = bufferDesc.width;
|
||||
metadata.height = bufferDesc.height;
|
||||
metadata.layers = bufferDesc.layers;
|
||||
metadata.isProtected = isProtectedFromUsage(bufferDesc.usage);
|
||||
std::tie(metadata.format, metadata.usage) =
|
||||
getVKFormatAndUsage(bufferDesc, fvkExternalImage->sRGB);
|
||||
|
||||
getVKFormatAndUsage(bufferDesc, metadata.format, metadata.usage, metadata.isProtected);
|
||||
}
|
||||
// In the unprotected case add R/W capabilities
|
||||
if (metadata.isProtected == false) {
|
||||
metadata.usage |= VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
|
||||
}
|
||||
|
||||
metadata.samples = VK_SAMPLE_COUNT_1_BIT;
|
||||
|
||||
VkAndroidHardwareBufferFormatPropertiesANDROID formatInfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_ANDROID_HARDWARE_BUFFER_FORMAT_PROPERTIES_ANDROID,
|
||||
@@ -258,145 +197,26 @@ VulkanPlatform::ExternalImageMetadata VulkanPlatform::getExternalImageMetadataIm
|
||||
};
|
||||
VkResult result = vkGetAndroidHardwareBufferPropertiesANDROID(device, buffer, &properties);
|
||||
FILAMENT_CHECK_POSTCONDITION(result == VK_SUCCESS)
|
||||
<< "vkGetAndroidHardwareBufferProperties failed with error="
|
||||
<< static_cast<int32_t>(result);
|
||||
|
||||
VkFormat bufferPropertiesFormat = transformVkFormat(formatInfo.format, fvkExternalImage->sRGB);
|
||||
FILAMENT_CHECK_POSTCONDITION(metadata.format == bufferPropertiesFormat)
|
||||
<< "mismatched image format( " << metadata.format << ") and queried format("
|
||||
<< bufferPropertiesFormat << ") for external image (AHB)";
|
||||
<< "vkGetAndroidHardwareBufferProperties failed with error="
|
||||
<< static_cast<int32_t>(result);
|
||||
FILAMENT_CHECK_POSTCONDITION(metadata.format == formatInfo.format)
|
||||
<< "mismatched image format for external image (AHB)";
|
||||
metadata.externalFormat = formatInfo.externalFormat;
|
||||
metadata.allocationSize = properties.allocationSize;
|
||||
metadata.memoryTypeBits = properties.memoryTypeBits;
|
||||
return metadata;
|
||||
}
|
||||
|
||||
VulkanPlatform::ImageData VulkanPlatform::createExternalImageDataImpl(
|
||||
ExternalImageHandleRef externalImage, VkDevice device,
|
||||
const ExternalImageMetadata& metadata, uint32_t memoryTypeIndex, VkImageUsageFlags usage) {
|
||||
auto const* fvkExternalImage =
|
||||
static_cast<fvkandroid::ExternalImageVulkanAndroid const*>(externalImage.get());
|
||||
ImageData data = allocateExternalImage(fvkExternalImage->aHardwareBuffer, device, metadata,
|
||||
memoryTypeIndex, usage);
|
||||
VulkanPlatform::ImageData VulkanPlatform::createExternalImageImpl(void* externalImage,
|
||||
VkDevice device, const VkAllocationCallbacks* allocator,
|
||||
const ExternalImageMetadata& metadata) {
|
||||
ImageData data = allocateExternalImage(externalImage, device, allocator, metadata);
|
||||
VkResult result = vkBindImageMemory(device, data.first, data.second, 0);
|
||||
FILAMENT_CHECK_POSTCONDITION(result == VK_SUCCESS)
|
||||
<< "vkBindImageMemory error=" << static_cast<int32_t>(result);
|
||||
<< "vkBindImageMemory error=" << static_cast<int32_t>(result);
|
||||
return data;
|
||||
}
|
||||
|
||||
VkImageView VulkanPlatform::createExternalImageViewImpl(VkDevice device, SamplerYcbcrConversion chroma,
|
||||
uint32_t internalFormat, VkImage image, VkImageSubresourceRange range,
|
||||
VkImageViewType viewType, VkComponentMapping swizzle){
|
||||
VkExternalFormatANDROID externalFormat = {
|
||||
.sType = VK_STRUCTURE_TYPE_EXTERNAL_FORMAT_ANDROID,
|
||||
.pNext = nullptr,
|
||||
.externalFormat = internalFormat,
|
||||
};
|
||||
|
||||
TextureSwizzle const swizzleArray[] = {chroma.r, chroma.g, chroma.b, chroma.a};
|
||||
VkSamplerYcbcrConversionCreateInfo conversionInfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_CREATE_INFO,
|
||||
.pNext = &externalFormat,
|
||||
.format = VK_FORMAT_UNDEFINED,
|
||||
.ycbcrModel = fvkutils::getYcbcrModelConversion(chroma.ycbcrModel),
|
||||
.ycbcrRange = fvkutils::getYcbcrRange(chroma.ycbcrRange),
|
||||
.components = fvkutils::getSwizzleMap(swizzleArray),
|
||||
.xChromaOffset = fvkutils::getChromaLocation(chroma.xChromaOffset),
|
||||
.yChromaOffset = fvkutils::getChromaLocation(chroma.yChromaOffset),
|
||||
.chromaFilter = fvkutils::getFilter(chroma.chromaFilter),
|
||||
};
|
||||
VkSamplerYcbcrConversion conversion = VK_NULL_HANDLE;
|
||||
VkResult result = vkCreateSamplerYcbcrConversion(device, &conversionInfo,
|
||||
nullptr, &conversion);
|
||||
FILAMENT_CHECK_POSTCONDITION(result == VK_SUCCESS)
|
||||
<< "Unable to create Ycbcr Conversion."
|
||||
<< " error=" << static_cast<int32_t>(result);
|
||||
|
||||
VkSamplerYcbcrConversionInfo samplerYcbcrConversionInfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_INFO,
|
||||
.pNext = nullptr,
|
||||
.conversion = conversion,
|
||||
};
|
||||
|
||||
VkImageViewCreateInfo viewInfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
|
||||
.pNext = &samplerYcbcrConversionInfo,
|
||||
.flags = 0,
|
||||
.image = image,
|
||||
.viewType = viewType,
|
||||
.format = VK_FORMAT_UNDEFINED,
|
||||
.components = swizzle,
|
||||
.subresourceRange = range,
|
||||
};
|
||||
VkImageView imageView;
|
||||
result = vkCreateImageView(device, &viewInfo, VKALLOC, &imageView);
|
||||
FILAMENT_CHECK_POSTCONDITION(result == VK_SUCCESS)
|
||||
<< "Unable to create VkImageView."
|
||||
<< " error=" << static_cast<int32_t>(result);
|
||||
|
||||
return imageView;
|
||||
}
|
||||
|
||||
VkSampler VulkanPlatform::createExternalSamplerImpl(
|
||||
VkDevice device, SamplerYcbcrConversion chroma, SamplerParams params,
|
||||
uint32_t internalFormat) {
|
||||
VkExternalFormatANDROID externalFormat = {
|
||||
.sType = VK_STRUCTURE_TYPE_EXTERNAL_FORMAT_ANDROID,
|
||||
.pNext = nullptr,
|
||||
.externalFormat = internalFormat,
|
||||
};
|
||||
|
||||
TextureSwizzle const swizzleArray[] = {chroma.r, chroma.g, chroma.b, chroma.a};
|
||||
VkSamplerYcbcrConversionCreateInfo conversionInfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_CREATE_INFO,
|
||||
.pNext = &externalFormat,
|
||||
.format = VK_FORMAT_UNDEFINED,
|
||||
.ycbcrModel = fvkutils::getYcbcrModelConversion(chroma.ycbcrModel),
|
||||
.ycbcrRange = fvkutils::getYcbcrRange(chroma.ycbcrRange),
|
||||
.components = fvkutils::getSwizzleMap(swizzleArray),
|
||||
.xChromaOffset = fvkutils::getChromaLocation(chroma.xChromaOffset),
|
||||
.yChromaOffset = fvkutils::getChromaLocation(chroma.yChromaOffset),
|
||||
.chromaFilter = fvkutils::getFilter(chroma.chromaFilter),
|
||||
};
|
||||
VkSamplerYcbcrConversion conversion = VK_NULL_HANDLE;
|
||||
VkResult result = vkCreateSamplerYcbcrConversion(device, &conversionInfo,
|
||||
nullptr, &conversion);
|
||||
FILAMENT_CHECK_POSTCONDITION(result == VK_SUCCESS)
|
||||
<< "Unable to create Ycbcr Conversion."
|
||||
<< " error=" << static_cast<int32_t>(result);
|
||||
|
||||
VkSamplerYcbcrConversionInfo samplerYcbcrConversionInfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_INFO,
|
||||
.pNext = nullptr,
|
||||
.conversion = conversion,
|
||||
};
|
||||
|
||||
VkSamplerCreateInfo samplerInfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO,
|
||||
.pNext = &samplerYcbcrConversionInfo,
|
||||
.magFilter = fvkutils::getFilter(params.filterMag),
|
||||
.minFilter = fvkutils::getFilter(params.filterMin),
|
||||
.mipmapMode = fvkutils::getMipmapMode(params.filterMin),
|
||||
.addressModeU = fvkutils::getWrapMode(params.wrapS),
|
||||
.addressModeV = fvkutils::getWrapMode(params.wrapT),
|
||||
.addressModeW = fvkutils::getWrapMode(params.wrapR),
|
||||
.anisotropyEnable = params.anisotropyLog2 == 0 ? VK_FALSE : VK_TRUE,
|
||||
.maxAnisotropy = (float)(1u << params.anisotropyLog2),
|
||||
.compareEnable = fvkutils::getCompareEnable(params.compareMode),
|
||||
.compareOp = fvkutils::getCompareOp(params.compareFunc),
|
||||
.minLod = 0.0f,
|
||||
.maxLod = fvkutils::getMaxLod(params.filterMin),
|
||||
.borderColor = VK_BORDER_COLOR_INT_OPAQUE_BLACK,
|
||||
.unnormalizedCoordinates = VK_FALSE,
|
||||
};
|
||||
VkSampler sampler;
|
||||
result = vkCreateSampler(device, &samplerInfo, VKALLOC, &sampler);
|
||||
FILAMENT_CHECK_POSTCONDITION(result == VK_SUCCESS)
|
||||
<< "Unable to create sampler."
|
||||
<< " error=" << static_cast<int32_t>(result);
|
||||
return sampler;
|
||||
}
|
||||
|
||||
VulkanPlatform::ExtensionSet VulkanPlatform::getSwapchainInstanceExtensions() {
|
||||
return {
|
||||
VK_KHR_ANDROID_SURFACE_EXTENSION_NAME,
|
||||
|
||||
@@ -64,29 +64,16 @@ VulkanPlatform::ExtensionSet VulkanPlatform::getSwapchainInstanceExtensions() {
|
||||
}
|
||||
|
||||
VulkanPlatform::ExternalImageMetadata VulkanPlatform::getExternalImageMetadataImpl(
|
||||
ExternalImageHandleRef externalImage, VkDevice device) {
|
||||
void* externalImage, VkDevice device) {
|
||||
return {};
|
||||
}
|
||||
|
||||
VulkanPlatform::ImageData VulkanPlatform::createExternalImageDataImpl(
|
||||
ExternalImageHandleRef externalImage, VkDevice device,
|
||||
const ExternalImageMetadata& metadata, uint32_t memoryTypeIndex, VkImageUsageFlags usage) {
|
||||
VulkanPlatform::ImageData VulkanPlatform::createExternalImageImpl(void* externalImage,
|
||||
VkDevice device, const VkAllocationCallbacks* allocator,
|
||||
const ExternalImageMetadata& metadata) {
|
||||
return {};
|
||||
}
|
||||
|
||||
VkSampler VulkanPlatform::createExternalSamplerImpl(VkDevice device,
|
||||
SamplerYcbcrConversion chroma,
|
||||
SamplerParams sampler,
|
||||
uint32_t internalFormat) {
|
||||
return VK_NULL_HANDLE;
|
||||
}
|
||||
|
||||
VkImageView VulkanPlatform::createExternalImageViewImpl(VkDevice device,
|
||||
SamplerYcbcrConversion chroma, uint32_t internalFormat, VkImage image,
|
||||
VkImageSubresourceRange range, VkImageViewType viewType, VkComponentMapping swizzle) {
|
||||
return VK_NULL_HANDLE;
|
||||
}
|
||||
|
||||
VulkanPlatform::SurfaceBundle VulkanPlatform::createVkSurfaceKHR(void* nativeWindow,
|
||||
VkInstance instance, uint64_t flags) noexcept {
|
||||
VkSurfaceKHR surface;
|
||||
|
||||
@@ -85,29 +85,16 @@ using namespace bluevk;
|
||||
namespace filament::backend {
|
||||
|
||||
VulkanPlatform::ExternalImageMetadata VulkanPlatform::getExternalImageMetadataImpl(
|
||||
ExternalImageHandleRef externalImage, VkDevice device) {
|
||||
void* externalImage, VkDevice device) {
|
||||
return {};
|
||||
}
|
||||
|
||||
VulkanPlatform::ImageData VulkanPlatform::createExternalImageDataImpl(
|
||||
ExternalImageHandleRef externalImage, VkDevice device,
|
||||
const ExternalImageMetadata& metadata, uint32_t memoryTypeIndex, VkImageUsageFlags usage) {
|
||||
VulkanPlatform::ImageData VulkanPlatform::createExternalImageImpl(void* externalImage,
|
||||
VkDevice device, const VkAllocationCallbacks* allocator,
|
||||
const ExternalImageMetadata& metadata) {
|
||||
return {};
|
||||
}
|
||||
|
||||
VkSampler VulkanPlatform::createExternalSamplerImpl(VkDevice device,
|
||||
SamplerYcbcrConversion chroma,
|
||||
SamplerParams sampler,
|
||||
uint32_t internalFormat) {
|
||||
return VK_NULL_HANDLE;
|
||||
}
|
||||
|
||||
VkImageView VulkanPlatform::createExternalImageViewImpl(VkDevice device,
|
||||
SamplerYcbcrConversion chroma, uint32_t internalFormat, VkImage image,
|
||||
VkImageSubresourceRange range, VkImageViewType viewType, VkComponentMapping swizzle) {
|
||||
return VK_NULL_HANDLE;
|
||||
}
|
||||
|
||||
VulkanPlatform::ExtensionSet VulkanPlatform::getSwapchainInstanceExtensions() {
|
||||
VulkanPlatform::ExtensionSet const ret = {
|
||||
#if defined(__linux__) && defined(FILAMENT_SUPPORTS_WAYLAND)
|
||||
|
||||
@@ -588,79 +588,6 @@ VkComponentMapping getSwizzleMap(TextureSwizzle const swizzle[4]) {
|
||||
return map;
|
||||
}
|
||||
|
||||
VkFilter getFilter(SamplerMinFilter filter) {
|
||||
switch (filter) {
|
||||
case SamplerMinFilter::NEAREST:
|
||||
return VK_FILTER_NEAREST;
|
||||
case SamplerMinFilter::LINEAR:
|
||||
return VK_FILTER_LINEAR;
|
||||
case SamplerMinFilter::NEAREST_MIPMAP_NEAREST:
|
||||
return VK_FILTER_NEAREST;
|
||||
case SamplerMinFilter::LINEAR_MIPMAP_NEAREST:
|
||||
return VK_FILTER_LINEAR;
|
||||
case SamplerMinFilter::NEAREST_MIPMAP_LINEAR:
|
||||
return VK_FILTER_NEAREST;
|
||||
case SamplerMinFilter::LINEAR_MIPMAP_LINEAR:
|
||||
return VK_FILTER_LINEAR;
|
||||
}
|
||||
}
|
||||
|
||||
VkFilter getFilter(SamplerMagFilter filter) {
|
||||
switch (filter) {
|
||||
case SamplerMagFilter::NEAREST:
|
||||
return VK_FILTER_NEAREST;
|
||||
case SamplerMagFilter::LINEAR:
|
||||
return VK_FILTER_LINEAR;
|
||||
}
|
||||
}
|
||||
|
||||
VkSamplerMipmapMode getMipmapMode(SamplerMinFilter filter) {
|
||||
switch (filter) {
|
||||
case SamplerMinFilter::NEAREST:
|
||||
return VK_SAMPLER_MIPMAP_MODE_NEAREST;
|
||||
case SamplerMinFilter::LINEAR:
|
||||
return VK_SAMPLER_MIPMAP_MODE_NEAREST;
|
||||
case SamplerMinFilter::NEAREST_MIPMAP_NEAREST:
|
||||
return VK_SAMPLER_MIPMAP_MODE_NEAREST;
|
||||
case SamplerMinFilter::LINEAR_MIPMAP_NEAREST:
|
||||
return VK_SAMPLER_MIPMAP_MODE_NEAREST;
|
||||
case SamplerMinFilter::NEAREST_MIPMAP_LINEAR:
|
||||
return VK_SAMPLER_MIPMAP_MODE_LINEAR;
|
||||
case SamplerMinFilter::LINEAR_MIPMAP_LINEAR:
|
||||
return VK_SAMPLER_MIPMAP_MODE_LINEAR;
|
||||
}
|
||||
}
|
||||
|
||||
VkSamplerAddressMode getWrapMode(SamplerWrapMode mode) {
|
||||
switch (mode) {
|
||||
case SamplerWrapMode::REPEAT:
|
||||
return VK_SAMPLER_ADDRESS_MODE_REPEAT;
|
||||
case SamplerWrapMode::CLAMP_TO_EDGE:
|
||||
return VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
|
||||
case SamplerWrapMode::MIRRORED_REPEAT:
|
||||
return VK_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT;
|
||||
}
|
||||
}
|
||||
|
||||
VkBool32 getCompareEnable(SamplerCompareMode mode) {
|
||||
return mode == SamplerCompareMode::NONE ? VK_FALSE : VK_TRUE;
|
||||
}
|
||||
|
||||
float getMaxLod(SamplerMinFilter filter) {
|
||||
switch (filter) {
|
||||
case SamplerMinFilter::NEAREST:
|
||||
case SamplerMinFilter::LINEAR:
|
||||
// The Vulkan spec recommends a max LOD of 0.25 to "disable" mipmapping.
|
||||
// See "Mapping of OpenGL to Vulkan filter modes" in the VK Spec.
|
||||
return 0.25f;
|
||||
case SamplerMinFilter::NEAREST_MIPMAP_NEAREST:
|
||||
case SamplerMinFilter::LINEAR_MIPMAP_NEAREST:
|
||||
case SamplerMinFilter::NEAREST_MIPMAP_LINEAR:
|
||||
case SamplerMinFilter::LINEAR_MIPMAP_LINEAR:
|
||||
return VK_LOD_CLAMP_NONE;
|
||||
}
|
||||
}
|
||||
|
||||
VkShaderStageFlags getShaderStageFlags(ShaderStageFlags stageFlags) {
|
||||
VkShaderStageFlags flags = 0x0;
|
||||
if (any(stageFlags & ShaderStageFlags::VERTEX)) flags |= VK_SHADER_STAGE_VERTEX_BIT;
|
||||
|
||||
@@ -56,19 +56,6 @@ uint32_t getComponentCount(VkFormat format);
|
||||
VkComponentMapping getSwizzleMap(TextureSwizzle const swizzle[4]);
|
||||
VkShaderStageFlags getShaderStageFlags(ShaderStageFlags stageFlags);
|
||||
|
||||
// Needed by the Platform for external sampler creation
|
||||
VkFilter getFilter(SamplerMinFilter filter);
|
||||
VkFilter getFilter(SamplerMagFilter filter);
|
||||
VkSamplerMipmapMode getMipmapMode(SamplerMinFilter filter);
|
||||
VkSamplerAddressMode getWrapMode(SamplerWrapMode mode);
|
||||
VkBool32 getCompareEnable(SamplerCompareMode mode);
|
||||
float getMaxLod(SamplerMinFilter filter);
|
||||
|
||||
// Ycbcr related functions
|
||||
VkSamplerYcbcrModelConversion getYcbcrModelConversion(SamplerYcbcrModelConversion model);
|
||||
VkSamplerYcbcrRange getYcbcrRange(SamplerYcbcrRange range);
|
||||
VkChromaLocation getChromaLocation(ChromaLocation loc);
|
||||
|
||||
inline VkImageViewType getViewType(SamplerType target) {
|
||||
switch (target) {
|
||||
case SamplerType::SAMPLER_CUBEMAP:
|
||||
|
||||
@@ -193,49 +193,6 @@ uint8_t reduceSampleCount(uint8_t sampleCount, VkSampleCountFlags mask) {
|
||||
return mostSignificantBit((sampleCount - 1) & mask);
|
||||
}
|
||||
|
||||
VkSamplerYcbcrModelConversion getYcbcrModelConversion(
|
||||
SamplerYcbcrModelConversion model) {
|
||||
switch (model) {
|
||||
case SamplerYcbcrModelConversion::RGB_IDENTITY:
|
||||
return VK_SAMPLER_YCBCR_MODEL_CONVERSION_RGB_IDENTITY;
|
||||
case SamplerYcbcrModelConversion::YCBCR_IDENTITY:
|
||||
return VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_IDENTITY;
|
||||
case SamplerYcbcrModelConversion::YCBCR_709:
|
||||
return VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_709;
|
||||
case SamplerYcbcrModelConversion::YCBCR_601:
|
||||
return VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_601;
|
||||
case SamplerYcbcrModelConversion::YCBCR_2020:
|
||||
return VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_2020;
|
||||
default:
|
||||
assert_invariant(false &&
|
||||
"Unknown data type, conversion is not supported.");
|
||||
}
|
||||
}
|
||||
|
||||
VkSamplerYcbcrRange getYcbcrRange(SamplerYcbcrRange range) {
|
||||
switch (range) {
|
||||
case SamplerYcbcrRange::ITU_FULL:
|
||||
return VK_SAMPLER_YCBCR_RANGE_ITU_FULL;
|
||||
case SamplerYcbcrRange::ITU_NARROW:
|
||||
return VK_SAMPLER_YCBCR_RANGE_ITU_NARROW;
|
||||
default:
|
||||
assert_invariant(false &&
|
||||
"Unknown data type, conversion is not supported.");
|
||||
}
|
||||
}
|
||||
|
||||
VkChromaLocation getChromaLocation(ChromaLocation loc) {
|
||||
switch (loc) {
|
||||
case ChromaLocation::COSITED_EVEN:
|
||||
return VK_CHROMA_LOCATION_COSITED_EVEN;
|
||||
case ChromaLocation::MIDPOINT:
|
||||
return VK_CHROMA_LOCATION_MIDPOINT;
|
||||
default:
|
||||
assert_invariant(false &&
|
||||
"Unknown data type, conversion is not supported.");
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace filament::backend::fvkutils
|
||||
|
||||
bool operator<(const VkImageSubresourceRange& a, const VkImageSubresourceRange& b) {
|
||||
|
||||
@@ -1,66 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2025 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.
|
||||
*/
|
||||
|
||||
#ifndef TNT_FILAMENT_BACKEND_WEBGPUCONSTANTS_H
|
||||
#define TNT_FILAMENT_BACKEND_WEBGPUCONSTANTS_H
|
||||
|
||||
#include <utils/Log.h>
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
// FWGPU is short for Filament WebGPU
|
||||
|
||||
// turn on runtime validation, namely for debugging, that would normally not run (for release)
|
||||
#define FWGPU_DEBUG_VALIDATION 0x00000001
|
||||
// print/log system component details to the console, e.g. about the
|
||||
// instance, surface, adapter, device, etc.
|
||||
#define FWGPU_PRINT_SYSTEM 0x00000002
|
||||
|
||||
// Set this to enable logging "only" to one output stream. This is useful in the case where we want
|
||||
// to debug with print statements and want ordered logging (e.g slog.i and slog.e will not appear in
|
||||
// order of calls).
|
||||
#define FWGPU_DEBUG_FORCE_LOG_TO_I 0x00000004
|
||||
|
||||
// Useful default combinations
|
||||
#define FWGPU_DEBUG_EVERYTHING 0xFFFFFFFF
|
||||
|
||||
#if defined(FILAMENT_BACKEND_DEBUG_FLAG)
|
||||
#define FWGPU_DEBUG_FORWARDED_FLAG (FILAMENT_BACKEND_DEBUG_FLAG & FWGPU_DEBUG_EVERYTHING)
|
||||
#else
|
||||
#define FWGPU_DEBUG_FORWARDED_FLAG 0
|
||||
#endif
|
||||
|
||||
#ifndef NDEBUG
|
||||
#define FWGPU_DEBUG_FLAGS FWGPU_DEBUG_FORWARDED_FLAG
|
||||
#else
|
||||
#define FWGPU_DEBUG_FLAGS 0
|
||||
#endif
|
||||
|
||||
#define FWGPU_ENABLED(flags) (((FWGPU_DEBUG_FLAGS) & (flags)) == (flags))
|
||||
|
||||
#if FWGPU_ENABLED(FWGPU_DEBUG_FORCE_LOG_TO_I)
|
||||
#define FWGPU_LOGI (utils::slog.i)
|
||||
#define FWGPU_LOGD FWGPU_LOGI
|
||||
#define FWGPU_LOGE FWGPU_LOGI
|
||||
#define FWGPU_LOGW FWGPU_LOGI
|
||||
#else
|
||||
#define FWGPU_LOGE (utils::slog.e)
|
||||
#define FWGPU_LOGW (utils::slog.w)
|
||||
#define FWGPU_LOGD (utils::slog.d)
|
||||
#define FWGPU_LOGI (utils::slog.i)
|
||||
#endif
|
||||
|
||||
#endif// TNT_FILAMENT_BACKEND_WEBGPUCONSTANTS_H
|
||||
@@ -14,254 +14,21 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "webgpu/WebGPUDriver.h"
|
||||
|
||||
#include "webgpu/WebGPUConstants.h"
|
||||
#include <backend/platforms/WebGPUPlatform.h>
|
||||
|
||||
#include "CommandStreamDispatcher.h"
|
||||
#include "DriverBase.h"
|
||||
#include "private/backend/Dispatcher.h"
|
||||
#include <backend/DriverEnums.h>
|
||||
#include <backend/Handle.h>
|
||||
|
||||
#include <math/mat3.h>
|
||||
#include <utils/CString.h>
|
||||
#include <utils/ostream.h>
|
||||
#include "webgpu/WebGPUDriver.h"
|
||||
#include "CommandStreamDispatcher.h"
|
||||
|
||||
#include <dawn/webgpu_cpp_print.h>
|
||||
#include <webgpu/webgpu_cpp.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <sstream>
|
||||
#include <string_view>
|
||||
#include <utility>
|
||||
#include <variant>
|
||||
#include <stdint.h>
|
||||
|
||||
namespace filament::backend {
|
||||
|
||||
namespace {
|
||||
|
||||
#if FWGPU_ENABLED(FWGPU_PRINT_SYSTEM)
|
||||
void printInstanceDetails(wgpu::Instance const& instance) {
|
||||
wgpu::SupportedWGSLLanguageFeatures supportedWGSLLanguageFeatures{};
|
||||
if (!instance.GetWGSLLanguageFeatures(&supportedWGSLLanguageFeatures)) {
|
||||
FWGPU_LOGW << "Failed to get WebGPU instance supported WGSL language features"
|
||||
<< utils::io::endl;
|
||||
} else {
|
||||
FWGPU_LOGI << "WebGPU instance supported WGSL language features ("
|
||||
<< supportedWGSLLanguageFeatures.featureCount << "):" << utils::io::endl;
|
||||
if (supportedWGSLLanguageFeatures.featureCount > 0 &&
|
||||
supportedWGSLLanguageFeatures.features != nullptr) {
|
||||
std::for_each(supportedWGSLLanguageFeatures.features,
|
||||
supportedWGSLLanguageFeatures.features +
|
||||
supportedWGSLLanguageFeatures.featureCount,
|
||||
[](wgpu::WGSLLanguageFeatureName const featureName) {
|
||||
std::stringstream nameStream{};
|
||||
nameStream << featureName;
|
||||
FWGPU_LOGI << " " << nameStream.str() << utils::io::endl;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if FWGPU_ENABLED(FWGPU_PRINT_SYSTEM)
|
||||
void printLimit(std::string_view name, const std::variant<uint32_t, uint64_t> value) {
|
||||
FWGPU_LOGI << " " << name.data() << ": ";
|
||||
bool undefined = true;
|
||||
if (std::holds_alternative<uint32_t>(value)) {
|
||||
if (std::get<uint32_t>(value) != WGPU_LIMIT_U32_UNDEFINED) {
|
||||
undefined = false;
|
||||
FWGPU_LOGI << std::get<uint32_t>(value);
|
||||
}
|
||||
} else if (std::holds_alternative<uint64_t>(value)) {
|
||||
if (std::get<uint64_t>(value) != WGPU_LIMIT_U64_UNDEFINED) {
|
||||
undefined = false;
|
||||
FWGPU_LOGI << std::get<uint64_t>(value);
|
||||
}
|
||||
}
|
||||
if (undefined) {
|
||||
FWGPU_LOGI << "UNDEFINED";
|
||||
}
|
||||
FWGPU_LOGI << utils::io::endl;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if FWGPU_ENABLED(FWGPU_PRINT_SYSTEM)
|
||||
void printLimits(wgpu::Limits const& limits) {
|
||||
printLimit("maxTextureDimension1D", limits.maxTextureDimension1D);
|
||||
printLimit("maxTextureDimension2D", limits.maxTextureDimension2D);
|
||||
printLimit("maxTextureDimension3D", limits.maxTextureDimension3D);
|
||||
printLimit("maxTextureArrayLayers", limits.maxTextureArrayLayers);
|
||||
printLimit("maxBindGroups", limits.maxBindGroups);
|
||||
printLimit("maxBindGroupsPlusVertexBuffers", limits.maxBindGroupsPlusVertexBuffers);
|
||||
printLimit("maxBindingsPerBindGroup", limits.maxBindingsPerBindGroup);
|
||||
printLimit("maxDynamicUniformBuffersPerPipelineLayout",
|
||||
limits.maxDynamicUniformBuffersPerPipelineLayout);
|
||||
printLimit("maxDynamicStorageBuffersPerPipelineLayout",
|
||||
limits.maxDynamicStorageBuffersPerPipelineLayout);
|
||||
printLimit("maxSampledTexturesPerShaderStage", limits.maxSampledTexturesPerShaderStage);
|
||||
printLimit("maxSamplersPerShaderStage", limits.maxSamplersPerShaderStage);
|
||||
printLimit("maxStorageBuffersPerShaderStage", limits.maxStorageBuffersPerShaderStage);
|
||||
printLimit("maxStorageTexturesPerShaderStage", limits.maxStorageTexturesPerShaderStage);
|
||||
printLimit("maxUniformBuffersPerShaderStage", limits.maxUniformBuffersPerShaderStage);
|
||||
printLimit("maxUniformBufferBindingSize", limits.maxUniformBufferBindingSize);
|
||||
printLimit("maxStorageBufferBindingSize", limits.maxStorageBufferBindingSize);
|
||||
printLimit("minUniformBufferOffsetAlignment", limits.minUniformBufferOffsetAlignment);
|
||||
printLimit("minStorageBufferOffsetAlignment", limits.minStorageBufferOffsetAlignment);
|
||||
printLimit("maxVertexBuffers", limits.maxVertexBuffers);
|
||||
printLimit("maxBufferSize", limits.maxBufferSize);
|
||||
printLimit("maxVertexAttributes", limits.maxVertexAttributes);
|
||||
printLimit("maxVertexBufferArrayStride", limits.maxVertexBufferArrayStride);
|
||||
printLimit("maxInterStageShaderComponents", limits.maxInterStageShaderComponents);
|
||||
printLimit("maxInterStageShaderVariables", limits.maxInterStageShaderVariables);
|
||||
printLimit("maxColorAttachments", limits.maxColorAttachments);
|
||||
printLimit("maxColorAttachmentBytesPerSample", limits.maxColorAttachmentBytesPerSample);
|
||||
printLimit("maxComputeWorkgroupStorageSize", limits.maxComputeWorkgroupStorageSize);
|
||||
printLimit("maxComputeInvocationsPerWorkgroup", limits.maxComputeInvocationsPerWorkgroup);
|
||||
printLimit("maxComputeWorkgroupSizeX", limits.maxComputeWorkgroupSizeX);
|
||||
printLimit("maxComputeWorkgroupSizeY", limits.maxComputeWorkgroupSizeY);
|
||||
printLimit("maxComputeWorkgroupSizeZ", limits.maxComputeWorkgroupSizeZ);
|
||||
printLimit("maxComputeWorkgroupsPerDimension", limits.maxComputeWorkgroupsPerDimension);
|
||||
printLimit("maxStorageBuffersInVertexStage", limits.maxStorageBuffersInVertexStage);
|
||||
printLimit("maxStorageTexturesInVertexStage", limits.maxStorageTexturesInVertexStage);
|
||||
printLimit("maxStorageBuffersInFragmentStage", limits.maxStorageBuffersInFragmentStage);
|
||||
printLimit("maxStorageTexturesInFragmentStage", limits.maxStorageTexturesInFragmentStage);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if FWGPU_ENABLED(FWGPU_PRINT_SYSTEM)
|
||||
void printAdapterDetails(wgpu::Adapter const& adapter) {
|
||||
wgpu::DawnAdapterPropertiesPowerPreference powerPreferenceProperties{};
|
||||
wgpu::AdapterInfo adapterInfo{};
|
||||
adapterInfo.nextInChain = &powerPreferenceProperties;
|
||||
if (!adapter.GetInfo(&adapterInfo)) {
|
||||
FWGPU_LOGW << "Failed to get WebGPU adapter info" << utils::io::endl;
|
||||
} else {
|
||||
std::stringstream backendTypeStream{};
|
||||
backendTypeStream << adapterInfo.backendType;
|
||||
std::stringstream adapterTypeStream{};
|
||||
adapterTypeStream << adapterInfo.adapterType;
|
||||
std::stringstream powerPreferenceStream{};
|
||||
powerPreferenceStream << powerPreferenceProperties.powerPreference;
|
||||
FWGPU_LOGI << "WebGPU adapter info:" << utils::io::endl;
|
||||
FWGPU_LOGI << " vendor: " << adapterInfo.vendor.data << utils::io::endl;
|
||||
FWGPU_LOGI << " architecture: " << adapterInfo.architecture.data << utils::io::endl;
|
||||
FWGPU_LOGI << " device: " << adapterInfo.device.data << utils::io::endl;
|
||||
FWGPU_LOGI << " description: " << adapterInfo.description.data << utils::io::endl;
|
||||
FWGPU_LOGI << " backend type: " << backendTypeStream.str().data() << utils::io::endl;
|
||||
FWGPU_LOGI << " adapter type: " << adapterTypeStream.str().data() << utils::io::endl;
|
||||
FWGPU_LOGI << " device ID: " << adapterInfo.deviceID << utils::io::endl;
|
||||
FWGPU_LOGI << " vendor ID: " << adapterInfo.vendorID << utils::io::endl;
|
||||
FWGPU_LOGI << " subgroup min size: " << adapterInfo.subgroupMinSize << utils::io::endl;
|
||||
FWGPU_LOGI << " subgroup max size: " << adapterInfo.subgroupMaxSize << utils::io::endl;
|
||||
FWGPU_LOGI << " compatibility mode: " << bool(adapterInfo.compatibilityMode)
|
||||
<< utils::io::endl;
|
||||
FWGPU_LOGI << " power preference: " << powerPreferenceStream.str() << utils::io::endl;
|
||||
}
|
||||
wgpu::SupportedFeatures supportedFeatures{};
|
||||
adapter.GetFeatures(&supportedFeatures);
|
||||
FWGPU_LOGI << "WebGPU adapter supported features (" << supportedFeatures.featureCount
|
||||
<< "):" << utils::io::endl;
|
||||
if (supportedFeatures.featureCount > 0 && supportedFeatures.features != nullptr) {
|
||||
std::for_each(supportedFeatures.features,
|
||||
supportedFeatures.features + supportedFeatures.featureCount,
|
||||
[](wgpu::FeatureName const name) {
|
||||
std::stringstream nameStream{};
|
||||
nameStream << name;
|
||||
FWGPU_LOGI << " " << nameStream.str().data() << utils::io::endl;
|
||||
});
|
||||
}
|
||||
wgpu::SupportedLimits supportedLimits{};
|
||||
if (!adapter.GetLimits(&supportedLimits)) {
|
||||
FWGPU_LOGW << "Failed to get WebGPU adapter supported limits" << utils::io::endl;
|
||||
} else {
|
||||
FWGPU_LOGI << "WebGPU adapter supported limits:" << utils::io::endl;
|
||||
printLimits(supportedLimits.limits);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if FWGPU_ENABLED(FWGPU_PRINT_SYSTEM)
|
||||
void printSurfaceCapabilitiesDetails(wgpu::SurfaceCapabilities const& capabilities) {
|
||||
std::stringstream usages_stream{};
|
||||
usages_stream << capabilities.usages;
|
||||
FWGPU_LOGI << "WebGPU surface capabilities:" << utils::io::endl;
|
||||
FWGPU_LOGI << " surface usages: " << usages_stream.str().data() << utils::io::endl;
|
||||
FWGPU_LOGI << " surface formats (" << capabilities.formatCount << "):" << utils::io::endl;
|
||||
if (capabilities.formatCount > 0 && capabilities.formats != nullptr) {
|
||||
std::for_each(capabilities.formats, capabilities.formats + capabilities.formatCount,
|
||||
[](wgpu::TextureFormat const format) {
|
||||
std::stringstream format_stream{};
|
||||
format_stream << format;
|
||||
FWGPU_LOGI << " " << format_stream.str().data() << utils::io::endl;
|
||||
});
|
||||
}
|
||||
FWGPU_LOGI << " surface present modes (" << capabilities.presentModeCount
|
||||
<< "):" << utils::io::endl;
|
||||
if (capabilities.presentModeCount > 0 && capabilities.presentModes != nullptr) {
|
||||
std::for_each(capabilities.presentModes,
|
||||
capabilities.presentModes + capabilities.presentModeCount,
|
||||
[](wgpu::PresentMode const presentMode) {
|
||||
std::stringstream present_mode_stream{};
|
||||
present_mode_stream << presentMode;
|
||||
FWGPU_LOGI << " " << present_mode_stream.str().data() << utils::io::endl;
|
||||
});
|
||||
}
|
||||
FWGPU_LOGI << " surface alpha modes (" << capabilities.alphaModeCount
|
||||
<< "):" << utils::io::endl;
|
||||
if (capabilities.alphaModeCount > 0 && capabilities.alphaModes != nullptr) {
|
||||
std::for_each(capabilities.alphaModes,
|
||||
capabilities.alphaModes + capabilities.alphaModeCount,
|
||||
[](wgpu::CompositeAlphaMode const alphaMode) {
|
||||
std::stringstream alpha_mode_stream{};
|
||||
alpha_mode_stream << alphaMode;
|
||||
FWGPU_LOGI << " " << alpha_mode_stream.str().data() << utils::io::endl;
|
||||
});
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if FWGPU_ENABLED(FWGPU_PRINT_SYSTEM)
|
||||
void printDeviceDetails(wgpu::Device const& device) {
|
||||
wgpu::SupportedFeatures supportedFeatures{};
|
||||
device.GetFeatures(&supportedFeatures);
|
||||
FWGPU_LOGI << "WebGPU device supported features (" << supportedFeatures.featureCount
|
||||
<< "):" << utils::io::endl;
|
||||
if (supportedFeatures.featureCount > 0 && supportedFeatures.features != nullptr) {
|
||||
std::for_each(supportedFeatures.features,
|
||||
supportedFeatures.features + supportedFeatures.featureCount,
|
||||
[](wgpu::FeatureName const name) {
|
||||
std::stringstream nameStream{};
|
||||
nameStream << name;
|
||||
FWGPU_LOGI << " " << nameStream.str().data() << utils::io::endl;
|
||||
});
|
||||
}
|
||||
wgpu::SupportedLimits supportedLimits{};
|
||||
if (!device.GetLimits(&supportedLimits)) {
|
||||
FWGPU_LOGW << "Failed to get WebGPU supported device limits" << utils::io::endl;
|
||||
} else {
|
||||
FWGPU_LOGI << "WebGPU device supported limits:" << utils::io::endl;
|
||||
printLimits(supportedLimits.limits);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
}// namespace
|
||||
|
||||
Driver* WebGPUDriver::create(WebGPUPlatform& platform) noexcept {
|
||||
return new WebGPUDriver(platform);
|
||||
Driver* WebGPUDriver::create() {
|
||||
return new WebGPUDriver();
|
||||
}
|
||||
|
||||
WebGPUDriver::WebGPUDriver(WebGPUPlatform& platform) noexcept
|
||||
: mPlatform(platform) {
|
||||
#if FWGPU_ENABLED(FWGPU_PRINT_SYSTEM)
|
||||
printInstanceDetails(mPlatform.getInstance());
|
||||
#endif
|
||||
}
|
||||
WebGPUDriver::WebGPUDriver() noexcept = default;
|
||||
|
||||
WebGPUDriver::~WebGPUDriver() noexcept = default;
|
||||
|
||||
@@ -278,7 +45,7 @@ ShaderModel WebGPUDriver::getShaderModel() const noexcept {
|
||||
}
|
||||
|
||||
ShaderLanguage WebGPUDriver::getShaderLanguage() const noexcept {
|
||||
return ShaderLanguage::WGSL;
|
||||
return ShaderLanguage::ESSL3;
|
||||
}
|
||||
|
||||
// explicit instantiation of the Dispatcher
|
||||
@@ -356,188 +123,6 @@ void WebGPUDriver::destroyDescriptorSetLayout(Handle<HwDescriptorSetLayout> tqh)
|
||||
void WebGPUDriver::destroyDescriptorSet(Handle<HwDescriptorSet> tqh) {
|
||||
}
|
||||
|
||||
Handle<HwSwapChain> WebGPUDriver::createSwapChainS() noexcept {
|
||||
return Handle<HwSwapChain>((Handle<HwSwapChain>::HandleId) mNextFakeHandle++);
|
||||
}
|
||||
|
||||
Handle<HwSwapChain> WebGPUDriver::createSwapChainHeadlessS() noexcept {
|
||||
return Handle<HwSwapChain>((Handle<HwSwapChain>::HandleId) mNextFakeHandle++);
|
||||
}
|
||||
|
||||
Handle<HwTexture> WebGPUDriver::createTextureS() noexcept {
|
||||
return Handle<HwTexture>((Handle<HwTexture>::HandleId) mNextFakeHandle++);
|
||||
}
|
||||
|
||||
Handle<HwTexture> WebGPUDriver::importTextureS() noexcept {
|
||||
return Handle<HwTexture>((Handle<HwTexture>::HandleId) mNextFakeHandle++);
|
||||
}
|
||||
|
||||
Handle<HwProgram> WebGPUDriver::createProgramS() noexcept {
|
||||
return Handle<HwProgram>((Handle<HwProgram>::HandleId) mNextFakeHandle++);
|
||||
}
|
||||
|
||||
Handle<HwFence> WebGPUDriver::createFenceS() noexcept {
|
||||
return Handle<HwFence>((Handle<HwFence>::HandleId) mNextFakeHandle++);
|
||||
}
|
||||
|
||||
Handle<HwTimerQuery> WebGPUDriver::createTimerQueryS() noexcept {
|
||||
return Handle<HwTimerQuery>((Handle<HwTimerQuery>::HandleId) mNextFakeHandle++);
|
||||
}
|
||||
|
||||
Handle<HwIndexBuffer> WebGPUDriver::createIndexBufferS() noexcept {
|
||||
return Handle<HwIndexBuffer>((Handle<HwIndexBuffer>::HandleId) mNextFakeHandle++);
|
||||
}
|
||||
|
||||
Handle<HwTexture> WebGPUDriver::createTextureViewS() noexcept {
|
||||
return Handle<HwTexture>((Handle<HwTexture>::HandleId) mNextFakeHandle++);
|
||||
}
|
||||
|
||||
Handle<HwBufferObject> WebGPUDriver::createBufferObjectS() noexcept {
|
||||
return Handle<HwBufferObject>((Handle<HwBufferObject>::HandleId) mNextFakeHandle++);
|
||||
}
|
||||
|
||||
Handle<HwRenderTarget> WebGPUDriver::createRenderTargetS() noexcept {
|
||||
return Handle<HwRenderTarget>((Handle<HwRenderTarget>::HandleId) mNextFakeHandle++);
|
||||
}
|
||||
|
||||
Handle<HwVertexBuffer> WebGPUDriver::createVertexBufferS() noexcept {
|
||||
return Handle<HwVertexBuffer>((Handle<HwVertexBuffer>::HandleId) mNextFakeHandle++);
|
||||
}
|
||||
|
||||
Handle<HwDescriptorSet> WebGPUDriver::createDescriptorSetS() noexcept {
|
||||
return Handle<HwDescriptorSet>((Handle<HwDescriptorSet>::HandleId) mNextFakeHandle++);
|
||||
}
|
||||
|
||||
Handle<HwRenderPrimitive> WebGPUDriver::createRenderPrimitiveS() noexcept {
|
||||
return Handle<HwRenderPrimitive>((Handle<HwRenderPrimitive>::HandleId) mNextFakeHandle++);
|
||||
}
|
||||
|
||||
Handle<HwVertexBufferInfo> WebGPUDriver::createVertexBufferInfoS() noexcept {
|
||||
return Handle<HwVertexBufferInfo>((Handle<HwVertexBufferInfo>::HandleId) mNextFakeHandle++);
|
||||
}
|
||||
|
||||
Handle<HwTexture> WebGPUDriver::createTextureViewSwizzleS() noexcept {
|
||||
return Handle<HwTexture>((Handle<HwTexture>::HandleId) mNextFakeHandle++);
|
||||
}
|
||||
|
||||
Handle<HwRenderTarget> WebGPUDriver::createDefaultRenderTargetS() noexcept {
|
||||
return Handle<HwRenderTarget>((Handle<HwRenderTarget>::HandleId) mNextFakeHandle++);
|
||||
}
|
||||
|
||||
Handle<HwDescriptorSetLayout> WebGPUDriver::createDescriptorSetLayoutS() noexcept {
|
||||
return Handle<HwDescriptorSetLayout>(
|
||||
(Handle<HwDescriptorSetLayout>::HandleId) mNextFakeHandle++);
|
||||
}
|
||||
|
||||
Handle<HwTexture> WebGPUDriver::createTextureExternalImageS() noexcept {
|
||||
return Handle<HwTexture>((Handle<HwTexture>::HandleId) mNextFakeHandle++);
|
||||
}
|
||||
|
||||
Handle<HwTexture> WebGPUDriver::createTextureExternalImage2S() noexcept {
|
||||
return Handle<HwTexture>((Handle<HwTexture>::HandleId) mNextFakeHandle++);
|
||||
}
|
||||
|
||||
Handle<HwTexture> WebGPUDriver::createTextureExternalImagePlaneS() noexcept {
|
||||
return Handle<HwTexture>((Handle<HwTexture>::HandleId) mNextFakeHandle++);
|
||||
}
|
||||
|
||||
void WebGPUDriver::createSwapChainR(Handle<HwSwapChain> sch, void* nativeWindow, uint64_t flags) {
|
||||
mSurface= mPlatform.createSurface(nativeWindow, flags);
|
||||
mAdapter = mPlatform.requestAdapter(mSurface);
|
||||
#if FWGPU_ENABLED(FWGPU_PRINT_SYSTEM)
|
||||
printAdapterDetails(mAdapter);
|
||||
wgpu::SurfaceCapabilities surfaceCapabilities{};
|
||||
if (!mSurface.GetCapabilities(mAdapter, &surfaceCapabilities)) {
|
||||
FWGPU_LOGW << "Failed to get WebGPU surface capabilities" << utils::io::endl;
|
||||
} else {
|
||||
printSurfaceCapabilitiesDetails(surfaceCapabilities);
|
||||
}
|
||||
#endif
|
||||
mDevice = mPlatform.requestDevice(mAdapter);
|
||||
#if FWGPU_ENABLED(FWGPU_PRINT_SYSTEM)
|
||||
printDeviceDetails(mDevice);
|
||||
#endif
|
||||
mQueue = mDevice.GetQueue();
|
||||
// TODO configure the surface (maybe before or after creating the swapchain?
|
||||
// how do we get the surface extent?)
|
||||
// TODO actually create the swapchain
|
||||
FWGPU_LOGW << "WebGPU support is still essentially a no-op at this point in development (only "
|
||||
"background components have been instantiated/selected, such as surface/screen, "
|
||||
"graphics device/GPU, etc.), thus nothing is being drawn to the screen."
|
||||
<< utils::io::endl;
|
||||
#if !FWGPU_ENABLED(FWGPU_PRINT_SYSTEM) && !defined(NDEBUG)
|
||||
FWGPU_LOGI << "If the FILAMENT_BACKEND_DEBUG_FLAG variable were set with the " << utils::io::hex
|
||||
<< FWGPU_PRINT_SYSTEM << utils::io::dec
|
||||
<< " bit flag on during build time the application would print system details "
|
||||
"about the selected graphics device, surface, etc. To see this try "
|
||||
"rebuilding Filament with that flag, e.g. ./build.sh -x "
|
||||
<< FWGPU_PRINT_SYSTEM << " ..." << utils::io::endl;
|
||||
#endif
|
||||
}
|
||||
|
||||
void WebGPUDriver::createSwapChainHeadlessR(Handle<HwSwapChain> sch, uint32_t width,
|
||||
uint32_t height, uint64_t flags) {}
|
||||
|
||||
void WebGPUDriver::createVertexBufferInfoR(Handle<HwVertexBufferInfo> vbih, uint8_t bufferCount,
|
||||
uint8_t attributeCount, AttributeArray attributes) {}
|
||||
|
||||
void WebGPUDriver::createVertexBufferR(Handle<HwVertexBuffer> vbh, uint32_t vertexCount,
|
||||
Handle<HwVertexBufferInfo> vbih) {}
|
||||
|
||||
void WebGPUDriver::createIndexBufferR(Handle<HwIndexBuffer> ibh, ElementType elementType,
|
||||
uint32_t indexCount, BufferUsage usage) {}
|
||||
|
||||
void WebGPUDriver::createBufferObjectR(Handle<HwBufferObject> boh, uint32_t byteCount,
|
||||
BufferObjectBinding bindingType, BufferUsage usage) {}
|
||||
|
||||
void WebGPUDriver::createTextureR(Handle<HwTexture> th, SamplerType target, uint8_t levels,
|
||||
TextureFormat format, uint8_t samples, uint32_t w, uint32_t h, uint32_t depth,
|
||||
TextureUsage usage) {}
|
||||
|
||||
void WebGPUDriver::createTextureViewR(Handle<HwTexture> th, Handle<HwTexture> srch,
|
||||
uint8_t baseLevel, uint8_t levelCount) {}
|
||||
|
||||
void WebGPUDriver::createTextureViewSwizzleR(Handle<HwTexture> th, Handle<HwTexture> srch,
|
||||
backend::TextureSwizzle r, backend::TextureSwizzle g, backend::TextureSwizzle b,
|
||||
backend::TextureSwizzle a) {}
|
||||
|
||||
void WebGPUDriver::createTextureExternalImage2R(Handle<HwTexture> th, backend::SamplerType target,
|
||||
backend::TextureFormat format, uint32_t width, uint32_t height, backend::TextureUsage usage,
|
||||
Platform::ExternalImageHandleRef externalImage) {}
|
||||
|
||||
void WebGPUDriver::createTextureExternalImageR(Handle<HwTexture> th, backend::SamplerType target,
|
||||
backend::TextureFormat format, uint32_t width, uint32_t height, backend::TextureUsage usage,
|
||||
void* externalImage) {}
|
||||
|
||||
void WebGPUDriver::createTextureExternalImagePlaneR(Handle<HwTexture> th,
|
||||
backend::TextureFormat format, uint32_t width, uint32_t height, backend::TextureUsage usage,
|
||||
void* image, uint32_t plane) {}
|
||||
|
||||
void WebGPUDriver::importTextureR(Handle<HwTexture> th, intptr_t id, SamplerType target,
|
||||
uint8_t levels, TextureFormat format, uint8_t samples, uint32_t w, uint32_t h,
|
||||
uint32_t depth, TextureUsage usage) {}
|
||||
|
||||
void WebGPUDriver::createRenderPrimitiveR(Handle<HwRenderPrimitive> rph, Handle<HwVertexBuffer> vbh,
|
||||
Handle<HwIndexBuffer> ibh, PrimitiveType pt) {}
|
||||
|
||||
void WebGPUDriver::createProgramR(Handle<HwProgram> ph, Program&& program) {}
|
||||
|
||||
void WebGPUDriver::createDefaultRenderTargetR(Handle<HwRenderTarget> rth, int) {}
|
||||
|
||||
void WebGPUDriver::createRenderTargetR(Handle<HwRenderTarget> rth, TargetBufferFlags targets,
|
||||
uint32_t width, uint32_t height, uint8_t samples, uint8_t layerCount, MRT color,
|
||||
TargetBufferInfo depth, TargetBufferInfo stencil) {}
|
||||
|
||||
void WebGPUDriver::createFenceR(Handle<HwFence> fh, int) {}
|
||||
|
||||
void WebGPUDriver::createTimerQueryR(Handle<HwTimerQuery> tqh, int) {}
|
||||
|
||||
void WebGPUDriver::createDescriptorSetLayoutR(Handle<HwDescriptorSetLayout> dslh,
|
||||
backend::DescriptorSetLayout&& info) {}
|
||||
|
||||
void WebGPUDriver::createDescriptorSetR(Handle<HwDescriptorSet> dsh,
|
||||
Handle<HwDescriptorSetLayout> dslh) {}
|
||||
|
||||
Handle<HwStream> WebGPUDriver::createStreamNative(void* nativeStream) {
|
||||
return {};
|
||||
}
|
||||
@@ -546,11 +131,9 @@ Handle<HwStream> WebGPUDriver::createStreamAcquired() {
|
||||
return {};
|
||||
}
|
||||
|
||||
void WebGPUDriver::setAcquiredImage(Handle<HwStream> sh, void* image, const math::mat3f& transform,
|
||||
CallbackHandler* handler, StreamCallback cb, void* userData) {}
|
||||
|
||||
void WebGPUDriver::registerBufferObjectStreams(Handle<HwBufferObject> boh,
|
||||
BufferObjectStreamDescriptor&& streams) {}
|
||||
void WebGPUDriver::setAcquiredImage(Handle<HwStream> sh, void* image,
|
||||
CallbackHandler* handler, StreamCallback cb, void* userData) {
|
||||
}
|
||||
|
||||
void WebGPUDriver::setStreamDimensions(Handle<HwStream> sh, uint32_t width, uint32_t height) {
|
||||
}
|
||||
@@ -651,18 +234,10 @@ uint8_t WebGPUDriver::getMaxDrawBuffers() {
|
||||
return MRT::MAX_SUPPORTED_RENDER_TARGET_COUNT;
|
||||
}
|
||||
|
||||
size_t WebGPUDriver::getMaxUniformBufferSize(SamplerType) {
|
||||
size_t WebGPUDriver::getMaxUniformBufferSize() {
|
||||
return 16384u;
|
||||
}
|
||||
|
||||
size_t WebGPUDriver::getMaxTextureSize() {
|
||||
return 2048u;
|
||||
}
|
||||
|
||||
size_t WebGPUDriver::getMaxArrayTextureLayers() {
|
||||
return 256u;
|
||||
}
|
||||
|
||||
void WebGPUDriver::updateIndexBuffer(Handle<HwIndexBuffer> ibh, BufferDescriptor&& p,
|
||||
uint32_t byteOffset) {
|
||||
scheduleDestroy(std::move(p));
|
||||
|
||||
@@ -17,44 +17,26 @@
|
||||
#ifndef TNT_FILAMENT_BACKEND_WEBGPUDRIVER_H
|
||||
#define TNT_FILAMENT_BACKEND_WEBGPUDRIVER_H
|
||||
|
||||
#include <backend/platforms/WebGPUPlatform.h>
|
||||
|
||||
#include "DriverBase.h"
|
||||
#include "private/backend/Dispatcher.h"
|
||||
#include "private/backend/Driver.h"
|
||||
#include <backend/DriverEnums.h>
|
||||
#include "DriverBase.h"
|
||||
|
||||
#include <utils/compiler.h>
|
||||
|
||||
#include <webgpu/webgpu_cpp.h>
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace filament::backend {
|
||||
|
||||
/**
|
||||
* WebGPU backend (driver) implementation
|
||||
*/
|
||||
class WebGPUDriver final : public DriverBase {
|
||||
public:
|
||||
WebGPUDriver() noexcept;
|
||||
~WebGPUDriver() noexcept override;
|
||||
Dispatcher getDispatcher() const noexcept final;
|
||||
|
||||
[[nodiscard]] Dispatcher getDispatcher() const noexcept final;
|
||||
[[nodiscard]] static Driver* create(WebGPUPlatform& platform) noexcept;
|
||||
public:
|
||||
static Driver* create();
|
||||
|
||||
private:
|
||||
explicit WebGPUDriver(WebGPUPlatform& platform) noexcept;
|
||||
[[nodiscard]] ShaderModel getShaderModel() const noexcept final;
|
||||
[[nodiscard]] ShaderLanguage getShaderLanguage() const noexcept final;
|
||||
ShaderModel getShaderModel() const noexcept final;
|
||||
ShaderLanguage getShaderLanguage() const noexcept final;
|
||||
|
||||
// the platform (e.g. OS) specific aspects of the WebGPU backend are strictly only
|
||||
// handled in the WebGPUPlatform
|
||||
WebGPUPlatform& mPlatform;
|
||||
wgpu::Surface mSurface = nullptr;
|
||||
wgpu::Adapter mAdapter = nullptr;
|
||||
wgpu::Device mDevice = nullptr;
|
||||
wgpu::Queue mQueue = nullptr;
|
||||
uint64_t mNextFakeHandle = 1;
|
||||
uint64_t nextFakeHandle = 1;
|
||||
|
||||
/*
|
||||
* Driver interface
|
||||
@@ -63,19 +45,20 @@ private:
|
||||
template<typename T>
|
||||
friend class ConcreteDispatcher;
|
||||
|
||||
#define DECL_DRIVER_API(methodName, paramsDecl, params) \
|
||||
#define DECL_DRIVER_API(methodName, paramsDecl, params) \
|
||||
UTILS_ALWAYS_INLINE inline void methodName(paramsDecl);
|
||||
|
||||
#define DECL_DRIVER_API_SYNCHRONOUS(RetType, methodName, paramsDecl, params) \
|
||||
#define DECL_DRIVER_API_SYNCHRONOUS(RetType, methodName, paramsDecl, params) \
|
||||
RetType methodName(paramsDecl) override;
|
||||
|
||||
#define DECL_DRIVER_API_RETURN(RetType, methodName, paramsDecl, params) \
|
||||
RetType methodName##S() noexcept override; \
|
||||
UTILS_ALWAYS_INLINE inline void methodName##R(RetType, paramsDecl);
|
||||
#define DECL_DRIVER_API_RETURN(RetType, methodName, paramsDecl, params) \
|
||||
RetType methodName##S() noexcept override { \
|
||||
return RetType((RetType::HandleId)nextFakeHandle++); } \
|
||||
UTILS_ALWAYS_INLINE inline void methodName##R(RetType, paramsDecl) { }
|
||||
|
||||
#include "private/backend/DriverAPI.inc"
|
||||
};
|
||||
|
||||
}// namespace filament::backend
|
||||
} // namespace filament
|
||||
|
||||
#endif// TNT_FILAMENT_BACKEND_WEBGPUDRIVER_H
|
||||
#endif // TNT_FILAMENT_BACKEND_WEBGPUDRIVER_H
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright (C) 2025 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.
|
||||
*/
|
||||
|
||||
#include "webgpu/WebGPUPlatform.h"
|
||||
#include "webgpu/WebGPUDriver.h"
|
||||
|
||||
#include "utils/Log.h"
|
||||
|
||||
namespace filament::backend {
|
||||
|
||||
Driver* WebGPUPlatform::createDriver(void* const sharedContext , const Platform::DriverConfig& driverConfig) noexcept {
|
||||
wgpu::InstanceDescriptor instance_descriptor {};
|
||||
wgpu::Instance instance = wgpu::CreateInstance(&instance_descriptor);
|
||||
if (instance) {
|
||||
utils::slog.i << " WebGPU instance created\n";
|
||||
} else {
|
||||
utils::slog.e << " WebGPU instance failed to create\n";
|
||||
return nullptr;
|
||||
}
|
||||
return WebGPUDriver::create();
|
||||
}
|
||||
|
||||
} // namespace filament
|
||||
+17
-11
@@ -14,23 +14,29 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef TNT_FILAMENT_BACKEND_PRIVATE_BACKENDUTILSANDROID_H
|
||||
#define TNT_FILAMENT_BACKEND_PRIVATE_BACKENDUTILSANDROID_H
|
||||
#ifndef TNT_FILAMENT_BACKEND_WEBGPUPLATFORM_H
|
||||
#define TNT_FILAMENT_BACKEND_WEBGPUPLATFORM_H
|
||||
|
||||
#include <backend/DriverEnums.h>
|
||||
#include <backend/Platform.h>
|
||||
|
||||
#include "webgpu/webgpu_cpp.h"
|
||||
|
||||
namespace filament::backend {
|
||||
|
||||
/**
|
||||
* Maps AHardwareBuffer format to TextureFormat.
|
||||
*/
|
||||
TextureFormat mapToFilamentFormat(unsigned int format, bool isSrgbTransfer) noexcept;
|
||||
class WebGPUPlatform
|
||||
final : public Platform {
|
||||
public:
|
||||
|
||||
/**
|
||||
* Maps AHardwareBuffer usage to TextureUsage.
|
||||
*/
|
||||
TextureUsage mapToFilamentUsage(unsigned int usage, TextureFormat format) noexcept;
|
||||
int getOSVersion() const noexcept final { return 0; }
|
||||
|
||||
~WebGPUPlatform() noexcept override = default;
|
||||
|
||||
protected:
|
||||
|
||||
Driver* createDriver(void* sharedContext, const Platform::DriverConfig& driverConfig) noexcept override;
|
||||
};
|
||||
|
||||
} // namespace filament
|
||||
|
||||
#endif // TNT_FILAMENT_BACKEND_PRIVATE_BACKENDUTILSANDROID_H
|
||||
#endif // TNT_FILAMENT_BACKEND_WEBGPUPLATFORM_H
|
||||
@@ -1,159 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2025 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.
|
||||
*/
|
||||
|
||||
#include <backend/platforms/WebGPUPlatform.h>
|
||||
|
||||
#include "webgpu/WebGPUConstants.h"
|
||||
#include "webgpu/WebGPUDriver.h"
|
||||
|
||||
#include <backend/Platform.h>
|
||||
#include <utils/Panic.h>
|
||||
#include <utils/ostream.h>
|
||||
|
||||
#include <dawn/webgpu_cpp_print.h>
|
||||
#include <webgpu/webgpu_cpp.h>
|
||||
|
||||
#include <cstdint>
|
||||
#include <sstream>
|
||||
|
||||
/**
|
||||
* WebGPU Backend implementation common across platforms or operating systems (at least for now).
|
||||
* Some of these functions may likely be refactored to platform/OS-specific implementations
|
||||
* over time as needed. The caller of the WebGPUPlatform doesn't need to care which is the case.
|
||||
*/
|
||||
|
||||
namespace filament::backend {
|
||||
|
||||
namespace {
|
||||
|
||||
//either returns a valid instance or panics
|
||||
[[nodiscard]] wgpu::Instance createInstance() {
|
||||
wgpu::DawnTogglesDescriptor dawnTogglesDescriptor{};
|
||||
#if defined(FILAMENT_WEBGPU_IMMEDIATE_ERROR_HANDLING)
|
||||
#if FWGPU_ENABLED(FWGPU_PRINT_SYSTEM)
|
||||
FWGPU_LOGI << "setting on toggle enable_immediate_error_handling" << utils::io::endl;
|
||||
#endif
|
||||
/**
|
||||
* Have the un-captured error callback invoked immediately when an error occurs, rather than
|
||||
* waiting for the next Tick. This enables using the stack trace in which the un-captured error
|
||||
* occurred when breaking into the un-captured error callback.
|
||||
* https://crbug.com/dawn/1789
|
||||
*/
|
||||
static const char* toggleName = "enable_immediate_error_handling";
|
||||
dawnTogglesDescriptor.enabledToggleCount = 1;
|
||||
dawnTogglesDescriptor.enabledToggles = &toggleName;
|
||||
#endif
|
||||
wgpu::InstanceDescriptor instanceDescriptor{
|
||||
.nextInChain = &dawnTogglesDescriptor,
|
||||
.capabilities = {
|
||||
.timedWaitAnyEnable = true// TODO consider using pure async instead
|
||||
}
|
||||
};
|
||||
wgpu::Instance instance = wgpu::CreateInstance(&instanceDescriptor);
|
||||
FILAMENT_CHECK_POSTCONDITION(instance != nullptr) << "Unable to create webgpu instance.";
|
||||
return instance;
|
||||
}
|
||||
|
||||
}// namespace
|
||||
|
||||
wgpu::Adapter WebGPUPlatform::requestAdapter(wgpu::Surface const& surface) {
|
||||
// TODO consider power preference etc. (can be custom preferences passed to the platform or
|
||||
// based on whether this is a Mobile or Desktop system,
|
||||
// etc...)
|
||||
wgpu::RequestAdapterOptions adaptorOptions{ .compatibleSurface = surface };
|
||||
// note this just gets the first adapter
|
||||
wgpu::Adapter adapter = nullptr;
|
||||
wgpu::WaitStatus status = mInstance.WaitAny(
|
||||
mInstance.RequestAdapter(&adaptorOptions, wgpu::CallbackMode::WaitAnyOnly,
|
||||
[&adapter](wgpu::RequestAdapterStatus const status,
|
||||
wgpu::Adapter const& readyAdapter, wgpu::StringView const message) {
|
||||
// TODO consider more robust error handling
|
||||
FILAMENT_CHECK_POSTCONDITION(status == wgpu::RequestAdapterStatus::Success)
|
||||
<< "Unable to request a WebGPU adapter. Status "
|
||||
<< static_cast<uint32_t>(status)
|
||||
<< " with message: " << message.data;
|
||||
adapter = readyAdapter;
|
||||
}),
|
||||
UINT16_MAX);// TODO define reasonable timeout (or do this asynchronously)
|
||||
FILAMENT_CHECK_POSTCONDITION(status == wgpu::WaitStatus::Success)
|
||||
<< "Non-successful wait status requesting a WebGPU adapter "
|
||||
<< static_cast<uint32_t>(status);
|
||||
FILAMENT_CHECK_POSTCONDITION(adapter != nullptr)
|
||||
<< "Failed to get a WebGPU adapter for the platform";
|
||||
// TODO consider validating adapter has required features and/or limits
|
||||
return adapter;
|
||||
}
|
||||
|
||||
wgpu::Device WebGPUPlatform::requestDevice(wgpu::Adapter const& adapter) {
|
||||
// TODO consider passing required features and/or limits
|
||||
wgpu::DeviceDescriptor deviceDescriptor{};
|
||||
deviceDescriptor.label = "graphics_device";
|
||||
deviceDescriptor.defaultQueue.label = "default_queue";
|
||||
deviceDescriptor.SetDeviceLostCallback(wgpu::CallbackMode::AllowSpontaneous,
|
||||
[](wgpu::Device const&, wgpu::DeviceLostReason const& reason,
|
||||
wgpu::StringView message) {
|
||||
if (reason == wgpu::DeviceLostReason::Destroyed) {
|
||||
FWGPU_LOGD << "WebGPU device lost due to being destroyed (expected)"
|
||||
<< utils::io::endl;
|
||||
return;
|
||||
}
|
||||
// TODO try recreating the device instead of just panicking
|
||||
std::stringstream reasonStream{};
|
||||
reasonStream << reason;
|
||||
FILAMENT_CHECK_POSTCONDITION(reason != wgpu::DeviceLostReason::Destroyed)
|
||||
<< "WebGPU device lost: " << reasonStream.str() << " " << message.data;
|
||||
});
|
||||
deviceDescriptor.SetUncapturedErrorCallback(
|
||||
[](wgpu::Device const&, wgpu::ErrorType errorType, wgpu::StringView message) {
|
||||
std::stringstream typeStream{};
|
||||
typeStream << errorType;
|
||||
FWGPU_LOGE << "WebGPU device error: " << typeStream.str() << " " << message.data
|
||||
<< utils::io::endl;
|
||||
});
|
||||
wgpu::Device device = nullptr;
|
||||
wgpu::WaitStatus status = mInstance.WaitAny(
|
||||
adapter.RequestDevice(&deviceDescriptor, wgpu::CallbackMode::WaitAnyOnly,
|
||||
[&device](wgpu::RequestDeviceStatus const status,
|
||||
wgpu::Device const& readyDevice, wgpu::StringView const message) {
|
||||
FILAMENT_CHECK_POSTCONDITION(status == wgpu::RequestDeviceStatus::Success)
|
||||
<< "Unable to request a WebGPU device. Status: "
|
||||
<< static_cast<uint32_t>(status)
|
||||
<< " with message: " << message.data;
|
||||
device = readyDevice;
|
||||
}),
|
||||
UINT64_MAX);// TODO define reasonable timeout (or do this asynchronously)
|
||||
FILAMENT_CHECK_POSTCONDITION(status == wgpu::WaitStatus::Success)
|
||||
<< "Non-successful wait status requesting a WebGPU device "
|
||||
<< static_cast<uint32_t>(status);
|
||||
FILAMENT_CHECK_POSTCONDITION(device != nullptr)
|
||||
<< "Failed to get a WebGPU device for the platform.";
|
||||
return device;
|
||||
}
|
||||
|
||||
Driver* WebGPUPlatform::createDriver(void* const sharedContext,
|
||||
const Platform::DriverConfig& /*driverConfig*/) noexcept {
|
||||
if (sharedContext) {
|
||||
FWGPU_LOGW << "sharedContext is ignored/unused in the WebGPU backend. A non-null "
|
||||
"sharedContext was provided, but it will be ignored."
|
||||
<< utils::io::endl;
|
||||
}
|
||||
return WebGPUDriver::create(*this);
|
||||
}
|
||||
|
||||
WebGPUPlatform::WebGPUPlatform()
|
||||
: mInstance(createInstance()) {}
|
||||
|
||||
}// namespace filament::backend
|
||||
@@ -1,43 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2025 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.
|
||||
*/
|
||||
|
||||
#include <backend/platforms/WebGPUPlatform.h>
|
||||
|
||||
#include <utils/Panic.h>
|
||||
|
||||
#include <webgpu/webgpu_cpp.h>
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
/**
|
||||
* Android OS specific implementation aspects of the WebGPU backend
|
||||
*/
|
||||
|
||||
namespace filament::backend {
|
||||
|
||||
wgpu::Surface WebGPUPlatform::createSurface(void* nativeWindow, uint64_t /*flags*/) {
|
||||
wgpu::SurfaceSourceAndroidNativeWindow surfaceSourceAndroidWindow{};
|
||||
surfaceSourceAndroidWindow.window = nativeWindow;
|
||||
wgpu::SurfaceDescriptor surfaceDescriptor{
|
||||
.nextInChain = &surfaceSourceAndroidWindow,
|
||||
.label = "android_surface"
|
||||
};
|
||||
wgpu::Surface surface = mInstance.CreateSurface(&surfaceDescriptor);
|
||||
FILAMENT_CHECK_POSTCONDITION(surface != nullptr) << "Unable to create Android-backed surface.";
|
||||
return surface;
|
||||
}
|
||||
|
||||
}// namespace filament::backend
|
||||
@@ -1,81 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2025 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.
|
||||
*/
|
||||
|
||||
#include <backend/platforms/WebGPUPlatform.h>
|
||||
|
||||
#include <utils/Panic.h>
|
||||
#include <utils/ostream.h>
|
||||
|
||||
#include <webgpu/webgpu_cpp.h>
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
// Platform specific includes and defines
|
||||
#if defined(__APPLE__)
|
||||
#include <Cocoa/Cocoa.h>
|
||||
#import <QuartzCore/CAMetalLayer.h>
|
||||
#elif defined(FILAMENT_IOS)
|
||||
// Metal is not available when building for the iOS simulator on Desktop.
|
||||
#define METAL_AVAILABLE __has_include(<QuartzCore/CAMetalLayer.h>)
|
||||
#if METAL_AVAILABLE
|
||||
#import <Metal/Metal.h>
|
||||
#import <QuartzCore/CAMetalLayer.h>
|
||||
#endif
|
||||
// is this needed?
|
||||
#define METALVIEW_TAG 255
|
||||
#else
|
||||
#error Not a supported Apple + WebGPU platform
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Apple (Mac OS and IOS) specific implementation aspects of the WebGPU backend
|
||||
*/
|
||||
|
||||
namespace filament::backend {
|
||||
|
||||
wgpu::Surface WebGPUPlatform::createSurface(void* nativeWindow, uint64_t /*flags*/) {
|
||||
wgpu::Surface surface = nullptr;
|
||||
#if defined(__APPLE__)
|
||||
auto nsView = (__bridge NSView*) nativeWindow;
|
||||
FILAMENT_CHECK_POSTCONDITION(nsView) << "Unable to obtain Metal-backed NSView.";
|
||||
[nsView setWantsLayer:YES];
|
||||
id metalLayer = [CAMetalLayer layer];
|
||||
[nsView setLayer:metalLayer];
|
||||
wgpu::SurfaceSourceMetalLayer surfaceSourceMetalLayer{};
|
||||
surfaceSourceMetalLayer.layer = (__bridge void*) metalLayer;
|
||||
wgpu::SurfaceDescriptor surfaceDescriptor = {
|
||||
.nextInChain = &surfaceSourceMetalLayer,
|
||||
.label = "metal_surface",
|
||||
};
|
||||
surface = mInstance.CreateSurface(&surfaceDescriptor);
|
||||
FILAMENT_CHECK_POSTCONDITION(surface != nullptr) << "Unable to create Metal-backed surface.";
|
||||
#elif defined(FILAMENT_IOS)
|
||||
CAMetalLayer* metalLayer = (CAMetalLayer*) nativeWindow;
|
||||
wgpu::SurfaceSourceMetalLayer surfaceSourceMetalLayer{};
|
||||
surfaceSourceMetalLayer.layer = (__bridge void*) metalLayer;
|
||||
wgpu::SurfaceDescriptor surfaceDescriptor = {
|
||||
.nextInChain = &surfaceSourceMetalLayer,
|
||||
.label = "metal_surface",
|
||||
};
|
||||
surface = mInstance.CreateSurface(&surfaceDescriptor);
|
||||
FILAMENT_CHECK_POSTCONDITION(surface != nullptr) << "Unable to create Metal-backed surface.";
|
||||
#else
|
||||
#error Not a supported Apple + WebGPU platform
|
||||
#endif
|
||||
return surface;
|
||||
}
|
||||
|
||||
}// namespace filament::backend
|
||||
@@ -1,159 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2025 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.
|
||||
*/
|
||||
#include <backend/platforms/WebGPUPlatform.h>
|
||||
|
||||
#include <utils/Panic.h>
|
||||
|
||||
#include <webgpu/webgpu_cpp.h>
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
|
||||
#if defined(__linux__) || defined(__FreeBSD__)
|
||||
#define LINUX_OR_FREEBSD 1
|
||||
#endif
|
||||
|
||||
// Platform specific includes and defines
|
||||
#if defined(__linux__) && defined(FILAMENT_SUPPORTS_WAYLAND)
|
||||
#include <dlfcn.h>
|
||||
namespace {
|
||||
typedef struct _wl {
|
||||
struct wl_display* display;
|
||||
struct wl_surface* surface;
|
||||
uint32_t width;
|
||||
uint32_t height;
|
||||
} wl;
|
||||
}// namespace
|
||||
#elif defined(LINUX_OR_FREEBSD) && defined(FILAMENT_SUPPORTS_X11)
|
||||
// TODO: we should allow for headless on Linux explicitly. Right now this is the headless path
|
||||
// (with no FILAMENT_SUPPORTS_XCB or FILAMENT_SUPPORTS_XLIB).
|
||||
#include <dlfcn.h>
|
||||
#if defined(FILAMENT_SUPPORTS_XCB)
|
||||
#include <xcb/xcb.h>
|
||||
namespace {
|
||||
typedef xcb_connection_t* (*XCB_CONNECT)(const char* displayname, int* screenp);
|
||||
}// namespace
|
||||
#endif
|
||||
#if defined(FILAMENT_SUPPORTS_XLIB)
|
||||
#include <X11/Xlib.h>
|
||||
namespace {
|
||||
typedef Display* (*X11_OPEN_DISPLAY)(const char*);
|
||||
}// namespace
|
||||
#endif
|
||||
static constexpr const char* LIBRARY_X11 = "libX11.so.6";
|
||||
namespace {
|
||||
struct XEnv {
|
||||
#if defined(FILAMENT_SUPPORTS_XCB)
|
||||
XCB_CONNECT xcbConnect;
|
||||
xcb_connection_t* connection;
|
||||
#endif
|
||||
#if defined(FILAMENT_SUPPORTS_XLIB)
|
||||
X11_OPEN_DISPLAY openDisplay;
|
||||
Display* display;
|
||||
#endif
|
||||
void* library = nullptr;
|
||||
} g_x11;
|
||||
}// namespace
|
||||
#else
|
||||
#error Not a supported Linux or FeeBSD + WebGPU platform
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Linux OS specific implementation aspects of the WebGPU Backend
|
||||
*/
|
||||
|
||||
namespace filament::backend {
|
||||
|
||||
wgpu::Surface WebGPUPlatform::createSurface(void* nativeWindow, uint64_t flags) {
|
||||
wgpu::Surface surface = nullptr;
|
||||
#if defined(__linux__) && defined(FILAMENT_SUPPORTS_WAYLAND)
|
||||
wl* ptrval = reinterpret_cast<wl*>(nativeWindow);
|
||||
wgpu::SurfaceSourceWaylandSurface surfaceSourceWayland{};
|
||||
surfaceSourceWayland.display = ptrval->display;
|
||||
surfaceSourceWayland.surface = ptrval->surface;
|
||||
wgpu::SurfaceDescriptor surfaceDescriptor{
|
||||
.nextInChain = &surfaceSourceWayland,
|
||||
.label = "linux_wayland_surface"
|
||||
};
|
||||
surface = mInstance.CreateSurface(&surfaceDescriptor);
|
||||
FILAMENT_CHECK_POSTCONDITION(surface != nullptr)
|
||||
<< "Unable to create Linux Wayland-backed surface.";
|
||||
#elif defined(LINUX_OR_FREEBSD) && defined(FILAMENT_SUPPORTS_X11)
|
||||
if (g_x11.library == nullptr) {
|
||||
g_x11.library = dlopen(LIBRARY_X11, RTLD_LOCAL | RTLD_NOW);
|
||||
FILAMENT_CHECK_PRECONDITION(g_x11.library) << "Unable to open X11 library.";
|
||||
#if defined(FILAMENT_SUPPORTS_XCB)
|
||||
g_x11.xcbConnect = (XCB_CONNECT) dlsym(g_x11.library, "xcb_connect");
|
||||
int screen = 0;
|
||||
g_x11.connection = g_x11.xcbConnect(nullptr, &screen);
|
||||
#endif
|
||||
#if defined(FILAMENT_SUPPORTS_XLIB)
|
||||
g_x11.openDisplay = (X11_OPEN_DISPLAY) dlsym(g_x11.library, "XOpenDisplay");
|
||||
g_x11.display = g_x11.openDisplay(NULL);
|
||||
FILAMENT_CHECK_PRECONDITION(g_x11.display) << "Unable to open X11 display.";
|
||||
#endif
|
||||
}
|
||||
#if defined(FILAMENT_SUPPORTS_XCB) || defined(FILAMENT_SUPPORTS_XLIB)
|
||||
bool useXcb = false;
|
||||
#endif
|
||||
#if defined(FILAMENT_SUPPORTS_XCB)
|
||||
#if defined(FILAMENT_SUPPORTS_XLIB)
|
||||
useXcb = (flags & SWAP_CHAIN_CONFIG_ENABLE_XCB) != 0;
|
||||
#else
|
||||
useXcb = true;
|
||||
#endif
|
||||
if (useXcb) {
|
||||
wgpu::SurfaceSourceXCBWindow surfaceSourceXcb{};
|
||||
surfaceSourceXcb.connection = g_x11.connection;
|
||||
surfaceSourceXcb.window = reinterpret_cast<uint32_t>(nativeWindow);
|
||||
wgpu::SurfaceDescriptor surfaceDescriptor{
|
||||
.nextInChain = &surfaceSourceXcb,
|
||||
.label = "linux_xcb_surface"
|
||||
};
|
||||
surface = mInstance.CreateSurface(&surfaceDescriptor);
|
||||
FILAMENT_CHECK_POSTCONDITION(surface != nullptr)
|
||||
<< "Unable to create Linux (or FreeBSD) XCB-backed surface.";
|
||||
}
|
||||
#endif
|
||||
#if defined(FILAMENT_SUPPORTS_XLIB)
|
||||
if (!useXcb) {
|
||||
wgpu::SurfaceSourceXlibWindow surfaceSourceXlib{};
|
||||
surfaceSourceXlib.display = g_x11.display;
|
||||
surfaceSourceXlib.window = reinterpret_cast<uint64_t>(nativeWindow);
|
||||
wgpu::SurfaceDescriptor surfaceDescriptor{
|
||||
.nextInChain = &surfaceSourceXlib,
|
||||
.label = "linux_xlib_surface"
|
||||
};
|
||||
surface = mInstance.CreateSurface(&surfaceDescriptor);
|
||||
FILAMENT_CHECK_POSTCONDITION(surface != nullptr)
|
||||
<< "Unable to create Linux (or FreeBSD) XLib-backed surface.";
|
||||
}
|
||||
#endif
|
||||
FILAMENT_CHECK_POSTCONDITION(surface != nullptr)
|
||||
<< "Cannot create WebGPU X11 surface for Linux (or FreeBSD) OS "
|
||||
"(not built with support for XCB or XLIB?)";
|
||||
#elif defined(__linux__)
|
||||
FILAMENT_CHECK_POSTCONDITION(surface != nullptr)
|
||||
<< "Cannot create WebGPU surface for Linux (or FreeBSD) OS "
|
||||
"(not built with support for Wayland or X11?)";
|
||||
#else
|
||||
FILAMENT_CHECK_POSTCONDITION(surface != nullptr)
|
||||
<< "Not a supported (Linux) OS + WebGPU platform";
|
||||
#endif
|
||||
return surface;
|
||||
}
|
||||
|
||||
}// namespace filament::backend
|
||||
@@ -1,53 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2025 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.
|
||||
*/
|
||||
|
||||
#include <backend/platforms/WebGPUPlatform.h>
|
||||
|
||||
#include <utils/Panic.h>
|
||||
|
||||
#include <webgpu/webgpu_cpp.h>
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
/**
|
||||
* Windows OS specific implementation aspects of the WebGPU backend
|
||||
*/
|
||||
|
||||
namespace filament::backend {
|
||||
|
||||
wgpu::Surface WebGPUPlatform::createSurface(void* nativeWindow, uint64_t /*flags*/) {
|
||||
// TODO verify this is necessary for Dawn implementation as well:
|
||||
// On (at least) NVIDIA drivers, the Vulkan implementation (specifically the call to
|
||||
// vkGetPhysicalDeviceSurfaceCapabilitiesKHR()) does not correctly handle the fact that
|
||||
// each native window has its own DPI_AWARENESS_CONTEXT, and erroneously uses the context
|
||||
// of the calling thread. As a workaround, we set the current thread's DPI_AWARENESS_CONTEXT
|
||||
// to that of the native window we've been given. This isn't a perfect solution, because an
|
||||
// application could create swap chains on multiple native windows with varying DPI-awareness,
|
||||
// but even then, at least one of the windows would be guaranteed to work correctly.
|
||||
SetThreadDpiAwarenessContext(GetWindowDpiAwarenessContext((HWND) nativeWindow));
|
||||
wgpu::SurfaceSourceWindowsHWND surfaceSourceWin{};
|
||||
surfaceSourceWin.hinstance = GetModuleHandle(nullptr);
|
||||
surfaceSourceWin.hwnd = nativeWindow;
|
||||
wgpu::SurfaceDescriptor surfaceDescriptor{
|
||||
.nextInChain = &surfaceSourceWin,
|
||||
.label = "windows_surface"
|
||||
};
|
||||
wgpu::Surface surface = mInstance.CreateSurface(&surfaceDescriptor);
|
||||
FILAMENT_CHECK_POSTCONDITION(surface != nullptr) << "Unable to create Windows-backed surface.";
|
||||
return surface;
|
||||
}
|
||||
|
||||
}// namespace filament::backend
|
||||
@@ -1,92 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2025 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.
|
||||
*/
|
||||
|
||||
#include "Lifetimes.h"
|
||||
|
||||
#include "backend/Platform.h"
|
||||
#include "private/backend/DriverApi.h"
|
||||
|
||||
RenderFrame::RenderFrame(filament::backend::DriverApi& api): mApi(api) {
|
||||
mApi.beginFrame(0, 0, 0);
|
||||
}
|
||||
|
||||
RenderFrame::~RenderFrame() {
|
||||
mApi.endFrame(0);
|
||||
}
|
||||
|
||||
Cleanup::Cleanup(filament::backend::DriverApi& driverApi) : mDriverApi(driverApi) {}
|
||||
|
||||
Cleanup::~Cleanup() {
|
||||
for (const auto swapChain: mSwapChains) {
|
||||
mDriverApi.destroySwapChain(swapChain);
|
||||
}
|
||||
for (const auto descriptorSet : mDescriptorSets) {
|
||||
mDriverApi.destroyDescriptorSet(descriptorSet);
|
||||
}
|
||||
for (const auto descriptorSetLayout : mDescriptorSetLayouts) {
|
||||
mDriverApi.destroyDescriptorSetLayout(descriptorSetLayout);
|
||||
}
|
||||
for (const auto bufferObject : mBufferObjects) {
|
||||
mDriverApi.destroyBufferObject(bufferObject);
|
||||
}
|
||||
for (const auto program : mPrograms) {
|
||||
mDriverApi.destroyProgram(program);
|
||||
}
|
||||
for (const auto texture : mTextures) {
|
||||
mDriverApi.destroyTexture(texture);
|
||||
}
|
||||
for (const auto renderTarget : mRenderTargets) {
|
||||
mDriverApi.destroyRenderTarget(renderTarget);
|
||||
}
|
||||
|
||||
for (const auto& callback : mCallbacks) {
|
||||
callback();
|
||||
}
|
||||
}
|
||||
|
||||
template <>
|
||||
void Cleanup::addInternal(filament::backend::SwapChainHandle handle) {
|
||||
mSwapChains.push_back(handle);
|
||||
}
|
||||
template <>
|
||||
void Cleanup::addInternal(filament::backend::DescriptorSetHandle handle) {
|
||||
mDescriptorSets.push_back(handle);
|
||||
}
|
||||
template <>
|
||||
void Cleanup::addInternal(
|
||||
filament::backend::DescriptorSetLayoutHandle handle) {
|
||||
mDescriptorSetLayouts.push_back(handle);
|
||||
}
|
||||
template <>
|
||||
void Cleanup::addInternal(filament::backend::BufferObjectHandle handle) {
|
||||
mBufferObjects.push_back(handle);
|
||||
}
|
||||
template <>
|
||||
void Cleanup::addInternal(filament::backend::ProgramHandle handle) {
|
||||
mPrograms.push_back(handle);
|
||||
}
|
||||
template <>
|
||||
void Cleanup::addInternal(filament::backend::TextureHandle handle) {
|
||||
mTextures.push_back(handle);
|
||||
}
|
||||
template <>
|
||||
void Cleanup::addInternal(filament::backend::RenderTargetHandle handle) {
|
||||
mRenderTargets.push_back(handle);
|
||||
}
|
||||
|
||||
void Cleanup::addPostCall(std::function<void()> callback){
|
||||
mCallbacks.emplace_back(std::move(callback));
|
||||
}
|
||||
@@ -1,78 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2025 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.
|
||||
*/
|
||||
|
||||
#ifndef TNT_LIFETIMES_H
|
||||
#define TNT_LIFETIMES_H
|
||||
|
||||
#include <vector>
|
||||
#include <functional>
|
||||
#include <optional>
|
||||
|
||||
#include "backend/Handle.h"
|
||||
#include "backend/DriverApiForward.h"
|
||||
#include "BackendTest.h"
|
||||
|
||||
class RenderFrame {
|
||||
public:
|
||||
explicit RenderFrame(filament::backend::DriverApi& api);
|
||||
~RenderFrame();
|
||||
|
||||
RenderFrame(RenderFrame const& rhs) noexcept = delete;
|
||||
RenderFrame& operator=(RenderFrame const& rhs) noexcept = delete;
|
||||
RenderFrame(RenderFrame const&& rhs) noexcept = delete;
|
||||
RenderFrame& operator=(RenderFrame const&& rhs) noexcept = delete;
|
||||
|
||||
private:
|
||||
filament::backend::DriverApi& mApi;
|
||||
};
|
||||
|
||||
class Cleanup {
|
||||
public:
|
||||
/**
|
||||
* @param driverApi Must be valid for the entire lifetime of the Cleanup object.
|
||||
*/
|
||||
explicit Cleanup(filament::backend::DriverApi& driverApi);
|
||||
~Cleanup();
|
||||
|
||||
template <typename HandleType>
|
||||
filament::backend::Handle<HandleType> add(filament::backend::Handle<HandleType> handle);
|
||||
|
||||
void addPostCall(std::function<void()> callback);
|
||||
|
||||
private:
|
||||
template <typename HandleType>
|
||||
void addInternal(filament::backend::Handle<HandleType> handle);
|
||||
|
||||
filament::backend::DriverApi & mDriverApi;
|
||||
|
||||
std::vector<filament::backend::SwapChainHandle> mSwapChains;
|
||||
std::vector<filament::backend::DescriptorSetHandle> mDescriptorSets;
|
||||
std::vector<filament::backend::DescriptorSetLayoutHandle> mDescriptorSetLayouts;
|
||||
std::vector<filament::backend::BufferObjectHandle> mBufferObjects;
|
||||
std::vector<filament::backend::ProgramHandle> mPrograms;
|
||||
std::vector<filament::backend::TextureHandle> mTextures;
|
||||
std::vector<filament::backend::RenderTargetHandle> mRenderTargets;
|
||||
|
||||
std::vector<std::function<void()>> mCallbacks;
|
||||
};
|
||||
|
||||
template <typename HandleType>
|
||||
filament::backend::Handle<HandleType> Cleanup::add(filament::backend::Handle<HandleType> handle) {
|
||||
addInternal(handle);
|
||||
return handle;
|
||||
}
|
||||
|
||||
#endif //TNT_LIFETIMES_H
|
||||
@@ -30,8 +30,7 @@ enum class Backend : uint8_t {
|
||||
OPENGL = 1,
|
||||
VULKAN = 2,
|
||||
METAL = 3,
|
||||
WEBGPU = 4,
|
||||
NOOP = 5,
|
||||
NOOP = 4,
|
||||
};
|
||||
|
||||
struct NativeView {
|
||||
|
||||
@@ -90,9 +90,6 @@ ShaderGenerator::ShaderGenerator(std::string vertex, std::string fragment, Backe
|
||||
case Backend::METAL:
|
||||
mShaderLanguage = filament::backend::ShaderLanguage::MSL;
|
||||
break;
|
||||
case Backend::WEBGPU:
|
||||
mShaderLanguage = filament::backend::ShaderLanguage::WGSL;
|
||||
break;
|
||||
case Backend::NOOP:
|
||||
mShaderLanguage = filament::backend::ShaderLanguage::ESSL3;
|
||||
break;
|
||||
@@ -118,8 +115,6 @@ ShaderGenerator::Blob ShaderGenerator::transpileShader(ShaderStage stage, std::s
|
||||
shader.insert(pos, "#define TARGET_METAL_ENVIRONMENT\n");
|
||||
} else if (backend == Backend::VULKAN) {
|
||||
shader.insert(pos, "#define TARGET_VULKAN_ENVIRONMENT\n");
|
||||
} else if (backend == Backend::WEBGPU) {
|
||||
shader.insert(pos, "#define TARGET_VULKAN_ENVIRONMENT\n");
|
||||
}
|
||||
|
||||
const char* shaderCString = shader.c_str();
|
||||
@@ -155,8 +150,7 @@ ShaderGenerator::Blob ShaderGenerator::transpileShader(ShaderStage stage, std::s
|
||||
|
||||
assert_invariant(backend == Backend::OPENGL ||
|
||||
backend == Backend::METAL ||
|
||||
backend == Backend::VULKAN ||
|
||||
backend == Backend::WEBGPU);
|
||||
backend == Backend::VULKAN);
|
||||
|
||||
if (backend == Backend::OPENGL) {
|
||||
if (isMobile) {
|
||||
@@ -172,8 +166,6 @@ ShaderGenerator::Blob ShaderGenerator::transpileShader(ShaderStage stage, std::s
|
||||
return { result.c_str(), result.c_str() + result.length() + 1 };
|
||||
} else if (backend == Backend::VULKAN) {
|
||||
return { (uint8_t*)spirv.data(), (uint8_t*)(spirv.data() + spirv.size()) };
|
||||
} else if (backend == Backend::WEBGPU){
|
||||
filamat::GLSLPostProcessor::spirvToWgsl(&spirv, &result);
|
||||
}
|
||||
|
||||
return {};
|
||||
|
||||
+141
-110
@@ -16,7 +16,6 @@
|
||||
|
||||
#include "BackendTest.h"
|
||||
|
||||
#include "Lifetimes.h"
|
||||
#include "ShaderGenerator.h"
|
||||
#include "TrianglePrimitive.h"
|
||||
|
||||
@@ -196,8 +195,6 @@ static void createFaces(DriverApi& dapi, Handle<HwTexture> texture, int baseWidt
|
||||
|
||||
TEST_F(BackendTest, ColorMagnify) {
|
||||
auto& api = getDriverApi();
|
||||
Cleanup cleanup(getDriverApi());
|
||||
cleanup.addPostCall([&]() { executeCommands(); });
|
||||
|
||||
constexpr int kSrcTexWidth = 256;
|
||||
constexpr int kSrcTexHeight = 256;
|
||||
@@ -208,30 +205,30 @@ TEST_F(BackendTest, ColorMagnify) {
|
||||
constexpr int kNumLevels = 3;
|
||||
|
||||
// Create a SwapChain and make it current. We don't really use it so the res doesn't matter.
|
||||
auto swapChain = cleanup.add(api.createSwapChainHeadless(256, 256, 0));
|
||||
auto swapChain = api.createSwapChainHeadless(256, 256, 0);
|
||||
api.makeCurrent(swapChain, swapChain);
|
||||
|
||||
// Create a source texture.
|
||||
Handle<HwTexture> const srcTexture = cleanup.add(api.createTexture(
|
||||
Handle<HwTexture> const srcTexture = api.createTexture(
|
||||
SamplerType::SAMPLER_2D, kNumLevels, kSrcTexFormat, 1, kSrcTexWidth, kSrcTexHeight, 1,
|
||||
TextureUsage::SAMPLEABLE | TextureUsage::UPLOADABLE | TextureUsage::COLOR_ATTACHMENT));
|
||||
TextureUsage::SAMPLEABLE | TextureUsage::UPLOADABLE | TextureUsage::COLOR_ATTACHMENT);
|
||||
const bool flipY = sBackend == Backend::OPENGL;
|
||||
createBitmap(api, srcTexture, kSrcTexWidth, kSrcTexHeight, 0, float3(0.5, 0, 0), flipY);
|
||||
createBitmap(api, srcTexture, kSrcTexWidth, kSrcTexHeight, 1, float3(0, 0, 0.5), flipY);
|
||||
|
||||
// Create a destination texture.
|
||||
Handle<HwTexture> const dstTexture = cleanup.add(api.createTexture(
|
||||
Handle<HwTexture> const dstTexture = api.createTexture(
|
||||
SamplerType::SAMPLER_2D, kNumLevels, kDstTexFormat, 1, kDstTexWidth, kDstTexHeight, 1,
|
||||
TextureUsage::SAMPLEABLE | TextureUsage::COLOR_ATTACHMENT));
|
||||
TextureUsage::SAMPLEABLE | TextureUsage::COLOR_ATTACHMENT);
|
||||
|
||||
// Create a RenderTarget for each texture's miplevel.
|
||||
Handle<HwRenderTarget> srcRenderTargets[kNumLevels];
|
||||
Handle<HwRenderTarget> dstRenderTargets[kNumLevels];
|
||||
for (uint8_t level = 0; level < kNumLevels; level++) {
|
||||
srcRenderTargets[level] = cleanup.add(api.createRenderTarget( TargetBufferFlags::COLOR,
|
||||
kSrcTexWidth >> level, kSrcTexHeight >> level, 1, 0, { srcTexture, level, 0 }, {}, {}));
|
||||
dstRenderTargets[level] = cleanup.add(api.createRenderTarget( TargetBufferFlags::COLOR,
|
||||
kDstTexWidth >> level, kDstTexHeight >> level, 1, 0, { dstTexture, level, 0 }, {}, {}));
|
||||
srcRenderTargets[level] = api.createRenderTarget( TargetBufferFlags::COLOR,
|
||||
kSrcTexWidth >> level, kSrcTexHeight >> level, 1, 0, { srcTexture, level, 0 }, {}, {});
|
||||
dstRenderTargets[level] = api.createRenderTarget( TargetBufferFlags::COLOR,
|
||||
kDstTexWidth >> level, kDstTexHeight >> level, 1, 0, { dstTexture, level, 0 }, {}, {});
|
||||
}
|
||||
|
||||
// Do a "magnify" blit from level 1 of the source RT to the level 0 of the destination RT.
|
||||
@@ -241,18 +238,16 @@ TEST_F(BackendTest, ColorMagnify) {
|
||||
{0, 0, kSrcTexWidth >> srcLevel, kSrcTexHeight >> srcLevel}, SamplerMagFilter::LINEAR);
|
||||
|
||||
// Push through an empty frame to allow the texture to upload and the blit to execute.
|
||||
{
|
||||
RenderFrame frame(api);
|
||||
api.commit(swapChain);
|
||||
}
|
||||
api.beginFrame(0, 0, 0);
|
||||
api.commit(swapChain);
|
||||
api.endFrame(0);
|
||||
|
||||
// Grab a screenshot.
|
||||
ScreenshotParams params { kDstTexWidth, kDstTexHeight, "ColorMagnify.png" };
|
||||
{
|
||||
RenderFrame frame(api);
|
||||
dumpScreenshot(api, dstRenderTargets[0], ¶ms);
|
||||
api.commit(swapChain);
|
||||
}
|
||||
api.beginFrame(0, 0, 0);
|
||||
dumpScreenshot(api, dstRenderTargets[0], ¶ms);
|
||||
api.commit(swapChain);
|
||||
api.endFrame(0);
|
||||
|
||||
// Wait for the ReadPixels result to come back.
|
||||
api.finish();
|
||||
@@ -263,12 +258,18 @@ TEST_F(BackendTest, ColorMagnify) {
|
||||
const uint32_t expected = 0x410bdd31;
|
||||
printf("Computed hash is 0x%8.8x, Expected 0x%8.8x\n", params.pixelHashResult, expected);
|
||||
EXPECT_TRUE(params.pixelHashResult == expected);
|
||||
|
||||
// Cleanup.
|
||||
api.destroyTexture(srcTexture);
|
||||
api.destroyTexture(dstTexture);
|
||||
api.destroySwapChain(swapChain);
|
||||
for (auto rt : srcRenderTargets) api.destroyRenderTarget(rt);
|
||||
for (auto rt : dstRenderTargets) api.destroyRenderTarget(rt);
|
||||
executeCommands();
|
||||
}
|
||||
|
||||
TEST_F(BackendTest, ColorMinify) {
|
||||
auto& api = getDriverApi();
|
||||
Cleanup cleanup(getDriverApi());
|
||||
cleanup.addPostCall([&]() { executeCommands(); });
|
||||
|
||||
constexpr int kSrcTexWidth = 1024;
|
||||
constexpr int kSrcTexHeight = 1024;
|
||||
@@ -279,30 +280,30 @@ TEST_F(BackendTest, ColorMinify) {
|
||||
constexpr int kNumLevels = 3;
|
||||
|
||||
// Create a SwapChain and make it current. We don't really use it so the res doesn't matter.
|
||||
auto swapChain = cleanup.add(api.createSwapChainHeadless(256, 256, 0));
|
||||
auto swapChain = api.createSwapChainHeadless(256, 256, 0);
|
||||
api.makeCurrent(swapChain, swapChain);
|
||||
|
||||
// Create a source texture.
|
||||
Handle<HwTexture> const srcTexture = cleanup.add(api.createTexture(
|
||||
Handle<HwTexture> const srcTexture = api.createTexture(
|
||||
SamplerType::SAMPLER_2D, kNumLevels, kSrcTexFormat, 1, kSrcTexWidth, kSrcTexHeight, 1,
|
||||
TextureUsage::SAMPLEABLE | TextureUsage::UPLOADABLE | TextureUsage::COLOR_ATTACHMENT));
|
||||
TextureUsage::SAMPLEABLE | TextureUsage::UPLOADABLE | TextureUsage::COLOR_ATTACHMENT);
|
||||
const bool flipY = sBackend == Backend::OPENGL;
|
||||
createBitmap(api, srcTexture, kSrcTexWidth, kSrcTexHeight, 0, float3(0.5, 0, 0), flipY);
|
||||
createBitmap(api, srcTexture, kSrcTexWidth, kSrcTexHeight, 1, float3(0, 0, 0.5), flipY);
|
||||
|
||||
// Create a destination texture.
|
||||
Handle<HwTexture> const dstTexture = cleanup.add(api.createTexture(
|
||||
Handle<HwTexture> const dstTexture = api.createTexture(
|
||||
SamplerType::SAMPLER_2D, kNumLevels, kDstTexFormat, 1, kDstTexWidth, kDstTexHeight, 1,
|
||||
TextureUsage::SAMPLEABLE | TextureUsage::COLOR_ATTACHMENT));
|
||||
TextureUsage::SAMPLEABLE | TextureUsage::COLOR_ATTACHMENT);
|
||||
|
||||
// Create a RenderTarget for each texture's miplevel.
|
||||
Handle<HwRenderTarget> srcRenderTargets[kNumLevels];
|
||||
Handle<HwRenderTarget> dstRenderTargets[kNumLevels];
|
||||
for (uint8_t level = 0; level < kNumLevels; level++) {
|
||||
srcRenderTargets[level] = cleanup.add(api.createRenderTarget( TargetBufferFlags::COLOR,
|
||||
kSrcTexWidth >> level, kSrcTexHeight >> level, 1, 0, { srcTexture, level, 0 }, {}, {}));
|
||||
dstRenderTargets[level] = cleanup.add(api.createRenderTarget( TargetBufferFlags::COLOR,
|
||||
kDstTexWidth >> level, kDstTexHeight >> level, 1, 0, { dstTexture, level, 0 }, {}, {}));
|
||||
srcRenderTargets[level] = api.createRenderTarget( TargetBufferFlags::COLOR,
|
||||
kSrcTexWidth >> level, kSrcTexHeight >> level, 1, 0, { srcTexture, level, 0 }, {}, {});
|
||||
dstRenderTargets[level] = api.createRenderTarget( TargetBufferFlags::COLOR,
|
||||
kDstTexWidth >> level, kDstTexHeight >> level, 1, 0, { dstTexture, level, 0 }, {}, {});
|
||||
}
|
||||
|
||||
// Do a "minify" blit from level 1 of the source RT to the level 0 of the destination RT.
|
||||
@@ -313,7 +314,6 @@ TEST_F(BackendTest, ColorMinify) {
|
||||
srcRenderTargets[srcLevel], {0, 0, kSrcTexWidth >> srcLevel, kSrcTexHeight >> srcLevel},
|
||||
SamplerMagFilter::LINEAR);
|
||||
|
||||
|
||||
// Grab a screenshot.
|
||||
ScreenshotParams params { kDstTexWidth, kDstTexHeight, "ColorMinify.png" };
|
||||
dumpScreenshot(api, dstRenderTargets[0], ¶ms);
|
||||
@@ -325,11 +325,18 @@ TEST_F(BackendTest, ColorMinify) {
|
||||
const uint32_t expected = 0xf3d9c53f;
|
||||
printf("Computed hash is 0x%8.8x, Expected 0x%8.8x\n", params.pixelHashResult, expected);
|
||||
EXPECT_TRUE(params.pixelHashResult == expected);
|
||||
|
||||
// Cleanup.
|
||||
api.destroyTexture(srcTexture);
|
||||
api.destroyTexture(dstTexture);
|
||||
api.destroySwapChain(swapChain);
|
||||
for (auto rt : srcRenderTargets) api.destroyRenderTarget(rt);
|
||||
for (auto rt : dstRenderTargets) api.destroyRenderTarget(rt);
|
||||
executeCommands();
|
||||
}
|
||||
|
||||
TEST_F(BackendTest, ColorResolve) {
|
||||
auto& api = getDriverApi();
|
||||
Cleanup cleanup(getDriverApi());
|
||||
|
||||
constexpr int kSrcTexWidth = 256;
|
||||
constexpr int kSrcTexHeight = 256;
|
||||
@@ -349,40 +356,40 @@ TEST_F(BackendTest, ColorResolve) {
|
||||
triangleVs, triangleFs, sBackend, sIsMobilePlatform, std::move(descriptors));
|
||||
Program prog = shaderGen.getProgram(api);
|
||||
prog.descriptorBindings(1, {{ "Params", DescriptorType::UNIFORM_BUFFER, 0 }});
|
||||
program = cleanup.add(api.createProgram(std::move(prog)));
|
||||
program = api.createProgram(std::move(prog));
|
||||
}
|
||||
|
||||
DescriptorSetLayoutHandle descriptorSetLayout = cleanup.add(api.createDescriptorSetLayout({
|
||||
DescriptorSetLayoutHandle descriptorSetLayout = api.createDescriptorSetLayout({
|
||||
{{
|
||||
DescriptorType::UNIFORM_BUFFER,
|
||||
ShaderStageFlags::ALL_SHADER_STAGE_FLAGS, 0,
|
||||
DescriptorFlags::NONE, 0
|
||||
}}}));
|
||||
}}});
|
||||
|
||||
DescriptorSetHandle descriptorSet = cleanup.add(api.createDescriptorSet(descriptorSetLayout));
|
||||
DescriptorSetHandle descriptorSet = api.createDescriptorSet(descriptorSetLayout);
|
||||
|
||||
// Create a VertexBuffer, IndexBuffer, and RenderPrimitive.
|
||||
TrianglePrimitive const triangle(api);
|
||||
|
||||
// Create 4-sample texture.
|
||||
Handle<HwTexture> const srcColorTexture = cleanup.add(api.createTexture(
|
||||
Handle<HwTexture> const srcColorTexture = api.createTexture(
|
||||
SamplerType::SAMPLER_2D, 1, kColorTexFormat, kSampleCount, kSrcTexWidth, kSrcTexHeight, 1,
|
||||
TextureUsage::COLOR_ATTACHMENT));
|
||||
TextureUsage::COLOR_ATTACHMENT);
|
||||
|
||||
// Create 1-sample texture.
|
||||
Handle<HwTexture> const dstColorTexture = cleanup.add(api.createTexture(
|
||||
Handle<HwTexture> const dstColorTexture = api.createTexture(
|
||||
SamplerType::SAMPLER_2D, 1, kColorTexFormat, 1, kDstTexWidth, kDstTexHeight, 1,
|
||||
TextureUsage::SAMPLEABLE | TextureUsage::COLOR_ATTACHMENT));
|
||||
TextureUsage::SAMPLEABLE | TextureUsage::COLOR_ATTACHMENT);
|
||||
|
||||
// Create a 4-sample render target with the 4-sample texture.
|
||||
Handle<HwRenderTarget> const srcRenderTarget = cleanup.add(api.createRenderTarget(
|
||||
Handle<HwRenderTarget> const srcRenderTarget = api.createRenderTarget(
|
||||
TargetBufferFlags::COLOR, kSrcTexWidth, kSrcTexHeight, kSampleCount, 0,
|
||||
{{ srcColorTexture }}, {}, {}));
|
||||
{{ srcColorTexture }}, {}, {});
|
||||
|
||||
// Create a 1-sample render target with the 1-sample texture.
|
||||
Handle<HwRenderTarget> const dstRenderTarget = cleanup.add(api.createRenderTarget(
|
||||
Handle<HwRenderTarget> const dstRenderTarget = api.createRenderTarget(
|
||||
TargetBufferFlags::COLOR, kDstTexWidth, kDstTexHeight, 1, 0,
|
||||
{{ dstColorTexture }}, {}, {}));
|
||||
{{ dstColorTexture }}, {}, {});
|
||||
|
||||
// Prep for rendering.
|
||||
RenderPassParams params = {};
|
||||
@@ -401,8 +408,8 @@ TEST_F(BackendTest, ColorResolve) {
|
||||
state.rasterState.depthFunc = RasterState::DepthFunc::A;
|
||||
state.rasterState.culling = CullingMode::NONE;
|
||||
|
||||
auto ubuffer = cleanup.add(api.createBufferObject(sizeof(MaterialParams),
|
||||
BufferObjectBinding::UNIFORM, BufferUsage::STATIC));
|
||||
auto ubuffer = api.createBufferObject(sizeof(MaterialParams),
|
||||
BufferObjectBinding::UNIFORM, BufferUsage::STATIC);
|
||||
// Draw red triangle into srcRenderTarget.
|
||||
uploadUniforms(api, ubuffer, {
|
||||
.color = float4(1, 0, 0, 1),
|
||||
@@ -413,12 +420,11 @@ TEST_F(BackendTest, ColorResolve) {
|
||||
api.bindDescriptorSet(descriptorSet, 1, {});
|
||||
|
||||
// FIXME: on Metal this triangle is not drawn. Can't understand why.
|
||||
{
|
||||
RenderFrame frame(api);
|
||||
api.beginFrame(0, 0, 0);
|
||||
api.beginRenderPass(srcRenderTarget, params);
|
||||
api.draw(state, triangle.getRenderPrimitive(), 0, 3, 1);
|
||||
api.endRenderPass();
|
||||
}
|
||||
api.endFrame(0);
|
||||
|
||||
// Resolve the MSAA render target into the single-sample render target.
|
||||
api.blitDEPRECATED(TargetBufferFlags::COLOR,
|
||||
@@ -437,15 +443,23 @@ TEST_F(BackendTest, ColorResolve) {
|
||||
const uint32_t expected = 0xebfac2ef;
|
||||
printf("Computed hash is 0x%8.8x, Expected 0x%8.8x\n", sparams.pixelHashResult, expected);
|
||||
EXPECT_TRUE(sparams.pixelHashResult == expected);
|
||||
|
||||
// Cleanup.
|
||||
api.destroyDescriptorSet(descriptorSet);
|
||||
api.destroyDescriptorSetLayout(descriptorSetLayout);
|
||||
api.destroyBufferObject(ubuffer);
|
||||
api.destroyProgram(program);
|
||||
api.destroyTexture(srcColorTexture);
|
||||
api.destroyTexture(dstColorTexture);
|
||||
api.destroyRenderTarget(srcRenderTarget);
|
||||
api.destroyRenderTarget(dstRenderTarget);
|
||||
flushAndWait();
|
||||
}
|
||||
|
||||
TEST_F(BackendTest, Blit2DTextureArray) {
|
||||
auto& api = getDriverApi();
|
||||
Cleanup cleanup(getDriverApi());
|
||||
cleanup.addPostCall([&]() { executeCommands(); });
|
||||
|
||||
api.startCapture(0);
|
||||
cleanup.addPostCall([&]() { api.stopCapture(0); });
|
||||
|
||||
constexpr int kSrcTexWidth = 256;
|
||||
constexpr int kSrcTexHeight = 256;
|
||||
@@ -460,27 +474,27 @@ TEST_F(BackendTest, Blit2DTextureArray) {
|
||||
constexpr int kDstTexLayer = 0;
|
||||
|
||||
// Create a SwapChain and make it current. We don't really use it so the res doesn't matter.
|
||||
auto swapChain = cleanup.add(api.createSwapChainHeadless(256, 256, 0));
|
||||
auto swapChain = api.createSwapChainHeadless(256, 256, 0);
|
||||
api.makeCurrent(swapChain, swapChain);
|
||||
|
||||
// Create a source texture.
|
||||
Handle<HwTexture> srcTexture = cleanup.add(api.createTexture(
|
||||
Handle<HwTexture> srcTexture = api.createTexture(
|
||||
SamplerType::SAMPLER_2D_ARRAY, kNumLevels, kSrcTexFormat, 1, kSrcTexWidth, kSrcTexHeight, kSrcTexDepth,
|
||||
TextureUsage::SAMPLEABLE | TextureUsage::UPLOADABLE | TextureUsage::COLOR_ATTACHMENT));
|
||||
TextureUsage::SAMPLEABLE | TextureUsage::UPLOADABLE | TextureUsage::COLOR_ATTACHMENT);
|
||||
const bool flipY = sBackend == Backend::OPENGL;
|
||||
createBitmap(api, srcTexture, kSrcTexWidth, kSrcTexHeight, 0, kSrcTexLayer, float3(0.5, 0, 0), flipY);
|
||||
|
||||
// Create a destination texture.
|
||||
Handle<HwTexture> dstTexture = cleanup.add(api.createTexture(
|
||||
Handle<HwTexture> dstTexture = api.createTexture(
|
||||
SamplerType::SAMPLER_2D, kNumLevels, kDstTexFormat, 1, kDstTexWidth, kDstTexHeight, 1,
|
||||
TextureUsage::SAMPLEABLE | TextureUsage::COLOR_ATTACHMENT));
|
||||
TextureUsage::SAMPLEABLE | TextureUsage::COLOR_ATTACHMENT);
|
||||
|
||||
// Create two RenderTargets.
|
||||
const int level = 0;
|
||||
Handle<HwRenderTarget> srcRenderTarget = cleanup.add(api.createRenderTarget( TargetBufferFlags::COLOR,
|
||||
kSrcTexWidth >> level, kSrcTexHeight >> level, 1, 0, { srcTexture, level, kSrcTexLayer }, {}, {}));
|
||||
Handle<HwRenderTarget> dstRenderTarget = cleanup.add(api.createRenderTarget( TargetBufferFlags::COLOR,
|
||||
kDstTexWidth >> level, kDstTexHeight >> level, 1, 0, { dstTexture, level, kDstTexLayer }, {}, {}));
|
||||
Handle<HwRenderTarget> srcRenderTarget = api.createRenderTarget( TargetBufferFlags::COLOR,
|
||||
kSrcTexWidth >> level, kSrcTexHeight >> level, 1, 0, { srcTexture, level, kSrcTexLayer }, {}, {});
|
||||
Handle<HwRenderTarget> dstRenderTarget = api.createRenderTarget( TargetBufferFlags::COLOR,
|
||||
kDstTexWidth >> level, kDstTexHeight >> level, 1, 0, { dstTexture, level, kDstTexLayer }, {}, {});
|
||||
|
||||
// Do a blit from kSrcTexLayer of the source RT to kDstTexLayer of the destination RT.
|
||||
const int srcLevel = 0;
|
||||
@@ -489,18 +503,16 @@ TEST_F(BackendTest, Blit2DTextureArray) {
|
||||
{0, 0, kSrcTexWidth >> srcLevel, kSrcTexHeight >> srcLevel}, SamplerMagFilter::LINEAR);
|
||||
|
||||
// Push through an empty frame to allow the texture to upload and the blit to execute.
|
||||
{
|
||||
RenderFrame frame(api);
|
||||
api.commit(swapChain);
|
||||
}
|
||||
api.beginFrame(0, 0, 0);
|
||||
api.commit(swapChain);
|
||||
api.endFrame(0);
|
||||
|
||||
// Grab a screenshot.
|
||||
ScreenshotParams params { kDstTexWidth, kDstTexHeight, "Blit2DTextureArray.png" };
|
||||
{
|
||||
RenderFrame frame(api);
|
||||
dumpScreenshot(api, dstRenderTarget, ¶ms);
|
||||
api.commit(swapChain);
|
||||
}
|
||||
api.beginFrame(0, 0, 0);
|
||||
dumpScreenshot(api, dstRenderTarget, ¶ms);
|
||||
api.commit(swapChain);
|
||||
api.endFrame(0);
|
||||
|
||||
// Wait for the ReadPixels result to come back.
|
||||
api.finish();
|
||||
@@ -511,12 +523,20 @@ TEST_F(BackendTest, Blit2DTextureArray) {
|
||||
const uint32_t expected = 0x8de7d55b;
|
||||
printf("Computed hash is 0x%8.8x, Expected 0x%8.8x\n", params.pixelHashResult, expected);
|
||||
EXPECT_TRUE(params.pixelHashResult == expected);
|
||||
|
||||
// Cleanup.
|
||||
api.destroyTexture(srcTexture);
|
||||
api.destroyTexture(dstTexture);
|
||||
api.destroySwapChain(swapChain);
|
||||
api.destroyRenderTarget(srcRenderTarget);
|
||||
api.destroyRenderTarget(dstRenderTarget);
|
||||
executeCommands();
|
||||
|
||||
api.stopCapture(0);
|
||||
}
|
||||
|
||||
TEST_F(BackendTest, BlitRegion) {
|
||||
auto& api = getDriverApi();
|
||||
Cleanup cleanup(getDriverApi());
|
||||
cleanup.addPostCall([&]() { executeCommands(); });
|
||||
|
||||
constexpr int kSrcTexWidth = 1024;
|
||||
constexpr int kSrcTexHeight = 1024;
|
||||
@@ -529,21 +549,21 @@ TEST_F(BackendTest, BlitRegion) {
|
||||
constexpr int kDstLevel = 0;
|
||||
|
||||
// Create a SwapChain and make it current. We don't really use it so the res doesn't matter.
|
||||
auto swapChain = cleanup.add(api.createSwapChainHeadless(256, 256, 0));
|
||||
auto swapChain = api.createSwapChainHeadless(256, 256, 0);
|
||||
api.makeCurrent(swapChain, swapChain);
|
||||
|
||||
// Create a source texture.
|
||||
Handle<HwTexture> srcTexture = cleanup.add(api.createTexture(
|
||||
Handle<HwTexture> srcTexture = api.createTexture(
|
||||
SamplerType::SAMPLER_2D, kNumLevels, kSrcTexFormat, 1, kSrcTexWidth, kSrcTexHeight, 1,
|
||||
TextureUsage::SAMPLEABLE | TextureUsage::UPLOADABLE | TextureUsage::COLOR_ATTACHMENT));
|
||||
TextureUsage::SAMPLEABLE | TextureUsage::UPLOADABLE | TextureUsage::COLOR_ATTACHMENT);
|
||||
const bool flipY = sBackend == Backend::OPENGL;
|
||||
createBitmap(api, srcTexture, kSrcTexWidth, kSrcTexHeight, 0, float3(0.5, 0, 0), flipY);
|
||||
createBitmap(api, srcTexture, kSrcTexWidth, kSrcTexHeight, 1, float3(0, 0, 0.5), flipY);
|
||||
|
||||
// Create a destination texture.
|
||||
Handle<HwTexture> dstTexture = cleanup.add(api.createTexture(
|
||||
Handle<HwTexture> dstTexture = api.createTexture(
|
||||
SamplerType::SAMPLER_2D, kNumLevels, kDstTexFormat, 1, kDstTexWidth, kDstTexHeight, 1,
|
||||
TextureUsage::SAMPLEABLE | TextureUsage::COLOR_ATTACHMENT));
|
||||
TextureUsage::SAMPLEABLE | TextureUsage::COLOR_ATTACHMENT);
|
||||
|
||||
// Blit one-quarter of src level 1 to dst level 0.
|
||||
Viewport srcRect = {
|
||||
@@ -563,34 +583,34 @@ TEST_F(BackendTest, BlitRegion) {
|
||||
// We purposely set the render target width and height to smaller than the texture, to check
|
||||
// that this case is handled correctly.
|
||||
Handle<HwRenderTarget> srcRenderTarget =
|
||||
cleanup.add(api.createRenderTarget(TargetBufferFlags::COLOR, srcRect.width,
|
||||
srcRect.height, 1, 0, {srcTexture, kSrcLevel, 0}, {}, {}));
|
||||
api.createRenderTarget(TargetBufferFlags::COLOR, srcRect.width,
|
||||
srcRect.height, 1, 0, {srcTexture, kSrcLevel, 0}, {}, {});
|
||||
Handle<HwRenderTarget> dstRenderTarget =
|
||||
cleanup.add(api.createRenderTarget(TargetBufferFlags::COLOR, kDstTexWidth >> kDstLevel,
|
||||
kDstTexHeight >> kDstLevel, 1, 0, {dstTexture, kDstLevel, 0}, {}, {}));
|
||||
api.createRenderTarget(TargetBufferFlags::COLOR, kDstTexWidth >> kDstLevel,
|
||||
kDstTexHeight >> kDstLevel, 1, 0, {dstTexture, kDstLevel, 0}, {}, {});
|
||||
|
||||
api.blitDEPRECATED(TargetBufferFlags::COLOR0, dstRenderTarget, dstRect, srcRenderTarget, srcRect,
|
||||
SamplerMagFilter::LINEAR);
|
||||
|
||||
// Push through an empty frame to allow the texture to upload and the blit to execute.
|
||||
{
|
||||
RenderFrame frame(api);
|
||||
api.commit(swapChain);
|
||||
}
|
||||
api.beginFrame(0, 0, 0);
|
||||
api.commit(swapChain);
|
||||
api.endFrame(0);
|
||||
|
||||
// Grab a screenshot.
|
||||
ScreenshotParams params { kDstTexWidth, kDstTexHeight, "BlitRegion.png" };
|
||||
{
|
||||
RenderFrame frame(api);
|
||||
dumpScreenshot(api, dstRenderTarget, ¶ms);
|
||||
api.commit(swapChain);
|
||||
}
|
||||
api.beginFrame(0, 0, 0);
|
||||
dumpScreenshot(api, dstRenderTarget, ¶ms);
|
||||
api.commit(swapChain);
|
||||
api.endFrame(0);
|
||||
|
||||
// Wait for the ReadPixels result to come back.
|
||||
api.finish();
|
||||
executeCommands();
|
||||
getDriver().purge();
|
||||
|
||||
// Check if the image matches perfectly to our golden run.
|
||||
//
|
||||
// TODO: for some reason, this test has very, very slight (as in one pixel) differences between
|
||||
// OpenGL and Metal. So disable golden checking for now.
|
||||
// Use the compare tool from ImageMagick to see visual differences:
|
||||
@@ -599,12 +619,18 @@ TEST_F(BackendTest, BlitRegion) {
|
||||
// const uint32_t expected = 0x74fa34ed;
|
||||
// printf("Computed hash is 0x%8.8x, Expected 0x%8.8x\n", params.pixelHashResult, expected);
|
||||
// EXPECT_TRUE(params.pixelHashResult == expected);
|
||||
|
||||
// Cleanup.
|
||||
api.destroyTexture(srcTexture);
|
||||
api.destroyTexture(dstTexture);
|
||||
api.destroySwapChain(swapChain);
|
||||
api.destroyRenderTarget(srcRenderTarget);
|
||||
api.destroyRenderTarget(dstRenderTarget);
|
||||
executeCommands();
|
||||
}
|
||||
|
||||
TEST_F(BackendTest, BlitRegionToSwapChain) {
|
||||
auto& api = getDriverApi();
|
||||
Cleanup cleanup(getDriverApi());
|
||||
cleanup.addPostCall([&]() { executeCommands(); });
|
||||
|
||||
constexpr int kSrcTexWidth = 1024;
|
||||
constexpr int kSrcTexHeight = 1024;
|
||||
@@ -614,15 +640,14 @@ TEST_F(BackendTest, BlitRegionToSwapChain) {
|
||||
constexpr int kNumLevels = 3;
|
||||
|
||||
// Create a SwapChain and make it current.
|
||||
auto swapChain = cleanup.add(createSwapChain());
|
||||
auto swapChain = createSwapChain();
|
||||
Handle<HwRenderTarget> dstRenderTarget = api.createDefaultRenderTarget();
|
||||
api.makeCurrent(swapChain, swapChain);
|
||||
|
||||
Handle<HwRenderTarget> dstRenderTarget = cleanup.add(api.createDefaultRenderTarget());
|
||||
|
||||
// Create a source texture.
|
||||
Handle<HwTexture> srcTexture = cleanup.add(api.createTexture(
|
||||
Handle<HwTexture> srcTexture = api.createTexture(
|
||||
SamplerType::SAMPLER_2D, kNumLevels, kSrcTexFormat, 1, kSrcTexWidth, kSrcTexHeight, 1,
|
||||
TextureUsage::SAMPLEABLE | TextureUsage::UPLOADABLE | TextureUsage::COLOR_ATTACHMENT));
|
||||
TextureUsage::SAMPLEABLE | TextureUsage::UPLOADABLE | TextureUsage::COLOR_ATTACHMENT);
|
||||
const bool flipY = sBackend == Backend::OPENGL;
|
||||
createBitmap(api, srcTexture, kSrcTexWidth, kSrcTexHeight, 0, float3(0.5, 0, 0), flipY);
|
||||
createBitmap(api, srcTexture, kSrcTexWidth, kSrcTexHeight, 1, float3(0, 0, 0.5), flipY);
|
||||
@@ -630,8 +655,8 @@ TEST_F(BackendTest, BlitRegionToSwapChain) {
|
||||
// Create a RenderTarget for each texture's miplevel.
|
||||
Handle<HwRenderTarget> srcRenderTargets[kNumLevels];
|
||||
for (uint8_t level = 0; level < kNumLevels; level++) {
|
||||
srcRenderTargets[level] = cleanup.add(api.createRenderTarget( TargetBufferFlags::COLOR,
|
||||
kSrcTexWidth >> level, kSrcTexHeight >> level, 1, 0, { srcTexture, level, 0 }, {}, {}));
|
||||
srcRenderTargets[level] = api.createRenderTarget( TargetBufferFlags::COLOR,
|
||||
kSrcTexWidth >> level, kSrcTexHeight >> level, 1, 0, { srcTexture, level, 0 }, {}, {});
|
||||
}
|
||||
|
||||
// Blit one-quarter of src level 1 to dst level 0.
|
||||
@@ -649,23 +674,29 @@ TEST_F(BackendTest, BlitRegionToSwapChain) {
|
||||
.height = kDstTexHeight - 10,
|
||||
};
|
||||
|
||||
{
|
||||
RenderFrame frame(api);
|
||||
api.beginFrame(0, 0, 0);
|
||||
|
||||
api.blitDEPRECATED(TargetBufferFlags::COLOR0, dstRenderTarget,
|
||||
dstRect, srcRenderTargets[srcLevel],
|
||||
srcRect, SamplerMagFilter::LINEAR);
|
||||
api.blitDEPRECATED(TargetBufferFlags::COLOR0, dstRenderTarget,
|
||||
dstRect, srcRenderTargets[srcLevel],
|
||||
srcRect, SamplerMagFilter::LINEAR);
|
||||
|
||||
ScreenshotParams params { kDstTexWidth, kDstTexHeight, "BlitRegionToSwapChain.png" };
|
||||
dumpScreenshot(api, dstRenderTarget, ¶ms);
|
||||
ScreenshotParams params { kDstTexWidth, kDstTexHeight, "BlitRegionToSwapChain.png" };
|
||||
dumpScreenshot(api, dstRenderTarget, ¶ms);
|
||||
|
||||
api.commit(swapChain);
|
||||
}
|
||||
api.commit(swapChain);
|
||||
|
||||
api.endFrame(0);
|
||||
|
||||
// Wait for the ReadPixels result to come back.
|
||||
api.finish();
|
||||
executeCommands();
|
||||
getDriver().purge();
|
||||
|
||||
// Cleanup.
|
||||
api.destroyTexture(srcTexture);
|
||||
api.destroySwapChain(swapChain);
|
||||
for (auto rt : srcRenderTargets) api.destroyRenderTarget(rt);
|
||||
executeCommands();
|
||||
}
|
||||
|
||||
} // namespace test
|
||||
|
||||
@@ -106,13 +106,6 @@ public:
|
||||
/** @return Whether a combination of texture format, pixel format and type is valid. */
|
||||
static bool validatePixelFormatAndType(InternalFormat internalFormat, Format format, Type type) noexcept;
|
||||
|
||||
/** @return the maximum size in texels of a texture of type \p type. At least 2048 for
|
||||
* 2D textures, 256 for 3D textures. */
|
||||
static size_t getMaxTextureSize(Engine& engine, Sampler type) noexcept;
|
||||
|
||||
/** @return the maximum number of layers supported by texture arrays. At least 256. */
|
||||
static size_t getMaxArrayTextureLayers(Engine& engine) noexcept;
|
||||
|
||||
/**
|
||||
* Options for environment prefiltering into reflection map
|
||||
*
|
||||
|
||||
@@ -62,8 +62,6 @@ constexpr std::pair<ChunkType, ChunkType> shaderLanguageToTags(ShaderLanguage co
|
||||
return { MaterialEssl1, DictionaryText };
|
||||
case ShaderLanguage::MSL:
|
||||
return { MaterialMetal, DictionaryText };
|
||||
case ShaderLanguage::WGSL:
|
||||
return { MaterialWgsl, DictionaryText };
|
||||
case ShaderLanguage::SPIRV:
|
||||
return { MaterialSpirv, DictionarySpirv };
|
||||
case ShaderLanguage::METAL_LIBRARY:
|
||||
|
||||
@@ -108,12 +108,4 @@ bool Texture::validatePixelFormatAndType(InternalFormat internalFormat, Format f
|
||||
return FTexture::validatePixelFormatAndType(internalFormat, format, type);
|
||||
}
|
||||
|
||||
size_t Texture::getMaxTextureSize(Engine& engine, Sampler type) noexcept {
|
||||
return FTexture::getMaxTextureSize(downcast(engine), type);
|
||||
|
||||
}
|
||||
size_t Texture::getMaxArrayTextureLayers(Engine& engine) noexcept {
|
||||
return FTexture::getMaxArrayTextureLayers(downcast(engine));
|
||||
}
|
||||
|
||||
} // namespace filament
|
||||
|
||||
@@ -751,8 +751,7 @@ int FEngine::loop() {
|
||||
#endif
|
||||
if (portString != nullptr) {
|
||||
const int port = atoi(portString);
|
||||
debug.server = new matdbg::DebugServer(mBackend, mDriver->getShaderLanguage(),
|
||||
matdbg::DbgShaderModel((uint8_t) mDriver->getShaderModel()), port);
|
||||
debug.server = new matdbg::DebugServer(mBackend, mDriver->getShaderLanguage(), port);
|
||||
|
||||
// Sometimes the server can fail to spin up (e.g. if the above port is already in use).
|
||||
// When this occurs, carry onward, developers can look at civetweb.txt for details.
|
||||
|
||||
@@ -388,13 +388,12 @@ void FMaterial::terminate(FEngine& engine) {
|
||||
<< "destroying material \"" << this->getName().c_str_safe() << "\" but "
|
||||
<< pos->second.size() << " instances still alive.";
|
||||
} else {
|
||||
if (UTILS_UNLIKELY(!pos->second.empty())) {
|
||||
slog.e << "destroying material \"" << this->getName().c_str_safe() << "\" but "
|
||||
<< pos->second.size() << " instances still alive." << io::endl;
|
||||
}
|
||||
utils::slog.e << "destroying material \"" << this->getName().c_str_safe() << "\" but "
|
||||
<< pos->second.size() << " instances still alive.";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#if FILAMENT_ENABLE_MATDBG
|
||||
// Unregister the material with matdbg.
|
||||
matdbg::DebugServer* server = engine.debug.server;
|
||||
|
||||
@@ -154,14 +154,7 @@ public:
|
||||
#if FILAMENT_ENABLE_MATDBG
|
||||
assert_invariant((size_t)variant.key < VARIANT_COUNT);
|
||||
std::unique_lock<utils::Mutex> lock(mActiveProgramsLock);
|
||||
if (getMaterialDomain() == MaterialDomain::SURFACE) {
|
||||
auto vert = Variant::filterVariantVertex(variant);
|
||||
auto frag = Variant::filterVariantFragment(variant);
|
||||
mActivePrograms.set(vert.key);
|
||||
mActivePrograms.set(frag.key);
|
||||
} else {
|
||||
mActivePrograms.set(variant.key);
|
||||
}
|
||||
mActivePrograms.set(variant.key);
|
||||
lock.unlock();
|
||||
|
||||
if (isSharedVariant(variant)) {
|
||||
|
||||
@@ -638,9 +638,6 @@ void FRenderer::renderJob(RootArenaScope& rootArenaScope, FView& view) {
|
||||
if (isRenderingMultiview) {
|
||||
hasPostProcess = false;
|
||||
msaaOptions.enabled = false;
|
||||
|
||||
// Picking is not supported for multiview rendering. Clear any pending picking queries.
|
||||
view.clearPickingQueries();
|
||||
}
|
||||
const uint8_t msaaSampleCount = msaaOptions.enabled ? msaaOptions.sampleCount : 1u;
|
||||
|
||||
|
||||
@@ -164,40 +164,6 @@ Texture* Texture::Builder::build(Engine& engine) {
|
||||
(isProtectedTexturesSupported && useProtectedMemory) || !useProtectedMemory)
|
||||
<< "Texture is PROTECTED but protected textures are not supported";
|
||||
|
||||
size_t const maxTextureDimension = getMaxTextureSize(engine, mImpl->mTarget);
|
||||
size_t const maxTextureDepth = (mImpl->mTarget == Sampler::SAMPLER_2D_ARRAY ||
|
||||
mImpl->mTarget == Sampler::SAMPLER_CUBEMAP_ARRAY)
|
||||
? getMaxArrayTextureLayers(engine)
|
||||
: maxTextureDimension;
|
||||
|
||||
FILAMENT_CHECK_PRECONDITION(
|
||||
mImpl->mWidth <= maxTextureDimension &&
|
||||
mImpl->mHeight <= maxTextureDimension &&
|
||||
mImpl->mDepth <= maxTextureDepth) << "Texture dimensions out of range: "
|
||||
<< "width= " << mImpl->mWidth << " (>" << maxTextureDimension << ")"
|
||||
<<", height= " << mImpl->mHeight << " (>" << maxTextureDimension << ")"
|
||||
<< ", depth= " << mImpl->mDepth << " (>" << maxTextureDepth << ")";
|
||||
|
||||
const auto validateSamplerType = [&engine = downcast(engine)](SamplerType const sampler) -> bool {
|
||||
switch (sampler) {
|
||||
case SamplerType::SAMPLER_2D:
|
||||
case SamplerType::SAMPLER_CUBEMAP:
|
||||
case SamplerType::SAMPLER_EXTERNAL:
|
||||
return true;
|
||||
case SamplerType::SAMPLER_3D:
|
||||
case SamplerType::SAMPLER_2D_ARRAY:
|
||||
return engine.hasFeatureLevel(FeatureLevel::FEATURE_LEVEL_1);
|
||||
case SamplerType::SAMPLER_CUBEMAP_ARRAY:
|
||||
return engine.hasFeatureLevel(FeatureLevel::FEATURE_LEVEL_2);
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
// Validate sampler before any further interaction with it.
|
||||
FILAMENT_CHECK_PRECONDITION(validateSamplerType(mImpl->mTarget))
|
||||
<< "SamplerType " << uint8_t(mImpl->mTarget) << " not support at feature level "
|
||||
<< uint8_t(engine.getActiveFeatureLevel());
|
||||
|
||||
// SAMPLER_EXTERNAL implies imported.
|
||||
if (mImpl->mTarget == SamplerType::SAMPLER_EXTERNAL) {
|
||||
mImpl->mExternal = true;
|
||||
@@ -250,6 +216,24 @@ Texture* Texture::Builder::build(Engine& engine) {
|
||||
FILAMENT_CHECK_PRECONDITION(!swizzled) << "WebGL does not support texture swizzling.";
|
||||
#endif
|
||||
|
||||
auto validateSamplerType = [&engine = downcast(engine)](SamplerType const sampler) -> bool {
|
||||
switch (sampler) {
|
||||
case SamplerType::SAMPLER_2D:
|
||||
case SamplerType::SAMPLER_CUBEMAP:
|
||||
case SamplerType::SAMPLER_EXTERNAL:
|
||||
return true;
|
||||
case SamplerType::SAMPLER_3D:
|
||||
case SamplerType::SAMPLER_2D_ARRAY:
|
||||
return engine.hasFeatureLevel(FeatureLevel::FEATURE_LEVEL_1);
|
||||
case SamplerType::SAMPLER_CUBEMAP_ARRAY:
|
||||
return engine.hasFeatureLevel(FeatureLevel::FEATURE_LEVEL_2);
|
||||
}
|
||||
};
|
||||
|
||||
FILAMENT_CHECK_PRECONDITION(validateSamplerType(mImpl->mTarget))
|
||||
<< "SamplerType " << uint8_t(mImpl->mTarget) << " not support at feature level "
|
||||
<< uint8_t(engine.getActiveFeatureLevel());
|
||||
|
||||
FILAMENT_CHECK_PRECONDITION((swizzled && sampleable) || !swizzled)
|
||||
<< "Swizzled texture must be SAMPLEABLE";
|
||||
|
||||
@@ -686,14 +670,6 @@ bool FTexture::isTextureSwizzleSupported(FEngine& engine) noexcept {
|
||||
return engine.getDriverApi().isTextureSwizzleSupported();
|
||||
}
|
||||
|
||||
size_t FTexture::getMaxTextureSize(FEngine& engine, Sampler type) noexcept {
|
||||
return engine.getDriverApi().getMaxTextureSize(type);
|
||||
}
|
||||
|
||||
size_t FTexture::getMaxArrayTextureLayers(FEngine& engine) noexcept {
|
||||
return engine.getDriverApi().getMaxArrayTextureLayers();
|
||||
}
|
||||
|
||||
size_t FTexture::computeTextureDataSize(Format const format, Type const type,
|
||||
size_t const stride, size_t const height, size_t const alignment) noexcept {
|
||||
return PixelBufferDescriptor::computeDataSize(format, type, stride, height, alignment);
|
||||
|
||||
@@ -124,10 +124,6 @@ public:
|
||||
static bool validatePixelFormatAndType(backend::TextureFormat internalFormat,
|
||||
backend::PixelDataFormat format, backend::PixelDataType type) noexcept;
|
||||
|
||||
static size_t getMaxTextureSize(FEngine& engine, Sampler type) noexcept;
|
||||
|
||||
static size_t getMaxArrayTextureLayers(FEngine& engine) noexcept;
|
||||
|
||||
bool textureHandleCanMutate() const noexcept;
|
||||
void updateLodRange(uint8_t level) noexcept;
|
||||
|
||||
|
||||
@@ -137,7 +137,12 @@ FView::~FView() noexcept = default;
|
||||
void FView::terminate(FEngine& engine) {
|
||||
// Here we would cleanly free resources we've allocated, or we own (currently none).
|
||||
|
||||
clearPickingQueries();
|
||||
while (mActivePickingQueriesList) {
|
||||
FPickingQuery* const pQuery = mActivePickingQueriesList;
|
||||
mActivePickingQueriesList = pQuery->next;
|
||||
pQuery->callback(pQuery->result, pQuery);
|
||||
FPickingQuery::put(pQuery);
|
||||
}
|
||||
|
||||
DriverApi& driver = engine.getDriverApi();
|
||||
driver.destroyBufferObject(mLightUbh);
|
||||
@@ -1173,15 +1178,6 @@ void FView::executePickingQueries(DriverApi& driver,
|
||||
}
|
||||
}
|
||||
|
||||
void FView::clearPickingQueries() noexcept {
|
||||
while (mActivePickingQueriesList) {
|
||||
FPickingQuery* const pQuery = mActivePickingQueriesList;
|
||||
mActivePickingQueriesList = pQuery->next;
|
||||
pQuery->callback(pQuery->result, pQuery);
|
||||
FPickingQuery::put(pQuery);
|
||||
}
|
||||
}
|
||||
|
||||
void FView::setTemporalAntiAliasingOptions(TemporalAntiAliasingOptions options) noexcept {
|
||||
options.feedback = clamp(options.feedback, 0.0f, 1.0f);
|
||||
options.filterWidth = std::max(0.2f, options.filterWidth); // below 0.2 causes issues
|
||||
|
||||
@@ -463,8 +463,6 @@ public:
|
||||
void executePickingQueries(backend::DriverApi& driver,
|
||||
backend::RenderTargetHandle handle, math::float2 scale) noexcept;
|
||||
|
||||
void clearPickingQueries() noexcept;
|
||||
|
||||
void setMaterialGlobal(uint32_t index, math::float4 const& value);
|
||||
|
||||
math::float4 getMaterialGlobal(uint32_t index) const;
|
||||
|
||||
@@ -78,10 +78,6 @@ fragment {
|
||||
void dummy(){}
|
||||
|
||||
vec4 resolveFragment() {
|
||||
#ifdef TARGET_WEBGPU_ENVIRONMENT
|
||||
//WebGPU Can not handle subpasses.
|
||||
return vec4(0,0,0,1);
|
||||
#else
|
||||
#if POST_PROCESS_OPAQUE
|
||||
return vec4(subpassLoad(materialParams_colorBuffer).rgb, 1.0);
|
||||
#else
|
||||
@@ -89,7 +85,6 @@ vec4 resolveFragment() {
|
||||
color.rgb *= 1.0 / (color.a + FLT_EPS);
|
||||
return color;
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
void postProcess(inout PostProcessInputs postProcess) {
|
||||
|
||||
@@ -39,16 +39,11 @@ fragment {
|
||||
void dummy(){}
|
||||
|
||||
vec4 resolveFragment() {
|
||||
#ifdef TARGET_WEBGPU_ENVIRONMENT
|
||||
//WebGPU Can not handle subpasses.
|
||||
return vec4(0,0,0,1);
|
||||
#else
|
||||
#if POST_PROCESS_OPAQUE
|
||||
return vec4(subpassLoad(materialParams_colorBuffer).rgb, 1.0);
|
||||
#else
|
||||
return subpassLoad(materialParams_colorBuffer);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
void postProcess(inout PostProcessInputs postProcess) {
|
||||
|
||||
@@ -52,10 +52,6 @@ include_directories(${PUBLIC_HDR_DIR})
|
||||
# we're building a library
|
||||
add_library(${TARGET} STATIC ${PUBLIC_HDRS} ${SRCS})
|
||||
|
||||
if(FILAMENT_SUPPORTS_OSMESA)
|
||||
target_compile_options(${TARGET} PRIVATE -I${FILAMENT_OSMESA_PATH}/include/GL)
|
||||
endif()
|
||||
|
||||
# specify where the public headers of this library are
|
||||
target_include_directories(${TARGET} PUBLIC ${PUBLIC_HDR_DIR})
|
||||
set_target_properties(${TARGET} PROPERTIES FOLDER Libs)
|
||||
|
||||
@@ -14,21 +14,16 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <GL/gl.h>
|
||||
#include <dlfcn.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <osmesa.h>
|
||||
|
||||
namespace bluegl {
|
||||
|
||||
namespace {
|
||||
using ProcAddressFunc = void*(*)(char const* funcName);
|
||||
}
|
||||
|
||||
// This is to ensure that linking during compilation will not fail even if
|
||||
// OSMesaGetProcAddress is not linked.
|
||||
__attribute__((weak)) OSMESAproc OSMesaGetProcAddress(char const*);
|
||||
|
||||
struct Driver {
|
||||
ProcAddressFunc OSMesaGetProcAddress;
|
||||
void* library;
|
||||
@@ -36,7 +31,7 @@ struct Driver {
|
||||
|
||||
bool initBinder() {
|
||||
constexpr char const* libraryNames[] = {"libOSMesa.so", "libosmesa.so"};
|
||||
for (char const* name: libraryNames) {
|
||||
for (char const* name : libraryNames) {
|
||||
g_driver.library = dlopen(name, RTLD_GLOBAL | RTLD_NOW);
|
||||
if (g_driver.library) {
|
||||
break;
|
||||
@@ -50,10 +45,6 @@ bool initBinder() {
|
||||
(ProcAddressFunc) dlsym(g_driver.library, "OSMesaGetProcAddress");
|
||||
}
|
||||
|
||||
if (!g_driver.OSMesaGetProcAddress) {
|
||||
g_driver.OSMesaGetProcAddress = (ProcAddressFunc) OSMesaGetProcAddress;
|
||||
}
|
||||
|
||||
return g_driver.OSMesaGetProcAddress;
|
||||
}
|
||||
|
||||
|
||||
@@ -26,47 +26,16 @@ set(SRCS
|
||||
src/JsonWriter.cpp
|
||||
)
|
||||
|
||||
# ==================================================================================================
|
||||
# Resources
|
||||
# ==================================================================================================
|
||||
|
||||
set(RESOURCE_DIR ${CMAKE_CURRENT_BINARY_DIR})
|
||||
|
||||
set(RESOURCE_BINS
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/web/api.js
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/web/app.js
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/web/index.html
|
||||
)
|
||||
|
||||
get_resgen_vars(${RESOURCE_DIR} fgviewer_resources)
|
||||
|
||||
add_custom_command(
|
||||
OUTPUT ${RESGEN_OUTPUTS}
|
||||
COMMAND resgen -t ${RESGEN_FLAGS} ${RESOURCE_BINS}
|
||||
DEPENDS resgen ${RESOURCE_BINS}
|
||||
)
|
||||
|
||||
if (DEFINED RESGEN_SOURCE_FLAGS)
|
||||
set_source_files_properties(${RESGEN_SOURCE} PROPERTIES COMPILE_FLAGS ${RESGEN_SOURCE_FLAGS})
|
||||
endif()
|
||||
|
||||
set(DUMMY_SRC "${RESOURCE_DIR}/dummy.c")
|
||||
add_custom_command(OUTPUT ${DUMMY_SRC} COMMAND echo "//" > ${DUMMY_SRC})
|
||||
|
||||
add_library(fgviewer_resources ${DUMMY_SRC} ${RESGEN_SOURCE})
|
||||
set_target_properties(fgviewer_resources PROPERTIES FOLDER Libs)
|
||||
|
||||
# ==================================================================================================
|
||||
# Include and target definitions
|
||||
# ==================================================================================================
|
||||
|
||||
include_directories(${PUBLIC_HDR_DIR} ${RESOURCE_DIR})
|
||||
include_directories(${PUBLIC_HDR_DIR})
|
||||
|
||||
add_library(${TARGET} STATIC ${PUBLIC_HDRS} ${SRCS})
|
||||
|
||||
target_link_libraries(${TARGET} PUBLIC
|
||||
civetweb
|
||||
fgviewer_resources
|
||||
utils
|
||||
)
|
||||
|
||||
@@ -88,12 +57,11 @@ endif()
|
||||
# Installation
|
||||
# ==================================================================================================
|
||||
|
||||
# fgviewer has dependencies on non-installed libraries. Here we bundle them all together into a single
|
||||
# matdbg has dependencies on non-installed libraries. Here we bundle them all together into a single
|
||||
# library that gets copied into the installation folder so users are only required to link against
|
||||
# fgviewer.
|
||||
# matdbg.
|
||||
set(FGVIEWER_DEPS
|
||||
fgviewer
|
||||
fgviewer_resources
|
||||
civetweb
|
||||
)
|
||||
|
||||
|
||||
@@ -30,26 +30,9 @@
|
||||
|
||||
namespace filament::fgviewer {
|
||||
|
||||
// If set to 0, this serves HTML from a resgen resource. Use 1 only during local development, which
|
||||
// serves files directly from the source code tree.
|
||||
#define SERVE_FROM_SOURCE_TREE 0
|
||||
|
||||
#if SERVE_FROM_SOURCE_TREE
|
||||
namespace {
|
||||
std::string const BASE_URL = "libs/fgviewer/web";
|
||||
} // anonymous
|
||||
#else
|
||||
#include "fgviewer_resources.h"
|
||||
#include <unordered_map>
|
||||
|
||||
namespace {
|
||||
struct Asset {
|
||||
std::string_view mime;
|
||||
std::string_view data;
|
||||
};
|
||||
std::unordered_map<std::string_view, Asset> ASSET_MAP;
|
||||
} // anonymous
|
||||
#endif // SERVE_FROM_SOURCE_TREE
|
||||
|
||||
using namespace utils;
|
||||
|
||||
@@ -73,21 +56,10 @@ public:
|
||||
uri = "/index.html";
|
||||
}
|
||||
|
||||
#if SERVE_FROM_SOURCE_TREE
|
||||
if (uri == "/index.html" || uri == "/app.js" || uri == "/api.js") {
|
||||
mg_send_file(conn, (BASE_URL + uri).c_str());
|
||||
return true;
|
||||
}
|
||||
#else
|
||||
auto const& asset_itr = ASSET_MAP.find(uri);
|
||||
if (asset_itr != ASSET_MAP.end()) {
|
||||
auto const& mime = asset_itr->second.mime;
|
||||
auto const& data = asset_itr->second.data;
|
||||
mg_printf(conn, kSuccessHeader.data(), mime.data());
|
||||
mg_write(conn, data.data(), data.size());
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
slog.e << "[fgviewer] DebugServer: bad request at line " << __LINE__ << ": " << uri << io::endl;
|
||||
return false;
|
||||
}
|
||||
@@ -96,21 +68,6 @@ private:
|
||||
};
|
||||
|
||||
DebugServer::DebugServer(int port) {
|
||||
#if !SERVE_FROM_SOURCE_TREE
|
||||
ASSET_MAP["/index.html"] = {
|
||||
.mime = "text/html",
|
||||
.data = {(char const*) FGVIEWER_RESOURCES_INDEX_DATA},
|
||||
};
|
||||
ASSET_MAP["/app.js"] = {
|
||||
.mime = "text/javascript",
|
||||
.data = {(char const*) FGVIEWER_RESOURCES_APP_DATA},
|
||||
};
|
||||
ASSET_MAP["/api.js"] = {
|
||||
.mime = "text/javascript",
|
||||
.data = {(char const*) FGVIEWER_RESOURCES_API_DATA},
|
||||
};
|
||||
#endif
|
||||
|
||||
// By default the server spawns 50 threads so we override this to 10. According to the civetweb
|
||||
// documentation, "it is recommended to use num_threads of at least 5, since browsers often
|
||||
/// establish multiple connections to load a single web page, including all linked documents
|
||||
|
||||
+29
-45
@@ -16,7 +16,7 @@
|
||||
|
||||
import {LitElement, html, css, unsafeCSS, nothing} from "https://unpkg.com/lit@2.8.0?module";
|
||||
|
||||
const kUntitledPlaceholder = "Untitled View";
|
||||
const kUntitledPlaceholder = "untitled";
|
||||
|
||||
// CSS constants
|
||||
const FOREGROUND_COLOR = '#fafafa';
|
||||
@@ -293,6 +293,11 @@ class FrameGraphTable extends LitElement {
|
||||
margin-right: 5px;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.hidden {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.scrollable-table td,
|
||||
.scrollable-table th {
|
||||
padding: 12px;
|
||||
@@ -346,7 +351,6 @@ class FrameGraphTable extends LitElement {
|
||||
super();
|
||||
this.frameGraphData = null;
|
||||
this.selectedResourceId = -1;
|
||||
this.expandedResourceSet = new Set();
|
||||
}
|
||||
|
||||
updated(props) {
|
||||
@@ -365,13 +369,11 @@ class FrameGraphTable extends LitElement {
|
||||
}
|
||||
|
||||
_toggleCollapse(resourceIndex) {
|
||||
if (this.expandedResourceSet.has(resourceIndex)) {
|
||||
this.expandedResourceSet.delete(resourceIndex);
|
||||
}
|
||||
else {
|
||||
this.expandedResourceSet.add(resourceIndex);
|
||||
}
|
||||
this.requestUpdate();
|
||||
const subresourceRows = this.shadowRoot.querySelectorAll(`[id^="subresource-${resourceIndex}-"]`);
|
||||
const icon = this.shadowRoot.querySelector(`#resource-${resourceIndex} .toggle-icon`);
|
||||
const isHidden = subresourceRows[0]?.classList.contains('hidden');
|
||||
subresourceRows.forEach(row => row.classList.toggle('hidden'));
|
||||
icon.textContent = isHidden ? '▼' : '▶';
|
||||
}
|
||||
|
||||
_handleResourceClick(ev) {
|
||||
@@ -382,16 +384,13 @@ class FrameGraphTable extends LitElement {
|
||||
}));
|
||||
}
|
||||
|
||||
_renderResourceUsage(allPasses, resourceIds, defaultColor) {
|
||||
_renderResourceUsage(allPasses, resourceId, defaultColor) {
|
||||
return allPasses.map((passData, index) => {
|
||||
const isRead = resourceIds.some(resourceId => passData?.reads.includes(resourceId));
|
||||
const isWrite = resourceIds.some(resourceId => passData?.writes.includes(resourceId));
|
||||
const isRead = passData?.reads.includes(resourceId);
|
||||
const isWrite = passData?.writes.includes(resourceId);
|
||||
let type = null;
|
||||
|
||||
const hasUsed = (passData) => {
|
||||
return resourceIds.some(resourceId =>
|
||||
passData?.reads.includes(resourceId) || passData?.writes.includes(resourceId)
|
||||
);
|
||||
return passData?.reads.includes(resourceId) || passData?.writes.includes(resourceId);
|
||||
};
|
||||
const hasBeenUsedBefore = allPasses.slice(0, index).some(hasUsed);
|
||||
const willBeUsedLater = allPasses.slice(index + 1).some(hasUsed);
|
||||
@@ -400,7 +399,6 @@ class FrameGraphTable extends LitElement {
|
||||
else if (isRead) type = RESOURCE_USAGE_TYPE_READ;
|
||||
else if (isWrite) type = RESOURCE_USAGE_TYPE_WRITE;
|
||||
else if (hasBeenUsedBefore && willBeUsedLater) type = RESOURCE_USAGE_TYPE_NO_ACCESS;
|
||||
|
||||
return html`
|
||||
<td style="background-color: ${unsafeCSS(this._getCellColor(type, defaultColor))};">
|
||||
${type ?? nothing}
|
||||
@@ -425,38 +423,24 @@ class FrameGraphTable extends LitElement {
|
||||
}
|
||||
|
||||
_renderResourceRow(resource, resourceIndex, resources, allPasses) {
|
||||
const subresourceIds = resources
|
||||
.filter(subresource => this._isSubresourceOfParent(subresource, resource))
|
||||
.map(subresource => subresource.id);
|
||||
|
||||
const hasSubresources = subresourceIds.length > 0;
|
||||
const isExpanded = this.expandedResourceSet.has(resourceIndex);
|
||||
// Show the aggregated resource usage when the subresources are collapsed.
|
||||
const resourceIds = isExpanded ? [resource.id]:[resource.id, ...subresourceIds];
|
||||
|
||||
const hasSubresources = resources.some(subresource => this._isSubresourceOfParent(subresource, resource));
|
||||
const onClickResource = () => this._handleResourceClick(resource.id);
|
||||
const selectedStyle = resource.id === this.selectedResourceId ? "selected" : "";
|
||||
|
||||
return html`
|
||||
<tr id="resource-${resourceIndex}">
|
||||
<th class="sticky-col resource ${selectedStyle}" @click="${onClickResource}">
|
||||
${hasSubresources
|
||||
? html`
|
||||
<span class="toggle-icon"
|
||||
@click="${(e) => { e.stopPropagation(); this._toggleCollapse(resourceIndex); }}">
|
||||
${isExpanded ? '▼' : '▶'}
|
||||
</span>`
|
||||
: nothing}
|
||||
${resource.name}
|
||||
${hasSubresources && isExpanded ? nothing : html`(${subresourceIds.length})`}
|
||||
</th>
|
||||
${this._renderResourceUsage(allPasses, resourceIds, DEFAULT_COLOR)}
|
||||
</tr>
|
||||
${isExpanded ? this._renderSubresourceRows(resources, resource, resourceIndex, allPasses) : nothing}
|
||||
`;
|
||||
<tr id="resource-${resourceIndex}">
|
||||
<th class="sticky-col resource ${selectedStyle}" @click="${onClickResource}">
|
||||
${hasSubresources ? html`
|
||||
<span class="toggle-icon"
|
||||
@click="${() => this._toggleCollapse(resourceIndex)}">▶</span>` : nothing}
|
||||
${resource.name}
|
||||
</th>
|
||||
${this._renderResourceUsage(allPasses, resource.id, DEFAULT_COLOR)}
|
||||
</tr>
|
||||
${this._renderSubresourceRows(resources, resource, resourceIndex, allPasses)}
|
||||
`;
|
||||
}
|
||||
|
||||
|
||||
_renderSubresourceRows(resources, parentResource, resourceIndex, allPasses) {
|
||||
return resources
|
||||
.filter(subresource => this._isSubresourceOfParent(subresource, parentResource))
|
||||
@@ -468,13 +452,13 @@ class FrameGraphTable extends LitElement {
|
||||
const selectedStyle = subresource.id === this.selectedResourceId ? "selected" : "";
|
||||
|
||||
return html`
|
||||
<tr id="subresource-${resourceIndex}-${subIndex}" class="collapsible">
|
||||
<tr id="subresource-${resourceIndex}-${subIndex}" class="collapsible hidden">
|
||||
<td class="sticky-col resource ${selectedStyle}"
|
||||
@click="${onClickResource}"
|
||||
style="background-color: ${SUBRESOURCE_COLOR}">
|
||||
${subresource.name}
|
||||
</td>
|
||||
${this._renderResourceUsage(allPasses, [subresource.id], SUBRESOURCE_COLOR)}
|
||||
${this._renderResourceUsage(allPasses, subresource.id, SUBRESOURCE_COLOR)}
|
||||
</tr>
|
||||
`;
|
||||
}
|
||||
|
||||
@@ -45,7 +45,6 @@ enum UTILS_PUBLIC ChunkType : uint64_t {
|
||||
MaterialEssl1 = charTo64bitNum("MAT_ESS1"),
|
||||
MaterialSpirv = charTo64bitNum("MAT_SPIR"),
|
||||
MaterialMetal = charTo64bitNum("MAT_METL"),
|
||||
MaterialWgsl = charTo64bitNum("MAT_WGSL"),
|
||||
MaterialMetalLibrary = charTo64bitNum("MAT_MLIB"),
|
||||
MaterialShaderModels = charTo64bitNum("MAT_SMDL"),
|
||||
MaterialBindingUniformInfo = charTo64bitNum("MAT_UFRM"),
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
namespace filament {
|
||||
|
||||
// update this when a new version of filament wouldn't work with older materials
|
||||
static constexpr size_t MATERIAL_VERSION = 57;
|
||||
static constexpr size_t MATERIAL_VERSION = 58;
|
||||
|
||||
/**
|
||||
* Supported shading models
|
||||
|
||||
@@ -183,7 +183,6 @@ bool MaterialChunk::getShader(ShaderContent& shaderContent, BlobDictionary const
|
||||
switch (mMaterialTag) {
|
||||
case filamat::ChunkType::MaterialGlsl:
|
||||
case filamat::ChunkType::MaterialEssl1:
|
||||
case filamat::ChunkType::MaterialWgsl:
|
||||
case filamat::ChunkType::MaterialMetal:
|
||||
return getTextShader(mUnflattener, dictionary, shaderContent, shaderModel, variant, stage);
|
||||
case filamat::ChunkType::MaterialSpirv:
|
||||
|
||||
@@ -85,10 +85,6 @@ target_include_directories(${TARGET} PUBLIC ${PUBLIC_HDR_DIR})
|
||||
set_target_properties(${TARGET} PROPERTIES FOLDER Libs)
|
||||
target_link_libraries(${TARGET} backend_headers shaders filabridge utils smol-v)
|
||||
|
||||
if (FILAMENT_SUPPORTS_WEBGPU)
|
||||
target_link_libraries(${TARGET} libtint)
|
||||
endif ()
|
||||
|
||||
# We are being naughty and accessing private headers here
|
||||
# For spirv-tools, we're just following glslang's example
|
||||
target_include_directories(${TARGET} PRIVATE ${spirv-tools_SOURCE_DIR}/include)
|
||||
@@ -144,12 +140,6 @@ set(FILAMAT_LIB_NAME ${CMAKE_STATIC_LIBRARY_PREFIX}filamat${CMAKE_STATIC_LIBRARY
|
||||
install(FILES "${FILAMAT_COMBINED_OUTPUT}" DESTINATION lib/${DIST_DIR} RENAME ${FILAMAT_LIB_NAME})
|
||||
install(DIRECTORY ${PUBLIC_HDR_DIR}/filamat DESTINATION include)
|
||||
|
||||
# Need to install libtint for filamat on Android.
|
||||
# See libs/filamat/CMakeLists.txt and android/filamat-android/CMakeLists.txt.
|
||||
if (ANDROID)
|
||||
target_link_libraries(${TARGET} libtint_combined)
|
||||
endif()
|
||||
|
||||
# ==================================================================================================
|
||||
# Tests
|
||||
# ==================================================================================================
|
||||
|
||||
@@ -81,11 +81,7 @@ public:
|
||||
VULKAN = 0x02u,
|
||||
METAL = 0x04u,
|
||||
WEBGPU = 0x08u,
|
||||
#ifdef FILAMENT_SUPPORTS_WEBGPU
|
||||
ALL = OPENGL | VULKAN | METAL | WEBGPU
|
||||
#else
|
||||
ALL = OPENGL | VULKAN | METAL
|
||||
#endif
|
||||
};
|
||||
|
||||
/*
|
||||
|
||||
@@ -44,10 +44,6 @@
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
#ifdef FILAMENT_SUPPORTS_WEBGPU
|
||||
#include <tint/tint.h>
|
||||
#endif
|
||||
|
||||
using namespace glslang;
|
||||
using namespace spirv_cross;
|
||||
using namespace spvtools;
|
||||
@@ -518,50 +514,8 @@ void GLSLPostProcessor::spirvToMsl(const SpirvBlob* spirv, std::string* outMsl,
|
||||
}
|
||||
}
|
||||
|
||||
bool GLSLPostProcessor::spirvToWgsl(SpirvBlob *spirv, std::string *outWsl) {
|
||||
#if FILAMENT_SUPPORTS_WEBGPU
|
||||
// We need to remove dead code for our variant-filter workaround for WebGPU to work
|
||||
// This is especially relevant for removing the push constants that morphing uses when not disabled
|
||||
spv::spirvbin_t remapper(0);
|
||||
remapper.remap(*spirv, spv::spirvbin_base_t::DCE_ALL);
|
||||
|
||||
//Currently no options we want to use
|
||||
const tint::spirv::reader::Options readerOpts{};
|
||||
tint::wgsl::writer::Options writerOpts{};
|
||||
|
||||
tint::Program tintRead = tint::spirv::reader::Read(*spirv, readerOpts);
|
||||
|
||||
if (tintRead.Diagnostics().ContainsErrors()) {
|
||||
//TODO remove this if block once combined image sampler conversion works.
|
||||
if (tintRead.Diagnostics().Str().rfind("error: WGSL does not support combined image-samplers") != std::string::npos) {
|
||||
slog.w << "This tint reader error is currently ignored during WebGPU bringup: " << tintRead.Diagnostics().Str() << io::endl;
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
slog.e << "Tint Reader Error: " << tintRead.Diagnostics().Str() << io::endl;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
tint::Result<tint::wgsl::writer::Output> wgslOut = tint::wgsl::writer::Generate(tintRead,writerOpts);
|
||||
/// An instance of SuccessType that can be used to check a tint Result.
|
||||
tint::SuccessType tintSuccess;
|
||||
|
||||
if (wgslOut != tintSuccess) {
|
||||
slog.e << "Tint writer error: " << wgslOut.Failure().reason.Str() << io::endl;
|
||||
return false;
|
||||
}
|
||||
*outWsl = wgslOut->wgsl;
|
||||
return true;
|
||||
#else
|
||||
slog.i << "Trying to emit WGSL without including WebGPU dependencies, please set CMake arg FILAMENT_SUPPORTS_WEBGPU and FILAMENT_SUPPORTS_WEBGPU" << io::endl;
|
||||
return false;
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
bool GLSLPostProcessor::process(const std::string& inputShader, Config const& config,
|
||||
std::string* outputGlsl, SpirvBlob* outputSpirv, std::string* outputMsl, std::string* outputWgsl) {
|
||||
std::string* outputGlsl, SpirvBlob* outputSpirv, std::string* outputMsl) {
|
||||
using TargetLanguage = MaterialBuilder::TargetLanguage;
|
||||
|
||||
if (config.targetLanguage == TargetLanguage::GLSL) {
|
||||
@@ -576,7 +530,6 @@ bool GLSLPostProcessor::process(const std::string& inputShader, Config const& co
|
||||
.glslOutput = outputGlsl,
|
||||
.spirvOutput = outputSpirv,
|
||||
.mslOutput = outputMsl,
|
||||
.wgslOutput = outputWgsl,
|
||||
};
|
||||
|
||||
switch (config.shaderType) {
|
||||
@@ -657,20 +610,13 @@ bool GLSLPostProcessor::process(const std::string& inputShader, Config const& co
|
||||
config.shaderType, config.shaderModel, config.hasFramebufferFetch, descriptors,
|
||||
mGenerateDebugInfo ? &internalConfig.minifier : nullptr);
|
||||
}
|
||||
if (internalConfig.wgslOutput) {
|
||||
if (!spirvToWgsl(internalConfig.spirvOutput, internalConfig.wgslOutput)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
slog.e << "GLSL post-processor invoked with optimization level NONE"
|
||||
<< io::endl;
|
||||
}
|
||||
break;
|
||||
case MaterialBuilder::Optimization::PREPROCESSOR:
|
||||
if (!preprocessOptimization(tShader, config, internalConfig)) {
|
||||
return false;
|
||||
}
|
||||
preprocessOptimization(tShader, config, internalConfig);
|
||||
break;
|
||||
case MaterialBuilder::Optimization::SIZE:
|
||||
case MaterialBuilder::Optimization::PERFORMANCE:
|
||||
@@ -700,7 +646,7 @@ bool GLSLPostProcessor::process(const std::string& inputShader, Config const& co
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GLSLPostProcessor::preprocessOptimization(glslang::TShader& tShader,
|
||||
void GLSLPostProcessor::preprocessOptimization(glslang::TShader& tShader,
|
||||
GLSLPostProcessor::Config const& config, InternalConfig& internalConfig) const {
|
||||
using TargetApi = MaterialBuilder::TargetApi;
|
||||
assert_invariant(bool(internalConfig.spirvOutput) == (config.targetApi != TargetApi::OPENGL));
|
||||
@@ -716,7 +662,6 @@ bool GLSLPostProcessor::preprocessOptimization(glslang::TShader& tShader,
|
||||
|
||||
if (!ok) {
|
||||
slog.e << tShader.getInfoLog() << io::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (internalConfig.spirvOutput) {
|
||||
@@ -738,7 +683,6 @@ bool GLSLPostProcessor::preprocessOptimization(glslang::TShader& tShader,
|
||||
bool const linkOk = program.link(msg);
|
||||
if (!ok || !linkOk) {
|
||||
slog.e << spirvShader.getInfoLog() << io::endl;
|
||||
return false;
|
||||
} else {
|
||||
SpvOptions options;
|
||||
options.generateDebugInfo = mGenerateDebugInfo;
|
||||
@@ -758,17 +702,10 @@ bool GLSLPostProcessor::preprocessOptimization(glslang::TShader& tShader,
|
||||
config.shaderModel, config.hasFramebufferFetch, descriptors,
|
||||
mGenerateDebugInfo ? &internalConfig.minifier : nullptr);
|
||||
}
|
||||
if (internalConfig.wgslOutput) {
|
||||
if (!spirvToWgsl(internalConfig.spirvOutput, internalConfig.wgslOutput)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (internalConfig.glslOutput) {
|
||||
*internalConfig.glslOutput = glsl;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GLSLPostProcessor::fullOptimization(const TShader& tShader,
|
||||
@@ -809,11 +746,6 @@ bool GLSLPostProcessor::fullOptimization(const TShader& tShader,
|
||||
config.hasFramebufferFetch, descriptors,
|
||||
mGenerateDebugInfo ? &internalConfig.minifier : nullptr);
|
||||
}
|
||||
if (internalConfig.wgslOutput) {
|
||||
if (!spirvToWgsl(&spirv, internalConfig.wgslOutput)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Transpile back to GLSL
|
||||
if (internalConfig.glslOutput) {
|
||||
@@ -920,10 +852,6 @@ std::shared_ptr<spvtools::Optimizer> GLSLPostProcessor::createOptimizer(
|
||||
optimizer->RegisterPass(CreateRedundancyEliminationPass());
|
||||
optimizer->RegisterPass(CreateAggressiveDCEPass());
|
||||
}
|
||||
if (config.targetApi == MaterialBuilder::TargetApi::WEBGPU) {
|
||||
optimizer->RegisterPass(CreateSplitCombinedImageSamplerPass());
|
||||
optimizer->RegisterPass(CreateResolveBindingConflictsPass());
|
||||
}
|
||||
|
||||
return optimizer;
|
||||
}
|
||||
|
||||
@@ -81,8 +81,7 @@ public:
|
||||
bool process(const std::string& inputShader, Config const& config,
|
||||
std::string* outputGlsl,
|
||||
SpirvBlob* outputSpirv,
|
||||
std::string* outputMsl,
|
||||
std::string* outputWgsl);
|
||||
std::string* outputMsl);
|
||||
|
||||
// public so backend_test can also use it
|
||||
static void spirvToMsl(const SpirvBlob* spirv, std::string* outMsl,
|
||||
@@ -90,14 +89,11 @@ public:
|
||||
bool useFramebufferFetch, const DescriptorSets& descriptorSets,
|
||||
const ShaderMinifier* minifier);
|
||||
|
||||
static bool spirvToWgsl(SpirvBlob* spirv, std::string* outWsl);
|
||||
|
||||
private:
|
||||
struct InternalConfig {
|
||||
std::string* glslOutput = nullptr;
|
||||
SpirvBlob* spirvOutput = nullptr;
|
||||
std::string* mslOutput = nullptr;
|
||||
std::string* wgslOutput = nullptr;
|
||||
EShLanguage shLang = EShLangFragment;
|
||||
// use 100 for ES environment, 110 for desktop
|
||||
int langVersion = 0;
|
||||
@@ -107,7 +103,7 @@ private:
|
||||
bool fullOptimization(const glslang::TShader& tShader,
|
||||
GLSLPostProcessor::Config const& config, InternalConfig& internalConfig) const;
|
||||
|
||||
bool preprocessOptimization(glslang::TShader& tShader,
|
||||
void preprocessOptimization(glslang::TShader& tShader,
|
||||
GLSLPostProcessor::Config const& config, InternalConfig& internalConfig) const;
|
||||
|
||||
/**
|
||||
|
||||
@@ -179,14 +179,6 @@ void MaterialBuilderBase::prepare(bool vulkanSemantics,
|
||||
effectiveFeatureLevel,
|
||||
});
|
||||
}
|
||||
if (any(mTargetApi & TargetApi::WEBGPU)) {
|
||||
mCodeGenPermutations.push_back({
|
||||
shaderModel,
|
||||
TargetApi::WEBGPU,
|
||||
TargetLanguage::SPIRV,
|
||||
effectiveFeatureLevel,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -844,7 +836,6 @@ static void showErrorMessage(const char* materialName, filament::Variant variant
|
||||
break;
|
||||
case TargetApi::WEBGPU:
|
||||
targetApiString = "WebGPU.\n";
|
||||
break;
|
||||
case TargetApi::ALL:
|
||||
assert(0); // Unreachable.
|
||||
break;
|
||||
@@ -888,7 +879,6 @@ bool MaterialBuilder::generateShaders(JobSystem& jobSystem, const std::vector<Va
|
||||
std::vector<TextEntry> essl1Entries;
|
||||
std::vector<BinaryEntry> spirvEntries;
|
||||
std::vector<TextEntry> metalEntries;
|
||||
std::vector<TextEntry> wgslEntries;
|
||||
LineDictionary textDictionary;
|
||||
BlobDictionary spirvDictionary;
|
||||
// End: must be protected by lock
|
||||
@@ -917,9 +907,8 @@ bool MaterialBuilder::generateShaders(JobSystem& jobSystem, const std::vector<Va
|
||||
|
||||
// Metal Shading Language is cross-compiled from Vulkan.
|
||||
const bool targetApiNeedsSpirv =
|
||||
(targetApi == TargetApi::VULKAN || targetApi == TargetApi::METAL || targetApi == TargetApi::WEBGPU);
|
||||
(targetApi == TargetApi::VULKAN || targetApi == TargetApi::METAL);
|
||||
const bool targetApiNeedsMsl = targetApi == TargetApi::METAL;
|
||||
const bool targetApiNeedsWgsl = targetApi == TargetApi::WEBGPU;
|
||||
const bool targetApiNeedsGlsl = targetApi == TargetApi::OPENGL;
|
||||
|
||||
// Set when a job fails
|
||||
@@ -934,26 +923,21 @@ bool MaterialBuilder::generateShaders(JobSystem& jobSystem, const std::vector<Va
|
||||
// TODO: avoid allocations when not required
|
||||
std::vector<uint32_t> spirv;
|
||||
std::string msl;
|
||||
std::string wgsl;
|
||||
|
||||
std::vector<uint32_t>* pSpirv = targetApiNeedsSpirv ? &spirv : nullptr;
|
||||
std::string* pMsl = targetApiNeedsMsl ? &msl : nullptr;
|
||||
std::string* pWgsl = targetApiNeedsWgsl ? &wgsl : nullptr;
|
||||
|
||||
TextEntry glslEntry{};
|
||||
BinaryEntry spirvEntry{};
|
||||
TextEntry metalEntry{};
|
||||
TextEntry wgslEntry{};
|
||||
|
||||
glslEntry.shaderModel = params.shaderModel;
|
||||
spirvEntry.shaderModel = params.shaderModel;
|
||||
metalEntry.shaderModel = params.shaderModel;
|
||||
wgslEntry.shaderModel = params.shaderModel;
|
||||
|
||||
glslEntry.variant = v.variant;
|
||||
spirvEntry.variant = v.variant;
|
||||
metalEntry.variant = v.variant;
|
||||
wgslEntry.variant = v.variant;
|
||||
|
||||
// Generate raw shader code.
|
||||
// The quotes in Google-style line directives cause problems with certain drivers. These
|
||||
@@ -1022,7 +1006,7 @@ bool MaterialBuilder::generateShaders(JobSystem& jobSystem, const std::vector<Va
|
||||
config.glsl.subpassInputToColorLocation.emplace_back(0, 0);
|
||||
}
|
||||
|
||||
bool const ok = postProcessor.process(shader, config, pGlsl, pSpirv, pMsl, pWgsl);
|
||||
bool const ok = postProcessor.process(shader, config, pGlsl, pSpirv, pMsl);
|
||||
if (!ok) {
|
||||
showErrorMessage(mMaterialName.c_str_safe(), v.variant, targetApi, v.stage,
|
||||
featureLevel, shader);
|
||||
@@ -1051,12 +1035,6 @@ bool MaterialBuilder::generateShaders(JobSystem& jobSystem, const std::vector<Va
|
||||
switch (targetApi) {
|
||||
// TODO: Handle webgpu here
|
||||
case TargetApi::WEBGPU:
|
||||
assert(!spirv.empty());
|
||||
assert(wgsl.length() > 0);
|
||||
wgslEntry.stage = v.stage;
|
||||
wgslEntry.shader = wgsl;
|
||||
wgslEntries.push_back(wgslEntry);
|
||||
break;
|
||||
case TargetApi::ALL:
|
||||
// should never happen
|
||||
break;
|
||||
@@ -1118,7 +1096,6 @@ bool MaterialBuilder::generateShaders(JobSystem& jobSystem, const std::vector<Va
|
||||
std::sort(essl1Entries.begin(), essl1Entries.end(), compare);
|
||||
std::sort(spirvEntries.begin(), spirvEntries.end(), compare);
|
||||
std::sort(metalEntries.begin(), metalEntries.end(), compare);
|
||||
std::sort(wgslEntries.begin(), wgslEntries.end(), compare);
|
||||
|
||||
// Generate the dictionaries.
|
||||
for (const auto& s : glslEntries) {
|
||||
@@ -1134,9 +1111,6 @@ bool MaterialBuilder::generateShaders(JobSystem& jobSystem, const std::vector<Va
|
||||
for (const auto& s : metalEntries) {
|
||||
textDictionary.addText(s.shader);
|
||||
}
|
||||
for (const auto& s : wgslEntries) {
|
||||
textDictionary.addText(s.shader);
|
||||
}
|
||||
|
||||
// Emit dictionary chunk (TextDictionaryReader and DictionaryTextChunk)
|
||||
const auto& dictionaryChunk = container.push<filamat::DictionaryTextChunk>(
|
||||
@@ -1167,12 +1141,6 @@ bool MaterialBuilder::generateShaders(JobSystem& jobSystem, const std::vector<Va
|
||||
dictionaryChunk.getDictionary(), ChunkType::MaterialMetal);
|
||||
}
|
||||
|
||||
// Emit WGSL chunk (MaterialTextChunk).
|
||||
if (!wgslEntries.empty()) {
|
||||
container.push<MaterialTextChunk>(std::move(wgslEntries),
|
||||
dictionaryChunk.getDictionary(), ChunkType::MaterialWgsl);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -525,11 +525,6 @@ EShMessages GLSLTools::glslangFlagsFromTargetApi(
|
||||
// choke on gl_VertexIndex.
|
||||
msg |= (Type)EShMessages::EShMsgVulkanRules;
|
||||
}
|
||||
if (targetApi == TargetApi::WEBGPU) {
|
||||
// FIXME: We have to use EShMsgVulkanRules for WEBGPU, otherwise compilation will
|
||||
// choke on gl_VertexIndex.
|
||||
msg |= (Type)EShMessages::EShMsgVulkanRules;
|
||||
}
|
||||
return (EShMessages)msg;
|
||||
}
|
||||
}
|
||||
@@ -545,13 +540,13 @@ void GLSLTools::prepareShaderParser(MaterialBuilder::TargetApi targetApi,
|
||||
shader.setEnvInput(EShSourceGlsl, stage, EShClientOpenGL, version);
|
||||
shader.setEnvClient(EShClientOpenGL, EShTargetOpenGL_450);
|
||||
break;
|
||||
case MaterialBuilderBase::TargetApi::WEBGPU:
|
||||
case MaterialBuilderBase::TargetApi::VULKAN:
|
||||
case MaterialBuilderBase::TargetApi::METAL:
|
||||
shader.setEnvInput(EShSourceGlsl, stage, EShClientVulkan, version);
|
||||
shader.setEnvClient(EShClientVulkan, EShTargetVulkan_1_1);
|
||||
break;
|
||||
// TODO: Handle webgpu here
|
||||
case MaterialBuilderBase::TargetApi::WEBGPU:
|
||||
case MaterialBuilderBase::TargetApi::ALL:
|
||||
// can't happen
|
||||
break;
|
||||
|
||||
@@ -175,11 +175,6 @@ utils::io::sstream& CodeGenerator::generateCommonProlog(utils::io::sstream& out,
|
||||
break;
|
||||
// TODO: Handle webgpu here
|
||||
case TargetApi::WEBGPU:
|
||||
//For now, no differences so inherit the same changes.
|
||||
// TODO Define a separte environment, OR relevant checks
|
||||
out << "#define TARGET_VULKAN_ENVIRONMENT\n";
|
||||
out << "#define TARGET_WEBGPU_ENVIRONMENT\n";
|
||||
break;
|
||||
case TargetApi::ALL:
|
||||
// invalid should never happen
|
||||
break;
|
||||
@@ -195,7 +190,6 @@ utils::io::sstream& CodeGenerator::generateCommonProlog(utils::io::sstream& out,
|
||||
}
|
||||
|
||||
if (mTargetApi == TargetApi::VULKAN ||
|
||||
mTargetApi == TargetApi::WEBGPU ||
|
||||
mTargetApi == TargetApi::METAL ||
|
||||
(mTargetApi == TargetApi::OPENGL && mShaderModel == ShaderModel::DESKTOP) ||
|
||||
mFeatureLevel >= FeatureLevel::FEATURE_LEVEL_2) {
|
||||
@@ -303,22 +297,12 @@ utils::io::sstream& CodeGenerator::generateCommonProlog(utils::io::sstream& out,
|
||||
generateSpecializationConstant(out, "BACKEND_FEATURE_LEVEL",
|
||||
+ReservedSpecializationConstants::BACKEND_FEATURE_LEVEL, 1);
|
||||
|
||||
if (mTargetApi == TargetApi::WEBGPU) {
|
||||
// Note: This is a revived hack for a hack.
|
||||
//
|
||||
// WGSL doesn't support specialization constants as an array length
|
||||
// CONFIG_MAX_INSTANCES is only needed for WebGL, so we can replace it with a constant.
|
||||
// More information at https://github.com/gpuweb/gpuweb/issues/572#issuecomment-649760005
|
||||
out << "const int CONFIG_MAX_INSTANCES = " << (int)CONFIG_MAX_INSTANCES << ";\n";
|
||||
out << "const int CONFIG_FROXEL_BUFFER_HEIGHT = 2048;\n";
|
||||
} else {
|
||||
generateSpecializationConstant(out, "CONFIG_MAX_INSTANCES",
|
||||
+ReservedSpecializationConstants::CONFIG_MAX_INSTANCES, (int)CONFIG_MAX_INSTANCES);
|
||||
generateSpecializationConstant(out, "CONFIG_MAX_INSTANCES",
|
||||
+ReservedSpecializationConstants::CONFIG_MAX_INSTANCES, (int)CONFIG_MAX_INSTANCES);
|
||||
|
||||
// the default of 1024 (16KiB) is needed for 32% of Android devices
|
||||
generateSpecializationConstant(out, "CONFIG_FROXEL_BUFFER_HEIGHT",
|
||||
+ReservedSpecializationConstants::CONFIG_FROXEL_BUFFER_HEIGHT, 1024);
|
||||
}
|
||||
// the default of 1024 (16KiB) is needed for 32% of Android devices
|
||||
generateSpecializationConstant(out, "CONFIG_FROXEL_BUFFER_HEIGHT",
|
||||
+ReservedSpecializationConstants::CONFIG_FROXEL_BUFFER_HEIGHT, 1024);
|
||||
|
||||
// directional shadowmap visualization
|
||||
generateSpecializationConstant(out, "CONFIG_DEBUG_DIRECTIONAL_SHADOWMAP",
|
||||
@@ -731,8 +715,6 @@ io::sstream& CodeGenerator::generateBufferInterfaceBlock(io::sstream& out, Shade
|
||||
break;
|
||||
// TODO: Handle webgpu here
|
||||
case TargetApi::WEBGPU:
|
||||
out << "set = " << +set << ", binding = " << +binding << ", ";
|
||||
break;
|
||||
case TargetApi::ALL:
|
||||
// nonsensical, shouldn't happen.
|
||||
break;
|
||||
@@ -821,8 +803,6 @@ io::sstream& CodeGenerator::generateCommonSamplers(utils::io::sstream& out,
|
||||
break;
|
||||
// TODO: Handle webgpu here
|
||||
case TargetApi::WEBGPU:
|
||||
out << "layout(binding = " << +info.binding << ", set = " << +set << ") ";
|
||||
break;
|
||||
case TargetApi::ALL:
|
||||
// should not happen
|
||||
break;
|
||||
|
||||
@@ -796,10 +796,8 @@ std::string ShaderGenerator::createPostProcessFragmentProgram(ShaderModel sm,
|
||||
|
||||
cg.generateCommonSamplers(fs, DescriptorSetBindingPoints::PER_MATERIAL, material.sib);
|
||||
|
||||
// Subpasses are not yet in WebGPU, https://github.com/gpuweb/gpuweb/issues/435
|
||||
CodeGenerator::generatePostProcessSubpass(fs, targetApi == MaterialBuilderBase::TargetApi::WEBGPU
|
||||
? SubpassInfo{}
|
||||
: material.subpass);
|
||||
// subpass
|
||||
CodeGenerator::generatePostProcessSubpass(fs, material.subpass);
|
||||
|
||||
CodeGenerator::generatePostProcessCommon(fs, ShaderStage::FRAGMENT);
|
||||
CodeGenerator::generatePostProcessGetters(fs, ShaderStage::FRAGMENT);
|
||||
|
||||
@@ -891,78 +891,7 @@ TEST_F(MaterialCompiler, FeatureLevel0Ess3CallFails) {
|
||||
EXPECT_FALSE(result.isValid());
|
||||
}
|
||||
|
||||
#if FILAMENT_SUPPORTS_WEBGPU
|
||||
TEST_F(MaterialCompiler, WgslConversionBakedColor) {
|
||||
std::string bakedColorCodeFrag(R"(
|
||||
void material(inout MaterialInputs material) {
|
||||
prepareMaterial(material);
|
||||
material.baseColor = getColor();
|
||||
}
|
||||
)");
|
||||
filamat::MaterialBuilder builder;
|
||||
builder.targetApi(filamat::MaterialBuilderBase::TargetApi::WEBGPU);
|
||||
builder.material(bakedColorCodeFrag.c_str());
|
||||
builder.shading(filamat::MaterialBuilder::Shading::UNLIT);
|
||||
builder.name("BakedColor");
|
||||
builder.culling(CullingMode::NONE);
|
||||
builder.featureLevel(FeatureLevel::FEATURE_LEVEL_0);
|
||||
builder.require(filament::VertexAttribute::COLOR);
|
||||
builder.variantFilter(static_cast<filament::UserVariantFilterMask>(
|
||||
filament::UserVariantFilterBit::SKINNING | filament::UserVariantFilterBit::STE));
|
||||
filamat::Package result = builder.build(*jobSystem);
|
||||
EXPECT_TRUE(result.isValid());
|
||||
}
|
||||
|
||||
TEST_F(MaterialCompiler, WgslConversionSandboxLitTransparent) {
|
||||
std::string litTransparentCodeFrag(R"(
|
||||
void material(inout MaterialInputs material) {
|
||||
prepareMaterial(material);
|
||||
material.baseColor.rgb = materialParams.baseColor * materialParams.alpha;
|
||||
material.baseColor.a = materialParams.alpha;
|
||||
material.roughness = materialParams.roughness;
|
||||
material.metallic = materialParams.metallic;
|
||||
material.reflectance = materialParams.reflectance;
|
||||
material.sheenColor = materialParams.sheenColor;
|
||||
material.sheenRoughness = materialParams.sheenRoughness;
|
||||
material.clearCoat = materialParams.clearCoat;
|
||||
material.clearCoatRoughness = materialParams.clearCoatRoughness;
|
||||
material.anisotropy = materialParams.anisotropy;
|
||||
material.emissive = materialParams.emissive;
|
||||
}
|
||||
)");
|
||||
filamat::MaterialBuilder builder;
|
||||
builder.targetApi(filamat::MaterialBuilderBase::TargetApi::WEBGPU);
|
||||
builder.material(litTransparentCodeFrag.c_str());
|
||||
builder.shading(filamat::MaterialBuilder::Shading::LIT);
|
||||
builder.name("LitTransparent");
|
||||
builder.blending(filament::BlendingMode::TRANSPARENT);
|
||||
builder.specularAntiAliasing(true);
|
||||
|
||||
builder.parameter("alpha", 1, UniformType::FLOAT);
|
||||
builder.parameter("baseColor", 1, UniformType::FLOAT3);
|
||||
builder.parameter("roughness", 1, UniformType::FLOAT);
|
||||
builder.parameter("metallic", 1, UniformType::FLOAT);
|
||||
builder.parameter("reflectance", 1, UniformType::FLOAT);
|
||||
builder.parameter("sheenColor", 1, UniformType::FLOAT3);
|
||||
builder.parameter("sheenRoughness", 1, UniformType::FLOAT);
|
||||
builder.parameter("clearCoat", 1, UniformType::FLOAT);
|
||||
builder.parameter("clearCoatRoughness", 1, UniformType::FLOAT);
|
||||
builder.parameter("anisotropy", 1, UniformType::FLOAT);
|
||||
builder.parameter("emissive", 1, UniformType::FLOAT4);
|
||||
|
||||
builder.variantFilter(static_cast<filament::UserVariantFilterMask>(
|
||||
filament::UserVariantFilterBit::SKINNING | filament::UserVariantFilterBit::STE));
|
||||
filamat::Package result = builder.build(*jobSystem);
|
||||
EXPECT_TRUE(result.isValid());
|
||||
}
|
||||
#endif
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
::testing::InitGoogleTest(&argc, argv);
|
||||
const int rv = RUN_ALL_TESTS();
|
||||
if (testing::UnitTest::GetInstance()->test_to_run_count() == 0) {
|
||||
//If you run a test filter that contains 0 tests that was likely not intentional. Fail in that scenario.
|
||||
return 1;
|
||||
}
|
||||
return rv;
|
||||
return RUN_ALL_TESTS();
|
||||
}
|
||||
|
||||
@@ -41,13 +41,6 @@ struct MaterialRecord {
|
||||
VariantList activeVariants;
|
||||
};
|
||||
|
||||
// Matches DriverEnums' ShaderModel
|
||||
enum class DbgShaderModel {
|
||||
MOBILE = 1, //!< Mobile level functionality
|
||||
DESKTOP = 2, //!< Desktop level functionality
|
||||
MATINFO = 10, //!< To indicate debug server is running from matinfo
|
||||
};
|
||||
|
||||
/**
|
||||
* Server-side material debugger.
|
||||
*
|
||||
@@ -59,8 +52,7 @@ public:
|
||||
static std::string_view const kSuccessHeader;
|
||||
static std::string_view const kErrorHeader;
|
||||
|
||||
DebugServer(backend::Backend backend, backend::ShaderLanguage shaderLanguage,
|
||||
DbgShaderModel perferredShaderModel, int port);
|
||||
DebugServer(backend::Backend backend, backend::ShaderLanguage shaderLanguage, int port);
|
||||
~DebugServer();
|
||||
|
||||
/**
|
||||
@@ -93,13 +85,10 @@ public:
|
||||
bool isReady() const { return mServer; }
|
||||
|
||||
private:
|
||||
// called from ApiHandler
|
||||
MaterialRecord const* getRecord(const MaterialKey& key) const;
|
||||
|
||||
// called from ApiHandler
|
||||
void updateActiveVariants();
|
||||
|
||||
// called from ApiHandler
|
||||
/**
|
||||
* Replaces the entire content of a particular shader variant. The given shader index uses the
|
||||
* same ordering that the variants have within the package.
|
||||
@@ -107,9 +96,8 @@ private:
|
||||
bool handleEditCommand(const MaterialKey& mat, backend::Backend api, int shaderIndex,
|
||||
const char* newShaderContent, size_t newShaderLength);
|
||||
|
||||
backend::Backend const mBackend;
|
||||
backend::ShaderLanguage const mShaderLanguage;
|
||||
DbgShaderModel const mPreferredShaderModel;
|
||||
const backend::Backend mBackend;
|
||||
const backend::ShaderLanguage mShaderLanguage;
|
||||
|
||||
CivetServer* mServer;
|
||||
|
||||
|
||||
@@ -17,8 +17,6 @@
|
||||
#ifndef MATDBG_JSONWRITER_H
|
||||
#define MATDBG_JSONWRITER_H
|
||||
|
||||
#include <matdbg/DebugServer.h>
|
||||
|
||||
#include <filaflat/ChunkContainer.h>
|
||||
|
||||
#include <backend/DriverEnums.h>
|
||||
@@ -49,8 +47,7 @@ public:
|
||||
// shader index is an active variant. Each bit in the activeVariants bitmask
|
||||
// represents one of the possible variant combinations.
|
||||
bool writeActiveInfo(const filaflat::ChunkContainer& package,
|
||||
backend::ShaderLanguage shaderLanguage, DbgShaderModel shaderModel,
|
||||
VariantList activeVariants);
|
||||
backend::ShaderLanguage shaderLanguage, VariantList activeVariants);
|
||||
|
||||
private:
|
||||
utils::CString mJsonString;
|
||||
|
||||
@@ -332,12 +332,11 @@ bool ApiHandler::handleGet(CivetServer* server, struct mg_connection* conn) {
|
||||
return error(__LINE__, uri);
|
||||
}
|
||||
JsonWriter writer;
|
||||
if (!writer.writeActiveInfo(package, mServer->mShaderLanguage,
|
||||
mServer->mPreferredShaderModel, record.activeVariants)) {
|
||||
if (!writer.writeActiveInfo(package, mServer->mShaderLanguage, record.activeVariants)) {
|
||||
return error(__LINE__, uri);
|
||||
}
|
||||
bool const last = (++index) == mServer->mMaterialRecords.size();
|
||||
mg_printf(conn, "\"%8.8x\": %s%s", pair.first, writer.getJsonString(),
|
||||
mg_printf(conn, "\"%8.8x\": %s %s", pair.first, writer.getJsonString(),
|
||||
last ? "" : ",");
|
||||
}
|
||||
mg_printf(conn, "}");
|
||||
@@ -357,18 +356,6 @@ bool ApiHandler::handleGet(CivetServer* server, struct mg_connection* conn) {
|
||||
return true;
|
||||
}
|
||||
|
||||
auto writeMaterialRecord = [&](JsonWriter* writer, MaterialRecord const* record) {
|
||||
ChunkContainer package(record->package, record->packageSize);
|
||||
if (!package.parse()) {
|
||||
return error(__LINE__, uri);
|
||||
}
|
||||
|
||||
if (!writer->writeMaterialInfo(package)) {
|
||||
return error(__LINE__, uri);
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
if (uri == "/api/materials") {
|
||||
std::unique_lock const lock(mServer->mMaterialRecordsMutex);
|
||||
mg_printf(conn, kSuccessHeader.data(), "application/json");
|
||||
@@ -376,11 +363,17 @@ bool ApiHandler::handleGet(CivetServer* server, struct mg_connection* conn) {
|
||||
int index = 0;
|
||||
for (auto const& record: mServer->mMaterialRecords) {
|
||||
bool const last = (++index) == mServer->mMaterialRecords.size();
|
||||
auto const& mat = record.second;
|
||||
JsonWriter writer;
|
||||
if (!writeMaterialRecord(&writer, &mat)) {
|
||||
return false;
|
||||
|
||||
ChunkContainer package(record.second.package, record.second.packageSize);
|
||||
if (!package.parse()) {
|
||||
return error(__LINE__, uri);
|
||||
}
|
||||
|
||||
JsonWriter writer;
|
||||
if (!writer.writeMaterialInfo(package)) {
|
||||
return error(__LINE__, uri);
|
||||
}
|
||||
|
||||
mg_printf(conn, "{ \"matid\": \"%8.8x\", %s } %s", record.first, writer.getJsonString(),
|
||||
last ? "" : ",");
|
||||
}
|
||||
@@ -393,9 +386,15 @@ bool ApiHandler::handleGet(CivetServer* server, struct mg_connection* conn) {
|
||||
if (!result) {
|
||||
return error(__LINE__, uri);
|
||||
}
|
||||
|
||||
ChunkContainer package(result->package, result->packageSize);
|
||||
if (!package.parse()) {
|
||||
return error(__LINE__, uri);
|
||||
}
|
||||
|
||||
JsonWriter writer;
|
||||
if (!writeMaterialRecord(&writer, result)) {
|
||||
return false;
|
||||
if (!writer.writeMaterialInfo(package)) {
|
||||
return error(__LINE__, uri);
|
||||
}
|
||||
mg_printf(conn, kSuccessHeader.data(), "application/json");
|
||||
mg_printf(conn, "{ %s }", writer.getJsonString());
|
||||
|
||||
@@ -122,11 +122,8 @@ private:
|
||||
DebugServer* mServer;
|
||||
};
|
||||
|
||||
DebugServer::DebugServer(Backend backend, ShaderLanguage shaderLanguage,
|
||||
DbgShaderModel perferredShaderModel, int port)
|
||||
: mBackend(backend),
|
||||
mShaderLanguage(shaderLanguage),
|
||||
mPreferredShaderModel(perferredShaderModel) {
|
||||
DebugServer::DebugServer(Backend backend, ShaderLanguage shaderLanguage, int port)
|
||||
: mBackend(backend), mShaderLanguage(shaderLanguage) {
|
||||
|
||||
#if !SERVE_FROM_SOURCE_TREE
|
||||
ASSET_MAP["/index.html"] = {
|
||||
|
||||
@@ -232,7 +232,7 @@ size_t JsonWriter::getJsonSize() const {
|
||||
}
|
||||
|
||||
bool JsonWriter::writeActiveInfo(const filaflat::ChunkContainer& package,
|
||||
ShaderLanguage shaderLanguage, DbgShaderModel shaderModel, VariantList activeVariants) {
|
||||
ShaderLanguage shaderLanguage, VariantList activeVariants) {
|
||||
vector<ShaderInfo> shaders;
|
||||
ostringstream json;
|
||||
json << "[\"";
|
||||
@@ -254,30 +254,13 @@ bool JsonWriter::writeActiveInfo(const filaflat::ChunkContainer& package,
|
||||
json << "metal";
|
||||
chunkType = ChunkType::MaterialMetal;
|
||||
break;
|
||||
case ShaderLanguage::WGSL:
|
||||
json << "webgpu";
|
||||
chunkType = ChunkType::MaterialWgsl;
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
shaders.resize(getShaderCount(package, chunkType));
|
||||
getShaderInfo(package, shaders.data(), chunkType);
|
||||
|
||||
json << "\", \"";
|
||||
switch (shaderModel) {
|
||||
case DbgShaderModel::DESKTOP:
|
||||
json << toString(ShaderModel::DESKTOP);
|
||||
break;
|
||||
case DbgShaderModel::MOBILE:
|
||||
json << toString(ShaderModel::MOBILE);
|
||||
break;
|
||||
case DbgShaderModel::MATINFO:
|
||||
json << "matinfo";
|
||||
break;
|
||||
}
|
||||
json << "\"";
|
||||
|
||||
for (size_t variant = 0; variant < activeVariants.size(); variant++) {
|
||||
if (activeVariants[variant]) {
|
||||
json << ", " << variant;
|
||||
|
||||
@@ -57,10 +57,6 @@ ShaderExtractor::ShaderExtractor(backend::ShaderLanguage target, const void* dat
|
||||
mMaterialTag = ChunkType::MaterialMetalLibrary;
|
||||
mDictionaryTag = ChunkType::DictionaryMetalLibrary;
|
||||
break;
|
||||
case backend::ShaderLanguage::WGSL:
|
||||
mMaterialTag = ChunkType::MaterialWgsl;
|
||||
mDictionaryTag = ChunkType::DictionaryText;
|
||||
break;
|
||||
case backend::ShaderLanguage::SPIRV:
|
||||
mMaterialTag = ChunkType::MaterialSpirv;
|
||||
mDictionaryTag = ChunkType::DictionarySpirv;
|
||||
|
||||
@@ -16,8 +16,6 @@
|
||||
|
||||
#include <matdbg/ShaderInfo.h>
|
||||
|
||||
#include "CommonWriter.h"
|
||||
|
||||
#include <filaflat/ChunkContainer.h>
|
||||
#include <filaflat/DictionaryReader.h>
|
||||
#include <filaflat/MaterialChunk.h>
|
||||
@@ -50,16 +48,12 @@ size_t getShaderCount(const ChunkContainer& container, ChunkType type) {
|
||||
return shaderCount;
|
||||
}
|
||||
|
||||
|
||||
bool getShaderInfo(const ChunkContainer& container, ShaderInfo* info, ChunkType chunkType) {
|
||||
if (!container.hasChunk(chunkType)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
MaterialDomain domain;
|
||||
if (!read(container, ChunkType::MaterialDomain, reinterpret_cast<uint8_t*>(&domain))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto [start, end] = container.getChunkRange(chunkType);
|
||||
Unflattener unflattener(start, end);
|
||||
|
||||
@@ -90,12 +84,6 @@ bool getShaderInfo(const ChunkContainer& container, ShaderInfo* info, ChunkType
|
||||
return false;
|
||||
}
|
||||
|
||||
auto stage = ShaderStage(pipelineStageValue);
|
||||
if (domain == MaterialDomain::SURFACE) {
|
||||
variant = stage == ShaderStage::VERTEX ?
|
||||
Variant::filterVariantVertex(variant) :
|
||||
Variant::filterVariantFragment(variant);
|
||||
}
|
||||
*info++ = {
|
||||
.shaderModel = ShaderModel(shaderModelValue),
|
||||
.variant = variant,
|
||||
|
||||
@@ -135,10 +135,6 @@ ShaderReplacer::ShaderReplacer(Backend backend, ShaderLanguage language,
|
||||
mMaterialTag = ChunkType::MaterialMetal;
|
||||
mDictionaryTag = ChunkType::DictionaryText;
|
||||
break;
|
||||
case backend::ShaderLanguage::WGSL:
|
||||
mMaterialTag = ChunkType::MaterialWgsl;
|
||||
mDictionaryTag = ChunkType::DictionaryText;
|
||||
break;
|
||||
case backend::ShaderLanguage::SPIRV:
|
||||
mMaterialTag = ChunkType::MaterialSpirv;
|
||||
mDictionaryTag = ChunkType::DictionarySpirv;
|
||||
|
||||
@@ -18,7 +18,6 @@
|
||||
#define MATDBG_SOURCE_FORMATTER_H
|
||||
|
||||
#include <mutex>
|
||||
#include <string>
|
||||
|
||||
namespace filament::matdbg {
|
||||
|
||||
|
||||
@@ -429,10 +429,7 @@ static bool printShaderInfo(ostream& text, const ChunkContainer& container, Chun
|
||||
break;
|
||||
case ChunkType::MaterialMetalLibrary:
|
||||
text << "Metal precompiled shader libraries:" << endl;
|
||||
break;
|
||||
case ChunkType::MaterialWgsl:
|
||||
text << "WGSL precompiled shader libraries:" << endl;
|
||||
break;
|
||||
break;
|
||||
default:
|
||||
assert(false && "Invalid shader ChunkType");
|
||||
break;
|
||||
@@ -470,9 +467,6 @@ bool TextWriter::writeMaterialInfo(const filaflat::ChunkContainer& container) {
|
||||
if (!printShaderInfo(text, container, ChunkType::MaterialMetalLibrary)) {
|
||||
return false;
|
||||
}
|
||||
if (!printShaderInfo(text, container, ChunkType::MaterialWgsl)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
printChunks(text, container);
|
||||
|
||||
|
||||
@@ -68,13 +68,14 @@ async function fetchMatIds() {
|
||||
}
|
||||
|
||||
async function queryActiveShaders() {
|
||||
const activeVariants = await _fetchJson("api/active");
|
||||
const activeMaterials = await _fetchJson("api/active");
|
||||
const actives = {};
|
||||
for (matid in activeVariants) {
|
||||
const backend = activeVariants[matid][0];
|
||||
const shaderModel = activeVariants[matid][1];
|
||||
const variants = activeVariants[matid].slice(2);
|
||||
actives[matid] = { backend, shaderModel, variants };
|
||||
for (matid in activeMaterials) {
|
||||
const backend = activeMaterials[matid][0];
|
||||
const variants = activeMaterials[matid].slice(1);
|
||||
actives[matid] = {
|
||||
backend, variants
|
||||
};
|
||||
}
|
||||
return actives;
|
||||
}
|
||||
|
||||
+50
-69
@@ -59,8 +59,8 @@ const FOREGROUND_COLOR = '#fafafa';
|
||||
const INACTIVE_COLOR = '#9a9a9a';
|
||||
const DARKER_INACTIVE_COLOR = '#6f6f6f';
|
||||
const LIGHTER_INACTIVE_COLOR = '#d9d9d9';
|
||||
const UNSELECTED_COLOR = '#d0d0d0';
|
||||
const BACKGROUND_COLOR = '#6885c5';
|
||||
const UNSELECTED_COLOR = '#dfdfdf';
|
||||
const BACKGROUND_COLOR = '#5362e5';
|
||||
const HOVER_BACKGROUND_COLOR = '#b3c2ff';
|
||||
const CODE_VIEWER_BOTTOM_ROW_HEIGHT = 60;
|
||||
const REGULAR_FONT_SIZE = 12;
|
||||
@@ -343,7 +343,7 @@ class MenuSection extends LitElement {
|
||||
color: ${unsafeCSS(UNSELECTED_COLOR)};
|
||||
}
|
||||
.section-title {
|
||||
font-size: 20px;
|
||||
font-size: 16px;
|
||||
color: ${unsafeCSS(UNSELECTED_COLOR)};
|
||||
cursor: pointer;
|
||||
}
|
||||
@@ -365,9 +365,6 @@ class MenuSection extends LitElement {
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
.expanded-title {
|
||||
color: ${unsafeCSS(FOREGROUND_COLOR)};
|
||||
}
|
||||
`;
|
||||
}
|
||||
|
||||
@@ -383,10 +380,9 @@ class MenuSection extends LitElement {
|
||||
render() {
|
||||
const expandedIcon = this.showing ? '-' : '+';
|
||||
const slot = (() => html`<slot></slot>`)();
|
||||
const epandedTitleClass = this.showing ? 'expanded-title' : '';
|
||||
return html`
|
||||
<div class="container">
|
||||
<div class="section-title expander ${epandedTitleClass}" @click="${this._showClick}">
|
||||
<div class="section-title expander" @click="${this._showClick}">
|
||||
<span>${this.title}</span> <span>${expandedIcon}</span>
|
||||
</div>
|
||||
<hr />
|
||||
@@ -464,7 +460,6 @@ class AdvancedOptions extends LitElement {
|
||||
static get properties() {
|
||||
return {
|
||||
currentBackend: {type: String, attribute: 'current-backend'},
|
||||
currentShaderModel: {type: String, attribute: 'current-shader-model'},
|
||||
hideInactiveVariants: {type: Boolean, attribute: 'hide-inactive-variants'},
|
||||
availableBackends: {type: Array, state: true},
|
||||
};
|
||||
@@ -483,7 +478,6 @@ class AdvancedOptions extends LitElement {
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: flex-start;
|
||||
margin-bottom: 6px;
|
||||
}
|
||||
.borderless {
|
||||
border: 1px solid rgba(0,0,0,0);
|
||||
@@ -576,7 +570,7 @@ class AdvancedOptions extends LitElement {
|
||||
return html`
|
||||
<div class="option">
|
||||
<div class="option-heading">Current Backend</div>
|
||||
<form style="display:flex;flex-wrap:wrap" action="" id="backend-option-form">
|
||||
<form action="" id="backend-option-form">
|
||||
${div}
|
||||
</form>
|
||||
</div>
|
||||
@@ -584,9 +578,6 @@ class AdvancedOptions extends LitElement {
|
||||
}
|
||||
|
||||
_hideInactiveVariantsOption() {
|
||||
if (this.currentShaderModel == 'matinfo') {
|
||||
return null;
|
||||
}
|
||||
const onChange = (ev) => {
|
||||
this.dispatchEvent(
|
||||
new CustomEvent(
|
||||
@@ -594,7 +585,7 @@ class AdvancedOptions extends LitElement {
|
||||
{detail: null, bubbles: true, composed: true}));
|
||||
}
|
||||
return html`
|
||||
<div class="option">
|
||||
<div class="option borderless">
|
||||
<!--<div class="option-heading">Current Backend</div>-->
|
||||
<form action="" id="hide-inactive-variants-form">
|
||||
<input type="checkbox" name="InactiveVariants"
|
||||
@@ -639,8 +630,8 @@ class MaterialSidePanel extends LitElement {
|
||||
color: white;
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
margin: 0 0 20px 0;
|
||||
font-size: 25px;
|
||||
margin: 0 0 10px 0;
|
||||
font-size: 20px;
|
||||
}
|
||||
.materials {
|
||||
display: flex;
|
||||
@@ -684,7 +675,6 @@ class MaterialSidePanel extends LitElement {
|
||||
currentBackend: {type: String, attribute: 'current-backend'},
|
||||
currentLanguage: {type: String, attribute: 'current-language'},
|
||||
hideInactiveVariants: {type: Boolean, attribute: 'hide-inactive-variants'},
|
||||
currentShaderModel: {type: String, attribute: 'current-shader-model'},
|
||||
|
||||
database: {type: Object, state: true},
|
||||
materials: {type: Array, state: true},
|
||||
@@ -712,19 +702,29 @@ class MaterialSidePanel extends LitElement {
|
||||
|
||||
updated(props) {
|
||||
if (props.has('database')) {
|
||||
const items = [];
|
||||
|
||||
// Names need not be unique, so we display a numeric suffix for non-unique names.
|
||||
// To achieve stable ordering of anonymous materials, we first sort by matid.
|
||||
const labels = new Set();
|
||||
const matids = Object.keys(this.database).sort();
|
||||
const names = matids.map(matid => (this.database[matid].name || kUntitledPlaceholder));
|
||||
const labelCount = {};
|
||||
names.forEach(name => labelCount[name] = (labelCount[name] || 0) + 1);
|
||||
const duplicates = names.filter(name => labelCount[name] > 1);
|
||||
const duplicatedLabels = {};
|
||||
for (const matid of matids) {
|
||||
const name = this.database[matid].name || kUntitledPlaceholder;
|
||||
if (labels.has(name)) {
|
||||
duplicatedLabels[name] = 0;
|
||||
} else {
|
||||
labels.add(name);
|
||||
}
|
||||
}
|
||||
|
||||
this.materials = matids.map((matid) => {
|
||||
const material = this.database[matid];
|
||||
let name = material.name || kUntitledPlaceholder;
|
||||
if (duplicates.includes(name)) {
|
||||
name = `${name} (${labelCount[name]--})`;
|
||||
if (name in duplicatedLabels) {
|
||||
const index = duplicatedLabels[name];
|
||||
duplicatedLabels[name] = index + 1;
|
||||
name = `${name} (${index})`;
|
||||
}
|
||||
return {
|
||||
matid: matid,
|
||||
@@ -784,7 +784,7 @@ class MaterialSidePanel extends LitElement {
|
||||
let divClass =
|
||||
'material_variant_language language' +
|
||||
(isLanguageSelected ? ' selected' : '') +
|
||||
(!isActive && this.currentShaderModel != 'matinfo' ? ' inactive' : '');
|
||||
(!isActive ? ' inactive' : '');
|
||||
const onClickLanguage = this._handleLanguageClick.bind(this, lang);
|
||||
lang = (isLanguageSelected ? '● ' : '') + lang;
|
||||
return html`
|
||||
@@ -796,11 +796,10 @@ class MaterialSidePanel extends LitElement {
|
||||
return html`<div class="languages">${languagesDiv}</div>`;
|
||||
}
|
||||
|
||||
_buildShaderDiv() {
|
||||
_buildShaderDiv(showAllShaders) {
|
||||
if (!this.variants) {
|
||||
return null;
|
||||
}
|
||||
const isMatinfo = this.currentShaderModel == 'matinfo';
|
||||
let variants =
|
||||
this.variants
|
||||
.sort((a, b) => {
|
||||
@@ -809,10 +808,7 @@ class MaterialSidePanel extends LitElement {
|
||||
if (b.active && !a.active) return 1;
|
||||
return 0;
|
||||
})
|
||||
.filter(variant => (!this.hideInactiveVariants || variant.shader.active))
|
||||
.filter(variant => (
|
||||
isMatinfo || variant.shader.shaderModel == this.currentShaderModel
|
||||
))
|
||||
.filter((variant) => (!this.hideInactiveVariants || variant.shader.active))
|
||||
.map((variant) => {
|
||||
let divClass = 'material_variant_language';
|
||||
const shaderIndex = +variant.shader.index;
|
||||
@@ -821,7 +817,7 @@ class MaterialSidePanel extends LitElement {
|
||||
if (isVariantSelected) {
|
||||
divClass += ' selected';
|
||||
}
|
||||
if (!isActive && !isMatinfo) {
|
||||
if (!isActive) {
|
||||
divClass += ' inactive';
|
||||
}
|
||||
const onClickVariant = this._handleVariantClick.bind(this, shaderIndex);
|
||||
@@ -830,18 +826,11 @@ class MaterialSidePanel extends LitElement {
|
||||
if (vstring.length > 0) {
|
||||
vstring = `[${vstring}]`;
|
||||
}
|
||||
const shaderModelSymbol = {
|
||||
'desktop': '🄳 ',
|
||||
'mobile': '🄼 ',
|
||||
};
|
||||
|
||||
let languagesDiv = isVariantSelected ? this._buildLanguagesDiv(isActive) : null;
|
||||
const stage =
|
||||
(isMatinfo ? shaderModelSymbol[variant.shader.shaderModel] : '') +
|
||||
(variant.shader.pipelineStage.indexOf('vertex') >=0 ? '𝕍ert' : '𝔽rag');
|
||||
const stage = (isVariantSelected ? '● ' : '') + variant.shader.pipelineStage;
|
||||
return html`
|
||||
<div class="${divClass}" @click="${onClickVariant}">
|
||||
<div>${stage}  ${vstring} </div>
|
||||
<div>${stage} ${vstring} </div>
|
||||
</div>
|
||||
${languagesDiv ?? nothing}
|
||||
`
|
||||
@@ -850,7 +839,6 @@ class MaterialSidePanel extends LitElement {
|
||||
}
|
||||
|
||||
render() {
|
||||
const isMatinfo = this.currentShaderModel == 'matinfo';
|
||||
const sections = (title, domain) => {
|
||||
const mats = this.materials
|
||||
.filter((m) => m.domain == domain)
|
||||
@@ -866,12 +854,14 @@ class MaterialSidePanel extends LitElement {
|
||||
const isMaterialSelected = mat.matid === this.currentMaterial;
|
||||
if (isMaterialSelected) {
|
||||
divClass += ' selected';
|
||||
shaderDiv = this._buildShaderDiv();
|
||||
// If we are looking at an inactive material, show all shaders regardless.
|
||||
const showAllShaders = !material.active;
|
||||
shaderDiv = this._buildShaderDiv(showAllShaders);
|
||||
}
|
||||
if (!material.active && !isMatinfo) {
|
||||
if (!material.active) {
|
||||
divClass += " inactive";
|
||||
}
|
||||
const matName = mat.name;
|
||||
const matName = (isMaterialSelected ? '● ' : '') + mat.name;
|
||||
return html`
|
||||
<div class="${divClass}" @click="${onClick}" data-id="${mat.matid}">
|
||||
${matName}
|
||||
@@ -888,7 +878,6 @@ class MaterialSidePanel extends LitElement {
|
||||
(() => html`
|
||||
<advanced-options id="advanced-options"
|
||||
current-backend=${this.currentBackend}
|
||||
current-shader-model=${this.currentShaderModel}
|
||||
?hide-inactive-variants=${this.hideInactiveVariants}
|
||||
></advanced-options>
|
||||
`)();
|
||||
@@ -896,7 +885,7 @@ class MaterialSidePanel extends LitElement {
|
||||
return html`
|
||||
<style>${this.dynamicStyle()}</style>
|
||||
<div class="container">
|
||||
<div class="title">${isMatinfo ? 'matinfo' : 'matdbg'}</div>
|
||||
<div class="title">matdbg</div>
|
||||
${sections("Surface", "surface") ?? nothing}
|
||||
${sections("Post-processing", "postpro") ?? nothing}
|
||||
<material-info id="material-info"></material-info>
|
||||
@@ -949,7 +938,8 @@ class MatdbgViewer extends LitElement {
|
||||
}
|
||||
);
|
||||
|
||||
this.database = await fetchMaterials();
|
||||
let materials = await fetchMaterials();
|
||||
this.database = materials;
|
||||
|
||||
// This is the user preferences stored in localStorage
|
||||
let hideInactiveVariantsVal = localStorage.getItem('option-hide-inactive-variants');
|
||||
@@ -989,7 +979,6 @@ class MatdbgViewer extends LitElement {
|
||||
this.currentMaterial = null;
|
||||
this.currentLanguage = null;
|
||||
this.currentBackend = null;
|
||||
this.currentShaderModel = null;
|
||||
this.hideInactiveVariants = false;
|
||||
this.init();
|
||||
|
||||
@@ -1060,7 +1049,6 @@ class MatdbgViewer extends LitElement {
|
||||
// Each material has a list of variants compiled for it, this index tracks a position in the list.
|
||||
currentShaderIndex: {type: Number, state: true},
|
||||
currentBackend: {type: String, state: true},
|
||||
currentShaderModel: {type: String, state: true},
|
||||
codeViewerExpectedWidth: {type: Number, state: true},
|
||||
codeViewerExpectedHeight: {type: Number, state: true},
|
||||
|
||||
@@ -1082,8 +1070,8 @@ class MatdbgViewer extends LitElement {
|
||||
const activeVariants = this.activeShaders[this.currentMaterial].variants;
|
||||
const materialShaders = material[this.currentBackend];
|
||||
for (let shader in materialShaders) {
|
||||
const shaderVariant = materialShaders[shader].variant;
|
||||
if (activeVariants.indexOf(shaderVariant) >= 0) {
|
||||
let ind = activeVariants.indexOf(+shader);
|
||||
if (ind >= 0) {
|
||||
this.currentShaderIndex = +shader;
|
||||
break;
|
||||
}
|
||||
@@ -1107,6 +1095,7 @@ class MatdbgViewer extends LitElement {
|
||||
shader.modified = false;
|
||||
this.database = this.database;
|
||||
}
|
||||
|
||||
// Size of the editor will be adjusted due to the code being loaded, we try to
|
||||
// fit the editor again by calling the resize signal.
|
||||
setTimeout(this._onResize.bind(this), 700);
|
||||
@@ -1130,29 +1119,22 @@ class MatdbgViewer extends LitElement {
|
||||
}
|
||||
}
|
||||
if (_validDict(this.activeShaders)) {
|
||||
let setBackend = null;
|
||||
let setShaderModel = null;
|
||||
let backends = {};
|
||||
for (let matid in this.activeShaders) {
|
||||
const backend = this.activeShaders[matid].backend;
|
||||
if (!setBackend && backend) {
|
||||
setBackend = backend;
|
||||
}
|
||||
const shaderModel = this.activeShaders[matid].shaderModel;
|
||||
if (!setShaderModel && shaderModel) {
|
||||
setShaderModel = shaderModel;
|
||||
if (backend in backends) {
|
||||
backends[backend] = backends[backend] + 1;
|
||||
} else {
|
||||
backends[backend] = 1;
|
||||
}
|
||||
}
|
||||
if (this.currentBackend != setBackend) {
|
||||
this.currentBackend = setBackend;
|
||||
let backendList = Object.keys(backends);
|
||||
if (backendList.length > 0) {
|
||||
this.currentBackend = backendList[0];
|
||||
}
|
||||
if (this.currentShaderModel != setShaderModel) {
|
||||
this.currentShaderModel = setShaderModel;
|
||||
}
|
||||
|
||||
} else if (!this.currentBackend || !this.currentShaderModel) {
|
||||
} else if (!this.currentBackend) {
|
||||
// Make a guess on the backend if one wasn't from activeShaders.
|
||||
this.currentBackend = guessBackend();
|
||||
this.currentShaderModel = 'matinfo';
|
||||
}
|
||||
|
||||
this._sidepanel.database = this.database;
|
||||
@@ -1184,7 +1166,6 @@ class MatdbgViewer extends LitElement {
|
||||
current-shader-index="${this.currentShaderIndex}"
|
||||
current-material="${this.currentMaterial}"
|
||||
current-backend="${this.currentBackend}"
|
||||
current-shader-model="${this.currentShaderModel}"
|
||||
?hide-inactive-variants="${this.hideInactiveVariants}" >
|
||||
</material-sidepanel>
|
||||
<code-viewer id="code-viewer"
|
||||
|
||||
+2
-28
@@ -20,6 +20,7 @@ set(MATERIAL_SRCS
|
||||
materials/aiDefaultMat.mat
|
||||
materials/bakedColor.mat
|
||||
materials/bakedTexture.mat
|
||||
materials/pointSprites.mat
|
||||
materials/aoPreview.mat
|
||||
materials/arrayTexture.mat
|
||||
materials/groundShadow.mat
|
||||
@@ -41,12 +42,6 @@ set(MATERIAL_SRCS
|
||||
materials/texturedLit.mat
|
||||
)
|
||||
|
||||
# Tint does not support setting gl_PointSize, disable the relevant sample if using WebGPU
|
||||
# https://github.com/gpuweb/gpuweb/issues/1190
|
||||
if (NOT FILAMENT_SUPPORTS_WEBGPU)
|
||||
set(MATERIAL_SRCS ${MATERIAL_SRCS} materials/pointSprites.mat)
|
||||
endif ()
|
||||
|
||||
if (CMAKE_CROSSCOMPILING)
|
||||
include(${IMPORT_EXECUTABLES})
|
||||
endif()
|
||||
@@ -245,20 +240,6 @@ function(add_demo NAME)
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
function(add_demo_plain NAME)
|
||||
include_directories(${GENERATION_ROOT})
|
||||
add_executable(${NAME} ${NAME}.cpp)
|
||||
target_compile_options(${NAME} PRIVATE ${COMPILER_FLAGS})
|
||||
set_target_properties(${NAME} PROPERTIES FOLDER Samples)
|
||||
|
||||
# This is needed after XCode 15.3
|
||||
if (APPLE)
|
||||
set_target_properties(${NAME} PROPERTIES BUILD_WITH_INSTALL_RPATH TRUE)
|
||||
set_target_properties(${NAME} PROPERTIES INSTALL_RPATH /usr/local/lib)
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
|
||||
if (NOT ANDROID)
|
||||
add_demo(animation)
|
||||
add_demo(depthtesting)
|
||||
@@ -277,11 +258,7 @@ if (NOT ANDROID)
|
||||
add_demo(lightbulb)
|
||||
add_demo(material_sandbox)
|
||||
add_demo(multiple_windows)
|
||||
# Tint does not support setting gl_PointSize, disable the relevant sample if using WebGPU
|
||||
# https://github.com/gpuweb/gpuweb/issues/1190
|
||||
if (NOT FILAMENT_SUPPORTS_WEBGPU)
|
||||
add_demo(point_sprites)
|
||||
endif ()
|
||||
add_demo(point_sprites)
|
||||
add_demo(rendertarget)
|
||||
add_demo(sample_cloth)
|
||||
add_demo(sample_full_pbr)
|
||||
@@ -294,9 +271,6 @@ if (NOT ANDROID)
|
||||
add_demo(vbotest)
|
||||
add_demo(viewtest)
|
||||
|
||||
add_demo_plain(spirv_test)
|
||||
target_link_libraries(spirv_test PRIVATE SPIRV-Headers utils)
|
||||
|
||||
# Sample app specific
|
||||
target_link_libraries(frame_generator PRIVATE imageio)
|
||||
target_link_libraries(gltf_viewer PRIVATE gltf-demo-resources uberarchive gltfio viewer)
|
||||
|
||||
@@ -77,11 +77,7 @@ static void printUsage(char* name) {
|
||||
" --help, -h\n"
|
||||
" Prints this message\n\n"
|
||||
" --api, -a\n"
|
||||
" Specify the backend API: opengl, vulkan, metal, or webgpu\n"
|
||||
" (note: webgpu is a no-op for now, printing backend\n"
|
||||
" component info if FILAMENT_BACKEND_DEBUG_FLAG, \n"
|
||||
" set at build time, includes the \n"
|
||||
" FWGPU_PRINT_SYSTEM bit flag 0x2)\n"
|
||||
" Specify the backend API: opengl, vulkan, or metal\n"
|
||||
);
|
||||
const std::string from("HELLOTRIANGLE");
|
||||
for (size_t pos = usage.find(from); pos != std::string::npos; pos = usage.find(from, pos)) {
|
||||
@@ -113,11 +109,8 @@ static int handleCommandLineArguments(int argc, char* argv[], App* app) {
|
||||
app->config.backend = Engine::Backend::VULKAN;
|
||||
} else if (arg == "metal") {
|
||||
app->config.backend = Engine::Backend::METAL;
|
||||
} else if (arg == "webgpu") {
|
||||
app->config.backend = Engine::Backend::WEBGPU;
|
||||
} else {
|
||||
std::cerr << "Unrecognized backend. Must be "
|
||||
"'opengl'|'vulkan'|'metal'|'webgpu'.\n";
|
||||
std::cerr << "Unrecognized backend. Must be 'opengl'|'vulkan'|'metal'.\n";
|
||||
exit(1);
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -1,145 +0,0 @@
|
||||
#include "spirv/unified1/spirv.hpp"
|
||||
#include <utils/Log.h>
|
||||
|
||||
#include <functional>
|
||||
#include <fstream>
|
||||
#include <vector>
|
||||
#include <unordered_map>
|
||||
|
||||
size_t getFileSize(const std::string& filename) {
|
||||
std::ifstream file(filename, std::ios::binary | std::ios::ate);
|
||||
if (!file.is_open()) {
|
||||
return -1;
|
||||
}
|
||||
size_t size = file.tellg();
|
||||
file.close();
|
||||
return size;
|
||||
}
|
||||
|
||||
std::vector<uint32_t> transform(std::vector<uint32_t> const& spirv) {
|
||||
constexpr size_t HEADER_SIZE = 5;
|
||||
size_t const dataSize = spirv.size();
|
||||
std::vector<uint32_t> output;
|
||||
output.resize(dataSize);
|
||||
uint32_t const* data = (uint32_t*) spirv.data();
|
||||
uint32_t* outputData = output.data();
|
||||
memcpy(&outputData[0], &data[0], HEADER_SIZE * 4);
|
||||
|
||||
struct Descriptor {
|
||||
uint32_t binding = 0xFFFFFFFF;
|
||||
uint32_t set = 0xFFFFFFFF;
|
||||
bool fixed = false;
|
||||
};
|
||||
|
||||
std::unordered_map<uint32_t, Descriptor> descriptors;
|
||||
auto getDesc = [&](uint32_t var) -> Descriptor& {
|
||||
using itertype = std::unordered_map<uint32_t, Descriptor>::iterator;
|
||||
itertype itr;
|
||||
if (itr = descriptors.find(var); itr == descriptors.end()) {
|
||||
itr = descriptors.insert({var, {}}).first;
|
||||
}
|
||||
return itr->second;
|
||||
};
|
||||
|
||||
auto pass = [&](uint32_t targetOp, std::function<void(uint32_t, uint32_t)> f) {
|
||||
for (uint32_t cursor = HEADER_SIZE, cursorEnd = dataSize; cursor < cursorEnd;) {
|
||||
uint32_t const firstWord = data[cursor];
|
||||
uint32_t const wordCount = firstWord >> 16;
|
||||
uint32_t const op = firstWord & 0x0000FFFF;
|
||||
if (targetOp == op) {
|
||||
f(wordCount-1, cursor+1);
|
||||
}
|
||||
cursor += wordCount;
|
||||
}
|
||||
};
|
||||
|
||||
uint32_t samplerTypeId = 0;
|
||||
uint32_t imageTypeId = 0;
|
||||
|
||||
// First we find the ID used to identify the sampler type and the image type.
|
||||
pass(spv::Op::OpTypeSampler, [&](uint32_t count, uint32_t pos) {
|
||||
samplerTypeId = data[pos];
|
||||
});
|
||||
|
||||
pass(spv::Op::OpTypeImage, [&](uint32_t count, uint32_t pos) {
|
||||
imageTypeId = data[pos];
|
||||
});
|
||||
|
||||
// Next we identify all the descriptors and record their set id and binding.
|
||||
pass(spv::Op::OpDecorate, [&](uint32_t count, uint32_t pos) {
|
||||
uint32_t const type = data[pos + 1];
|
||||
if (type == spv::Decoration::DecorationBinding) {
|
||||
uint32_t const targetVar = data[pos];
|
||||
uint32_t const binding = data[pos + 2];
|
||||
auto& desc = getDesc(targetVar);
|
||||
desc.binding = binding;
|
||||
// Note these decorations do not need to be written to the output.
|
||||
} else if (type == spv::Decoration::DecorationDescriptorSet) {
|
||||
uint32_t const targetVar = data[pos];
|
||||
uint32_t const set = data[pos + 2];
|
||||
auto& desc = getDesc(targetVar);
|
||||
desc.set = set;
|
||||
}
|
||||
});
|
||||
|
||||
// If any descriptor is loaded to be a sampler, we offset it by a fixed amount. Note that it
|
||||
// could be "loaded" multiple times, so we use a boolean to skip if it's already offsetted.
|
||||
constexpr uint32_t SAMPLER_BINDING_OFFSET = 100;
|
||||
pass(spv::Op::OpLoad, [&](uint32_t count, uint32_t pos) {
|
||||
uint32_t const retType = data[pos];
|
||||
uint32_t const targetVar = data[pos + 2];
|
||||
if (retType == samplerTypeId) {
|
||||
auto& desc = getDesc(targetVar);
|
||||
if (!desc.fixed) {
|
||||
desc.binding += SAMPLER_BINDING_OFFSET;
|
||||
desc.fixed = true;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Write out the offsetted bindings and copy the rest.
|
||||
for (uint32_t cursor = HEADER_SIZE, cursorEnd = dataSize; cursor < cursorEnd;) {
|
||||
uint32_t const firstWord = data[cursor];
|
||||
uint32_t const wordCount = firstWord >> 16;
|
||||
uint32_t const op = firstWord & 0x0000FFFF;
|
||||
|
||||
uint32_t* out = &outputData[cursor];
|
||||
std::memcpy(out, &data[cursor], wordCount * 4);
|
||||
|
||||
if (op == spv::Op::OpDecorate && data[cursor + 2] == spv::Decoration::DecorationBinding) {
|
||||
uint32_t const targetVar = data[cursor + 1];
|
||||
auto const& modified = getDesc(targetVar);
|
||||
out[3] = modified.binding;
|
||||
}
|
||||
cursor += wordCount;
|
||||
}
|
||||
|
||||
// Note that you should be able to do this in-place (without making another vector).
|
||||
return output;
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
if (argc < 3) {
|
||||
utils::slog.e <<"need input and output spirv filenames" << utils::io::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
std::string infname {argv[1]};
|
||||
size_t const fsize = getFileSize(infname);
|
||||
size_t const wordCount = fsize / 4;
|
||||
|
||||
std::ifstream inputFile(infname, std::ios::binary);
|
||||
|
||||
std::vector<uint32_t> words;
|
||||
words.resize(wordCount);
|
||||
inputFile.read((char*) words.data(), fsize);
|
||||
inputFile.close();
|
||||
|
||||
std::string outfname {argv[2]};
|
||||
std::vector<uint32_t> output = transform(words);
|
||||
std::ofstream outputFile(outfname, std::ios::binary);
|
||||
outputFile.write((char const*) output.data(), output.size() * 4);
|
||||
outputFile.close();
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -35,13 +35,10 @@ if [[ "$GITHUB_WORKFLOW" ]]; then
|
||||
sudo update-alternatives --install /usr/bin/c++ c++ /usr/bin/clang++-${GITHUB_CLANG_VERSION} 100
|
||||
else
|
||||
set +e
|
||||
sudo apt-get -y build-dep mesa
|
||||
sudo apt -y remove llvm-18 llvm-18-* llvm-19 llvm-19-*
|
||||
apt-get -y build-dep mesa
|
||||
sudo apt -y remove llvm-18 llvm-18-*
|
||||
set -e
|
||||
|
||||
CURRENT_CLANG_VERSION=$(clang --version | head -n 1 | awk '{ print $4 }' | awk 'BEGIN { FS="\\." } { print $1 }')
|
||||
GITHUB_CLANG_VERSION=${GITHUB_CLANG_VERSION:-${CURRENT_CLANG_VERSION}}
|
||||
|
||||
sudo apt-get -y install clang-${GITHUB_CLANG_VERSION} \
|
||||
libc++-${GITHUB_CLANG_VERSION}-dev \
|
||||
libc++abi-${GITHUB_CLANG_VERSION}-dev \
|
||||
|
||||
Vendored
+1
-55
@@ -12,59 +12,5 @@ set(DAWN_ABSEIL_DIR ${EXTERNAL}/abseil)
|
||||
set(DAWN_SPIRV_TOOLS_DIR ${EXTERNAL}/spirv-tools/)
|
||||
set(DAWN_SPIRV_HEADERS_DIR ${EXTERNAL}/spirv-headers)
|
||||
set(DAWN_GLSLANG_DIR ${EXTERNAL}/glslang/)
|
||||
set(DAWN_DXC_ENABLE_ASSERTS_IN_NDEBUG OFF)
|
||||
|
||||
#set(TINT_BUILD_CMD_TOOLS OFF)
|
||||
|
||||
if (FILAMENT_BUILD_FILAMAT)
|
||||
set(TINT_BUILD_SPV_READER ON)
|
||||
endif ()
|
||||
|
||||
add_subdirectory(../ ${PROJECT_BINARY_DIR}/third_party/dawn)
|
||||
|
||||
# Need to install libtint for filamat on Android.
|
||||
# See third_party/dawn/tnt/CMakeLists.txt and android/filamat-android/CMakeLists.txt.
|
||||
if (ANDROID AND FILAMENT_BUILD_FILAMAT)
|
||||
set(COMBINED_TARGET libtint_combined)
|
||||
set(COMBINED_OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/${COMBINED_TARGET}.a")
|
||||
|
||||
# TODO: maybe use this target in place of libtint in filamat proper. (it's smaller)
|
||||
set(LIBTINT_DEPS
|
||||
tint_lang_core
|
||||
tint_lang_core_constant
|
||||
tint_lang_core_intrinsic
|
||||
tint_lang_core_type
|
||||
tint_lang_spirv_reader
|
||||
tint_lang_spirv_reader_ast_lower
|
||||
tint_lang_spirv_reader_ast_parser
|
||||
tint_lang_spirv_reader_common
|
||||
tint_lang_spirv_writer
|
||||
tint_lang_wgsl
|
||||
tint_lang_wgsl_ast
|
||||
tint_lang_wgsl_ast_transform
|
||||
tint_lang_wgsl_features
|
||||
tint_lang_wgsl_intrinsic
|
||||
tint_lang_wgsl_program
|
||||
tint_lang_wgsl_resolver
|
||||
tint_lang_wgsl_sem
|
||||
tint_lang_wgsl_writer
|
||||
tint_lang_wgsl_writer_ast_printer
|
||||
tint_results
|
||||
tint_utils
|
||||
tint_utils_diagnostic
|
||||
tint_utils_ice
|
||||
tint_utils_result
|
||||
tint_utils_rtti
|
||||
tint_utils_strconv
|
||||
tint_utils_symbol
|
||||
tint_utils_text
|
||||
)
|
||||
|
||||
# Use the following no-op definitions to introduce a library and its dependency.
|
||||
add_library(${COMBINED_TARGET} STATIC dummy.cpp)
|
||||
target_link_libraries(${COMBINED_TARGET} PRIVATE
|
||||
${LIBTINT_DEPS}
|
||||
)
|
||||
combine_static_libs(${COMBINED_TARGET} "${COMBINED_OUTPUT}" "${LIBTINT_DEPS}")
|
||||
install(FILES "${COMBINED_OUTPUT}" DESTINATION lib/${DIST_DIR})
|
||||
endif()
|
||||
add_subdirectory(../ ${PROJECT_BINARY_DIR}/third_party/dawn)
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user