Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c903903fcb | ||
|
|
89edb1a129 | ||
|
|
9eb6b17325 | ||
|
|
75a1498a95 | ||
|
|
0cb9e85c66 | ||
|
|
72abf1fc7d | ||
|
|
87cfa6a0de | ||
|
|
d183347120 | ||
|
|
9916f9ec63 | ||
|
|
4a65fa75fc | ||
|
|
5d8e366649 | ||
|
|
ba769212e9 | ||
|
|
035d75873d | ||
|
|
ce71136c8f | ||
|
|
15c54e8e67 | ||
|
|
2101444f46 | ||
|
|
2bb9d13797 | ||
|
|
edbaa30ad8 | ||
|
|
04cac2159f | ||
|
|
426c2e01ed | ||
|
|
320162bb19 | ||
|
|
1043eaa076 | ||
|
|
6a28bdb3fc | ||
|
|
b440217503 | ||
|
|
b3ddad7070 | ||
|
|
2274bfddb2 | ||
|
|
46ccb6bab1 | ||
|
|
70680721c4 | ||
|
|
aeb292f5e1 | ||
|
|
74c68fe312 | ||
|
|
0865e3d042 | ||
|
|
43432ddc39 | ||
|
|
80ef2ed67e | ||
|
|
93ad78a81d | ||
|
|
94b8ee481f | ||
|
|
05bd56d0e8 | ||
|
|
11d3d82f13 | ||
|
|
c368d977ea | ||
|
|
f384f504b8 | ||
|
|
f3f65e8dbb | ||
|
|
ac29bb5094 | ||
|
|
4909826d21 | ||
|
|
4e920ed077 | ||
|
|
db6baed3a5 | ||
|
|
ede471ce0b | ||
|
|
580157662d | ||
|
|
c7ad86906c | ||
|
|
a488b3d3ee | ||
|
|
1014c7b214 | ||
|
|
005e9a6812 | ||
|
|
1a08514d9f | ||
|
|
3f5965e591 | ||
|
|
cb9944979e | ||
|
|
3ffea1a984 | ||
|
|
0f5351b184 | ||
|
|
6ca16574d9 | ||
|
|
4cd76247e2 | ||
|
|
c4fb50f0a4 | ||
|
|
c6d447d963 | ||
|
|
2c03004311 | ||
|
|
0b409e90f0 | ||
|
|
2fda451f6b | ||
|
|
505969cdf6 | ||
|
|
0acda5fc2d | ||
|
|
dffa7a29a4 | ||
|
|
e0529a9ba4 | ||
|
|
1362c09512 | ||
|
|
3105a67e15 | ||
|
|
fc287bd7c0 | ||
|
|
3c09e36410 | ||
|
|
3a6d36cd66 | ||
|
|
70b5e11653 | ||
|
|
10ea71c476 | ||
|
|
72ad5da352 | ||
|
|
e10cfd7da9 | ||
|
|
a6caf8e630 | ||
|
|
6ad63bb8c8 | ||
|
|
38744e8297 | ||
|
|
fe197c4628 | ||
|
|
20b940a70f | ||
|
|
a1cf965787 | ||
|
|
58e59977db | ||
|
|
c5842d2f44 | ||
|
|
758c957f42 | ||
|
|
b036428fdc | ||
|
|
f483c93c5a | ||
|
|
12faf3a01f | ||
|
|
29ececc5f9 | ||
|
|
4d35a7db75 | ||
|
|
eb8260ab2c | ||
|
|
596c17ecc0 | ||
|
|
4536752c47 | ||
|
|
3b9f4df1a8 | ||
|
|
c701a19292 | ||
|
|
b68e2a9503 | ||
|
|
99fbb63528 | ||
|
|
10169b94a2 | ||
|
|
7c0f62ce9d | ||
|
|
10fdb3b9a2 | ||
|
|
0236f45bad | ||
|
|
123bce928c | ||
|
|
963fc9b15a | ||
|
|
99c82115d4 | ||
|
|
219208049b | ||
|
|
c4f0798c5d | ||
|
|
fac324d5cf | ||
|
|
97ed8143e4 | ||
|
|
43860b6830 | ||
|
|
c0884c03dc | ||
|
|
c24e5089c4 | ||
|
|
4be96c8748 | ||
|
|
a1397c9ce9 | ||
|
|
fd6facf52f | ||
|
|
2919298fed | ||
|
|
b0bc351642 | ||
|
|
9758e68424 | ||
|
|
b5ad54b963 | ||
|
|
57f6214637 | ||
|
|
26171e7f76 | ||
|
|
472054631a | ||
|
|
a3609eba2e | ||
|
|
d53abebbe9 | ||
|
|
cec7150b4c | ||
|
|
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
-3
@@ -65,6 +65,4 @@ SpacesInParentheses: false
|
||||
SpacesInSquareBrackets: false
|
||||
TabWidth: 4
|
||||
UseTab: Never
|
||||
PackConstructorInitializers: Never
|
||||
ConstructorInitializerIndentWidth: 8
|
||||
IndentWrappedFunctionNames: true
|
||||
PackConstructorInitializers: Never
|
||||
+1
-1
@@ -351,7 +351,7 @@ else()
|
||||
endif()
|
||||
|
||||
if (FILAMENT_USE_EXTERNAL_GLES3)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DFILAMENT_USE_EXTERNAL_GLES3")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DUSE_EXTERNAL_GLES3")
|
||||
endif()
|
||||
|
||||
if (FILAMENT_SUPPORTS_EGL_ON_LINUX)
|
||||
|
||||
+6
-18
@@ -20,7 +20,7 @@ The guiding principles of the filament code style and code formatting can be res
|
||||
- class access modifiers are not indented
|
||||
- last line of `.cpp` or `.h` file must be an empty line
|
||||
|
||||
```c++
|
||||
```
|
||||
for (int i = 0; i < max; i++) {
|
||||
}
|
||||
|
||||
@@ -73,24 +73,12 @@ src/data.inc
|
||||
- `public` class attributes *are not* prefixed
|
||||
- class attributes and methods are lower camelcase
|
||||
|
||||
```c++
|
||||
```
|
||||
extern int gGlobalWarming;
|
||||
|
||||
class FooBar {
|
||||
public:
|
||||
FooBar(int attributeName, int sizeInBytes)
|
||||
: mAttributeName(attributeName),
|
||||
sizeInBytes(sizeInBytes) {}
|
||||
|
||||
void reallyLongMethodNameWithLotsOfArguments(bool argument1,
|
||||
int someSecondArgument, int bestArgument) {
|
||||
std::pair<bool, int> pair = {
|
||||
argument1,
|
||||
argument2,
|
||||
};
|
||||
// etc
|
||||
}
|
||||
|
||||
void methodName();
|
||||
int sizeInBytes;
|
||||
private:
|
||||
int mAttributeName;
|
||||
@@ -109,7 +97,7 @@ private:
|
||||
- always include the copyright notice at the top of every file
|
||||
- make sure the date is correct
|
||||
|
||||
```c++
|
||||
```
|
||||
/*
|
||||
* Copyright (C) 2018 The Android Open Source Project
|
||||
*
|
||||
@@ -151,7 +139,7 @@ conversely containers and algorithms are not allowed. There are exceptions such
|
||||
|
||||
*Sorting the headers is important to help catching missing `#include` directives.*
|
||||
|
||||
```c++
|
||||
```
|
||||
/*
|
||||
* Copyright (C) 2018 The Android Open Source Project
|
||||
*
|
||||
@@ -195,7 +183,7 @@ conversely containers and algorithms are not allowed. There are exceptions such
|
||||
### Misc
|
||||
|
||||
- Use `auto` only when the type appears on the same line or with iterators and lambdas.
|
||||
```c++
|
||||
```
|
||||
auto foo = new Foo();
|
||||
for (auto& i : collection) { }
|
||||
```
|
||||
|
||||
@@ -31,7 +31,7 @@ repositories {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation 'com.google.android.filament:filament-android:1.66.0'
|
||||
implementation 'com.google.android.filament:filament-android:1.65.3'
|
||||
}
|
||||
```
|
||||
|
||||
@@ -51,7 +51,7 @@ Here are all the libraries available in the group `com.google.android.filament`:
|
||||
iOS projects can use CocoaPods to install the latest release:
|
||||
|
||||
```shell
|
||||
pod 'Filament', '~> 1.66.0'
|
||||
pod 'Filament', '~> 1.65.3'
|
||||
```
|
||||
|
||||
## Documentation
|
||||
|
||||
@@ -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.66.0
|
||||
|
||||
- materials: include default values of spec constants in material metadata [⚠️ **Recompile Materials**]
|
||||
|
||||
## v1.65.4
|
||||
|
||||
|
||||
## v1.65.3
|
||||
|
||||
|
||||
|
||||
@@ -356,7 +356,6 @@ Java_com_google_android_filament_View_nSetFogOptions(JNIEnv *, jclass , jlong na
|
||||
view->setFogOptions(options);
|
||||
}
|
||||
|
||||
|
||||
extern "C" JNIEXPORT void JNICALL
|
||||
Java_com_google_android_filament_View_nSetBlendMode(JNIEnv *, jclass , jlong nativeView, jint blendMode) {
|
||||
View* view = (View*) nativeView;
|
||||
@@ -555,20 +554,3 @@ Java_com_google_android_filament_View_nClearFrameHistory(JNIEnv *env, jclass cla
|
||||
Engine *engine = (Engine *) nativeEngine;
|
||||
view->clearFrameHistory(*engine);
|
||||
}
|
||||
|
||||
extern "C"
|
||||
JNIEXPORT void JNICALL
|
||||
Java_com_google_android_filament_View_nSetChannelDepthClearEnabled(JNIEnv *, jclass ,
|
||||
jlong nativeView, jint channel, jboolean enabled) {
|
||||
View* view = (View*) nativeView;
|
||||
view->setChannelDepthClearEnabled((uint8_t) channel, (bool) enabled);
|
||||
}
|
||||
|
||||
extern "C"
|
||||
JNIEXPORT jboolean JNICALL
|
||||
Java_com_google_android_filament_View_nIsChannelDepthClearEnabled(JNIEnv *env, jclass clazz,
|
||||
jlong nativeView, jint channel) {
|
||||
// TODO: implement nIsChannelDepthClearEnabled()
|
||||
View* view = (View*) nativeView;
|
||||
return (jboolean)view->isChannelDepthClearEnabled((uint8_t) channel);
|
||||
}
|
||||
|
||||
+4
-4
@@ -332,7 +332,7 @@ public class RenderableManager {
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the channel this renderable is associated to. There can be 8 channels.
|
||||
* Set the channel this renderable is associated to. There can be 4 channels.
|
||||
*
|
||||
* <p>All renderables in a given channel are rendered together, regardless of anything else.
|
||||
* They are sorted as usual within a channel.</p>
|
||||
@@ -342,7 +342,7 @@ public class RenderableManager {
|
||||
* <p>Channels 0 and 1 may not have render primitives using a material with `refractionType`
|
||||
* set to `screenspace`.</p>
|
||||
*
|
||||
* @param channel clamped to the range [0..7], defaults to 2.
|
||||
* @param channel clamped to the range [0..3], defaults to 2.
|
||||
*
|
||||
* @return Builder reference for chaining calls.
|
||||
*
|
||||
@@ -351,7 +351,7 @@ public class RenderableManager {
|
||||
* @see RenderableManager::setBlendOrderAt()
|
||||
*/
|
||||
@NonNull
|
||||
public Builder channel(@IntRange(from = 0, to = 7) int channel) {
|
||||
public Builder channel(@IntRange(from = 0, to = 3) int channel) {
|
||||
nBuilderChannel(mNativeBuilder, channel);
|
||||
return this;
|
||||
}
|
||||
@@ -730,7 +730,7 @@ public class RenderableManager {
|
||||
*
|
||||
* @see Builder#channel
|
||||
*/
|
||||
public void setChannel(@EntityInstance int i, @IntRange(from = 0, to = 7) int channel) {
|
||||
public void setChannel(@EntityInstance int i, @IntRange(from = 0, to = 3) int channel) {
|
||||
nSetChannel(mNativeObject, i, channel);
|
||||
}
|
||||
|
||||
|
||||
@@ -291,25 +291,6 @@ public class View {
|
||||
return mViewport;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether a channel must clear the depth buffer before all primitives are rendered.
|
||||
* Channel depth clear is off by default for all channels.
|
||||
* This is orthogonal to Renderer::setClearOptions().
|
||||
* @param channel between 0 and 7
|
||||
* @param enabled true to enable clear, false to disable
|
||||
*/
|
||||
void setChannelDepthClearEnabled(@IntRange(from = 0, to = 7) int channel, boolean enabled) {
|
||||
nSetChannelDepthClearEnabled(getNativeObject(), channel, enabled);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param channel between 0 and 7
|
||||
* @return true if this channel has depth clear enabled.
|
||||
*/
|
||||
boolean isChannelDepthClearEnabled(@IntRange(from = 0, to = 7) int channel) {
|
||||
return nIsChannelDepthClearEnabled(getNativeObject(), channel);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the blending mode used to draw the view into the SwapChain.
|
||||
*
|
||||
@@ -1337,8 +1318,6 @@ public class View {
|
||||
boolean lensFlare, boolean starburst, float chromaticAberration, int ghostCount, float ghostSpacing, float ghostThreshold, float haloThickness, float haloRadius, float haloThreshold);
|
||||
private static native void nSetFogOptions(long nativeView, float distance, float maximumOpacity, float height, float heightFalloff, float cutOffDistance, float v, float v1, float v2, float density, float inScatteringStart, float inScatteringSize, boolean fogColorFromIbl, long skyColorNativeObject, boolean enabled);
|
||||
private static native void nSetStereoscopicOptions(long nativeView, boolean enabled);
|
||||
private static native void nSetChannelDepthClearEnabled(long nativeView, int channel, boolean enabled);
|
||||
private static native boolean nIsChannelDepthClearEnabled(long nativeView, int channel);
|
||||
private static native void nSetBlendMode(long nativeView, int blendMode);
|
||||
private static native void nSetDepthOfFieldOptions(long nativeView, float cocScale, float maxApertureDiameter, boolean enabled, int filter,
|
||||
boolean nativeResolution, int foregroundRingCount, int backgroundRingCount, int fastGatherRingCount, int maxForegroundCOC, int maxBackgroundCOC);
|
||||
@@ -1636,7 +1615,7 @@ public class View {
|
||||
*
|
||||
* This value is used as a tint instead, when fogColorFromIbl is enabled.
|
||||
*
|
||||
* @see #fogColorFromIbl
|
||||
* @see fogColorFromIbl
|
||||
*/
|
||||
@NonNull @Size(min = 3)
|
||||
public float[] color = {1.0f, 1.0f, 1.0f};
|
||||
@@ -1677,7 +1656,7 @@ public class View {
|
||||
*
|
||||
* `fogColorFromIbl` is ignored when skyTexture is specified.
|
||||
*
|
||||
* @see #skyColor
|
||||
* @see skyColor
|
||||
*/
|
||||
public boolean fogColorFromIbl = false;
|
||||
/**
|
||||
@@ -1695,7 +1674,7 @@ public class View {
|
||||
* In `linearFog` mode mipmap level 0 is always used.
|
||||
*
|
||||
* @see Texture
|
||||
* @see #fogColorFromIbl
|
||||
* @see fogColorFromIbl
|
||||
*/
|
||||
@Nullable
|
||||
public Texture skyColor = null;
|
||||
@@ -1817,8 +1796,7 @@ public class View {
|
||||
/**
|
||||
* Structure used to set the precision of the color buffer and related quality settings.
|
||||
*
|
||||
* @see #setRenderQuality
|
||||
* @see #getRenderQuality
|
||||
* @see setRenderQuality, getRenderQuality
|
||||
*/
|
||||
public static class RenderQuality {
|
||||
/**
|
||||
@@ -1836,7 +1814,7 @@ public class View {
|
||||
|
||||
/**
|
||||
* Options for screen space Ambient Occlusion (SSAO) and Screen Space Cone Tracing (SSCT)
|
||||
* @see #setAmbientOcclusionOptions
|
||||
* @see setAmbientOcclusionOptions()
|
||||
*/
|
||||
public static class AmbientOcclusionOptions {
|
||||
public enum AmbientOcclusionType {
|
||||
@@ -1988,7 +1966,7 @@ public class View {
|
||||
|
||||
/**
|
||||
* Options for Multi-Sample Anti-aliasing (MSAA)
|
||||
* @see #setMultiSampleAntiAliasingOptions
|
||||
* @see setMultiSampleAntiAliasingOptions()
|
||||
*/
|
||||
public static class MultiSampleAntiAliasingOptions {
|
||||
/**
|
||||
@@ -2018,7 +1996,7 @@ public class View {
|
||||
* `feedback` of 0.1 effectively accumulates a maximum of 19 samples in steady state.
|
||||
* see "A Survey of Temporal Antialiasing Techniques" by Lei Yang and all for more information.
|
||||
*
|
||||
* @see #setTemporalAntiAliasingOptions
|
||||
* @see setTemporalAntiAliasingOptions()
|
||||
*/
|
||||
public static class TemporalAntiAliasingOptions {
|
||||
public enum BoxType {
|
||||
@@ -2120,7 +2098,7 @@ public class View {
|
||||
|
||||
/**
|
||||
* Options for Screen-space Reflections.
|
||||
* @see #setScreenSpaceReflectionsOptions
|
||||
* @see setScreenSpaceReflectionsOptions()
|
||||
*/
|
||||
public static class ScreenSpaceReflectionsOptions {
|
||||
/**
|
||||
@@ -2154,9 +2132,7 @@ public class View {
|
||||
|
||||
/**
|
||||
* List of available post-processing anti-aliasing techniques.
|
||||
* @see #setAntiAliasing
|
||||
* @see #getAntiAliasing
|
||||
* @see #setSampleCount
|
||||
* @see setAntiAliasing, getAntiAliasing, setSampleCount
|
||||
*/
|
||||
public enum AntiAliasing {
|
||||
/**
|
||||
@@ -2185,7 +2161,7 @@ public class View {
|
||||
|
||||
/**
|
||||
* List of available shadow mapping techniques.
|
||||
* @see #setShadowType
|
||||
* @see setShadowType
|
||||
*/
|
||||
public enum ShadowType {
|
||||
/**
|
||||
@@ -2209,7 +2185,7 @@ public class View {
|
||||
|
||||
/**
|
||||
* View-level options for VSM Shadowing.
|
||||
* @see #setVsmShadowOptions
|
||||
* @see setVsmShadowOptions()
|
||||
* @warning This API is still experimental and subject to change.
|
||||
*/
|
||||
public static class VsmShadowOptions {
|
||||
@@ -2250,7 +2226,7 @@ public class View {
|
||||
|
||||
/**
|
||||
* View-level options for DPCF and PCSS Shadowing.
|
||||
* @see #setSoftShadowOptions
|
||||
* @see setSoftShadowOptions()
|
||||
* @warning This API is still experimental and subject to change.
|
||||
*/
|
||||
public static class SoftShadowOptions {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
GROUP=com.google.android.filament
|
||||
VERSION_NAME=1.66.0
|
||||
VERSION_NAME=1.65.3
|
||||
|
||||
POM_DESCRIPTION=Real-time physically based rendering engine for Android.
|
||||
|
||||
|
||||
@@ -179,7 +179,7 @@ Google code style and is derived from the Java code style, but not quite.</p>
|
||||
<li>class access modifiers are not indented</li>
|
||||
<li>last line of <code>.cpp</code> or <code>.h</code> file must be an empty line</li>
|
||||
</ul>
|
||||
<pre><code class="language-c++">for (int i = 0; i < max; i++) {
|
||||
<pre><code>for (int i = 0; i < max; i++) {
|
||||
}
|
||||
|
||||
class Foo {
|
||||
@@ -227,23 +227,11 @@ src/data.inc
|
||||
<li><code>public</code> class attributes <em>are not</em> prefixed</li>
|
||||
<li>class attributes and methods are lower camelcase</li>
|
||||
</ul>
|
||||
<pre><code class="language-c++">extern int gGlobalWarming;
|
||||
<pre><code>extern int gGlobalWarming;
|
||||
|
||||
class FooBar {
|
||||
public:
|
||||
FooBar(int attributeName, int sizeInBytes)
|
||||
: mAttributeName(attributeName),
|
||||
sizeInBytes(sizeInBytes) {}
|
||||
|
||||
void reallyLongMethodNameWithLotsOfArguments(bool argument1,
|
||||
int someSecondArgument, int bestArgument) {
|
||||
std::pair<bool, int> pair = {
|
||||
argument1,
|
||||
argument2,
|
||||
};
|
||||
// etc
|
||||
}
|
||||
|
||||
void methodName();
|
||||
int sizeInBytes;
|
||||
private:
|
||||
int mAttributeName;
|
||||
@@ -260,7 +248,7 @@ private:
|
||||
<li>always include the copyright notice at the top of every file</li>
|
||||
<li>make sure the date is correct</li>
|
||||
</ul>
|
||||
<pre><code class="language-c++">/*
|
||||
<pre><code>/*
|
||||
* Copyright (C) 2018 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@@ -305,7 +293,7 @@ conversely containers and algorithms are not allowed. There are exceptions such
|
||||
</li>
|
||||
</ul>
|
||||
<p><em>Sorting the headers is important to help catching missing <code>#include</code> directives.</em></p>
|
||||
<pre><code class="language-c++">/*
|
||||
<pre><code>/*
|
||||
* Copyright (C) 2018 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@@ -348,7 +336,7 @@ from other string types.</li>
|
||||
<ul>
|
||||
<li>Use <code>auto</code> only when the type appears on the same line or with iterators and lambdas.</li>
|
||||
</ul>
|
||||
<pre><code class="language-c++">auto foo = new Foo();
|
||||
<pre><code>auto foo = new Foo();
|
||||
for (auto& i : collection) { }
|
||||
</code></pre>
|
||||
|
||||
|
||||
+2
-2
@@ -181,7 +181,7 @@ important for <code>matc</code> (material compiler).</p>
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation 'com.google.android.filament:filament-android:1.65.3'
|
||||
implementation 'com.google.android.filament:filament-android:1.65.1'
|
||||
}
|
||||
</code></pre>
|
||||
<p>Here are all the libraries available in the group <code>com.google.android.filament</code>:</p>
|
||||
@@ -196,7 +196,7 @@ dependencies {
|
||||
</div>
|
||||
<h3 id="ios"><a class="header" href="#ios">iOS</a></h3>
|
||||
<p>iOS projects can use CocoaPods to install the latest release:</p>
|
||||
<pre><code class="language-shell">pod 'Filament', '~> 1.65.3'
|
||||
<pre><code class="language-shell">pod 'Filament', '~> 1.65.1'
|
||||
</code></pre>
|
||||
<h2 id="documentation"><a class="header" href="#documentation">Documentation</a></h2>
|
||||
<ul>
|
||||
|
||||
+50
-53
@@ -161,92 +161,97 @@
|
||||
<h1 id="rendering-difference-test"><a class="header" href="#rendering-difference-test">Rendering Difference Test</a></h1>
|
||||
<p>We created a few scripts to run <code>gltf_viewer</code> and produce headless renderings.</p>
|
||||
<p>This is mainly useful for continuous integration where GPUs are generally not available on cloud
|
||||
machines. To perform software rasterization, these scripts are centered around <a href="https://docs.mesa3d.org">Mesa</a>'s
|
||||
software rasterizers, but nothing bars us from using another rasterizer like <a href="https://github.com/google/swiftshader">SwiftShader</a>.
|
||||
Additionally, we should be able to use GPUs where available (though this is more of a future
|
||||
work).</p>
|
||||
machines. To perform software rasterization, these scripts are centered around <a href="https://docs.mesa3d.org">Mesa</a>'s software
|
||||
rasterizers, but nothing bars us from using another rasterizer like <a href="https://github.com/google/swiftshader">SwiftShader</a>. Additionally,
|
||||
we should be able to use GPUs where available (though this is more of a future work).</p>
|
||||
<p>The script <code>render.py</code> contains the core logic for taking input parameters (such as the test
|
||||
description file) and then running gltf_viewer to produce the renderings.</p>
|
||||
<p>In the <code>test</code> directory is a list of test descriptions that are specified in json. Please see
|
||||
<p>In the <code>test</code> directory is a list of test descriptions that are specified in json. Please see
|
||||
<code>sample.json</code> to parse the structure.</p>
|
||||
<h2 id="setting-up-python"><a class="header" href="#setting-up-python">Setting up python</a></h2>
|
||||
<p>The <code>renderdiff</code> project uses <code>python</code> extensively. To install the dependencies for producing
|
||||
renderings, do the following step</p>
|
||||
<ul>
|
||||
<li>Set up a virtual environment (from the root directory)
|
||||
<pre><code>python3 -m venv venv
|
||||
. ./venv/bin/activate
|
||||
<pre><code> python3 -m venv venv
|
||||
. ./venv/bin/activate
|
||||
</code></pre>
|
||||
</li>
|
||||
<li>Install the rendering dependencies
|
||||
<pre><code>pip install -r test/renderdiff/src/rendering_requirements.txt
|
||||
<pre><code> pip install -r test/renderdiff/src/rendering_requirements.txt
|
||||
</code></pre>
|
||||
</li>
|
||||
<li>Install the viewer depdencies
|
||||
<pre><code>pip install -r test/renderdiff/src/viewer_requirements.txt
|
||||
<pre><code> pip install -r test/renderdiff/src/viewer_requirements.txt
|
||||
</code></pre>
|
||||
</li>
|
||||
<li>For the commands in the following section, do not exit the virtual environment. Once you've
|
||||
completed all your work, you can exit with
|
||||
<pre><code>deactivate
|
||||
<pre><code> deactivate
|
||||
</code></pre>
|
||||
</li>
|
||||
</ul>
|
||||
<h2 id="running-the-test-locally"><a class="header" href="#running-the-test-locally">Running the test locally</a></h2>
|
||||
<ul>
|
||||
<li>To run the same presbumit as <a href="presubmit-renderdiff"><code>test-renderdiff</code></a>, you can do
|
||||
<li>
|
||||
<p>To run the same presbumit as <a href="presubmit-renderdiff"><code>test-renderdiff</code></a>, you can do</p>
|
||||
<pre><code>bash test/renderdiff/local_test.sh
|
||||
</code></pre>
|
||||
</li>
|
||||
<li>This script will generate the renderings based on the current state of your repo.
|
||||
<li>
|
||||
<p>This script will generate the renderings based on the current state of your repo.
|
||||
Additionally, it will also compare the generated images with corresponding images in the
|
||||
golden repo.</li>
|
||||
<li>To just render without running the test, you could use the following script
|
||||
golden repo.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>To just render without running the test, you could use the following script</p>
|
||||
<pre><code>bash test/renderdiff/generate.sh
|
||||
</code></pre>
|
||||
</li>
|
||||
</ul>
|
||||
<h2 id="filtering-tests"><a class="header" href="#filtering-tests">Filtering Tests</a></h2>
|
||||
<p>You can run a subset of the tests by passing the <code>--test_filter</code> flag to <code>local_test.sh</code>. The
|
||||
filter supports wildcards (<code>*</code>) to match test names. For example, to run all tests in the
|
||||
<code>ClearCoat</code> suite, you can use the following command:</p>
|
||||
<pre><code>bash test/renderdiff/local_test.sh --test_filter='ClearCoat.*.*'
|
||||
</code></pre>
|
||||
<h2 id="update-the-golden-images"><a class="header" href="#update-the-golden-images">Update the golden images</a></h2>
|
||||
<p>The golden images are stored in a github repository:
|
||||
https://github.com/google/filament-assets. Filament team members should have access to write
|
||||
to the repository. A typical flow for updating the goldens is to upload your changed images
|
||||
into <strong>branch</strong> of <code>filament-assets</code>. This branch is paired with a PR or commit on the
|
||||
<code>filament</code> repo.</p>
|
||||
<p>As an example, imagine I am working on a PR, and I've uploaded my change, which is in a
|
||||
branch called <code>my-pr-branch</code>, to <code>filament</code>. This PR requires updating the golden. We would do
|
||||
it in the following fashion</p>
|
||||
<p>The golden images are stored in a github repository: https://github.com/google/filament-assets.
|
||||
Filament team members should have access to write to the repository. A typical flow for updating
|
||||
the goldens is to upload your changed images into <strong>branch</strong> of <code>filament-assets</code>. This branch is
|
||||
paired with a PR or commit on the <code>filament</code> repo.</p>
|
||||
<p>As an example, imagine I am working on a PR, and I've uploaded my change, which is in a branch
|
||||
called <code>my-pr-branch</code>, to <code>filament</code>. This PR requires updating the golden. We would do it
|
||||
in the following fashion</p>
|
||||
<h3 id="using-a-script-to-update-the-golden-repo"><a class="header" href="#using-a-script-to-update-the-golden-repo">Using a script to update the golden repo</a></h3>
|
||||
<ul>
|
||||
<li>Run interactive mode in the <code>update_golden.py</code> script.
|
||||
<li>
|
||||
<p>Run interactive mode in the <code>update_golden.py</code> script.</p>
|
||||
<pre><code>python3 test/renderdiff/src/update_golden.py
|
||||
</code></pre>
|
||||
</li>
|
||||
<li>This will guide you through a series of steps to push the changes to a remote branch on
|
||||
<code>filament-assets</code>.</li>
|
||||
<li>
|
||||
<p>This will guide you through a series of steps to push the changes to a remote branch
|
||||
on <code>filament-assets</code>.</p>
|
||||
</li>
|
||||
</ul>
|
||||
<h3 id="manually-updating-the-golden-repo"><a class="header" href="#manually-updating-the-golden-repo">Manually updating the golden repo</a></h3>
|
||||
<ul>
|
||||
<li>Check out the golden repo
|
||||
<li>
|
||||
<p>Check out the golden repo</p>
|
||||
<pre><code>git clone git@github.com:google/filament-assets.git
|
||||
</code></pre>
|
||||
</li>
|
||||
<li>Create a branch on the golden repo
|
||||
<li>
|
||||
<p>Create a branch on the golden repo</p>
|
||||
<pre><code>cd filament-assets
|
||||
git switch -c my-pr-branch-golden
|
||||
</code></pre>
|
||||
</li>
|
||||
<li>Copy the new images to their appropriate place in <code>filament-assets</code></li>
|
||||
<li>Push the <code>filament-assets</code> working branch to remote
|
||||
<li>
|
||||
<p>Copy the new images to their appropriate place in <code>filament-assets</code></p>
|
||||
</li>
|
||||
<li>
|
||||
<p>Push the <code>filament-assets</code> working branch to remote</p>
|
||||
<pre><code>git push origin my-pr-branch-golden
|
||||
</code></pre>
|
||||
</li>
|
||||
<li>In the commit message of your working branch on <code>filament</code>, add the following line
|
||||
<li>
|
||||
<p>In the commit message of your working branch on <code>filament</code>, add the following line</p>
|
||||
<pre><code>RDIFF_BBRANCH=my-pr-branch-golden
|
||||
</code></pre>
|
||||
</li>
|
||||
@@ -255,17 +260,16 @@ git switch -c my-pr-branch-golden
|
||||
<ul>
|
||||
<li>The presubmit test <a href="https://github.com/google/filament/blob/e85dfe75c86106a05019e13ccdbef67e030af675/.github/workflows/presubmit.yml#L118"><code>test-renderdiff</code></a> will test against the provided
|
||||
branch of the golden repo (i.e. <code>my-pr-branch-golden</code>).</li>
|
||||
<li>If the PR is merged, then there is another workflow that will merge <code>my-pr-branch-golden</code>
|
||||
to the <code>main</code> branch of the golden repo.</li>
|
||||
<li>If the PR is merged, then there is another workflow that will merge <code>my-pr-branch-golden</code> to
|
||||
the <code>main</code> branch of the golden repo.</li>
|
||||
</ul>
|
||||
<h2 id="viewing-test-results"><a class="header" href="#viewing-test-results">Viewing test results</a></h2>
|
||||
<p>We provide a viewer for looking at the result of a test run. The viewer is a webapp that can
|
||||
be used by pointing your browser to a localhost port. If you input the viewer with a PR or a
|
||||
directory, it will parse the test result and show the results and the rendered and/or golden
|
||||
images.</p>
|
||||
<p>We provide a viewer for looking at the result of a test run. The viewer is a webapp that can be used by
|
||||
pointing your browser to a localhost port. If you input the viewer with a PR or a directory, it will
|
||||
parse the test result and show the results and the rendered and/or golden images.</p>
|
||||
<p><img src="../images/renderdiff_example.png" alt="Viewer" /></p>
|
||||
<p>To run the viewer of a test output directory that has been generated locally, you would run
|
||||
the following</p>
|
||||
<p>To run the viewer of a test output directory that has been generated locally, you would run the
|
||||
following</p>
|
||||
<pre><code>python3 test/renderdiff/src/viewer.py --diff=[test output]
|
||||
</code></pre>
|
||||
<p>where <code>[test output]</code> is a directory containing the <code>compare_results.json</code> of the test run.
|
||||
@@ -274,15 +278,8 @@ For example, it could be <code>out/renderdiff/diffs/presubmit</code> for the sta
|
||||
<p>To see the results of a Pull Request initiated test run, you would do the following</p>
|
||||
<pre><code>python3 test/renderdiff/src/viewer.py --pr_number=[PR #] --github_token=[github token]
|
||||
</code></pre>
|
||||
<p>where <code>[PR #]</code> is the numeric ID of your pull request, and the <code>[github token]</code> is an acess
|
||||
token that you (as a github user) needs to generate (<a href="https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/managing-your-personal-access-tokens">reference</a>).</p>
|
||||
<p>To see the results of a specific run, you would do the following</p>
|
||||
<pre><code>python3 test/renderdiff/src/viewer.py --run_number=[RUN #] --github_token=[github token]
|
||||
</code></pre>
|
||||
<p>where <code>[RUN #]</code> is the numeric ID of the run. You can find the run number in the URL of the
|
||||
GitHub Actions page. For example, in the URL
|
||||
<code>https://github.com/google/filament/actions/runs/18023632663/job/51286323708?pr=9264</code>,
|
||||
the run number is <code>18023632663</code>.</p>
|
||||
<p>where <code>[PR #]</code> is the numeric ID of your pull request, and the <code>[github token]</code> is an acess token
|
||||
that you (as a github user) needs to generate (<a href="https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/managing-your-personal-access-tokens">reference</a>).</p>
|
||||
|
||||
</main>
|
||||
|
||||
|
||||
+1
-1
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -249,10 +249,9 @@ set(PRIVATE_HDRS
|
||||
set(MATERIAL_SRCS
|
||||
src/materials/antiAliasing/fxaa/fxaa.mat
|
||||
src/materials/antiAliasing/taa/taa.mat
|
||||
src/materials/blitArray.mat
|
||||
src/materials/blitDepth.mat
|
||||
src/materials/blitLow.mat
|
||||
src/materials/clearDepth.mat
|
||||
src/materials/blitArray.mat
|
||||
src/materials/bloom/bloomDownsample.mat
|
||||
src/materials/bloom/bloomDownsample2x.mat
|
||||
src/materials/bloom/bloomDownsample9.mat
|
||||
|
||||
@@ -179,7 +179,6 @@ endif()
|
||||
if (FILAMENT_SUPPORTS_VULKAN)
|
||||
list(APPEND SRCS
|
||||
include/backend/platforms/VulkanPlatform.h
|
||||
src/vulkan/VulkanAsyncHandles.cpp
|
||||
src/vulkan/VulkanAsyncHandles.h
|
||||
src/vulkan/VulkanBlitter.cpp
|
||||
src/vulkan/VulkanBlitter.h
|
||||
@@ -218,10 +217,6 @@ if (FILAMENT_SUPPORTS_VULKAN)
|
||||
src/vulkan/VulkanReadPixels.h
|
||||
src/vulkan/VulkanSamplerCache.cpp
|
||||
src/vulkan/VulkanSamplerCache.h
|
||||
src/vulkan/VulkanSemaphore.cpp
|
||||
src/vulkan/VulkanSemaphore.h
|
||||
src/vulkan/VulkanSemaphoreManager.cpp
|
||||
src/vulkan/VulkanSemaphoreManager.h
|
||||
src/vulkan/VulkanStagePool.cpp
|
||||
src/vulkan/VulkanStagePool.h
|
||||
src/vulkan/VulkanSwapChain.cpp
|
||||
|
||||
@@ -197,7 +197,6 @@ constexpr std::string_view to_string(Backend const backend) noexcept {
|
||||
* - The Metal backend can prefer precompiled Metal libraries, while falling back to MSL.
|
||||
*/
|
||||
enum class ShaderLanguage {
|
||||
UNSPECIFIED = -1,
|
||||
ESSL1 = 0,
|
||||
ESSL3 = 1,
|
||||
SPIRV = 2,
|
||||
@@ -220,8 +219,6 @@ constexpr const char* shaderLanguageToString(ShaderLanguage shaderLanguage) noex
|
||||
return "Metal precompiled library";
|
||||
case ShaderLanguage::WGSL:
|
||||
return "WGSL";
|
||||
case ShaderLanguage::UNSPECIFIED:
|
||||
return "Unspecified";
|
||||
}
|
||||
return "UNKNOWN";
|
||||
}
|
||||
@@ -713,12 +710,6 @@ enum class Precision : uint8_t {
|
||||
DEFAULT
|
||||
};
|
||||
|
||||
union ConstantValue {
|
||||
int32_t i;
|
||||
float f;
|
||||
bool b;
|
||||
};
|
||||
|
||||
/**
|
||||
* Shader compiler priority queue
|
||||
*
|
||||
@@ -1703,8 +1694,6 @@ enum class Workaround : uint16_t {
|
||||
// prevents these stutters by not precaching depth variants of the default material for those
|
||||
// particular browsers.
|
||||
DISABLE_DEPTH_PRECACHE_FOR_DEFAULT_MATERIAL,
|
||||
// Emulate an sRGB swapchain in shader code.
|
||||
EMULATE_SRGB_SWAPCHAIN,
|
||||
};
|
||||
|
||||
using StereoscopicType = backend::Platform::StereoscopicType;
|
||||
|
||||
@@ -236,7 +236,7 @@ public:
|
||||
* @return nullptr on failure, or a pointer to the newly created driver.
|
||||
*/
|
||||
virtual Driver* UTILS_NULLABLE createDriver(void* UTILS_NULLABLE sharedContext,
|
||||
const DriverConfig& driverConfig) = 0;
|
||||
const DriverConfig& driverConfig) noexcept = 0;
|
||||
|
||||
/**
|
||||
* Processes the platform's event queue when called from its primary event-handling thread.
|
||||
|
||||
@@ -50,7 +50,11 @@ public:
|
||||
descriptor_binding_t binding;
|
||||
};
|
||||
|
||||
using SpecializationConstant = std::variant<int32_t, float, bool>;
|
||||
struct SpecializationConstant {
|
||||
using Type = std::variant<int32_t, float, bool>;
|
||||
uint32_t id; // id set in glsl
|
||||
Type value; // value and type
|
||||
};
|
||||
|
||||
struct Uniform { // For ES2 support
|
||||
utils::CString name; // full qualified name of the uniform field
|
||||
@@ -114,7 +118,7 @@ public:
|
||||
Program& multiview(bool multiview) noexcept;
|
||||
|
||||
// For ES2 support only...
|
||||
Program& uniforms(uint32_t index, utils::CString name, UniformInfo uniforms);
|
||||
Program& uniforms(uint32_t index, utils::CString name, UniformInfo uniforms) noexcept;
|
||||
Program& attributes(AttributesInfo attributes) noexcept;
|
||||
|
||||
//
|
||||
|
||||
@@ -112,7 +112,7 @@ public:
|
||||
*
|
||||
*/
|
||||
virtual SwapChain* UTILS_NULLABLE createSwapChain(
|
||||
void* UTILS_NULLABLE nativeWindow, uint64_t flags) = 0;
|
||||
void* UTILS_NULLABLE nativeWindow, uint64_t flags) noexcept = 0;
|
||||
|
||||
/**
|
||||
* Called by the driver create a headless SwapChain.
|
||||
@@ -126,7 +126,7 @@ public:
|
||||
* A void* might be enough.
|
||||
*/
|
||||
virtual SwapChain* UTILS_NULLABLE createSwapChain(
|
||||
uint32_t width, uint32_t height, uint64_t flags) = 0;
|
||||
uint32_t width, uint32_t height, uint64_t flags) noexcept = 0;
|
||||
|
||||
/**
|
||||
* Called by the driver to destroys the SwapChain
|
||||
|
||||
@@ -40,7 +40,7 @@ protected:
|
||||
// Platform Interface
|
||||
|
||||
Driver* createDriver(void* sharedContext,
|
||||
const DriverConfig& driverConfig) override;
|
||||
const DriverConfig& driverConfig) noexcept override;
|
||||
|
||||
// Currently returns 0
|
||||
int getOSVersion() const noexcept override;
|
||||
|
||||
@@ -38,7 +38,7 @@ public:
|
||||
// Platform Interface
|
||||
|
||||
Driver* createDriver(void* sharedGLContext,
|
||||
const DriverConfig& driverConfig) override;
|
||||
const DriverConfig& driverConfig) noexcept override;
|
||||
|
||||
int getOSVersion() const noexcept final { return 0; }
|
||||
|
||||
|
||||
@@ -80,7 +80,7 @@ protected:
|
||||
* Initializes EGL, creates the OpenGL context and returns a concrete Driver implementation
|
||||
* that supports OpenGL/OpenGL ES.
|
||||
*/
|
||||
Driver* createDriver(void* sharedContext, const DriverConfig& driverConfig) override;
|
||||
Driver* createDriver(void* sharedContext, const DriverConfig& driverConfig) noexcept override;
|
||||
|
||||
/**
|
||||
* This returns zero. This method can be overridden to return something more useful.
|
||||
@@ -101,8 +101,8 @@ protected:
|
||||
bool isSRGBSwapChainSupported() const noexcept override;
|
||||
bool isMSAASwapChainSupported(uint32_t samples) const noexcept override;
|
||||
|
||||
SwapChain* createSwapChain(void* nativewindow, uint64_t flags) override;
|
||||
SwapChain* createSwapChain(uint32_t width, uint32_t height, uint64_t flags) override;
|
||||
SwapChain* createSwapChain(void* nativewindow, uint64_t flags) noexcept override;
|
||||
SwapChain* createSwapChain(uint32_t width, uint32_t height, uint64_t flags) noexcept override;
|
||||
void destroySwapChain(SwapChain* swapChain) noexcept override;
|
||||
bool isSwapChainProtected(SwapChain* swapChain) noexcept override;
|
||||
|
||||
|
||||
@@ -80,7 +80,7 @@ protected:
|
||||
int getOSVersion() const noexcept override;
|
||||
|
||||
Driver* createDriver(void* sharedContext,
|
||||
const Platform::DriverConfig& driverConfig) override;
|
||||
const Platform::DriverConfig& driverConfig) noexcept override;
|
||||
|
||||
// --------------------------------------------------------------------------------------------
|
||||
// OpenGLPlatform Interface
|
||||
|
||||
@@ -29,7 +29,7 @@ public:
|
||||
PlatformEGLHeadless() noexcept;
|
||||
|
||||
Driver* createDriver(void* sharedContext,
|
||||
const Platform::DriverConfig& driverConfig) override;
|
||||
const Platform::DriverConfig& driverConfig) noexcept override;
|
||||
|
||||
protected:
|
||||
bool isOpenGL() const noexcept override;
|
||||
|
||||
@@ -39,7 +39,7 @@ protected:
|
||||
// Platform Interface
|
||||
|
||||
Driver* createDriver(void* sharedGLContext,
|
||||
const DriverConfig& driverConfig) override;
|
||||
const DriverConfig& driverConfig) noexcept override;
|
||||
|
||||
int getOSVersion() const noexcept final override { return 0; }
|
||||
|
||||
@@ -55,9 +55,9 @@ protected:
|
||||
void commit(SwapChain* swapChain) noexcept override;
|
||||
|
||||
private:
|
||||
Display* mGLXDisplay;
|
||||
GLXContext mGLXContext{};
|
||||
GLXFBConfig mGLXConfig{};
|
||||
Display *mGLXDisplay;
|
||||
GLXContext mGLXContext;
|
||||
GLXFBConfig* mGLXConfig;
|
||||
GLXPbuffer mDummySurface;
|
||||
std::vector<GLXPbuffer> mPBuffers;
|
||||
};
|
||||
|
||||
@@ -36,7 +36,7 @@ public:
|
||||
PlatformMetal();
|
||||
~PlatformMetal() noexcept override;
|
||||
|
||||
Driver* createDriver(void* sharedContext, const Platform::DriverConfig& driverConfig) override;
|
||||
Driver* createDriver(void* sharedContext, const Platform::DriverConfig& driverConfig) noexcept override;
|
||||
int getOSVersion() const noexcept override { return 0; }
|
||||
|
||||
/**
|
||||
|
||||
@@ -43,7 +43,7 @@ protected:
|
||||
// --------------------------------------------------------------------------------------------
|
||||
// Platform Interface
|
||||
|
||||
Driver* createDriver(void* sharedGLContext, const DriverConfig& driverConfig) override;
|
||||
Driver* createDriver(void* sharedGLContext, const DriverConfig& driverConfig) noexcept override;
|
||||
|
||||
int getOSVersion() const noexcept final override { return 0; }
|
||||
|
||||
|
||||
@@ -38,7 +38,7 @@ protected:
|
||||
// Platform Interface
|
||||
|
||||
Driver* createDriver(void* sharedGLContext,
|
||||
const Platform::DriverConfig& driverConfig) override;
|
||||
const Platform::DriverConfig& driverConfig) noexcept override;
|
||||
|
||||
int getOSVersion() const noexcept final override { return 0; }
|
||||
|
||||
@@ -61,12 +61,8 @@ protected:
|
||||
HWND mHWnd = NULL;
|
||||
HDC mWhdc = NULL;
|
||||
PIXELFORMATDESCRIPTOR mPfd = {};
|
||||
std::vector<int> mAttribs;
|
||||
|
||||
// For shared contexts
|
||||
static constexpr int SHARED_CONTEXT_NUM = 1;
|
||||
std::vector<HGLRC> mAdditionalContexts;
|
||||
std::atomic<int> mNextFreeSharedContextIndex{0};
|
||||
std::vector<int> mAttribs;
|
||||
};
|
||||
|
||||
} // namespace filament::backend
|
||||
|
||||
@@ -34,7 +34,7 @@ protected:
|
||||
// Platform Interface
|
||||
|
||||
Driver* createDriver(void* sharedGLContext,
|
||||
const Platform::DriverConfig& driverConfig) override;
|
||||
const Platform::DriverConfig& driverConfig) noexcept override;
|
||||
|
||||
int getOSVersion() const noexcept override;
|
||||
|
||||
|
||||
@@ -119,7 +119,7 @@ public:
|
||||
~VulkanPlatform() override;
|
||||
|
||||
Driver* createDriver(void* sharedContext,
|
||||
Platform::DriverConfig const& driverConfig) override;
|
||||
Platform::DriverConfig const& driverConfig) noexcept override;
|
||||
|
||||
int getOSVersion() const noexcept override {
|
||||
return 0;
|
||||
|
||||
@@ -72,7 +72,7 @@ public:
|
||||
|
||||
protected:
|
||||
[[nodiscard]] Driver* createDriver(void* sharedContext,
|
||||
const Platform::DriverConfig& driverConfig) override;
|
||||
const Platform::DriverConfig& driverConfig) noexcept override;
|
||||
|
||||
private:
|
||||
// returns adapter request option variations applicable for the particular
|
||||
|
||||
@@ -61,7 +61,7 @@ class CommandBase {
|
||||
protected:
|
||||
using Execute = Dispatcher::Execute;
|
||||
|
||||
constexpr explicit CommandBase(Execute const execute) noexcept : mExecute(execute) {}
|
||||
constexpr explicit CommandBase(Execute execute) noexcept : mExecute(execute) {}
|
||||
|
||||
public:
|
||||
// alignment of all Commands in the CommandStream
|
||||
@@ -70,7 +70,7 @@ public:
|
||||
}
|
||||
|
||||
// executes this command and returns the next one
|
||||
CommandBase* execute(Driver& driver) {
|
||||
inline CommandBase* execute(Driver& driver) {
|
||||
// returning the next command by output parameter allows the compiler to perform the
|
||||
// tail-call optimization in the function called by mExecute, however that comes at
|
||||
// a cost here (writing and reading the stack at each iteration), in the end it's
|
||||
@@ -80,7 +80,7 @@ public:
|
||||
return reinterpret_cast<CommandBase*>(reinterpret_cast<intptr_t>(this) + next);
|
||||
}
|
||||
|
||||
~CommandBase() noexcept = default;
|
||||
inline ~CommandBase() noexcept = default;
|
||||
|
||||
private:
|
||||
Execute mExecute;
|
||||
@@ -135,7 +135,7 @@ struct CommandType<void (Driver::*)(ARGS...)> {
|
||||
|
||||
public:
|
||||
template<typename M, typename D>
|
||||
static void execute(M&& method, D&& driver, CommandBase* base, intptr_t* next) {
|
||||
static inline void execute(M&& method, D&& driver, CommandBase* base, intptr_t* next) {
|
||||
Command* self = static_cast<Command*>(base);
|
||||
*next = align(sizeof(Command));
|
||||
#if DEBUG_COMMAND_STREAM
|
||||
@@ -147,15 +147,15 @@ struct CommandType<void (Driver::*)(ARGS...)> {
|
||||
}
|
||||
|
||||
// A command can be moved
|
||||
Command(Command&& rhs) noexcept = default;
|
||||
inline Command(Command&& rhs) noexcept = default;
|
||||
|
||||
template<typename... A>
|
||||
explicit constexpr Command(Execute const execute, A&& ... args) noexcept
|
||||
inline explicit constexpr Command(Execute execute, A&& ... args)
|
||||
: CommandBase(execute), mArgs(std::forward<A>(args)...) {
|
||||
}
|
||||
|
||||
// placement new declared as "throw" to avoid the compiler's null-check
|
||||
void* operator new(std::size_t, void* ptr) noexcept {
|
||||
inline void* operator new(std::size_t, void* ptr) {
|
||||
assert_invariant(ptr);
|
||||
return ptr;
|
||||
}
|
||||
@@ -171,9 +171,8 @@ class CustomCommand : public CommandBase {
|
||||
std::function<void()> mCommand;
|
||||
static void execute(Driver&, CommandBase* base, intptr_t* next);
|
||||
public:
|
||||
CustomCommand(CustomCommand&& rhs) = default;
|
||||
|
||||
explicit CustomCommand(std::function<void()> cmd)
|
||||
inline CustomCommand(CustomCommand&& rhs) = default;
|
||||
inline explicit CustomCommand(std::function<void()> cmd)
|
||||
: CommandBase(execute), mCommand(std::move(cmd)) { }
|
||||
};
|
||||
|
||||
@@ -185,7 +184,7 @@ class NoopCommand : public CommandBase {
|
||||
*next = static_cast<NoopCommand*>(self)->mNext;
|
||||
}
|
||||
public:
|
||||
constexpr explicit NoopCommand(void* next) noexcept
|
||||
inline constexpr explicit NoopCommand(void* next) noexcept
|
||||
: CommandBase(execute), mNext(intptr_t((char *)next - (char *)this)) { }
|
||||
};
|
||||
|
||||
@@ -208,8 +207,8 @@ class CommandStream {
|
||||
template<typename T>
|
||||
struct AutoExecute {
|
||||
T closure;
|
||||
explicit AutoExecute(T&& closure) : closure(std::forward<T>(closure)) {}
|
||||
~AutoExecute() { closure(); }
|
||||
inline explicit AutoExecute(T&& closure) : closure(std::forward<T>(closure)) {}
|
||||
inline ~AutoExecute() { closure(); }
|
||||
};
|
||||
|
||||
public:
|
||||
@@ -222,7 +221,7 @@ public:
|
||||
|
||||
public:
|
||||
#define DECL_DRIVER_API(methodName, paramsDecl, params) \
|
||||
inline void methodName(paramsDecl) noexcept { \
|
||||
inline void methodName(paramsDecl) { \
|
||||
DEBUG_COMMAND_BEGIN(methodName, false, params); \
|
||||
using Cmd = COMMAND_TYPE(methodName); \
|
||||
void* const p = allocateCommand(CommandBase::align(sizeof(Cmd))); \
|
||||
@@ -231,7 +230,7 @@ public:
|
||||
}
|
||||
|
||||
#define DECL_DRIVER_API_SYNCHRONOUS(RetType, methodName, paramsDecl, params) \
|
||||
inline RetType methodName(paramsDecl) noexcept { \
|
||||
inline RetType methodName(paramsDecl) { \
|
||||
DEBUG_COMMAND_BEGIN(methodName, true, params); \
|
||||
AutoExecute callOnExit([=, this](){ \
|
||||
DEBUG_COMMAND_END(methodName, true); \
|
||||
@@ -240,7 +239,7 @@ public:
|
||||
}
|
||||
|
||||
#define DECL_DRIVER_API_RETURN(RetType, methodName, paramsDecl, params) \
|
||||
inline RetType methodName(paramsDecl) noexcept { \
|
||||
inline RetType methodName(paramsDecl) { \
|
||||
DEBUG_COMMAND_BEGIN(methodName, false, params); \
|
||||
RetType result = mDriver.methodName##S(); \
|
||||
using Cmd = COMMAND_TYPE(methodName##R); \
|
||||
@@ -256,7 +255,7 @@ public:
|
||||
// This is for debugging only. Currently, CircularBuffer can only be written from a
|
||||
// single thread. In debug builds we assert this condition.
|
||||
// Call this first in the render loop.
|
||||
void debugThreading() noexcept {
|
||||
inline void debugThreading() noexcept {
|
||||
#ifndef NDEBUG
|
||||
mThreadId = utils::ThreadUtils::getThreadId();
|
||||
#endif
|
||||
@@ -282,11 +281,11 @@ public:
|
||||
*/
|
||||
template<typename PodType,
|
||||
typename = typename std::enable_if<std::is_trivially_destructible<PodType>::value>::type>
|
||||
PodType* allocatePod(
|
||||
inline PodType* allocatePod(
|
||||
size_t count = 1, size_t alignment = alignof(PodType)) noexcept;
|
||||
|
||||
private:
|
||||
void* allocateCommand(size_t const size) noexcept {
|
||||
inline void* allocateCommand(size_t size) {
|
||||
assert_invariant(utils::ThreadUtils::isThisThread(mThreadId));
|
||||
return mCurrentBuffer.allocate(size);
|
||||
}
|
||||
|
||||
@@ -27,8 +27,6 @@
|
||||
#include <backend/AcquiredImage.h>
|
||||
|
||||
#include <utils/CString.h>
|
||||
#include <utils/ImmutableCString.h>
|
||||
#include <utils/FixedCapacityVector.h>
|
||||
#include <utils/compiler.h>
|
||||
|
||||
#include <functional>
|
||||
@@ -73,11 +71,7 @@ public:
|
||||
|
||||
virtual ShaderModel getShaderModel() const noexcept = 0;
|
||||
|
||||
// The shader languages used for shaders for this driver in order of preference, used to inform
|
||||
// matdbg.
|
||||
//
|
||||
// The `preferredLanguage` is only a hint. If the backend supports it, it will appear first in
|
||||
// the list.
|
||||
// The shader language used for shaders for this driver, used to inform matdbg.
|
||||
//
|
||||
// For OpenGL, this distinguishes whether the driver's shaders are powered by ESSL1 or ESSL3.
|
||||
// This information is used by matdbg to display the correct shader code to the web UI and patch
|
||||
@@ -85,8 +79,7 @@ public:
|
||||
//
|
||||
// Metal shaders can either be MSL or Metal libraries, but at time of writing, matdbg can only
|
||||
// interface with MSL.
|
||||
virtual utils::FixedCapacityVector<ShaderLanguage> getShaderLanguages(
|
||||
ShaderLanguage preferredLanguage) const noexcept = 0;
|
||||
virtual ShaderLanguage getShaderLanguage() const noexcept = 0;
|
||||
|
||||
// Returns the dispatcher. This is only called once during initialization of the CommandStream,
|
||||
// so it doesn't matter that it's virtual.
|
||||
|
||||
@@ -108,15 +108,15 @@
|
||||
DECL_DRIVER_API_RETURN(R, N, PAIR_ARGS_N(ARG, ##__VA_ARGS__), PAIR_ARGS_N(PARAM, ##__VA_ARGS__))
|
||||
|
||||
#define DECL_DRIVER_API_TAGGED_R_N(R, N, ...) \
|
||||
DECL_DRIVER_API_RETURN(R, N, PAIR_ARGS_N(ARG, ##__VA_ARGS__, utils::ImmutableCString&&, tag = {}), \
|
||||
PAIR_ARGS_N(PARAM, ##__VA_ARGS__, utils::ImmutableCString&&, tag))
|
||||
DECL_DRIVER_API_RETURN(R, N, PAIR_ARGS_N(ARG, ##__VA_ARGS__, utils::CString&&, tag = {}), \
|
||||
PAIR_ARGS_N(PARAM, ##__VA_ARGS__, utils::CString&&, tag))
|
||||
|
||||
#define DECL_DRIVER_API_SYNCHRONOUS_N(R, N, ...) \
|
||||
DECL_DRIVER_API_SYNCHRONOUS(R, N, PAIR_ARGS_N(ARG, ##__VA_ARGS__), PAIR_ARGS_N(PARAM, ##__VA_ARGS__))
|
||||
|
||||
#define DECL_DRIVER_API_SYNCHRONOUS_TAGGED_N(R, N, ...) \
|
||||
DECL_DRIVER_API_SYNCHRONOUS(R, N, PAIR_ARGS_N(ARG, ##__VA_ARGS__, utils::ImmutableCString, tag = {}), \
|
||||
PAIR_ARGS_N(PARAM, ##__VA_ARGS__, utils::ImmutableCString, tag))
|
||||
DECL_DRIVER_API_SYNCHRONOUS(R, N, PAIR_ARGS_N(ARG, ##__VA_ARGS__, utils::CString, tag = {}), \
|
||||
PAIR_ARGS_N(PARAM, ##__VA_ARGS__, utils::CString, tag))
|
||||
|
||||
// on some compilers the ##__VA_ARGS__ hack is not supported, so we can't handle 0-parameter APIs
|
||||
// with DECL_DRIVER_API_SYNCHRONOUS_N
|
||||
@@ -336,7 +336,6 @@ DECL_DRIVER_API_SYNCHRONOUS_N(void, setStreamDimensions, backend::StreamHandle,
|
||||
DECL_DRIVER_API_SYNCHRONOUS_N(int64_t, getStreamTimestamp, backend::StreamHandle, stream)
|
||||
DECL_DRIVER_API_SYNCHRONOUS_N(void, updateStreams, backend::DriverApi*, driver)
|
||||
DECL_DRIVER_API_SYNCHRONOUS_N(backend::FenceStatus, getFenceStatus, backend::FenceHandle, fh)
|
||||
DECL_DRIVER_API_SYNCHRONOUS_N(backend::FenceStatus, fenceWait, backend::FenceHandle, fh, uint64_t, timeout)
|
||||
DECL_DRIVER_API_SYNCHRONOUS_N(void, getPlatformSync, backend::SyncHandle, sh,
|
||||
backend::CallbackHandler*, handler, backend::Platform::SyncCallback, cb, void*, userData)
|
||||
DECL_DRIVER_API_SYNCHRONOUS_N(bool, isTextureFormatSupported, backend::TextureFormat, format)
|
||||
@@ -417,6 +416,14 @@ DECL_DRIVER_API_N(setExternalStream,
|
||||
backend::TextureHandle, th,
|
||||
backend::StreamHandle, sh)
|
||||
|
||||
DECL_DRIVER_API_N(beginRenderPass,
|
||||
backend::RenderTargetHandle, rth,
|
||||
const backend::RenderPassParams&, params)
|
||||
|
||||
DECL_DRIVER_API_0(endRenderPass)
|
||||
|
||||
DECL_DRIVER_API_0(nextSubpass)
|
||||
|
||||
DECL_DRIVER_API_N(beginTimerQuery,
|
||||
backend::TimerQueryHandle, tqh)
|
||||
|
||||
@@ -449,36 +456,6 @@ DECL_DRIVER_API_N(copyToMemoryMappedBuffer,
|
||||
size_t, offset,
|
||||
backend::BufferDescriptor&&, data)
|
||||
|
||||
DECL_DRIVER_API_N(setPushConstant,
|
||||
backend::ShaderStage, stage,
|
||||
uint8_t, index,
|
||||
backend::PushConstantVariant, value)
|
||||
|
||||
/*
|
||||
* Setting rendering state
|
||||
* -----------------------
|
||||
*/
|
||||
|
||||
DECL_DRIVER_API_N(beginRenderPass,
|
||||
backend::RenderTargetHandle, rth,
|
||||
const backend::RenderPassParams&, params)
|
||||
|
||||
DECL_DRIVER_API_0(endRenderPass)
|
||||
|
||||
DECL_DRIVER_API_0(nextSubpass)
|
||||
|
||||
DECL_DRIVER_API_N(bindPipeline,
|
||||
backend::PipelineState const&, state)
|
||||
|
||||
DECL_DRIVER_API_N(bindRenderPrimitive,
|
||||
backend::RenderPrimitiveHandle, rph)
|
||||
|
||||
DECL_DRIVER_API_N(bindDescriptorSet,
|
||||
backend::DescriptorSetHandle, dsh,
|
||||
backend::descriptor_set_t, set,
|
||||
backend::DescriptorSetOffsetArray&&, offsets
|
||||
)
|
||||
|
||||
/*
|
||||
* Swap chain
|
||||
*/
|
||||
@@ -496,6 +473,11 @@ DECL_DRIVER_API_N(commit,
|
||||
* -----------------------
|
||||
*/
|
||||
|
||||
DECL_DRIVER_API_N(setPushConstant,
|
||||
backend::ShaderStage, stage,
|
||||
uint8_t, index,
|
||||
backend::PushConstantVariant, value)
|
||||
|
||||
DECL_DRIVER_API_N(insertEventMarker,
|
||||
const char*, string)
|
||||
|
||||
@@ -556,6 +538,18 @@ DECL_DRIVER_API_N(blit,
|
||||
math::uint2, srcOrigin,
|
||||
math::uint2, size)
|
||||
|
||||
DECL_DRIVER_API_N(bindPipeline,
|
||||
backend::PipelineState const&, state)
|
||||
|
||||
DECL_DRIVER_API_N(bindRenderPrimitive,
|
||||
backend::RenderPrimitiveHandle, rph)
|
||||
|
||||
DECL_DRIVER_API_N(bindDescriptorSet,
|
||||
backend::DescriptorSetHandle, dsh,
|
||||
backend::descriptor_set_t, set,
|
||||
backend::DescriptorSetOffsetArray&&, offsets
|
||||
)
|
||||
|
||||
DECL_DRIVER_API_N(draw2,
|
||||
uint32_t, indexOffset,
|
||||
uint32_t, indexCount,
|
||||
|
||||
@@ -21,7 +21,6 @@
|
||||
|
||||
#include <utils/Allocator.h>
|
||||
#include <utils/CString.h>
|
||||
#include <utils/ImmutableCString.h>
|
||||
#include <utils/Log.h>
|
||||
#include <utils/Panic.h>
|
||||
#include <utils/compiler.h>
|
||||
@@ -53,16 +52,16 @@ namespace filament::backend {
|
||||
class DebugTag {
|
||||
public:
|
||||
DebugTag();
|
||||
void writePoolHandleTag(HandleBase::HandleId key, utils::ImmutableCString&& tag) noexcept;
|
||||
void writeHeapHandleTag(HandleBase::HandleId key, utils::ImmutableCString&& tag) noexcept;
|
||||
utils::ImmutableCString findHandleTag(HandleBase::HandleId key) const noexcept;
|
||||
void writePoolHandleTag(HandleBase::HandleId key, utils::CString&& tag) noexcept;
|
||||
void writeHeapHandleTag(HandleBase::HandleId key, utils::CString&& tag) noexcept;
|
||||
utils::CString findHandleTag(HandleBase::HandleId key) const noexcept;
|
||||
|
||||
private:
|
||||
// This is used to associate a tag to a handle. mDebugTags is only written the in the main
|
||||
// driver thread, but it can be accessed from any thread, because it's called from handle_cast<>
|
||||
// which is used by synchronous calls.
|
||||
mutable utils::Mutex mDebugTagLock;
|
||||
tsl::robin_map<HandleBase::HandleId, utils::ImmutableCString> mDebugTags;
|
||||
tsl::robin_map<HandleBase::HandleId, utils::CString> mDebugTags;
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -71,12 +70,12 @@ private:
|
||||
template<size_t P0, size_t P1, size_t P2>
|
||||
class HandleAllocator : public DebugTag {
|
||||
public:
|
||||
HandleAllocator(const char* name, size_t size);
|
||||
HandleAllocator(const char* name, size_t size) noexcept;
|
||||
HandleAllocator(const char* name, size_t size,
|
||||
bool disableUseAfterFreeCheck, bool disableHeapHandleTags);
|
||||
bool disableUseAfterFreeCheck, bool disableHeapHandleTags) noexcept;
|
||||
HandleAllocator(HandleAllocator const& rhs) = delete;
|
||||
HandleAllocator& operator=(HandleAllocator const& rhs) = delete;
|
||||
~HandleAllocator() noexcept;
|
||||
~HandleAllocator();
|
||||
|
||||
/*
|
||||
* Constructs a D object and returns a Handle<D>
|
||||
@@ -107,7 +106,7 @@ public:
|
||||
*
|
||||
*/
|
||||
template<typename D>
|
||||
Handle<D> allocate() {
|
||||
Handle<D> allocate() noexcept {
|
||||
Handle<D> h{ allocateHandle<D>() };
|
||||
return h;
|
||||
}
|
||||
@@ -223,7 +222,7 @@ public:
|
||||
return static_cast<Dp>(p);
|
||||
}
|
||||
|
||||
utils::ImmutableCString getHandleTag(HandleBase::HandleId key) const noexcept;
|
||||
utils::CString getHandleTag(HandleBase::HandleId key) const noexcept;
|
||||
|
||||
template<typename B>
|
||||
bool is_valid(Handle<B>& handle) {
|
||||
@@ -249,7 +248,7 @@ public:
|
||||
return handle_cast<Dp>(const_cast<Handle<B>&>(handle));
|
||||
}
|
||||
|
||||
void associateTagToHandle(HandleBase::HandleId id, utils::ImmutableCString&& tag) noexcept {
|
||||
void associateTagToHandle(HandleBase::HandleId id, utils::CString&& tag) noexcept {
|
||||
if (tag.empty()) {
|
||||
return;
|
||||
}
|
||||
@@ -343,7 +342,7 @@ private:
|
||||
// allocation size this is always inlined, because all these do is to call
|
||||
// allocateHandleInPool()/deallocateHandleFromPool() with the right pool size.
|
||||
template<typename D>
|
||||
HandleBase::HandleId allocateHandle() {
|
||||
HandleBase::HandleId allocateHandle() noexcept {
|
||||
constexpr size_t BUCKET_SIZE = getBucketSize<D>();
|
||||
return allocateHandleInPool<BUCKET_SIZE>();
|
||||
}
|
||||
@@ -359,7 +358,7 @@ private:
|
||||
// the code generated is not trivial (even if it's not insane either).
|
||||
template<size_t SIZE>
|
||||
UTILS_NOINLINE
|
||||
HandleBase::HandleId allocateHandleInPool() {
|
||||
HandleBase::HandleId allocateHandleInPool() noexcept {
|
||||
uint8_t age;
|
||||
void* p = mHandleArena.alloc(SIZE, alignof(std::max_align_t), 0, &age);
|
||||
if (UTILS_LIKELY(p)) {
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
|
||||
namespace filament::backend {
|
||||
|
||||
CallbackManager::CallbackManager(DriverBase& driver)
|
||||
CallbackManager::CallbackManager(DriverBase& driver) noexcept
|
||||
: mDriver(driver), mCallbacks(1) {
|
||||
}
|
||||
|
||||
|
||||
@@ -51,7 +51,7 @@ class CallbackManager {
|
||||
public:
|
||||
using Handle = Container::const_iterator;
|
||||
|
||||
explicit CallbackManager(DriverBase& driver);
|
||||
explicit CallbackManager(DriverBase& driver) noexcept;
|
||||
|
||||
~CallbackManager() noexcept;
|
||||
|
||||
@@ -78,7 +78,7 @@ private:
|
||||
return --mCallbacks.end();
|
||||
}
|
||||
|
||||
Container::iterator allocateNewSlot() {
|
||||
Container::iterator allocateNewSlot() noexcept {
|
||||
std::lock_guard const lock(mLock);
|
||||
auto curr = --mCallbacks.end();
|
||||
mCallbacks.emplace_back();
|
||||
|
||||
@@ -57,15 +57,12 @@ static void printParameterPack(io::ostream& out, const FIRST& first, const REMAI
|
||||
printParameterPack(out, rest...);
|
||||
}
|
||||
|
||||
static UTILS_NOINLINE UTILS_UNUSED std::string_view extractMethodName(std::string_view command) noexcept { // NOLINT(*-exception-escape)
|
||||
constexpr char startPattern[] = "::Command<&filament::backend::Driver::";
|
||||
static UTILS_NOINLINE UTILS_UNUSED std::string_view extractMethodName(std::string_view command) noexcept {
|
||||
constexpr const char startPattern[] = "::Command<&filament::backend::Driver::";
|
||||
auto pos = command.rfind(startPattern);
|
||||
auto end = command.rfind('(');
|
||||
pos += sizeof(startPattern) - 1;
|
||||
if (pos > command.size()) {
|
||||
return { command.data(), command.size() };
|
||||
}
|
||||
return command.substr(pos, end-pos); // this can't throw by construction
|
||||
return command.substr(pos, end-pos);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
|
||||
@@ -18,14 +18,7 @@
|
||||
|
||||
#include <private/utils/Tracing.h>
|
||||
|
||||
#include <utils/compiler.h>
|
||||
#include <utils/debug.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <iterator>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <utility>
|
||||
|
||||
namespace filament::backend {
|
||||
|
||||
@@ -43,7 +36,7 @@ CompilerThreadPool::~CompilerThreadPool() noexcept {
|
||||
}
|
||||
|
||||
void CompilerThreadPool::init(uint32_t threadCount,
|
||||
ThreadSetup&& threadSetup, ThreadCleanup&& threadCleanup) {
|
||||
ThreadSetup&& threadSetup, ThreadCleanup&& threadCleanup) noexcept {
|
||||
auto setup = std::make_shared<ThreadSetup>(std::move(threadSetup));
|
||||
auto cleanup = std::make_shared<ThreadCleanup>(std::move(threadCleanup));
|
||||
|
||||
|
||||
@@ -47,7 +47,8 @@ public:
|
||||
using Job = utils::Invocable<void()>;
|
||||
using ThreadSetup = utils::Invocable<void()>;
|
||||
using ThreadCleanup = utils::Invocable<void()>;
|
||||
void init(uint32_t threadCount, ThreadSetup&& threadSetup, ThreadCleanup&& threadCleanup);
|
||||
void init(uint32_t threadCount,
|
||||
ThreadSetup&& threadSetup, ThreadCleanup&& threadCleanup) noexcept;
|
||||
void terminate() noexcept;
|
||||
void queue(CompilerPriorityQueue priorityQueue, program_token_t const& token, Job&& job);
|
||||
Job dequeue(program_token_t const& token);
|
||||
|
||||
@@ -131,7 +131,7 @@ void DriverBase::purge() noexcept {
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
|
||||
void DriverBase::scheduleDestroySlow(BufferDescriptor&& buffer) {
|
||||
void DriverBase::scheduleDestroySlow(BufferDescriptor&& buffer) noexcept {
|
||||
auto const handler = buffer.getHandler();
|
||||
scheduleCallback(handler, [buffer = std::move(buffer)]() {
|
||||
// user callback is called when BufferDescriptor gets destroyed
|
||||
@@ -140,7 +140,7 @@ void DriverBase::scheduleDestroySlow(BufferDescriptor&& buffer) {
|
||||
|
||||
// This is called from an async driver method so it's in the GL thread, but purge is called
|
||||
// on the user thread. This is typically called 0 or 1 times per frame.
|
||||
void DriverBase::scheduleRelease(AcquiredImage const& image) {
|
||||
void DriverBase::scheduleRelease(AcquiredImage const& image) noexcept {
|
||||
scheduleCallback(image.handler, [callback = image.callback, image = image.image, userData = image.userData]() {
|
||||
callback(image, userData);
|
||||
});
|
||||
|
||||
@@ -214,15 +214,15 @@ public:
|
||||
protected:
|
||||
class CallbackDataDetails;
|
||||
|
||||
void scheduleDestroy(BufferDescriptor&& buffer) {
|
||||
void scheduleDestroy(BufferDescriptor&& buffer) noexcept {
|
||||
if (buffer.hasCallback()) {
|
||||
scheduleDestroySlow(std::move(buffer));
|
||||
}
|
||||
}
|
||||
|
||||
void scheduleDestroySlow(BufferDescriptor&& buffer);
|
||||
void scheduleDestroySlow(BufferDescriptor&& buffer) noexcept;
|
||||
|
||||
void scheduleRelease(AcquiredImage const& image);
|
||||
void scheduleRelease(AcquiredImage const& image) noexcept;
|
||||
|
||||
void debugCommandBegin(CommandStream* cmds, bool synchronous, const char* methodName) noexcept override;
|
||||
void debugCommandEnd(CommandStream* cmds, bool synchronous, const char* methodName) noexcept override;
|
||||
|
||||
@@ -81,19 +81,19 @@ HandleAllocator<P0, P1, P2>::Allocator::Allocator(AreaPolicy::HeapArea const& ar
|
||||
template <size_t P0, size_t P1, size_t P2>
|
||||
HandleAllocator<P0, P1, P2>::HandleAllocator(const char* name, size_t size,
|
||||
bool disableUseAfterFreeCheck,
|
||||
bool disableHeapHandleTags)
|
||||
bool disableHeapHandleTags) noexcept
|
||||
: mHandleArena(name, size, disableUseAfterFreeCheck),
|
||||
mUseAfterFreeCheckDisabled(disableUseAfterFreeCheck),
|
||||
mHeapHandleTagsDisabled(disableHeapHandleTags) {
|
||||
}
|
||||
|
||||
template <size_t P0, size_t P1, size_t P2>
|
||||
HandleAllocator<P0, P1, P2>::HandleAllocator(const char* name, size_t size)
|
||||
HandleAllocator<P0, P1, P2>::HandleAllocator(const char* name, size_t size) noexcept
|
||||
: HandleAllocator(name, size, false, false) {
|
||||
}
|
||||
|
||||
template <size_t P0, size_t P1, size_t P2>
|
||||
HandleAllocator<P0, P1, P2>::~HandleAllocator() noexcept {
|
||||
HandleAllocator<P0, P1, P2>::~HandleAllocator() {
|
||||
auto& overflowMap = mOverflowMap;
|
||||
if (!overflowMap.empty()) {
|
||||
PANIC_LOG("Not all handles have been freed. Probably leaking memory.");
|
||||
@@ -156,7 +156,7 @@ void HandleAllocator<P0, P1, P2>::deallocateHandleSlow(HandleBase::HandleId id,
|
||||
|
||||
template<size_t P0, size_t P1, size_t P2>
|
||||
UTILS_NOINLINE
|
||||
ImmutableCString HandleAllocator<P0, P1, P2>::getHandleTag(HandleBase::HandleId id) const noexcept {
|
||||
CString HandleAllocator<P0, P1, P2>::getHandleTag(HandleBase::HandleId id) const noexcept {
|
||||
uint32_t key = id;
|
||||
if (UTILS_LIKELY(isPoolHandle(id))) {
|
||||
// Truncate the age to get the debug tag
|
||||
@@ -172,7 +172,7 @@ DebugTag::DebugTag() {
|
||||
}
|
||||
|
||||
UTILS_NOINLINE
|
||||
ImmutableCString DebugTag::findHandleTag(HandleBase::HandleId key) const noexcept {
|
||||
CString DebugTag::findHandleTag(HandleBase::HandleId key) const noexcept {
|
||||
std::unique_lock const lock(mDebugTagLock);
|
||||
if (auto pos = mDebugTags.find(key); pos != mDebugTags.end()) {
|
||||
return pos->second;
|
||||
@@ -181,7 +181,7 @@ ImmutableCString DebugTag::findHandleTag(HandleBase::HandleId key) const noexcep
|
||||
}
|
||||
|
||||
UTILS_NOINLINE
|
||||
void DebugTag::writePoolHandleTag(HandleBase::HandleId key, ImmutableCString&& tag) noexcept {
|
||||
void DebugTag::writePoolHandleTag(HandleBase::HandleId key, CString&& tag) noexcept {
|
||||
// This line is the costly part. In the future, we could potentially use a custom
|
||||
// allocator.
|
||||
std::unique_lock const lock(mDebugTagLock);
|
||||
@@ -190,7 +190,7 @@ void DebugTag::writePoolHandleTag(HandleBase::HandleId key, ImmutableCString&& t
|
||||
}
|
||||
|
||||
UTILS_NOINLINE
|
||||
void DebugTag::writeHeapHandleTag(HandleBase::HandleId key, ImmutableCString&& tag) noexcept {
|
||||
void DebugTag::writeHeapHandleTag(HandleBase::HandleId key, CString&& tag) noexcept {
|
||||
// This line is the costly part. In the future, we could potentially use a custom
|
||||
// allocator.
|
||||
std::unique_lock const lock(mDebugTagLock);
|
||||
|
||||
@@ -41,37 +41,37 @@ Program& Program::operator=(Program&& rhs) noexcept = default;
|
||||
|
||||
Program::~Program() noexcept = default;
|
||||
|
||||
Program& Program::priorityQueue(CompilerPriorityQueue const priorityQueue) noexcept {
|
||||
Program& Program::priorityQueue(CompilerPriorityQueue priorityQueue) noexcept {
|
||||
mPriorityQueue = priorityQueue;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Program& Program::diagnostics(CString const& name,
|
||||
Invocable<io::ostream&(CString const& name, io::ostream&)>&& logger) {
|
||||
Invocable<io::ostream&(utils::CString const& name, io::ostream&)>&& logger) {
|
||||
mName = name;
|
||||
mLogger = std::move(logger);
|
||||
return *this;
|
||||
}
|
||||
|
||||
Program& Program::shader(ShaderStage shader, void const* data, size_t const size) {
|
||||
Program& Program::shader(ShaderStage shader, void const* data, size_t size) {
|
||||
ShaderBlob blob(size);
|
||||
std::copy_n((const uint8_t *)data, size, blob.data());
|
||||
mShadersSource[size_t(shader)] = std::move(blob);
|
||||
return *this;
|
||||
}
|
||||
|
||||
Program& Program::shaderLanguage(ShaderLanguage const shaderLanguage) {
|
||||
Program& Program::shaderLanguage(ShaderLanguage shaderLanguage) {
|
||||
mShaderLanguage = shaderLanguage;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Program& Program::descriptorBindings(descriptor_set_t const set,
|
||||
Program& Program::descriptorBindings(backend::descriptor_set_t set,
|
||||
DescriptorBindingsInfo descriptorBindings) noexcept {
|
||||
mDescriptorBindings[set] = std::move(descriptorBindings);
|
||||
return *this;
|
||||
}
|
||||
|
||||
Program& Program::uniforms(uint32_t index, CString name, UniformInfo uniforms) {
|
||||
Program& Program::uniforms(uint32_t index, utils::CString name, UniformInfo uniforms) noexcept {
|
||||
mBindingUniformsInfo.reserve(mBindingUniformsInfo.capacity() + 1);
|
||||
mBindingUniformsInfo.emplace_back(index, std::move(name), std::move(uniforms));
|
||||
return *this;
|
||||
@@ -88,17 +88,17 @@ Program& Program::specializationConstants(SpecializationConstantsInfo specConsta
|
||||
}
|
||||
|
||||
Program& Program::pushConstants(ShaderStage stage,
|
||||
FixedCapacityVector<PushConstant> constants) noexcept {
|
||||
utils::FixedCapacityVector<PushConstant> constants) noexcept {
|
||||
mPushConstants[static_cast<uint8_t>(stage)] = std::move(constants);
|
||||
return *this;
|
||||
}
|
||||
|
||||
Program& Program::cacheId(uint64_t const cacheId) noexcept {
|
||||
Program& Program::cacheId(uint64_t cacheId) noexcept {
|
||||
mCacheId = cacheId;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Program& Program::multiview(bool const multiview) noexcept {
|
||||
Program& Program::multiview(bool multiview) noexcept {
|
||||
mMultiview = multiview;
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -192,7 +192,7 @@ public:
|
||||
|
||||
void* getCpuBuffer() const noexcept { return mCpuBuffer; }
|
||||
|
||||
void setLabel(const utils::ImmutableCString& label) {
|
||||
void setLabel(const utils::CString& label) {
|
||||
#if FILAMENT_METAL_DEBUG_LABELS
|
||||
if (label.empty()) {
|
||||
return;
|
||||
|
||||
@@ -25,9 +25,8 @@
|
||||
|
||||
#include <backend/SamplerDescriptor.h>
|
||||
|
||||
#include <utils/FixedCapacityVector.h>
|
||||
#include <utils/Log.h>
|
||||
#include <utils/compiler.h>
|
||||
#include <utils/Log.h>
|
||||
#include <utils/debug.h>
|
||||
|
||||
#include <functional>
|
||||
@@ -70,8 +69,7 @@ private:
|
||||
MetalContext* mContext;
|
||||
|
||||
ShaderModel getShaderModel() const noexcept final;
|
||||
utils::FixedCapacityVector<ShaderLanguage> getShaderLanguages(
|
||||
ShaderLanguage preferredLanguage) const noexcept final;
|
||||
ShaderLanguage getShaderLanguage() const noexcept final;
|
||||
|
||||
// Overrides the default implementation by wrapping the call to fn in an @autoreleasepool block.
|
||||
void execute(std::function<void(void)> const& fn) noexcept final;
|
||||
|
||||
@@ -42,7 +42,6 @@
|
||||
#include <utils/Logger.h>
|
||||
#include <utils/Panic.h>
|
||||
#include <utils/sstream.h>
|
||||
#include <utils/ImmutableCString.h>
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
@@ -419,14 +418,14 @@ void MetalDriver::finish(int) {
|
||||
}
|
||||
|
||||
void MetalDriver::createVertexBufferInfoR(Handle<HwVertexBufferInfo> vbih, uint8_t bufferCount,
|
||||
uint8_t attributeCount, AttributeArray attributes, utils::ImmutableCString&& tag) {
|
||||
uint8_t attributeCount, AttributeArray attributes, utils::CString&& tag) {
|
||||
construct_handle<MetalVertexBufferInfo>(vbih, *mContext,
|
||||
bufferCount, attributeCount, attributes);
|
||||
mHandleAllocator.associateTagToHandle(vbih.getId(), std::move(tag));
|
||||
}
|
||||
|
||||
void MetalDriver::createVertexBufferR(Handle<HwVertexBuffer> vbh,
|
||||
uint32_t vertexCount, Handle<HwVertexBufferInfo> vbih, utils::ImmutableCString&& tag) {
|
||||
uint32_t vertexCount, Handle<HwVertexBufferInfo> vbih, utils::CString&& tag) {
|
||||
MetalVertexBufferInfo const* const vbi = handle_cast<const MetalVertexBufferInfo>(vbih);
|
||||
construct_handle<MetalVertexBuffer>(vbh, *mContext, vertexCount, vbi->bufferCount, vbih);
|
||||
mHandleAllocator.associateTagToHandle(vbh.getId(), std::move(tag));
|
||||
@@ -434,7 +433,7 @@ void MetalDriver::createVertexBufferR(Handle<HwVertexBuffer> vbh,
|
||||
}
|
||||
|
||||
void MetalDriver::createIndexBufferR(Handle<HwIndexBuffer> ibh, ElementType elementType,
|
||||
uint32_t indexCount, BufferUsage usage, utils::ImmutableCString&& tag) {
|
||||
uint32_t indexCount, BufferUsage usage, utils::CString&& tag) {
|
||||
auto elementSize = (uint8_t)getElementTypeSize(elementType);
|
||||
auto* indexBuffer =
|
||||
construct_handle<MetalIndexBuffer>(ibh, *mContext, usage, elementSize, indexCount);
|
||||
@@ -447,7 +446,7 @@ void MetalDriver::createIndexBufferR(Handle<HwIndexBuffer> ibh, ElementType elem
|
||||
}
|
||||
|
||||
void MetalDriver::createBufferObjectR(Handle<HwBufferObject> boh, uint32_t byteCount,
|
||||
BufferObjectBinding bindingType, BufferUsage usage, utils::ImmutableCString&& tag) {
|
||||
BufferObjectBinding bindingType, BufferUsage usage, utils::CString&& tag) {
|
||||
auto* bufferObject =
|
||||
construct_handle<MetalBufferObject>(boh, *mContext, bindingType, usage, byteCount);
|
||||
FILAMENT_CHECK_POSTCONDITION(bufferObject->getBuffer()->wasAllocationSuccessful())
|
||||
@@ -489,7 +488,7 @@ inline const char* stringify(SamplerType samplerType) {
|
||||
|
||||
void MetalDriver::createTextureR(Handle<HwTexture> th, SamplerType target, uint8_t levels,
|
||||
TextureFormat format, uint8_t samples, uint32_t width, uint32_t height,
|
||||
uint32_t depth, TextureUsage usage, utils::ImmutableCString&& tag) {
|
||||
uint32_t depth, TextureUsage usage, utils::CString&& tag) {
|
||||
// Clamp sample count to what the device supports.
|
||||
auto& sc = mContext->sampleCountLookup;
|
||||
samples = sc[std::min(MAX_SAMPLE_COUNT, samples)];
|
||||
@@ -509,7 +508,7 @@ void MetalDriver::createTextureR(Handle<HwTexture> th, SamplerType target, uint8
|
||||
}
|
||||
|
||||
void MetalDriver::createTextureViewR(Handle<HwTexture> th, Handle<HwTexture> srch,
|
||||
uint8_t baseLevel, uint8_t levelCount, utils::ImmutableCString&& tag) {
|
||||
uint8_t baseLevel, uint8_t levelCount, utils::CString&& tag) {
|
||||
MetalTexture const* src = handle_cast<MetalTexture>(srch);
|
||||
MetalTexture* texture =
|
||||
construct_handle<MetalTexture>(th, *mContext, src, baseLevel, levelCount);
|
||||
@@ -520,7 +519,7 @@ void MetalDriver::createTextureViewR(Handle<HwTexture> th, Handle<HwTexture> src
|
||||
|
||||
void MetalDriver::createTextureViewSwizzleR(Handle<HwTexture> th, Handle<HwTexture> srch,
|
||||
backend::TextureSwizzle r, backend::TextureSwizzle g, backend::TextureSwizzle b,
|
||||
backend::TextureSwizzle a, utils::ImmutableCString&& tag) {
|
||||
backend::TextureSwizzle a, utils::CString&& tag) {
|
||||
MetalTexture const* src = handle_cast<MetalTexture>(srch);
|
||||
MetalTexture* texture = construct_handle<MetalTexture>(th, *mContext, src, r, g, b, a);
|
||||
mContext->textures.insert(texture);
|
||||
@@ -532,13 +531,13 @@ void MetalDriver::createTextureExternalImage2R(Handle<HwTexture> th,
|
||||
backend::SamplerType target,
|
||||
backend::TextureFormat format,
|
||||
uint32_t width, uint32_t height, backend::TextureUsage usage,
|
||||
Platform::ExternalImageHandleRef image, utils::ImmutableCString&& tag) {
|
||||
Platform::ExternalImageHandleRef image, utils::CString&& tag) {
|
||||
// FIXME: implement createTextureExternalImage2R
|
||||
}
|
||||
|
||||
void MetalDriver::createTextureExternalImageR(Handle<HwTexture> th, backend::SamplerType target,
|
||||
backend::TextureFormat format, uint32_t width, uint32_t height, backend::TextureUsage usage,
|
||||
void* image, utils::ImmutableCString&& tag) {
|
||||
void* image, utils::CString&& tag) {
|
||||
MetalTexture* texture = construct_handle<MetalTexture>(th, *mContext, format, width, height,
|
||||
usage, (CVPixelBufferRef) image);
|
||||
mContext->textures.insert(texture);
|
||||
@@ -551,7 +550,7 @@ void MetalDriver::createTextureExternalImageR(Handle<HwTexture> th, backend::Sam
|
||||
|
||||
void MetalDriver::createTextureExternalImagePlaneR(Handle<HwTexture> th,
|
||||
backend::TextureFormat format, uint32_t width, uint32_t height, backend::TextureUsage usage,
|
||||
void* image, uint32_t plane, utils::ImmutableCString&& tag) {
|
||||
void* image, uint32_t plane, utils::CString&& tag) {
|
||||
MetalTexture* texture = construct_handle<MetalTexture>(th, *mContext, format, width, height,
|
||||
usage, (CVPixelBufferRef) image, plane);
|
||||
mContext->textures.insert(texture);
|
||||
@@ -565,7 +564,7 @@ void MetalDriver::createTextureExternalImagePlaneR(Handle<HwTexture> th,
|
||||
void MetalDriver::importTextureR(Handle<HwTexture> th, intptr_t i,
|
||||
SamplerType target, uint8_t levels,
|
||||
TextureFormat format, uint8_t samples, uint32_t width, uint32_t height,
|
||||
uint32_t depth, TextureUsage usage, utils::ImmutableCString&& tag) {
|
||||
uint32_t depth, TextureUsage usage, utils::CString&& tag) {
|
||||
id<MTLTexture> metalTexture = (id<MTLTexture>) CFBridgingRelease((void*) i);
|
||||
FILAMENT_CHECK_PRECONDITION(metalTexture.width == width)
|
||||
<< "Imported id<MTLTexture> width (" << metalTexture.width
|
||||
@@ -589,13 +588,13 @@ void MetalDriver::importTextureR(Handle<HwTexture> th, intptr_t i,
|
||||
|
||||
void MetalDriver::createRenderPrimitiveR(Handle<HwRenderPrimitive> rph,
|
||||
Handle<HwVertexBuffer> vbh, Handle<HwIndexBuffer> ibh,
|
||||
PrimitiveType pt, utils::ImmutableCString&& tag) {
|
||||
PrimitiveType pt, utils::CString&& tag) {
|
||||
construct_handle<MetalRenderPrimitive>(rph);
|
||||
MetalDriver::setRenderPrimitiveBuffer(rph, pt, vbh, ibh);
|
||||
mHandleAllocator.associateTagToHandle(rph.getId(), std::move(tag));
|
||||
}
|
||||
|
||||
void MetalDriver::createProgramR(Handle<HwProgram> rph, Program&& program, utils::ImmutableCString&& tag) {
|
||||
void MetalDriver::createProgramR(Handle<HwProgram> rph, Program&& program, utils::CString&& tag) {
|
||||
#if FILAMENT_METAL_DEBUG_LOG
|
||||
auto handleId = rph.getId();
|
||||
DEBUG_LOG("createProgramR(rph = %d, program = ", handleId);
|
||||
@@ -605,7 +604,7 @@ void MetalDriver::createProgramR(Handle<HwProgram> rph, Program&& program, utils
|
||||
mHandleAllocator.associateTagToHandle(rph.getId(), std::move(tag));
|
||||
}
|
||||
|
||||
void MetalDriver::createDefaultRenderTargetR(Handle<HwRenderTarget> rth, utils::ImmutableCString&& tag) {
|
||||
void MetalDriver::createDefaultRenderTargetR(Handle<HwRenderTarget> rth, utils::CString&& tag) {
|
||||
construct_handle<MetalRenderTarget>(rth, mContext);
|
||||
mHandleAllocator.associateTagToHandle(rth.getId(), std::move(tag));
|
||||
}
|
||||
@@ -613,7 +612,7 @@ void MetalDriver::createDefaultRenderTargetR(Handle<HwRenderTarget> rth, utils::
|
||||
void MetalDriver::createRenderTargetR(Handle<HwRenderTarget> rth,
|
||||
TargetBufferFlags targetBufferFlags, uint32_t width, uint32_t height,
|
||||
uint8_t samples, uint8_t layerCount, MRT color,
|
||||
TargetBufferInfo depth, TargetBufferInfo stencil, utils::ImmutableCString&& tag) {
|
||||
TargetBufferInfo depth, TargetBufferInfo stencil, utils::CString&& tag) {
|
||||
FILAMENT_CHECK_PRECONDITION(!isInRenderPass(mContext))
|
||||
<< "createRenderTarget must be called outside of a render pass.";
|
||||
// Clamp sample count to what the device supports.
|
||||
@@ -660,14 +659,14 @@ void MetalDriver::createRenderTargetR(Handle<HwRenderTarget> rth,
|
||||
mHandleAllocator.associateTagToHandle(rth.getId(), std::move(tag));
|
||||
}
|
||||
|
||||
void MetalDriver::createFenceR(Handle<HwFence> fh, utils::ImmutableCString&& tag) {
|
||||
void MetalDriver::createFenceR(Handle<HwFence> fh, utils::CString&& tag) {
|
||||
auto* fence = handle_cast<MetalFence>(fh);
|
||||
fence->encode();
|
||||
mHandleAllocator.associateTagToHandle(fh.getId(), std::move(tag));
|
||||
}
|
||||
|
||||
void MetalDriver::createSwapChainR(Handle<HwSwapChain> sch, void* nativeWindow, uint64_t flags,
|
||||
utils::ImmutableCString&& tag) {
|
||||
utils::CString&& tag) {
|
||||
// TODO: support MSAA swapchain
|
||||
|
||||
if (UTILS_UNLIKELY(flags & SWAP_CHAIN_CONFIG_APPLE_CVPIXELBUFFER)) {
|
||||
@@ -684,18 +683,18 @@ void MetalDriver::createSwapChainR(Handle<HwSwapChain> sch, void* nativeWindow,
|
||||
}
|
||||
|
||||
void MetalDriver::createSwapChainHeadlessR(Handle<HwSwapChain> sch,
|
||||
uint32_t width, uint32_t height, uint64_t flags, utils::ImmutableCString&& tag) {
|
||||
uint32_t width, uint32_t height, uint64_t flags, utils::CString&& tag) {
|
||||
construct_handle<MetalSwapChain>(sch, *mContext, mPlatform, width, height, flags);
|
||||
mHandleAllocator.associateTagToHandle(sch.getId(), std::move(tag));
|
||||
}
|
||||
|
||||
void MetalDriver::createSyncR(Handle<HwSync> sh, utils::ImmutableCString&& tag) {
|
||||
void MetalDriver::createSyncR(Handle<HwSync> sh, utils::CString&& tag) {
|
||||
// TODO: Ensure sync is active, and then invoke and clear all pending
|
||||
// callbacks.
|
||||
mHandleAllocator.associateTagToHandle(sh.getId(), std::move(tag));
|
||||
}
|
||||
|
||||
void MetalDriver::createTimerQueryR(Handle<HwTimerQuery> tqh, utils::ImmutableCString&& tag) {
|
||||
void MetalDriver::createTimerQueryR(Handle<HwTimerQuery> tqh, utils::CString&& tag) {
|
||||
// nothing to do, timer query was constructed in createTimerQueryS
|
||||
mHandleAllocator.associateTagToHandle(tqh.getId(), std::move(tag));
|
||||
}
|
||||
@@ -734,12 +733,12 @@ const char* toString(DescriptorFlags flags) {
|
||||
}
|
||||
|
||||
void MetalDriver::createDescriptorSetLayoutR(
|
||||
Handle<HwDescriptorSetLayout> dslh, DescriptorSetLayout&& info, utils::ImmutableCString&& tag) {
|
||||
Handle<HwDescriptorSetLayout> dslh, DescriptorSetLayout&& info, utils::CString&& tag) {
|
||||
#if FILAMENT_METAL_DEBUG_LOG == 1
|
||||
const char* labelStr = "";
|
||||
std::visit([&labelStr](auto&& arg) {
|
||||
using T = std::decay_t<decltype(arg)>;
|
||||
if constexpr (std::is_same_v<T, utils::ImmutableCString> || std::is_same_v<T, utils::StaticString>) {
|
||||
if constexpr (std::is_same_v<T, utils::CString> || std::is_same_v<T, utils::StaticString>) {
|
||||
labelStr = arg.c_str();
|
||||
}
|
||||
}, info.label);
|
||||
@@ -759,7 +758,7 @@ void MetalDriver::createDescriptorSetLayoutR(
|
||||
}
|
||||
|
||||
void MetalDriver::createDescriptorSetR(
|
||||
Handle<HwDescriptorSet> dsh, Handle<HwDescriptorSetLayout> dslh, utils::ImmutableCString&& tag) {
|
||||
Handle<HwDescriptorSet> dsh, Handle<HwDescriptorSetLayout> dslh, utils::CString&& tag) {
|
||||
DEBUG_LOG("createDescriptorSetR(dsh = %d, dslh = %d)\n", dsh.getId(), dslh.getId());
|
||||
MetalDescriptorSetLayout* layout = handle_cast<MetalDescriptorSetLayout>(dslh);
|
||||
MetalDescriptorSet* ds = construct_handle<MetalDescriptorSet>(dsh, layout);
|
||||
@@ -1003,19 +1002,15 @@ ShaderModel MetalDriver::getShaderModel() const noexcept {
|
||||
#endif
|
||||
}
|
||||
|
||||
utils::FixedCapacityVector<ShaderLanguage> MetalDriver::getShaderLanguages(
|
||||
ShaderLanguage preferredLanguage) const noexcept {
|
||||
if (preferredLanguage == backend::ShaderLanguage::MSL) {
|
||||
return { backend::ShaderLanguage::MSL, backend::ShaderLanguage::METAL_LIBRARY };
|
||||
}
|
||||
return { backend::ShaderLanguage::METAL_LIBRARY, backend::ShaderLanguage::MSL };
|
||||
ShaderLanguage MetalDriver::getShaderLanguage() const noexcept {
|
||||
return ShaderLanguage::MSL;
|
||||
}
|
||||
|
||||
Handle<HwStream> MetalDriver::createStreamNative(void* stream, utils::ImmutableCString tag) {
|
||||
Handle<HwStream> MetalDriver::createStreamNative(void* stream, utils::CString tag) {
|
||||
return {};
|
||||
}
|
||||
|
||||
Handle<HwStream> MetalDriver::createStreamAcquired(utils::ImmutableCString tag) {
|
||||
Handle<HwStream> MetalDriver::createStreamAcquired(utils::CString tag) {
|
||||
return {};
|
||||
}
|
||||
|
||||
@@ -1043,15 +1038,11 @@ void MetalDriver::destroyFence(Handle<HwFence> fh) {
|
||||
}
|
||||
|
||||
FenceStatus MetalDriver::getFenceStatus(Handle<HwFence> fh) {
|
||||
return fenceWait(fh, 0);
|
||||
}
|
||||
|
||||
FenceStatus MetalDriver::fenceWait(FenceHandle fh, uint64_t const timeout) {
|
||||
auto* fence = handle_cast<MetalFence>(fh);
|
||||
if (!fence) {
|
||||
return FenceStatus::ERROR;
|
||||
}
|
||||
return fence->wait(timeout);
|
||||
return fence->wait(0);
|
||||
}
|
||||
|
||||
void MetalDriver::destroySync(Handle<HwSync> sh) {
|
||||
@@ -2232,7 +2223,7 @@ MemoryMappedBufferHandle MetalDriver::mapBufferS() noexcept {
|
||||
|
||||
void MetalDriver::mapBufferR(MemoryMappedBufferHandle mmbh,
|
||||
BufferObjectHandle boh, size_t offset,
|
||||
size_t size, MapBufferAccessFlags access, utils::ImmutableCString&& tag) {
|
||||
size_t size, MapBufferAccessFlags access, utils::CString&& tag) {
|
||||
construct_handle<MetalMemoryMappedBuffer>(mmbh, boh, offset, size, access);
|
||||
mHandleAllocator.associateTagToHandle(mmbh.getId(), std::move(tag));
|
||||
}
|
||||
|
||||
@@ -267,7 +267,7 @@ public:
|
||||
|
||||
static MTLPixelFormat decidePixelFormat(MetalContext* context, TextureFormat format);
|
||||
|
||||
void setLabel(const utils::ImmutableCString& label) {
|
||||
void setLabel(const utils::CString& label) {
|
||||
#if FILAMENT_METAL_DEBUG_LABELS
|
||||
if (label.empty()) {
|
||||
return;
|
||||
@@ -494,7 +494,7 @@ struct MetalDescriptorSet : public HwDescriptorSet {
|
||||
|
||||
void finalize(MetalDriver* driver);
|
||||
|
||||
void setLabel(const utils::ImmutableCString& l) {
|
||||
void setLabel(const utils::CString& l) {
|
||||
#if FILAMENT_METAL_DEBUG_LABELS
|
||||
if (l.empty()) {
|
||||
return;
|
||||
@@ -527,7 +527,7 @@ struct MetalDescriptorSet : public HwDescriptorSet {
|
||||
std::array<TrackedMetalBuffer, Program::SHADER_TYPE_COUNT> cachedBuffer = { nil };
|
||||
|
||||
#if FILAMENT_METAL_DEBUG_LABELS
|
||||
utils::ImmutableCString label;
|
||||
utils::CString label;
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
@@ -134,7 +134,6 @@ bool MetalShaderCompiler::isParallelShaderCompileSupported() const noexcept {
|
||||
case ShaderLanguage::ESSL3:
|
||||
case ShaderLanguage::SPIRV:
|
||||
case ShaderLanguage::WGSL:
|
||||
case ShaderLanguage::UNSPECIFIED:
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -153,15 +152,14 @@ bool MetalShaderCompiler::isParallelShaderCompileSupported() const noexcept {
|
||||
|
||||
MTLFunctionConstantValues* constants = [MTLFunctionConstantValues new];
|
||||
auto const& specializationConstants = program.getSpecializationConstants();
|
||||
for (size_t i = 0; i < specializationConstants.size(); i++) {
|
||||
auto const& sc = specializationConstants[i];
|
||||
for (auto const& sc : specializationConstants) {
|
||||
const std::array<MTLDataType, 3> types{
|
||||
MTLDataTypeInt, MTLDataTypeFloat, MTLDataTypeBool };
|
||||
std::visit([i, constants, type = types[sc.index()]](auto&& arg) {
|
||||
std::visit([&sc, constants, type = types[sc.value.index()]](auto&& arg) {
|
||||
[constants setConstantValue:&arg
|
||||
type:type
|
||||
atIndex:i];
|
||||
}, sc);
|
||||
atIndex:sc.id];
|
||||
}, sc.value);
|
||||
}
|
||||
|
||||
id<MTLFunction> function = [library newFunctionWithName:@"main0"
|
||||
|
||||
@@ -155,11 +155,9 @@ id<MTLSamplerState> SamplerStateCreator::operator()(id<MTLDevice> device,
|
||||
// Older Apple devices (and the simulator) don't support setting a comparison function in
|
||||
// MTLSamplerDescriptor.
|
||||
// In practice, this means shadows are not supported when running in the simulator.
|
||||
if (samplerDescriptor.compareFunction != MTLCompareFunctionNever) {
|
||||
if (![device supportsFeatureSet:MTLFeatureSet_iOS_GPUFamily3_v1]) {
|
||||
LOG(WARNING) << "Warning: sample comparison not supported by this GPU";
|
||||
samplerDescriptor.compareFunction = MTLCompareFunctionNever;
|
||||
}
|
||||
if (![device supportsFeatureSet:MTLFeatureSet_iOS_GPUFamily3_v1]) {
|
||||
LOG(WARNING) << "Warning: sample comparison not supported by this GPU";
|
||||
samplerDescriptor.compareFunction = MTLCompareFunctionNever;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
@@ -52,7 +52,7 @@ PlatformMetal::~PlatformMetal() noexcept {
|
||||
delete pImpl;
|
||||
}
|
||||
|
||||
Driver* PlatformMetal::createDriver(void* /*sharedContext*/, const Platform::DriverConfig& driverConfig) {
|
||||
Driver* PlatformMetal::createDriver(void* /*sharedContext*/, const Platform::DriverConfig& driverConfig) noexcept {
|
||||
pImpl->mDrawableFailureBehavior = driverConfig.metalDisablePanicOnDrawableFailure
|
||||
? DrawableFailureBehavior::ABORT_FRAME
|
||||
: DrawableFailureBehavior::PANIC;
|
||||
|
||||
@@ -21,8 +21,6 @@
|
||||
#include "noop/NoopDriver.h"
|
||||
#include "CommandStreamDispatcher.h"
|
||||
|
||||
#include <utils/ImmutableCString.h>
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
namespace filament::backend {
|
||||
@@ -47,16 +45,8 @@ ShaderModel NoopDriver::getShaderModel() const noexcept {
|
||||
#endif
|
||||
}
|
||||
|
||||
utils::FixedCapacityVector<ShaderLanguage> NoopDriver::getShaderLanguages(
|
||||
ShaderLanguage /*preferredLanguage*/) const noexcept {
|
||||
return {
|
||||
ShaderLanguage::ESSL3,
|
||||
ShaderLanguage::ESSL1,
|
||||
ShaderLanguage::SPIRV,
|
||||
ShaderLanguage::MSL,
|
||||
ShaderLanguage::METAL_LIBRARY,
|
||||
ShaderLanguage::WGSL,
|
||||
};
|
||||
ShaderLanguage NoopDriver::getShaderLanguage() const noexcept {
|
||||
return ShaderLanguage::ESSL3;
|
||||
}
|
||||
|
||||
// explicit instantiation of the Dispatcher
|
||||
@@ -137,11 +127,11 @@ void NoopDriver::destroyDescriptorSetLayout(Handle<HwDescriptorSetLayout> tqh) {
|
||||
void NoopDriver::destroyDescriptorSet(Handle<HwDescriptorSet> tqh) {
|
||||
}
|
||||
|
||||
Handle<HwStream> NoopDriver::createStreamNative(void* nativeStream, utils::ImmutableCString tag) {
|
||||
Handle<HwStream> NoopDriver::createStreamNative(void* nativeStream, utils::CString tag) {
|
||||
return {};
|
||||
}
|
||||
|
||||
Handle<HwStream> NoopDriver::createStreamAcquired(utils::ImmutableCString tag) {
|
||||
Handle<HwStream> NoopDriver::createStreamAcquired(utils::CString tag) {
|
||||
return {};
|
||||
}
|
||||
|
||||
@@ -170,10 +160,6 @@ FenceStatus NoopDriver::getFenceStatus(Handle<HwFence> fh) {
|
||||
return FenceStatus::CONDITION_SATISFIED;
|
||||
}
|
||||
|
||||
FenceStatus NoopDriver::fenceWait(Handle<HwFence> fh, uint64_t timeout) {
|
||||
return FenceStatus::ERROR;
|
||||
}
|
||||
|
||||
// We create all textures using VK_IMAGE_TILING_OPTIMAL, so our definition of "supported" is that
|
||||
// the GPU supports the given texture format with non-zero optimal tiling features.
|
||||
bool NoopDriver::isTextureFormatSupported(TextureFormat format) {
|
||||
|
||||
@@ -20,7 +20,6 @@
|
||||
#include "private/backend/Driver.h"
|
||||
#include "DriverBase.h"
|
||||
|
||||
#include <utils/FixedCapacityVector.h>
|
||||
#include <utils/compiler.h>
|
||||
|
||||
namespace filament::backend {
|
||||
@@ -35,8 +34,7 @@ public:
|
||||
|
||||
private:
|
||||
ShaderModel getShaderModel() const noexcept final;
|
||||
utils::FixedCapacityVector<ShaderLanguage> getShaderLanguages(
|
||||
ShaderLanguage preferredLanguage) const noexcept final;
|
||||
ShaderLanguage getShaderLanguage() const noexcept final;
|
||||
|
||||
uint64_t nextFakeHandle = 1;
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
|
||||
namespace filament::backend {
|
||||
|
||||
Driver* PlatformNoop::createDriver(void* sharedGLContext, const Platform::DriverConfig& driverConfig) {
|
||||
Driver* PlatformNoop::createDriver(void* sharedGLContext, const Platform::DriverConfig& driverConfig) noexcept {
|
||||
return NoopDriver::create();
|
||||
}
|
||||
|
||||
|
||||
@@ -31,7 +31,7 @@ public:
|
||||
|
||||
protected:
|
||||
|
||||
Driver* createDriver(void* sharedContext, const Platform::DriverConfig& driverConfig) override;
|
||||
Driver* createDriver(void* sharedContext, const Platform::DriverConfig& driverConfig) noexcept override;
|
||||
};
|
||||
|
||||
} // namespace filament
|
||||
|
||||
@@ -33,7 +33,6 @@
|
||||
|
||||
#include <utils/BitmaskEnum.h>
|
||||
#include <utils/Log.h>
|
||||
#include <utils/Logger.h>
|
||||
#include <utils/Panic.h>
|
||||
#include <utils/bitset.h>
|
||||
#include <utils/compiler.h>
|
||||
@@ -50,7 +49,7 @@
|
||||
namespace filament::backend {
|
||||
|
||||
GLDescriptorSet::GLDescriptorSet(OpenGLContext& gl, DescriptorSetLayoutHandle dslh,
|
||||
GLDescriptorSetLayout const* layout)
|
||||
GLDescriptorSetLayout const* layout) noexcept
|
||||
: descriptors(layout->maxDescriptorBinding + 1),
|
||||
dslh(std::move(dslh)) {
|
||||
|
||||
@@ -157,9 +156,8 @@ void GLDescriptorSet::update(OpenGLContext&,
|
||||
arg.bo = bo;
|
||||
arg.offset = uint32_t(offset);
|
||||
} else {
|
||||
// User asked to update the wrong type of descriptor. This should never happen
|
||||
// because we're checking that on the filament side
|
||||
LOG(ERROR) << "descriptor " << +binding << " is not a buffer";
|
||||
// API usage error. User asked to update the wrong type of descriptor.
|
||||
PANIC_PRECONDITION("descriptor %d is not a buffer", +binding);
|
||||
}
|
||||
}, descriptors[binding].desc);
|
||||
}
|
||||
@@ -216,9 +214,8 @@ void GLDescriptorSet::update(OpenGLContext& gl, HandleAllocatorGL& handleAllocat
|
||||
arg.params = params;
|
||||
}
|
||||
} else {
|
||||
// User asked to update the wrong type of descriptor. This should never happen
|
||||
// because we're checking that on the filament side
|
||||
LOG(ERROR) << "descriptor " << +binding << " is not a texture";
|
||||
// API usage error. User asked to update the wrong type of descriptor.
|
||||
PANIC_PRECONDITION("descriptor %d is not a texture", +binding);
|
||||
}
|
||||
}, descriptors[binding].desc);
|
||||
}
|
||||
|
||||
@@ -52,7 +52,7 @@ struct GLDescriptorSet : public HwDescriptorSet {
|
||||
using HwDescriptorSet::HwDescriptorSet;
|
||||
|
||||
GLDescriptorSet(OpenGLContext& gl, DescriptorSetLayoutHandle dslh,
|
||||
GLDescriptorSetLayout const* layout);
|
||||
GLDescriptorSetLayout const* layout) noexcept;
|
||||
|
||||
// update a buffer descriptor in the set
|
||||
void update(OpenGLContext& gl,
|
||||
|
||||
@@ -277,7 +277,7 @@ void OpenGLContext::terminate() noexcept {
|
||||
}
|
||||
|
||||
void OpenGLContext::destroyWithContext(
|
||||
size_t index, std::function<void(OpenGLContext&)> const& closure) {
|
||||
size_t index, std::function<void(OpenGLContext&)> const& closure) noexcept {
|
||||
if (index == 0) {
|
||||
// Note: we only need to delay the destruction of objects on the unprotected context
|
||||
// (index 0) because the protected context is always immediately destroyed and all its
|
||||
@@ -296,7 +296,7 @@ void OpenGLContext::unbindEverything() noexcept {
|
||||
// worry about.
|
||||
}
|
||||
|
||||
void OpenGLContext::synchronizeStateAndCache(size_t index) {
|
||||
void OpenGLContext::synchronizeStateAndCache(size_t index) noexcept {
|
||||
|
||||
// if we're just switching back to context 0, run all the pending destructors
|
||||
if (index == 0) {
|
||||
@@ -507,40 +507,20 @@ void OpenGLContext::initBugs(Bugs* bugs, Extensions const& exts,
|
||||
} else if (strstr(renderer, "Mali")) {
|
||||
// ARM GPU
|
||||
bugs->vao_doesnt_store_element_array_buffer_binding = true;
|
||||
|
||||
// We have run into several problems with timer queries on Mali-Gxx:
|
||||
// - timer queries seem to cause memory corruptions in some cases on some devices
|
||||
// (see b/233754398)
|
||||
// - appeared at least in: "OpenGL ES 3.2 v1.r26p0-01eac0"
|
||||
// - wasn't present in: "OpenGL ES 3.2 v1.r32p1-00pxl1"
|
||||
// - timer queries sometime crash with an NPE (see b/273759031)
|
||||
// (see b/273759031)
|
||||
// - possibly not present in: "OpenGL ES 3.2 v1.r46p0"
|
||||
bugs->dont_use_timer_query = true;
|
||||
|
||||
// at least some version of Mali have problems with framebuffer_fetch
|
||||
// (see b/445721121, https://github.com/google/filament/issues/7794)
|
||||
bugs->disable_framebuffer_fetch_extension = true;
|
||||
|
||||
if (strstr(renderer, "Mali-T")) {
|
||||
bugs->disable_glFlush = true;
|
||||
bugs->disable_shared_context_draws = true;
|
||||
// We have not verified that timer queries work on Mali-T, so we disable to be safe.
|
||||
bugs->dont_use_timer_query = true;
|
||||
}
|
||||
if (strstr(renderer, "Mali-G")) {
|
||||
int maj, min, driverVersion, driverRelease;
|
||||
int const c = sscanf(version, "OpenGL ES %d.%d v%d.r%d",
|
||||
&maj, &min, &driverVersion, &driverRelease);
|
||||
if (UTILS_LIKELY(c == 4)) {
|
||||
// we were able to parse the version string
|
||||
if (driverVersion > 1 || (driverVersion == 1 && driverRelease >= 46)) {
|
||||
// this driver version is known to be good
|
||||
bugs->dont_use_timer_query = false;
|
||||
}
|
||||
if (driverVersion > 1 || (driverVersion == 1 && driverRelease >= 53)) {
|
||||
// this driver version is known to be good
|
||||
bugs->disable_framebuffer_fetch_extension = false;
|
||||
}
|
||||
}
|
||||
// We have run into several problems with timer queries on Mali-Gxx:
|
||||
// - timer queries seem to cause memory corruptions in some cases on some devices
|
||||
// (see b/233754398)
|
||||
// - appeared at least in: "OpenGL ES 3.2 v1.r26p0-01eac0"
|
||||
// - wasn't present in: "OpenGL ES 3.2 v1.r32p1-00pxl1"
|
||||
// - timer queries sometime crash with an NPE (see b/273759031)
|
||||
bugs->dont_use_timer_query = true;
|
||||
}
|
||||
// Mali seems to have no problem with this (which is good for us)
|
||||
bugs->allow_read_only_ancillary_feedback_loop = true;
|
||||
@@ -865,12 +845,10 @@ GLuint OpenGLContext::bindFramebuffer(GLenum target, GLuint buffer) noexcept {
|
||||
if (UTILS_UNLIKELY(buffer == 0)) {
|
||||
// we're binding the default frame buffer, resolve its actual name
|
||||
auto& defaultFboForThisContext = mDefaultFbo[contextIndex];
|
||||
|
||||
if (UTILS_UNLIKELY(!defaultFboForThisContext.has_value())) {
|
||||
defaultFboForThisContext = GLuint(mPlatform.getDefaultFramebufferObject());
|
||||
}
|
||||
// by construction, defaultFboForThisContext has a value. value_or() avoids a throwing call.
|
||||
buffer = defaultFboForThisContext.value_or(0);
|
||||
buffer = defaultFboForThisContext.value();
|
||||
}
|
||||
bindFramebufferResolved(target, buffer);
|
||||
return buffer;
|
||||
|
||||
@@ -193,7 +193,7 @@ public:
|
||||
void deleteBuffer(GLuint buffer, GLenum target) noexcept;
|
||||
void deleteVertexArray(GLuint vao) noexcept;
|
||||
|
||||
void destroyWithContext(size_t index, std::function<void(OpenGLContext&)> const& closure);
|
||||
void destroyWithContext(size_t index, std::function<void(OpenGLContext&)> const& closure) noexcept;
|
||||
|
||||
// glGet*() values
|
||||
struct Gets {
|
||||
@@ -338,7 +338,6 @@ public:
|
||||
// 'OpenGL error 0x502 (GL_INVALID_OPERATION) in "draw2" at line 4389'
|
||||
// This coincides with the use of framebuffer fetch (ColorGradingAsSubpass). We disable
|
||||
// framebuffer fetch in the case of llvmpipe.
|
||||
// Some Mali drivers also have problems with this (b/445721121)
|
||||
bool disable_framebuffer_fetch_extension;
|
||||
|
||||
} bugs = {};
|
||||
@@ -498,7 +497,7 @@ public:
|
||||
} procs{};
|
||||
|
||||
void unbindEverything() noexcept;
|
||||
void synchronizeStateAndCache(size_t index);
|
||||
void synchronizeStateAndCache(size_t index) noexcept;
|
||||
|
||||
#ifndef FILAMENT_SILENCE_NOT_SUPPORTED_BY_ES2
|
||||
GLuint getSamplerSlow(SamplerParams sp) const noexcept;
|
||||
|
||||
@@ -50,7 +50,6 @@
|
||||
#include <type_traits>
|
||||
#include <utils/BitmaskEnum.h>
|
||||
#include <utils/CString.h>
|
||||
#include <utils/ImmutableCString.h>
|
||||
#include <utils/FixedCapacityVector.h>
|
||||
#include <utils/Invocable.h>
|
||||
#include <utils/Logger.h>
|
||||
@@ -369,9 +368,8 @@ ShaderModel OpenGLDriver::getShaderModel() const noexcept {
|
||||
return mContext.getShaderModel();
|
||||
}
|
||||
|
||||
utils::FixedCapacityVector<ShaderLanguage> OpenGLDriver::getShaderLanguages(
|
||||
ShaderLanguage /*preferredLanguage*/) const noexcept {
|
||||
return { mContext.isES2() ? ShaderLanguage::ESSL1 : ShaderLanguage::ESSL3 };
|
||||
ShaderLanguage OpenGLDriver::getShaderLanguage() const noexcept {
|
||||
return mContext.isES2() ? ShaderLanguage::ESSL1 : ShaderLanguage::ESSL3;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
@@ -395,7 +393,7 @@ void OpenGLDriver::setPushConstant(ShaderStage const stage, uint8_t const index,
|
||||
}
|
||||
#endif
|
||||
|
||||
Slice<const std::pair<GLint, ConstantType>> constants;
|
||||
Slice<std::pair<GLint, ConstantType>> constants;
|
||||
if (stage == ShaderStage::VERTEX) {
|
||||
constants = mCurrentPushConstants->vertexConstants;
|
||||
} else if (stage == ShaderStage::FRAGMENT) {
|
||||
@@ -662,7 +660,7 @@ void OpenGLDriver::createVertexBufferInfoR(
|
||||
uint8_t bufferCount,
|
||||
uint8_t attributeCount,
|
||||
AttributeArray attributes,
|
||||
ImmutableCString&& tag) {
|
||||
CString&& tag) {
|
||||
DEBUG_MARKER()
|
||||
construct<GLVertexBufferInfo>(vbih, bufferCount, attributeCount, attributes);
|
||||
mHandleAllocator.associateTagToHandle(vbih.getId(), std::move(tag));
|
||||
@@ -672,7 +670,7 @@ void OpenGLDriver::createVertexBufferR(
|
||||
Handle<HwVertexBuffer> vbh,
|
||||
uint32_t vertexCount,
|
||||
Handle<HwVertexBufferInfo> vbih,
|
||||
ImmutableCString&& tag) {
|
||||
CString&& tag) {
|
||||
DEBUG_MARKER()
|
||||
construct<GLVertexBuffer>(vbh, vertexCount, vbih);
|
||||
mHandleAllocator.associateTagToHandle(vbh.getId(), std::move(tag));
|
||||
@@ -683,7 +681,7 @@ void OpenGLDriver::createIndexBufferR(
|
||||
ElementType const elementType,
|
||||
uint32_t indexCount,
|
||||
BufferUsage const usage,
|
||||
ImmutableCString&& tag) {
|
||||
CString&& tag) {
|
||||
DEBUG_MARKER()
|
||||
|
||||
auto& gl = mContext;
|
||||
@@ -699,7 +697,7 @@ void OpenGLDriver::createIndexBufferR(
|
||||
}
|
||||
|
||||
void OpenGLDriver::createBufferObjectR(Handle<HwBufferObject> boh, uint32_t byteCount,
|
||||
BufferObjectBinding bindingType, BufferUsage usage, ImmutableCString&& tag) {
|
||||
BufferObjectBinding bindingType, BufferUsage usage, CString&& tag) {
|
||||
DEBUG_MARKER()
|
||||
assert_invariant(byteCount > 0);
|
||||
|
||||
@@ -726,7 +724,7 @@ void OpenGLDriver::createBufferObjectR(Handle<HwBufferObject> boh, uint32_t byte
|
||||
|
||||
void OpenGLDriver::createRenderPrimitiveR(Handle<HwRenderPrimitive> rph,
|
||||
Handle<HwVertexBuffer> vbh, Handle<HwIndexBuffer> ibh,
|
||||
PrimitiveType const pt, ImmutableCString&& tag) {
|
||||
PrimitiveType const pt, CString&& tag) {
|
||||
DEBUG_MARKER()
|
||||
|
||||
auto& gl = mContext;
|
||||
@@ -762,9 +760,32 @@ void OpenGLDriver::createRenderPrimitiveR(Handle<HwRenderPrimitive> rph,
|
||||
mHandleAllocator.associateTagToHandle(rph.getId(), std::move(tag));
|
||||
}
|
||||
|
||||
void OpenGLDriver::createProgramR(Handle<HwProgram> ph, Program&& program, ImmutableCString&& tag) {
|
||||
void OpenGLDriver::createProgramR(Handle<HwProgram> ph, Program&& program, CString&& tag) {
|
||||
DEBUG_MARKER()
|
||||
|
||||
|
||||
if (UTILS_UNLIKELY(mContext.isES2())) {
|
||||
// Here we patch the specialization constants to enable or not the rec709 output
|
||||
// color space emulation in this program. Obviously, the backend shouldn't know about
|
||||
// specific spec-constants, so we need to handle failures gracefully. This cannot be
|
||||
// done at Material creation time because only the backend has access to
|
||||
// Platform.isSRGBSwapChainSupported().
|
||||
if (!mPlatform.isSRGBSwapChainSupported()) {
|
||||
auto& specializationConstants = program.getSpecializationConstants();
|
||||
auto const pos = std::find_if(specializationConstants.begin(), specializationConstants.end(),
|
||||
[](auto&& sc) {
|
||||
// This constant must match
|
||||
// ReservedSpecializationConstants::CONFIG_SRGB_SWAPCHAIN_EMULATION
|
||||
// which we can't use here because it's defined in EngineEnums.h.
|
||||
// (we're breaking layering here, but it's for the good cause).
|
||||
return sc.id == 3;
|
||||
});
|
||||
if (pos != specializationConstants.end()) {
|
||||
pos->value = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
construct<OpenGLProgram>(ph, *this, std::move(program));
|
||||
CHECK_GL_ERROR()
|
||||
mHandleAllocator.associateTagToHandle(ph.getId(), std::move(tag));
|
||||
@@ -872,7 +893,7 @@ void OpenGLDriver::textureStorage(GLTexture* t,
|
||||
|
||||
void OpenGLDriver::createTextureR(Handle<HwTexture> th, SamplerType target, uint8_t levels,
|
||||
TextureFormat format, uint8_t samples, uint32_t width, uint32_t height, uint32_t depth,
|
||||
TextureUsage usage, ImmutableCString&& tag) {
|
||||
TextureUsage usage, CString&& tag) {
|
||||
DEBUG_MARKER()
|
||||
|
||||
GLenum internalFormat = getInternalFormat(format);
|
||||
@@ -965,7 +986,7 @@ void OpenGLDriver::createTextureR(Handle<HwTexture> th, SamplerType target, uint
|
||||
}
|
||||
|
||||
void OpenGLDriver::createTextureViewR(Handle<HwTexture> th,
|
||||
Handle<HwTexture> srch, uint8_t const baseLevel, uint8_t const levelCount, ImmutableCString&& tag) {
|
||||
Handle<HwTexture> srch, uint8_t const baseLevel, uint8_t const levelCount, CString&& tag) {
|
||||
DEBUG_MARKER()
|
||||
GLTexture const* const src = handle_cast<GLTexture const*>(srch);
|
||||
|
||||
@@ -1013,7 +1034,7 @@ void OpenGLDriver::createTextureViewR(Handle<HwTexture> th,
|
||||
|
||||
void OpenGLDriver::createTextureViewSwizzleR(Handle<HwTexture> th, Handle<HwTexture> srch,
|
||||
TextureSwizzle const r, TextureSwizzle const g, TextureSwizzle const b, TextureSwizzle const a,
|
||||
ImmutableCString&& tag) {
|
||||
CString&& tag) {
|
||||
|
||||
DEBUG_MARKER()
|
||||
GLTexture const* const src = handle_cast<GLTexture const*>(srch);
|
||||
@@ -1079,7 +1100,7 @@ void OpenGLDriver::createTextureViewSwizzleR(Handle<HwTexture> th, Handle<HwText
|
||||
|
||||
void OpenGLDriver::createTextureExternalImage2R(Handle<HwTexture> th, SamplerType target,
|
||||
TextureFormat format, uint32_t width, uint32_t height, TextureUsage usage,
|
||||
Platform::ExternalImageHandleRef image, ImmutableCString&& tag) {
|
||||
Platform::ExternalImageHandleRef image, CString&& tag) {
|
||||
DEBUG_MARKER()
|
||||
|
||||
usage |= TextureUsage::SAMPLEABLE;
|
||||
@@ -1131,7 +1152,7 @@ void OpenGLDriver::createTextureExternalImage2R(Handle<HwTexture> th, SamplerTyp
|
||||
|
||||
void OpenGLDriver::createTextureExternalImageR(Handle<HwTexture> th, SamplerType target,
|
||||
TextureFormat format, uint32_t width, uint32_t height, TextureUsage usage, void* image,
|
||||
ImmutableCString&& tag) {
|
||||
CString&& tag) {
|
||||
DEBUG_MARKER()
|
||||
|
||||
usage |= TextureUsage::SAMPLEABLE;
|
||||
@@ -1182,13 +1203,13 @@ void OpenGLDriver::createTextureExternalImageR(Handle<HwTexture> th, SamplerType
|
||||
|
||||
void OpenGLDriver::createTextureExternalImagePlaneR(Handle<HwTexture> th,
|
||||
TextureFormat format, uint32_t width, uint32_t height, TextureUsage usage,
|
||||
void* image, uint32_t plane, ImmutableCString&&) {
|
||||
void* image, uint32_t plane, CString&&) {
|
||||
// not relevant for the OpenGL backend
|
||||
}
|
||||
|
||||
void OpenGLDriver::importTextureR(Handle<HwTexture> th, intptr_t const id,
|
||||
SamplerType target, uint8_t levels, TextureFormat format, uint8_t samples,
|
||||
uint32_t width, uint32_t height, uint32_t depth, TextureUsage usage, ImmutableCString&& tag) {
|
||||
uint32_t width, uint32_t height, uint32_t depth, TextureUsage usage, CString&& tag) {
|
||||
DEBUG_MARKER()
|
||||
|
||||
auto const& gl = mContext;
|
||||
@@ -1643,7 +1664,7 @@ void OpenGLDriver::renderBufferStorage(GLuint const rbo, GLenum internalformat,
|
||||
}
|
||||
|
||||
void OpenGLDriver::createDefaultRenderTargetR(
|
||||
Handle<HwRenderTarget> rth, ImmutableCString&& tag) {
|
||||
Handle<HwRenderTarget> rth, CString&& tag) {
|
||||
DEBUG_MARKER()
|
||||
|
||||
construct<GLRenderTarget>(rth, 0, 0); // FIXME: we don't know the width/height
|
||||
@@ -1666,7 +1687,7 @@ void OpenGLDriver::createRenderTargetR(Handle<HwRenderTarget> rth,
|
||||
MRT color,
|
||||
TargetBufferInfo depth,
|
||||
TargetBufferInfo stencil,
|
||||
ImmutableCString&& tag) {
|
||||
CString&& tag) {
|
||||
DEBUG_MARKER()
|
||||
|
||||
GLRenderTarget* rt = construct<GLRenderTarget>(rth, width, height);
|
||||
@@ -1782,41 +1803,31 @@ void OpenGLDriver::createRenderTargetR(Handle<HwRenderTarget> rth,
|
||||
mHandleAllocator.associateTagToHandle(rth.getId(), std::move(tag));
|
||||
}
|
||||
|
||||
void OpenGLDriver::createFenceR(Handle<HwFence> fh, ImmutableCString&& tag) {
|
||||
void OpenGLDriver::createFenceR(Handle<HwFence> fh, CString&& tag) {
|
||||
DEBUG_MARKER()
|
||||
|
||||
mHandleAllocator.associateTagToHandle(fh.getId(), std::move(tag));
|
||||
|
||||
GLFence* f = handle_cast<GLFence*>(fh);
|
||||
assert_invariant(f->state);
|
||||
|
||||
bool const platformCanCreateFence = mPlatform.canCreateFence();
|
||||
|
||||
if (mContext.isES2() || platformCanCreateFence) {
|
||||
std::lock_guard const lock(f->state->lock);
|
||||
if (platformCanCreateFence) {
|
||||
f->fence = mPlatform.createFence();
|
||||
f->state->cond.notify_all();
|
||||
} else {
|
||||
f->state->status = FenceStatus::ERROR;
|
||||
}
|
||||
return;
|
||||
if (mPlatform.canCreateFence() || mContext.isES2()) {
|
||||
assert_invariant(mPlatform.canCreateFence());
|
||||
f->fence = mPlatform.createFence();
|
||||
}
|
||||
|
||||
// This is the case where we need to use OpenGL fences
|
||||
#ifndef FILAMENT_SILENCE_NOT_SUPPORTED_BY_ES2
|
||||
std::weak_ptr<GLFence::State> const weak = f->state;
|
||||
whenGpuCommandsComplete([weak] {
|
||||
if (auto const state = weak.lock()) {
|
||||
std::lock_guard const lock(state->lock);
|
||||
state->status = FenceStatus::CONDITION_SATISFIED;
|
||||
state->cond.notify_all();
|
||||
}
|
||||
});
|
||||
else {
|
||||
std::weak_ptr const weak = f->state;
|
||||
whenGpuCommandsComplete([weak](){
|
||||
if (auto const state = weak.lock()) {
|
||||
std::lock_guard const lock(state->lock);
|
||||
state->status = FenceStatus::CONDITION_SATISFIED;
|
||||
state->cond.notify_all();
|
||||
}
|
||||
});
|
||||
}
|
||||
#endif
|
||||
mHandleAllocator.associateTagToHandle(fh.getId(), std::move(tag));
|
||||
}
|
||||
|
||||
void OpenGLDriver::createSyncR(Handle<HwSync> sh, ImmutableCString&& tag) {
|
||||
void OpenGLDriver::createSyncR(Handle<HwSync> sh, CString&& tag) {
|
||||
DEBUG_MARKER()
|
||||
|
||||
GLSyncFence* s = handle_cast<GLSyncFence*>(sh);
|
||||
@@ -1835,7 +1846,7 @@ void OpenGLDriver::createSyncR(Handle<HwSync> sh, ImmutableCString&& tag) {
|
||||
}
|
||||
|
||||
void OpenGLDriver::createSwapChainR(Handle<HwSwapChain> sch, void* nativeWindow, uint64_t const flags,
|
||||
ImmutableCString&& tag) {
|
||||
CString&& tag) {
|
||||
DEBUG_MARKER()
|
||||
|
||||
GLSwapChain* sc = handle_cast<GLSwapChain*>(sch);
|
||||
@@ -1857,7 +1868,7 @@ void OpenGLDriver::createSwapChainR(Handle<HwSwapChain> sch, void* nativeWindow,
|
||||
}
|
||||
|
||||
void OpenGLDriver::createSwapChainHeadlessR(Handle<HwSwapChain> sch,
|
||||
uint32_t const width, uint32_t const height, uint64_t const flags, ImmutableCString&& tag) {
|
||||
uint32_t const width, uint32_t const height, uint64_t const flags, CString&& tag) {
|
||||
DEBUG_MARKER()
|
||||
|
||||
GLSwapChain* sc = handle_cast<GLSwapChain*>(sch);
|
||||
@@ -1879,7 +1890,7 @@ void OpenGLDriver::createSwapChainHeadlessR(Handle<HwSwapChain> sch,
|
||||
mHandleAllocator.associateTagToHandle(sch.getId(), std::move(tag));
|
||||
}
|
||||
|
||||
void OpenGLDriver::createTimerQueryR(Handle<HwTimerQuery> tqh, ImmutableCString&& tag) {
|
||||
void OpenGLDriver::createTimerQueryR(Handle<HwTimerQuery> tqh, CString&& tag) {
|
||||
DEBUG_MARKER()
|
||||
GLTimerQuery* tq = handle_cast<GLTimerQuery*>(tqh);
|
||||
mContext.createTimerQuery(tq);
|
||||
@@ -1887,14 +1898,14 @@ void OpenGLDriver::createTimerQueryR(Handle<HwTimerQuery> tqh, ImmutableCString&
|
||||
}
|
||||
|
||||
void OpenGLDriver::createDescriptorSetLayoutR(Handle<HwDescriptorSetLayout> dslh,
|
||||
DescriptorSetLayout&& info, ImmutableCString&& tag) {
|
||||
DescriptorSetLayout&& info, CString&& tag) {
|
||||
DEBUG_MARKER()
|
||||
construct<GLDescriptorSetLayout>(dslh, std::move(info));
|
||||
mHandleAllocator.associateTagToHandle(dslh.getId(), std::move(tag));
|
||||
}
|
||||
|
||||
void OpenGLDriver::createDescriptorSetR(Handle<HwDescriptorSet> dsh,
|
||||
Handle<HwDescriptorSetLayout> dslh, ImmutableCString&& tag) {
|
||||
Handle<HwDescriptorSetLayout> dslh, CString&& tag) {
|
||||
DEBUG_MARKER()
|
||||
GLDescriptorSetLayout const* dsl = handle_cast<GLDescriptorSetLayout*>(dslh);
|
||||
construct<GLDescriptorSet>(dsh, mContext, dslh, dsl);
|
||||
@@ -1903,7 +1914,7 @@ void OpenGLDriver::createDescriptorSetR(Handle<HwDescriptorSet> dsh,
|
||||
|
||||
void OpenGLDriver::mapBufferR(MemoryMappedBufferHandle mmbh,
|
||||
BufferObjectHandle boh, size_t offset,
|
||||
size_t size, MapBufferAccessFlags access, ImmutableCString&& tag) {
|
||||
size_t size, MapBufferAccessFlags access, CString&& tag) {
|
||||
DEBUG_MARKER()
|
||||
construct<GLMemoryMappedBuffer>(mmbh, mContext, mHandleAllocator, boh, offset, size, access);
|
||||
mHandleAllocator.associateTagToHandle(mmbh.getId(), std::move(tag));
|
||||
@@ -2173,14 +2184,14 @@ void OpenGLDriver::unmapBuffer(MemoryMappedBufferHandle mmbh) {
|
||||
// These are called on the application's thread
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
|
||||
Handle<HwStream> OpenGLDriver::createStreamNative(void* nativeStream, ImmutableCString tag) {
|
||||
Handle<HwStream> OpenGLDriver::createStreamNative(void* nativeStream, CString tag) {
|
||||
Platform::Stream* stream = mPlatform.createStream(nativeStream);
|
||||
auto handle = initHandle<GLStream>(stream);
|
||||
mHandleAllocator.associateTagToHandle(handle.getId(), std::move(tag));
|
||||
return handle;
|
||||
}
|
||||
|
||||
Handle<HwStream> OpenGLDriver::createStreamAcquired(ImmutableCString tag) {
|
||||
Handle<HwStream> OpenGLDriver::createStreamAcquired(CString tag) {
|
||||
auto handle = initHandle<GLStream>();
|
||||
mHandleAllocator.associateTagToHandle(handle.getId(), std::move(tag));
|
||||
return handle;
|
||||
@@ -2296,62 +2307,29 @@ void OpenGLDriver::destroyFence(Handle<HwFence> fh) {
|
||||
}
|
||||
|
||||
FenceStatus OpenGLDriver::getFenceStatus(Handle<HwFence> fh) {
|
||||
return fenceWait(fh, 0);
|
||||
}
|
||||
|
||||
FenceStatus OpenGLDriver::fenceWait(FenceHandle fh, uint64_t const timeout) {
|
||||
if (fh) {
|
||||
// we have to take into account that the STL's wait_for() actually works with
|
||||
// time_points relative to steady_clock::now() internally.
|
||||
using namespace std::chrono;
|
||||
auto const now = steady_clock::now();
|
||||
steady_clock::time_point until = steady_clock::time_point::max();
|
||||
if (now <= steady_clock::time_point::max() - nanoseconds(timeout)) {
|
||||
until = now + nanoseconds(timeout);
|
||||
}
|
||||
|
||||
GLFence const* f = handle_cast<GLFence*>(fh);
|
||||
assert_invariant(f->state);
|
||||
|
||||
bool const platformCanCreateFence = mPlatform.canCreateFence();
|
||||
|
||||
// immediately acquire a reference on our state, so that things don't go south if
|
||||
// the HwFence gets destroyed (on the main thread) while we wait.
|
||||
std::shared_ptr const state{ f->state };
|
||||
|
||||
if (mContext.isES2() || platformCanCreateFence) {
|
||||
if (platformCanCreateFence) {
|
||||
std::unique_lock lock(state->lock);
|
||||
if (f->fence == nullptr) {
|
||||
// we've been called before the fence was created asynchronously,
|
||||
// so we need to wait for that, before using the real fence.
|
||||
// By construction, "f" can't be destroyed while we wait, because its
|
||||
// construction call is in the queue and a destroy call will have to come later.
|
||||
state->cond.wait_until(lock, until, [f] {
|
||||
return f->fence != nullptr;
|
||||
});
|
||||
if (f->fence == nullptr) {
|
||||
// the only possible choice here is that we timed out
|
||||
assert_invariant(state->status == FenceStatus::TIMEOUT_EXPIRED);
|
||||
return FenceStatus::TIMEOUT_EXPIRED;
|
||||
}
|
||||
GLFence* f = handle_cast<GLFence*>(fh);
|
||||
if (mPlatform.canCreateFence() || mContext.isES2()) {
|
||||
if (f->fence == nullptr) {
|
||||
// we can end-up here if:
|
||||
// - the platform doesn't support h/w fences
|
||||
if (UTILS_UNLIKELY(!mPlatform.canCreateFence())) {
|
||||
return FenceStatus::ERROR;
|
||||
}
|
||||
lock.unlock();
|
||||
// here we know that we have the platform fence
|
||||
assert_invariant(f->fence);
|
||||
return mPlatform.waitFence(f->fence, timeout);
|
||||
// - wait() was called before the fence was asynchronously created.
|
||||
return FenceStatus::TIMEOUT_EXPIRED;
|
||||
}
|
||||
// platform doesn't support fences -- nothing we can do.
|
||||
return FenceStatus::ERROR;
|
||||
return mPlatform.waitFence(f->fence, 0);
|
||||
}
|
||||
|
||||
// This is the case where we need to use OpenGL fences
|
||||
#ifndef FILAMENT_SILENCE_NOT_SUPPORTED_BY_ES2
|
||||
std::unique_lock lock(state->lock);
|
||||
state->cond.wait_until(lock, until, [&state] {
|
||||
return state->status != FenceStatus::TIMEOUT_EXPIRED;
|
||||
});
|
||||
return state->status;
|
||||
else {
|
||||
assert_invariant(f->state);
|
||||
std::unique_lock lock(f->state->lock);
|
||||
f->state->cond.wait_for(lock, std::chrono::nanoseconds(0), [&state = f->state]() {
|
||||
return state->status != FenceStatus::TIMEOUT_EXPIRED;
|
||||
});
|
||||
return f->state->status;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
return FenceStatus::ERROR;
|
||||
@@ -2618,8 +2596,6 @@ bool OpenGLDriver::isWorkaroundNeeded(Workaround const workaround) {
|
||||
return mContext.bugs.powervr_shader_workarounds;
|
||||
case Workaround::DISABLE_DEPTH_PRECACHE_FOR_DEFAULT_MATERIAL:
|
||||
return mContext.bugs.disable_depth_precache_for_default_material;
|
||||
case Workaround::EMULATE_SRGB_SWAPCHAIN:
|
||||
return mContext.isES2() && !mPlatform.isSRGBSwapChainSupported();
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
@@ -3193,7 +3169,7 @@ void OpenGLDriver::setExternalStream(Handle<HwTexture> th, Handle<HwStream> sh)
|
||||
}
|
||||
|
||||
UTILS_NOINLINE
|
||||
void OpenGLDriver::attachStream(GLTexture* t, GLStream* hwStream) {
|
||||
void OpenGLDriver::attachStream(GLTexture* t, GLStream* hwStream) noexcept {
|
||||
mTexturesWithStreamsAttached.push_back(t);
|
||||
|
||||
switch (hwStream->streamType) {
|
||||
@@ -3779,16 +3755,16 @@ void OpenGLDriver::readBufferSubData(BufferObjectHandle boh,
|
||||
}
|
||||
|
||||
|
||||
void OpenGLDriver::runEveryNowAndThen(std::function<bool()> fn) {
|
||||
void OpenGLDriver::runEveryNowAndThen(std::function<bool()> fn) noexcept {
|
||||
mEveryNowAndThenOps.push_back(std::move(fn));
|
||||
}
|
||||
|
||||
void OpenGLDriver::executeEveryNowAndThenOps() noexcept { // NOLINT(*-exception-escape)
|
||||
void OpenGLDriver::executeEveryNowAndThenOps() noexcept {
|
||||
auto& v = mEveryNowAndThenOps;
|
||||
auto it = v.begin();
|
||||
while (it != v.end()) {
|
||||
if ((*it)()) {
|
||||
it = v.erase(it); // cannot throw by construction
|
||||
it = v.erase(it);
|
||||
} else {
|
||||
++it;
|
||||
}
|
||||
@@ -3796,17 +3772,17 @@ void OpenGLDriver::executeEveryNowAndThenOps() noexcept { // NOLINT(*-exception-
|
||||
}
|
||||
|
||||
#ifndef FILAMENT_SILENCE_NOT_SUPPORTED_BY_ES2
|
||||
void OpenGLDriver::whenFrameComplete(const std::function<void()>& fn) {
|
||||
void OpenGLDriver::whenFrameComplete(const std::function<void()>& fn) noexcept {
|
||||
mFrameCompleteOps.push_back(fn);
|
||||
}
|
||||
|
||||
void OpenGLDriver::whenGpuCommandsComplete(const std::function<void()>& fn) {
|
||||
void OpenGLDriver::whenGpuCommandsComplete(const std::function<void()>& fn) noexcept {
|
||||
GLsync sync = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
|
||||
mGpuCommandCompleteOps.emplace_back(sync, fn);
|
||||
CHECK_GL_ERROR()
|
||||
}
|
||||
|
||||
void OpenGLDriver::executeGpuCommandsCompleteOps() noexcept { // NOLINT(*-exception-escape)
|
||||
void OpenGLDriver::executeGpuCommandsCompleteOps() noexcept {
|
||||
auto& v = mGpuCommandCompleteOps;
|
||||
auto it = v.begin();
|
||||
while (it != v.end()) {
|
||||
@@ -3822,13 +3798,13 @@ void OpenGLDriver::executeGpuCommandsCompleteOps() noexcept { // NOLINT(*-except
|
||||
// ready
|
||||
it->second();
|
||||
glDeleteSync(sync);
|
||||
it = v.erase(it); // cannot throw by construction
|
||||
it = v.erase(it);
|
||||
break;
|
||||
default:
|
||||
// This should never happen, but is very problematic if it does, as we might leak
|
||||
// some data depending on what the callback does. However, we clean up our own state.
|
||||
glDeleteSync(sync);
|
||||
it = v.erase(it); // cannot throw by construction
|
||||
it = v.erase(it);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -45,7 +45,6 @@
|
||||
#include <utils/FixedCapacityVector.h>
|
||||
#include <utils/compiler.h>
|
||||
#include <utils/CString.h>
|
||||
#include <utils/ImmutableCString.h>
|
||||
#include <utils/debug.h>
|
||||
|
||||
#include <math/vec4.h>
|
||||
@@ -195,8 +194,8 @@ public:
|
||||
struct GLFence : public HwFence {
|
||||
using HwFence::HwFence;
|
||||
struct State {
|
||||
utils::Mutex lock; // NOLINT(*-include-cleaner)
|
||||
utils::Condition cond; // NOLINT(*-include-cleaner)
|
||||
std::mutex lock;
|
||||
std::condition_variable cond;
|
||||
FenceStatus status{ FenceStatus::TIMEOUT_EXPIRED };
|
||||
};
|
||||
std::shared_ptr<State> state{ std::make_shared<State>() };
|
||||
@@ -234,8 +233,7 @@ private:
|
||||
}
|
||||
|
||||
ShaderModel getShaderModel() const noexcept override;
|
||||
utils::FixedCapacityVector<ShaderLanguage> getShaderLanguages(
|
||||
ShaderLanguage preferredLanguage) const noexcept override;
|
||||
ShaderLanguage getShaderLanguage() const noexcept override;
|
||||
|
||||
/*
|
||||
* OpenGLDriver interface
|
||||
@@ -396,23 +394,23 @@ private:
|
||||
|
||||
std::unordered_map<GLuint, BufferObjectStreamDescriptor> mStreamUniformDescriptors;
|
||||
|
||||
void attachStream(GLTexture* t, GLStream* stream);
|
||||
void attachStream(GLTexture* t, GLStream* stream) noexcept;
|
||||
void detachStream(GLTexture* t) noexcept;
|
||||
void replaceStream(GLTexture* t, GLStream* stream) noexcept;
|
||||
math::mat3f getStreamTransformMatrix(Handle<HwStream> sh);
|
||||
|
||||
#ifndef FILAMENT_SILENCE_NOT_SUPPORTED_BY_ES2
|
||||
// tasks executed on the main thread after the fence signaled
|
||||
void whenGpuCommandsComplete(const std::function<void()>& fn);
|
||||
void whenGpuCommandsComplete(const std::function<void()>& fn) noexcept;
|
||||
void executeGpuCommandsCompleteOps() noexcept;
|
||||
std::vector<std::pair<GLsync, std::function<void()>>> mGpuCommandCompleteOps;
|
||||
|
||||
void whenFrameComplete(const std::function<void()>& fn);
|
||||
void whenFrameComplete(const std::function<void()>& fn) noexcept;
|
||||
std::vector<std::function<void()>> mFrameCompleteOps;
|
||||
#endif
|
||||
|
||||
// tasks regularly executed on the main thread at until they return true
|
||||
void runEveryNowAndThen(std::function<bool()> fn);
|
||||
void runEveryNowAndThen(std::function<bool()> fn) noexcept;
|
||||
void executeEveryNowAndThenOps() noexcept;
|
||||
std::vector<std::function<bool()>> mEveryNowAndThenOps;
|
||||
|
||||
|
||||
@@ -121,7 +121,7 @@ void OpenGLProgram::initialize(OpenGLDriver& gld) {
|
||||
* checkProgramStatus() has been successfully called.
|
||||
*/
|
||||
void OpenGLProgram::initializeProgramState(OpenGLContext& context, GLuint program,
|
||||
LazyInitializationData& lazyInitializationData) {
|
||||
LazyInitializationData& lazyInitializationData) noexcept {
|
||||
FILAMENT_TRACING_CALL(FILAMENT_TRACING_CATEGORY_FILAMENT);
|
||||
|
||||
// from the pipeline layout we compute a mapping from {set, binding} to {binding}
|
||||
|
||||
@@ -43,8 +43,8 @@ namespace filament::backend {
|
||||
class OpenGLDriver;
|
||||
|
||||
struct PushConstantBundle {
|
||||
utils::Slice<const std::pair<GLint, ConstantType>> vertexConstants;
|
||||
utils::Slice<const std::pair<GLint, ConstantType>> fragmentConstants;
|
||||
utils::Slice<std::pair<GLint, ConstantType>> vertexConstants;
|
||||
utils::Slice<std::pair<GLint, ConstantType>> fragmentConstants;
|
||||
};
|
||||
|
||||
class OpenGLProgram : public HwProgram {
|
||||
@@ -94,8 +94,8 @@ public:
|
||||
PushConstantBundle getPushConstants() {
|
||||
auto fragBegin = mPushConstants.begin() + mPushConstantFragmentStageOffset;
|
||||
return {
|
||||
.vertexConstants = { mPushConstants.begin(), fragBegin },
|
||||
.fragmentConstants = { fragBegin, mPushConstants.end() },
|
||||
.vertexConstants = utils::Slice(mPushConstants.begin(), fragBegin),
|
||||
.fragmentConstants = utils::Slice(fragBegin, mPushConstants.end()),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -106,7 +106,7 @@ private:
|
||||
void initialize(OpenGLDriver& gld);
|
||||
|
||||
void initializeProgramState(OpenGLContext& context, GLuint program,
|
||||
LazyInitializationData& lazyInitializationData);
|
||||
LazyInitializationData& lazyInitializationData) noexcept;
|
||||
|
||||
BindingMap mBindingMap; // 8 bytes + out-of-line 256 bytes
|
||||
|
||||
|
||||
@@ -51,7 +51,7 @@ class OpenGLDriver;
|
||||
bool TimerQueryFactory::mGpuTimeSupported = false;
|
||||
|
||||
TimerQueryFactoryInterface* TimerQueryFactory::init(
|
||||
OpenGLPlatform& platform, OpenGLContext& context) {
|
||||
OpenGLPlatform& platform, OpenGLContext& context) noexcept {
|
||||
(void)context;
|
||||
|
||||
TimerQueryFactoryInterface* impl = nullptr;
|
||||
@@ -172,12 +172,46 @@ void TimerQueryNativeFactory::endTimeElapsedQuery(OpenGLDriver& driver, GLTimerQ
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
|
||||
TimerQueryFenceFactory::TimerQueryFenceFactory(OpenGLPlatform& platform)
|
||||
: mPlatform(platform),
|
||||
mJobQueue("OpenGLTimerQueryFence", utils::AsyncJobQueue::Priority::URGENT_DISPLAY) {
|
||||
: mPlatform(platform) {
|
||||
mQueue.reserve(2);
|
||||
mThread = std::thread([this]() {
|
||||
utils::JobSystem::setThreadName("OpenGLTimerQueryFence");
|
||||
utils::JobSystem::setThreadPriority(utils::JobSystem::Priority::URGENT_DISPLAY);
|
||||
auto& queue = mQueue;
|
||||
bool exitRequested;
|
||||
do {
|
||||
std::unique_lock<utils::Mutex> lock(mLock);
|
||||
mCondition.wait(lock, [this, &queue]() -> bool {
|
||||
return mExitRequested || !queue.empty();
|
||||
});
|
||||
exitRequested = mExitRequested;
|
||||
if (!queue.empty()) {
|
||||
Job const job(queue.front());
|
||||
queue.erase(queue.begin());
|
||||
lock.unlock();
|
||||
job();
|
||||
}
|
||||
} while (!exitRequested);
|
||||
});
|
||||
}
|
||||
|
||||
TimerQueryFenceFactory::~TimerQueryFenceFactory() {
|
||||
mJobQueue.drainAndExit();
|
||||
assert_invariant(mQueue.empty());
|
||||
if (mThread.joinable()) {
|
||||
std::unique_lock<utils::Mutex> lock(mLock);
|
||||
mExitRequested = true;
|
||||
mCondition.notify_one();
|
||||
lock.unlock();
|
||||
if (mThread.joinable()) {
|
||||
mThread.join();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TimerQueryFenceFactory::push(TimerQueryFenceFactory::Job&& job) {
|
||||
std::unique_lock<utils::Mutex> const lock(mLock);
|
||||
mQueue.push_back(std::move(job));
|
||||
mCondition.notify_one();
|
||||
}
|
||||
|
||||
void TimerQueryFenceFactory::createTimerQuery(GLTimerQuery* tq) {
|
||||
@@ -202,7 +236,7 @@ void TimerQueryFenceFactory::beginTimeElapsedQuery(GLTimerQuery* tq) {
|
||||
// on a dummy target for instance, or somehow latch the begin time at the next renderpass
|
||||
// start.
|
||||
|
||||
mJobQueue.push([&platform = mPlatform, fence = mPlatform.createFence(), weak]() {
|
||||
push([&platform = mPlatform, fence = mPlatform.createFence(), weak]() {
|
||||
auto state = weak.lock();
|
||||
if (state) {
|
||||
platform.waitFence(fence, FENCE_WAIT_FOR_EVER);
|
||||
@@ -218,7 +252,7 @@ void TimerQueryFenceFactory::endTimeElapsedQuery(OpenGLDriver&, GLTimerQuery* tq
|
||||
assert_invariant(tq->state);
|
||||
std::weak_ptr<GLTimerQuery::State> const weak = tq->state;
|
||||
|
||||
mJobQueue.push([&platform = mPlatform, fence = mPlatform.createFence(), weak]() {
|
||||
push([&platform = mPlatform, fence = mPlatform.createFence(), weak]() {
|
||||
auto state = weak.lock();
|
||||
if (state) {
|
||||
platform.waitFence(fence, FENCE_WAIT_FOR_EVER);
|
||||
|
||||
@@ -21,7 +21,8 @@
|
||||
|
||||
#include "DriverBase.h"
|
||||
|
||||
#include <utils/AsyncJobQueue.h>
|
||||
#include <utils/Condition.h>
|
||||
#include <utils/Mutex.h>
|
||||
|
||||
#include "gl_headers.h"
|
||||
|
||||
@@ -64,7 +65,7 @@ class TimerQueryFactory {
|
||||
static bool mGpuTimeSupported;
|
||||
public:
|
||||
static TimerQueryFactoryInterface* init(
|
||||
OpenGLPlatform& platform, OpenGLContext& context);
|
||||
OpenGLPlatform& platform, OpenGLContext& context) noexcept;
|
||||
|
||||
static bool isGpuTimeSupported() noexcept {
|
||||
return mGpuTimeSupported;
|
||||
@@ -107,13 +108,22 @@ public:
|
||||
explicit TimerQueryFenceFactory(OpenGLPlatform& platform);
|
||||
~TimerQueryFenceFactory() override;
|
||||
private:
|
||||
using Job = std::function<void()>;
|
||||
using Container = std::vector<Job>;
|
||||
|
||||
void createTimerQuery(GLTimerQuery* query) override;
|
||||
void destroyTimerQuery(GLTimerQuery* query) override;
|
||||
void beginTimeElapsedQuery(GLTimerQuery* tq) override;
|
||||
void endTimeElapsedQuery(OpenGLDriver& driver, GLTimerQuery* tq) override;
|
||||
|
||||
void push(Job&& job);
|
||||
|
||||
OpenGLPlatform& mPlatform;
|
||||
utils::AsyncJobQueue mJobQueue;
|
||||
std::thread mThread;
|
||||
mutable utils::Mutex mLock;
|
||||
mutable utils::Condition mCondition;
|
||||
Container mQueue;
|
||||
bool mExitRequested = false;
|
||||
};
|
||||
|
||||
class TimerQueryFallbackFactory final : public TimerQueryFactoryInterface {
|
||||
|
||||
@@ -71,7 +71,7 @@ static CString to_string(int const i) { return utils::to_string(i); }
|
||||
static CString to_string(float const f) { return "float(" + utils::to_string(f) + ")"; }
|
||||
|
||||
static void logCompilationError(ShaderStage shaderType, const char* name, GLuint shaderId,
|
||||
Program::ShaderBlob const& sourceCode);
|
||||
Program::ShaderBlob const& sourceCode) noexcept;
|
||||
static void logProgramLinkError(char const* name, GLuint program) noexcept;
|
||||
|
||||
static void process_GOOGLE_cpp_style_line_directive(OpenGLContext const& context, char* source,
|
||||
@@ -79,7 +79,7 @@ static void process_GOOGLE_cpp_style_line_directive(OpenGLContext const& context
|
||||
static void process_OVR_multiview2(OpenGLContext const& context, int32_t eyeCount, char* source,
|
||||
size_t len) noexcept;
|
||||
static std::string_view process_ARB_shading_language_packing(OpenGLContext& context) noexcept;
|
||||
static std::array<std::string_view, 3> splitShaderSource(std::string_view source);
|
||||
static std::array<std::string_view, 3> splitShaderSource(std::string_view source) noexcept;
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
|
||||
@@ -312,7 +312,7 @@ ShaderCompilerService::program_token_t ShaderCompilerService::createProgram(
|
||||
}
|
||||
|
||||
void ShaderCompilerService::compileProgram(
|
||||
program_token_t const& token, Program&& program) {
|
||||
program_token_t const& token, Program&& program) noexcept {
|
||||
auto& gl = mDriver.getContext();
|
||||
CompilerPriorityQueue const priorityQueue = program.getPriorityQueue();
|
||||
switch (mMode) {
|
||||
@@ -343,12 +343,6 @@ void ShaderCompilerService::compileProgram(
|
||||
program.getSpecializationConstants(), program.isMultiview(),
|
||||
token);
|
||||
linkProgram(gl, token);
|
||||
// Check status of program linking. If it failed, errors will be logged.
|
||||
bool const linked = checkLinkStatusAndCleanupShaders(token);
|
||||
// We panic if it failed to create the program.
|
||||
FILAMENT_CHECK_POSTCONDITION(linked)
|
||||
<< "OpenGL program " << token->name.c_str_safe()
|
||||
<< " failed to link or compile";
|
||||
}
|
||||
// Now `token->gl.program` must be populated, so we signal the completion
|
||||
// of the linking. We don't need to check the result of the program here
|
||||
@@ -481,14 +475,16 @@ GLuint ShaderCompilerService::initialize(program_token_t& token) {
|
||||
ensureTokenIsReady(token);
|
||||
assert_invariant(token->gl.program);
|
||||
|
||||
// Check status of program linking. If it failed, errors will be logged.
|
||||
bool const linked = checkLinkStatusAndCleanupShaders(token);
|
||||
|
||||
// We panic if it failed to create the program.
|
||||
FILAMENT_CHECK_POSTCONDITION(linked)
|
||||
<< "OpenGL program " << token->name.c_str_safe() << " failed to link or compile";
|
||||
|
||||
GLuint const program = token->gl.program;
|
||||
|
||||
if (mMode != Mode::THREAD_POOL) {
|
||||
// Check status of program linking. If it failed, errors will be logged.
|
||||
bool const linked = checkLinkStatusAndCleanupShaders(token);
|
||||
// We panic if it failed to create the program.
|
||||
FILAMENT_CHECK_POSTCONDITION(linked)
|
||||
<< "OpenGL program " << token->name.c_str_safe() << " failed to link or compile";
|
||||
// The program has been successfully created. Try caching the program blob for
|
||||
// non-THREAD_POOL modes. In the THREAD_POOL mode, caching is performed in the pool.
|
||||
tryCachingProgram(mBlobCache, mDriver.mPlatform, token);
|
||||
@@ -590,7 +586,7 @@ void ShaderCompilerService::handleCanceledTokensForThreadPool() {
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
|
||||
void ShaderCompilerService::runAtNextTick(CompilerPriorityQueue priority,
|
||||
program_token_t const& token, Job job) {
|
||||
program_token_t const& token, Job job) noexcept {
|
||||
// insert items in order of priority and at the end of the range
|
||||
auto& ops = mRunAtNextTickOps;
|
||||
auto const pos = std::lower_bound(ops.begin(), ops.end(), priority,
|
||||
@@ -618,7 +614,7 @@ bool ShaderCompilerService::cancelTickOp(program_token_t const& token) noexcept
|
||||
return false;
|
||||
}
|
||||
|
||||
void ShaderCompilerService::executeTickOps() {
|
||||
void ShaderCompilerService::executeTickOps() noexcept {
|
||||
auto& ops = mRunAtNextTickOps;
|
||||
auto it = ops.begin();
|
||||
while (it != ops.end()) {
|
||||
@@ -640,7 +636,7 @@ bool ShaderCompilerService::shouldCompileSynchronousProgramThisTick() const noex
|
||||
mNumTicksUntilNextSynchronousProgram == 0);
|
||||
}
|
||||
|
||||
void ShaderCompilerService::compilePendingSynchronousPrograms() {
|
||||
void ShaderCompilerService::compilePendingSynchronousPrograms() noexcept {
|
||||
if (mDriver.getDriverConfig().disableAmortizedShaderCompile) {
|
||||
return;
|
||||
}
|
||||
@@ -659,7 +655,7 @@ void ShaderCompilerService::compilePendingSynchronousPrograms() {
|
||||
}
|
||||
|
||||
void ShaderCompilerService::compilePendingSynchronousProgramNow(
|
||||
program_token_t const& token) {
|
||||
program_token_t const& token) noexcept {
|
||||
if (mDriver.getDriverConfig().disableAmortizedShaderCompile) {
|
||||
return;
|
||||
}
|
||||
@@ -696,28 +692,27 @@ void ShaderCompilerService::cancelPendingSynchronousProgram(program_token_t cons
|
||||
/* static */ void ShaderCompilerService::compileShaders(OpenGLContext& context,
|
||||
Program::ShaderSource shadersSource,
|
||||
FixedCapacityVector<Program::SpecializationConstant> const& specializationConstants,
|
||||
bool multiview, program_token_t const& token) {
|
||||
bool multiview, program_token_t const& token) noexcept {
|
||||
FILAMENT_TRACING_CALL(FILAMENT_TRACING_CATEGORY_FILAMENT);
|
||||
|
||||
auto const appendSpecConstantString =
|
||||
+[](CString& s, size_t id, Program::SpecializationConstant const& sc) {
|
||||
s += "#define SPIRV_CROSS_CONSTANT_ID_" + utils::to_string(id) + ' ';
|
||||
s += std::visit([](auto&& arg) { return to_string(arg); }, sc);
|
||||
s += '\n';
|
||||
return s;
|
||||
};
|
||||
auto const appendSpecConstantString = +[](CString& s, Program::SpecializationConstant const& sc) {
|
||||
s += "#define SPIRV_CROSS_CONSTANT_ID_" + utils::to_string(sc.id) + ' ';
|
||||
s += std::visit([](auto&& arg) { return to_string(arg); }, sc.value);
|
||||
s += '\n';
|
||||
return s;
|
||||
};
|
||||
|
||||
CString specializationConstantString;
|
||||
// This constant must match
|
||||
// ReservedSpecializationConstants::CONFIG_STEREO_EYE_COUNT
|
||||
// which we can't use here because it's defined in EngineEnums.h.
|
||||
// (we're breaking layering here, but it's for the good cause).
|
||||
constexpr size_t CONFIG_STEREO_EYE_COUNT = 8;
|
||||
int32_t numViews = specializationConstants.size() >= CONFIG_STEREO_EYE_COUNT
|
||||
? std::get<int32_t>(specializationConstants[CONFIG_STEREO_EYE_COUNT])
|
||||
: 2;
|
||||
for (size_t id = 0; id < specializationConstants.size(); id++) {
|
||||
appendSpecConstantString(specializationConstantString, id, specializationConstants[id]);
|
||||
int32_t numViews = 2;
|
||||
for (auto const& sc: specializationConstants) {
|
||||
appendSpecConstantString(specializationConstantString, sc);
|
||||
if (sc.id == 8) {
|
||||
// This constant must match
|
||||
// ReservedSpecializationConstants::CONFIG_STEREO_EYE_COUNT
|
||||
// which we can't use here because it's defined in EngineEnums.h.
|
||||
// (we're breaking layering here, but it's for the good cause).
|
||||
numViews = std::get<int32_t>(sc.value);
|
||||
}
|
||||
}
|
||||
if (!specializationConstantString.empty()) {
|
||||
specializationConstantString += '\n';
|
||||
@@ -822,7 +817,7 @@ void ShaderCompilerService::cancelPendingSynchronousProgram(program_token_t cons
|
||||
return true;
|
||||
}
|
||||
|
||||
/* static */ void ShaderCompilerService::checkCompileStatus(program_token_t const& token) {
|
||||
/* static */ void ShaderCompilerService::checkCompileStatus(program_token_t const& token) noexcept {
|
||||
FILAMENT_TRACING_CALL(FILAMENT_TRACING_CATEGORY_FILAMENT);
|
||||
|
||||
UTILS_NOUNROLL
|
||||
@@ -844,7 +839,7 @@ void ShaderCompilerService::cancelPendingSynchronousProgram(program_token_t cons
|
||||
}
|
||||
|
||||
/* static */ void ShaderCompilerService::linkProgram(OpenGLContext const& context,
|
||||
program_token_t const& token) {
|
||||
program_token_t const& token) noexcept {
|
||||
FILAMENT_TRACING_CALL(FILAMENT_TRACING_CATEGORY_FILAMENT);
|
||||
|
||||
// Shader compilation should be completed by now. Check the status and log errors on failure.
|
||||
@@ -938,7 +933,7 @@ void ShaderCompilerService::cancelPendingSynchronousProgram(program_token_t cons
|
||||
UTILS_NOINLINE
|
||||
/* static */ void logCompilationError(ShaderStage shaderType, const char* name,
|
||||
GLuint const shaderId,
|
||||
UTILS_UNUSED_IN_RELEASE Program::ShaderBlob const& sourceCode) {
|
||||
UTILS_UNUSED_IN_RELEASE Program::ShaderBlob const& sourceCode) noexcept {
|
||||
|
||||
// Collects the current GL error for additional context. While often redundant,
|
||||
// errors like `GL_CONTEXT_LOST` can occur asynchronously after `glCompileShader`.
|
||||
@@ -1184,7 +1179,7 @@ mediump vec4 unpackSnorm4x8(highp uint v) {
|
||||
// - the version line
|
||||
// - extensions
|
||||
// - everything else
|
||||
/* static */ std::array<std::string_view, 3> splitShaderSource(std::string_view source) {
|
||||
/* static */ std::array<std::string_view, 3> splitShaderSource(std::string_view source) noexcept {
|
||||
auto const version_start = source.find("#version");
|
||||
assert_invariant(version_start != std::string_view::npos);
|
||||
|
||||
|
||||
@@ -148,16 +148,16 @@ private:
|
||||
|
||||
// Methods for SYNCHRONOUS and ASYNCHRONOUS modes.
|
||||
void runAtNextTick(CompilerPriorityQueue priority, program_token_t const& token,
|
||||
Job job);
|
||||
void executeTickOps();
|
||||
Job job) noexcept;
|
||||
void executeTickOps() noexcept;
|
||||
bool cancelTickOp(program_token_t const& token) noexcept;
|
||||
|
||||
bool shouldCompileSynchronousProgramThisTick() const noexcept;
|
||||
void compilePendingSynchronousPrograms();
|
||||
void compilePendingSynchronousProgramNow(program_token_t const& token);
|
||||
void compilePendingSynchronousPrograms() noexcept;
|
||||
void compilePendingSynchronousProgramNow(program_token_t const& token) noexcept;
|
||||
void cancelPendingSynchronousProgram(program_token_t const& token) noexcept;
|
||||
|
||||
void compileProgram(program_token_t const& token, Program&& program);
|
||||
void compileProgram(program_token_t const& token, Program&& program) noexcept;
|
||||
|
||||
// Compile shaders with the given `shaderSource`. `gl.shaders` is always populated with valid
|
||||
// shader IDs after this method. But this doesn't necessarily mean the shaders are successfully
|
||||
@@ -165,20 +165,20 @@ private:
|
||||
static void compileShaders(OpenGLContext& context, Program::ShaderSource shadersSource,
|
||||
utils::FixedCapacityVector<Program::SpecializationConstant> const&
|
||||
specializationConstants,
|
||||
bool multiview, program_token_t const& token);
|
||||
bool multiview, program_token_t const& token) noexcept;
|
||||
|
||||
// Check if the shader compilation is completed. You may want to call this when the extension
|
||||
// `KHR_parallel_shader_compile` is enabled.
|
||||
static bool isCompileCompleted(program_token_t const& token) noexcept;
|
||||
|
||||
// Check compilation status of the shaders and log errors on failure.
|
||||
static void checkCompileStatus(program_token_t const& token);
|
||||
static void checkCompileStatus(program_token_t const& token) noexcept;
|
||||
|
||||
// Create a program by linking the compiled shaders. `gl.program` is always populated with a
|
||||
// valid program ID after this method. But this doesn't necessarily mean the program is
|
||||
// successfully linked. Errors can be checked by calling `checkLinkStatusAndCleanupShaders`
|
||||
// later.
|
||||
static void linkProgram(OpenGLContext const& context, program_token_t const& token);
|
||||
static void linkProgram(OpenGLContext const& context, program_token_t const& token) noexcept;
|
||||
|
||||
// Check if the program link is completed. You may want to call this when the extension
|
||||
// `KHR_parallel_shader_compile` is enabled.
|
||||
|
||||
@@ -148,7 +148,7 @@ PlatformCocoaGL::~PlatformCocoaGL() noexcept {
|
||||
delete pImpl;
|
||||
}
|
||||
|
||||
Driver* PlatformCocoaGL::createDriver(void* sharedContext, const Platform::DriverConfig& driverConfig) {
|
||||
Driver* PlatformCocoaGL::createDriver(void* sharedContext, const Platform::DriverConfig& driverConfig) noexcept {
|
||||
// NSOpenGLPFAColorSize: when unspecified, a format that matches the screen is preferred
|
||||
NSOpenGLPixelFormatAttribute pixelFormatAttributes[] = {
|
||||
NSOpenGLPFAOpenGLProfile, NSOpenGLProfileVersion3_2Core,
|
||||
|
||||
@@ -64,7 +64,7 @@ PlatformCocoaTouchGL::~PlatformCocoaTouchGL() noexcept {
|
||||
delete pImpl;
|
||||
}
|
||||
|
||||
Driver* PlatformCocoaTouchGL::createDriver(void* sharedGLContext, const Platform::DriverConfig& driverConfig) {
|
||||
Driver* PlatformCocoaTouchGL::createDriver(void* sharedGLContext, const Platform::DriverConfig& driverConfig) noexcept {
|
||||
EAGLSharegroup* sharegroup = (__bridge EAGLSharegroup*) sharedGLContext;
|
||||
|
||||
EAGLContext *context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES3 sharegroup:sharegroup];
|
||||
|
||||
@@ -119,7 +119,7 @@ bool PlatformEGL::isOpenGL() const noexcept {
|
||||
|
||||
PlatformEGL::ExternalImageEGL::~ExternalImageEGL() = default;
|
||||
|
||||
Driver* PlatformEGL::createDriver(void* sharedContext, const DriverConfig& driverConfig) {
|
||||
Driver* PlatformEGL::createDriver(void* sharedContext, const DriverConfig& driverConfig) noexcept {
|
||||
mEGLDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
|
||||
assert_invariant(mEGLDisplay != EGL_NO_DISPLAY);
|
||||
|
||||
@@ -500,7 +500,7 @@ bool PlatformEGL::isMSAASwapChainSupported(uint32_t samples) const noexcept {
|
||||
}
|
||||
|
||||
Platform::SwapChain* PlatformEGL::createSwapChain(
|
||||
void* nativeWindow, uint64_t flags) {
|
||||
void* nativeWindow, uint64_t flags) noexcept {
|
||||
|
||||
Config attribs;
|
||||
|
||||
@@ -561,7 +561,7 @@ Platform::SwapChain* PlatformEGL::createSwapChain(
|
||||
}
|
||||
|
||||
Platform::SwapChain* PlatformEGL::createSwapChain(
|
||||
uint32_t width, uint32_t height, uint64_t flags) {
|
||||
uint32_t width, uint32_t height, uint64_t flags) noexcept {
|
||||
|
||||
Config attribs = {
|
||||
{ EGL_WIDTH, EGLint(width) },
|
||||
|
||||
@@ -198,7 +198,7 @@ void backend::PlatformEGLAndroid::preCommit() noexcept {
|
||||
}
|
||||
|
||||
Driver* PlatformEGLAndroid::createDriver(void* sharedContext,
|
||||
const Platform::DriverConfig& driverConfig) {
|
||||
const Platform::DriverConfig& driverConfig) noexcept {
|
||||
|
||||
// the refresh rate default value doesn't matter, we change it later
|
||||
int32_t const tid = gettid();
|
||||
|
||||
@@ -39,7 +39,7 @@ bool PlatformEGLHeadless::isOpenGL() const noexcept {
|
||||
}
|
||||
|
||||
backend::Driver* PlatformEGLHeadless::createDriver(void* sharedContext,
|
||||
const Platform::DriverConfig& driverConfig) {
|
||||
const Platform::DriverConfig& driverConfig) noexcept {
|
||||
EGLBoolean bindAPI = eglBindAPI(EGL_OPENGL_API);
|
||||
if (UTILS_UNLIKELY(!bindAPI)) {
|
||||
LOG(ERROR) << "eglBindAPI EGL_OPENGL_API failed";
|
||||
|
||||
@@ -31,7 +31,6 @@
|
||||
// Function pointer types for X11 functions
|
||||
typedef Display* (* X11_OPEN_DISPLAY)(const char*);
|
||||
typedef Display* (* X11_CLOSE_DISPLAY)(Display*);
|
||||
typedef int (* X11_FREE)(void*);
|
||||
|
||||
// Function pointer types for GLX functions
|
||||
typedef void (* GLX_DESTROY_CONTEXT)(Display*, GLXContext);
|
||||
@@ -44,7 +43,7 @@ struct GLXFunctions {
|
||||
PFNGLXDESTROYPBUFFERPROC destroyPbuffer;
|
||||
PFNGLXMAKECONTEXTCURRENTPROC setCurrentContext;
|
||||
|
||||
/*
|
||||
/*
|
||||
When creating a shared GL context, we query the used
|
||||
GLX_FBCONFIG_ID to make sure our display framebuffer
|
||||
attributes match; otherwise making our context current
|
||||
@@ -53,7 +52,7 @@ struct GLXFunctions {
|
||||
*/
|
||||
PFNGLXQUERYCONTEXTPROC queryContext;
|
||||
|
||||
/*
|
||||
/*
|
||||
When creating a shared GL context, we select the matching
|
||||
GLXFBConfig that is used by the shared GL context. `getFBConfigs`
|
||||
will return all the available GLXFBConfigs.
|
||||
@@ -77,7 +76,6 @@ struct GLXFunctions {
|
||||
struct X11Functions {
|
||||
X11_OPEN_DISPLAY openDisplay;
|
||||
X11_CLOSE_DISPLAY closeDisplay;
|
||||
X11_FREE free;
|
||||
void* library;
|
||||
} g_x11;
|
||||
|
||||
@@ -123,7 +121,6 @@ static bool loadLibraries() {
|
||||
|
||||
g_x11.openDisplay = (X11_OPEN_DISPLAY)dlsym(g_x11.library, "XOpenDisplay");
|
||||
g_x11.closeDisplay = (X11_CLOSE_DISPLAY)dlsym(g_x11.library, "XCloseDisplay");
|
||||
g_x11.free = (X11_FREE)dlsym(g_x11.library, "XFree");
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -132,7 +129,7 @@ namespace filament::backend {
|
||||
using namespace backend;
|
||||
|
||||
Driver* PlatformGLX::createDriver(void* sharedGLContext,
|
||||
const DriverConfig& driverConfig) {
|
||||
const DriverConfig& driverConfig) noexcept {
|
||||
loadLibraries();
|
||||
// Get the display device
|
||||
mGLXDisplay = g_x11.openDisplay(NULL);
|
||||
@@ -154,13 +151,16 @@ Driver* PlatformGLX::createDriver(void* sharedGLContext,
|
||||
|
||||
int numConfigs = 0;
|
||||
GLXFBConfig* fbConfigs = g_glx.getFbConfigs(mGLXDisplay, 0, &numConfigs);
|
||||
|
||||
if (fbConfigs == nullptr) {
|
||||
LOG(ERROR) << "Failed to get the available GLXFBConfigs.";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
int fbId = 0;
|
||||
int fbIndex = -1;
|
||||
|
||||
for (int i = 0; i < numConfigs; ++i) {
|
||||
int fbId = 0;
|
||||
r = g_glx.getFbConfigAttrib(mGLXDisplay, fbConfigs[i], GLX_FBCONFIG_ID, &fbId);
|
||||
if (r != 0) {
|
||||
LOG(ERROR) << "Failed to get GLX_FBCONFIG_ID for entry " << i << ".";
|
||||
@@ -168,17 +168,17 @@ Driver* PlatformGLX::createDriver(void* sharedGLContext,
|
||||
}
|
||||
|
||||
if (fbId == usedFbId) {
|
||||
mGLXConfig = fbConfigs[i];
|
||||
fbIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
g_x11.free(fbConfigs);
|
||||
|
||||
if (!mGLXConfig) {
|
||||
if (fbIndex < 0) {
|
||||
LOG(ERROR) << "Failed to find an `GLXFBConfig` with the requested ID.";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
mGLXConfig = fbConfigs + fbIndex;
|
||||
} else {
|
||||
// Create a context
|
||||
static int attribs[] = {
|
||||
@@ -188,17 +188,17 @@ Driver* PlatformGLX::createDriver(void* sharedGLContext,
|
||||
};
|
||||
|
||||
int configCount = 0;
|
||||
GLXFBConfig* fbConfigs = g_glx.chooseFbConfig(mGLXDisplay, DefaultScreen(mGLXDisplay),
|
||||
mGLXConfig = g_glx.chooseFbConfig(mGLXDisplay, DefaultScreen(mGLXDisplay),
|
||||
attribs, &configCount);
|
||||
if (fbConfigs == nullptr || configCount == 0) {
|
||||
if (mGLXConfig == nullptr || configCount == 0) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
mGLXConfig = fbConfigs[0];
|
||||
g_x11.free(fbConfigs);
|
||||
}
|
||||
|
||||
if (g_glx.createContext == nullptr) {
|
||||
PFNGLXCREATECONTEXTATTRIBSARBPROC glXCreateContextAttribs = (PFNGLXCREATECONTEXTATTRIBSARBPROC)
|
||||
getProcAddress((GLubyte*)"glXCreateContextAttribsARB");
|
||||
|
||||
if (glXCreateContextAttribs == nullptr) {
|
||||
LOG(INFO) << "Unable to retrieve function pointer for `glXCreateContextAttribs()`.";
|
||||
return nullptr;
|
||||
}
|
||||
@@ -209,7 +209,7 @@ Driver* PlatformGLX::createDriver(void* sharedGLContext,
|
||||
GL_NONE
|
||||
};
|
||||
|
||||
mGLXContext = g_glx.createContext(mGLXDisplay, mGLXConfig,
|
||||
mGLXContext = g_glx.createContext(mGLXDisplay, mGLXConfig[0],
|
||||
(GLXContext)sharedGLContext, True, contextAttribs);
|
||||
|
||||
int pbufferAttribs[] = {
|
||||
@@ -218,7 +218,7 @@ Driver* PlatformGLX::createDriver(void* sharedGLContext,
|
||||
GL_NONE
|
||||
};
|
||||
|
||||
mDummySurface = g_glx.createPbuffer(mGLXDisplay, mGLXConfig, pbufferAttribs);
|
||||
mDummySurface = g_glx.createPbuffer(mGLXDisplay, mGLXConfig[0], pbufferAttribs);
|
||||
g_glx.setCurrentContext(mGLXDisplay, mDummySurface, mDummySurface, mGLXContext);
|
||||
|
||||
int result = bluegl::bind();
|
||||
@@ -246,7 +246,7 @@ Platform::SwapChain* PlatformGLX::createSwapChain(
|
||||
GLX_PBUFFER_HEIGHT, int(height),
|
||||
GL_NONE
|
||||
};
|
||||
GLXPbuffer sur = g_glx.createPbuffer(mGLXDisplay, mGLXConfig, pbufferAttribs);
|
||||
GLXPbuffer sur = g_glx.createPbuffer(mGLXDisplay, mGLXConfig[0], pbufferAttribs);
|
||||
if (sur) {
|
||||
mPBuffers.push_back(sur);
|
||||
}
|
||||
|
||||
@@ -113,7 +113,7 @@ private:
|
||||
}// anonymous namespace
|
||||
|
||||
Driver* PlatformOSMesa::createDriver(void* sharedGLContext,
|
||||
const DriverConfig& driverConfig) {
|
||||
const DriverConfig& driverConfig) noexcept {
|
||||
|
||||
OSMesaAPI* api = new OSMesaAPI();
|
||||
mOsMesaApi = api;
|
||||
|
||||
@@ -75,7 +75,7 @@ struct WGLSwapChain {
|
||||
static PFNWGLCREATECONTEXTATTRIBSARBPROC wglCreateContextAttribs = nullptr;
|
||||
|
||||
Driver* PlatformWGL::createDriver(void* sharedGLContext,
|
||||
const Platform::DriverConfig& driverConfig) {
|
||||
const Platform::DriverConfig& driverConfig) noexcept {
|
||||
int result = 0;
|
||||
int pixelFormat = 0;
|
||||
DWORD dwError = 0;
|
||||
@@ -124,6 +124,8 @@ Driver* PlatformWGL::createDriver(void* sharedGLContext,
|
||||
(PFNWGLCREATECONTEXTATTRIBSARBPROC) wglGetProcAddress("wglCreateContextAttribsARB");
|
||||
|
||||
// try all versions down, from GL 4.5 to 4.1
|
||||
|
||||
|
||||
for (int minor = 5; minor >= 1; minor--) {
|
||||
mAttribs = {
|
||||
WGL_CONTEXT_MAJOR_VERSION_ARB, 4,
|
||||
@@ -142,18 +144,6 @@ Driver* PlatformWGL::createDriver(void* sharedGLContext,
|
||||
goto error;
|
||||
}
|
||||
|
||||
// Create shared contexts here for use by other threads. This is a Windows specific workaround
|
||||
// necessitated by the requirement that shared contexts must be initialized on the same thread
|
||||
// as the primary context. If more shared contexts are necessary, the constant
|
||||
// SHARED_CONTEXT_NUM must be updated.
|
||||
for (int i = 0; i < SHARED_CONTEXT_NUM; ++i) {
|
||||
HGLRC context = wglCreateContextAttribs(mWhdc, mContext, mAttribs.data());
|
||||
if (context) {
|
||||
mAdditionalContexts.push_back(context);
|
||||
}
|
||||
}
|
||||
|
||||
// Delete the temporary context
|
||||
wglMakeCurrent(NULL, NULL);
|
||||
wglDeleteContext(tempContext);
|
||||
tempContext = NULL;
|
||||
@@ -179,17 +169,13 @@ error:
|
||||
}
|
||||
|
||||
bool PlatformWGL::isExtraContextSupported() const noexcept {
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
void PlatformWGL::createContext(bool shared) {
|
||||
int nextIndex = mNextFreeSharedContextIndex.fetch_add(1, std::memory_order_relaxed);
|
||||
FILAMENT_CHECK_PRECONDITION(nextIndex < SHARED_CONTEXT_NUM)
|
||||
<< "Shared context index out of range. Increase SHARED_CONTEXT_NUM.";
|
||||
|
||||
HGLRC context = mAdditionalContexts[nextIndex];
|
||||
BOOL result = wglMakeCurrent(mWhdc, context);
|
||||
FILAMENT_CHECK_POSTCONDITION(result) << "Failed to make current.";
|
||||
HGLRC context = wglCreateContextAttribs(mWhdc, shared ? mContext : nullptr, mAttribs.data());
|
||||
wglMakeCurrent(mWhdc, context);
|
||||
mAdditionalContexts.push_back(context);
|
||||
}
|
||||
|
||||
void PlatformWGL::terminate() noexcept {
|
||||
|
||||
@@ -21,7 +21,7 @@ namespace filament::backend {
|
||||
using namespace backend;
|
||||
|
||||
Driver* PlatformWebGL::createDriver(void* sharedGLContext,
|
||||
const Platform::DriverConfig& driverConfig) {
|
||||
const Platform::DriverConfig& driverConfig) noexcept {
|
||||
return OpenGLPlatform::createDefaultDriver(this, sharedGLContext, driverConfig);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,82 +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 "VulkanAsyncHandles.h"
|
||||
|
||||
#include <backend/DriverEnums.h>
|
||||
|
||||
#include <utils/debug.h>
|
||||
|
||||
#include <cstdint>
|
||||
#include <mutex>
|
||||
#include <shared_mutex>
|
||||
#include <chrono>
|
||||
|
||||
using namespace bluevk;
|
||||
|
||||
namespace filament::backend {
|
||||
|
||||
FenceStatus VulkanCmdFence::wait(VkDevice device, uint64_t const timeout,
|
||||
std::chrono::steady_clock::time_point const until) {
|
||||
|
||||
std::shared_lock l(mLock);
|
||||
|
||||
// If the vulkan fence has not been submitted yet, we need to wait for that before we
|
||||
// can use vkWaitForFences()
|
||||
if (mStatus == VK_INCOMPLETE) {
|
||||
bool const success = mCond.wait_until(l, until, [this] {
|
||||
// Internally we use the VK_INCOMPLETE status to mean "not yet submitted".
|
||||
// When this fence gets submitted, its status changes to VK_NOT_READY.
|
||||
return mStatus != VK_INCOMPLETE;
|
||||
});
|
||||
if (!success) {
|
||||
// !success indicates a timeout
|
||||
return FenceStatus::TIMEOUT_EXPIRED;
|
||||
}
|
||||
}
|
||||
|
||||
// The fence could have already signaled, avoid calling into vkWaitForFences()
|
||||
if (mStatus == VK_SUCCESS) {
|
||||
return FenceStatus::CONDITION_SATISFIED;
|
||||
}
|
||||
|
||||
// If we're here, we know that vkQueueSubmit has been called (because it sets the status
|
||||
// to VK_NOT_READY).
|
||||
// Now really wait for the fence while holding the shared_lock, this allows several
|
||||
// threads to call vkWaitForFences(), but will prevent vkResetFence from taking
|
||||
// place simultaneously. vkResetFence is only called once it knows the fence has signaled,
|
||||
// which guaranties that vkResetFence won't have to wait too long, just enough for
|
||||
// all the vkWaitForFences() to return.
|
||||
mStatus = vkWaitForFences(device, 1, &mFence, VK_TRUE, timeout);
|
||||
if (mStatus == VK_SUCCESS) {
|
||||
return FenceStatus::CONDITION_SATISFIED;
|
||||
}
|
||||
if (mStatus == VK_TIMEOUT) {
|
||||
return FenceStatus::TIMEOUT_EXPIRED;
|
||||
}
|
||||
return FenceStatus::ERROR; // not supported
|
||||
}
|
||||
|
||||
void VulkanCmdFence::resetFence(VkDevice device) {
|
||||
// This lock prevents vkResetFences() from being called simultaneously with vkWaitForFences(),
|
||||
// but by construction, when we're here, we know that the fence has signaled and
|
||||
// vkWaitForFences() will return shortly.
|
||||
std::lock_guard const l(mLock);
|
||||
assert_invariant(mStatus == VK_SUCCESS);
|
||||
vkResetFences(device, 1, &mFence);
|
||||
}
|
||||
|
||||
} // namespace filament::backend
|
||||
@@ -20,81 +20,37 @@
|
||||
#include <bluevk/BlueVK.h>
|
||||
|
||||
#include "DriverBase.h"
|
||||
#include "backend/DriverEnums.h"
|
||||
#include "backend/Platform.h"
|
||||
|
||||
#include "vulkan/memory/Resource.h"
|
||||
|
||||
#include <chrono>
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <shared_mutex>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
#include <utils/Mutex.h>
|
||||
#include <utils/Condition.h>
|
||||
|
||||
namespace filament::backend {
|
||||
|
||||
// Wrapper to enable use of shared_ptr for implementing shared ownership of low-level Vulkan fences.
|
||||
struct VulkanCmdFence {
|
||||
explicit VulkanCmdFence(VkFence fence) : mFence(fence) { }
|
||||
VulkanCmdFence(VkResult initialStatus) {
|
||||
// Internally we use the VK_INCOMPLETE status to mean "not yet submitted". When this fence
|
||||
// gets submitted, its status changes to VK_NOT_READY. Finally, when the GPU actually
|
||||
// finishes executing the command buffer, the status changes to VK_SUCCESS.
|
||||
status.store(initialStatus);
|
||||
}
|
||||
|
||||
~VulkanCmdFence() = default;
|
||||
|
||||
void setStatus(VkResult const value) {
|
||||
std::lock_guard const l(mLock);
|
||||
mStatus = value;
|
||||
mCond.notify_all();
|
||||
}
|
||||
void setStatus(VkResult value) { status.store(value); }
|
||||
|
||||
VkResult getStatus() {
|
||||
std::shared_lock const l(mLock);
|
||||
return mStatus;
|
||||
}
|
||||
|
||||
void resetFence(VkDevice device);
|
||||
|
||||
FenceStatus wait(VkDevice device, uint64_t timeout,
|
||||
std::chrono::steady_clock::time_point until);
|
||||
VkResult getStatus() { return status.load(std::memory_order_acquire); }
|
||||
|
||||
private:
|
||||
std::shared_mutex mLock; // NOLINT(*-include-cleaner)
|
||||
std::condition_variable_any mCond;
|
||||
// Internally we use the VK_INCOMPLETE status to mean "not yet submitted". When this fence
|
||||
// gets submitted, its status changes to VK_NOT_READY. Finally, when the GPU actually
|
||||
// finishes executing the command buffer, the status changes to VK_SUCCESS.
|
||||
VkResult mStatus{ VK_INCOMPLETE };
|
||||
VkFence mFence;
|
||||
std::atomic<VkResult> status;
|
||||
};
|
||||
|
||||
struct VulkanFence : public HwFence, fvkmemory::ThreadSafeResource {
|
||||
VulkanFence() {}
|
||||
|
||||
void setFence(std::shared_ptr<VulkanCmdFence> fence) {
|
||||
std::lock_guard lock(mState->lock);
|
||||
mState->sharedFence = std::move(fence);
|
||||
mState->cond.notify_all();
|
||||
}
|
||||
|
||||
std::shared_ptr<VulkanCmdFence>& getSharedFence() {
|
||||
std::lock_guard lock(mState->lock);
|
||||
return mState->sharedFence;
|
||||
}
|
||||
|
||||
std::shared_ptr<VulkanCmdFence> wait(std::chrono::steady_clock::time_point const until) {
|
||||
// hold a reference so that our state doesn't disappear while we wait
|
||||
std::shared_ptr state{ mState };
|
||||
std::unique_lock lock(state->lock);
|
||||
state->cond.wait_until(lock, until, [&state] { return bool(state->sharedFence); });
|
||||
// here mSharedFence will be null if we timed out
|
||||
return state->sharedFence;
|
||||
}
|
||||
private:
|
||||
struct State {
|
||||
std::mutex lock;
|
||||
std::condition_variable cond;
|
||||
std::shared_ptr<VulkanCmdFence> sharedFence;
|
||||
};
|
||||
std::shared_ptr<State> mState{ std::make_shared<State>() };
|
||||
std::shared_ptr<VulkanCmdFence> fence;
|
||||
};
|
||||
|
||||
struct VulkanSync : fvkmemory::ThreadSafeResource, public HwSync {
|
||||
@@ -116,12 +72,12 @@ struct VulkanTimerQuery : public HwTimerQuery, fvkmemory::ThreadSafeResource {
|
||||
mStoppingQueryIndex(stoppingIndex) {}
|
||||
|
||||
void setFence(std::shared_ptr<VulkanCmdFence> fence) noexcept {
|
||||
std::unique_lock const lock(mFenceMutex);
|
||||
mFence = std::move(fence);
|
||||
std::unique_lock<utils::Mutex> lock(mFenceMutex);
|
||||
mFence = fence;
|
||||
}
|
||||
|
||||
bool isCompleted() noexcept {
|
||||
std::unique_lock const lock(mFenceMutex);
|
||||
std::unique_lock<utils::Mutex> lock(mFenceMutex);
|
||||
// QueryValue is a synchronous call and might occur before beginTimerQuery has written
|
||||
// anything into the command buffer, which is an error according to the validation layer
|
||||
// that ships in the Android NDK. Even when AVAILABILITY_BIT is set, validation seems to
|
||||
|
||||
@@ -28,24 +28,24 @@ namespace filament::backend {
|
||||
|
||||
namespace {
|
||||
|
||||
VkBufferUsageFlags getVkBufferUsage(VulkanBufferBinding usage) {
|
||||
VkBufferUsageFlags getVkBufferUsage(VulkanBufferUsage usage) {
|
||||
switch (usage) {
|
||||
case VulkanBufferBinding::VERTEX:
|
||||
case VulkanBufferUsage::VERTEX:
|
||||
return VK_BUFFER_USAGE_VERTEX_BUFFER_BIT;
|
||||
case VulkanBufferBinding::INDEX:
|
||||
case VulkanBufferUsage::INDEX:
|
||||
return VK_BUFFER_USAGE_INDEX_BUFFER_BIT;
|
||||
case VulkanBufferBinding::UNIFORM:
|
||||
case VulkanBufferUsage::UNIFORM:
|
||||
return VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT;
|
||||
case VulkanBufferBinding::SHADER_STORAGE:
|
||||
case VulkanBufferUsage::SHADER_STORAGE:
|
||||
return VK_BUFFER_USAGE_STORAGE_BUFFER_BIT;
|
||||
case VulkanBufferBinding::UNKNOWN:
|
||||
case VulkanBufferUsage::UNKNOWN:
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
}// namespace
|
||||
|
||||
VulkanBufferCache::VulkanBufferCache(VulkanContext const& context,
|
||||
fvkmemory::ResourceManager& resourceManager, VmaAllocator allocator)
|
||||
@@ -53,11 +53,11 @@ VulkanBufferCache::VulkanBufferCache(VulkanContext const& context,
|
||||
mResourceManager(resourceManager),
|
||||
mAllocator(allocator) {}
|
||||
|
||||
fvkmemory::resource_ptr<VulkanBuffer> VulkanBufferCache::acquire(VulkanBufferBinding binding,
|
||||
fvkmemory::resource_ptr<VulkanBuffer> VulkanBufferCache::acquire(VulkanBufferUsage usage,
|
||||
uint32_t numBytes) noexcept {
|
||||
assert_invariant(binding != VulkanBufferBinding::UNKNOWN);
|
||||
assert_invariant(usage != VulkanBufferUsage::UNKNOWN);
|
||||
|
||||
BufferPool& bufferPool = getPool(binding);
|
||||
BufferPool& bufferPool = getPool(usage);
|
||||
|
||||
// First check if an allocation exists whose capacity is greater than or equal to the requested
|
||||
// size.
|
||||
@@ -71,7 +71,7 @@ fvkmemory::resource_ptr<VulkanBuffer> VulkanBufferCache::acquire(VulkanBufferBin
|
||||
|
||||
// We were not able to find a sufficiently large allocation, so create a new one that is
|
||||
// recycled after being yielded.
|
||||
VulkanGpuBuffer const* gpuBuffer = allocate(binding, numBytes);
|
||||
VulkanGpuBuffer const* gpuBuffer = allocate(usage, numBytes);
|
||||
return fvkmemory::resource_ptr<VulkanBuffer>::construct(&mResourceManager, gpuBuffer,
|
||||
[this](VulkanGpuBuffer const* gpuBuffer) { this->release(gpuBuffer); });
|
||||
}
|
||||
@@ -93,10 +93,9 @@ void VulkanBufferCache::gc() noexcept {
|
||||
if (poolIter->second.lastAccessed < evictionTime) {
|
||||
#if FVK_ENABLED(FVK_DEBUG_VULKAN_BUFFER_CACHE)
|
||||
FVK_LOGD << "VulkanBufferCache - Destroyed vkBuffer "
|
||||
<< poolIter->second.gpuBuffer->vkbuffer << " with binding "
|
||||
<< static_cast<int>(poolIter->second.gpuBuffer->binding)
|
||||
<< utils::io::endl;
|
||||
#endif // FVK_DEBUG_VULKAN_BUFFER_CACHE
|
||||
<< poolIter->second.gpuBuffer->vkbuffer << " with usage "
|
||||
<< static_cast<int>(poolIter->second.gpuBuffer->usage) << utils::io::endl;
|
||||
#endif// FVK_DEBUG_VULKAN_BUFFER_CACHE
|
||||
|
||||
destroy(poolIter->second.gpuBuffer);
|
||||
poolIter = bufferPool.erase(poolIter);
|
||||
@@ -121,33 +120,35 @@ void VulkanBufferCache::terminate() noexcept {
|
||||
void VulkanBufferCache::release(VulkanGpuBuffer const* gpuBuffer) noexcept {
|
||||
assert_invariant(gpuBuffer != nullptr);
|
||||
|
||||
BufferPool& bufferPool = getPool(gpuBuffer->binding);
|
||||
BufferPool& bufferPool = getPool(gpuBuffer->usage);
|
||||
bufferPool.insert(std::make_pair(gpuBuffer->numBytes, UnusedGpuBuffer{
|
||||
.lastAccessed = mCurrentFrame,
|
||||
.gpuBuffer = gpuBuffer,
|
||||
}));
|
||||
}
|
||||
|
||||
VulkanGpuBuffer const* VulkanBufferCache::allocate(VulkanBufferBinding binding,
|
||||
VulkanGpuBuffer const* VulkanBufferCache::allocate(VulkanBufferUsage usage,
|
||||
uint32_t numBytes) noexcept {
|
||||
VkBufferCreateInfo const bufferInfo{
|
||||
.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
|
||||
.size = numBytes,
|
||||
// `VK_BUFFER_USAGE_TRANSFER_DST_BIT` is needed to allow updating the buffer through
|
||||
// a staging using `vkCmdCopyBuffer`.
|
||||
.usage = getVkBufferUsage(binding) | VK_BUFFER_USAGE_TRANSFER_DST_BIT,
|
||||
.usage = getVkBufferUsage(usage) | VK_BUFFER_USAGE_TRANSFER_DST_BIT,
|
||||
};
|
||||
|
||||
VmaAllocationCreateFlags vmaFlags = 0;
|
||||
// In the case of UMA, the buffers will always be mappable
|
||||
if (mContext.isUnifiedMemoryArchitecture()) {
|
||||
vmaFlags |= VMA_ALLOCATION_CREATE_MAPPED_BIT |
|
||||
VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT;
|
||||
if (usage == VulkanBufferUsage::UNIFORM) {
|
||||
// In the case of UMA, the uniform buffers will always be mappable
|
||||
if (mContext.isUnifiedMemoryArchitecture()) {
|
||||
vmaFlags |= VMA_ALLOCATION_CREATE_MAPPED_BIT |
|
||||
VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT;
|
||||
}
|
||||
}
|
||||
|
||||
VulkanGpuBuffer* gpuBuffer = new VulkanGpuBuffer{
|
||||
.numBytes = numBytes,
|
||||
.binding = binding,
|
||||
.usage = usage,
|
||||
};
|
||||
VmaAllocationCreateInfo const allocInfo{
|
||||
.flags = vmaFlags,
|
||||
@@ -160,14 +161,14 @@ VulkanGpuBuffer const* VulkanBufferCache::allocate(VulkanBufferBinding binding,
|
||||
#if FVK_ENABLED(FVK_DEBUG_VULKAN_BUFFER_CACHE)
|
||||
if (result != VK_SUCCESS) {
|
||||
FVK_LOGE << "VulkanBufferCache - failed to allocate a new vkBuffer of size " << numBytes
|
||||
<< " and binding " << static_cast<int>(binding) << ", error: " << result
|
||||
<< " and usage " << static_cast<int>(usage) << ", error: " << result
|
||||
<< utils::io::endl;
|
||||
} else {
|
||||
FVK_LOGD << "VulkanBufferCache - allocated a vkBuffer " << gpuBuffer->vkbuffer
|
||||
<< " of size " << numBytes << " and binding = " << static_cast<int>(binding)
|
||||
<< " of size " << numBytes << " and usage = " << static_cast<int>(usage)
|
||||
<< " successfully" << utils::io::endl;
|
||||
}
|
||||
#endif // FVK_DEBUG_VULKAN_BUFFER_CACHE
|
||||
#endif// FVK_DEBUG_VULKAN_BUFFER_CACHE
|
||||
|
||||
return gpuBuffer;
|
||||
}
|
||||
@@ -178,24 +179,24 @@ void VulkanBufferCache::destroy(VulkanGpuBuffer const* gpuBuffer) noexcept {
|
||||
gpuBuffer = nullptr;
|
||||
}
|
||||
|
||||
VulkanBufferCache::BufferPool& VulkanBufferCache::getPool(VulkanBufferBinding binding) noexcept {
|
||||
VulkanBufferCache::BufferPool& VulkanBufferCache::getPool(VulkanBufferUsage usage) noexcept {
|
||||
|
||||
int poolIndex = -1;
|
||||
switch (binding) {
|
||||
case VulkanBufferBinding::VERTEX:
|
||||
switch (usage) {
|
||||
case VulkanBufferUsage::VERTEX:
|
||||
poolIndex = 0;
|
||||
break;
|
||||
case VulkanBufferBinding::INDEX:
|
||||
case VulkanBufferUsage::INDEX:
|
||||
poolIndex = 1;
|
||||
break;
|
||||
case VulkanBufferBinding::UNIFORM:
|
||||
case VulkanBufferUsage::UNIFORM:
|
||||
poolIndex = 2;
|
||||
break;
|
||||
case VulkanBufferBinding::SHADER_STORAGE:
|
||||
case VulkanBufferUsage::SHADER_STORAGE:
|
||||
poolIndex = 3;
|
||||
break;
|
||||
case VulkanBufferBinding::UNKNOWN:
|
||||
PANIC_LOG("There's no pool for buffers with unkown binding.");
|
||||
case VulkanBufferUsage::UNKNOWN:
|
||||
PANIC_LOG("There's no pool for buffers with unkown usage.");
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -203,4 +204,4 @@ VulkanBufferCache::BufferPool& VulkanBufferCache::getPool(VulkanBufferBinding bi
|
||||
return mGpuBufferPools[poolIndex];
|
||||
}
|
||||
|
||||
} // namespace filament::backend
|
||||
}// namespace filament::backend
|
||||
|
||||
@@ -38,7 +38,7 @@ public:
|
||||
|
||||
// Allocates or reuse a new VkBuffer that is device local.
|
||||
// In the case of Unified memory architecture, uniform buffers are also host visible.
|
||||
fvkmemory::resource_ptr<VulkanBuffer> acquire(VulkanBufferBinding binding,
|
||||
fvkmemory::resource_ptr<VulkanBuffer> acquire(VulkanBufferUsage usage,
|
||||
uint32_t numBytes) noexcept;
|
||||
|
||||
// Evicts old unused `VulkanGpuBuffer` and bumps the current frame number
|
||||
@@ -60,12 +60,12 @@ private:
|
||||
void release(VulkanGpuBuffer const* gpuBuffer) noexcept;
|
||||
|
||||
// Allocate a new VkBuffer from the VMA pool of the corresponding `numBytes` and `usage`.
|
||||
VulkanGpuBuffer const* allocate(VulkanBufferBinding binding, uint32_t numBytes) noexcept;
|
||||
VulkanGpuBuffer const* allocate(VulkanBufferUsage usage, uint32_t numBytes) noexcept;
|
||||
|
||||
// Destroy the corresponding VkBuffer and return the VkDeviceMemory to the VMA pool.
|
||||
void destroy(VulkanGpuBuffer const* gpuBuffer) noexcept;
|
||||
|
||||
BufferPool& getPool(VulkanBufferBinding binding) noexcept;
|
||||
BufferPool& getPool(VulkanBufferUsage usage) noexcept;
|
||||
|
||||
VulkanContext const& mContext;
|
||||
fvkmemory::ResourceManager& mResourceManager;
|
||||
|
||||
@@ -19,25 +19,22 @@
|
||||
#include "VulkanBufferCache.h"
|
||||
#include "VulkanCommands.h"
|
||||
#include "VulkanContext.h"
|
||||
#include "VulkanHandles.h"
|
||||
#include "VulkanMemory.h"
|
||||
|
||||
#include <backend/DriverEnums.h>
|
||||
#include "VulkanHandles.h"
|
||||
|
||||
using namespace bluevk;
|
||||
|
||||
namespace filament::backend {
|
||||
|
||||
VulkanBufferProxy::VulkanBufferProxy(VulkanContext const& context, VmaAllocator allocator,
|
||||
VulkanStagePool& stagePool, VulkanBufferCache& bufferCache, VulkanBufferBinding binding,
|
||||
BufferUsage usage, uint32_t numBytes)
|
||||
VulkanStagePool& stagePool, VulkanBufferCache& bufferCache, VulkanBufferUsage usage,
|
||||
uint32_t numBytes)
|
||||
: mStagingBufferBypassEnabled(context.stagingBufferBypassEnabled()),
|
||||
mAllocator(allocator),
|
||||
mStagePool(stagePool),
|
||||
mBufferCache(bufferCache),
|
||||
mBuffer(mBufferCache.acquire(binding, numBytes)),
|
||||
mLastReadAge(0),
|
||||
mUsage(usage) {}
|
||||
mBuffer(mBufferCache.acquire(usage, numBytes)),
|
||||
mLastReadAge(0) {}
|
||||
|
||||
void VulkanBufferProxy::loadFromCpu(VulkanCommandBuffer& commands, const void* cpuData,
|
||||
uint32_t byteOffset, uint32_t numBytes) {
|
||||
@@ -52,18 +49,12 @@ void VulkanBufferProxy::loadFromCpu(VulkanCommandBuffer& commands, const void* c
|
||||
commands.acquire(mBuffer);
|
||||
|
||||
// Check if we can just memcpy directly to the GPU memory.
|
||||
// This is only allowed for UNIFORMS that are AVAILABLE and the memory is HOST_VISIBLE
|
||||
// (supports memcpy from host). This works regardless if it's a full or partial update of the
|
||||
// buffer.
|
||||
bool const isMemcopyable = mBuffer->getGpuBuffer()->allocationInfo.pMappedData != nullptr;
|
||||
|
||||
// In the case of UNIFORMS, check that is available to see to know if a memcpy is possible.
|
||||
// This works regardless if it's a full or partial update of the buffer.
|
||||
bool const isUniformAndAvailable = getBinding() == VulkanBufferBinding::UNIFORM && isAvailable;
|
||||
|
||||
// In the case the content is marked as memory mapped or static, is guaranteed to be safe to do
|
||||
// a memcpy if its available.
|
||||
bool const isStaticOrShared =
|
||||
any(mUsage & (BufferUsage::STATIC | BufferUsage::SHARED_WRITE_BIT));
|
||||
bool const useMemcpy = (isUniformAndAvailable || isStaticOrShared) && isMemcopyable &&
|
||||
mStagingBufferBypassEnabled;
|
||||
bool const isUniform = getUsage() == VulkanBufferUsage::UNIFORM;
|
||||
bool const useMemcpy = isUniform && isMemcopyable && isAvailable && mStagingBufferBypassEnabled;
|
||||
if (useMemcpy) {
|
||||
char* dest = static_cast<char*>(mBuffer->getGpuBuffer()->allocationInfo.pMappedData) +
|
||||
byteOffset;
|
||||
@@ -90,13 +81,13 @@ void VulkanBufferProxy::loadFromCpu(VulkanCommandBuffer& commands, const void* c
|
||||
if (!isAvailable) {
|
||||
VkAccessFlags srcAccess = 0;
|
||||
VkPipelineStageFlags srcStage = 0;
|
||||
if (getBinding() == VulkanBufferBinding::UNIFORM) {
|
||||
if (getUsage() == VulkanBufferUsage::UNIFORM) {
|
||||
srcAccess = VK_ACCESS_SHADER_READ_BIT;
|
||||
srcStage = VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
|
||||
} else if (getBinding() == VulkanBufferBinding::VERTEX) {
|
||||
} else if (getUsage() == VulkanBufferUsage::VERTEX) {
|
||||
srcAccess = VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT;
|
||||
srcStage = VK_PIPELINE_STAGE_VERTEX_INPUT_BIT;
|
||||
} else if (getBinding() == VulkanBufferBinding::INDEX) {
|
||||
} else if (getUsage() == VulkanBufferUsage::INDEX) {
|
||||
srcAccess = VK_ACCESS_INDEX_READ_BIT;
|
||||
srcStage = VK_PIPELINE_STAGE_VERTEX_INPUT_BIT;
|
||||
}
|
||||
@@ -129,16 +120,16 @@ void VulkanBufferProxy::loadFromCpu(VulkanCommandBuffer& commands, const void* c
|
||||
VkAccessFlags dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
|
||||
VkPipelineStageFlags dstStageMask = VK_PIPELINE_STAGE_TRANSFER_BIT;
|
||||
|
||||
if (getBinding() == VulkanBufferBinding::VERTEX) {
|
||||
if (getUsage() == VulkanBufferUsage::VERTEX) {
|
||||
dstAccessMask |= VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT;
|
||||
dstStageMask |= VK_PIPELINE_STAGE_VERTEX_INPUT_BIT;
|
||||
} else if (getBinding() == VulkanBufferBinding::INDEX) {
|
||||
} else if (getUsage() == VulkanBufferUsage::INDEX) {
|
||||
dstAccessMask |= VK_ACCESS_INDEX_READ_BIT;
|
||||
dstStageMask |= VK_PIPELINE_STAGE_VERTEX_INPUT_BIT;
|
||||
} else if (getBinding() == VulkanBufferBinding::UNIFORM) {
|
||||
} else if (getUsage() == VulkanBufferUsage::UNIFORM) {
|
||||
dstAccessMask |= VK_ACCESS_SHADER_READ_BIT;
|
||||
dstStageMask |= VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_VERTEX_SHADER_BIT;
|
||||
} else if (getBinding() == VulkanBufferBinding::SHADER_STORAGE) {
|
||||
} else if (getUsage() == VulkanBufferUsage::SHADER_STORAGE) {
|
||||
// TODO: implement me
|
||||
}
|
||||
|
||||
@@ -161,8 +152,8 @@ VkBuffer VulkanBufferProxy::getVkBuffer() const noexcept {
|
||||
return mBuffer->getGpuBuffer()->vkbuffer;
|
||||
}
|
||||
|
||||
VulkanBufferBinding VulkanBufferProxy::getBinding() const noexcept {
|
||||
return mBuffer->getGpuBuffer()->binding;
|
||||
VulkanBufferUsage VulkanBufferProxy::getUsage() const noexcept {
|
||||
return mBuffer->getGpuBuffer()->usage;
|
||||
}
|
||||
|
||||
void VulkanBufferProxy::referencedBy(VulkanCommandBuffer& commands) {
|
||||
|
||||
@@ -23,8 +23,6 @@
|
||||
#include "VulkanMemory.h"
|
||||
#include "VulkanStagePool.h"
|
||||
|
||||
#include <backend/DriverEnums.h>
|
||||
|
||||
namespace filament::backend {
|
||||
|
||||
struct VulkanDescriptorSet;
|
||||
@@ -35,8 +33,8 @@ struct VulkanCommandBuffer;
|
||||
class VulkanBufferProxy {
|
||||
public:
|
||||
VulkanBufferProxy(VulkanContext const& context, VmaAllocator allocator,
|
||||
VulkanStagePool& stagePool, VulkanBufferCache& bufferCache, VulkanBufferBinding binding,
|
||||
BufferUsage usage, uint32_t numBytes);
|
||||
VulkanStagePool& stagePool, VulkanBufferCache& bufferCache, VulkanBufferUsage usage,
|
||||
uint32_t numBytes);
|
||||
|
||||
void loadFromCpu(VulkanCommandBuffer& commands, const void* cpuData, uint32_t byteOffset,
|
||||
uint32_t numBytes);
|
||||
@@ -46,7 +44,7 @@ public:
|
||||
void referencedBy(VulkanCommandBuffer& commands);
|
||||
|
||||
private:
|
||||
VulkanBufferBinding getBinding() const noexcept;
|
||||
VulkanBufferUsage getUsage() const noexcept;
|
||||
|
||||
bool const mStagingBufferBypassEnabled;
|
||||
VmaAllocator mAllocator;
|
||||
@@ -56,7 +54,6 @@ private:
|
||||
fvkmemory::resource_ptr<VulkanBuffer> mBuffer;
|
||||
|
||||
uint32_t mLastReadAge;
|
||||
BufferUsage mUsage;
|
||||
};
|
||||
|
||||
} // namespace filament::backend
|
||||
|
||||
@@ -90,17 +90,18 @@ bool VulkanGroupMarkers::empty() const noexcept {
|
||||
uint32_t VulkanCommandBuffer::sAgeCounter = 0;
|
||||
|
||||
VulkanCommandBuffer::VulkanCommandBuffer(VulkanContext const& context, VkDevice device,
|
||||
VkQueue queue, VkCommandPool pool, VulkanSemaphoreManager* semaphoreManager,
|
||||
bool isProtected)
|
||||
VkQueue queue, VkCommandPool pool, bool isProtected)
|
||||
: mContext(context),
|
||||
mMarkerCount(0),
|
||||
isProtected(isProtected),
|
||||
mDevice(device),
|
||||
mQueue(queue),
|
||||
mSemaphoreManager(semaphoreManager),
|
||||
mBuffer(createCommandBuffer(device, pool)),
|
||||
mSubmission(semaphoreManager->acquire()),
|
||||
mFenceStatus(std::make_shared<VulkanCmdFence>(VK_INCOMPLETE)),
|
||||
mAge(++sAgeCounter) {
|
||||
VkSemaphoreCreateInfo sci{.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO};
|
||||
vkCreateSemaphore(mDevice, &sci, VKALLOC, &mSubmission);
|
||||
|
||||
VkFenceCreateInfo fenceCreateInfo{.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO};
|
||||
VkExportFenceCreateInfo exportFenceCreateInfo{
|
||||
.sType = VK_STRUCTURE_TYPE_EXPORT_FENCE_CREATE_INFO,
|
||||
@@ -112,11 +113,10 @@ VulkanCommandBuffer::VulkanCommandBuffer(VulkanContext const& context, VkDevice
|
||||
fenceCreateInfo.pNext = &exportFenceCreateInfo;
|
||||
}
|
||||
vkCreateFence(device, &fenceCreateInfo, VKALLOC, &mFence);
|
||||
|
||||
mFenceStatus = std::make_shared<VulkanCmdFence>(mFence);
|
||||
}
|
||||
|
||||
VulkanCommandBuffer::~VulkanCommandBuffer() {
|
||||
vkDestroySemaphore(mDevice, mSubmission, VKALLOC);
|
||||
vkDestroyFence(mDevice, mFence, VKALLOC);
|
||||
}
|
||||
|
||||
@@ -126,15 +126,12 @@ void VulkanCommandBuffer::reset() noexcept {
|
||||
mWaitSemaphores.clear();
|
||||
mWaitSemaphoreStages.clear();
|
||||
mAge = ++sAgeCounter;
|
||||
mSubmission = mSemaphoreManager->acquire();
|
||||
|
||||
// reset the fence with proper host synchronization
|
||||
mFenceStatus->resetFence(mDevice);
|
||||
|
||||
// Internally we use the VK_INCOMPLETE status to mean "not yet submitted". When this fence
|
||||
// gets, gets submitted, its status changes to VK_NOT_READY. Finally, when the GPU actually
|
||||
// finishes executing the command buffer, the status changes to VK_SUCCESS.
|
||||
mFenceStatus = std::make_shared<VulkanCmdFence>(mFence);
|
||||
mFenceStatus = std::make_shared<VulkanCmdFence>(VK_INCOMPLETE);
|
||||
vkResetFences(mDevice, 1, &mFence);
|
||||
}
|
||||
|
||||
void VulkanCommandBuffer::pushMarker(char const* marker) noexcept {
|
||||
@@ -193,14 +190,13 @@ void VulkanCommandBuffer::begin() noexcept {
|
||||
vkBeginCommandBuffer(mBuffer, &binfo);
|
||||
}
|
||||
|
||||
fvkmemory::resource_ptr<VulkanSemaphore> VulkanCommandBuffer::submit() {
|
||||
VkSemaphore VulkanCommandBuffer::submit() {
|
||||
while (mMarkerCount > 0) {
|
||||
popMarker();
|
||||
}
|
||||
|
||||
vkEndCommandBuffer(mBuffer);
|
||||
|
||||
VkSemaphore submissionSemaphore = mSubmission->getVkSemaphore();
|
||||
VkSubmitInfo submitInfo{
|
||||
.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
|
||||
.waitSemaphoreCount = mWaitSemaphores.size(),
|
||||
@@ -209,7 +205,7 @@ fvkmemory::resource_ptr<VulkanSemaphore> VulkanCommandBuffer::submit() {
|
||||
.commandBufferCount = 1u,
|
||||
.pCommandBuffers = &mBuffer,
|
||||
.signalSemaphoreCount = 1u,
|
||||
.pSignalSemaphores = &submissionSemaphore,
|
||||
.pSignalSemaphores = &mSubmission,
|
||||
};
|
||||
// add submit protection if needed
|
||||
VkProtectedSubmitInfo protectedSubmitInfo{
|
||||
@@ -230,13 +226,13 @@ fvkmemory::resource_ptr<VulkanSemaphore> VulkanCommandBuffer::submit() {
|
||||
<< (s < mWaitSemaphores.size() - 1 ? "\n" : "");
|
||||
}
|
||||
FVK_LOGI << ") "
|
||||
<< " signal=" << submissionSemaphore
|
||||
<< " signal=" << mSubmission
|
||||
<< " fence=" << mFence;
|
||||
#endif
|
||||
|
||||
mFenceStatus->setStatus(VK_NOT_READY);
|
||||
UTILS_UNUSED_IN_RELEASE VkResult result =
|
||||
vkQueueSubmit(mQueue, 1, &submitInfo, mFence);
|
||||
mFenceStatus->setStatus(VK_NOT_READY);
|
||||
|
||||
#if FVK_ENABLED(FVK_DEBUG_COMMAND_BUFFER)
|
||||
if (result != VK_SUCCESS) {
|
||||
@@ -249,7 +245,7 @@ fvkmemory::resource_ptr<VulkanSemaphore> VulkanCommandBuffer::submit() {
|
||||
}
|
||||
|
||||
CommandBufferPool::CommandBufferPool(VulkanContext const& context, VkDevice device, VkQueue queue,
|
||||
uint8_t queueFamilyIndex, VulkanSemaphoreManager* semaphoreManager, bool isProtected)
|
||||
uint8_t queueFamilyIndex, bool isProtected)
|
||||
: mDevice(device),
|
||||
mRecording(INVALID) {
|
||||
VkCommandPoolCreateInfo createInfo = {
|
||||
@@ -262,8 +258,8 @@ CommandBufferPool::CommandBufferPool(VulkanContext const& context, VkDevice devi
|
||||
vkCreateCommandPool(device, &createInfo, VKALLOC, &mPool);
|
||||
|
||||
for (size_t i = 0; i < CAPACITY; ++i) {
|
||||
mBuffers.emplace_back(std::make_unique<VulkanCommandBuffer>(
|
||||
context, device, queue, mPool, semaphoreManager, isProtected));
|
||||
mBuffers.emplace_back(
|
||||
std::make_unique<VulkanCommandBuffer>(context, device, queue, mPool, isProtected));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -335,10 +331,10 @@ void CommandBufferPool::update() {
|
||||
});
|
||||
}
|
||||
|
||||
fvkmemory::resource_ptr<VulkanSemaphore> CommandBufferPool::flush() {
|
||||
VkSemaphore CommandBufferPool::flush() {
|
||||
// We're not recording right now.
|
||||
if (!isRecording()) {
|
||||
return {};
|
||||
return VK_NULL_HANDLE;
|
||||
}
|
||||
auto submitSemaphore = mBuffers[mRecording]->submit();
|
||||
mSubmitted.set(mRecording, true);
|
||||
@@ -400,21 +396,16 @@ void CommandBufferPool::insertEvent(char const* marker) {
|
||||
#endif // FVK_DEBUG_GROUP_MARKERS
|
||||
|
||||
VulkanCommands::VulkanCommands(VkDevice device, VkQueue queue, uint32_t queueFamilyIndex,
|
||||
VkQueue protectedQueue, uint32_t protectedQueueFamilyIndex, VulkanContext const& context,
|
||||
VulkanSemaphoreManager* semaphoreManager)
|
||||
VkQueue protectedQueue, uint32_t protectedQueueFamilyIndex, VulkanContext const& context)
|
||||
: mDevice(device),
|
||||
mProtectedQueue(protectedQueue),
|
||||
mProtectedQueueFamilyIndex(protectedQueueFamilyIndex),
|
||||
mContext(context),
|
||||
mSemaphoreManager(semaphoreManager),
|
||||
mPool(std::make_unique<CommandBufferPool>(
|
||||
context, device, queue, queueFamilyIndex, semaphoreManager, false)) {}
|
||||
mPool(std::make_unique<CommandBufferPool>(context, device, queue, queueFamilyIndex, false)) {}
|
||||
|
||||
void VulkanCommands::terminate() {
|
||||
mPool.reset();
|
||||
mProtectedPool.reset();
|
||||
mLastSubmit = {};
|
||||
mLastFenceStatus = {};
|
||||
}
|
||||
|
||||
VulkanCommandBuffer& VulkanCommands::get() {
|
||||
@@ -427,7 +418,7 @@ VulkanCommandBuffer& VulkanCommands::getProtected() {
|
||||
|
||||
if (!mProtectedPool) {
|
||||
mProtectedPool = std::make_unique<CommandBufferPool>(mContext, mDevice, mProtectedQueue,
|
||||
mProtectedQueueFamilyIndex, mSemaphoreManager, true);
|
||||
mProtectedQueueFamilyIndex, true);
|
||||
}
|
||||
auto& ret = mProtectedPool->getRecording();
|
||||
return ret;
|
||||
@@ -439,8 +430,8 @@ bool VulkanCommands::flush() {
|
||||
return false;
|
||||
}
|
||||
|
||||
VkSemaphore injectedDependency = mInjectedDependency;
|
||||
fvkmemory::resource_ptr<VulkanSemaphore> dependency;
|
||||
VkSemaphore dependency = mInjectedDependency;
|
||||
VkSemaphore lastSubmit = mLastSubmit;
|
||||
bool hasFlushed = false;
|
||||
|
||||
VkFence flushedFence = VK_NULL_HANDLE;
|
||||
@@ -453,19 +444,19 @@ bool VulkanCommands::flush() {
|
||||
if (!pool || !pool->isRecording()) {
|
||||
continue;
|
||||
}
|
||||
if (injectedDependency != VK_NULL_HANDLE) {
|
||||
pool->waitFor(injectedDependency, mInjectedDependencyWaitStage);
|
||||
if (dependency != VK_NULL_HANDLE) {
|
||||
pool->waitFor(dependency, mInjectedDependencyWaitStage);
|
||||
}
|
||||
if (mLastSubmit) {
|
||||
if (lastSubmit != VK_NULL_HANDLE) {
|
||||
// Note that the stage we're waiting on is the fragment shader stage. This assumes
|
||||
// that the subsequent command buffer will only depend on
|
||||
// 1) fragment output of the previous command buffer
|
||||
// 2) reading/writing of buffers (i.e. UBO) of the previous command buffer
|
||||
// Restricting the wait stages will allow for vertex work to proceed (more overlapping
|
||||
// vertex/fragment work).
|
||||
pool->waitFor(mLastSubmit->getVkSemaphore(),
|
||||
pool->waitFor(lastSubmit,
|
||||
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_TRANSFER_BIT);
|
||||
mLastSubmit = {};
|
||||
lastSubmit = VK_NULL_HANDLE;
|
||||
}
|
||||
flushedFence = pool->getRecording().getVkFence();
|
||||
flushedFenceStatus = pool->getRecording().getFenceStatus();
|
||||
|
||||
@@ -24,7 +24,6 @@
|
||||
#include "VulkanAsyncHandles.h"
|
||||
#include "VulkanConstants.h"
|
||||
#include "VulkanContext.h"
|
||||
#include "VulkanSemaphoreManager.h"
|
||||
#include "vulkan/memory/ResourcePointer.h"
|
||||
#include "vulkan/utils/StaticVector.h"
|
||||
|
||||
@@ -64,8 +63,8 @@ private:
|
||||
// DriverApi fence object and should not be destroyed until both the DriverApi object is freed and
|
||||
// we're done waiting on the most recent submission of the given command buffer.
|
||||
struct VulkanCommandBuffer {
|
||||
VulkanCommandBuffer(VulkanContext const& mContext, VkDevice device, VkQueue queue,
|
||||
VkCommandPool pool, VulkanSemaphoreManager* semaphoreManager, bool isProtected);
|
||||
VulkanCommandBuffer(VulkanContext const& mContext,
|
||||
VkDevice device, VkQueue queue, VkCommandPool pool, bool isProtected);
|
||||
|
||||
VulkanCommandBuffer(VulkanCommandBuffer const&) = delete;
|
||||
VulkanCommandBuffer& operator=(VulkanCommandBuffer const&) = delete;
|
||||
@@ -88,7 +87,7 @@ struct VulkanCommandBuffer {
|
||||
void insertEvent(char const* marker) noexcept;
|
||||
|
||||
void begin() noexcept;
|
||||
fvkmemory::resource_ptr<VulkanSemaphore> submit();
|
||||
VkSemaphore submit();
|
||||
|
||||
inline void setComplete() {
|
||||
mFenceStatus->setStatus(VK_SUCCESS);
|
||||
@@ -122,11 +121,10 @@ private:
|
||||
bool const isProtected;
|
||||
VkDevice mDevice;
|
||||
VkQueue mQueue;
|
||||
VulkanSemaphoreManager* mSemaphoreManager;
|
||||
fvkutils::StaticVector<VkSemaphore, 2> mWaitSemaphores;
|
||||
fvkutils::StaticVector<VkPipelineStageFlags, 2> mWaitSemaphoreStages;
|
||||
VkCommandBuffer mBuffer;
|
||||
fvkmemory::resource_ptr<VulkanSemaphore> mSubmission;
|
||||
VkSemaphore mSubmission;
|
||||
VkFence mFence;
|
||||
std::shared_ptr<VulkanCmdFence> mFenceStatus;
|
||||
std::vector<fvkmemory::resource_ptr<Resource>> mResources;
|
||||
@@ -138,14 +136,14 @@ struct CommandBufferPool {
|
||||
static constexpr int8_t INVALID = -1;
|
||||
|
||||
CommandBufferPool(VulkanContext const& context, VkDevice device, VkQueue queue,
|
||||
uint8_t queueFamilyIndex, VulkanSemaphoreManager* semaphoreManager, bool isProtected);
|
||||
uint8_t queueFamilyIndex, bool isProtected);
|
||||
~CommandBufferPool();
|
||||
|
||||
VulkanCommandBuffer& getRecording();
|
||||
|
||||
void gc();
|
||||
void update();
|
||||
fvkmemory::resource_ptr<VulkanSemaphore> flush();
|
||||
VkSemaphore flush();
|
||||
void wait();
|
||||
void waitFor(VkSemaphore previousAction, VkPipelineStageFlags waitStage);
|
||||
|
||||
@@ -206,7 +204,7 @@ class VulkanCommands {
|
||||
public:
|
||||
VulkanCommands(VkDevice device, VkQueue queue, uint32_t queueFamilyIndex,
|
||||
VkQueue protectedQueue, uint32_t protectedQueueFamilyIndex,
|
||||
VulkanContext const& context, VulkanSemaphoreManager* semaphoreManager);
|
||||
VulkanContext const& context);
|
||||
|
||||
void terminate();
|
||||
|
||||
@@ -224,10 +222,10 @@ public:
|
||||
// Returns the "rendering finished" semaphore for the most recent flush and removes
|
||||
// it from the existing dependency chain. This is especially useful for setting up
|
||||
// vkQueuePresentKHR.
|
||||
fvkmemory::resource_ptr<VulkanSemaphore> acquireFinishedSignal() {
|
||||
fvkmemory::resource_ptr<VulkanSemaphore> sem = mLastSubmit;
|
||||
mLastSubmit = {};
|
||||
return sem;
|
||||
VkSemaphore acquireFinishedSignal() {
|
||||
VkSemaphore ret = mLastSubmit;
|
||||
mLastSubmit = VK_NULL_HANDLE;
|
||||
return ret;
|
||||
}
|
||||
|
||||
VkFence getMostRecentFence() {
|
||||
@@ -268,13 +266,12 @@ private:
|
||||
// For defered initialization if/when we need protected content
|
||||
uint32_t const mProtectedQueueFamilyIndex;
|
||||
VulkanContext const& mContext;
|
||||
VulkanSemaphoreManager* mSemaphoreManager;
|
||||
|
||||
std::unique_ptr<CommandBufferPool> mPool;
|
||||
std::unique_ptr<CommandBufferPool> mProtectedPool;
|
||||
|
||||
VkSemaphore mInjectedDependency = VK_NULL_HANDLE;
|
||||
fvkmemory::resource_ptr<VulkanSemaphore> mLastSubmit;
|
||||
VkSemaphore mLastSubmit = VK_NULL_HANDLE;
|
||||
|
||||
VkFence mLastFence = VK_NULL_HANDLE;
|
||||
std::shared_ptr<VulkanCmdFence> mLastFenceStatus;
|
||||
|
||||
@@ -37,15 +37,12 @@
|
||||
|
||||
#include <utils/compiler.h>
|
||||
#include <utils/CString.h>
|
||||
#include <utils/ImmutableCString.h>
|
||||
#include <utils/Panic.h>
|
||||
|
||||
#ifndef NDEBUG
|
||||
#include <set> // For VulkanDriver::debugCommandBegin
|
||||
#endif
|
||||
|
||||
#include <chrono>
|
||||
|
||||
using namespace bluevk;
|
||||
|
||||
#if defined(__clang__)
|
||||
@@ -225,10 +222,9 @@ VulkanDriver::VulkanDriver(VulkanPlatform* platform, VulkanContext& context,
|
||||
mAllocator(createAllocator(mPlatform->getInstance(), mPlatform->getPhysicalDevice(),
|
||||
mPlatform->getDevice())),
|
||||
mContext(context),
|
||||
mSemaphoreManager(mPlatform->getDevice(), &mResourceManager),
|
||||
mCommands(mPlatform->getDevice(), mPlatform->getGraphicsQueue(),
|
||||
mPlatform->getGraphicsQueueFamilyIndex(), mPlatform->getProtectedGraphicsQueue(),
|
||||
mPlatform->getProtectedGraphicsQueueFamilyIndex(), mContext, &mSemaphoreManager),
|
||||
mPlatform->getProtectedGraphicsQueueFamilyIndex(), mContext),
|
||||
mPipelineLayoutCache(mPlatform->getDevice()),
|
||||
mPipelineCache(mPlatform->getDevice()),
|
||||
mStagePool(mAllocator, &mResourceManager, &mCommands, &mContext.getPhysicalDeviceLimits()),
|
||||
@@ -323,9 +319,8 @@ ShaderModel VulkanDriver::getShaderModel() const noexcept {
|
||||
#endif
|
||||
}
|
||||
|
||||
utils::FixedCapacityVector<ShaderLanguage> VulkanDriver::getShaderLanguages(
|
||||
ShaderLanguage /*prefferedLanguage*/) const noexcept {
|
||||
return { ShaderLanguage::SPIRV };
|
||||
ShaderLanguage VulkanDriver::getShaderLanguage() const noexcept {
|
||||
return ShaderLanguage::SPIRV;
|
||||
}
|
||||
|
||||
void VulkanDriver::terminate() {
|
||||
@@ -370,9 +365,6 @@ void VulkanDriver::terminate() {
|
||||
// reclaimed, as they perform cleanup within the stage pool.
|
||||
mStagePool.terminate();
|
||||
|
||||
// By this point, all of the VkSemaphores should have been returned to the pool.
|
||||
mSemaphoreManager.terminate();
|
||||
|
||||
#if FVK_ENABLED(FVK_DEBUG_RESOURCE_LEAK)
|
||||
mResourceManager.print();
|
||||
#endif
|
||||
@@ -525,7 +517,7 @@ void VulkanDriver::finish(int dummy) {
|
||||
|
||||
void VulkanDriver::createRenderPrimitiveR(Handle<HwRenderPrimitive> rph,
|
||||
Handle<HwVertexBuffer> vbh, Handle<HwIndexBuffer> ibh,
|
||||
PrimitiveType pt, utils::ImmutableCString&& tag) {
|
||||
PrimitiveType pt, utils::CString&& tag) {
|
||||
FVK_SYSTRACE_SCOPE();
|
||||
auto vb = resource_ptr<VulkanVertexBuffer>::cast(&mResourceManager, vbh);
|
||||
auto ib = resource_ptr<VulkanIndexBuffer>::cast(&mResourceManager, ibh);
|
||||
@@ -544,7 +536,7 @@ void VulkanDriver::destroyRenderPrimitive(Handle<HwRenderPrimitive> rph) {
|
||||
}
|
||||
|
||||
void VulkanDriver::createVertexBufferInfoR(Handle<HwVertexBufferInfo> vbih, uint8_t bufferCount,
|
||||
uint8_t attributeCount, AttributeArray attributes, utils::ImmutableCString&& tag) {
|
||||
uint8_t attributeCount, AttributeArray attributes, utils::CString&& tag) {
|
||||
FVK_SYSTRACE_SCOPE();
|
||||
auto vbi = resource_ptr<VulkanVertexBufferInfo>::make(&mResourceManager, vbih, bufferCount,
|
||||
attributeCount, attributes);
|
||||
@@ -562,7 +554,7 @@ void VulkanDriver::destroyVertexBufferInfo(Handle<HwVertexBufferInfo> vbih) {
|
||||
}
|
||||
|
||||
void VulkanDriver::createVertexBufferR(Handle<HwVertexBuffer> vbh, uint32_t vertexCount,
|
||||
Handle<HwVertexBufferInfo> vbih, utils::ImmutableCString&& tag) {
|
||||
Handle<HwVertexBufferInfo> vbih, utils::CString&& tag) {
|
||||
FVK_SYSTRACE_SCOPE();
|
||||
auto vbi = resource_ptr<VulkanVertexBufferInfo>::cast(&mResourceManager, vbih);
|
||||
auto vb = resource_ptr<VulkanVertexBuffer>::make(&mResourceManager, vbh, mContext, mStagePool,
|
||||
@@ -581,7 +573,7 @@ void VulkanDriver::destroyVertexBuffer(Handle<HwVertexBuffer> vbh) {
|
||||
}
|
||||
|
||||
void VulkanDriver::createIndexBufferR(Handle<HwIndexBuffer> ibh, ElementType elementType,
|
||||
uint32_t indexCount, BufferUsage usage, utils::ImmutableCString&& tag) {
|
||||
uint32_t indexCount, BufferUsage usage, utils::CString&& tag) {
|
||||
FVK_SYSTRACE_SCOPE();
|
||||
auto elementSize = (uint8_t) getElementTypeSize(elementType);
|
||||
auto ib = resource_ptr<VulkanIndexBuffer>::make(&mResourceManager, ibh, mContext, mAllocator,
|
||||
@@ -600,10 +592,10 @@ void VulkanDriver::destroyIndexBuffer(Handle<HwIndexBuffer> ibh) {
|
||||
}
|
||||
|
||||
void VulkanDriver::createBufferObjectR(Handle<HwBufferObject> boh, uint32_t byteCount,
|
||||
BufferObjectBinding bindingType, BufferUsage usage, utils::ImmutableCString&& tag) {
|
||||
BufferObjectBinding bindingType, BufferUsage usage, utils::CString&& tag) {
|
||||
FVK_SYSTRACE_SCOPE();
|
||||
auto bo = resource_ptr<VulkanBufferObject>::make(&mResourceManager, boh, mContext, mAllocator,
|
||||
mStagePool, mBufferCache, byteCount, bindingType, usage);
|
||||
mStagePool, mBufferCache, byteCount, bindingType);
|
||||
bo.inc();
|
||||
mResourceManager.associateHandle(boh.getId(), std::move(tag));
|
||||
}
|
||||
@@ -619,7 +611,7 @@ void VulkanDriver::destroyBufferObject(Handle<HwBufferObject> boh) {
|
||||
|
||||
void VulkanDriver::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, utils::ImmutableCString&& tag) {
|
||||
TextureUsage usage, utils::CString&& tag) {
|
||||
FVK_SYSTRACE_SCOPE();
|
||||
auto texture = resource_ptr<VulkanTexture>::make(&mResourceManager, th, mPlatform->getDevice(),
|
||||
mPlatform->getPhysicalDevice(), mContext, mAllocator, &mResourceManager, &mCommands,
|
||||
@@ -636,7 +628,7 @@ void VulkanDriver::createTextureR(Handle<HwTexture> th, SamplerType target, uint
|
||||
}
|
||||
|
||||
void VulkanDriver::createTextureViewR(Handle<HwTexture> th, Handle<HwTexture> srch,
|
||||
uint8_t baseLevel, uint8_t levelCount, utils::ImmutableCString&& tag) {
|
||||
uint8_t baseLevel, uint8_t levelCount, utils::CString&& tag) {
|
||||
auto src = resource_ptr<VulkanTexture>::cast(&mResourceManager, srch);
|
||||
auto texture = resource_ptr<VulkanTexture>::make(&mResourceManager, th, mPlatform->getDevice(),
|
||||
mPlatform->getPhysicalDevice(), mContext, mAllocator, &mCommands, src, baseLevel,
|
||||
@@ -647,7 +639,7 @@ void VulkanDriver::createTextureViewR(Handle<HwTexture> th, Handle<HwTexture> sr
|
||||
|
||||
void VulkanDriver::createTextureViewSwizzleR(Handle<HwTexture> th, Handle<HwTexture> srch,
|
||||
backend::TextureSwizzle r, backend::TextureSwizzle g, backend::TextureSwizzle b,
|
||||
backend::TextureSwizzle a, utils::ImmutableCString&& tag) {
|
||||
backend::TextureSwizzle a, utils::CString&& tag) {
|
||||
TextureSwizzle const swizzleArray[] = { r, g, b, a };
|
||||
VkComponentMapping const swizzle = fvkutils::getSwizzleMap(swizzleArray);
|
||||
auto src = resource_ptr<VulkanTexture>::cast(&mResourceManager, srch);
|
||||
@@ -659,7 +651,7 @@ void VulkanDriver::createTextureViewSwizzleR(Handle<HwTexture> th, Handle<HwText
|
||||
|
||||
void VulkanDriver::createTextureExternalImage2R(Handle<HwTexture> th, backend::SamplerType target,
|
||||
backend::TextureFormat format, uint32_t width, uint32_t height, backend::TextureUsage usage,
|
||||
Platform::ExternalImageHandleRef externalImage, utils::ImmutableCString&& tag) {
|
||||
Platform::ExternalImageHandleRef externalImage, utils::CString&& tag) {
|
||||
FVK_SYSTRACE_SCOPE();
|
||||
auto metadata = mPlatform->extractExternalImageMetadata(externalImage);
|
||||
|
||||
@@ -710,7 +702,7 @@ void VulkanDriver::createTextureExternalImage2R(Handle<HwTexture> th, backend::S
|
||||
|
||||
void VulkanDriver::createTextureExternalImageR(Handle<HwTexture> th, backend::SamplerType target,
|
||||
backend::TextureFormat format, uint32_t width, uint32_t height, backend::TextureUsage usage,
|
||||
void* externalImage, utils::ImmutableCString&& tag) {
|
||||
void* externalImage, utils::CString&& tag) {
|
||||
FVK_SYSTRACE_SCOPE();
|
||||
assert_invariant(false && "Not supported in Vulkan backend");
|
||||
// not supported in this backend
|
||||
@@ -718,14 +710,14 @@ void VulkanDriver::createTextureExternalImageR(Handle<HwTexture> th, backend::Sa
|
||||
|
||||
void VulkanDriver::createTextureExternalImagePlaneR(Handle<HwTexture> th,
|
||||
backend::TextureFormat format, uint32_t width, uint32_t height, backend::TextureUsage usage,
|
||||
void* image, uint32_t plane, utils::ImmutableCString&& tag) {
|
||||
void* image, uint32_t plane, utils::CString&& tag) {
|
||||
assert_invariant(false && "Not supported in Vulkan backend");
|
||||
}
|
||||
|
||||
void VulkanDriver::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, utils::ImmutableCString&& tag) {
|
||||
TextureUsage usage, utils::CString&& tag) {
|
||||
// not supported in this backend
|
||||
assert_invariant(false && "Not supported in Vulkan backend");
|
||||
mResourceManager.associateHandle(th.getId(), std::move(tag));
|
||||
@@ -741,7 +733,7 @@ void VulkanDriver::destroyTexture(Handle<HwTexture> th) {
|
||||
mExternalImageManager.removeExternallySampledTexture(texture);
|
||||
}
|
||||
|
||||
void VulkanDriver::createProgramR(Handle<HwProgram> ph, Program&& program, utils::ImmutableCString&& tag) {
|
||||
void VulkanDriver::createProgramR(Handle<HwProgram> ph, Program&& program, utils::CString&& tag) {
|
||||
FVK_SYSTRACE_SCOPE();
|
||||
auto vprogram = resource_ptr<VulkanProgram>::make(&mResourceManager, ph, mPlatform->getDevice(),
|
||||
program);
|
||||
@@ -757,7 +749,7 @@ void VulkanDriver::destroyProgram(Handle<HwProgram> ph) {
|
||||
vprogram.dec();
|
||||
}
|
||||
|
||||
void VulkanDriver::createDefaultRenderTargetR(Handle<HwRenderTarget> rth, utils::ImmutableCString&& tag) {
|
||||
void VulkanDriver::createDefaultRenderTargetR(Handle<HwRenderTarget> rth, utils::CString&& tag) {
|
||||
assert_invariant(mDefaultRenderTarget); // Default render target should already exist.
|
||||
|
||||
auto renderTarget = resource_ptr<VulkanRenderTarget>::make(&mResourceManager, rth,
|
||||
@@ -770,7 +762,7 @@ void VulkanDriver::createDefaultRenderTargetR(Handle<HwRenderTarget> rth, utils:
|
||||
void VulkanDriver::createRenderTargetR(Handle<HwRenderTarget> rth,
|
||||
TargetBufferFlags targets, uint32_t width, uint32_t height, uint8_t samples,
|
||||
uint8_t layerCount, MRT color, TargetBufferInfo depth, TargetBufferInfo stencil,
|
||||
utils::ImmutableCString&& tag) {
|
||||
utils::CString&& tag) {
|
||||
|
||||
FVK_SYSTRACE_SCOPE();
|
||||
|
||||
@@ -847,7 +839,7 @@ void VulkanDriver::destroyRenderTarget(Handle<HwRenderTarget> rth) {
|
||||
}
|
||||
}
|
||||
|
||||
void VulkanDriver::createFenceR(Handle<HwFence> fh, utils::ImmutableCString&& tag) {
|
||||
void VulkanDriver::createFenceR(Handle<HwFence> fh, utils::CString&& tag) {
|
||||
VulkanCommandBuffer* cmdbuf;
|
||||
if (mCurrentRenderPass.commandBuffer) {
|
||||
cmdbuf = mCurrentRenderPass.commandBuffer;
|
||||
@@ -858,11 +850,11 @@ void VulkanDriver::createFenceR(Handle<HwFence> fh, utils::ImmutableCString&& ta
|
||||
// it with appropriate VulkanCmdFence, which is associated with the current, recording command
|
||||
// buffer.
|
||||
auto fence = resource_ptr<VulkanFence>::cast(&mResourceManager, fh);
|
||||
fence->setFence(cmdbuf->getFenceStatus());
|
||||
fence->fence = cmdbuf->getFenceStatus();
|
||||
mResourceManager.associateHandle(fh.getId(), std::move(tag));
|
||||
}
|
||||
|
||||
void VulkanDriver::createSyncR(Handle<HwSync> sh, utils::ImmutableCString&& tag) {
|
||||
void VulkanDriver::createSyncR(Handle<HwSync> sh, utils::CString&& tag) {
|
||||
auto sync = resource_ptr<VulkanSync>::cast(&mResourceManager, sh);
|
||||
VkFence fence = VK_NULL_HANDLE;
|
||||
std::shared_ptr<VulkanCmdFence> fenceStatus;
|
||||
@@ -893,7 +885,7 @@ void VulkanDriver::createSyncR(Handle<HwSync> sh, utils::ImmutableCString&& tag)
|
||||
}
|
||||
|
||||
void VulkanDriver::createSwapChainR(Handle<HwSwapChain> sch, void* nativeWindow, uint64_t flags,
|
||||
utils::ImmutableCString&& tag) {
|
||||
utils::CString&& tag) {
|
||||
FVK_SYSTRACE_SCOPE();
|
||||
// Running gc() to guard against an edge case where the old swapchains need to have been
|
||||
// destroyed before the new swapchain can be created. Otherwise, we would fail
|
||||
@@ -922,7 +914,7 @@ void VulkanDriver::createSwapChainR(Handle<HwSwapChain> sch, void* nativeWindow,
|
||||
}
|
||||
|
||||
void VulkanDriver::createSwapChainHeadlessR(Handle<HwSwapChain> sch, uint32_t width,
|
||||
uint32_t height, uint64_t flags, utils::ImmutableCString&& tag) {
|
||||
uint32_t height, uint64_t flags, utils::CString&& tag) {
|
||||
if ((flags & backend::SWAP_CHAIN_CONFIG_SRGB_COLORSPACE) != 0 && !isSRGBSwapChainSupported()) {
|
||||
FVK_LOGW << "sRGB swapchain requested, but Platform does not support it";
|
||||
flags = flags | ~(backend::SWAP_CHAIN_CONFIG_SRGB_COLORSPACE);
|
||||
@@ -935,13 +927,13 @@ void VulkanDriver::createSwapChainHeadlessR(Handle<HwSwapChain> sch, uint32_t wi
|
||||
mResourceManager.associateHandle(sch.getId(), std::move(tag));
|
||||
}
|
||||
|
||||
void VulkanDriver::createTimerQueryR(Handle<HwTimerQuery> tqh, utils::ImmutableCString&& tag) {
|
||||
void VulkanDriver::createTimerQueryR(Handle<HwTimerQuery> tqh, utils::CString&& tag) {
|
||||
// nothing to do, timer query was constructed in createTimerQueryS
|
||||
mResourceManager.associateHandle(tqh.getId(), std::move(tag));
|
||||
}
|
||||
|
||||
void VulkanDriver::createDescriptorSetLayoutR(Handle<HwDescriptorSetLayout> dslh,
|
||||
backend::DescriptorSetLayout&& info, utils::ImmutableCString&& tag) {
|
||||
backend::DescriptorSetLayout&& info, utils::CString&& tag) {
|
||||
FVK_SYSTRACE_SCOPE();
|
||||
auto layout = mDescriptorSetLayoutCache.createLayout(dslh, std::move(info));
|
||||
layout.inc();
|
||||
@@ -949,7 +941,7 @@ void VulkanDriver::createDescriptorSetLayoutR(Handle<HwDescriptorSetLayout> dslh
|
||||
}
|
||||
|
||||
void VulkanDriver::createDescriptorSetR(Handle<HwDescriptorSet> dsh,
|
||||
Handle<HwDescriptorSetLayout> dslh, utils::ImmutableCString&& tag) {
|
||||
Handle<HwDescriptorSetLayout> dslh, utils::CString&& tag) {
|
||||
FVK_SYSTRACE_SCOPE();
|
||||
fvkmemory::resource_ptr<VulkanDescriptorSetLayout> layout =
|
||||
fvkmemory::resource_ptr<VulkanDescriptorSetLayout>::cast(&mResourceManager, dslh);
|
||||
@@ -965,7 +957,7 @@ void VulkanDriver::createDescriptorSetR(Handle<HwDescriptorSet> dsh,
|
||||
|
||||
void VulkanDriver::mapBufferR(MemoryMappedBufferHandle mmbh,
|
||||
BufferObjectHandle boh, size_t offset,
|
||||
size_t size, MapBufferAccessFlags access, utils::ImmutableCString&& tag) {
|
||||
size_t size, MapBufferAccessFlags access, utils::CString&& tag) {
|
||||
FVK_SYSTRACE_SCOPE();
|
||||
auto mmb = resource_ptr<VulkanMemoryMappedBuffer>::make(&mResourceManager, mmbh,
|
||||
boh, offset, size, access);
|
||||
@@ -1132,11 +1124,11 @@ void VulkanDriver::destroyDescriptorSet(Handle<HwDescriptorSet> dsh) {
|
||||
}
|
||||
}
|
||||
|
||||
Handle<HwStream> VulkanDriver::createStreamNative(void* nativeStream, utils::ImmutableCString tag) {
|
||||
Handle<HwStream> VulkanDriver::createStreamNative(void* nativeStream, utils::CString tag) {
|
||||
return {};
|
||||
}
|
||||
|
||||
Handle<HwStream> VulkanDriver::createStreamAcquired(utils::ImmutableCString tag) {
|
||||
Handle<HwStream> VulkanDriver::createStreamAcquired(utils::CString tag) {
|
||||
return {};
|
||||
}
|
||||
|
||||
@@ -1159,30 +1151,29 @@ void VulkanDriver::destroyFence(Handle<HwFence> fh) {
|
||||
fence.dec();
|
||||
}
|
||||
|
||||
FenceStatus VulkanDriver::getFenceStatus(Handle<HwFence> const fh) {
|
||||
return fenceWait(fh, 0);
|
||||
}
|
||||
|
||||
FenceStatus VulkanDriver::fenceWait(FenceHandle const fh, uint64_t const timeout) {
|
||||
FenceStatus VulkanDriver::getFenceStatus(Handle<HwFence> fh) {
|
||||
auto fence = resource_ptr<VulkanFence>::cast(&mResourceManager, fh);
|
||||
|
||||
// we have to take into account that the STL's wait_for() actually works with
|
||||
// time_points relative to steady_clock::now() internally.
|
||||
using namespace std::chrono;
|
||||
auto const now = steady_clock::now();
|
||||
steady_clock::time_point until = steady_clock::time_point::max();
|
||||
if (now <= steady_clock::time_point::max() - nanoseconds(timeout)) {
|
||||
until = now + nanoseconds(timeout);
|
||||
}
|
||||
|
||||
std::shared_ptr const cmdfence = fence->wait(until);
|
||||
auto& cmdfence = fence->fence;
|
||||
if (!cmdfence) {
|
||||
// If wait is called before a fence actually exists, we return timeout. This matches the
|
||||
// current behavior in OpenGLDriver, but we should eventually reconsider a different error
|
||||
// code.
|
||||
return FenceStatus::TIMEOUT_EXPIRED;
|
||||
}
|
||||
|
||||
// now we are holding a reference to our VulkanCmdFence, so we know it can't
|
||||
// disappear while we wait
|
||||
return cmdfence->wait(mPlatform->getDevice(), timeout, until);
|
||||
// Internally we use the VK_INCOMPLETE status to mean "not yet submitted".
|
||||
// When this fence gets submitted, its status changes to VK_NOT_READY.
|
||||
if (cmdfence->getStatus() == VK_SUCCESS) {
|
||||
return FenceStatus::CONDITION_SATISFIED;
|
||||
}
|
||||
|
||||
|
||||
// Two other states are possible:
|
||||
// - VK_INCOMPLETE: the corresponding buffer has not yet been submitted.
|
||||
// - VK_NOT_READY: the buffer has been submitted but not yet signaled.
|
||||
// In either case, we return TIMEOUT_EXPIRED to indicate the fence has not been signaled.
|
||||
return FenceStatus::TIMEOUT_EXPIRED;
|
||||
}
|
||||
|
||||
void VulkanDriver::getPlatformSync(Handle<HwSync> sh, CallbackHandler* handler,
|
||||
|
||||
@@ -28,7 +28,6 @@
|
||||
#include "VulkanQueryManager.h"
|
||||
#include "VulkanReadPixels.h"
|
||||
#include "VulkanSamplerCache.h"
|
||||
#include "VulkanSemaphoreManager.h"
|
||||
#include "VulkanStagePool.h"
|
||||
#include "VulkanYcbcrConversionCache.h"
|
||||
#include "vulkan/VulkanDescriptorSetCache.h"
|
||||
@@ -44,7 +43,6 @@
|
||||
#include "DriverBase.h"
|
||||
#include "private/backend/Driver.h"
|
||||
|
||||
#include <utils/FixedCapacityVector.h>
|
||||
#include <utils/Allocator.h>
|
||||
#include <utils/compiler.h>
|
||||
|
||||
@@ -102,8 +100,7 @@ private:
|
||||
Dispatcher getDispatcher() const noexcept final;
|
||||
|
||||
ShaderModel getShaderModel() const noexcept final;
|
||||
utils::FixedCapacityVector<ShaderLanguage> getShaderLanguages(
|
||||
ShaderLanguage preferredLanguage) const noexcept final;
|
||||
ShaderLanguage getShaderLanguage() const noexcept final;
|
||||
|
||||
template<typename T>
|
||||
friend class ConcreteDispatcher;
|
||||
@@ -142,7 +139,6 @@ private:
|
||||
|
||||
VulkanContext& mContext;
|
||||
|
||||
VulkanSemaphoreManager mSemaphoreManager;
|
||||
VulkanCommands mCommands;
|
||||
VulkanPipelineLayoutCache mPipelineLayoutCache;
|
||||
VulkanPipelineCache mPipelineCache;
|
||||
|
||||
@@ -40,18 +40,18 @@ namespace filament::backend {
|
||||
|
||||
namespace {
|
||||
|
||||
inline VulkanBufferBinding getBufferObjectBinding(BufferObjectBinding bindingType) noexcept {
|
||||
inline VulkanBufferUsage getBufferObjectUsage(BufferObjectBinding bindingType) noexcept {
|
||||
switch (bindingType) {
|
||||
case BufferObjectBinding::VERTEX:
|
||||
return VulkanBufferBinding::VERTEX;
|
||||
return VulkanBufferUsage::VERTEX;
|
||||
case BufferObjectBinding::UNIFORM:
|
||||
return VulkanBufferBinding::UNIFORM;
|
||||
return VulkanBufferUsage::UNIFORM;
|
||||
case BufferObjectBinding::SHADER_STORAGE:
|
||||
return VulkanBufferBinding::SHADER_STORAGE;
|
||||
return VulkanBufferUsage::SHADER_STORAGE;
|
||||
// when adding more buffer-types here, make sure to update VulkanBuffer::loadFromCpu()
|
||||
// if necessary.
|
||||
}
|
||||
return VulkanBufferBinding::UNKNOWN;
|
||||
return VulkanBufferUsage::UNKNOWN;
|
||||
}
|
||||
|
||||
void flipVertically(VkViewport* rect, uint32_t framebufferHeight) {
|
||||
@@ -614,11 +614,10 @@ void VulkanVertexBuffer::setBuffer(fvkmemory::resource_ptr<VulkanBufferObject> b
|
||||
|
||||
VulkanBufferObject::VulkanBufferObject(VulkanContext const& context, VmaAllocator allocator,
|
||||
VulkanStagePool& stagePool, VulkanBufferCache& bufferCache, uint32_t byteCount,
|
||||
BufferObjectBinding bindingType, BufferUsage usage)
|
||||
BufferObjectBinding bindingType)
|
||||
: HwBufferObject(byteCount),
|
||||
bindingType(bindingType),
|
||||
mBuffer(context, allocator, stagePool, bufferCache, getBufferObjectBinding(bindingType),
|
||||
usage, byteCount) {}
|
||||
mBuffer(context, allocator, stagePool, bufferCache, getBufferObjectUsage(bindingType), byteCount) {}
|
||||
|
||||
VulkanRenderPrimitive::VulkanRenderPrimitive(PrimitiveType pt,
|
||||
fvkmemory::resource_ptr<VulkanVertexBuffer> vb,
|
||||
|
||||
@@ -477,8 +477,8 @@ struct VulkanIndexBuffer : public HwIndexBuffer, fvkmemory::Resource {
|
||||
uint32_t indexCount)
|
||||
: HwIndexBuffer(elementSize, indexCount),
|
||||
indexType(elementSize == 2 ? VK_INDEX_TYPE_UINT16 : VK_INDEX_TYPE_UINT32),
|
||||
mBuffer(context, allocator, stagePool, bufferCache, VulkanBufferBinding::INDEX,
|
||||
BufferUsage::STATIC, elementSize * indexCount) {}
|
||||
mBuffer(context, allocator, stagePool, bufferCache, VulkanBufferUsage::INDEX,
|
||||
elementSize * indexCount) {}
|
||||
|
||||
inline void loadFromCpu(VulkanCommandBuffer& commands, const void* cpuData, uint32_t byteOffset,
|
||||
uint32_t numBytes) {
|
||||
@@ -496,7 +496,7 @@ private:
|
||||
struct VulkanBufferObject : public HwBufferObject, fvkmemory::Resource {
|
||||
VulkanBufferObject(VulkanContext const& context, VmaAllocator allocator,
|
||||
VulkanStagePool& stagePool, VulkanBufferCache& bufferCache, uint32_t byteCount,
|
||||
BufferObjectBinding bindingType, BufferUsage usage);
|
||||
BufferObjectBinding bindingType);
|
||||
|
||||
inline void loadFromCpu(VulkanCommandBuffer& commands, const void* cpuData, uint32_t byteOffset,
|
||||
uint32_t numBytes) {
|
||||
|
||||
@@ -39,7 +39,7 @@ VK_DEFINE_HANDLE(VmaPool)
|
||||
|
||||
namespace filament::backend {
|
||||
|
||||
enum class VulkanBufferBinding : uint8_t {
|
||||
enum class VulkanBufferUsage : uint8_t {
|
||||
UNKNOWN,
|
||||
VERTEX,
|
||||
INDEX,
|
||||
@@ -52,7 +52,7 @@ struct VulkanGpuBuffer {
|
||||
VmaAllocation vmaAllocation = VK_NULL_HANDLE;
|
||||
VmaAllocationInfo allocationInfo;
|
||||
uint32_t numBytes = 0;
|
||||
VulkanBufferBinding binding = VulkanBufferBinding::UNKNOWN;
|
||||
VulkanBufferUsage usage = VulkanBufferUsage::UNKNOWN;
|
||||
};
|
||||
|
||||
} // namespace filament::backend
|
||||
|
||||
@@ -1,29 +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 "vulkan/VulkanSemaphore.h"
|
||||
#include "vulkan/VulkanSemaphoreManager.h"
|
||||
|
||||
namespace filament::backend {
|
||||
|
||||
VulkanSemaphore::VulkanSemaphore(VulkanSemaphoreManager* manager, VkSemaphore semaphore)
|
||||
: mManager(manager), mSemaphore(semaphore) {}
|
||||
|
||||
VulkanSemaphore::~VulkanSemaphore() {
|
||||
mManager->recycle(mSemaphore);
|
||||
}
|
||||
|
||||
} // namespace filament::backend
|
||||
@@ -1,42 +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_VULKAN_VULKANSEMAPHORE_H
|
||||
#define TNT_FILAMENT_BACKEND_VULKAN_VULKANSEMAPHORE_H
|
||||
|
||||
#include "memory/Resource.h"
|
||||
|
||||
#include <bluevk/BlueVK.h>
|
||||
|
||||
namespace filament::backend {
|
||||
|
||||
class VulkanSemaphoreManager;
|
||||
|
||||
struct VulkanSemaphore : public fvkmemory::Resource {
|
||||
public:
|
||||
VulkanSemaphore(VulkanSemaphoreManager* manager, VkSemaphore semaphore);
|
||||
~VulkanSemaphore();
|
||||
|
||||
VkSemaphore getVkSemaphore() const { return mSemaphore; }
|
||||
|
||||
private:
|
||||
VulkanSemaphoreManager* mManager;
|
||||
VkSemaphore mSemaphore;
|
||||
};
|
||||
|
||||
} // namespace filament::backend
|
||||
|
||||
#endif // TNT_FILAMENT_BACKEND_VULKAN_VULKANSEMAPHORE_H
|
||||
@@ -1,70 +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 "VulkanSemaphoreManager.h"
|
||||
|
||||
#include "VulkanConstants.h"
|
||||
|
||||
using namespace bluevk;
|
||||
|
||||
namespace {
|
||||
constexpr size_t INITIAL_POOL_SIZE = FVK_MAX_COMMAND_BUFFERS;
|
||||
|
||||
VkSemaphore createSemaphore(VkDevice device) {
|
||||
VkSemaphore semaphore;
|
||||
VkSemaphoreCreateInfo semaphoreInfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO,
|
||||
};
|
||||
vkCreateSemaphore(device, &semaphoreInfo, VKALLOC, &semaphore);
|
||||
return semaphore;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace filament::backend {
|
||||
|
||||
VulkanSemaphoreManager::VulkanSemaphoreManager(VkDevice device,
|
||||
fvkmemory::ResourceManager* resourceManager)
|
||||
: mDevice(device),
|
||||
mResourceManager(resourceManager) {
|
||||
for (size_t i= 0; i < INITIAL_POOL_SIZE; ++i) {
|
||||
mPool.push_back(createSemaphore(mDevice));
|
||||
}
|
||||
}
|
||||
|
||||
void VulkanSemaphoreManager::terminate() {
|
||||
for (VkSemaphore semaphore : mPool) {
|
||||
vkDestroySemaphore(mDevice, semaphore, VKALLOC);
|
||||
}
|
||||
mPool.clear();
|
||||
}
|
||||
|
||||
VulkanSemaphoreManager::Semaphore VulkanSemaphoreManager::acquire() {
|
||||
VkSemaphore semaphore;
|
||||
if (!mPool.empty()) {
|
||||
semaphore = mPool.back();
|
||||
mPool.pop_back();
|
||||
} else {
|
||||
semaphore = createSemaphore(mDevice);
|
||||
}
|
||||
return Semaphore::construct(mResourceManager, this, semaphore);
|
||||
}
|
||||
|
||||
void VulkanSemaphoreManager::recycle(VkSemaphore semaphore) {
|
||||
mPool.push_back(semaphore);
|
||||
}
|
||||
|
||||
} // namespace filament::backend
|
||||
@@ -1,51 +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_VULKAN_VULKANSEMAPHOREMANAGER_H
|
||||
#define TNT_FILAMENT_BACKEND_VULKAN_VULKANSEMAPHOREMANAGER_H
|
||||
|
||||
#include "vulkan/VulkanSemaphore.h"
|
||||
#include "vulkan/memory/ResourceManager.h"
|
||||
#include "vulkan/memory/ResourcePointer.h"
|
||||
|
||||
#include <bluevk/BlueVK.h>
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace filament::backend {
|
||||
|
||||
class VulkanSemaphoreManager {
|
||||
public:
|
||||
using Semaphore = fvkmemory::resource_ptr<VulkanSemaphore>;
|
||||
|
||||
VulkanSemaphoreManager(VkDevice device, fvkmemory::ResourceManager* resourceManager);
|
||||
~VulkanSemaphoreManager() = default;
|
||||
|
||||
void terminate();
|
||||
Semaphore acquire();
|
||||
|
||||
private:
|
||||
friend struct VulkanSemaphore;
|
||||
void recycle(VkSemaphore semaphore);
|
||||
|
||||
VkDevice mDevice;
|
||||
fvkmemory::ResourceManager* mResourceManager;
|
||||
std::vector<VkSemaphore> mPool;
|
||||
};
|
||||
|
||||
} // namespace filament::backend
|
||||
|
||||
#endif // TNT_FILAMENT_BACKEND_VULKAN_VULKANSEMAPHOREMANAGER_H
|
||||
@@ -59,10 +59,7 @@ VulkanSwapChain::~VulkanSwapChain() {
|
||||
|
||||
mColors = {};
|
||||
mDepth = {};
|
||||
for (auto& semaphore : mFinishedDrawing) {
|
||||
semaphore = {};
|
||||
}
|
||||
mFinishedDrawing.clear();
|
||||
|
||||
mPlatform->destroy(swapChain);
|
||||
}
|
||||
|
||||
@@ -70,17 +67,9 @@ void VulkanSwapChain::update() {
|
||||
mColors.clear();
|
||||
|
||||
auto const bundle = mPlatform->getSwapChainBundle(swapChain);
|
||||
size_t const swapChainCount = bundle.colors.size();
|
||||
mColors.reserve(bundle.colors.size());
|
||||
VkDevice const device = mPlatform->getDevice();
|
||||
|
||||
mFinishedDrawing.clear();
|
||||
mFinishedDrawing.reserve(swapChainCount);
|
||||
mFinishedDrawing.resize(swapChainCount);
|
||||
for (size_t i = 0; i < swapChainCount; ++i) {
|
||||
mFinishedDrawing[i] = {};
|
||||
}
|
||||
|
||||
TextureUsage depthUsage = TextureUsage::DEPTH_ATTACHMENT;
|
||||
TextureUsage colorUsage = TextureUsage::COLOR_ATTACHMENT;
|
||||
if (bundle.isProtected) {
|
||||
@@ -121,10 +110,8 @@ void VulkanSwapChain::present(DriverBase& driver) {
|
||||
|
||||
// We only present if it is not headless. No-op for headless.
|
||||
if (!mHeadless) {
|
||||
auto finishedDrawing = mCommands->acquireFinishedSignal();
|
||||
mFinishedDrawing[mCurrentSwapIndex] = finishedDrawing;
|
||||
VkResult const result =
|
||||
mPlatform->present(swapChain, mCurrentSwapIndex, finishedDrawing->getVkSemaphore());
|
||||
VkSemaphore const finishedDrawing = mCommands->acquireFinishedSignal();
|
||||
VkResult const result = mPlatform->present(swapChain, mCurrentSwapIndex, finishedDrawing);
|
||||
FILAMENT_CHECK_POSTCONDITION(result == VK_SUCCESS || result == VK_SUBOPTIMAL_KHR ||
|
||||
result == VK_ERROR_OUT_OF_DATE_KHR)
|
||||
<< "Cannot present in swapchain. error=" << static_cast<int32_t>(result);
|
||||
@@ -162,7 +149,6 @@ void VulkanSwapChain::acquire(bool& resized) {
|
||||
VulkanPlatform::ImageSyncData imageSyncData;
|
||||
VkResult const result = mPlatform->acquire(swapChain, &imageSyncData);
|
||||
mCurrentSwapIndex = imageSyncData.imageIndex;
|
||||
mFinishedDrawing[mCurrentSwapIndex] = {};
|
||||
FILAMENT_CHECK_POSTCONDITION(result == VK_SUCCESS || result == VK_SUBOPTIMAL_KHR)
|
||||
<< "Cannot acquire in swapchain. error=" << static_cast<int32_t>(result);
|
||||
if (imageSyncData.imageReadySemaphore != VK_NULL_HANDLE) {
|
||||
|
||||
@@ -116,7 +116,6 @@ private:
|
||||
// We create VulkanTextures based on VkImages. VulkanTexture has facilities for doing layout
|
||||
// transitions, which are useful here.
|
||||
utils::FixedCapacityVector<fvkmemory::resource_ptr<VulkanTexture>> mColors;
|
||||
utils::FixedCapacityVector<fvkmemory::resource_ptr<VulkanSemaphore>> mFinishedDrawing;
|
||||
fvkmemory::resource_ptr<VulkanTexture> mDepth;
|
||||
VkExtent2D mExtent;
|
||||
uint32_t mLayerCount;
|
||||
|
||||
@@ -40,7 +40,6 @@ template ResourceType getTypeEnum<VulkanFence>() noexcept;
|
||||
template ResourceType getTypeEnum<VulkanBuffer>() noexcept;
|
||||
template ResourceType getTypeEnum<VulkanSync>() noexcept;
|
||||
template ResourceType getTypeEnum<VulkanMemoryMappedBuffer>() noexcept;
|
||||
template ResourceType getTypeEnum<VulkanSemaphore>() noexcept;
|
||||
|
||||
template<typename D>
|
||||
ResourceType getTypeEnum() noexcept {
|
||||
@@ -101,9 +100,6 @@ ResourceType getTypeEnum() noexcept {
|
||||
if constexpr (std::is_same_v<D, VulkanMemoryMappedBuffer>) {
|
||||
return ResourceType::MEMORY_MAPPED_BUFFER;
|
||||
}
|
||||
if constexpr (std::is_same_v<D, VulkanSemaphore>) {
|
||||
return ResourceType::SEMAPHORE;
|
||||
}
|
||||
return ResourceType::UNDEFINED_TYPE;
|
||||
}
|
||||
|
||||
@@ -147,8 +143,6 @@ std::string_view getTypeStr(ResourceType type) {
|
||||
return "Sync";
|
||||
case ResourceType::MEMORY_MAPPED_BUFFER:
|
||||
return "VulkanMemoryMappedBuffer";
|
||||
case ResourceType::SEMAPHORE:
|
||||
return "Semaphore";
|
||||
case ResourceType::UNDEFINED_TYPE:
|
||||
return "";
|
||||
}
|
||||
|
||||
@@ -54,8 +54,7 @@ enum class ResourceType : uint8_t {
|
||||
STAGE_IMAGE = 16,
|
||||
SYNC = 17,
|
||||
MEMORY_MAPPED_BUFFER = 18,
|
||||
SEMAPHORE = 19,
|
||||
UNDEFINED_TYPE = 20, // Must be the last enum because we use it for iterating over the enums.
|
||||
UNDEFINED_TYPE = 19, // Must be the last enum because we use it for iterating over the enums.
|
||||
};
|
||||
|
||||
template<typename D>
|
||||
|
||||
@@ -120,9 +120,6 @@ void ResourceManager::destroyWithType(ResourceType type, HandleId id) {
|
||||
case ResourceType::MEMORY_MAPPED_BUFFER:
|
||||
destruct<VulkanMemoryMappedBuffer>(Handle<VulkanMemoryMappedBuffer>(id));
|
||||
break;
|
||||
case ResourceType::SEMAPHORE:
|
||||
destruct<VulkanSemaphore>(Handle<VulkanSemaphore>(id));
|
||||
break;
|
||||
case ResourceType::UNDEFINED_TYPE:
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -24,7 +24,6 @@
|
||||
#include <private/backend/HandleAllocator.h>
|
||||
|
||||
#include <utils/Panic.h>
|
||||
#include <utils/ImmutableCString.h>
|
||||
|
||||
namespace filament::backend::fvkmemory {
|
||||
|
||||
@@ -37,7 +36,7 @@ public:
|
||||
return mHandleAllocatorImpl.allocate<D>();
|
||||
}
|
||||
|
||||
inline void associateHandle(HandleBase::HandleId id, utils::ImmutableCString&& tag) noexcept {
|
||||
inline void associateHandle(HandleBase::HandleId id, utils::CString&& tag) noexcept {
|
||||
mHandleAllocatorImpl.associateTagToHandle(id, std::move(tag));
|
||||
}
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user