mirror of
https://github.com/doitsujin/dxvk.git
synced 2025-03-06 20:58:37 +01:00
Compare commits
1152 commits
Author | SHA1 | Date | |
---|---|---|---|
|
a08579e555 | ||
|
45ec01a0a1 | ||
|
542e0d2ab0 | ||
|
91b48dd31d | ||
|
d8eb4d0d66 | ||
|
f161d9bc7b | ||
|
634f38b38d | ||
|
ff8378be19 | ||
|
ad75fb17cd | ||
|
76244812fb | ||
|
9c0dec9f58 | ||
|
a4a5bf5d63 | ||
|
49f0968f57 | ||
|
ec0deb73da | ||
|
fed51e6c92 | ||
|
196258111c | ||
|
d04fe1cdc0 | ||
|
3cf453160c | ||
|
9769df9dd8 | ||
|
106032fa65 | ||
|
d2b53b76de | ||
|
02dc403074 | ||
|
420d083677 | ||
|
cd29f0feaa | ||
|
baaf72a373 | ||
|
1f0ad760e1 | ||
|
fe58b393d4 | ||
|
c21f4e0190 | ||
|
416f9c5a4a | ||
|
5b68884fd9 | ||
|
8f84085370 | ||
|
b35e69b467 | ||
|
11dc0e7ce8 | ||
|
6b5d595b3e | ||
|
396a4e0235 | ||
|
c04410ca00 | ||
|
fcbdff3b72 | ||
|
0359a3521d | ||
|
b41253e18d | ||
|
96a260e94e | ||
|
2cb9d40f88 | ||
|
2cd305e606 | ||
|
ec5bd04378 | ||
|
43f360d20c | ||
|
6f59124e9a | ||
|
d6d13edb7a | ||
|
31192b6d3f | ||
|
31a4679960 | ||
|
13bd234cea | ||
|
dafb71b18e | ||
|
a0c8bbaf10 | ||
|
9c395fd60d | ||
|
866228a37d | ||
|
60bf1f9ec4 | ||
|
95e12decf1 | ||
|
e3f047a96a | ||
|
7208d06548 | ||
|
fc3cf3e822 | ||
|
c69dbc4490 | ||
|
a0ea29a2fa | ||
|
9b37ba679a | ||
|
016f05a770 | ||
|
7e503fa053 | ||
|
7815b6942d | ||
|
fc3d3ae331 | ||
|
20dc389ab7 | ||
|
9f9d51d52c | ||
|
9389456d20 | ||
|
69171873fa | ||
|
c0983a32be | ||
|
3e6dfcfb15 | ||
|
9d890c75ac | ||
|
771f14c466 | ||
|
b0d881046f | ||
|
f2ab76c8db | ||
|
4fdbfffdcc | ||
|
a61c114519 | ||
|
41ec7b6a02 | ||
|
be61341178 | ||
|
6080e6d24d | ||
|
75599780f2 | ||
|
5f16faaae0 | ||
|
94b48c1633 | ||
|
f7d56886c5 | ||
|
0691a7fc46 | ||
|
a135e01f89 | ||
|
1d8fb818fc | ||
|
6f7a468174 | ||
|
dd1ca4ce59 | ||
|
c475960754 | ||
|
e01a6eec3e | ||
|
d94e3633dc | ||
|
8c7da07085 | ||
|
22052106d8 | ||
|
3716d48c89 | ||
|
317607e192 | ||
|
19361c962c | ||
|
636669e1a5 | ||
|
b03d457ffb | ||
|
a2c9c0f740 | ||
|
07f7ccdc96 | ||
|
d37a13847a | ||
|
18e5c12b6d | ||
|
48d145fff6 | ||
|
04d2609a91 | ||
|
3bbae86ec9 | ||
|
53b076be61 | ||
|
009f8ee356 | ||
|
be9391ded5 | ||
|
96337f11d4 | ||
|
24b58e5858 | ||
|
21eb682b39 | ||
|
a7c1e7a2a0 | ||
|
978d7cb65b | ||
|
23067c48c7 | ||
|
4c8ee300b5 | ||
|
4282829f38 | ||
|
92523fc0dd | ||
|
4a89b75bb7 | ||
|
274c590ad6 | ||
|
84b2ac3f97 | ||
|
8efa3ed84a | ||
|
3269f92138 | ||
|
0aebedae16 | ||
|
f2802dd2ff | ||
|
9389a0ca96 | ||
|
6d9e0baa27 | ||
|
9573c389de | ||
|
3453732bba | ||
|
0a84dbb787 | ||
|
f5a5ec7c88 | ||
|
1cabbee2bb | ||
|
563129c863 | ||
|
c5a3aa73a0 | ||
|
80bfd2ed97 | ||
|
813ae020b6 | ||
|
7e3c6f819a | ||
|
94b5cfc3d8 | ||
|
beaf6dd2a6 | ||
|
cf9ccf711b | ||
|
94254f556e | ||
|
70492b2954 | ||
|
b1174a1bdf | ||
|
efeb15edbd | ||
|
ac17d5f9b1 | ||
|
11ec65d516 | ||
|
4d3b35ae53 | ||
|
3aeedb9c98 | ||
|
9b5499caf2 | ||
|
fcabffc1e5 | ||
|
821386aeff | ||
|
fa2d791d79 | ||
|
80fb7e2294 | ||
|
00299b264b | ||
|
4a92b92f58 | ||
|
6c1bc35264 | ||
|
7d35afdc37 | ||
|
f615594f22 | ||
|
76f9bec7cc | ||
|
0a19e5b6db | ||
|
946419cda2 | ||
|
13554f18bd | ||
|
54a26dde3d | ||
|
357484bd4b | ||
|
9664e0b850 | ||
|
e5a81f8c7e | ||
|
215cebc019 | ||
|
a413eb0843 | ||
|
0434b23167 | ||
|
cf946eb981 | ||
|
3a34dae722 | ||
|
bd69d1efdc | ||
|
e3f1d4c021 | ||
|
5569274a97 | ||
|
dd5b28e557 | ||
|
8860bde34b | ||
|
8776cf2ce6 | ||
|
0cad97d5ec | ||
|
06bdc88eb6 | ||
|
1d90772eb2 | ||
|
3d35925a05 | ||
|
5b21286377 | ||
|
ad0920fe1e | ||
|
c6dc7e0939 | ||
|
48d24893d4 | ||
|
753c11d144 | ||
|
7482e45534 | ||
|
e757170211 | ||
|
e2a078d534 | ||
|
d846e89a4b | ||
|
e40f03b96a | ||
|
088915e24c | ||
|
470764e24c | ||
|
0983ab1f39 | ||
|
20b047600f | ||
|
b61ea1db76 | ||
|
4184452f49 | ||
|
736ee20eb5 | ||
|
4f9b106d40 | ||
|
86c317fbbc | ||
|
59e53c1863 | ||
|
539da5abdf | ||
|
0e9efa5183 | ||
|
4b009237d7 | ||
|
66dc0a9383 | ||
|
4c2990f199 | ||
|
c700d76477 | ||
|
859117797f | ||
|
4fcbf52752 | ||
|
0e3ed707ba | ||
|
50375ee1ee | ||
|
21f69eceaa | ||
|
23f08eaedd | ||
|
2ee598b4af | ||
|
95b8dc59fb | ||
|
273e4abb14 | ||
|
552470de63 | ||
|
55639889c7 | ||
|
53e5c4875f | ||
|
b73f9d8ecb | ||
|
84ccad3528 | ||
|
a3ba8fb4dc | ||
|
685126482d | ||
|
863591275c | ||
|
c52a68a5be | ||
|
5ed2d990af | ||
|
3dbe8ad43c | ||
|
f9c3dd1f5f | ||
|
c43cf6895b | ||
|
785649f3b8 | ||
|
42adc4ac11 | ||
|
b03ff775ce | ||
|
81c3242b6d | ||
|
816f8e9c87 | ||
|
0f9245ff33 | ||
|
cb42ea21be | ||
|
d200184306 | ||
|
a09d372caf | ||
|
8be30d7d5a | ||
|
5134a4b3c5 | ||
|
c1ed8cd1f3 | ||
|
0eeedf9259 | ||
|
d5744e5a81 | ||
|
d85d07c0ec | ||
|
1d790970d5 | ||
|
b586294e29 | ||
|
ed3c02906c | ||
|
84317f913a | ||
|
ff41a5ab12 | ||
|
ad11509e83 | ||
|
43838d3df8 | ||
|
06b44c6237 | ||
|
63e88debee | ||
|
ab9646551f | ||
|
073806df7c | ||
|
c707d9026f | ||
|
3d401690cb | ||
|
5f5c9a4cdd | ||
|
af45295a2f | ||
|
5b7726cf6f | ||
|
d5832c3075 | ||
|
f17317061c | ||
|
7f4e25267c | ||
|
07397305f1 | ||
|
efb9d444c1 | ||
|
071dec7148 | ||
|
279c6f150a | ||
|
50f9630250 | ||
|
485090d039 | ||
|
498ecca81d | ||
|
9bb06baaaa | ||
|
ca2afb0b8b | ||
|
1b9ea8c6e3 | ||
|
d9b5f09239 | ||
|
71bd780340 | ||
|
b62a8c78b4 | ||
|
8c3d7a1979 | ||
|
4970dc3358 | ||
|
1721be4973 | ||
|
d2d46be8da | ||
|
3339b165cd | ||
|
3e77893ef7 | ||
|
098d5adca5 | ||
|
2507820339 | ||
|
7f4f927980 | ||
|
5487f8b9a0 | ||
|
4151d35e8e | ||
|
639f815432 | ||
|
13ec120289 | ||
|
9d37e4abb4 | ||
|
7bb8819fbc | ||
|
8017607fe7 | ||
|
84ad2ea261 | ||
|
8ead28e481 | ||
|
475bf4e9c1 | ||
|
150cb0d4c7 | ||
|
28a08cae6d | ||
|
9a244e8951 | ||
|
24f98c5835 | ||
|
33498eb512 | ||
|
8b9b46dfff | ||
|
7425a33dd7 | ||
|
39f4d804a2 | ||
|
1eb0c687a6 | ||
|
b4faf0bb3e | ||
|
acf93aa70a | ||
|
65843aa016 | ||
|
67f4ec73aa | ||
|
d1789c4d85 | ||
|
fb8f79e4a7 | ||
|
0997719a73 | ||
|
5868b067e4 | ||
|
32399461da | ||
|
4dd0afe121 | ||
|
d1abce3be2 | ||
|
45da7d6678 | ||
|
b1ad43145b | ||
|
a78c1bd6dd | ||
|
d094053018 | ||
|
d956b188ed | ||
|
8c4c814fb7 | ||
|
027fe5963a | ||
|
17b85accfb | ||
|
f23c74949a | ||
|
fb56668dc0 | ||
|
9c012c8e75 | ||
|
640a266158 | ||
|
93d2715b7a | ||
|
218b67dd0c | ||
|
4e07302cbf | ||
|
b8ce414820 | ||
|
d7bd3cd58e | ||
|
15db475edf | ||
|
9e1bc1db23 | ||
|
97ad37e409 | ||
|
77020760f1 | ||
|
bb227fa850 | ||
|
34165f3814 | ||
|
423c86bf5e | ||
|
dd183b4a53 | ||
|
4f98844f47 | ||
|
43b79bcb23 | ||
|
dd15328ccf | ||
|
7f1e52703d | ||
|
b276c60f49 | ||
|
7ffd6dae2c | ||
|
987c132df2 | ||
|
fefa4ee1f6 | ||
|
ce1b06d0c6 | ||
|
482e758aee | ||
|
1dcc9f3b6a | ||
|
4fb6403b8f | ||
|
12c2b2f81b | ||
|
4c09b006a5 | ||
|
2dadad57f0 | ||
|
8dc1fe1262 | ||
|
e6209d28cd | ||
|
56b7c8cd41 | ||
|
757081a55a | ||
|
3756e83ae4 | ||
|
6610f4237f | ||
|
bca3e8db5a | ||
|
a71603a2a4 | ||
|
f05b104310 | ||
|
d9d99445bd | ||
|
664783b290 | ||
|
125f0acefd | ||
|
d13375f4ed | ||
|
847a581288 | ||
|
c745136f67 | ||
|
8bca36460a | ||
|
9b272fb3f6 | ||
|
c5bc4d1bac | ||
|
8584fc7722 | ||
|
bdd4956dd3 | ||
|
2db10b0af8 | ||
|
da406133f1 | ||
|
1d2d05dde0 | ||
|
43e636cf42 | ||
|
bd6b7aedc1 | ||
|
9e316b8c71 | ||
|
1dfb869df2 | ||
|
ae67c026aa | ||
|
789e8db699 | ||
|
30f2a8c26b | ||
|
64e32d4ee1 | ||
|
f5241d187c | ||
|
1832332d6d | ||
|
81bdf191cb | ||
|
c5d776c3b8 | ||
|
a5e8a42288 | ||
|
bdf4cb765a | ||
|
116d488faa | ||
|
35d94ae057 | ||
|
0896df7b9a | ||
|
62970d24c3 | ||
|
eb98047412 | ||
|
c466dec207 | ||
|
c968ba624b | ||
|
64b35c5c0f | ||
|
3c88591326 | ||
|
ccd19ce90b | ||
|
c4421348cf | ||
|
cde8661bc1 | ||
|
778b04f39a | ||
|
54c45ef3fa | ||
|
c764dd97a6 | ||
|
f3c320b490 | ||
|
b38c6b4dc2 | ||
|
27ceecfad9 | ||
|
860d038d77 | ||
|
88be8256e6 | ||
|
931796d1c2 | ||
|
0c117595b1 | ||
|
1181efd09d | ||
|
a760f4a8dc | ||
|
a7c2eb140e | ||
|
35352b9c52 | ||
|
11d5f9ee36 | ||
|
0e6be8a48b | ||
|
48d8e7c402 | ||
|
19fea8c48d | ||
|
8d10bfecd4 | ||
|
c606ab03e8 | ||
|
f74b2cd6c6 | ||
|
6e43bf6d61 | ||
|
d4f25c81be | ||
|
f9bb8f0ad5 | ||
|
65aa74aa7f | ||
|
a91afc3a2f | ||
|
f0e9138886 | ||
|
67c5ab87f9 | ||
|
8ee7031742 | ||
|
223691b7aa | ||
|
84ce80f931 | ||
|
85684109b3 | ||
|
3c389ae06b | ||
|
ff78112271 | ||
|
e41b1a11b2 | ||
|
0e14fff749 | ||
|
10fac66007 | ||
|
201e1628b0 | ||
|
e499f2e081 | ||
|
c2928ab3e2 | ||
|
7cd8a14673 | ||
|
34b82a2b5b | ||
|
d85cabe457 | ||
|
b5e5d7a498 | ||
|
c795415c39 | ||
|
301f06bdfb | ||
|
e69f09175f | ||
|
28a1077c06 | ||
|
8269b93f51 | ||
|
c8ab88e8f5 | ||
|
f0054e7e65 | ||
|
dd6d82e1ce | ||
|
0fd00087e9 | ||
|
469025d234 | ||
|
0259f55285 | ||
|
5ad84563dd | ||
|
7ffe77f7c4 | ||
|
a0d48cd2a2 | ||
|
63d9affdcb | ||
|
a323abe085 | ||
|
678ccc721d | ||
|
80fbaed291 | ||
|
4709d429ed | ||
|
640758afcf | ||
|
ed83534970 | ||
|
e9574a4155 | ||
|
d535e2964f | ||
|
3268bda4a2 | ||
|
1a4ac219ed | ||
|
7df58de815 | ||
|
763780fb4c | ||
|
662cfd49f5 | ||
|
640379e54b | ||
|
ec62551412 | ||
|
9977313c32 | ||
|
62f266098e | ||
|
de400ae8a9 | ||
|
7a09ab6c83 | ||
|
787671ef62 | ||
|
899f48bc43 | ||
|
c4cddebb89 | ||
|
2c8fe59924 | ||
|
69437c2fea | ||
|
7a693ed41a | ||
|
9cbd45b8cf | ||
|
0723250c12 | ||
|
13da763f9b | ||
|
800792a67d | ||
|
c7a9c626f5 | ||
|
a9bcb40655 | ||
|
bfcfcab60f | ||
|
a3c8c88222 | ||
|
3a1de271cb | ||
|
9a8406f28a | ||
|
8e94a8bcc6 | ||
|
4e40d0b939 | ||
|
bb05f123db | ||
|
efebceecbe | ||
|
7ccfb57d57 | ||
|
809257051b | ||
|
3befea6516 | ||
|
90f32d76ff | ||
|
77a1164d1b | ||
|
1c157d1a63 | ||
|
4af31a9d64 | ||
|
b4ed108105 | ||
|
f9a99e81f4 | ||
|
f3fa2535e8 | ||
|
800f71c4f5 | ||
|
ae9024492b | ||
|
d10df6353b | ||
|
565af8c311 | ||
|
24e0440043 | ||
|
01300bb884 | ||
|
cd4d68244d | ||
|
f813549ced | ||
|
ce42ce2f3f | ||
|
a5dc3400bd | ||
|
27539fc838 | ||
|
1ee60048c0 | ||
|
4c0cbbef6a | ||
|
6540ab4f3e | ||
|
3a587c5116 | ||
|
cc22ccfc5c | ||
|
8389734e9f | ||
|
b011e22406 | ||
|
7fef97dae0 | ||
|
50d8e3933a | ||
|
4a00623c40 | ||
|
56e8d55830 | ||
|
863ce5f117 | ||
|
d72346f2cb | ||
|
43355ecd73 | ||
|
f56b77942d | ||
|
f85596ffbf | ||
|
01684d36ba | ||
|
e2b4060d43 | ||
|
990c7f562a | ||
|
fb6e0ad6c1 | ||
|
500c86c054 | ||
|
0249193403 | ||
|
bdec26b442 | ||
|
f8b9efd11e | ||
|
d2155c7f8c | ||
|
f69dc96c24 | ||
|
8ab6b8616b | ||
|
255e7b7d7a | ||
|
af4ec3c63d | ||
|
f76fb75956 | ||
|
b2598906ca | ||
|
6301b9d23d | ||
|
708d23ca4b | ||
|
4d2799f0d4 | ||
|
56a58095fe | ||
|
4b94b8989d | ||
|
0388f20cd3 | ||
|
7c274d0852 | ||
|
3d12c1aea5 | ||
|
d00d0a39ce | ||
|
c2edd0f9bb | ||
|
7b65ee00d9 | ||
|
7b436a63fb | ||
|
63347b5fce | ||
|
706d6cbc1c | ||
|
42da4348bf | ||
|
2864a5e474 | ||
|
793f9b3d38 | ||
|
856a84e6fd | ||
|
59d37757b0 | ||
|
e21c2977df | ||
|
d7dd80b62f | ||
|
389e40be67 | ||
|
82c2f5d5d1 | ||
|
a4daa63d2b | ||
|
ab9ade76d7 | ||
|
e70e72f109 | ||
|
ab300dce2f | ||
|
a1a9cd5bb6 | ||
|
7edfad763a | ||
|
33b146467a | ||
|
03a716e308 | ||
|
ee9d09c2e2 | ||
|
826114f612 | ||
|
3ecca3d171 | ||
|
6ef6cb3b45 | ||
|
5dfc4d6300 | ||
|
cc3dd31a5f | ||
|
bbe7767475 | ||
|
318e79c2ad | ||
|
50b1932aea | ||
|
b33f0c3d30 | ||
|
e6c0903600 | ||
|
9698653055 | ||
|
94915fcbe3 | ||
|
6b01203ddf | ||
|
6e6ee35587 | ||
|
b771bef837 | ||
|
d154a684ad | ||
|
3de0f27dd9 | ||
|
801ef39895 | ||
|
154eee96a0 | ||
|
704fc4eaa7 | ||
|
4d19e58f51 | ||
|
7ffde27551 | ||
|
bbd041194b | ||
|
18cdc25773 | ||
|
e8a5583562 | ||
|
088e4024f5 | ||
|
ebd067f098 | ||
|
2353867d54 | ||
|
aff6cb744c | ||
|
971042b3d3 | ||
|
c24be65f2a | ||
|
ef79f8a617 | ||
|
1e8631189c | ||
|
8955d2a285 | ||
|
756ff73c8a | ||
|
c6c85d7532 | ||
|
af3c46d83c | ||
|
763b82b1e4 | ||
|
35ead85929 | ||
|
de65e06831 | ||
|
e4630685e4 | ||
|
01a1c8359a | ||
|
eafdf0bfd7 | ||
|
25069dbd1d | ||
|
a044c639f7 | ||
|
98fa338be0 | ||
|
b707ca1309 | ||
|
f65897be4c | ||
|
421ead5b30 | ||
|
b99012d332 | ||
|
05d089bee5 | ||
|
458b8e3b41 | ||
|
693ee7898d | ||
|
1b9c59c964 | ||
|
d00669cb52 | ||
|
5890eae32f | ||
|
5ff365b9f1 | ||
|
48c57c11e9 | ||
|
44b682051b | ||
|
c8759418af | ||
|
d39d879838 | ||
|
395ac38890 | ||
|
a1a3800b3f | ||
|
a30fdc466b | ||
|
ac1dfbacb6 | ||
|
0f6f543583 | ||
|
df60a061a4 | ||
|
ec18dd7846 | ||
|
d330718353 | ||
|
e137f049ee | ||
|
e6f90b8003 | ||
|
ad1f70beea | ||
|
f67c8dd1da | ||
|
501b0991da | ||
|
725a04b954 | ||
|
34e0f6952b | ||
|
2fac69b7f9 | ||
|
15d5b69d2c | ||
|
3c50ac1f12 | ||
|
c92ee8ee07 | ||
|
c27cae2f10 | ||
|
c614e537a9 | ||
|
7eec8fb8dc | ||
|
559398f6a4 | ||
|
1689cacc47 | ||
|
66bd9ec4dd | ||
|
8c54969552 | ||
|
088cf45439 | ||
|
6e0c048b88 | ||
|
912a530d1c | ||
|
eae12e6f23 | ||
|
bc78fc6ed0 | ||
|
4a8ba388ff | ||
|
653559979c | ||
|
7935f3934f | ||
|
571a2d5811 | ||
|
813524c146 | ||
|
851f02fa58 | ||
|
36907ec01c | ||
|
980a8d185c | ||
|
4f90ad46b9 | ||
|
1675aea857 | ||
|
b13b875ca6 | ||
|
bbe82aa534 | ||
|
7ff5321910 | ||
|
87a7882812 | ||
|
050886d08a | ||
|
9d19fa18a7 | ||
|
329d9a0bb2 | ||
|
4420c39b62 | ||
|
dbaa4d8df4 | ||
|
836e990dc5 | ||
|
a278d6bf1d | ||
|
c9ec2eeab2 | ||
|
2af3fde5f2 | ||
|
172d3450d1 | ||
|
c678e8c803 | ||
|
129efdaba6 | ||
|
89ebabd8fd | ||
|
bf9dfc77ce | ||
|
63b200f08d | ||
|
b35c0bce4f | ||
|
46f10c8fd5 | ||
|
7d31a7f16f | ||
|
4ce200bcae | ||
|
aa162365ce | ||
|
207e15eb24 | ||
|
1c06431e18 | ||
|
09284988ff | ||
|
0c49e30882 | ||
|
513312885e | ||
|
7d05a99640 | ||
|
4807af01ad | ||
|
1443e22626 | ||
|
90b036f550 | ||
|
a5e3f29074 | ||
|
e83446f5c9 | ||
|
c26c21edb4 | ||
|
11f8dc0818 | ||
|
9f0bd8e17f | ||
|
c59d6bd12c | ||
|
438a08f87c | ||
|
abd888a0bb | ||
|
b164d6e2a7 | ||
|
5f3fa9e423 | ||
|
2fa773e791 | ||
|
150c40280f | ||
|
67d1285b08 | ||
|
58dab7e8c6 | ||
|
8c67af680c | ||
|
2c176f4950 | ||
|
ae90e74a5a | ||
|
fd439c3e54 | ||
|
56a07b5bd0 | ||
|
bfbb7987b2 | ||
|
53f14e2914 | ||
|
ae3a9f595e | ||
|
e6f89062f5 | ||
|
07dfeeb319 | ||
|
543b5c7af8 | ||
|
c7dab6a442 | ||
|
707ddd63a1 | ||
|
4635397bb1 | ||
|
5f9f43e658 | ||
|
b4e69dce76 | ||
|
8195bea63e | ||
|
b0d0959329 | ||
|
1cefe90ce7 | ||
|
01a7457a6f | ||
|
a172cab34f | ||
|
4ed50ec6be | ||
|
78f5136fde | ||
|
5e5c283149 | ||
|
39f50999a3 | ||
|
50878f2846 | ||
|
347925c8b7 | ||
|
25076d9220 | ||
|
713b76bea5 | ||
|
d7e1794e29 | ||
|
eec4f0fb35 | ||
|
bcd12a5b56 | ||
|
0f23a17d8f | ||
|
af4a2f7973 | ||
|
bbd2461c8f | ||
|
1ba6b81901 | ||
|
5263307c4a | ||
|
7ac9918b39 | ||
|
9cf72b5b19 | ||
|
428b1087a0 | ||
|
2722a41675 | ||
|
9a51849920 | ||
|
4db0007af3 | ||
|
93547aec8d | ||
|
088ba404a6 | ||
|
1fd3c8040d | ||
|
14990dbb49 | ||
|
ec2f43e5e3 | ||
|
10164fdf4d | ||
|
51649f6da6 | ||
|
5813e7c031 | ||
|
00f7545d15 | ||
|
e80dd6db5f | ||
|
3bee390d91 | ||
|
f36a536288 | ||
|
5dd7a29261 | ||
|
4064c89e8c | ||
|
6f6e75b4b8 | ||
|
8e45a60542 | ||
|
eae66201f6 | ||
|
75dadf2c1c | ||
|
5c2f56c9cc | ||
|
d0832f8431 | ||
|
7ec75aaf81 | ||
|
888906a6da | ||
|
06baa48c2b | ||
|
401ca41091 | ||
|
3cd7e3efb5 | ||
|
5c8728abd2 | ||
|
d00ca261af | ||
|
27088beea8 | ||
|
e1fd2bff2c | ||
|
3a4dadb528 | ||
|
266b99ad8d | ||
|
f679d7d90f | ||
|
b46ef2ceff | ||
|
35fea6475d | ||
|
3faa1a76da | ||
|
661385584a | ||
|
5efaa06c61 | ||
|
1eec969448 | ||
|
343af21594 | ||
|
0cf05780ab | ||
|
15365f2d82 | ||
|
97091aad39 | ||
|
a7b3b1e3a4 | ||
|
4fad20d77c | ||
|
bb6d1b3b4c | ||
|
f5ca3cf5df | ||
|
d7c2e3ac76 | ||
|
ca3aa2014b | ||
|
1d49f247ac | ||
|
ef8bad33a5 | ||
|
5a08b3c451 | ||
|
04ad98690b | ||
|
033104f335 | ||
|
5bb8d09a96 | ||
|
97fb6e4f6d | ||
|
7985ac9cdb | ||
|
e687303197 | ||
|
07e7781c0b | ||
|
c7cf0a7368 | ||
|
c8791a6ba5 | ||
|
900edf55b5 | ||
|
46e8161649 | ||
|
828aaa5cdd | ||
|
43c27670ef | ||
|
dd8af9da78 | ||
|
80e950ac32 | ||
|
2f9ce66879 | ||
|
398c198df6 | ||
|
18ecc17e59 | ||
|
c8410e578e | ||
|
fb552db65f | ||
|
ddb59ae394 | ||
|
ab557a2eed | ||
|
901861c20b | ||
|
11ec603540 | ||
|
ed9ffa6584 | ||
|
758dc805bb | ||
|
5cf0783edb | ||
|
010738c107 | ||
|
89e190b771 | ||
|
84a8ea9d4a | ||
|
9f8832dd14 | ||
|
f3fa4b102a | ||
|
0a2f2275da | ||
|
04cf0008a0 | ||
|
8e03b64ca4 | ||
|
903f1af176 | ||
|
26a14c5175 | ||
|
3e26958906 | ||
|
1a1c3a4202 | ||
|
c1a25df468 | ||
|
565ec7e0d3 | ||
|
619b9b12c2 | ||
|
63506ee1ff | ||
|
22ff53013a | ||
|
9077e5212d | ||
|
daccde7643 | ||
|
7f8cfec46f | ||
|
1b172344eb | ||
|
11efd5092e | ||
|
2c23e462b3 | ||
|
d0ea5a4a87 | ||
|
427e706a40 | ||
|
04d558cf2e | ||
|
38308d443e | ||
|
d31b7997c0 | ||
|
8c58bef9cf | ||
|
a5fc08d176 | ||
|
e4fd9ff16b | ||
|
eb8d1885bd | ||
|
9a280b063a | ||
|
1c30bc92bb | ||
|
6da1ba7cff | ||
|
d89e324bc4 | ||
|
be45907479 | ||
|
02d8fa593b | ||
|
71e44b380d | ||
|
159f540e10 | ||
|
1e5b78e8ea | ||
|
60e04503a6 | ||
|
beaf01ecad | ||
|
813b653645 | ||
|
6308266a0f | ||
|
0d0b9eaac1 | ||
|
4ee907a6df | ||
|
5c987ea3d1 | ||
|
e38693cdbc | ||
|
7c9e1ed7cd | ||
|
e2b823b760 | ||
|
1077d6a67f | ||
|
33bf09122c | ||
|
c26b2ade1d | ||
|
10ab85c3ba | ||
|
031a98c232 | ||
|
b7d61b70c1 | ||
|
bac7ae2929 | ||
|
2a2d51e049 | ||
|
b74725b264 | ||
|
af1ba1b205 | ||
|
a8dbbcfa31 | ||
|
ba47af53da | ||
|
008afc1c5f | ||
|
d731608d5e | ||
|
ff137dac9f | ||
|
d456d0b437 | ||
|
cc87870be1 | ||
|
a7ae5999a9 | ||
|
5f9ca08071 | ||
4b0c9c611c | |||
|
fe9c875fe9 | ||
|
a63a5753d4 | ||
|
5a0f05ae66 | ||
|
6ffd5acefa | ||
|
33e7497ef4 | ||
|
38006e9cda | ||
|
60e523b4bf | ||
|
ef0c6b6f6f | ||
|
9b504b506e | ||
|
b2d89db8d8 | ||
|
fa5ce49675 | ||
|
bbe851f6a2 | ||
|
7de88ff993 | ||
|
ab12ffa0da | ||
|
dc3dd0f88c | ||
|
da814668bc | ||
|
df9bdfc6ea | ||
|
9e422a2b63 | ||
|
11db6d691c | ||
|
9c898bd269 | ||
|
175772944c | ||
|
5ae3cfe402 | ||
|
b03de97f1b | ||
|
18035820de | ||
|
1783b9591a | ||
|
499460184a | ||
|
afbcd94569 | ||
|
86f04a2da3 | ||
|
8573190c7d | ||
|
fe0e02de18 | ||
|
3145020a62 | ||
|
e9fc071d95 | ||
|
a276e13821 | ||
|
4b4d323ec3 | ||
|
d9994665a8 | ||
|
22b13a94ca | ||
|
3e5eb1660f | ||
|
a8710f70a5 | ||
|
336c9b6acc | ||
|
018db92342 | ||
|
51f2e246fa | ||
|
1811f4b995 | ||
|
5674abe483 | ||
|
1c198dcd48 | ||
|
379346751a | ||
|
b4c4c9e683 | ||
|
2188caae8e | ||
|
8d965359a5 | ||
|
fd978704fb | ||
|
ee18aecb8a | ||
|
c2fd91f835 | ||
|
79eea564fb | ||
|
7df8017e46 | ||
|
c98152683f | ||
|
890ad3f47f | ||
|
60cfafe027 | ||
|
889802887f | ||
|
a1ce690c5c | ||
|
07d007c642 | ||
|
58d8ea2d31 | ||
|
61bd62c327 | ||
|
7bc77b597e | ||
|
2ff2c826a5 | ||
|
f9b4046223 | ||
|
83436a97f2 | ||
|
e991bfa604 | ||
|
f33453afbb | ||
|
65dd3c7df3 | ||
|
dfc3776b24 | ||
|
3420cd78ac | ||
|
4225f35034 | ||
|
2cb2f8694e | ||
|
c1f665f92b | ||
|
20185a5309 | ||
|
0c2efda804 | ||
|
c7d61b2fc0 | ||
|
6259e86392 | ||
|
d5d236a1e2 | ||
|
10b83d184b | ||
|
0f7c1f753a | ||
|
529129c332 | ||
|
4055a92856 | ||
|
7bad17c1d1 | ||
|
6b76d70d9d | ||
|
611dc60018 | ||
|
b2789ab894 | ||
|
ab715a8876 | ||
|
1fb35b6d19 | ||
|
4333ee872d | ||
|
b99d42c688 | ||
|
dacb8b434b | ||
|
ea4cb84d8a | ||
|
65373792d2 | ||
|
29253da356 | ||
|
79398b468d | ||
|
e7d14e97de | ||
|
c613078ba8 | ||
|
2970645f33 | ||
|
462165da19 | ||
|
3f27a0ee58 | ||
|
aac3396671 | ||
|
92a43ebf65 | ||
|
8ba5256dc7 | ||
|
2b70ba8f77 | ||
|
9c66c4bf1d | ||
|
00872e9e4f | ||
|
35157357dd | ||
|
617ebf4e05 | ||
|
c2489d5a45 | ||
|
6ef98c613f | ||
|
7441137a33 | ||
|
571948cfc0 | ||
|
133f0794bc | ||
|
44695f9311 | ||
|
49e9ea5f5a | ||
|
198bd3a4b8 | ||
|
f06c646315 | ||
|
855b2746b6 | ||
|
28c7c09bf5 | ||
|
2742486540 | ||
|
037d0fa1ad | ||
|
cbf51a7a25 | ||
|
70e34dc31c | ||
|
c5aeb0f87a | ||
|
a163082770 | ||
|
2e1a19c7fd | ||
|
0beb18ef73 | ||
|
ef4428ab8c | ||
|
1085ba713e | ||
|
e857b09432 | ||
|
538f1d13d4 | ||
|
783c9d4591 | ||
|
1a685b1c67 | ||
|
8b8be7c2bf | ||
|
0776d764a4 | ||
|
15ddadc4de | ||
|
69a52b3da0 | ||
|
707ad6f328 | ||
|
3a6992ea97 | ||
|
72c86b8229 | ||
|
85215b10d6 | ||
|
fd3fbf6607 | ||
|
0a699fddb6 | ||
|
afec5cce88 | ||
|
4b0e3111d1 | ||
|
0414bbe2d5 | ||
|
20490b678f | ||
|
428c98bc63 | ||
|
a0e39e94fa | ||
|
eaa732d0b3 | ||
|
49b18f03fe | ||
|
c9cea93b7b | ||
|
69d74a46a0 | ||
|
94098aa97d | ||
|
c677ba9b3e | ||
|
77c7396ee1 | ||
|
f07e5f9eaa | ||
|
d5c3011f54 | ||
|
6b3b934471 | ||
|
9004c132ed | ||
|
24d4c9c938 | ||
|
5ded7d67f0 | ||
|
234f3ea071 | ||
|
c5a37d443a | ||
|
f254afb4fb | ||
|
39c19e9299 | ||
|
738fd4f895 | ||
|
9491b56beb | ||
|
ab3593185f | ||
|
e9a0fec5b3 | ||
|
fae78407a2 | ||
|
5312ef1cf9 | ||
|
62d64bd63a | ||
|
f83ba898af | ||
|
30f2b2df31 | ||
|
05cb963e22 | ||
|
eb339bc7e4 | ||
|
c423819e90 | ||
|
e2a46a347d | ||
|
afc6aa70fb | ||
|
799aeff560 | ||
|
2ca8fdf890 | ||
|
0841f5faf4 | ||
|
2334bbccb0 | ||
|
7d9864c077 | ||
|
d4c5fc74e7 | ||
|
6199776869 | ||
|
6faf3c1acd | ||
|
ab6bd8b17f | ||
|
89267b62ad | ||
|
34d8e65fd7 | ||
|
1568c263fb | ||
|
0cd4165658 | ||
|
4b8e8bed6e | ||
|
ac78048c23 | ||
|
14560600a9 | ||
|
854e06d3f0 | ||
|
eb806952d8 | ||
|
a44dfabe26 | ||
|
5e06cf9573 | ||
|
2cf590f636 | ||
|
a7a63b37c3 | ||
|
9cde0b5798 | ||
|
adb33d3af1 | ||
|
1b31aa5dbc | ||
|
03c09ce15f | ||
|
91f7f43c35 | ||
|
d998dee46e | ||
|
ea3149801f | ||
|
1cb58b0732 | ||
|
2ed1778df9 | ||
|
a427d22cde | ||
|
22c2abb9b7 | ||
|
f45911a28f | ||
|
e00db24557 | ||
|
552d2f0a6d | ||
|
4d974685c9 | ||
|
f0ff0007dc | ||
|
494f7fd38d | ||
|
0632da1935 | ||
|
83dc4678df | ||
|
f93cfbc26a | ||
|
c113b791a1 | ||
|
41191af3b1 | ||
|
5828f0e2b9 |
400 changed files with 44071 additions and 16633 deletions
41
.github/workflows/artifacts.yml
vendored
41
.github/workflows/artifacts.yml
vendored
|
@ -4,18 +4,18 @@ on: [push, pull_request, workflow_dispatch]
|
|||
|
||||
jobs:
|
||||
artifacts-mingw-w64:
|
||||
runs-on: ubuntu-20.04
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
id: checkout-code
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: recursive
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Setup problem matcher
|
||||
uses: Joshua-Ashton/gcc-problem-matcher@v2
|
||||
uses: Joshua-Ashton/gcc-problem-matcher@v3
|
||||
|
||||
- name: Build release
|
||||
id: build-release
|
||||
|
@ -28,39 +28,56 @@ jobs:
|
|||
|
||||
- name: Upload artifacts
|
||||
id: upload-artifacts
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: dxvk-${{ env.VERSION_NAME }}
|
||||
name: dxvk-win-${{ env.VERSION_NAME }}
|
||||
path: build/dxvk-${{ env.VERSION_NAME }}
|
||||
if-no-files-found: error
|
||||
|
||||
artifacts-steamrt-sniper:
|
||||
runs-on: ubuntu-20.04
|
||||
runs-on: ubuntu-latest
|
||||
container: registry.gitlab.steamos.cloud/steamrt/sniper/sdk:beta
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
id: checkout-code
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: recursive
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Setup problem matcher
|
||||
uses: Joshua-Ashton/gcc-problem-matcher@v2
|
||||
uses: Joshua-Ashton/gcc-problem-matcher@v3
|
||||
|
||||
- name: Build release
|
||||
id: build-release
|
||||
shell: bash
|
||||
run: |
|
||||
export VERSION_NAME="${GITHUB_REF##*/}-${GITHUB_SHA##*/}"
|
||||
./package-native.sh ${VERSION_NAME} build --no-package
|
||||
./package-native.sh ${VERSION_NAME} build
|
||||
echo "VERSION_NAME=${VERSION_NAME}" >> $GITHUB_ENV
|
||||
|
||||
- name: Upload artifacts
|
||||
id: upload-artifacts
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: dxvk-${{ env.VERSION_NAME }}
|
||||
path: build/dxvk-native-${{ env.VERSION_NAME }}
|
||||
name: dxvk-native-${{ env.VERSION_NAME }}
|
||||
path: build/dxvk-native-${{ env.VERSION_NAME }}.tar.gz
|
||||
if-no-files-found: error
|
||||
|
||||
merge-artifacts:
|
||||
runs-on: ubuntu-latest
|
||||
needs: [artifacts-mingw-w64, artifacts-steamrt-sniper]
|
||||
steps:
|
||||
- name: Get version
|
||||
id: get-version
|
||||
shell: bash
|
||||
run: |
|
||||
echo "VERSION_NAME=${GITHUB_REF##*/}-${GITHUB_SHA##*/}" >> $GITHUB_ENV
|
||||
|
||||
- name: Merge Artifacts
|
||||
uses: actions/upload-artifact/merge@v4
|
||||
with:
|
||||
name: dxvk-${{ env.VERSION_NAME }}
|
||||
pattern: dxvk*
|
||||
delete-merged: true
|
||||
|
|
34
.github/workflows/test-build-windows.yml
vendored
34
.github/workflows/test-build-windows.yml
vendored
|
@ -4,14 +4,15 @@ on: [push, pull_request, workflow_dispatch]
|
|||
|
||||
jobs:
|
||||
build-set-windows:
|
||||
runs-on: windows-2022
|
||||
runs-on: windows-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
id: checkout-code
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: recursive
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Setup glslangValidator
|
||||
shell: pwsh
|
||||
|
@ -32,6 +33,19 @@ jobs:
|
|||
Write-Output "VSDEVCMD=${installationPath}\Common7\Tools\VsDevCmd.bat" `
|
||||
| Out-File -FilePath "${Env:GITHUB_ENV}" -Append
|
||||
|
||||
- name: Download D3D8 SDK Headers
|
||||
shell: pwsh
|
||||
run: |
|
||||
Invoke-WebRequest -URI https://raw.githubusercontent.com/NovaRain/DXSDK_Collection/master/DXSDK_Aug2007/Include/d3d8.h -OutFile include/d3d8.h
|
||||
Invoke-WebRequest -URI https://raw.githubusercontent.com/NovaRain/DXSDK_Collection/master/DXSDK_Aug2007/Include/d3d8types.h -OutFile include/d3d8types.h
|
||||
Invoke-WebRequest -URI https://raw.githubusercontent.com/NovaRain/DXSDK_Collection/master/DXSDK_Aug2007/Include/d3d8caps.h -OutFile include/d3d8caps.h
|
||||
|
||||
- name: Get version
|
||||
id: get-version
|
||||
shell: bash
|
||||
run: |
|
||||
echo "VERSION_NAME=${GITHUB_REF##*/}-${GITHUB_SHA##*/}" >> $GITHUB_ENV
|
||||
|
||||
- name: Build MSVC x86
|
||||
shell: pwsh
|
||||
run: |
|
||||
|
@ -49,3 +63,19 @@ jobs:
|
|||
| % { [System.Environment]::SetEnvironmentVariable($_[0], $_[1]) }
|
||||
meson --buildtype release --backend vs2022 build-msvc-x64
|
||||
msbuild -m build-msvc-x64/dxvk.sln
|
||||
|
||||
- name: Prepare artifacts
|
||||
shell: pwsh
|
||||
run: |
|
||||
mkdir artifacts\x32
|
||||
ls -Path build-msvc-x86\src -Include *.dll,*.pdb -Recurse
|
||||
| cp -Destination (Join-Path -Path (pwd) -ChildPath artifacts\x32)
|
||||
mkdir artifacts\x64
|
||||
ls -Path build-msvc-x64\src -Include *.dll,*.pdb -Recurse
|
||||
| cp -Destination (Join-Path -Path (pwd) -ChildPath artifacts\x64)
|
||||
|
||||
- name: Upload artifacts
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: dxvk-${{ env.VERSION_NAME }}-msvc-output
|
||||
path: artifacts\*
|
||||
|
|
2
LICENSE
2
LICENSE
|
@ -1,5 +1,7 @@
|
|||
Copyright (c) 2017 Philip Rebohle
|
||||
Copyright (c) 2019 Joshua Ashton
|
||||
Copyright (c) 2019 Robin Kertels
|
||||
Copyright (c) 2023 Jeffrey Ellison
|
||||
|
||||
zlib/libpng license
|
||||
|
||||
|
|
176
README.md
176
README.md
|
@ -1,6 +1,6 @@
|
|||
# DXVK
|
||||
|
||||
A Vulkan-based translation layer for Direct3D 9/10/11 which allows running 3D applications on Linux using Wine.
|
||||
A Vulkan-based translation layer for Direct3D 8/9/10/11 which allows running 3D applications on Linux using Wine.
|
||||
|
||||
For the current status of the project, please refer to the [project wiki](https://github.com/doitsujin/dxvk/wiki).
|
||||
|
||||
|
@ -9,7 +9,7 @@ The most recent development builds can be found [here](https://github.com/doitsu
|
|||
Release builds can be found [here](https://github.com/doitsujin/dxvk/releases).
|
||||
|
||||
## How to use
|
||||
In order to install a DXVK package obtained from the [release](https://github.com/doitsujin/dxvk/releases) page into a given wine prefix, copy or symlink the DLLs into the following directories as follows, then open `winecfg` and manually add DLL overrides for `d3d11`, `d3d10core`, `dxgi`, and `d3d9`.
|
||||
In order to install a DXVK package obtained from the [release](https://github.com/doitsujin/dxvk/releases) page into a given wine prefix, copy or symlink the DLLs into the following directories as follows, then open `winecfg` and manually add `native` DLL overrides for `d3d8`, `d3d9`, `d3d10core`, `d3d11` and `dxgi` under the Libraries tab.
|
||||
|
||||
In a default Wine prefix that would be as follows:
|
||||
```
|
||||
|
@ -32,9 +32,87 @@ In order to remove DXVK from a prefix, remove the DLLs and DLL overrides, and ru
|
|||
|
||||
Tools such as Steam Play, Lutris, Bottles, Heroic Launcher, etc will automatically handle setup of dxvk on their own when enabled.
|
||||
|
||||
#### DLL dependencies
|
||||
Listed below are the DLL requirements for using DXVK with any single API.
|
||||
|
||||
- d3d8: `d3d8.dll` and `d3d9.dll`
|
||||
- d3d9: `d3d9.dll`
|
||||
- d3d10: `d3d10core.dll`, `d3d11.dll` and `dxgi.dll`
|
||||
- d3d11: `d3d11.dll` and `dxgi.dll`
|
||||
|
||||
### Notes on Vulkan drivers
|
||||
Before reporting an issue, please check the [Wiki](https://github.com/doitsujin/dxvk/wiki/Driver-support) page on the current driver status and make sure you run a recent enough driver version for your hardware.
|
||||
|
||||
### Online multi-player games
|
||||
Manipulation of Direct3D libraries in multi-player games may be considered cheating and can get your account **banned**. This may also apply to single-player games with an embedded or dedicated multiplayer portion. **Use at your own risk.**
|
||||
|
||||
### HUD
|
||||
The `DXVK_HUD` environment variable controls a HUD which can display the framerate and some stat counters. It accepts a comma-separated list of the following options:
|
||||
- `devinfo`: Displays the name of the GPU and the driver version.
|
||||
- `fps`: Shows the current frame rate.
|
||||
- `frametimes`: Shows a frame time graph.
|
||||
- `submissions`: Shows the number of command buffers submitted per frame.
|
||||
- `drawcalls`: Shows the number of draw calls and render passes per frame.
|
||||
- `pipelines`: Shows the total number of graphics and compute pipelines.
|
||||
- `descriptors`: Shows the number of descriptor pools and descriptor sets.
|
||||
- `memory`: Shows the amount of device memory allocated and used.
|
||||
- `allocations`: Shows detailed memory chunk suballocation info.
|
||||
- `gpuload`: Shows estimated GPU load. May be inaccurate.
|
||||
- `version`: Shows DXVK version.
|
||||
- `api`: Shows the D3D feature level used by the application.
|
||||
- `cs`: Shows worker thread statistics.
|
||||
- `compiler`: Shows shader compiler activity
|
||||
- `samplers`: Shows the current number of sampler pairs used *[D3D9 Only]*
|
||||
- `ffshaders`: Shows the current number of shaders generated from fixed function state *[D3D9 Only]*
|
||||
- `swvp`: Shows whether or not the device is running in software vertex processing mode *[D3D9 Only]*
|
||||
- `scale=x`: Scales the HUD by a factor of `x` (e.g. `1.5`)
|
||||
- `opacity=y`: Adjusts the HUD opacity by a factor of `y` (e.g. `0.5`, `1.0` being fully opaque).
|
||||
|
||||
Additionally, `DXVK_HUD=1` has the same effect as `DXVK_HUD=devinfo,fps`, and `DXVK_HUD=full` enables all available HUD elements.
|
||||
|
||||
### Logs
|
||||
When used with Wine, DXVK will print log messages to `stderr`. Additionally, standalone log files can optionally be generated by setting the `DXVK_LOG_PATH` variable, where log files in the given directory will be called `app_d3d11.log`, `app_dxgi.log` etc., where `app` is the name of the game executable.
|
||||
|
||||
On Windows, log files will be created in the game's working directory by default, which is usually next to the game executable.
|
||||
|
||||
### Frame rate limit
|
||||
The `DXVK_FRAME_RATE` environment variable can be used to limit the frame rate. A value of `0` uncaps the frame rate, while any positive value will limit rendering to the given number of frames per second. Alternatively, the configuration file can be used.
|
||||
|
||||
### Device filter
|
||||
Some applications do not provide a method to select a different GPU. In that case, DXVK can be forced to use a given device:
|
||||
- `DXVK_FILTER_DEVICE_NAME="Device Name"` Selects devices with a matching Vulkan device name, which can be retrieved with tools such as `vulkaninfo`. Matches on substrings, so "VEGA" or "AMD RADV VEGA10" is supported if the full device name is "AMD RADV VEGA10 (LLVM 9.0.0)", for example. If the substring matches more than one device, the first device matched will be used.
|
||||
|
||||
**Note:** If the device filter is configured incorrectly, it may filter out all devices and applications will be unable to create a D3D device.
|
||||
|
||||
### Debugging
|
||||
The following environment variables can be used for **debugging** purposes.
|
||||
- `VK_INSTANCE_LAYERS=VK_LAYER_KHRONOS_validation` Enables Vulkan debug layers. Highly recommended for troubleshooting rendering issues and driver crashes. Requires the Vulkan SDK to be installed on the host system.
|
||||
- `DXVK_LOG_LEVEL=none|error|warn|info|debug` Controls message logging.
|
||||
- `DXVK_LOG_PATH=/some/directory` Changes path where log files are stored. Set to `none` to disable log file creation entirely, without disabling logging.
|
||||
- `DXVK_DEBUG=markers|validation` Enables use of the `VK_EXT_debug_utils` extension for translating performance event markers, or to enable Vulkan validation, respecticely.
|
||||
- `DXVK_CONFIG_FILE=/xxx/dxvk.conf` Sets path to the configuration file.
|
||||
- `DXVK_CONFIG="dxgi.hideAmdGpu = True; dxgi.syncInterval = 0"` Can be used to set config variables through the environment instead of a configuration file using the same syntax. `;` is used as a seperator.
|
||||
|
||||
### Graphics Pipeline Library
|
||||
On drivers which support `VK_EXT_graphics_pipeline_library` Vulkan shaders will be compiled at the time the game loads its D3D shaders, rather than at draw time. This reduces or eliminates shader compile stutter in many games when compared to the previous system.
|
||||
|
||||
In games that load their shaders during loading screens or in the menu, this can lead to prolonged periods of very high CPU utilization, especially on weaker CPUs. For affected games it is recommended to wait for shader compilation to finish before starting the game to avoid stutter and low performance. Shader compiler activity can be monitored with `DXVK_HUD=compiler`.
|
||||
|
||||
This feature largely replaces the state cache.
|
||||
|
||||
**Note:** Games which only load their D3D shaders at draw time (e.g. most Unreal Engine games) will still exhibit some stutter, although it should still be less severe than without this feature.
|
||||
|
||||
### State cache
|
||||
DXVK caches pipeline state by default, so that shaders can be recompiled ahead of time on subsequent runs of an application, even if the driver's own shader cache got invalidated in the meantime. This cache is enabled by default, and generally reduces stuttering.
|
||||
|
||||
The following environment variables can be used to control the cache:
|
||||
- `DXVK_STATE_CACHE`: Controls the state cache. The following values are supported:
|
||||
- `disable`: Disables the cache entirely.
|
||||
- `reset`: Clears the cache file.
|
||||
- `DXVK_STATE_CACHE_PATH=/some/directory` Specifies a directory where to put the cache files. Defaults to the current working directory of the application.
|
||||
|
||||
This feature is mostly only relevant on systems without support for `VK_EXT_graphics_pipeline_library`
|
||||
|
||||
## Build instructions
|
||||
|
||||
In order to pull in all submodules that are needed for building, clone the repository using the following command:
|
||||
|
@ -42,11 +120,9 @@ In order to pull in all submodules that are needed for building, clone the repos
|
|||
git clone --recursive https://github.com/doitsujin/dxvk.git
|
||||
```
|
||||
|
||||
|
||||
|
||||
### Requirements:
|
||||
- [wine 7.1](https://www.winehq.org/) or newer
|
||||
- [Meson](https://mesonbuild.com/) build system (at least version 0.49)
|
||||
- [Meson](https://mesonbuild.com/) build system (at least version 0.58)
|
||||
- [Mingw-w64](https://www.mingw-w64.org) compiler and headers (at least version 10.0)
|
||||
- [glslang](https://github.com/KhronosGroup/glslang) compiler
|
||||
|
||||
|
@ -76,76 +152,9 @@ cd build.w64
|
|||
ninja install
|
||||
```
|
||||
|
||||
The D3D9, D3D10, D3D11 and DXGI DLLs will be located in `/your/dxvk/directory/bin`. Setup has to be done manually in this case.
|
||||
The D3D8, D3D9, D3D10, D3D11 and DXGI DLLs will be located in `/your/dxvk/directory/bin`.
|
||||
|
||||
### Online multi-player games
|
||||
Manipulation of Direct3D libraries in multi-player games may be considered cheating and can get your account **banned**. This may also apply to single-player games with an embedded or dedicated multiplayer portion. **Use at your own risk.**
|
||||
|
||||
### Logs
|
||||
When used with Wine, DXVK will print log messages to `stderr`. Additionally, standalone log files can optionally be generated by setting the `DXVK_LOG_PATH` variable, where log files in the given directory will be called `app_d3d11.log`, `app_dxgi.log` etc., where `app` is the name of the game executable.
|
||||
|
||||
On Windows, log files will be created in the game's working directory by default, which is usually next to the game executable.
|
||||
|
||||
### HUD
|
||||
The `DXVK_HUD` environment variable controls a HUD which can display the framerate and some stat counters. It accepts a comma-separated list of the following options:
|
||||
- `devinfo`: Displays the name of the GPU and the driver version.
|
||||
- `fps`: Shows the current frame rate.
|
||||
- `frametimes`: Shows a frame time graph.
|
||||
- `submissions`: Shows the number of command buffers submitted per frame.
|
||||
- `drawcalls`: Shows the number of draw calls and render passes per frame.
|
||||
- `pipelines`: Shows the total number of graphics and compute pipelines.
|
||||
- `descriptors`: Shows the number of descriptor pools and descriptor sets.
|
||||
- `memory`: Shows the amount of device memory allocated and used.
|
||||
- `gpuload`: Shows estimated GPU load. May be inaccurate.
|
||||
- `version`: Shows DXVK version.
|
||||
- `api`: Shows the D3D feature level used by the application.
|
||||
- `cs`: Shows worker thread statistics.
|
||||
- `compiler`: Shows shader compiler activity
|
||||
- `samplers`: Shows the current number of sampler pairs used *[D3D9 Only]*
|
||||
- `scale=x`: Scales the HUD by a factor of `x` (e.g. `1.5`)
|
||||
- `opacity=y`: Adjusts the HUD opacity by a factor of `y` (e.g. `0.5`, `1.0` being fully opaque).
|
||||
|
||||
Additionally, `DXVK_HUD=1` has the same effect as `DXVK_HUD=devinfo,fps`, and `DXVK_HUD=full` enables all available HUD elements.
|
||||
|
||||
### Frame rate limit
|
||||
The `DXVK_FRAME_RATE` environment variable can be used to limit the frame rate. A value of `0` uncaps the frame rate, while any positive value will limit rendering to the given number of frames per second. Alternatively, the configuration file can be used.
|
||||
|
||||
### Device filter
|
||||
Some applications do not provide a method to select a different GPU. In that case, DXVK can be forced to use a given device:
|
||||
- `DXVK_FILTER_DEVICE_NAME="Device Name"` Selects devices with a matching Vulkan device name, which can be retrieved with tools such as `vulkaninfo`. Matches on substrings, so "VEGA" or "AMD RADV VEGA10" is supported if the full device name is "AMD RADV VEGA10 (LLVM 9.0.0)", for example. If the substring matches more than one device, the first device matched will be used.
|
||||
|
||||
**Note:** If the device filter is configured incorrectly, it may filter out all devices and applications will be unable to create a D3D device.
|
||||
|
||||
### Graphics Pipeline Library
|
||||
On drivers which support `VK_EXT_graphics_pipeline_library` Vulkan shaders will be compiled at the time the game loads its D3D shaders, rather than at draw time. This reduces or eliminates shader compile stutter in many games when compared to the previous system.
|
||||
|
||||
In games that load their shaders during loading screens or in the menu, this can lead to prolonged periods of very high CPU utilization, especially on weaker CPUs. For affected games it is recommended to wait for shader compilation to finish before starting the game to avoid stutter and low performance. Shader compiler activity can be monitored with `DXVK_HUD=compiler`.
|
||||
|
||||
This feature largely replaces the state cache.
|
||||
|
||||
**Note:** Games which only load their D3D shaders at draw time (e.g. most Unreal Engine games) will still exhibit some stutter, although it should still be less severe than without this feature.
|
||||
|
||||
### State cache
|
||||
DXVK caches pipeline state by default, so that shaders can be recompiled ahead of time on subsequent runs of an application, even if the driver's own shader cache got invalidated in the meantime. This cache is enabled by default, and generally reduces stuttering.
|
||||
|
||||
The following environment variables can be used to control the cache:
|
||||
- `DXVK_STATE_CACHE`: Controls the state cache. The following values are supported:
|
||||
- `disable`: Disables the cache entirely.
|
||||
- `reset`: Clears the cache file.
|
||||
- `DXVK_STATE_CACHE_PATH=/some/directory` Specifies a directory where to put the cache files. Defaults to the current working directory of the application.
|
||||
|
||||
This feature is mostly only relevant on systems without support for `VK_EXT_graphics_pipeline_library`
|
||||
|
||||
### Debugging
|
||||
The following environment variables can be used for **debugging** purposes.
|
||||
- `VK_INSTANCE_LAYERS=VK_LAYER_KHRONOS_validation` Enables Vulkan debug layers. Highly recommended for troubleshooting rendering issues and driver crashes. Requires the Vulkan SDK to be installed on the host system.
|
||||
- `DXVK_LOG_LEVEL=none|error|warn|info|debug` Controls message logging.
|
||||
- `DXVK_LOG_PATH=/some/directory` Changes path where log files are stored. Set to `none` to disable log file creation entirely, without disabling logging.
|
||||
- `DXVK_DEBUG=markers|validation` Enables use of the `VK_EXT_debug_utils` extension for translating performance event markers, or to enable Vulkan validation, respecticely.
|
||||
- `DXVK_CONFIG_FILE=/xxx/dxvk.conf` Sets path to the configuration file.
|
||||
- `DXVK_CONFIG="dxgi.hideAmdGpu = True; dxgi.syncInterval = 0"` Can be used to set config variables through the environment instead of a configuration file using the same syntax. `;` is used as a seperator.
|
||||
|
||||
## Troubleshooting
|
||||
### Build troubleshooting
|
||||
DXVK requires threading support from your mingw-w64 build environment. If you
|
||||
are missing this, you may see "error: ‘std::cv_status’ has not been declared"
|
||||
or similar threading related errors.
|
||||
|
@ -163,3 +172,22 @@ For non debian based distros, make sure that your mingw-w64-gcc cross compiler
|
|||
does have `--enable-threads=posix` enabled during configure. If your distro does
|
||||
ship its mingw-w64-gcc binary with `--enable-threads=win32` you might have to
|
||||
recompile locally or open a bug at your distro's bugtracker to ask for it.
|
||||
|
||||
# DXVK Native
|
||||
|
||||
DXVK Native is a version of DXVK which allows it to be used natively without Wine.
|
||||
|
||||
This is primarily useful for game and application ports to either avoid having to write another rendering backend, or to help with port bringup during development.
|
||||
|
||||
[Release builds](https://github.com/doitsujin/dxvk/releases) are built using the Steam Runtime.
|
||||
|
||||
### How does it work?
|
||||
|
||||
DXVK Native replaces certain Windows-isms with a platform and framework-agnostic replacement, for example, `HWND`s can become `SDL_Window*`s, etc.
|
||||
All it takes to do that is to add another WSI backend.
|
||||
|
||||
**Note:** DXVK Native requires a backend to be explicitly set via the `DXVK_WSI_DRIVER` environment variable. The current built-in options are `SDL3`, `SDL2`, and `GLFW`.
|
||||
|
||||
DXVK Native comes with a slim set of Windows header definitions required for D3D9/11 and the MinGW headers for D3D9/11.
|
||||
In most cases, it will end up being plug and play with your renderer, but there may be certain teething issues such as:
|
||||
- `__uuidof(type)` is supported, but `__uuidof(variable)` is not supported. Use `__uuidof_var(variable)` instead.
|
||||
|
|
2
RELEASE
2
RELEASE
|
@ -1 +1 @@
|
|||
2.3
|
||||
2.5.3
|
||||
|
|
6
buildenv.h.in
Normal file
6
buildenv.h.in
Normal file
|
@ -0,0 +1,6 @@
|
|||
#pragma once
|
||||
|
||||
#define DXVK_TARGET "@BUILD_TARGET@"
|
||||
#define DXVK_COMPILER "@BUILD_COMPILER@"
|
||||
#define DXVK_COMPILER_VERSION "@BUILD_COMPILER_VERSION@"
|
||||
|
302
dxvk.conf
302
dxvk.conf
|
@ -1,3 +1,10 @@
|
|||
# Device filter. Only exposes devices whose Vulkan device name contains
|
||||
# the given string. May be useful to force an application to run on a
|
||||
# specific GPU, but not applications launched by that application.
|
||||
|
||||
# dxvk.deviceFilter = ""
|
||||
|
||||
|
||||
# Expose the HDR10 ColorSpace (DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020)
|
||||
# to the application by default.
|
||||
# This shows to the game that the global Windows 'HDR Mode' is enabled.
|
||||
|
@ -10,6 +17,40 @@
|
|||
|
||||
# dxgi.enableHDR = True
|
||||
|
||||
|
||||
# Expose support for dcomp swap chains with a dummy window.
|
||||
#
|
||||
# This is not a valid implementation of DirectComposition swapchains,
|
||||
# however some games may rely on this functionality to be present while
|
||||
# others may require swap chain creation to fail.
|
||||
#
|
||||
# Supported values: True, False
|
||||
|
||||
# dxgi.enableDummyCompositionSwapchain = False
|
||||
|
||||
|
||||
# Allows the Vulkan driver to opt-in to exclusive full-screen mode on
|
||||
# Windows. Certain features, such as variable refresh rate or HDR, will
|
||||
# not work without this setting, however enabling it will break certain
|
||||
# games that use additional GDI windows, and it will also break alt+tab.
|
||||
#
|
||||
# This setting has no effect on non-Windows platforms.
|
||||
#
|
||||
# Supported values: True, False
|
||||
|
||||
# dxvk.allowFse = False
|
||||
|
||||
|
||||
# Enables Unreal Engine 4 HDR workarounds for games that do not follow
|
||||
# the standard -Win64-Shipping.exe naming scheme. May be needed to avoid
|
||||
# crashes in D3D11 games on HDR-enabled systems due to statically linked
|
||||
# AMDAGS.
|
||||
#
|
||||
# Supported values: True, False
|
||||
|
||||
# dxgi.enableUe4Workarounds = False
|
||||
|
||||
|
||||
# Create the VkSurface on the first call to IDXGISwapChain::Present,
|
||||
# rather than when creating the swap chain. Some games that start
|
||||
# rendering with a different graphics API may require this option,
|
||||
|
@ -35,12 +76,57 @@
|
|||
# bugs in games that have physics or other simulation tied to their frame
|
||||
# rate, but do not provide their own limiter.
|
||||
#
|
||||
# Supported values : Any non-negative integer
|
||||
# Supported values
|
||||
# -1: Always disables the limiter
|
||||
# 0: Default behaviour. Limits the frame rate to the selected display
|
||||
# refresh rate when vertical synchronization is enabled if the
|
||||
# actual display mode does not match the game's one.
|
||||
# n: Limit to n frames per second.
|
||||
|
||||
# dxgi.maxFrameRate = 0
|
||||
# d3d9.maxFrameRate = 0
|
||||
|
||||
|
||||
# Controls latency sleep and Nvidia Reflex support.
|
||||
#
|
||||
# Supported values:
|
||||
# - Auto: By default, DXVK only supports latency sleep in D3D11 games that
|
||||
# use Reflex if the graphics driver supports VK_NV_low_latency2,
|
||||
# and if dxvk-nvapi is enabled in Proton.
|
||||
# - True: Enables built-in latency reduction based on internal timings.
|
||||
# This assumes that input sampling for any given frame happens after
|
||||
# the D3D9 or DXGI Present call returns; games that render and present
|
||||
# asynchronously will not behave as intended.
|
||||
# Similarly, this will not have any effect in games with built-in frame
|
||||
# rate limiters, or if an external limiter (such as MangoHud) is used.
|
||||
# In some games, enabling this may reduce performance or lead to less
|
||||
# consistent frame pacing.
|
||||
# The implementation will either use VK_NV_low_latency2 if supported
|
||||
# by the driver, or a custom algorithm.
|
||||
# - False: Disable Reflex support as well as built-in latency reduction.
|
||||
|
||||
# dxvk.latencySleep = Auto
|
||||
|
||||
|
||||
# Tolerance for the latency sleep heuristic, in microseconds. Higher values
|
||||
# increase latency, but may lead to better frame pacing in some cases. Does
|
||||
# not have any effect if NV_low_latency2 is used.
|
||||
#
|
||||
# Supported values: Any non-negative number
|
||||
|
||||
# dxvk.latencyTolerance = 1000
|
||||
|
||||
|
||||
# Disables the use of VK_NV_low_latency2. This will make Reflex unavailable
|
||||
# in games, and if dxvk.latencySleep is set to True, a custom algorithm will
|
||||
# be used for latency control. By default, the extension will not be used in
|
||||
# 32-bit applications due to driver issues.
|
||||
#
|
||||
# Supported values: Auto, True, False
|
||||
|
||||
# dxvk.disableNvLowLatency2 = Auto
|
||||
|
||||
|
||||
# Override PCI vendor and device IDs reported to the application. Can
|
||||
# cause the app to adjust behaviour depending on the selected values.
|
||||
#
|
||||
|
@ -62,7 +148,7 @@
|
|||
|
||||
|
||||
# Report Nvidia GPUs as AMD GPUs. Unless NVAPI support is explicitly
|
||||
# enabled through proton, this is done by default in order to work
|
||||
# enabled through Proton, this is done by default in order to work
|
||||
# around crashes or low performance with Nvidia-speciic code paths
|
||||
# in games, especially Unreal Engine.
|
||||
#
|
||||
|
@ -71,6 +157,13 @@
|
|||
# dxgi.hideNvidiaGpu = Auto
|
||||
|
||||
|
||||
# Report Nvidia GPUs running on NVK as AMD GPUs.
|
||||
#
|
||||
# Supported values: Auto, True, False
|
||||
|
||||
# dxgi.hideNvkGpu = Auto
|
||||
|
||||
|
||||
# Report AMD GPUs as Nvidia GPUs. This is only done for games that are
|
||||
# known to have issues with AMDAGS or other AMD-specific code paths.
|
||||
#
|
||||
|
@ -90,6 +183,7 @@
|
|||
# Override maximum amount of device memory and shared system memory
|
||||
# reported to the application. This may fix texture streaming issues
|
||||
# in games that do not support cards with large amounts of VRAM.
|
||||
# This is not a hard cap and applications can choose to ignore it.
|
||||
#
|
||||
# Supported values: Any number in Megabytes.
|
||||
|
||||
|
@ -97,24 +191,6 @@
|
|||
# dxgi.maxSharedMemory = 0
|
||||
|
||||
|
||||
# Some games think we are on Intel given a lack of NVAPI or
|
||||
# AGS/atiadlxx support. Report our device memory as shared memory,
|
||||
# and some small amount for a "carveout".
|
||||
|
||||
# Supported values: True, False
|
||||
|
||||
# dxgi.emulateUMA = False
|
||||
|
||||
|
||||
# Override back buffer count for the Vulkan swap chain.
|
||||
# Setting this to 0 or less will have no effect.
|
||||
#
|
||||
# Supported values: Any number greater than or equal to 2.
|
||||
|
||||
# dxgi.numBackBuffers = 0
|
||||
# d3d9.numBackBuffers = 0
|
||||
|
||||
|
||||
# Overrides synchronization interval (Vsync) for presentation.
|
||||
# Setting this to 0 disables vertical synchronization entirely.
|
||||
# A positive value 'n' will enable Vsync and repeat the same
|
||||
|
@ -126,10 +202,10 @@
|
|||
# d3d9.presentInterval = -1
|
||||
|
||||
|
||||
# Controls tearing behaviour with regards to in-game Vsync settings.
|
||||
#
|
||||
# True enables the mailbox present mode in case regular Vsync is disabled.
|
||||
# This should avoid tearing, but may be unsupported on some systems
|
||||
# or require setting dxgi.numBackBuffers to a higher value in order
|
||||
# to work properly.
|
||||
# This eliminates tearing, but may be unsupported on some systems.
|
||||
#
|
||||
# False enables the relaxed fifo present mode in case regular Vsync is enabled.
|
||||
# This should result in tearing but reduce stutter if FPS are too low,
|
||||
|
@ -142,13 +218,14 @@
|
|||
# dxvk.tearFree = Auto
|
||||
|
||||
|
||||
# Assume single-use mode for command lists created on deferred contexts.
|
||||
# This may need to be disabled for some applications to avoid rendering
|
||||
# issues, which may come at a significant performance cost.
|
||||
# Controls tiler optimizations. Enabling these will alter the behaviour of
|
||||
# submission heuristics and enables some non-default behaviour in DXVK.
|
||||
# This option is only intended to be changed for performance testing and
|
||||
# debugging purposes.
|
||||
#
|
||||
# Supported values: True, False
|
||||
# Supported values: Auto, True, False
|
||||
|
||||
# d3d11.dcSingleUseMode = True
|
||||
# dxvk.tilerMode = Auto
|
||||
|
||||
|
||||
# Override the maximum feature level that a D3D11 device can be created
|
||||
|
@ -169,23 +246,25 @@
|
|||
|
||||
|
||||
# Enables relaxed pipeline barriers around UAV writes.
|
||||
#
|
||||
# This may improve performance in some games, but may also introduce
|
||||
# rendering issues. Please don't report bugs with the option enabled.
|
||||
#
|
||||
# Ignores write-after-write hazards in compute shaders, and all UAV
|
||||
# hazards in graphics shaders. This may improve performance in some
|
||||
# games, but may also introduce rendering issues. Please don't report
|
||||
# bugs with the option enabled.
|
||||
#
|
||||
# Supported values: True, False
|
||||
|
||||
# d3d11.relaxedBarriers = False
|
||||
|
||||
|
||||
# Ignores barriers around UAV writes from fragment shaders.
|
||||
# Enables relaxed UAV pipeline barriers in graphics shaders only.
|
||||
#
|
||||
# This may improve performance in some games, but may also introduce
|
||||
# rendering issues. Please don't report bugs with the option enabled.
|
||||
# Similar to the relaxedBarriers option, except it does not apply to
|
||||
# compute UAVs. Please do not report bugs with this option enabled.
|
||||
#
|
||||
# Supported values: True, False
|
||||
|
||||
# d3d11.ignoreGraphicsBarriers = False
|
||||
# d3d11.relaxedGraphicsBarriers = False
|
||||
|
||||
|
||||
# Overrides anisotropic filtering for all samplers. Set this to a positive
|
||||
|
@ -253,20 +332,33 @@
|
|||
# d3d11.zeroWorkgroupMemory = False
|
||||
|
||||
|
||||
# Resource size limit for implicit discards, in kilobytes. For small staging
|
||||
# resources mapped with MAP_WRITE, DXVK will sometimes allocate new backing
|
||||
# storage in order to avoid GPU synchronization, so setting this too high
|
||||
# may cause memory issues, setting it to -1 disables the feature.
|
||||
# Forces insertion of memory barriers after writes to group-shared memory in
|
||||
# compute shaders. This is only intended to be used as a workaround for games
|
||||
# that don't properly synchronize access to groupshard variables, and may have
|
||||
# a negative performance impact as it prevents compiler optimizations.
|
||||
#
|
||||
# Supported values: True, False
|
||||
|
||||
# d3d11.maxImplicitDiscardSize = 256
|
||||
# d3d11.forceVolatileTgsmAccess = False
|
||||
|
||||
|
||||
# Resource size limit for buffer-mapped dynamic images, in kilobytes.
|
||||
# A higher threshold may reduce memory usage and PCI-E bandwidth in
|
||||
# some games, but may also increase GPU synchronizations. Setting it
|
||||
# to -1 disables the feature.
|
||||
# Forces insertion of full memory and control barriers after accessing any
|
||||
# read-write UAV inside compute shaders. This is only intended to be used as
|
||||
# a workaround for games that do not synchronize access to coherent UAVs,
|
||||
# and will likely have a negative performance impact.
|
||||
#
|
||||
# Supported values: True, False
|
||||
|
||||
# d3d11.maxDynamicImageBufferSize = -1
|
||||
# d3d11.forceComputeUavBarriers = False
|
||||
|
||||
|
||||
# Clears mapped memory to zero when suballocated memory is freed. This will
|
||||
# drastically increase CPU overhead and should only be used as a last resort
|
||||
# if a game does not properly initialize mapped buffers on its own.
|
||||
#
|
||||
# Supported values: True, False
|
||||
|
||||
# dxvk.zeroMappedMemory = False
|
||||
|
||||
|
||||
# Allocates dynamic resources with the given set of bind flags in
|
||||
|
@ -292,6 +384,32 @@
|
|||
# d3d11.enableContextLock = False
|
||||
|
||||
|
||||
# Exposes or hides support for driver command lists
|
||||
#
|
||||
# Some games use the feature flag to decide whether to use deferred
|
||||
# contexts or not. We enable this by default, but in some situations
|
||||
# this can lead to issues if games detect an AMD GPU where command
|
||||
# lists are not natively supported on Windows.
|
||||
#
|
||||
# Supported values: True, False
|
||||
|
||||
# d3d11.exposeDriverCommandLists = True
|
||||
|
||||
|
||||
# Reproducible Command Stream
|
||||
#
|
||||
# Ensure that for the same D3D commands the output VK commands
|
||||
# don't change between runs. Useful for comparative benchmarking,
|
||||
# can negatively affect performance and can break some games
|
||||
# that don't use queries correctly.
|
||||
#
|
||||
# Supported values:
|
||||
# - True/False
|
||||
|
||||
# d3d11.reproducibleCommandStream = False
|
||||
# d3d9.reproducibleCommandStream = False
|
||||
|
||||
|
||||
# Sets number of pipeline compiler threads.
|
||||
#
|
||||
# If the graphics pipeline library feature is enabled, the given
|
||||
|
@ -320,17 +438,6 @@
|
|||
# dxvk.useRawSsbo = Auto
|
||||
|
||||
|
||||
# Changes memory chunk size.
|
||||
#
|
||||
# Can be used to override the maximum memory chunk size.
|
||||
#
|
||||
# Supported values:
|
||||
# - 0 to use the defaults
|
||||
# - any positive integer to limit the chunk size, in MiB
|
||||
|
||||
# dxvk.maxChunkSize = 0
|
||||
|
||||
|
||||
# Controls graphics pipeline library behaviour
|
||||
#
|
||||
# Can be used to change VK_EXT_graphics_pipeline_library usage for
|
||||
|
@ -359,6 +466,21 @@
|
|||
# dxvk.trackPipelineLifetime = Auto
|
||||
|
||||
|
||||
# Controls memory defragmentation
|
||||
#
|
||||
# By default, DXVK will try to defragment video memory if there is a
|
||||
# significant amount of memory wasted, or if the allocation budget of
|
||||
# the application is exceeded. This option is provided solely for
|
||||
# debug purposes.
|
||||
#
|
||||
# Supported values:
|
||||
# - True: Enable defragmentation
|
||||
# - Auto: Enable defragmentation, except on blocked drivers
|
||||
# - False: Disable defragmentation
|
||||
|
||||
# dxvk.enableMemoryDefrag = Auto
|
||||
|
||||
|
||||
# Sets enabled HUD elements
|
||||
#
|
||||
# Behaves like the DXVK_HUD environment variable if the
|
||||
|
@ -374,6 +496,7 @@
|
|||
# capabilities that the applicatation queries.
|
||||
#
|
||||
# Supported values:
|
||||
# - 0: Fixed-function only
|
||||
# - 1: Shader Model 1
|
||||
# - 2: Shader Model 2
|
||||
# - 3: Shader Model 3
|
||||
|
@ -453,16 +576,6 @@
|
|||
# d3d9.floatEmulation = Auto
|
||||
|
||||
|
||||
# Enable dialog box mode
|
||||
#
|
||||
# Changes the default state of dialog box mode.
|
||||
# *Disables* exclusive fullscreen when enabled.
|
||||
#
|
||||
# Supported values:
|
||||
# - True, False: Always enable / disable
|
||||
|
||||
# d3d9.enableDialogMode = False
|
||||
|
||||
# Overrides the application's MSAA level on the swapchain
|
||||
#
|
||||
# Supported values: -1 (application) and 0 to 16 (user override)
|
||||
|
@ -470,17 +583,6 @@
|
|||
# d3d9.forceSwapchainMSAA = -1
|
||||
|
||||
|
||||
# Long Mad
|
||||
#
|
||||
# Should we make our Mads a FFma or do it the long way with an FMul and an FAdd?
|
||||
# This solves some rendering bugs in games that have z-pass shaders which
|
||||
# don't match entirely to the regular vertex shader in this way.
|
||||
#
|
||||
# Supported values:
|
||||
# - True/False
|
||||
|
||||
# d3d9.longMad = False
|
||||
|
||||
# Device Local Constant Buffers
|
||||
#
|
||||
# Enables using device local, host accessible memory for constant buffers in D3D9.
|
||||
|
@ -494,7 +596,9 @@
|
|||
|
||||
# Support DF formats
|
||||
#
|
||||
# Support the vendor extension DF floating point depth formats
|
||||
# Support the vendor extension DF floating point depth formats on AMD and Intel.
|
||||
# Note that this config is ignored and disabled by default on Nvidia, or when
|
||||
# spoofing a Nvidia GPU, as it does not support these formats natively.
|
||||
#
|
||||
# Supported values:
|
||||
# - True/False
|
||||
|
@ -520,14 +624,16 @@
|
|||
|
||||
# d3d9.supportX4R4G4B4 = True
|
||||
|
||||
# Support D32
|
||||
# Support D16_LOCKABLE
|
||||
#
|
||||
# Support the D32 format.
|
||||
# Support the D16_LOCKABLE format.
|
||||
# Always enabled on AMD, or when spoofing an AMD GPU
|
||||
# via customVendorId, disabled by default on Nvidia and Intel.
|
||||
#
|
||||
# Supported values:
|
||||
# - True/False
|
||||
|
||||
# d3d9.supportD32 = True
|
||||
# d3d9.supportD16Lockable = False
|
||||
|
||||
# Disable A8 as a Render Target
|
||||
#
|
||||
|
@ -623,3 +729,37 @@
|
|||
# DO NOT CHANGE THIS UNLESS YOU HAVE A VERY GOOD REASON.
|
||||
|
||||
# d3d9.textureMemory = 100
|
||||
|
||||
# Hide integrated graphics from applications
|
||||
#
|
||||
# Only has an effect when dedicated GPUs are present on the system. It is
|
||||
# not recommended to use this option at all unless absolutely necessary for
|
||||
# a game to work; prefer using DXVK_FILTER_DEVICE_NAME whenever possible.
|
||||
#
|
||||
# Supported values:
|
||||
# - True/False
|
||||
|
||||
# dxvk.hideIntegratedGraphics = False
|
||||
|
||||
# Trigger DEVICELOST when losing focus
|
||||
#
|
||||
# D3D9 requires the application to call Device::Reset after
|
||||
# it loses focus in fullscreen.
|
||||
# Some games rely on observing a D3DERR_DEVICELOST or D3DERR_NOTRESET.
|
||||
# Others don't handle it correctly.
|
||||
#
|
||||
# Supported values:
|
||||
# - True/False
|
||||
|
||||
# d3d9.deviceLossOnFocusLoss = False
|
||||
|
||||
# Reject Device::Reset if any losable resource is still alive
|
||||
#
|
||||
# D3D9 rejects Device::Reset if there's still any alive resources of specific types.
|
||||
# (State blocks, additional swapchains, D3DPOOL_DEFAULT resources)
|
||||
# Some games leak resources leading to a hang.
|
||||
#
|
||||
# Supported values:
|
||||
# - True/False
|
||||
|
||||
# d3d9.countLosableResources = True
|
||||
|
|
20
include/native/meson.build
Normal file
20
include/native/meson.build
Normal file
|
@ -0,0 +1,20 @@
|
|||
install_subdir(
|
||||
'directx',
|
||||
install_dir: get_option('includedir') / 'dxvk',
|
||||
strip_directory: true,
|
||||
exclude_files: '.git'
|
||||
)
|
||||
|
||||
install_subdir(
|
||||
'windows',
|
||||
install_dir: get_option('includedir') / 'dxvk',
|
||||
strip_directory: true,
|
||||
)
|
||||
|
||||
install_headers(
|
||||
'wsi/native_wsi.h',
|
||||
'wsi/native_sdl3.h',
|
||||
'wsi/native_sdl2.h',
|
||||
'wsi/native_glfw.h',
|
||||
subdir: 'dxvk/wsi',
|
||||
)
|
|
@ -48,7 +48,6 @@ typedef const void* LPCVOID;
|
|||
typedef size_t SIZE_T;
|
||||
|
||||
typedef int8_t INT8;
|
||||
|
||||
typedef uint8_t UINT8;
|
||||
typedef uint8_t BYTE;
|
||||
|
||||
|
@ -56,9 +55,13 @@ typedef int16_t SHORT;
|
|||
typedef uint16_t USHORT;
|
||||
|
||||
typedef int64_t LONGLONG;
|
||||
typedef int64_t INT64;
|
||||
|
||||
typedef uint64_t ULONGLONG;
|
||||
typedef uint64_t UINT64;
|
||||
|
||||
typedef intptr_t LONG_PTR;
|
||||
typedef uintptr_t ULONG_PTR;
|
||||
|
||||
typedef float FLOAT;
|
||||
|
||||
|
@ -284,6 +287,8 @@ typedef struct RGNDATA {
|
|||
#define DXGI_ERROR_NAME_ALREADY_EXISTS ((HRESULT)0x887A002C)
|
||||
#define DXGI_ERROR_SDK_COMPONENT_MISSING ((HRESULT)0x887A002D)
|
||||
|
||||
#define D3D11_ERROR_DEFERRED_CONTEXT_MAP_WITHOUT_INITIAL_DISCARD ((HRESULT)0x887C0004)
|
||||
|
||||
#define WINAPI
|
||||
#define WINUSERAPI
|
||||
|
||||
|
@ -330,12 +335,21 @@ typedef struct RGNDATA {
|
|||
#define DECLARE_INTERFACE(x) struct x
|
||||
#define DECLARE_INTERFACE_(x, y) struct x : public y
|
||||
#else
|
||||
#ifdef CONST_VTABLE
|
||||
#define DECLARE_INTERFACE(x) \
|
||||
typedef interface x { \
|
||||
const struct x##Vtbl *lpVtbl; \
|
||||
} x; \
|
||||
typedef const struct x##Vtbl x##Vtbl; \
|
||||
const struct x##Vtbl
|
||||
#else
|
||||
#define DECLARE_INTERFACE(x) \
|
||||
typedef interface x { \
|
||||
struct x##Vtbl *lpVtbl; \
|
||||
} x; \
|
||||
typedef struct x##Vtbl x##Vtbl; \
|
||||
struct x##Vtbl
|
||||
#endif // CONST_VTABLE
|
||||
#define DECLARE_INTERFACE_(x, y) DECLARE_INTERFACE(x)
|
||||
#endif // __cplusplus
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#include <windows.h>
|
||||
|
||||
#include <SDL2/SDL.h>
|
||||
#include <SDL.h>
|
||||
|
||||
namespace dxvk::wsi {
|
||||
|
||||
|
@ -22,4 +22,4 @@ namespace dxvk::wsi {
|
|||
return reinterpret_cast<HMONITOR>(static_cast<intptr_t>(displayId + 1));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
25
include/native/wsi/native_sdl3.h
Normal file
25
include/native/wsi/native_sdl3.h
Normal file
|
@ -0,0 +1,25 @@
|
|||
#include <windows.h>
|
||||
|
||||
#include <SDL3/SDL.h>
|
||||
|
||||
namespace dxvk::wsi {
|
||||
|
||||
inline SDL_Window* fromHwnd(HWND hWindow) {
|
||||
return reinterpret_cast<SDL_Window*>(hWindow);
|
||||
}
|
||||
|
||||
inline HWND toHwnd(SDL_Window* pWindow) {
|
||||
return reinterpret_cast<HWND>(pWindow);
|
||||
}
|
||||
|
||||
// Offset so null HMONITORs go to -1
|
||||
inline SDL_DisplayID fromHmonitor(HMONITOR hMonitor) {
|
||||
return SDL_DisplayID(reinterpret_cast<uintptr_t>(hMonitor));
|
||||
}
|
||||
|
||||
// Offset so -1 display id goes to 0 == NULL
|
||||
inline HMONITOR toHmonitor(SDL_DisplayID display) {
|
||||
return reinterpret_cast<HMONITOR>(uintptr_t(display));
|
||||
}
|
||||
|
||||
}
|
|
@ -2,6 +2,8 @@
|
|||
|
||||
#ifdef DXVK_WSI_WIN32
|
||||
#error You shouldnt be using this code path.
|
||||
#elif DXVK_WSI_SDL3
|
||||
#include "wsi/native_sdl3.h"
|
||||
#elif DXVK_WSI_SDL2
|
||||
#include "wsi/native_sdl2.h"
|
||||
#elif DXVK_WSI_GLFW
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit 0bcc624926a25a2a273d07877fd25a6ff5ba1cfb
|
||||
Subproject commit 8b246ff75c6615ba4532fe4fde20f1be090c3764
|
|
@ -1 +1 @@
|
|||
Subproject commit 85c2334e92e215cce34e8e0ed8b2dce4700f4a50
|
||||
Subproject commit 234c4b7370a8ea3239a214c9e871e4b17c89f4ab
|
146
meson.build
146
meson.build
|
@ -1,11 +1,13 @@
|
|||
project('dxvk', ['c', 'cpp'], version : 'v2.3', meson_version : '>= 0.49', default_options : [ 'cpp_std=c++17', 'warning_level=2' ])
|
||||
project('dxvk', ['c', 'cpp'], version : '2.5.3', meson_version : '>= 0.58', default_options : [ 'cpp_std=c++17', 'b_vscrt=static_from_buildtype', 'warning_level=2' ])
|
||||
|
||||
pkg = import('pkgconfig')
|
||||
cpu_family = target_machine.cpu_family()
|
||||
platform = target_machine.system()
|
||||
fs = import('fs')
|
||||
|
||||
cpp = meson.get_compiler('cpp')
|
||||
cc = meson.get_compiler('c')
|
||||
dxvk_is_msvc = cpp.get_id() == 'msvc'
|
||||
dxvk_is_msvc = cpp.get_argument_syntax() == 'msvc'
|
||||
|
||||
compiler_args = [
|
||||
'-msse',
|
||||
|
@ -16,6 +18,7 @@ compiler_args = [
|
|||
# gcc
|
||||
'-Wno-missing-field-initializers',
|
||||
'-Wno-unused-parameter',
|
||||
'-Wno-misleading-indentation',
|
||||
'-Wno-cast-function-type', # Needed for GetProcAddress.
|
||||
# clang
|
||||
'-Wno-unused-private-field',
|
||||
|
@ -33,42 +36,70 @@ if get_option('build_id')
|
|||
]
|
||||
endif
|
||||
|
||||
dxvk_include_dirs = [
|
||||
'./include',
|
||||
'./include/vulkan/include',
|
||||
'./include/spirv/include'
|
||||
]
|
||||
dxvk_include_dirs = ['./include']
|
||||
if fs.is_dir('./include/vulkan/include')
|
||||
dxvk_include_dirs += ['./include/vulkan/include']
|
||||
elif not cpp.check_header('vulkan/vulkan.h')
|
||||
error('Missing Vulkan-Headers')
|
||||
endif
|
||||
if fs.is_dir('./include/spirv/include')
|
||||
dxvk_include_dirs += ['./include/spirv/include']
|
||||
elif not cpp.check_header('spirv/unified1/spirv.hpp')
|
||||
error('Missing SPIRV-Headers')
|
||||
endif
|
||||
|
||||
proj_displayinfo = subproject('libdisplay-info')
|
||||
dep_displayinfo = proj_displayinfo.get_variable('di_dep')
|
||||
dep_displayinfo = dependency(
|
||||
'libdisplay-info',
|
||||
version: ['>= 0.0.0', '< 0.2.0'],
|
||||
fallback: ['libdisplay-info', 'di_dep'],
|
||||
default_options: ['default_library=static'],
|
||||
)
|
||||
|
||||
if platform == 'windows'
|
||||
dxvk_so_version = {'name_prefix': ''}
|
||||
|
||||
compiler_args += [
|
||||
'-DNOMINMAX',
|
||||
'-D_WIN32_WINNT=0xa00',
|
||||
]
|
||||
|
||||
link_args += [
|
||||
'-static',
|
||||
'-static-libgcc',
|
||||
'-static-libstdc++',
|
||||
# We need to set the section alignment for debug symbols to
|
||||
# work properly as well as avoiding a memcpy from the Wine loader.
|
||||
'-Wl,--file-alignment=4096',
|
||||
]
|
||||
|
||||
# Wine's built-in back traces only work with dwarf4 symbols
|
||||
if get_option('debug')
|
||||
compiler_args += [
|
||||
'-gdwarf-4',
|
||||
]
|
||||
endif
|
||||
|
||||
# Enable stdcall fixup on 32-bit
|
||||
if cpu_family == 'x86'
|
||||
if not dxvk_is_msvc
|
||||
link_args += [
|
||||
'-Wl,--enable-stdcall-fixup',
|
||||
'-Wl,--kill-at',
|
||||
'-static',
|
||||
'-static-libgcc',
|
||||
'-static-libstdc++',
|
||||
# We need to set the section alignment for debug symbols to
|
||||
# work properly as well as avoiding a memcpy from the Wine loader.
|
||||
'-Wl,--file-alignment=4096',
|
||||
]
|
||||
|
||||
# Wine's built-in back traces only work with dwarf4 symbols
|
||||
if get_option('debug')
|
||||
compiler_args += [
|
||||
'-gdwarf-4',
|
||||
]
|
||||
endif
|
||||
|
||||
if cpu_family == 'x86'
|
||||
# Enable stdcall fixup on 32-bit
|
||||
link_args += [
|
||||
'-Wl,--enable-stdcall-fixup',
|
||||
'-Wl,--kill-at',
|
||||
]
|
||||
# Fix stack alignment issues with mingw on 32-bit
|
||||
compiler_args += [
|
||||
'-mpreferred-stack-boundary=2'
|
||||
]
|
||||
endif
|
||||
else
|
||||
# setup file alignment + enable PDB output for MSVC builds
|
||||
# PDBs are useful for Windows consumers of DXVK
|
||||
compiler_args += [
|
||||
'/Z7'
|
||||
]
|
||||
link_args += [
|
||||
'/FILEALIGN:4096',
|
||||
'/DEBUG:FULL'
|
||||
]
|
||||
endif
|
||||
|
||||
|
@ -76,12 +107,6 @@ if platform == 'windows'
|
|||
lib_d3d11 = cpp.find_library('d3d11')
|
||||
lib_dxgi = cpp.find_library('dxgi')
|
||||
|
||||
if dxvk_is_msvc
|
||||
lib_d3dcompiler_47 = cpp.find_library('d3dcompiler')
|
||||
else
|
||||
lib_d3dcompiler_47 = cpp.find_library('d3dcompiler_47')
|
||||
endif
|
||||
|
||||
if dxvk_is_msvc
|
||||
res_ext = '.res'
|
||||
wrc = find_program('rc')
|
||||
|
@ -98,10 +123,21 @@ if platform == 'windows'
|
|||
)
|
||||
endif
|
||||
|
||||
dxvk_wsi = 'win32'
|
||||
dxvk_name_prefix = ''
|
||||
compiler_args += ['-DDXVK_WSI_WIN32']
|
||||
else
|
||||
dxvk_abi_version = '0'
|
||||
dxvk_version_raw = meson.project_version().strip('v').split('.')
|
||||
dxvk_version = [ dxvk_version_raw[0] ]
|
||||
foreach i : [ 1, 2 ]
|
||||
padded = dxvk_version_raw[i]
|
||||
if padded.to_int() < 10
|
||||
padded = '0' + padded
|
||||
endif
|
||||
dxvk_version += [ padded ]
|
||||
endforeach
|
||||
dxvk_so_version = {'version': dxvk_abi_version + '.' + dxvk_version[0] + dxvk_version[1] + dxvk_version[2]}
|
||||
|
||||
wrc = find_program('touch')
|
||||
wrc_generator = generator(wrc, output : [ '@BASENAME@_ignored.h' ], arguments : [ '@OUTPUT@' ] )
|
||||
|
||||
|
@ -111,17 +147,24 @@ else
|
|||
'./include/native/directx'
|
||||
]
|
||||
|
||||
dxvk_wsi = get_option('dxvk_native_wsi')
|
||||
|
||||
if dxvk_wsi == 'sdl2'
|
||||
lib_sdl2 = cpp.find_library('SDL2')
|
||||
lib_sdl3 = dependency('SDL3', required: false)
|
||||
lib_sdl2 = dependency('SDL2', required: false)
|
||||
lib_glfw = dependency('glfw', required: false)
|
||||
if lib_sdl3.found()
|
||||
compiler_args += ['-DDXVK_WSI_SDL3']
|
||||
endif
|
||||
if lib_sdl2.found()
|
||||
compiler_args += ['-DDXVK_WSI_SDL2']
|
||||
elif dxvk_wsi == 'glfw'
|
||||
lib_glfw = cpp.find_library('glfw')
|
||||
endif
|
||||
if lib_glfw.found()
|
||||
compiler_args += ['-DDXVK_WSI_GLFW']
|
||||
endif
|
||||
if (not lib_sdl3.found() and not lib_sdl2.found() and not lib_glfw.found())
|
||||
error('SDL3, SDL2, or GLFW are required to build dxvk-native')
|
||||
endif
|
||||
|
||||
dxvk_name_prefix = 'libdxvk_'
|
||||
dxvk_name_prefix = 'dxvk_'
|
||||
dxvk_pkg_prefix = 'dxvk-'
|
||||
|
||||
link_args += [
|
||||
'-static-libgcc',
|
||||
|
@ -137,13 +180,12 @@ add_project_link_arguments(cpp.get_supported_link_arguments(link_args), language
|
|||
add_project_link_arguments(cc.get_supported_link_arguments(link_args), language: 'c')
|
||||
|
||||
exe_ext = ''
|
||||
dll_ext = ''
|
||||
def_spec_ext = '.def'
|
||||
|
||||
glsl_compiler = find_program('glslang', 'glslangValidator')
|
||||
glsl_args = [
|
||||
'--quiet',
|
||||
'--target-env', 'vulkan1.2',
|
||||
'--target-env', 'vulkan1.3',
|
||||
'--vn', '@BASENAME@',
|
||||
'--depfile', '@DEPFILE@',
|
||||
'@INPUT@',
|
||||
|
@ -162,4 +204,18 @@ dxvk_version = vcs_tag(
|
|||
output: 'version.h',
|
||||
)
|
||||
|
||||
conf_data = configuration_data()
|
||||
conf_data.set('BUILD_COMPILER', cpp.get_id())
|
||||
conf_data.set('BUILD_COMPILER_VERSION', cpp.version())
|
||||
conf_data.set('BUILD_TARGET', cpu_family)
|
||||
dxvk_buildenv = configure_file(
|
||||
configuration : conf_data,
|
||||
input: 'buildenv.h.in',
|
||||
output: 'buildenv.h',
|
||||
)
|
||||
|
||||
if platform != 'windows'
|
||||
subdir('include/native')
|
||||
endif
|
||||
|
||||
subdir('src')
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
option('enable_dxgi', type : 'boolean', value : true, description: 'Build DXGI')
|
||||
option('enable_d3d8', type : 'boolean', value : true, description: 'Build D3D8')
|
||||
option('enable_d3d9', type : 'boolean', value : true, description: 'Build D3D9')
|
||||
option('enable_d3d10', type : 'boolean', value : true, description: 'Build D3D10')
|
||||
option('enable_d3d11', type : 'boolean', value : true, description: 'Build D3D11')
|
||||
|
|
|
@ -25,6 +25,8 @@ shift 2
|
|||
opt_nopackage=0
|
||||
opt_devbuild=0
|
||||
opt_buildid=false
|
||||
opt_64_only=0
|
||||
opt_32_only=0
|
||||
|
||||
CC=${CC:="gcc"}
|
||||
CXX=${CXX:="g++"}
|
||||
|
@ -41,6 +43,12 @@ while [ $# -gt 0 ]; do
|
|||
"--build-id")
|
||||
opt_buildid=true
|
||||
;;
|
||||
"--64-only")
|
||||
opt_64_only=1
|
||||
;;
|
||||
"--32-only")
|
||||
opt_32_only=1
|
||||
;;
|
||||
*)
|
||||
echo "Unrecognized option: $1" >&2
|
||||
exit 1
|
||||
|
@ -56,13 +64,14 @@ function build_arch {
|
|||
opt_strip=--strip
|
||||
fi
|
||||
|
||||
CC="$CC -m$1" CXX="$CXX -m$1" meson setup \
|
||||
--buildtype "release" \
|
||||
--prefix "$DXVK_BUILD_DIR/usr" \
|
||||
$opt_strip \
|
||||
--bindir "$2" \
|
||||
--libdir "$2" \
|
||||
-Dbuild_id=$opt_buildid \
|
||||
CC="$CC -m$1" CXX="$CXX -m$1" meson setup \
|
||||
--buildtype "release" \
|
||||
--prefix "$DXVK_BUILD_DIR/usr" \
|
||||
$opt_strip \
|
||||
--bindir "$2" \
|
||||
--libdir "$2" \
|
||||
-Dbuild_id=$opt_buildid \
|
||||
--force-fallback-for=libdisplay-info \
|
||||
"$DXVK_BUILD_DIR/build.$1"
|
||||
|
||||
cd "$DXVK_BUILD_DIR/build.$1"
|
||||
|
@ -80,8 +89,12 @@ function package {
|
|||
rm -R "dxvk-native-$DXVK_VERSION"
|
||||
}
|
||||
|
||||
build_arch 64 lib
|
||||
build_arch 32 lib32
|
||||
if [ $opt_32_only -eq 0 ]; then
|
||||
build_arch 64 lib
|
||||
fi
|
||||
if [ $opt_64_only -eq 0 ]; then
|
||||
build_arch 32 lib32
|
||||
fi
|
||||
|
||||
if [ $opt_nopackage -eq 0 ]; then
|
||||
package
|
||||
|
|
|
@ -25,6 +25,8 @@ shift 2
|
|||
opt_nopackage=0
|
||||
opt_devbuild=0
|
||||
opt_buildid=false
|
||||
opt_64_only=0
|
||||
opt_32_only=0
|
||||
|
||||
crossfile="build-win"
|
||||
|
||||
|
@ -40,6 +42,12 @@ while [ $# -gt 0 ]; do
|
|||
"--build-id")
|
||||
opt_buildid=true
|
||||
;;
|
||||
"--64-only")
|
||||
opt_64_only=1
|
||||
;;
|
||||
"--32-only")
|
||||
opt_32_only=1
|
||||
;;
|
||||
*)
|
||||
echo "Unrecognized option: $1" >&2
|
||||
exit 1
|
||||
|
@ -64,6 +72,7 @@ function build_arch {
|
|||
$opt_strip \
|
||||
--bindir "x$1" \
|
||||
--libdir "x$1" \
|
||||
-Db_ndebug=if-release \
|
||||
-Dbuild_id=$opt_buildid \
|
||||
"$DXVK_BUILD_DIR/build.$1"
|
||||
|
||||
|
@ -83,8 +92,12 @@ function package {
|
|||
rm -R "dxvk-$DXVK_VERSION"
|
||||
}
|
||||
|
||||
build_arch 64
|
||||
build_arch 32
|
||||
if [ $opt_32_only -eq 0 ]; then
|
||||
build_arch 64
|
||||
fi
|
||||
if [ $opt_64_only -eq 0 ]; then
|
||||
build_arch 32
|
||||
fi
|
||||
|
||||
if [ $opt_nopackage -eq 0 ]; then
|
||||
package
|
||||
|
|
|
@ -15,16 +15,23 @@ else
|
|||
d3d10_d3d11_dep = d3d11_dep
|
||||
endif
|
||||
|
||||
d3d10_core_dll = shared_library('d3d10core'+dll_ext, d3d10_core_src, d3d10_core_res,
|
||||
name_prefix : dxvk_name_prefix,
|
||||
d3d10_core_dll = shared_library(dxvk_name_prefix+'d3d10core', d3d10_core_src, d3d10_core_res,
|
||||
dependencies : [ d3d10_d3d11_dep ],
|
||||
include_directories : dxvk_include_path,
|
||||
install : true,
|
||||
vs_module_defs : 'd3d10core'+def_spec_ext,
|
||||
link_args : d3d10_core_ld_args,
|
||||
link_depends : [ d3d10_core_link_depends ],
|
||||
kwargs : dxvk_so_version,
|
||||
)
|
||||
|
||||
d3d10_core_dep = declare_dependency(
|
||||
link_with : [ d3d10_core_dll ],
|
||||
)
|
||||
|
||||
if platform != 'windows'
|
||||
pkg.generate(d3d10_core_dll,
|
||||
filebase: dxvk_pkg_prefix + 'd3d10core',
|
||||
subdirs: 'dxvk',
|
||||
)
|
||||
endif
|
||||
|
|
|
@ -37,8 +37,8 @@ namespace dxvk {
|
|||
D3D11UserDefinedAnnotation<ContextType>::D3D11UserDefinedAnnotation(
|
||||
ContextType* container,
|
||||
const Rc<DxvkDevice>& dxvkDevice)
|
||||
: m_container(container), m_eventDepth(0),
|
||||
m_annotationsEnabled(dxvkDevice->instance()->extensions().extDebugUtils) {
|
||||
: m_container(container),
|
||||
m_annotationsEnabled(dxvkDevice->debugFlags().test(DxvkDebugFlag::Markers)) {
|
||||
if (!IsDeferred && m_annotationsEnabled)
|
||||
RegisterUserDefinedAnnotation<true>(this);
|
||||
}
|
||||
|
@ -75,19 +75,16 @@ namespace dxvk {
|
|||
INT STDMETHODCALLTYPE D3D11UserDefinedAnnotation<ContextType>::BeginEvent(
|
||||
D3DCOLOR Color,
|
||||
LPCWSTR Name) {
|
||||
if (!m_annotationsEnabled)
|
||||
if (!m_annotationsEnabled || !Name)
|
||||
return -1;
|
||||
|
||||
D3D10DeviceLock lock = m_container->LockContext();
|
||||
|
||||
m_container->EmitCs([color = Color, labelName = dxvk::str::fromws(Name)](DxvkContext *ctx) {
|
||||
VkDebugUtilsLabelEXT label;
|
||||
label.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT;
|
||||
label.pNext = nullptr;
|
||||
label.pLabelName = labelName.c_str();
|
||||
DecodeD3DCOLOR(color, label.color);
|
||||
|
||||
ctx->beginDebugLabel(&label);
|
||||
m_container->EmitCs([
|
||||
cColor = Color,
|
||||
cLabel = dxvk::str::fromws(Name)
|
||||
] (DxvkContext* ctx) {
|
||||
ctx->beginDebugLabel(vk::makeLabel(cColor, cLabel.c_str()));
|
||||
});
|
||||
|
||||
return m_eventDepth++;
|
||||
|
@ -101,11 +98,14 @@ namespace dxvk {
|
|||
|
||||
D3D10DeviceLock lock = m_container->LockContext();
|
||||
|
||||
m_container->EmitCs([](DxvkContext *ctx) {
|
||||
if (!m_eventDepth)
|
||||
return 0;
|
||||
|
||||
m_container->EmitCs([] (DxvkContext* ctx) {
|
||||
ctx->endDebugLabel();
|
||||
});
|
||||
|
||||
return m_eventDepth--;
|
||||
return --m_eventDepth;
|
||||
}
|
||||
|
||||
|
||||
|
@ -113,19 +113,16 @@ namespace dxvk {
|
|||
void STDMETHODCALLTYPE D3D11UserDefinedAnnotation<ContextType>::SetMarker(
|
||||
D3DCOLOR Color,
|
||||
LPCWSTR Name) {
|
||||
if (!m_annotationsEnabled)
|
||||
if (!m_annotationsEnabled || !Name)
|
||||
return;
|
||||
|
||||
D3D10DeviceLock lock = m_container->LockContext();
|
||||
|
||||
m_container->EmitCs([color = Color, labelName = dxvk::str::fromws(Name)](DxvkContext *ctx) {
|
||||
VkDebugUtilsLabelEXT label;
|
||||
label.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT;
|
||||
label.pNext = nullptr;
|
||||
label.pLabelName = labelName.c_str();
|
||||
DecodeD3DCOLOR(color, label.color);
|
||||
|
||||
ctx->insertDebugLabel(&label);
|
||||
m_container->EmitCs([
|
||||
cColor = Color,
|
||||
cLabel = dxvk::str::fromws(Name)
|
||||
] (DxvkContext* ctx) {
|
||||
ctx->insertDebugLabel(vk::makeLabel(cColor, cLabel.c_str()));
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -48,9 +48,10 @@ namespace dxvk {
|
|||
|
||||
private:
|
||||
|
||||
ContextType* m_container;
|
||||
int32_t m_eventDepth;
|
||||
bool m_annotationsEnabled;
|
||||
ContextType* m_container = nullptr;
|
||||
int32_t m_eventDepth = 0u;
|
||||
bool m_annotationsEnabled = false;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -1,9 +1,8 @@
|
|||
#include "d3d11_buffer.h"
|
||||
#include "d3d11_context.h"
|
||||
#include "d3d11_context_imm.h"
|
||||
#include "d3d11_device.h"
|
||||
|
||||
#include "../dxvk/dxvk_data.h"
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
D3D11Buffer::D3D11Buffer(
|
||||
|
@ -12,7 +11,7 @@ namespace dxvk {
|
|||
const D3D11_ON_12_RESOURCE_INFO* p11on12Info)
|
||||
: D3D11DeviceChild<ID3D11Buffer>(pDevice),
|
||||
m_desc (*pDesc),
|
||||
m_resource (this),
|
||||
m_resource (this, pDevice),
|
||||
m_d3d10 (this) {
|
||||
DxvkBufferCreateInfo info;
|
||||
info.flags = 0;
|
||||
|
@ -84,6 +83,10 @@ namespace dxvk {
|
|||
info.access |= VK_ACCESS_HOST_WRITE_BIT;
|
||||
}
|
||||
|
||||
// Always enable BDA usage if available so that CUDA interop can work
|
||||
if (m_parent->GetDXVKDevice()->features().vk12.bufferDeviceAddress)
|
||||
info.usage |= VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT;
|
||||
|
||||
if (p11on12Info) {
|
||||
m_11on12 = *p11on12Info;
|
||||
|
||||
|
@ -95,21 +98,24 @@ namespace dxvk {
|
|||
m_11on12.Resource->Map(0, nullptr, &importInfo.mapPtr);
|
||||
|
||||
m_buffer = m_parent->GetDXVKDevice()->importBuffer(info, importInfo, GetMemoryFlags());
|
||||
m_mapped = m_buffer->getSliceHandle();
|
||||
|
||||
m_mapMode = DetermineMapMode();
|
||||
m_cookie = m_buffer->cookie();
|
||||
m_mapPtr = m_buffer->mapPtr(0);
|
||||
m_mapMode = DetermineMapMode(m_buffer->memFlags());
|
||||
} else if (!(pDesc->MiscFlags & D3D11_RESOURCE_MISC_TILE_POOL)) {
|
||||
VkMemoryPropertyFlags memoryFlags = GetMemoryFlags();
|
||||
m_mapMode = DetermineMapMode(memoryFlags);
|
||||
|
||||
// Create the buffer and set the entire buffer slice as mapped,
|
||||
// so that we only have to update it when invalidating the buffer
|
||||
m_buffer = m_parent->GetDXVKDevice()->createBuffer(info, GetMemoryFlags());
|
||||
m_mapped = m_buffer->getSliceHandle();
|
||||
|
||||
m_mapMode = DetermineMapMode();
|
||||
m_buffer = m_parent->GetDXVKDevice()->createBuffer(info, memoryFlags);
|
||||
m_cookie = m_buffer->cookie();
|
||||
m_mapPtr = m_buffer->mapPtr(0);
|
||||
} else {
|
||||
m_sparseAllocator = m_parent->GetDXVKDevice()->createSparsePageAllocator();
|
||||
m_sparseAllocator->setCapacity(info.size / SparseMemoryPageSize);
|
||||
|
||||
m_mapped = DxvkBufferSliceHandle();
|
||||
m_cookie = 0u;
|
||||
m_mapPtr = nullptr;
|
||||
m_mapMode = D3D11_COMMON_BUFFER_MAP_MODE_NONE;
|
||||
}
|
||||
|
||||
|
@ -206,6 +212,18 @@ namespace dxvk {
|
|||
}
|
||||
|
||||
|
||||
void D3D11Buffer::SetDebugName(const char* pName) {
|
||||
if (m_buffer) {
|
||||
m_parent->GetContext()->InjectCs(DxvkCsQueue::HighPriority, [
|
||||
cBuffer = m_buffer,
|
||||
cName = std::string(pName ? pName : "")
|
||||
] (DxvkContext* ctx) {
|
||||
ctx->setDebugName(cBuffer, cName.c_str());
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
HRESULT D3D11Buffer::NormalizeBufferProperties(D3D11_BUFFER_DESC* pDesc) {
|
||||
// Zero-sized buffers are illegal
|
||||
if (!pDesc->ByteWidth && !(pDesc->MiscFlags & D3D11_RESOURCE_MISC_TILE_POOL))
|
||||
|
@ -365,12 +383,14 @@ namespace dxvk {
|
|||
| VK_ACCESS_INDIRECT_COMMAND_READ_BIT
|
||||
| VK_ACCESS_TRANSFORM_FEEDBACK_COUNTER_READ_BIT_EXT
|
||||
| VK_ACCESS_TRANSFORM_FEEDBACK_COUNTER_WRITE_BIT_EXT;
|
||||
info.debugName = "SO counter";
|
||||
|
||||
return device->createBuffer(info, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
|
||||
}
|
||||
|
||||
|
||||
D3D11_COMMON_BUFFER_MAP_MODE D3D11Buffer::DetermineMapMode() {
|
||||
return (m_buffer->memFlags() & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT)
|
||||
D3D11_COMMON_BUFFER_MAP_MODE D3D11Buffer::DetermineMapMode(VkMemoryPropertyFlags MemFlags) {
|
||||
return (MemFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT)
|
||||
? D3D11_COMMON_BUFFER_MAP_MODE_DIRECT
|
||||
: D3D11_COMMON_BUFFER_MAP_MODE_NONE;
|
||||
}
|
||||
|
|
|
@ -61,6 +61,8 @@ namespace dxvk {
|
|||
void STDMETHODCALLTYPE GetDesc(
|
||||
D3D11_BUFFER_DESC *pDesc) final;
|
||||
|
||||
void STDMETHODCALLTYPE SetDebugName(const char* pName) final;
|
||||
|
||||
bool CheckViewCompatibility(
|
||||
UINT BindFlags,
|
||||
DXGI_FORMAT Format) const;
|
||||
|
@ -77,6 +79,10 @@ namespace dxvk {
|
|||
return m_mapMode;
|
||||
}
|
||||
|
||||
uint64_t GetCookie() const {
|
||||
return m_cookie;
|
||||
}
|
||||
|
||||
Rc<DxvkBuffer> GetBuffer() const {
|
||||
return m_buffer;
|
||||
}
|
||||
|
@ -113,17 +119,18 @@ namespace dxvk {
|
|||
: DxvkBufferSlice();
|
||||
}
|
||||
|
||||
DxvkBufferSliceHandle AllocSlice() {
|
||||
return m_buffer->allocSlice();
|
||||
Rc<DxvkResourceAllocation> AllocSlice(DxvkLocalAllocationCache* cache) {
|
||||
return m_buffer->allocateStorage(cache);
|
||||
}
|
||||
|
||||
DxvkBufferSliceHandle DiscardSlice() {
|
||||
m_mapped = m_buffer->allocSlice();
|
||||
return m_mapped;
|
||||
Rc<DxvkResourceAllocation> DiscardSlice(DxvkLocalAllocationCache* cache) {
|
||||
auto allocation = m_buffer->allocateStorage(cache);
|
||||
m_mapPtr = allocation->mapPtr();
|
||||
return allocation;
|
||||
}
|
||||
|
||||
DxvkBufferSliceHandle GetMappedSlice() const {
|
||||
return m_mapped;
|
||||
void* GetMapPtr() const {
|
||||
return m_mapPtr;
|
||||
}
|
||||
|
||||
D3D10Buffer* GetD3D10Iface() {
|
||||
|
@ -182,11 +189,14 @@ namespace dxvk {
|
|||
D3D11_COMMON_BUFFER_MAP_MODE m_mapMode;
|
||||
|
||||
Rc<DxvkBuffer> m_buffer;
|
||||
uint64_t m_cookie = 0u;
|
||||
|
||||
Rc<DxvkBuffer> m_soCounter;
|
||||
Rc<DxvkSparsePageAllocator> m_sparseAllocator;
|
||||
DxvkBufferSliceHandle m_mapped;
|
||||
uint64_t m_seq = 0ull;
|
||||
|
||||
void* m_mapPtr = nullptr;
|
||||
|
||||
D3D11DXGIResource m_resource;
|
||||
D3D10Buffer m_d3d10;
|
||||
|
||||
|
@ -198,7 +208,8 @@ namespace dxvk {
|
|||
|
||||
Rc<DxvkBuffer> CreateSoCounterBuffer();
|
||||
|
||||
D3D11_COMMON_BUFFER_MAP_MODE DetermineMapMode();
|
||||
static D3D11_COMMON_BUFFER_MAP_MODE DetermineMapMode(
|
||||
VkMemoryPropertyFlags MemFlags);
|
||||
|
||||
};
|
||||
|
||||
|
|
|
@ -10,20 +10,12 @@ namespace dxvk {
|
|||
* Used to identify the type of command
|
||||
* data most recently added to a CS chunk.
|
||||
*/
|
||||
enum class D3D11CmdType {
|
||||
enum class D3D11CmdType : uint32_t {
|
||||
None,
|
||||
DrawIndirect,
|
||||
DrawIndirectIndexed,
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* \brief Command data header
|
||||
*
|
||||
* Stores the command type. All command
|
||||
* data structs must inherit this struct.
|
||||
*/
|
||||
struct D3D11CmdData {
|
||||
D3D11CmdType type;
|
||||
Draw,
|
||||
DrawIndexed,
|
||||
};
|
||||
|
||||
|
||||
|
@ -34,10 +26,10 @@ namespace dxvk {
|
|||
* the first draw, as well as the number of
|
||||
* draws to execute.
|
||||
*/
|
||||
struct D3D11CmdDrawIndirectData : public D3D11CmdData {
|
||||
struct D3D11CmdDrawIndirectData {
|
||||
uint32_t offset;
|
||||
uint32_t count;
|
||||
uint32_t stride;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -74,8 +74,6 @@ namespace dxvk {
|
|||
m_resources.push_back(std::move(entry));
|
||||
}
|
||||
|
||||
pCommandList->MarkSubmitted();
|
||||
|
||||
// Return ID of the last chunk added. The command list
|
||||
// added can never be empty, so do not handle zero.
|
||||
return m_chunks.size() - 1;
|
||||
|
@ -102,8 +100,6 @@ namespace dxvk {
|
|||
while (j < m_resources.size() && m_resources[j].chunkId == i)
|
||||
TrackResourceSequenceNumber(m_resources[j++].ref, seq);
|
||||
}
|
||||
|
||||
MarkSubmitted();
|
||||
}
|
||||
|
||||
|
||||
|
@ -150,15 +146,5 @@ namespace dxvk {
|
|||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void D3D11CommandList::MarkSubmitted() {
|
||||
if (m_submitted.exchange(true) && !m_warned.exchange(true)
|
||||
&& m_parent->GetOptions()->dcSingleUseMode) {
|
||||
Logger::warn(
|
||||
"D3D11: Command list submitted multiple times,\n"
|
||||
" but d3d11.dcSingleUseMode is enabled");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -55,14 +55,9 @@ namespace dxvk {
|
|||
std::vector<Com<D3D11Query, false>> m_queries;
|
||||
std::vector<TrackedResource> m_resources;
|
||||
|
||||
std::atomic<bool> m_submitted = { false };
|
||||
std::atomic<bool> m_warned = { false };
|
||||
|
||||
void TrackResourceSequenceNumber(
|
||||
const D3D11ResourceRef& Resource,
|
||||
uint64_t Seq);
|
||||
|
||||
void MarkSubmitted();
|
||||
|
||||
};
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -72,7 +72,14 @@ namespace dxvk {
|
|||
template<typename T> friend class D3D11DeviceContextExt;
|
||||
template<typename T> friend class D3D11UserDefinedAnnotation;
|
||||
|
||||
constexpr static VkDeviceSize StagingBufferSize = 4ull << 20;
|
||||
// Use a local staging buffer to handle tiny uploads, most
|
||||
// of the time we're fine with hitting the global allocator
|
||||
constexpr static VkDeviceSize StagingBufferSize = 256ull << 10;
|
||||
|
||||
protected:
|
||||
// Compile-time debug flag to force lazy binding on (True) or off (False)
|
||||
constexpr static Tristate DebugLazyBinding = Tristate::Auto;
|
||||
|
||||
public:
|
||||
|
||||
D3D11CommonContext(
|
||||
|
@ -102,6 +109,11 @@ namespace dxvk {
|
|||
const D3D11_RECT* pRects,
|
||||
UINT NumRects);
|
||||
|
||||
void STDMETHODCALLTYPE DiscardViewBase(
|
||||
ID3D11View* pResourceView,
|
||||
const D3D11_RECT* pRects,
|
||||
UINT NumRects);
|
||||
|
||||
void STDMETHODCALLTYPE CopySubresourceRegion(
|
||||
ID3D11Resource* pDstResource,
|
||||
UINT DstSubresource,
|
||||
|
@ -123,6 +135,17 @@ namespace dxvk {
|
|||
const D3D11_BOX* pSrcBox,
|
||||
UINT CopyFlags);
|
||||
|
||||
void STDMETHODCALLTYPE CopySubresourceRegionBase(
|
||||
ID3D11Resource* pDstResource,
|
||||
UINT DstSubresource,
|
||||
UINT DstX,
|
||||
UINT DstY,
|
||||
UINT DstZ,
|
||||
ID3D11Resource* pSrcResource,
|
||||
UINT SrcSubresource,
|
||||
const D3D11_BOX* pSrcBox,
|
||||
UINT CopyFlags);
|
||||
|
||||
void STDMETHODCALLTYPE CopyResource(
|
||||
ID3D11Resource* pDstResource,
|
||||
ID3D11Resource* pSrcResource);
|
||||
|
@ -769,19 +792,44 @@ namespace dxvk {
|
|||
UINT m_flags;
|
||||
|
||||
DxvkStagingBuffer m_staging;
|
||||
Rc<DxvkDataBuffer> m_updateBuffer;
|
||||
|
||||
D3D11CmdType m_csDataType = D3D11CmdType::None;
|
||||
|
||||
DxvkCsChunkFlags m_csFlags;
|
||||
DxvkCsChunkRef m_csChunk;
|
||||
D3D11CmdData* m_cmdData;
|
||||
DxvkCsDataBlock* m_csData = nullptr;
|
||||
|
||||
DxvkLocalAllocationCache m_allocationCache;
|
||||
|
||||
DxvkCsChunkRef AllocCsChunk();
|
||||
|
||||
DxvkDataSlice AllocUpdateBufferSlice(size_t Size);
|
||||
|
||||
DxvkBufferSlice AllocStagingBuffer(
|
||||
VkDeviceSize Size);
|
||||
|
||||
void ApplyDirtyConstantBuffers(
|
||||
DxbcProgramType Stage,
|
||||
const DxbcBindingMask& BoundMask,
|
||||
DxbcBindingMask& DirtyMask);
|
||||
|
||||
void ApplyDirtySamplers(
|
||||
DxbcProgramType Stage,
|
||||
const DxbcBindingMask& BoundMask,
|
||||
DxbcBindingMask& DirtyMask);
|
||||
|
||||
void ApplyDirtyShaderResources(
|
||||
DxbcProgramType Stage,
|
||||
const DxbcBindingMask& BoundMask,
|
||||
DxbcBindingMask& DirtyMask);
|
||||
|
||||
void ApplyDirtyUnorderedAccessViews(
|
||||
DxbcProgramType Stage,
|
||||
const DxbcBindingMask& BoundMask,
|
||||
DxbcBindingMask& DirtyMask);
|
||||
|
||||
void ApplyDirtyGraphicsBindings();
|
||||
|
||||
void ApplyDirtyComputeBindings();
|
||||
|
||||
void ApplyInputLayout();
|
||||
|
||||
void ApplyPrimitiveTopology();
|
||||
|
@ -800,6 +848,12 @@ namespace dxvk {
|
|||
|
||||
void ApplyViewportState();
|
||||
|
||||
void BatchDraw(
|
||||
const VkDrawIndirectCommand& draw);
|
||||
|
||||
void BatchDrawIndexed(
|
||||
const VkDrawIndexedIndirectCommand& draw);
|
||||
|
||||
template<DxbcProgramType ShaderStage>
|
||||
void BindShader(
|
||||
const D3D11CommonShader* pShaderModule);
|
||||
|
@ -837,35 +891,33 @@ namespace dxvk {
|
|||
D3D11Buffer* pBuffer,
|
||||
UINT Offset);
|
||||
|
||||
template<DxbcProgramType ShaderStage>
|
||||
void BindConstantBuffer(
|
||||
DxbcProgramType ShaderStage,
|
||||
UINT Slot,
|
||||
D3D11Buffer* pBuffer,
|
||||
UINT Offset,
|
||||
UINT Length);
|
||||
|
||||
template<DxbcProgramType ShaderStage>
|
||||
void BindConstantBufferRange(
|
||||
DxbcProgramType ShaderStage,
|
||||
UINT Slot,
|
||||
UINT Offset,
|
||||
UINT Length);
|
||||
|
||||
template<DxbcProgramType ShaderStage>
|
||||
void BindSampler(
|
||||
DxbcProgramType ShaderStage,
|
||||
UINT Slot,
|
||||
D3D11SamplerState* pSampler);
|
||||
|
||||
template<DxbcProgramType ShaderStage>
|
||||
void BindShaderResource(
|
||||
DxbcProgramType ShaderStage,
|
||||
UINT Slot,
|
||||
D3D11ShaderResourceView* pResource);
|
||||
|
||||
template<DxbcProgramType ShaderStage>
|
||||
void BindUnorderedAccessView(
|
||||
UINT UavSlot,
|
||||
D3D11UnorderedAccessView* pUav,
|
||||
UINT CtrSlot,
|
||||
UINT Counter);
|
||||
DxbcProgramType ShaderStage,
|
||||
UINT Slot,
|
||||
D3D11UnorderedAccessView* pUav);
|
||||
|
||||
VkClearValue ConvertColorValue(
|
||||
const FLOAT Color[4],
|
||||
|
@ -894,6 +946,36 @@ namespace dxvk {
|
|||
DxvkBufferSlice BufferSlice,
|
||||
UINT Flags);
|
||||
|
||||
template<typename T>
|
||||
bool DirtyBindingGeneric(
|
||||
DxbcProgramType ShaderStage,
|
||||
T BoundMask,
|
||||
T& DirtyMask,
|
||||
T DirtyBit,
|
||||
bool IsNull);
|
||||
|
||||
bool DirtyConstantBuffer(
|
||||
DxbcProgramType ShaderStage,
|
||||
uint32_t Slot,
|
||||
bool IsNull);
|
||||
|
||||
bool DirtySampler(
|
||||
DxbcProgramType ShaderStage,
|
||||
uint32_t Slot,
|
||||
bool IsNull);
|
||||
|
||||
bool DirtyShaderResource(
|
||||
DxbcProgramType ShaderStage,
|
||||
uint32_t Slot,
|
||||
bool IsNull);
|
||||
|
||||
bool DirtyComputeUnorderedAccessView(
|
||||
uint32_t Slot,
|
||||
bool IsNull);
|
||||
|
||||
bool DirtyGraphicsUnorderedAccessView(
|
||||
uint32_t Slot);
|
||||
|
||||
void DiscardBuffer(
|
||||
ID3D11Resource* pResource);
|
||||
|
||||
|
@ -926,10 +1008,16 @@ namespace dxvk {
|
|||
|
||||
D3D11MaxUsedBindings GetMaxUsedBindings();
|
||||
|
||||
bool HasDirtyComputeBindings();
|
||||
|
||||
bool HasDirtyGraphicsBindings();
|
||||
|
||||
void ResetCommandListState();
|
||||
|
||||
void ResetContextState();
|
||||
|
||||
void ResetDirtyTracking();
|
||||
|
||||
void ResetStagingBuffer();
|
||||
|
||||
template<DxbcProgramType ShaderStage, typename T>
|
||||
|
@ -952,18 +1040,18 @@ namespace dxvk {
|
|||
|
||||
void RestoreCommandListState();
|
||||
|
||||
template<DxbcProgramType Stage>
|
||||
void RestoreConstantBuffers();
|
||||
|
||||
template<DxbcProgramType Stage>
|
||||
void RestoreSamplers();
|
||||
|
||||
template<DxbcProgramType Stage>
|
||||
void RestoreShaderResources();
|
||||
|
||||
template<DxbcProgramType Stage>
|
||||
void RestoreUnorderedAccessViews();
|
||||
void RestoreConstantBuffers(
|
||||
DxbcProgramType Stage);
|
||||
|
||||
void RestoreSamplers(
|
||||
DxbcProgramType Stage);
|
||||
|
||||
void RestoreShaderResources(
|
||||
DxbcProgramType Stage);
|
||||
|
||||
void RestoreUnorderedAccessViews(
|
||||
DxbcProgramType Stage);
|
||||
|
||||
template<DxbcProgramType ShaderStage>
|
||||
void SetConstantBuffers(
|
||||
UINT StartSlot,
|
||||
|
@ -1046,6 +1134,10 @@ namespace dxvk {
|
|||
UINT SrcDepthPitch,
|
||||
UINT CopyFlags);
|
||||
|
||||
void UpdateUnorderedAccessViewCounter(
|
||||
D3D11UnorderedAccessView* pUav,
|
||||
uint32_t CounterValue);
|
||||
|
||||
bool ValidateRenderTargets(
|
||||
UINT NumViews,
|
||||
ID3D11RenderTargetView* const* ppRenderTargetViews,
|
||||
|
@ -1066,48 +1158,49 @@ namespace dxvk {
|
|||
DxvkMultisampleState* pMsState,
|
||||
UINT SampleMask);
|
||||
|
||||
template<bool AllowFlush = !IsDeferred, typename Cmd>
|
||||
template<bool AllowFlush = true, typename Cmd>
|
||||
void EmitCs(Cmd&& command) {
|
||||
m_cmdData = nullptr;
|
||||
if (unlikely(m_csDataType != D3D11CmdType::None)) {
|
||||
m_csData = nullptr;
|
||||
m_csDataType = D3D11CmdType::None;
|
||||
}
|
||||
|
||||
if (unlikely(!m_csChunk->push(command))) {
|
||||
GetTypedContext()->EmitCsChunk(std::move(m_csChunk));
|
||||
m_csChunk = AllocCsChunk();
|
||||
|
||||
if constexpr (AllowFlush)
|
||||
if constexpr (!IsDeferred && AllowFlush)
|
||||
GetTypedContext()->ConsiderFlush(GpuFlushType::ImplicitWeakHint);
|
||||
|
||||
m_csChunk->push(command);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename M, bool AllowFlush = !IsDeferred, typename Cmd, typename... Args>
|
||||
M* EmitCsCmd(Cmd&& command, Args&&... args) {
|
||||
M* data = m_csChunk->pushCmd<M, Cmd, Args...>(
|
||||
command, std::forward<Args>(args)...);
|
||||
template<typename M, bool AllowFlush = true, typename Cmd>
|
||||
void EmitCsCmd(D3D11CmdType type, size_t count, Cmd&& command) {
|
||||
m_csDataType = type;
|
||||
m_csData = m_csChunk->pushCmd<M, Cmd>(command, count);
|
||||
|
||||
if (unlikely(!data)) {
|
||||
if (unlikely(!m_csData)) {
|
||||
GetTypedContext()->EmitCsChunk(std::move(m_csChunk));
|
||||
m_csChunk = AllocCsChunk();
|
||||
|
||||
if constexpr (AllowFlush)
|
||||
if constexpr (!IsDeferred && AllowFlush)
|
||||
GetTypedContext()->ConsiderFlush(GpuFlushType::ImplicitWeakHint);
|
||||
|
||||
// We must record this command after the potential
|
||||
// flush since the caller may still access the data
|
||||
data = m_csChunk->pushCmd<M, Cmd, Args...>(
|
||||
command, std::forward<Args>(args)...);
|
||||
m_csData = m_csChunk->pushCmd<M, Cmd>(command, count);
|
||||
}
|
||||
|
||||
m_cmdData = data;
|
||||
return data;
|
||||
}
|
||||
|
||||
void FlushCsChunk() {
|
||||
if (likely(!m_csChunk->empty())) {
|
||||
m_csData = nullptr;
|
||||
m_csDataType = D3D11CmdType::None;
|
||||
|
||||
GetTypedContext()->EmitCsChunk(std::move(m_csChunk));
|
||||
m_csChunk = AllocCsChunk();
|
||||
m_cmdData = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1130,7 +1223,7 @@ namespace dxvk {
|
|||
if (likely(pBuffer != nullptr))
|
||||
bufferSize = static_cast<D3D11Buffer*>(pBuffer)->Desc()->ByteWidth;
|
||||
|
||||
return bufferSize >= Offset + Size;
|
||||
return uint64_t(bufferSize) >= uint64_t(Offset) + uint64_t(Size);
|
||||
}
|
||||
|
||||
private:
|
||||
|
|
|
@ -7,7 +7,7 @@ namespace dxvk {
|
|||
D3D11Device* pParent,
|
||||
const Rc<DxvkDevice>& Device,
|
||||
UINT ContextFlags)
|
||||
: D3D11CommonContext<D3D11DeferredContext>(pParent, Device, ContextFlags, GetCsChunkFlags(pParent)),
|
||||
: D3D11CommonContext<D3D11DeferredContext>(pParent, Device, ContextFlags, 0u),
|
||||
m_commandList (CreateCommandList()) {
|
||||
ResetContextState();
|
||||
}
|
||||
|
@ -206,39 +206,37 @@ namespace dxvk {
|
|||
if (unlikely(!pResource || !pMappedResource))
|
||||
return E_INVALIDARG;
|
||||
|
||||
if (MapType == D3D11_MAP_WRITE_DISCARD) {
|
||||
if (likely(MapType == D3D11_MAP_WRITE_DISCARD)) {
|
||||
D3D11_RESOURCE_DIMENSION resourceDim;
|
||||
pResource->GetType(&resourceDim);
|
||||
|
||||
D3D11_MAPPED_SUBRESOURCE mapInfo;
|
||||
HRESULT status = resourceDim == D3D11_RESOURCE_DIMENSION_BUFFER
|
||||
? MapBuffer(pResource, &mapInfo)
|
||||
: MapImage (pResource, Subresource, &mapInfo);
|
||||
|
||||
if (unlikely(FAILED(status))) {
|
||||
*pMappedResource = D3D11_MAPPED_SUBRESOURCE();
|
||||
return status;
|
||||
}
|
||||
|
||||
AddMapEntry(pResource, Subresource, resourceDim, mapInfo);
|
||||
*pMappedResource = mapInfo;
|
||||
return S_OK;
|
||||
} else if (MapType == D3D11_MAP_WRITE_NO_OVERWRITE) {
|
||||
return likely(resourceDim == D3D11_RESOURCE_DIMENSION_BUFFER)
|
||||
? MapBuffer(pResource, pMappedResource)
|
||||
: MapImage(pResource, Subresource, pMappedResource);
|
||||
} else if (likely(MapType == D3D11_MAP_WRITE_NO_OVERWRITE)) {
|
||||
// The resource must be mapped with D3D11_MAP_WRITE_DISCARD
|
||||
// before it can be mapped with D3D11_MAP_WRITE_NO_OVERWRITE.
|
||||
auto entry = FindMapEntry(pResource, Subresource);
|
||||
|
||||
if (unlikely(!entry)) {
|
||||
*pMappedResource = D3D11_MAPPED_SUBRESOURCE();
|
||||
D3D11_RESOURCE_DIMENSION resourceDim;
|
||||
pResource->GetType(&resourceDim);
|
||||
|
||||
if (likely(resourceDim == D3D11_RESOURCE_DIMENSION_BUFFER)) {
|
||||
D3D11_MAPPED_SUBRESOURCE sr = FindMapEntry(static_cast<D3D11Buffer*>(pResource)->GetCookie());
|
||||
pMappedResource->pData = sr.pData;
|
||||
|
||||
if (unlikely(!sr.pData))
|
||||
return D3D11_ERROR_DEFERRED_CONTEXT_MAP_WITHOUT_INITIAL_DISCARD;
|
||||
|
||||
pMappedResource->RowPitch = sr.RowPitch;
|
||||
pMappedResource->DepthPitch = sr.DepthPitch;
|
||||
return S_OK;
|
||||
} else {
|
||||
// Images cannot be mapped with NO_OVERWRITE
|
||||
pMappedResource->pData = nullptr;
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
|
||||
// Return same memory region as earlier
|
||||
*pMappedResource = entry->MapInfo;
|
||||
return S_OK;
|
||||
} else {
|
||||
// Not allowed on deferred contexts
|
||||
*pMappedResource = D3D11_MAPPED_SUBRESOURCE();
|
||||
pMappedResource->pData = nullptr;
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
}
|
||||
|
@ -265,44 +263,26 @@ namespace dxvk {
|
|||
ID3D11Resource* pResource,
|
||||
D3D11_MAPPED_SUBRESOURCE* pMappedResource) {
|
||||
D3D11Buffer* pBuffer = static_cast<D3D11Buffer*>(pResource);
|
||||
|
||||
|
||||
if (unlikely(pBuffer->GetMapMode() == D3D11_COMMON_BUFFER_MAP_MODE_NONE)) {
|
||||
Logger::err("D3D11: Cannot map a device-local buffer");
|
||||
pMappedResource->pData = nullptr;
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
|
||||
|
||||
auto bufferSlice = pBuffer->AllocSlice(&m_allocationCache);
|
||||
pMappedResource->pData = bufferSlice->mapPtr();
|
||||
pMappedResource->RowPitch = pBuffer->Desc()->ByteWidth;
|
||||
pMappedResource->DepthPitch = pBuffer->Desc()->ByteWidth;
|
||||
|
||||
if (likely(m_csFlags.test(DxvkCsChunkFlag::SingleUse))) {
|
||||
// For resources that cannot be written by the GPU,
|
||||
// we may write to the buffer resource directly and
|
||||
// just swap in the buffer slice as needed.
|
||||
auto bufferSlice = pBuffer->AllocSlice();
|
||||
pMappedResource->pData = bufferSlice.mapPtr;
|
||||
|
||||
EmitCs([
|
||||
cDstBuffer = pBuffer->GetBuffer(),
|
||||
cPhysSlice = bufferSlice
|
||||
] (DxvkContext* ctx) {
|
||||
ctx->invalidateBuffer(cDstBuffer, cPhysSlice);
|
||||
});
|
||||
} else {
|
||||
// For GPU-writable resources, we need a data slice
|
||||
// to perform the update operation at execution time.
|
||||
auto dataSlice = AllocUpdateBufferSlice(pBuffer->Desc()->ByteWidth);
|
||||
pMappedResource->pData = dataSlice.ptr();
|
||||
EmitCs([
|
||||
cDstBuffer = pBuffer->GetBuffer(),
|
||||
cDstSlice = std::move(bufferSlice)
|
||||
] (DxvkContext* ctx) {
|
||||
ctx->invalidateBuffer(cDstBuffer, Rc<DxvkResourceAllocation>(cDstSlice));
|
||||
});
|
||||
|
||||
EmitCs([
|
||||
cDstBuffer = pBuffer->GetBuffer(),
|
||||
cDataSlice = dataSlice
|
||||
] (DxvkContext* ctx) {
|
||||
DxvkBufferSliceHandle slice = cDstBuffer->allocSlice();
|
||||
std::memcpy(slice.mapPtr, cDataSlice.ptr(), cDataSlice.length());
|
||||
ctx->invalidateBuffer(cDstBuffer, slice);
|
||||
});
|
||||
}
|
||||
|
||||
AddMapEntry(pBuffer->GetCookie(), *pMappedResource);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
@ -313,33 +293,52 @@ namespace dxvk {
|
|||
D3D11_MAPPED_SUBRESOURCE* pMappedResource) {
|
||||
D3D11CommonTexture* pTexture = GetCommonTexture(pResource);
|
||||
|
||||
if (unlikely(pTexture->GetMapMode() == D3D11_COMMON_TEXTURE_MAP_MODE_NONE)) {
|
||||
Logger::err("D3D11: Cannot map a device-local image");
|
||||
if (unlikely(Subresource >= pTexture->CountSubresources())) {
|
||||
pMappedResource->pData = nullptr;
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
|
||||
if (unlikely(Subresource >= pTexture->CountSubresources()))
|
||||
if (unlikely(pTexture->Desc()->Usage != D3D11_USAGE_DYNAMIC)) {
|
||||
pMappedResource->pData = nullptr;
|
||||
return E_INVALIDARG;
|
||||
|
||||
VkFormat packedFormat = pTexture->GetPackedFormat();
|
||||
|
||||
auto formatInfo = lookupFormatInfo(packedFormat);
|
||||
auto subresource = pTexture->GetSubresourceFromIndex(
|
||||
formatInfo->aspectMask, Subresource);
|
||||
|
||||
VkExtent3D levelExtent = pTexture->MipLevelExtent(subresource.mipLevel);
|
||||
|
||||
auto layout = pTexture->GetSubresourceLayout(formatInfo->aspectMask, Subresource);
|
||||
auto dataSlice = AllocStagingBuffer(util::computeImageDataSize(packedFormat, levelExtent));
|
||||
|
||||
pMappedResource->RowPitch = layout.RowPitch;
|
||||
pMappedResource->DepthPitch = layout.DepthPitch;
|
||||
pMappedResource->pData = dataSlice.mapPtr(0);
|
||||
}
|
||||
|
||||
UpdateImage(pTexture, &subresource,
|
||||
VkOffset3D { 0, 0, 0 }, levelExtent,
|
||||
std::move(dataSlice));
|
||||
return S_OK;
|
||||
VkFormat packedFormat = pTexture->GetPackedFormat();
|
||||
auto formatInfo = lookupFormatInfo(packedFormat);
|
||||
auto layout = pTexture->GetSubresourceLayout(formatInfo->aspectMask, Subresource);
|
||||
|
||||
if (pTexture->GetMapMode() == D3D11_COMMON_TEXTURE_MAP_MODE_DIRECT) {
|
||||
auto storage = pTexture->AllocStorage();
|
||||
auto mapPtr = storage->mapPtr();
|
||||
|
||||
EmitCs([
|
||||
cImage = pTexture->GetImage(),
|
||||
cStorage = std::move(storage)
|
||||
] (DxvkContext* ctx) {
|
||||
ctx->invalidateImage(cImage, Rc<DxvkResourceAllocation>(cStorage));
|
||||
ctx->initImage(cImage, cImage->getAvailableSubresources(), VK_IMAGE_LAYOUT_PREINITIALIZED);
|
||||
});
|
||||
|
||||
pMappedResource->RowPitch = layout.RowPitch;
|
||||
pMappedResource->DepthPitch = layout.DepthPitch;
|
||||
pMappedResource->pData = mapPtr;
|
||||
return S_OK;
|
||||
} else {
|
||||
auto dataSlice = AllocStagingBuffer(layout.Size);
|
||||
|
||||
pMappedResource->RowPitch = layout.RowPitch;
|
||||
pMappedResource->DepthPitch = layout.DepthPitch;
|
||||
pMappedResource->pData = dataSlice.mapPtr(0);
|
||||
|
||||
auto subresource = pTexture->GetSubresourceFromIndex(formatInfo->aspectMask, Subresource);
|
||||
auto mipExtent = pTexture->MipLevelExtent(subresource.mipLevel);
|
||||
|
||||
UpdateImage(pTexture, &subresource,
|
||||
VkOffset3D { 0, 0, 0 }, mipExtent,
|
||||
std::move(dataSlice));
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -351,19 +350,15 @@ namespace dxvk {
|
|||
UINT CopyFlags) {
|
||||
void* mapPtr = nullptr;
|
||||
|
||||
if (unlikely(CopyFlags == D3D11_COPY_NO_OVERWRITE)) {
|
||||
auto entry = FindMapEntry(pDstBuffer, 0);
|
||||
|
||||
if (entry)
|
||||
mapPtr = entry->MapInfo.pData;
|
||||
}
|
||||
if (unlikely(CopyFlags == D3D11_COPY_NO_OVERWRITE))
|
||||
mapPtr = FindMapEntry(pDstBuffer->GetCookie()).pData;
|
||||
|
||||
if (likely(!mapPtr)) {
|
||||
// The caller validates the map mode, so we can
|
||||
// safely ignore the MapBuffer return value here
|
||||
D3D11_MAPPED_SUBRESOURCE mapInfo;
|
||||
MapBuffer(pDstBuffer, &mapInfo);
|
||||
AddMapEntry(pDstBuffer, 0, D3D11_RESOURCE_DIMENSION_BUFFER, mapInfo);
|
||||
AddMapEntry(pDstBuffer->GetCookie(), mapInfo);
|
||||
mapPtr = mapInfo.pData;
|
||||
}
|
||||
|
||||
|
@ -418,40 +413,27 @@ namespace dxvk {
|
|||
}
|
||||
|
||||
|
||||
D3D11DeferredContextMapEntry* D3D11DeferredContext::FindMapEntry(
|
||||
ID3D11Resource* pResource,
|
||||
UINT Subresource) {
|
||||
D3D11_MAPPED_SUBRESOURCE D3D11DeferredContext::FindMapEntry(
|
||||
uint64_t Cookie) {
|
||||
// Recently mapped resources as well as entries with
|
||||
// up-to-date map infos will be located at the end
|
||||
// of the resource array, so scan in reverse order.
|
||||
size_t size = m_mappedResources.size();
|
||||
|
||||
for (size_t i = 1; i <= size; i++) {
|
||||
auto entry = &m_mappedResources[size - i];
|
||||
const auto& entry = m_mappedResources[size - i];
|
||||
|
||||
if (entry->Resource.Get() == pResource
|
||||
&& entry->Resource.GetSubresource() == Subresource)
|
||||
return entry;
|
||||
if (entry.ResourceCookie == Cookie)
|
||||
return entry.MapInfo;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
return D3D11_MAPPED_SUBRESOURCE();
|
||||
}
|
||||
|
||||
void D3D11DeferredContext::AddMapEntry(
|
||||
ID3D11Resource* pResource,
|
||||
UINT Subresource,
|
||||
D3D11_RESOURCE_DIMENSION ResourceType,
|
||||
uint64_t Cookie,
|
||||
const D3D11_MAPPED_SUBRESOURCE& MapInfo) {
|
||||
m_mappedResources.emplace_back(pResource,
|
||||
Subresource, ResourceType, MapInfo);
|
||||
m_mappedResources.push_back({ Cookie, MapInfo });
|
||||
}
|
||||
|
||||
|
||||
DxvkCsChunkFlags D3D11DeferredContext::GetCsChunkFlags(
|
||||
D3D11Device* pDevice) {
|
||||
return pDevice->GetOptions()->dcSingleUseMode
|
||||
? DxvkCsChunkFlags(DxvkCsChunkFlag::SingleUse)
|
||||
: DxvkCsChunkFlags();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,17 +8,8 @@
|
|||
namespace dxvk {
|
||||
|
||||
struct D3D11DeferredContextMapEntry {
|
||||
D3D11DeferredContextMapEntry() { }
|
||||
D3D11DeferredContextMapEntry(
|
||||
ID3D11Resource* pResource,
|
||||
UINT Subresource,
|
||||
D3D11_RESOURCE_DIMENSION ResourceType,
|
||||
const D3D11_MAPPED_SUBRESOURCE& MappedResource)
|
||||
: Resource(pResource, Subresource, ResourceType),
|
||||
MapInfo(MappedResource) { }
|
||||
|
||||
D3D11ResourceRef Resource;
|
||||
D3D11_MAPPED_SUBRESOURCE MapInfo;
|
||||
uint64_t ResourceCookie = 0u;
|
||||
D3D11_MAPPED_SUBRESOURCE MapInfo = { };
|
||||
};
|
||||
|
||||
class D3D11DeferredContext : public D3D11CommonContext<D3D11DeferredContext> {
|
||||
|
@ -130,14 +121,11 @@ namespace dxvk {
|
|||
void TrackBufferSequenceNumber(
|
||||
D3D11Buffer* pResource);
|
||||
|
||||
D3D11DeferredContextMapEntry* FindMapEntry(
|
||||
ID3D11Resource* pResource,
|
||||
UINT Subresource);
|
||||
D3D11_MAPPED_SUBRESOURCE FindMapEntry(
|
||||
uint64_t Coookie);
|
||||
|
||||
void AddMapEntry(
|
||||
ID3D11Resource* pResource,
|
||||
UINT Subresource,
|
||||
D3D11_RESOURCE_DIMENSION ResourceType,
|
||||
uint64_t Cookie,
|
||||
const D3D11_MAPPED_SUBRESOURCE& MapInfo);
|
||||
|
||||
static DxvkCsChunkFlags GetCsChunkFlags(
|
||||
|
|
|
@ -48,12 +48,15 @@ namespace dxvk {
|
|||
D3D10DeviceLock lock = m_ctx->LockContext();
|
||||
m_ctx->SetDrawBuffers(pBufferForArgs, nullptr);
|
||||
|
||||
if (unlikely(m_ctx->HasDirtyGraphicsBindings()))
|
||||
m_ctx->ApplyDirtyGraphicsBindings();
|
||||
|
||||
m_ctx->EmitCs([
|
||||
cCount = DrawCount,
|
||||
cOffset = ByteOffsetForArgs,
|
||||
cStride = ByteStrideForArgs
|
||||
] (DxvkContext* ctx) {
|
||||
ctx->drawIndirect(cOffset, cCount, cStride);
|
||||
ctx->drawIndirect(cOffset, cCount, cStride, false);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -67,12 +70,15 @@ namespace dxvk {
|
|||
D3D10DeviceLock lock = m_ctx->LockContext();
|
||||
m_ctx->SetDrawBuffers(pBufferForArgs, nullptr);
|
||||
|
||||
if (unlikely(m_ctx->HasDirtyGraphicsBindings()))
|
||||
m_ctx->ApplyDirtyGraphicsBindings();
|
||||
|
||||
m_ctx->EmitCs([
|
||||
cCount = DrawCount,
|
||||
cOffset = ByteOffsetForArgs,
|
||||
cStride = ByteStrideForArgs
|
||||
] (DxvkContext* ctx) {
|
||||
ctx->drawIndexedIndirect(cOffset, cCount, cStride);
|
||||
ctx->drawIndexedIndirect(cOffset, cCount, cStride, false);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -88,6 +94,9 @@ namespace dxvk {
|
|||
D3D10DeviceLock lock = m_ctx->LockContext();
|
||||
m_ctx->SetDrawBuffers(pBufferForArgs, pBufferForCount);
|
||||
|
||||
if (unlikely(m_ctx->HasDirtyGraphicsBindings()))
|
||||
m_ctx->ApplyDirtyGraphicsBindings();
|
||||
|
||||
m_ctx->EmitCs([
|
||||
cMaxCount = MaxDrawCount,
|
||||
cArgOffset = ByteOffsetForArgs,
|
||||
|
@ -110,6 +119,9 @@ namespace dxvk {
|
|||
D3D10DeviceLock lock = m_ctx->LockContext();
|
||||
m_ctx->SetDrawBuffers(pBufferForArgs, pBufferForCount);
|
||||
|
||||
if (unlikely(m_ctx->HasDirtyGraphicsBindings()))
|
||||
m_ctx->ApplyDirtyGraphicsBindings();
|
||||
|
||||
m_ctx->EmitCs([
|
||||
cMaxCount = MaxDrawCount,
|
||||
cArgOffset = ByteOffsetForArgs,
|
||||
|
@ -143,13 +155,13 @@ namespace dxvk {
|
|||
void STDMETHODCALLTYPE D3D11DeviceContextExt<ContextType>::SetBarrierControl(
|
||||
UINT ControlFlags) {
|
||||
D3D10DeviceLock lock = m_ctx->LockContext();
|
||||
DxvkBarrierControlFlags flags;
|
||||
|
||||
if (ControlFlags & D3D11_VK_BARRIER_CONTROL_IGNORE_WRITE_AFTER_WRITE)
|
||||
flags.set(DxvkBarrierControl::IgnoreWriteAfterWrite);
|
||||
D3D11Device* parent = static_cast<D3D11Device*>(m_ctx->GetParentInterface());
|
||||
DxvkBarrierControlFlags flags = parent->GetOptionsBarrierControlFlags();
|
||||
|
||||
if (ControlFlags & D3D11_VK_BARRIER_CONTROL_IGNORE_GRAPHICS_UAV)
|
||||
flags.set(DxvkBarrierControl::IgnoreGraphicsBarriers);
|
||||
if (ControlFlags & D3D11_VK_BARRIER_CONTROL_IGNORE_WRITE_AFTER_WRITE) {
|
||||
flags.set(DxvkBarrierControl::ComputeAllowReadWriteOverlap,
|
||||
DxvkBarrierControl::GraphicsAllowReadWriteOverlap);
|
||||
}
|
||||
|
||||
m_ctx->EmitCs([cFlags = flags] (DxvkContext* ctx) {
|
||||
ctx->setBarrierControl(cFlags);
|
||||
|
|
|
@ -16,28 +16,24 @@ namespace dxvk {
|
|||
D3D11Device* pParent,
|
||||
const Rc<DxvkDevice>& Device)
|
||||
: D3D11CommonContext<D3D11ImmediateContext>(pParent, Device, 0, DxvkCsChunkFlag::SingleUse),
|
||||
m_csThread(Device, Device->createContext(DxvkContextType::Primary)),
|
||||
m_maxImplicitDiscardSize(pParent->GetOptions()->maxImplicitDiscardSize),
|
||||
m_csThread(Device, Device->createContext()),
|
||||
m_submissionFence(new sync::CallbackFence()),
|
||||
m_flushTracker(GetMaxFlushType(pParent, Device)),
|
||||
m_stagingBufferFence(new sync::Fence(0)),
|
||||
m_multithread(this, false, pParent->GetOptions()->enableContextLock),
|
||||
m_videoContext(this, Device) {
|
||||
EmitCs([
|
||||
cDevice = m_device,
|
||||
cRelaxedBarriers = pParent->GetOptions()->relaxedBarriers,
|
||||
cIgnoreGraphicsBarriers = pParent->GetOptions()->ignoreGraphicsBarriers
|
||||
cBarrierControlFlags = pParent->GetOptionsBarrierControlFlags()
|
||||
] (DxvkContext* ctx) {
|
||||
ctx->beginRecording(cDevice->createCommandList());
|
||||
|
||||
DxvkBarrierControlFlags barrierControl;
|
||||
|
||||
if (cRelaxedBarriers)
|
||||
barrierControl.set(DxvkBarrierControl::IgnoreWriteAfterWrite);
|
||||
|
||||
if (cIgnoreGraphicsBarriers)
|
||||
barrierControl.set(DxvkBarrierControl::IgnoreGraphicsBarriers);
|
||||
|
||||
ctx->setBarrierControl(barrierControl);
|
||||
ctx->setBarrierControl(cBarrierControlFlags);
|
||||
});
|
||||
|
||||
// Stall here so that external submissions to the
|
||||
// CS thread can actually access the command list
|
||||
SynchronizeCsThread(DxvkCsThread::SynchronizeAll);
|
||||
|
||||
ClearState();
|
||||
}
|
||||
|
@ -101,6 +97,10 @@ namespace dxvk {
|
|||
// Ignore the DONOTFLUSH flag here as some games will spin
|
||||
// on queries without ever flushing the context otherwise.
|
||||
D3D10DeviceLock lock = LockContext();
|
||||
|
||||
if (unlikely(m_device->debugFlags().test(DxvkDebugFlag::Capture)))
|
||||
m_flushReason = "Query read-back";
|
||||
|
||||
ConsiderFlush(GpuFlushType::ImplicitSynchronization);
|
||||
}
|
||||
|
||||
|
@ -160,6 +160,9 @@ namespace dxvk {
|
|||
void STDMETHODCALLTYPE D3D11ImmediateContext::Flush() {
|
||||
D3D10DeviceLock lock = LockContext();
|
||||
|
||||
if (unlikely(m_device->debugFlags().test(DxvkDebugFlag::Capture)))
|
||||
m_flushReason = "Explicit Flush";
|
||||
|
||||
ExecuteFlush(GpuFlushType::ExplicitFlush, nullptr, true);
|
||||
}
|
||||
|
||||
|
@ -169,6 +172,9 @@ namespace dxvk {
|
|||
HANDLE hEvent) {
|
||||
D3D10DeviceLock lock = LockContext();
|
||||
|
||||
if (unlikely(m_device->debugFlags().test(DxvkDebugFlag::Capture)))
|
||||
m_flushReason = "Explicit Flush";
|
||||
|
||||
ExecuteFlush(GpuFlushType::ExplicitFlush, hEvent, true);
|
||||
}
|
||||
|
||||
|
@ -189,6 +195,9 @@ namespace dxvk {
|
|||
ctx->signalFence(cFence, cValue);
|
||||
});
|
||||
|
||||
if (unlikely(m_device->debugFlags().test(DxvkDebugFlag::Capture)))
|
||||
m_flushReason = "Fence signal";
|
||||
|
||||
ExecuteFlush(GpuFlushType::ExplicitFlush, nullptr, true);
|
||||
return S_OK;
|
||||
}
|
||||
|
@ -203,6 +212,9 @@ namespace dxvk {
|
|||
if (!fence)
|
||||
return E_INVALIDARG;
|
||||
|
||||
if (unlikely(m_device->debugFlags().test(DxvkDebugFlag::Capture)))
|
||||
m_flushReason = "Fence wait";
|
||||
|
||||
ExecuteFlush(GpuFlushType::ExplicitFlush, nullptr, true);
|
||||
|
||||
EmitCs([
|
||||
|
@ -222,7 +234,12 @@ namespace dxvk {
|
|||
D3D10DeviceLock lock = LockContext();
|
||||
|
||||
auto commandList = static_cast<D3D11CommandList*>(pCommandList);
|
||||
|
||||
|
||||
// Reset dirty binding tracking before submitting any CS chunks.
|
||||
// This is needed so that any submission that might occur during
|
||||
// this call does not disrupt bindings set by the deferred context.
|
||||
ResetDirtyTracking();
|
||||
|
||||
// Clear state so that the command list can't observe any
|
||||
// current context state. The command list itself will clean
|
||||
// up after execution to ensure that no state changes done
|
||||
|
@ -283,23 +300,14 @@ namespace dxvk {
|
|||
D3D11_RESOURCE_DIMENSION resourceDim = D3D11_RESOURCE_DIMENSION_UNKNOWN;
|
||||
pResource->GetType(&resourceDim);
|
||||
|
||||
HRESULT hr;
|
||||
|
||||
if (likely(resourceDim == D3D11_RESOURCE_DIMENSION_BUFFER)) {
|
||||
hr = MapBuffer(
|
||||
return MapBuffer(
|
||||
static_cast<D3D11Buffer*>(pResource),
|
||||
MapType, MapFlags, pMappedResource);
|
||||
} else {
|
||||
hr = MapImage(
|
||||
GetCommonTexture(pResource),
|
||||
Subresource, MapType, MapFlags,
|
||||
pMappedResource);
|
||||
return MapImage(GetCommonTexture(pResource),
|
||||
Subresource, MapType, MapFlags, pMappedResource);
|
||||
}
|
||||
|
||||
if (unlikely(FAILED(hr)))
|
||||
*pMappedResource = D3D11_MAPPED_SUBRESOURCE();
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
|
||||
|
@ -331,6 +339,7 @@ namespace dxvk {
|
|||
|
||||
if (unlikely(pResource->GetMapMode() == D3D11_COMMON_BUFFER_MAP_MODE_NONE)) {
|
||||
Logger::err("D3D11: Cannot map a device-local buffer");
|
||||
pMappedResource->pData = nullptr;
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
|
||||
|
@ -340,24 +349,28 @@ namespace dxvk {
|
|||
// Allocate a new backing slice for the buffer and set
|
||||
// it as the 'new' mapped slice. This assumes that the
|
||||
// only way to invalidate a buffer is by mapping it.
|
||||
auto physSlice = pResource->DiscardSlice();
|
||||
pMappedResource->pData = physSlice.mapPtr;
|
||||
auto bufferSlice = pResource->DiscardSlice(&m_allocationCache);
|
||||
pMappedResource->pData = bufferSlice->mapPtr();
|
||||
pMappedResource->RowPitch = bufferSize;
|
||||
pMappedResource->DepthPitch = bufferSize;
|
||||
|
||||
EmitCs([
|
||||
cBuffer = pResource->GetBuffer(),
|
||||
cBufferSlice = physSlice
|
||||
] (DxvkContext* ctx) {
|
||||
ctx->invalidateBuffer(cBuffer, cBufferSlice);
|
||||
cBufferSlice = std::move(bufferSlice)
|
||||
] (DxvkContext* ctx) mutable {
|
||||
ctx->invalidateBuffer(cBuffer, std::move(cBufferSlice));
|
||||
});
|
||||
|
||||
// Ignore small buffers here. These are often updated per
|
||||
// draw and won't contribute much to memory waste anyway.
|
||||
if (unlikely(bufferSize > DxvkPageAllocator::PageSize))
|
||||
ThrottleDiscard(bufferSize);
|
||||
|
||||
return S_OK;
|
||||
} else if (likely(MapType == D3D11_MAP_WRITE_NO_OVERWRITE)) {
|
||||
// Put this on a fast path without any extra checks since it's
|
||||
// a somewhat desired method to partially update large buffers
|
||||
DxvkBufferSliceHandle physSlice = pResource->GetMappedSlice();
|
||||
pMappedResource->pData = physSlice.mapPtr;
|
||||
pMappedResource->pData = pResource->GetMapPtr();
|
||||
pMappedResource->RowPitch = bufferSize;
|
||||
pMappedResource->DepthPitch = bufferSize;
|
||||
return S_OK;
|
||||
|
@ -372,7 +385,7 @@ namespace dxvk {
|
|||
auto buffer = pResource->GetBuffer();
|
||||
auto sequenceNumber = pResource->GetSequenceNumber();
|
||||
|
||||
if (MapType != D3D11_MAP_READ && !MapFlags && bufferSize <= m_maxImplicitDiscardSize) {
|
||||
if (MapType != D3D11_MAP_READ && !MapFlags && bufferSize <= D3D11Initializer::MaxMemoryPerSubmission) {
|
||||
SynchronizeCsThread(sequenceNumber);
|
||||
|
||||
bool hasWoAccess = buffer->isInUse(DxvkAccess::Write);
|
||||
|
@ -385,27 +398,32 @@ namespace dxvk {
|
|||
}
|
||||
|
||||
if (doInvalidatePreserve) {
|
||||
auto prevSlice = pResource->GetMappedSlice();
|
||||
auto physSlice = pResource->DiscardSlice();
|
||||
auto srcPtr = pResource->GetMapPtr();
|
||||
|
||||
auto dstSlice = pResource->DiscardSlice(nullptr);
|
||||
auto dstPtr = dstSlice->mapPtr();
|
||||
|
||||
EmitCs([
|
||||
cBuffer = std::move(buffer),
|
||||
cBufferSlice = physSlice
|
||||
] (DxvkContext* ctx) {
|
||||
ctx->invalidateBuffer(cBuffer, cBufferSlice);
|
||||
cBufferSlice = std::move(dstSlice)
|
||||
] (DxvkContext* ctx) mutable {
|
||||
ctx->invalidateBuffer(cBuffer, std::move(cBufferSlice));
|
||||
});
|
||||
|
||||
std::memcpy(physSlice.mapPtr, prevSlice.mapPtr, physSlice.length);
|
||||
pMappedResource->pData = physSlice.mapPtr;
|
||||
std::memcpy(dstPtr, srcPtr, bufferSize);
|
||||
pMappedResource->pData = dstPtr;
|
||||
pMappedResource->RowPitch = bufferSize;
|
||||
pMappedResource->DepthPitch = bufferSize;
|
||||
|
||||
ThrottleDiscard(bufferSize);
|
||||
return S_OK;
|
||||
} else {
|
||||
if (!WaitForResource(buffer, sequenceNumber, MapType, MapFlags))
|
||||
if (!WaitForResource(*buffer, sequenceNumber, MapType, MapFlags)) {
|
||||
pMappedResource->pData = nullptr;
|
||||
return DXGI_ERROR_WAS_STILL_DRAWING;
|
||||
}
|
||||
|
||||
DxvkBufferSliceHandle physSlice = pResource->GetMappedSlice();
|
||||
pMappedResource->pData = physSlice.mapPtr;
|
||||
pMappedResource->pData = pResource->GetMapPtr();
|
||||
pMappedResource->RowPitch = bufferSize;
|
||||
pMappedResource->DepthPitch = bufferSize;
|
||||
return S_OK;
|
||||
|
@ -420,19 +438,46 @@ namespace dxvk {
|
|||
D3D11_MAP MapType,
|
||||
UINT MapFlags,
|
||||
D3D11_MAPPED_SUBRESOURCE* pMappedResource) {
|
||||
const Rc<DxvkImage> mappedImage = pResource->GetImage();
|
||||
const Rc<DxvkBuffer> mappedBuffer = pResource->GetMappedBuffer(Subresource);
|
||||
|
||||
auto mapMode = pResource->GetMapMode();
|
||||
|
||||
if (unlikely(mapMode == D3D11_COMMON_TEXTURE_MAP_MODE_NONE)) {
|
||||
Logger::err("D3D11: Cannot map a device-local image");
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
|
||||
if (pMappedResource)
|
||||
pMappedResource->pData = nullptr;
|
||||
|
||||
if (unlikely(Subresource >= pResource->CountSubresources()))
|
||||
return E_INVALIDARG;
|
||||
|
||||
|
||||
switch (MapType) {
|
||||
case D3D11_MAP_READ: {
|
||||
if (!(pResource->Desc()->CPUAccessFlags & D3D11_CPU_ACCESS_READ))
|
||||
return E_INVALIDARG;
|
||||
} break;
|
||||
|
||||
case D3D11_MAP_READ_WRITE: {
|
||||
if (!(pResource->Desc()->CPUAccessFlags & D3D11_CPU_ACCESS_READ)
|
||||
|| !(pResource->Desc()->CPUAccessFlags & D3D11_CPU_ACCESS_WRITE))
|
||||
return E_INVALIDARG;
|
||||
} break;
|
||||
|
||||
case D3D11_MAP_WRITE: {
|
||||
if (!(pResource->Desc()->CPUAccessFlags & D3D11_CPU_ACCESS_WRITE)
|
||||
|| (pResource->Desc()->Usage == D3D11_USAGE_DYNAMIC))
|
||||
return E_INVALIDARG;
|
||||
} break;
|
||||
|
||||
case D3D11_MAP_WRITE_DISCARD: {
|
||||
if (!(pResource->Desc()->CPUAccessFlags & D3D11_CPU_ACCESS_WRITE)
|
||||
|| pResource->Desc()->Usage != D3D11_USAGE_DYNAMIC)
|
||||
return E_INVALIDARG;
|
||||
} break;
|
||||
|
||||
case D3D11_MAP_WRITE_NO_OVERWRITE: {
|
||||
// NO_OVERWRITE is explcitly banned for dynamic images
|
||||
if (!(pResource->Desc()->CPUAccessFlags & D3D11_CPU_ACCESS_WRITE)
|
||||
|| (pResource->Desc()->Usage != D3D11_USAGE_DEFAULT))
|
||||
return E_INVALIDARG;
|
||||
} break;
|
||||
}
|
||||
|
||||
if (likely(pMappedResource != nullptr)) {
|
||||
// Resources with an unknown memory layout cannot return a pointer
|
||||
if (pResource->Desc()->Usage == D3D11_USAGE_DEFAULT
|
||||
|
@ -449,23 +494,32 @@ namespace dxvk {
|
|||
uint64_t sequenceNumber = pResource->GetSequenceNumber(Subresource);
|
||||
|
||||
auto formatInfo = lookupFormatInfo(packedFormat);
|
||||
void* mapPtr;
|
||||
auto layout = pResource->GetSubresourceLayout(formatInfo->aspectMask, Subresource);
|
||||
|
||||
if (mapMode == D3D11_COMMON_TEXTURE_MAP_MODE_DIRECT) {
|
||||
// Wait for the resource to become available. We do not
|
||||
// support image renaming, so stall on DISCARD instead.
|
||||
if (MapType == D3D11_MAP_WRITE_DISCARD)
|
||||
MapFlags &= ~D3D11_MAP_FLAG_DO_NOT_WAIT;
|
||||
Rc<DxvkImage> mappedImage = pResource->GetImage();
|
||||
|
||||
if (MapType != D3D11_MAP_WRITE_NO_OVERWRITE) {
|
||||
if (!WaitForResource(mappedImage, sequenceNumber, MapType, MapFlags))
|
||||
if (MapType == D3D11_MAP_WRITE_DISCARD) {
|
||||
EmitCs([
|
||||
cImage = std::move(mappedImage),
|
||||
cStorage = pResource->DiscardStorage()
|
||||
] (DxvkContext* ctx) {
|
||||
ctx->invalidateImage(cImage, Rc<DxvkResourceAllocation>(cStorage));
|
||||
ctx->initImage(cImage, cImage->getAvailableSubresources(), VK_IMAGE_LAYOUT_PREINITIALIZED);
|
||||
});
|
||||
|
||||
ThrottleDiscard(layout.Size);
|
||||
} else if (MapType != D3D11_MAP_WRITE_NO_OVERWRITE) {
|
||||
if (!WaitForResource(*mappedImage, sequenceNumber, MapType, MapFlags))
|
||||
return DXGI_ERROR_WAS_STILL_DRAWING;
|
||||
}
|
||||
|
||||
// Query the subresource's memory layout and hope that
|
||||
// the application respects the returned pitch values.
|
||||
mapPtr = mappedImage->mapPtr(0);
|
||||
} else if (mapMode == D3D11_COMMON_TEXTURE_MAP_MODE_DYNAMIC) {
|
||||
// Nothing else to really do here, NotifyMap will ensure that we
|
||||
// actually get a staging buffer that isn't currently in use.
|
||||
ThrottleDiscard(layout.Size);
|
||||
} else {
|
||||
Rc<DxvkBuffer> mappedBuffer = pResource->GetMappedBuffer(Subresource);
|
||||
|
||||
constexpr uint32_t DoInvalidate = (1u << 0);
|
||||
constexpr uint32_t DoPreserve = (1u << 1);
|
||||
constexpr uint32_t DoWait = (1u << 2);
|
||||
|
@ -503,11 +557,11 @@ namespace dxvk {
|
|||
// Need to synchronize thread to determine pending GPU accesses
|
||||
SynchronizeCsThread(sequenceNumber);
|
||||
|
||||
// Don't implicitly discard large buffers or buffers of images with
|
||||
// multiple subresources, as that is likely to cause memory issues.
|
||||
VkDeviceSize bufferSize = pResource->GetMappedSlice(Subresource).length;
|
||||
// Don't implicitly discard large very large resources
|
||||
// since that might lead to memory issues.
|
||||
VkDeviceSize bufferSize = mappedBuffer->info().size;
|
||||
|
||||
if (bufferSize >= m_maxImplicitDiscardSize || pResource->CountSubresources() > 1) {
|
||||
if (bufferSize > D3D11Initializer::MaxMemoryPerSubmission) {
|
||||
// Don't check access flags, WaitForResource will return
|
||||
// early anyway if the resource is currently in use
|
||||
doFlags = DoWait;
|
||||
|
@ -530,20 +584,25 @@ namespace dxvk {
|
|||
}
|
||||
|
||||
if (doFlags & DoInvalidate) {
|
||||
DxvkBufferSliceHandle prevSlice = pResource->GetMappedSlice(Subresource);
|
||||
DxvkBufferSliceHandle physSlice = pResource->DiscardSlice(Subresource);
|
||||
VkDeviceSize bufferSize = mappedBuffer->info().size;
|
||||
|
||||
auto srcSlice = pResource->GetMappedSlice(Subresource);
|
||||
auto dstSlice = pResource->DiscardSlice(Subresource);
|
||||
|
||||
auto srcPtr = srcSlice->mapPtr();
|
||||
auto dstPtr = dstSlice->mapPtr();
|
||||
|
||||
EmitCs([
|
||||
cImageBuffer = mappedBuffer,
|
||||
cBufferSlice = physSlice
|
||||
] (DxvkContext* ctx) {
|
||||
ctx->invalidateBuffer(cImageBuffer, cBufferSlice);
|
||||
cImageBuffer = std::move(mappedBuffer),
|
||||
cImageBufferSlice = std::move(dstSlice)
|
||||
] (DxvkContext* ctx) mutable {
|
||||
ctx->invalidateBuffer(cImageBuffer, std::move(cImageBufferSlice));
|
||||
});
|
||||
|
||||
if (doFlags & DoPreserve)
|
||||
std::memcpy(physSlice.mapPtr, prevSlice.mapPtr, physSlice.length);
|
||||
std::memcpy(dstPtr, srcPtr, bufferSize);
|
||||
|
||||
mapPtr = physSlice.mapPtr;
|
||||
ThrottleDiscard(bufferSize);
|
||||
} else {
|
||||
if (doFlags & DoWait) {
|
||||
// We cannot respect DO_NOT_WAIT for buffer-mapped resources since
|
||||
|
@ -552,20 +611,17 @@ namespace dxvk {
|
|||
MapFlags &= ~D3D11_MAP_FLAG_DO_NOT_WAIT;
|
||||
|
||||
// Wait for mapped buffer to become available
|
||||
if (!WaitForResource(mappedBuffer, sequenceNumber, MapType, MapFlags))
|
||||
if (!WaitForResource(*mappedBuffer, sequenceNumber, MapType, MapFlags))
|
||||
return DXGI_ERROR_WAS_STILL_DRAWING;
|
||||
}
|
||||
|
||||
mapPtr = pResource->GetMappedSlice(Subresource).mapPtr;
|
||||
}
|
||||
}
|
||||
|
||||
// Mark the given subresource as mapped
|
||||
pResource->SetMapType(Subresource, MapType);
|
||||
// Mark the subresource as successfully mapped
|
||||
pResource->NotifyMap(Subresource, MapType);
|
||||
|
||||
if (pMappedResource) {
|
||||
auto layout = pResource->GetSubresourceLayout(formatInfo->aspectMask, Subresource);
|
||||
pMappedResource->pData = reinterpret_cast<char*>(mapPtr) + layout.Offset;
|
||||
pMappedResource->pData = pResource->GetMapPtr(Subresource, layout.Offset);
|
||||
pMappedResource->RowPitch = layout.RowPitch;
|
||||
pMappedResource->DepthPitch = layout.DepthPitch;
|
||||
}
|
||||
|
@ -578,28 +634,35 @@ namespace dxvk {
|
|||
void D3D11ImmediateContext::UnmapImage(
|
||||
D3D11CommonTexture* pResource,
|
||||
UINT Subresource) {
|
||||
D3D11_MAP mapType = pResource->GetMapType(Subresource);
|
||||
pResource->SetMapType(Subresource, D3D11_MAP(~0u));
|
||||
auto mapType = pResource->GetMapType(Subresource);
|
||||
auto mapMode = pResource->GetMapMode();
|
||||
|
||||
if (mapType == D3D11_MAP(~0u))
|
||||
if (mapType == D3D11CommonTexture::UnmappedSubresource)
|
||||
return;
|
||||
|
||||
// Decrement mapped image counter only after making sure
|
||||
// the given subresource is actually mapped right now
|
||||
m_mappedImageCount -= 1;
|
||||
|
||||
if ((mapType != D3D11_MAP_READ) && (pResource->GetMapMode() == D3D11_COMMON_TEXTURE_MAP_MODE_BUFFER)) {
|
||||
// If the texture has an image as well as a staging buffer,
|
||||
// upload the written buffer data to the image
|
||||
bool needsUpload = mapType != uint32_t(D3D11_MAP_READ)
|
||||
&& (mapMode == D3D11_COMMON_TEXTURE_MAP_MODE_BUFFER || mapMode == D3D11_COMMON_TEXTURE_MAP_MODE_DYNAMIC);
|
||||
|
||||
if (needsUpload) {
|
||||
if (pResource->NeedsDirtyRegionTracking()) {
|
||||
for (uint32_t i = 0; i < pResource->GetDirtyRegionCount(Subresource); i++) {
|
||||
D3D11_COMMON_TEXTURE_REGION region = pResource->GetDirtyRegion(Subresource, i);
|
||||
UpdateDirtyImageRegion(pResource, Subresource, ®ion);
|
||||
}
|
||||
|
||||
pResource->ClearDirtyRegions(Subresource);
|
||||
} else {
|
||||
UpdateDirtyImageRegion(pResource, Subresource, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
// Unmap the subresource. This will implicitly destroy the
|
||||
// staging buffer for dynamically mapped images.
|
||||
pResource->NotifyUnmap(Subresource);
|
||||
}
|
||||
|
||||
|
||||
|
@ -618,18 +681,8 @@ namespace dxvk {
|
|||
VkOffset3D offset = { 0, 0, 0 };
|
||||
VkExtent3D extent = cSrcImage->mipLevelExtent(cSrcSubresource.mipLevel);
|
||||
|
||||
if (cSrcSubresource.aspectMask != (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) {
|
||||
ctx->copyImageToBuffer(cDstBuffer, 0, 0, 0,
|
||||
cSrcImage, cSrcSubresource, offset, extent);
|
||||
} else {
|
||||
ctx->copyDepthStencilImageToPackedBuffer(cDstBuffer, 0,
|
||||
VkOffset2D { 0, 0 },
|
||||
VkExtent2D { extent.width, extent.height },
|
||||
cSrcImage, cSrcSubresource,
|
||||
VkOffset2D { 0, 0 },
|
||||
VkExtent2D { extent.width, extent.height },
|
||||
cPackedFormat);
|
||||
}
|
||||
ctx->copyImageToBuffer(cDstBuffer, 0, 0, 0, cPackedFormat,
|
||||
cSrcImage, cSrcSubresource, offset, extent);
|
||||
});
|
||||
|
||||
if (pResource->HasSequenceNumber())
|
||||
|
@ -676,20 +729,10 @@ namespace dxvk {
|
|||
cSrcDepthPitch = subresourceLayout.DepthPitch,
|
||||
cPackedFormat = pResource->GetPackedFormat()
|
||||
] (DxvkContext* ctx) {
|
||||
if (cDstSubresource.aspectMask != (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) {
|
||||
ctx->copyBufferToImage(
|
||||
cDstImage, cDstSubresource, cDstOffset, cDstExtent,
|
||||
cSrcBuffer, cSrcOffset, cSrcRowPitch, cSrcDepthPitch);
|
||||
} else {
|
||||
ctx->copyPackedBufferToDepthStencilImage(
|
||||
cDstImage, cDstSubresource,
|
||||
VkOffset2D { cDstOffset.x, cDstOffset.y },
|
||||
VkExtent2D { cDstExtent.width, cDstExtent.height },
|
||||
cSrcBuffer, 0,
|
||||
VkOffset2D { cDstOffset.x, cDstOffset.y },
|
||||
VkExtent2D { cDstExtent.width, cDstExtent.height },
|
||||
cPackedFormat);
|
||||
}
|
||||
ctx->copyBufferToImage(
|
||||
cDstImage, cDstSubresource, cDstOffset, cDstExtent,
|
||||
cSrcBuffer, cSrcOffset, cSrcRowPitch, cSrcDepthPitch,
|
||||
cPackedFormat);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -704,22 +747,23 @@ namespace dxvk {
|
|||
UINT Length,
|
||||
const void* pSrcData,
|
||||
UINT CopyFlags) {
|
||||
DxvkBufferSliceHandle slice;
|
||||
void* mapPtr = nullptr;
|
||||
|
||||
if (likely(CopyFlags != D3D11_COPY_NO_OVERWRITE)) {
|
||||
slice = pDstBuffer->DiscardSlice();
|
||||
auto bufferSlice = pDstBuffer->DiscardSlice(&m_allocationCache);
|
||||
mapPtr = bufferSlice->mapPtr();
|
||||
|
||||
EmitCs([
|
||||
cBuffer = pDstBuffer->GetBuffer(),
|
||||
cBufferSlice = slice
|
||||
] (DxvkContext* ctx) {
|
||||
ctx->invalidateBuffer(cBuffer, cBufferSlice);
|
||||
cBufferSlice = std::move(bufferSlice)
|
||||
] (DxvkContext* ctx) mutable {
|
||||
ctx->invalidateBuffer(cBuffer, std::move(cBufferSlice));
|
||||
});
|
||||
} else {
|
||||
slice = pDstBuffer->GetMappedSlice();
|
||||
mapPtr = pDstBuffer->GetMapPtr();
|
||||
}
|
||||
|
||||
std::memcpy(reinterpret_cast<char*>(slice.mapPtr) + Offset, pSrcData, Length);
|
||||
std::memcpy(reinterpret_cast<char*>(mapPtr) + Offset, pSrcData, Length);
|
||||
}
|
||||
|
||||
|
||||
|
@ -731,7 +775,11 @@ namespace dxvk {
|
|||
if (!pState)
|
||||
return;
|
||||
|
||||
// Reset all state affected by the current context state
|
||||
// Clear dirty tracking here since all context state will be
|
||||
// re-applied anyway when the context state is swapped in again.
|
||||
ResetDirtyTracking();
|
||||
|
||||
// Reset all state affected by the current context state.
|
||||
ResetCommandListState();
|
||||
|
||||
Com<D3D11DeviceContextState, false> oldState = std::move(m_stateObject);
|
||||
|
@ -838,17 +886,28 @@ namespace dxvk {
|
|||
}
|
||||
|
||||
|
||||
void D3D11ImmediateContext::EndFrame() {
|
||||
void D3D11ImmediateContext::EndFrame(
|
||||
Rc<DxvkLatencyTracker> LatencyTracker) {
|
||||
D3D10DeviceLock lock = LockContext();
|
||||
|
||||
EmitCs<false>([] (DxvkContext* ctx) {
|
||||
// Don't keep draw buffers alive indefinitely. This cannot be
|
||||
// done in ExecuteFlush because command recording itself might
|
||||
// flush, so no state changes are allowed to happen there.
|
||||
SetDrawBuffers(nullptr, nullptr);
|
||||
|
||||
EmitCs<false>([
|
||||
cTracker = std::move(LatencyTracker)
|
||||
] (DxvkContext* ctx) {
|
||||
ctx->endFrame();
|
||||
|
||||
if (cTracker && cTracker->needsAutoMarkers())
|
||||
ctx->endLatencyTracking(cTracker);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
bool D3D11ImmediateContext::WaitForResource(
|
||||
const Rc<DxvkResource>& Resource,
|
||||
const DxvkPagedResource& Resource,
|
||||
uint64_t SequenceNumber,
|
||||
D3D11_MAP MapType,
|
||||
UINT MapFlags) {
|
||||
|
@ -860,37 +919,52 @@ namespace dxvk {
|
|||
// Wait for any CS chunk using the resource to execute, since
|
||||
// otherwise we cannot accurately determine if the resource is
|
||||
// actually being used by the GPU right now.
|
||||
bool isInUse = Resource->isInUse(access);
|
||||
|
||||
if (!isInUse) {
|
||||
if (!Resource.isInUse(access)) {
|
||||
SynchronizeCsThread(SequenceNumber);
|
||||
isInUse = Resource->isInUse(access);
|
||||
|
||||
if (!Resource.isInUse(access))
|
||||
return true;
|
||||
}
|
||||
|
||||
if (unlikely(m_device->debugFlags().test(DxvkDebugFlag::Capture))) {
|
||||
m_flushReason = str::format("Map ", Resource.getDebugName(), " (MAP",
|
||||
MapType != D3D11_MAP_WRITE ? "_READ" : "",
|
||||
MapType != D3D11_MAP_READ ? "_WRITE" : "", ")");
|
||||
}
|
||||
|
||||
if (MapFlags & D3D11_MAP_FLAG_DO_NOT_WAIT) {
|
||||
if (isInUse) {
|
||||
// We don't have to wait, but misbehaving games may
|
||||
// still try to spin on `Map` until the resource is
|
||||
// idle, so we should flush pending commands
|
||||
ConsiderFlush(GpuFlushType::ImplicitSynchronization);
|
||||
return false;
|
||||
}
|
||||
// We don't have to wait, but misbehaving games may
|
||||
// still try to spin on `Map` until the resource is
|
||||
// idle, so we should flush pending commands
|
||||
ConsiderFlush(GpuFlushType::ImplicitSynchronization);
|
||||
return false;
|
||||
} else {
|
||||
if (isInUse) {
|
||||
// Make sure pending commands using the resource get
|
||||
// executed on the the GPU if we have to wait for it
|
||||
ExecuteFlush(GpuFlushType::ImplicitSynchronization, nullptr, false);
|
||||
SynchronizeCsThread(SequenceNumber);
|
||||
// Make sure pending commands using the resource get
|
||||
// executed on the the GPU if we have to wait for it
|
||||
ExecuteFlush(GpuFlushType::ImplicitSynchronization, nullptr, false);
|
||||
SynchronizeCsThread(SequenceNumber);
|
||||
|
||||
m_device->waitForResource(Resource, access);
|
||||
}
|
||||
m_device->waitForResource(Resource, access);
|
||||
return true;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void D3D11ImmediateContext::InjectCsChunk(
|
||||
DxvkCsQueue Queue,
|
||||
DxvkCsChunkRef&& Chunk,
|
||||
bool Synchronize) {
|
||||
// Do not update the sequence number when emitting a chunk
|
||||
// from an external source since that would break tracking
|
||||
m_csThread.injectChunk(Queue, std::move(Chunk), Synchronize);
|
||||
}
|
||||
|
||||
|
||||
void D3D11ImmediateContext::EmitCsChunk(DxvkCsChunkRef&& chunk) {
|
||||
// Flush init commands so that the CS thread
|
||||
// can processe them before the first use.
|
||||
m_parent->FlushInitCommands();
|
||||
|
||||
m_csSeqNum = m_csThread.dispatchChunk(std::move(chunk));
|
||||
}
|
||||
|
||||
|
@ -927,8 +1001,106 @@ namespace dxvk {
|
|||
}
|
||||
|
||||
|
||||
void D3D11ImmediateContext::ApplyDirtyNullBindings() {
|
||||
// At the end of a submission, set all bindings that have not been applied yet
|
||||
// to null on the DXVK context. This way, we avoid keeping resources alive that
|
||||
// are bound to the DXVK context but not to the immediate context.
|
||||
//
|
||||
// Note: This requires that all methods that may modify dirty bindings on the
|
||||
// DXVK context also reset the corresponding dirty bits *before* performing the
|
||||
// bind operation, or otherwise an implicit flush can potentially override them.
|
||||
auto& dirtyState = m_state.lazy.bindingsDirty;
|
||||
|
||||
EmitCs<false>([
|
||||
cDirtyState = dirtyState
|
||||
] (DxvkContext* ctx) {
|
||||
for (uint32_t i = 0; i < uint32_t(DxbcProgramType::Count); i++) {
|
||||
auto dxStage = DxbcProgramType(i);
|
||||
auto vkStage = GetShaderStage(dxStage);
|
||||
|
||||
// Unbind all dirty constant buffers
|
||||
auto cbvSlot = computeConstantBufferBinding(dxStage, 0);
|
||||
|
||||
for (uint32_t index : bit::BitMask(cDirtyState[dxStage].cbvMask))
|
||||
ctx->bindUniformBuffer(vkStage, cbvSlot + index, DxvkBufferSlice());
|
||||
|
||||
// Unbind all dirty samplers
|
||||
auto samplerSlot = computeSamplerBinding(dxStage, 0);
|
||||
|
||||
for (uint32_t index : bit::BitMask(cDirtyState[dxStage].samplerMask))
|
||||
ctx->bindResourceSampler(vkStage, samplerSlot + index, nullptr);
|
||||
|
||||
// Unbind all dirty shader resource views
|
||||
auto srvSlot = computeSrvBinding(dxStage, 0);
|
||||
|
||||
for (uint32_t m = 0; m < cDirtyState[dxStage].srvMask.size(); m++) {
|
||||
for (uint32_t index : bit::BitMask(cDirtyState[dxStage].srvMask[m]))
|
||||
ctx->bindResourceImageView(vkStage, srvSlot + index + m * 64u, nullptr);
|
||||
}
|
||||
|
||||
// Unbind all dirty unordered access views
|
||||
VkShaderStageFlags uavStages = 0u;
|
||||
|
||||
if (dxStage == DxbcProgramType::ComputeShader)
|
||||
uavStages = VK_SHADER_STAGE_COMPUTE_BIT;
|
||||
else if (dxStage == DxbcProgramType::PixelShader)
|
||||
uavStages = VK_SHADER_STAGE_ALL_GRAPHICS;
|
||||
|
||||
if (uavStages) {
|
||||
auto uavSlot = computeUavBinding(dxStage, 0);
|
||||
auto ctrSlot = computeUavCounterBinding(dxStage, 0);
|
||||
|
||||
for (uint32_t index : bit::BitMask(cDirtyState[dxStage].uavMask)) {
|
||||
ctx->bindResourceImageView(vkStage, uavSlot + index, nullptr);
|
||||
ctx->bindResourceBufferView(vkStage, ctrSlot + index, nullptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Since we set the DXVK context bindings to null, any bindings that are null
|
||||
// on the D3D context are no longer dirty, so we can clear the respective bits.
|
||||
for (uint32_t i = 0; i < uint32_t(DxbcProgramType::Count); i++) {
|
||||
auto stage = DxbcProgramType(i);
|
||||
|
||||
for (uint32_t index : bit::BitMask(dirtyState[stage].cbvMask)) {
|
||||
if (!m_state.cbv[stage].buffers[index].buffer.ptr())
|
||||
dirtyState[stage].cbvMask &= ~(1u << index);
|
||||
}
|
||||
|
||||
for (uint32_t index : bit::BitMask(dirtyState[stage].samplerMask)) {
|
||||
if (!m_state.samplers[stage].samplers[index])
|
||||
dirtyState[stage].samplerMask &= ~(1u << index);
|
||||
}
|
||||
|
||||
for (uint32_t m = 0; m < dirtyState[stage].srvMask.size(); m++) {
|
||||
for (uint32_t index : bit::BitMask(dirtyState[stage].srvMask[m])) {
|
||||
if (!m_state.srv[stage].views[index + m * 64u].ptr())
|
||||
dirtyState[stage].srvMask[m] &= ~(uint64_t(1u) << index);
|
||||
}
|
||||
}
|
||||
|
||||
if (stage == DxbcProgramType::ComputeShader || stage == DxbcProgramType::PixelShader) {
|
||||
auto& uavs = stage == DxbcProgramType::ComputeShader ? m_state.uav.views : m_state.om.uavs;
|
||||
|
||||
for (uint32_t index : bit::BitMask(dirtyState[stage].uavMask)) {
|
||||
if (!uavs[index].ptr())
|
||||
dirtyState[stage].uavMask &= ~(uint64_t(1u) << index);
|
||||
}
|
||||
}
|
||||
|
||||
if (dirtyState[stage].empty())
|
||||
m_state.lazy.shadersDirty.clr(stage);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void D3D11ImmediateContext::ConsiderFlush(
|
||||
GpuFlushType FlushType) {
|
||||
// In stress test mode, behave as if this would always flush
|
||||
if (DebugLazyBinding == Tristate::True)
|
||||
ApplyDirtyNullBindings();
|
||||
|
||||
uint64_t chunkId = GetCurrentSequenceNumber();
|
||||
uint64_t submissionId = m_submissionFence->value();
|
||||
|
||||
|
@ -946,15 +1118,13 @@ namespace dxvk {
|
|||
if (synchronizeSubmission)
|
||||
m_submitStatus.result = VK_NOT_READY;
|
||||
|
||||
// Flush init context so that new resources are fully initialized
|
||||
// before the app can access them in any way. This has to happen
|
||||
// unconditionally since we may otherwise deadlock on Map.
|
||||
m_parent->FlushInitContext();
|
||||
|
||||
// Exit early if there's nothing to do
|
||||
if (!GetPendingCsChunks() && !hEvent)
|
||||
return;
|
||||
|
||||
// Unbind unused resources
|
||||
ApplyDirtyNullBindings();
|
||||
|
||||
// Signal the submission fence and flush the command list
|
||||
uint64_t submissionId = ++m_submissionId;
|
||||
|
||||
|
@ -967,10 +1137,16 @@ namespace dxvk {
|
|||
EmitCs<false>([
|
||||
cSubmissionFence = m_submissionFence,
|
||||
cSubmissionId = submissionId,
|
||||
cSubmissionStatus = synchronizeSubmission ? &m_submitStatus : nullptr
|
||||
cSubmissionStatus = synchronizeSubmission ? &m_submitStatus : nullptr,
|
||||
cStagingFence = m_stagingBufferFence,
|
||||
cStagingMemory = GetStagingMemoryStatistics().allocatedTotal,
|
||||
cFlushReason = std::exchange(m_flushReason, std::string())
|
||||
] (DxvkContext* ctx) {
|
||||
auto debugLabel = vk::makeLabel(0xff5959, cFlushReason.c_str());
|
||||
|
||||
ctx->signal(cSubmissionFence, cSubmissionId);
|
||||
ctx->flushCommandList(cSubmissionStatus);
|
||||
ctx->signal(cStagingFence, cStagingMemory);
|
||||
ctx->flushCommandList(&debugLabel, cSubmissionStatus);
|
||||
});
|
||||
|
||||
FlushCsChunk();
|
||||
|
@ -983,6 +1159,69 @@ namespace dxvk {
|
|||
// Vulkan queue submission is performed.
|
||||
if (synchronizeSubmission)
|
||||
m_device->waitForSubmission(&m_submitStatus);
|
||||
|
||||
// Free local staging buffer so that we don't
|
||||
// end up with a persistent allocation
|
||||
ResetStagingBuffer();
|
||||
|
||||
// Reset counter for discarded memory in flight
|
||||
m_discardMemoryOnFlush = m_discardMemoryCounter;
|
||||
|
||||
// Notify the device that the context has been flushed,
|
||||
// this resets some resource initialization heuristics.
|
||||
m_parent->NotifyContextFlush();
|
||||
|
||||
// No point in tracking this across submissions
|
||||
m_hasPendingMsaaResolve = false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void D3D11ImmediateContext::ThrottleAllocation() {
|
||||
DxvkStagingBufferStats stats = GetStagingMemoryStatistics();
|
||||
|
||||
VkDeviceSize stagingMemoryInFlight = stats.allocatedTotal - m_stagingBufferFence->value();
|
||||
|
||||
if (stagingMemoryInFlight > stats.allocatedSinceLastReset + D3D11Initializer::MaxMemoryInFlight) {
|
||||
// Stall calling thread to avoid situation where we keep growing the staging
|
||||
// buffer indefinitely, but ignore the newly allocated amount so that we don't
|
||||
// wait for the GPU to go fully idle in case of a large allocation.
|
||||
ExecuteFlush(GpuFlushType::ExplicitFlush, nullptr, false);
|
||||
|
||||
m_device->waitForFence(*m_stagingBufferFence, stats.allocatedTotal -
|
||||
stats.allocatedSinceLastReset - D3D11Initializer::MaxMemoryInFlight);
|
||||
} else if (stats.allocatedSinceLastReset >= D3D11Initializer::MaxMemoryPerSubmission) {
|
||||
// Flush somewhat aggressively if there's a lot of memory in flight
|
||||
ExecuteFlush(GpuFlushType::ExplicitFlush, nullptr, false);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void D3D11ImmediateContext::ThrottleDiscard(
|
||||
VkDeviceSize Size) {
|
||||
m_discardMemoryCounter += Size;
|
||||
|
||||
if (m_discardMemoryCounter - m_discardMemoryOnFlush >= D3D11Initializer::MaxMemoryPerSubmission)
|
||||
ThrottleAllocation();
|
||||
}
|
||||
|
||||
|
||||
DxvkStagingBufferStats D3D11ImmediateContext::GetStagingMemoryStatistics() {
|
||||
DxvkStagingBufferStats stats = m_staging.getStatistics();
|
||||
stats.allocatedTotal += m_discardMemoryCounter;
|
||||
stats.allocatedSinceLastReset += m_discardMemoryCounter - m_discardMemoryOnFlush;
|
||||
return stats;
|
||||
}
|
||||
|
||||
|
||||
GpuFlushType D3D11ImmediateContext::GetMaxFlushType(
|
||||
D3D11Device* pParent,
|
||||
const Rc<DxvkDevice>& Device) {
|
||||
if (pParent->GetOptions()->reproducibleCommandStream)
|
||||
return GpuFlushType::ExplicitFlush;
|
||||
else if (Device->perfHints().preferRenderPassOps)
|
||||
return GpuFlushType::ImplicitMediumHint;
|
||||
else
|
||||
return GpuFlushType::ImplicitWeakHint;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -89,10 +89,29 @@ namespace dxvk {
|
|||
void SynchronizeCsThread(
|
||||
uint64_t SequenceNumber);
|
||||
|
||||
D3D10Multithread& GetMultithread() {
|
||||
return m_multithread;
|
||||
}
|
||||
|
||||
D3D10DeviceLock LockContext() {
|
||||
return m_multithread.AcquireLock();
|
||||
}
|
||||
|
||||
void InjectCsChunk(
|
||||
DxvkCsQueue Queue,
|
||||
DxvkCsChunkRef&& Chunk,
|
||||
bool Synchronize);
|
||||
|
||||
template<typename Fn>
|
||||
void InjectCs(
|
||||
DxvkCsQueue Queue,
|
||||
Fn&& Command) {
|
||||
auto chunk = AllocCsChunk();
|
||||
chunk->push(std::move(Command));
|
||||
|
||||
InjectCsChunk(Queue, std::move(chunk), false);
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
DxvkCsThread m_csThread;
|
||||
|
@ -100,8 +119,6 @@ namespace dxvk {
|
|||
|
||||
uint32_t m_mappedImageCount = 0u;
|
||||
|
||||
VkDeviceSize m_maxImplicitDiscardSize = 0ull;
|
||||
|
||||
Rc<sync::CallbackFence> m_submissionFence;
|
||||
uint64_t m_submissionId = 0ull;
|
||||
DxvkSubmitStatus m_submitStatus;
|
||||
|
@ -109,11 +126,20 @@ namespace dxvk {
|
|||
uint64_t m_flushSeqNum = 0ull;
|
||||
GpuFlushTracker m_flushTracker;
|
||||
|
||||
Rc<sync::Fence> m_stagingBufferFence;
|
||||
|
||||
VkDeviceSize m_discardMemoryCounter = 0u;
|
||||
VkDeviceSize m_discardMemoryOnFlush = 0u;
|
||||
|
||||
bool m_hasPendingMsaaResolve = false;
|
||||
|
||||
D3D10Multithread m_multithread;
|
||||
D3D11VideoContext m_videoContext;
|
||||
|
||||
Com<D3D11DeviceContextState, false> m_stateObject;
|
||||
|
||||
|
||||
std::string m_flushReason;
|
||||
|
||||
HRESULT MapBuffer(
|
||||
D3D11Buffer* pResource,
|
||||
D3D11_MAP MapType,
|
||||
|
@ -149,10 +175,11 @@ namespace dxvk {
|
|||
|
||||
void SynchronizeDevice();
|
||||
|
||||
void EndFrame();
|
||||
void EndFrame(
|
||||
Rc<DxvkLatencyTracker> LatencyTracker);
|
||||
|
||||
bool WaitForResource(
|
||||
const Rc<DxvkResource>& Resource,
|
||||
const DxvkPagedResource& Resource,
|
||||
uint64_t SequenceNumber,
|
||||
D3D11_MAP MapType,
|
||||
UINT MapFlags);
|
||||
|
@ -170,6 +197,8 @@ namespace dxvk {
|
|||
|
||||
uint64_t GetPendingCsChunks();
|
||||
|
||||
void ApplyDirtyNullBindings();
|
||||
|
||||
void ConsiderFlush(
|
||||
GpuFlushType FlushType);
|
||||
|
||||
|
@ -178,6 +207,17 @@ namespace dxvk {
|
|||
HANDLE hEvent,
|
||||
BOOL Synchronize);
|
||||
|
||||
void ThrottleAllocation();
|
||||
|
||||
void ThrottleDiscard(
|
||||
VkDeviceSize Size);
|
||||
|
||||
DxvkStagingBufferStats GetStagingMemoryStatistics();
|
||||
|
||||
static GpuFlushType GetMaxFlushType(
|
||||
D3D11Device* pParent,
|
||||
const Rc<DxvkDevice>& Device);
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -199,10 +199,11 @@ namespace dxvk {
|
|||
UINT stencilRef = D3D11_DEFAULT_STENCIL_REFERENCE;
|
||||
|
||||
UINT maxRtv = 0u;
|
||||
UINT minUav = D3D11_1_UAV_SLOT_COUNT;
|
||||
UINT maxUav = 0u;
|
||||
|
||||
void reset() {
|
||||
for (uint32_t i = 0; i < maxUav; i++)
|
||||
for (uint32_t i = minUav; i < maxUav; i++)
|
||||
uavs[i] = nullptr;
|
||||
|
||||
for (uint32_t i = 0; i < maxRtv; i++)
|
||||
|
@ -220,8 +221,9 @@ namespace dxvk {
|
|||
sampleMask = D3D11_DEFAULT_SAMPLE_MASK;
|
||||
stencilRef = D3D11_DEFAULT_STENCIL_REFERENCE;
|
||||
|
||||
maxRtv = 0;
|
||||
maxUav = 0;
|
||||
maxRtv = 0u;
|
||||
minUav = D3D11_1_UAV_SLOT_COUNT;
|
||||
maxUav = 0u;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -232,12 +234,12 @@ namespace dxvk {
|
|||
* argument and draw count buffer.
|
||||
*/
|
||||
struct D3D11ContextStateID {
|
||||
Com<D3D11Buffer, false> argBuffer = nullptr;
|
||||
Com<D3D11Buffer, false> cntBuffer = nullptr;
|
||||
uint64_t argBufferCookie = 0u;
|
||||
uint64_t cntBufferCookie = 0u;
|
||||
|
||||
void reset() {
|
||||
argBuffer = nullptr;
|
||||
cntBuffer = nullptr;
|
||||
argBufferCookie = 0u;
|
||||
cntBufferCookie = 0u;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -302,6 +304,32 @@ namespace dxvk {
|
|||
predicateValue = false;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* \brief Lazy binding state
|
||||
*
|
||||
* Keeps track of what state needs to be
|
||||
* re-applied to the context.
|
||||
*/
|
||||
struct D3D11LazyBindings {
|
||||
DxbcProgramTypeFlags shadersUsed = 0u;
|
||||
DxbcProgramTypeFlags shadersDirty = 0u;
|
||||
DxbcProgramTypeFlags graphicsUavShaders = 0u;
|
||||
|
||||
D3D11ShaderStageState<DxbcBindingMask> bindingsUsed;
|
||||
D3D11ShaderStageState<DxbcBindingMask> bindingsDirty;
|
||||
|
||||
void reset() {
|
||||
shadersUsed = 0u;
|
||||
shadersDirty = 0u;
|
||||
graphicsUavShaders = 0u;
|
||||
|
||||
bindingsUsed.reset();
|
||||
bindingsDirty.reset();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* \brief Context state
|
||||
|
@ -325,6 +353,8 @@ namespace dxvk {
|
|||
D3D11SrvBindings srv;
|
||||
D3D11UavBindings uav;
|
||||
D3D11SamplerBindings samplers;
|
||||
|
||||
D3D11LazyBindings lazy;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -342,9 +372,9 @@ namespace dxvk {
|
|||
* \brief Maximum used binding numbers for all context state
|
||||
*/
|
||||
struct D3D11MaxUsedBindings {
|
||||
std::array<D3D11MaxUsedStageBindings, 6> stages;
|
||||
std::array<D3D11MaxUsedStageBindings, uint32_t(DxbcProgramType::Count)> stages;
|
||||
uint32_t vbCount;
|
||||
uint32_t soCount;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,7 +3,8 @@
|
|||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "../dxvk/dxvk_resource.h"
|
||||
#include "../dxvk/dxvk_memory.h"
|
||||
#include "../dxvk/dxvk_sparse.h"
|
||||
|
||||
#include "../util/com/com_guid.h"
|
||||
#include "../util/com/com_object.h"
|
||||
|
|
|
@ -45,10 +45,10 @@ namespace dxvk {
|
|||
m_dxvkDevice (pContainer->GetDXVKDevice()),
|
||||
m_dxvkAdapter (m_dxvkDevice->adapter()),
|
||||
m_d3d11Formats (m_dxvkDevice),
|
||||
m_d3d11Options (m_dxvkDevice->instance()->config(), m_dxvkDevice),
|
||||
m_d3d11Options (m_dxvkDevice->instance()->config()),
|
||||
m_dxbcOptions (m_dxvkDevice, m_d3d11Options),
|
||||
m_maxFeatureLevel (GetMaxFeatureLevel(m_dxvkDevice->instance(), m_dxvkDevice->adapter())),
|
||||
m_deviceFeatures (m_dxvkDevice->instance(), m_dxvkDevice->adapter(), m_featureLevel) {
|
||||
m_deviceFeatures (m_dxvkDevice->instance(), m_dxvkDevice->adapter(), m_d3d11Options, m_featureLevel) {
|
||||
m_initializer = new D3D11Initializer(this);
|
||||
m_context = new D3D11ImmediateContext(this, m_dxvkDevice);
|
||||
m_d3d10Device = new D3D10Device(this, m_context.ptr());
|
||||
|
@ -183,7 +183,7 @@ namespace dxvk {
|
|||
desc.TextureLayout = D3D11_TEXTURE_LAYOUT_UNDEFINED;
|
||||
|
||||
ID3D11Texture2D1* texture2D = nullptr;
|
||||
HRESULT hr = CreateTexture2D1(&desc, pInitialData, ppTexture2D ? &texture2D : nullptr);
|
||||
HRESULT hr = CreateTexture2DBase(&desc, pInitialData, ppTexture2D ? &texture2D : nullptr);
|
||||
|
||||
if (hr != S_OK)
|
||||
return hr;
|
||||
|
@ -202,6 +202,14 @@ namespace dxvk {
|
|||
if (!pDesc)
|
||||
return E_INVALIDARG;
|
||||
|
||||
return CreateTexture2DBase(pDesc, pInitialData, ppTexture2D);
|
||||
}
|
||||
|
||||
|
||||
HRESULT STDMETHODCALLTYPE D3D11Device::CreateTexture2DBase(
|
||||
const D3D11_TEXTURE2D_DESC1* pDesc,
|
||||
const D3D11_SUBRESOURCE_DATA* pInitialData,
|
||||
ID3D11Texture2D1** ppTexture2D) {
|
||||
D3D11_COMMON_TEXTURE_DESC desc;
|
||||
desc.Width = pDesc->Width;
|
||||
desc.Height = pDesc->Height;
|
||||
|
@ -262,7 +270,7 @@ namespace dxvk {
|
|||
desc.TextureLayout = D3D11_TEXTURE_LAYOUT_UNDEFINED;
|
||||
|
||||
ID3D11Texture3D1* texture3D = nullptr;
|
||||
HRESULT hr = CreateTexture3D1(&desc, pInitialData, ppTexture3D ? &texture3D : nullptr);
|
||||
HRESULT hr = CreateTexture3DBase(&desc, pInitialData, ppTexture3D ? &texture3D : nullptr);
|
||||
|
||||
if (hr != S_OK)
|
||||
return hr;
|
||||
|
@ -280,7 +288,15 @@ namespace dxvk {
|
|||
|
||||
if (!pDesc)
|
||||
return E_INVALIDARG;
|
||||
|
||||
|
||||
return CreateTexture3DBase(pDesc, pInitialData, ppTexture3D);
|
||||
}
|
||||
|
||||
|
||||
HRESULT STDMETHODCALLTYPE D3D11Device::CreateTexture3DBase(
|
||||
const D3D11_TEXTURE3D_DESC1* pDesc,
|
||||
const D3D11_SUBRESOURCE_DATA* pInitialData,
|
||||
ID3D11Texture3D1** ppTexture3D) {
|
||||
D3D11_COMMON_TEXTURE_DESC desc;
|
||||
desc.Width = pDesc->Width;
|
||||
desc.Height = pDesc->Height;
|
||||
|
@ -325,6 +341,9 @@ namespace dxvk {
|
|||
ID3D11ShaderResourceView** ppSRView) {
|
||||
InitReturnPtr(ppSRView);
|
||||
|
||||
if (!pResource)
|
||||
return E_INVALIDARG;
|
||||
|
||||
uint32_t plane = GetViewPlaneIndex(pResource, pDesc ? pDesc->Format : DXGI_FORMAT_UNKNOWN);
|
||||
|
||||
D3D11_SHADER_RESOURCE_VIEW_DESC1 desc = pDesc
|
||||
|
@ -333,7 +352,7 @@ namespace dxvk {
|
|||
|
||||
ID3D11ShaderResourceView1* view = nullptr;
|
||||
|
||||
HRESULT hr = CreateShaderResourceView1(pResource,
|
||||
HRESULT hr = CreateShaderResourceViewBase(pResource,
|
||||
pDesc ? &desc : nullptr,
|
||||
ppSRView ? &view : nullptr);
|
||||
|
||||
|
@ -353,7 +372,15 @@ namespace dxvk {
|
|||
|
||||
if (!pResource)
|
||||
return E_INVALIDARG;
|
||||
|
||||
|
||||
return CreateShaderResourceViewBase(pResource, pDesc, ppSRView);
|
||||
}
|
||||
|
||||
|
||||
HRESULT STDMETHODCALLTYPE D3D11Device::CreateShaderResourceViewBase(
|
||||
ID3D11Resource* pResource,
|
||||
const D3D11_SHADER_RESOURCE_VIEW_DESC1* pDesc,
|
||||
ID3D11ShaderResourceView1** ppSRView) {
|
||||
D3D11_COMMON_RESOURCE_DESC resourceDesc;
|
||||
GetCommonResourceDesc(pResource, &resourceDesc);
|
||||
|
||||
|
@ -402,21 +429,24 @@ namespace dxvk {
|
|||
ID3D11UnorderedAccessView** ppUAView) {
|
||||
InitReturnPtr(ppUAView);
|
||||
|
||||
if (!pResource)
|
||||
return E_INVALIDARG;
|
||||
|
||||
uint32_t plane = GetViewPlaneIndex(pResource, pDesc ? pDesc->Format : DXGI_FORMAT_UNKNOWN);
|
||||
|
||||
D3D11_UNORDERED_ACCESS_VIEW_DESC1 desc = pDesc
|
||||
? D3D11UnorderedAccessView::PromoteDesc(pDesc, plane)
|
||||
: D3D11_UNORDERED_ACCESS_VIEW_DESC1();
|
||||
|
||||
|
||||
ID3D11UnorderedAccessView1* view = nullptr;
|
||||
|
||||
HRESULT hr = CreateUnorderedAccessView1(pResource,
|
||||
HRESULT hr = CreateUnorderedAccessViewBase(pResource,
|
||||
pDesc ? &desc : nullptr,
|
||||
ppUAView ? &view : nullptr);
|
||||
|
||||
|
||||
if (hr != S_OK)
|
||||
return hr;
|
||||
|
||||
|
||||
*ppUAView = view;
|
||||
return S_OK;
|
||||
}
|
||||
|
@ -430,7 +460,15 @@ namespace dxvk {
|
|||
|
||||
if (!pResource)
|
||||
return E_INVALIDARG;
|
||||
|
||||
|
||||
return CreateUnorderedAccessViewBase(pResource, pDesc, ppUAView);
|
||||
}
|
||||
|
||||
|
||||
HRESULT STDMETHODCALLTYPE D3D11Device::CreateUnorderedAccessViewBase(
|
||||
ID3D11Resource* pResource,
|
||||
const D3D11_UNORDERED_ACCESS_VIEW_DESC1* pDesc,
|
||||
ID3D11UnorderedAccessView1** ppUAView) {
|
||||
D3D11_COMMON_RESOURCE_DESC resourceDesc;
|
||||
GetCommonResourceDesc(pResource, &resourceDesc);
|
||||
|
||||
|
@ -481,6 +519,9 @@ namespace dxvk {
|
|||
ID3D11RenderTargetView** ppRTView) {
|
||||
InitReturnPtr(ppRTView);
|
||||
|
||||
if (!pResource)
|
||||
return E_INVALIDARG;
|
||||
|
||||
uint32_t plane = GetViewPlaneIndex(pResource, pDesc ? pDesc->Format : DXGI_FORMAT_UNKNOWN);
|
||||
|
||||
D3D11_RENDER_TARGET_VIEW_DESC1 desc = pDesc
|
||||
|
@ -489,7 +530,7 @@ namespace dxvk {
|
|||
|
||||
ID3D11RenderTargetView1* view = nullptr;
|
||||
|
||||
HRESULT hr = CreateRenderTargetView1(pResource,
|
||||
HRESULT hr = CreateRenderTargetViewBase(pResource,
|
||||
pDesc ? &desc : nullptr,
|
||||
ppRTView ? &view : nullptr);
|
||||
|
||||
|
@ -509,7 +550,15 @@ namespace dxvk {
|
|||
|
||||
if (!pResource)
|
||||
return E_INVALIDARG;
|
||||
|
||||
|
||||
return CreateRenderTargetViewBase(pResource, pDesc, ppRTView);
|
||||
}
|
||||
|
||||
|
||||
HRESULT STDMETHODCALLTYPE D3D11Device::CreateRenderTargetViewBase(
|
||||
ID3D11Resource* pResource,
|
||||
const D3D11_RENDER_TARGET_VIEW_DESC1* pDesc,
|
||||
ID3D11RenderTargetView1** ppRTView) {
|
||||
// DXVK only supports render target views for image resources
|
||||
D3D11_COMMON_RESOURCE_DESC resourceDesc;
|
||||
GetCommonResourceDesc(pResource, &resourceDesc);
|
||||
|
@ -1202,7 +1251,7 @@ namespace dxvk {
|
|||
desc.ContextType = D3D11_CONTEXT_TYPE_ALL;
|
||||
|
||||
ID3D11Query1* query = nullptr;
|
||||
HRESULT hr = CreateQuery1(&desc, ppQuery ? &query : nullptr);
|
||||
HRESULT hr = CreateQueryBase(&desc, ppQuery ? &query : nullptr);
|
||||
|
||||
if (hr != S_OK)
|
||||
return hr;
|
||||
|
@ -1219,7 +1268,14 @@ namespace dxvk {
|
|||
|
||||
if (!pQueryDesc)
|
||||
return E_INVALIDARG;
|
||||
|
||||
|
||||
return CreateQueryBase(pQueryDesc, ppQuery);
|
||||
}
|
||||
|
||||
|
||||
HRESULT STDMETHODCALLTYPE D3D11Device::CreateQueryBase(
|
||||
const D3D11_QUERY_DESC1* pQueryDesc,
|
||||
ID3D11Query1** ppQuery) {
|
||||
HRESULT hr = D3D11Query::ValidateDesc(pQueryDesc);
|
||||
|
||||
if (FAILED(hr))
|
||||
|
@ -1348,7 +1404,7 @@ namespace dxvk {
|
|||
m_deviceFeatures = D3D11DeviceFeatures(
|
||||
m_dxvkDevice->instance(),
|
||||
m_dxvkDevice->adapter(),
|
||||
m_featureLevel);
|
||||
m_d3d11Options, m_featureLevel);
|
||||
}
|
||||
|
||||
if (pChosenFeatureLevel)
|
||||
|
@ -1396,10 +1452,10 @@ namespace dxvk {
|
|||
|| texture->CountSubresources() <= SrcSubresource)
|
||||
return;
|
||||
|
||||
D3D11_MAP map = texture->GetMapType(SrcSubresource);
|
||||
uint32_t map = texture->GetMapType(SrcSubresource);
|
||||
|
||||
if (map != D3D11_MAP_READ
|
||||
&& map != D3D11_MAP_READ_WRITE)
|
||||
if (map != uint32_t(D3D11_MAP_READ)
|
||||
&& map != uint32_t(D3D11_MAP_READ_WRITE))
|
||||
return;
|
||||
|
||||
CopySubresourceData(
|
||||
|
@ -1425,11 +1481,11 @@ namespace dxvk {
|
|||
|| texture->CountSubresources() <= DstSubresource)
|
||||
return;
|
||||
|
||||
D3D11_MAP map = texture->GetMapType(DstSubresource);
|
||||
uint32_t map = texture->GetMapType(DstSubresource);
|
||||
|
||||
if (map != D3D11_MAP_WRITE
|
||||
&& map != D3D11_MAP_WRITE_NO_OVERWRITE
|
||||
&& map != D3D11_MAP_READ_WRITE)
|
||||
if (map != uint32_t(D3D11_MAP_WRITE)
|
||||
&& map != uint32_t(D3D11_MAP_WRITE_NO_OVERWRITE)
|
||||
&& map != uint32_t(D3D11_MAP_READ_WRITE))
|
||||
return;
|
||||
|
||||
CopySubresourceData(
|
||||
|
@ -1839,11 +1895,6 @@ namespace dxvk {
|
|||
}
|
||||
|
||||
|
||||
void D3D11Device::FlushInitContext() {
|
||||
m_initializer->Flush();
|
||||
}
|
||||
|
||||
|
||||
D3D_FEATURE_LEVEL D3D11Device::GetMaxFeatureLevel(
|
||||
const Rc<DxvkInstance>& Instance,
|
||||
const Rc<DxvkAdapter>& Adapter) {
|
||||
|
@ -1905,8 +1956,6 @@ namespace dxvk {
|
|||
enabled.core.features.shaderImageGatherExtended = VK_TRUE;
|
||||
enabled.core.features.textureCompressionBC = VK_TRUE;
|
||||
|
||||
enabled.vk11.shaderDrawParameters = VK_TRUE;
|
||||
|
||||
enabled.vk12.samplerMirrorClampToEdge = VK_TRUE;
|
||||
|
||||
enabled.vk13.shaderDemoteToHelperInvocation = VK_TRUE;
|
||||
|
@ -1923,7 +1972,6 @@ namespace dxvk {
|
|||
// Required for Feature Level 11_0
|
||||
enabled.core.features.drawIndirectFirstInstance = supported.core.features.drawIndirectFirstInstance;
|
||||
enabled.core.features.fragmentStoresAndAtomics = supported.core.features.fragmentStoresAndAtomics;
|
||||
enabled.core.features.multiDrawIndirect = supported.core.features.multiDrawIndirect;
|
||||
enabled.core.features.tessellationShader = supported.core.features.tessellationShader;
|
||||
|
||||
// Required for Feature Level 11_1
|
||||
|
@ -1969,6 +2017,9 @@ namespace dxvk {
|
|||
size_t BytecodeLength,
|
||||
ID3D11ClassLinkage* pClassLinkage,
|
||||
const DxbcModuleInfo* pModuleInfo) {
|
||||
if (!BytecodeLength || !pShaderBytecode)
|
||||
return E_INVALIDARG;
|
||||
|
||||
if (pClassLinkage != nullptr)
|
||||
Logger::warn("D3D11Device::CreateShaderModule: Class linkage not supported");
|
||||
|
||||
|
@ -2384,11 +2435,7 @@ namespace dxvk {
|
|||
D3D11_COMMON_TEXTURE_SUBRESOURCE_LAYOUT layout = pTexture->GetSubresourceLayout(aspect, Subresource);
|
||||
|
||||
// Compute actual map pointer, accounting for the region offset
|
||||
VkDeviceSize mapOffset = pTexture->ComputeMappedOffset(Subresource, i, offset);
|
||||
|
||||
void* mapPtr = pTexture->GetMapMode() == D3D11_COMMON_TEXTURE_MAP_MODE_BUFFER
|
||||
? pTexture->GetMappedBuffer(Subresource)->mapPtr(mapOffset)
|
||||
: image->mapPtr(mapOffset);
|
||||
void* mapPtr = pTexture->GetMapPtr(Subresource, pTexture->ComputeMappedOffset(Subresource, i, offset));
|
||||
|
||||
if constexpr (std::is_const<Void>::value) {
|
||||
// WriteToSubresource
|
||||
|
@ -2492,15 +2539,15 @@ namespace dxvk {
|
|||
|
||||
D3D11SamplerState* pSS = static_cast<D3D11SamplerState*>(samplerState);
|
||||
Rc<DxvkSampler> pDSS = pSS->GetDXVKSampler();
|
||||
VkSampler vkSampler = pDSS->handle();
|
||||
|
||||
D3D11ShaderResourceView* pSRV = static_cast<D3D11ShaderResourceView*>(srv);
|
||||
Rc<DxvkImageView> pIV = pSRV->GetImageView();
|
||||
VkImageView vkImageView = pIV->handle();
|
||||
|
||||
VkImageViewHandleInfoNVX imageViewHandleInfo = {VK_STRUCTURE_TYPE_IMAGE_VIEW_HANDLE_INFO_NVX};
|
||||
imageViewHandleInfo.imageView = vkImageView;
|
||||
imageViewHandleInfo.sampler = vkSampler;
|
||||
LockImage(pIV->image(), 0u);
|
||||
|
||||
VkImageViewHandleInfoNVX imageViewHandleInfo = { VK_STRUCTURE_TYPE_IMAGE_VIEW_HANDLE_INFO_NVX };
|
||||
imageViewHandleInfo.imageView = pIV->handle();
|
||||
imageViewHandleInfo.sampler = pDSS->handle();
|
||||
imageViewHandleInfo.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
|
||||
|
||||
// note: there's no implicit lifetime management here; it's up to the
|
||||
|
@ -2558,21 +2605,9 @@ namespace dxvk {
|
|||
ID3D11Resource* pResource = static_cast<ID3D11Resource*>(hObject);
|
||||
|
||||
D3D11_COMMON_RESOURCE_DESC resourceDesc;
|
||||
if (FAILED(GetCommonResourceDesc(pResource, &resourceDesc))) {
|
||||
Logger::warn("GetResourceHandleGPUVirtualAddressAndSize() - GetCommonResourceDesc() failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (resourceDesc.Dim) {
|
||||
case D3D11_RESOURCE_DIMENSION_BUFFER:
|
||||
case D3D11_RESOURCE_DIMENSION_TEXTURE2D:
|
||||
// okay - we can deal with those two dimensions
|
||||
break;
|
||||
case D3D11_RESOURCE_DIMENSION_TEXTURE1D:
|
||||
case D3D11_RESOURCE_DIMENSION_TEXTURE3D:
|
||||
case D3D11_RESOURCE_DIMENSION_UNKNOWN:
|
||||
default:
|
||||
Logger::warn(str::format("GetResourceHandleGPUVirtualAddressAndSize(?) - failure - unsupported dimension: ", resourceDesc.Dim));
|
||||
if (FAILED(GetCommonResourceDesc(pResource, &resourceDesc))) {
|
||||
Logger::warn("GetResourceHandleGPUVirtualAddressAndSize: Invalid resource");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -2581,57 +2616,49 @@ namespace dxvk {
|
|||
|
||||
if (resourceDesc.Dim == D3D11_RESOURCE_DIMENSION_TEXTURE2D) {
|
||||
D3D11CommonTexture *texture = GetCommonTexture(pResource);
|
||||
|
||||
// Ensure that the image has a stable GPU address and
|
||||
// won't be relocated by the backend going forward
|
||||
Rc<DxvkImage> dxvkImage = texture->GetImage();
|
||||
if (0 == (dxvkImage->info().usage & (VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_SAMPLED_BIT))) {
|
||||
Logger::warn(str::format("GetResourceHandleGPUVirtualAddressAndSize(res=", pResource,") image info missing required usage bit(s); can't be used for vkGetImageViewHandleNVX - failure"));
|
||||
|
||||
if (!LockImage(dxvkImage, VK_IMAGE_USAGE_SAMPLED_BIT))
|
||||
return false;
|
||||
}
|
||||
|
||||
// The d3d11 nvapi provides us a texture but vulkan only lets us get the GPU address from an imageview. So, make a private imageview and get the address from that...
|
||||
// The d3d11 nvapi provides us a texture, but vulkan only lets us
|
||||
// get the GPU address from an image view. So, make a private image
|
||||
// view and get the address from that.
|
||||
DxvkImageViewKey viewInfo;
|
||||
viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
|
||||
viewInfo.format = dxvkImage->info().format;
|
||||
viewInfo.aspects = dxvkImage->formatInfo()->aspectMask;
|
||||
viewInfo.mipIndex = 0;
|
||||
viewInfo.mipCount = dxvkImage->info().mipLevels;
|
||||
viewInfo.layerIndex = 0;
|
||||
viewInfo.layerCount = 1;
|
||||
viewInfo.usage = VK_IMAGE_USAGE_SAMPLED_BIT;
|
||||
|
||||
D3D11_SHADER_RESOURCE_VIEW_DESC resourceViewDesc;
|
||||
auto dxvkView = dxvkImage->createView(viewInfo);
|
||||
VkImageViewAddressPropertiesNVX imageViewAddressProperties = { VK_STRUCTURE_TYPE_IMAGE_VIEW_ADDRESS_PROPERTIES_NVX };
|
||||
|
||||
const D3D11_COMMON_TEXTURE_DESC *texDesc = texture->Desc();
|
||||
if (texDesc->ArraySize != 1) {
|
||||
Logger::debug(str::format("GetResourceHandleGPUVirtualAddressAndSize(?) - unexpected array size: ", texDesc->ArraySize));
|
||||
}
|
||||
resourceViewDesc.Format = texDesc->Format;
|
||||
resourceViewDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
|
||||
resourceViewDesc.Texture2D.MostDetailedMip = 0;
|
||||
resourceViewDesc.Texture2D.MipLevels = texDesc->MipLevels;
|
||||
VkResult vr = dxvkDevice->vkd()->vkGetImageViewAddressNVX(vkDevice,
|
||||
dxvkView->handle(), &imageViewAddressProperties);
|
||||
|
||||
Com<ID3D11ShaderResourceView> pNewSRV;
|
||||
HRESULT hr = m_device->CreateShaderResourceView(pResource, &resourceViewDesc, &pNewSRV);
|
||||
if (FAILED(hr)) {
|
||||
Logger::warn("GetResourceHandleGPUVirtualAddressAndSize() - private CreateShaderResourceView() failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
Rc<DxvkImageView> dxvkImageView = static_cast<D3D11ShaderResourceView*>(pNewSRV.ptr())->GetImageView();
|
||||
VkImageView vkImageView = dxvkImageView->handle();
|
||||
|
||||
VkImageViewAddressPropertiesNVX imageViewAddressProperties = {VK_STRUCTURE_TYPE_IMAGE_VIEW_ADDRESS_PROPERTIES_NVX};
|
||||
|
||||
VkResult res = dxvkDevice->vkd()->vkGetImageViewAddressNVX(vkDevice, vkImageView, &imageViewAddressProperties);
|
||||
if (res != VK_SUCCESS) {
|
||||
Logger::warn(str::format("GetResourceHandleGPUVirtualAddressAndSize(): vkGetImageViewAddressNVX() result is failure: ", res));
|
||||
if (vr != VK_SUCCESS) {
|
||||
Logger::warn(str::format("GetResourceHandleGPUVirtualAddressAndSize(): Failed: vr = ", vr));
|
||||
return false;
|
||||
}
|
||||
|
||||
*gpuVAStart = imageViewAddressProperties.deviceAddress;
|
||||
*gpuVASize = imageViewAddressProperties.size;
|
||||
}
|
||||
else if (resourceDesc.Dim == D3D11_RESOURCE_DIMENSION_BUFFER) {
|
||||
D3D11Buffer *buffer = GetCommonBuffer(pResource);
|
||||
const DxvkBufferSliceHandle bufSliceHandle = buffer->GetBuffer()->getSliceHandle();
|
||||
VkBuffer vkBuffer = bufSliceHandle.handle;
|
||||
} else if (resourceDesc.Dim == D3D11_RESOURCE_DIMENSION_BUFFER) {
|
||||
Rc<DxvkBuffer> dxvkBuffer = GetCommonBuffer(pResource)->GetBuffer();
|
||||
LockBuffer(dxvkBuffer);
|
||||
|
||||
VkBufferDeviceAddressInfo bdaInfo = { VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO };
|
||||
bdaInfo.buffer = vkBuffer;
|
||||
|
||||
VkDeviceAddress bufAddr = dxvkDevice->vkd()->vkGetBufferDeviceAddress(vkDevice, &bdaInfo);
|
||||
*gpuVAStart = uint64_t(bufAddr) + bufSliceHandle.offset;
|
||||
*gpuVASize = bufSliceHandle.length;
|
||||
*gpuVAStart = dxvkBuffer->gpuAddress();
|
||||
*gpuVASize = dxvkBuffer->info().size;
|
||||
} else {
|
||||
Logger::warn(str::format("GetResourceHandleGPUVirtualAddressAndSize(): Unsupported resource type: ", resourceDesc.Dim));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!*gpuVAStart)
|
||||
|
@ -2641,102 +2668,99 @@ namespace dxvk {
|
|||
}
|
||||
|
||||
|
||||
bool STDMETHODCALLTYPE D3D11DeviceExt::CreateUnorderedAccessViewAndGetDriverHandleNVX(ID3D11Resource* pResource, const D3D11_UNORDERED_ACCESS_VIEW_DESC* pDesc, ID3D11UnorderedAccessView** ppUAV, uint32_t* pDriverHandle) {
|
||||
D3D11_COMMON_RESOURCE_DESC resourceDesc;
|
||||
if (!SUCCEEDED(GetCommonResourceDesc(pResource, &resourceDesc))) {
|
||||
Logger::warn("CreateUnorderedAccessViewAndGetDriverHandleNVX() - GetCommonResourceDesc() failed");
|
||||
return false;
|
||||
}
|
||||
bool STDMETHODCALLTYPE D3D11DeviceExt::CreateUnorderedAccessViewAndGetDriverHandleNVX(
|
||||
ID3D11Resource* pResource,
|
||||
const D3D11_UNORDERED_ACCESS_VIEW_DESC* pDesc,
|
||||
ID3D11UnorderedAccessView** ppUAV,
|
||||
uint32_t* pDriverHandle) {
|
||||
D3D11_COMMON_RESOURCE_DESC resourceDesc = { };
|
||||
GetCommonResourceDesc(pResource, &resourceDesc);
|
||||
|
||||
if (resourceDesc.Dim != D3D11_RESOURCE_DIMENSION_TEXTURE2D) {
|
||||
Logger::warn(str::format("CreateUnorderedAccessViewAndGetDriverHandleNVX() - failure - unsupported dimension: ", resourceDesc.Dim));
|
||||
Logger::warn(str::format("CreateUnorderedAccessViewAndGetDriverHandleNVX(): Unsupported dimension: ", resourceDesc.Dim));
|
||||
return false;
|
||||
}
|
||||
|
||||
auto texture = GetCommonTexture(pResource);
|
||||
Rc<DxvkImage> dxvkImage = texture->GetImage();
|
||||
if (0 == (dxvkImage->info().usage & (VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_SAMPLED_BIT))) {
|
||||
Logger::warn(str::format("CreateUnorderedAccessViewAndGetDriverHandleNVX(res=", pResource, ") image info missing required usage bit(s); can't be used for vkGetImageViewHandleNVX - failure"));
|
||||
Rc<DxvkImage> dxvkImage = GetCommonTexture(pResource)->GetImage();
|
||||
|
||||
if (!(dxvkImage->info().usage & VK_IMAGE_USAGE_STORAGE_BIT)) {
|
||||
Logger::warn(str::format("CreateUnorderedAccessViewAndGetDriverHandleNVX(res=", pResource, "): Image not UAV compatible"));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!SUCCEEDED(m_device->CreateUnorderedAccessView(pResource, pDesc, ppUAV))) {
|
||||
return false;
|
||||
}
|
||||
Com<ID3D11UnorderedAccessView> uav;
|
||||
|
||||
D3D11UnorderedAccessView *pUAV = static_cast<D3D11UnorderedAccessView *>(*ppUAV);
|
||||
Rc<DxvkDevice> dxvkDevice = m_device->GetDXVKDevice();
|
||||
VkDevice vkDevice = dxvkDevice->handle();
|
||||
if (FAILED(m_device->CreateUnorderedAccessView(pResource, pDesc, &uav)))
|
||||
return false;
|
||||
|
||||
Rc<DxvkImageView> dxvkImageView = static_cast<D3D11UnorderedAccessView*>(uav.ptr())->GetImageView();
|
||||
LockImage(dxvkImageView->image(), 0u);
|
||||
|
||||
VkImageViewHandleInfoNVX imageViewHandleInfo = {VK_STRUCTURE_TYPE_IMAGE_VIEW_HANDLE_INFO_NVX};
|
||||
Rc<DxvkImageView> dxvkImageView = pUAV->GetImageView();
|
||||
VkImageView vkImageView = dxvkImageView->handle();
|
||||
|
||||
imageViewHandleInfo.imageView = vkImageView;
|
||||
imageViewHandleInfo.imageView = dxvkImageView->handle();
|
||||
imageViewHandleInfo.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE;
|
||||
|
||||
*pDriverHandle = dxvkDevice->vkd()->vkGetImageViewHandleNVX(vkDevice, &imageViewHandleInfo);
|
||||
Rc<DxvkDevice> dxvkDevice = m_device->GetDXVKDevice();
|
||||
*pDriverHandle = dxvkDevice->vkd()->vkGetImageViewHandleNVX(
|
||||
dxvkDevice->handle(), &imageViewHandleInfo);
|
||||
|
||||
if (!*pDriverHandle) {
|
||||
Logger::warn("CreateUnorderedAccessViewAndGetDriverHandleNVX() handle==0 - failure");
|
||||
pUAV->Release();
|
||||
Logger::warn("CreateUnorderedAccessViewAndGetDriverHandleNVX(): Handle is 0");
|
||||
return false;
|
||||
}
|
||||
|
||||
*ppUAV = uav.ref();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool STDMETHODCALLTYPE D3D11DeviceExt::CreateShaderResourceViewAndGetDriverHandleNVX(ID3D11Resource* pResource, const D3D11_SHADER_RESOURCE_VIEW_DESC* pDesc, ID3D11ShaderResourceView** ppSRV, uint32_t* pDriverHandle) {
|
||||
D3D11_COMMON_RESOURCE_DESC resourceDesc;
|
||||
if (!SUCCEEDED(GetCommonResourceDesc(pResource, &resourceDesc))) {
|
||||
Logger::warn("CreateShaderResourceViewAndGetDriverHandleNVX() - GetCommonResourceDesc() failed");
|
||||
return false;
|
||||
}
|
||||
D3D11_COMMON_RESOURCE_DESC resourceDesc = { };
|
||||
GetCommonResourceDesc(pResource, &resourceDesc);
|
||||
|
||||
if (resourceDesc.Dim != D3D11_RESOURCE_DIMENSION_TEXTURE2D) {
|
||||
Logger::warn(str::format("CreateShaderResourceViewAndGetDriverHandleNVX() - failure - unsupported dimension: ", resourceDesc.Dim));
|
||||
Logger::warn(str::format("CreateShaderResourceViewAndGetDriverHandleNVX(): Unsupported dimension: ", resourceDesc.Dim));
|
||||
return false;
|
||||
}
|
||||
|
||||
auto texture = GetCommonTexture(pResource);
|
||||
Rc<DxvkImage> dxvkImage = texture->GetImage();
|
||||
if (0 == (dxvkImage->info().usage & (VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_SAMPLED_BIT))) {
|
||||
Logger::warn(str::format("CreateShaderResourceViewAndGetDriverHandleNVX(res=", pResource, ") image info missing required usage bit(s); can't be used for vkGetImageViewHandleNVX - failure"));
|
||||
Rc<DxvkImage> dxvkImage = GetCommonTexture(pResource)->GetImage();
|
||||
|
||||
if (!(dxvkImage->info().usage & VK_IMAGE_USAGE_SAMPLED_BIT)) {
|
||||
Logger::warn(str::format("CreateShaderResourceViewAndGetDriverHandleNVX(res=", pResource, "): Image not SRV compatible"));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!SUCCEEDED(m_device->CreateShaderResourceView(pResource, pDesc, ppSRV))) {
|
||||
return false;
|
||||
}
|
||||
Com<ID3D11ShaderResourceView> srv;
|
||||
|
||||
D3D11ShaderResourceView* pSRV = static_cast<D3D11ShaderResourceView*>(*ppSRV);
|
||||
Rc<DxvkDevice> dxvkDevice = m_device->GetDXVKDevice();
|
||||
VkDevice vkDevice = dxvkDevice->handle();
|
||||
if (FAILED(m_device->CreateShaderResourceView(pResource, pDesc, &srv)))
|
||||
return false;
|
||||
|
||||
Rc<DxvkImageView> dxvkImageView = static_cast<D3D11ShaderResourceView*>(srv.ptr())->GetImageView();
|
||||
LockImage(dxvkImageView->image(), 0u);
|
||||
|
||||
VkImageViewHandleInfoNVX imageViewHandleInfo = {VK_STRUCTURE_TYPE_IMAGE_VIEW_HANDLE_INFO_NVX};
|
||||
Rc<DxvkImageView> dxvkImageView = pSRV->GetImageView();
|
||||
VkImageView vkImageView = dxvkImageView->handle();
|
||||
|
||||
imageViewHandleInfo.imageView = vkImageView;
|
||||
imageViewHandleInfo.imageView = dxvkImageView->handle();
|
||||
imageViewHandleInfo.descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE;
|
||||
|
||||
*pDriverHandle = dxvkDevice->vkd()->vkGetImageViewHandleNVX(vkDevice, &imageViewHandleInfo);
|
||||
Rc<DxvkDevice> dxvkDevice = m_device->GetDXVKDevice();
|
||||
*pDriverHandle = dxvkDevice->vkd()->vkGetImageViewHandleNVX(
|
||||
dxvkDevice->handle(), &imageViewHandleInfo);
|
||||
|
||||
if (!*pDriverHandle) {
|
||||
Logger::warn("CreateShaderResourceViewAndGetDriverHandleNVX() handle==0 - failure");
|
||||
pSRV->Release();
|
||||
Logger::warn("CreateShaderResourceViewAndGetDriverHandleNVX(): Handle is 0");
|
||||
return false;
|
||||
}
|
||||
|
||||
// will need to look-up resource from uint32 handle later
|
||||
AddSrvAndHandleNVX(*ppSRV, *pDriverHandle);
|
||||
*ppSRV = srv.ref();
|
||||
AddSrvAndHandleNVX(srv.ptr(), *pDriverHandle);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool STDMETHODCALLTYPE D3D11DeviceExt::CreateSamplerStateAndGetDriverHandleNVX(const D3D11_SAMPLER_DESC* pSamplerDesc, ID3D11SamplerState** ppSamplerState, uint32_t* pDriverHandle) {
|
||||
if (!SUCCEEDED(m_device->CreateSamplerState(pSamplerDesc, ppSamplerState))) {
|
||||
if (FAILED(m_device->CreateSamplerState(pSamplerDesc, ppSamplerState)))
|
||||
return false;
|
||||
}
|
||||
|
||||
// for our purposes the actual value doesn't matter, only its uniqueness
|
||||
static std::atomic<ULONG> s_seqNum = 0;
|
||||
|
@ -2782,8 +2806,57 @@ namespace dxvk {
|
|||
}
|
||||
|
||||
|
||||
bool D3D11DeviceExt::LockImage(
|
||||
const Rc<DxvkImage>& Image,
|
||||
VkImageUsageFlags Usage) {
|
||||
if (!Image->canRelocate() && (Image->info().usage & Usage))
|
||||
return true;
|
||||
|
||||
bool feedback = false;
|
||||
|
||||
auto chunk = m_device->AllocCsChunk(DxvkCsChunkFlag::SingleUse);
|
||||
|
||||
chunk->push([
|
||||
cImage = Image,
|
||||
cUsage = Usage,
|
||||
&feedback
|
||||
] (DxvkContext* ctx) {
|
||||
DxvkImageUsageInfo usageInfo;
|
||||
usageInfo.usage = cUsage;
|
||||
usageInfo.stableGpuAddress = VK_TRUE;
|
||||
|
||||
feedback = ctx->ensureImageCompatibility(cImage, usageInfo);
|
||||
});
|
||||
|
||||
m_device->GetContext()->InjectCsChunk(DxvkCsQueue::HighPriority, std::move(chunk), true);
|
||||
|
||||
if (!feedback) {
|
||||
Logger::err(str::format("Failed to lock image:"
|
||||
"\n Image format: ", Image->info().format,
|
||||
"\n Image usage: ", std::hex, Image->info().usage,
|
||||
"\n Desired usage: ", std::hex, Usage));
|
||||
}
|
||||
|
||||
return feedback;
|
||||
}
|
||||
|
||||
|
||||
void D3D11DeviceExt::LockBuffer(
|
||||
const Rc<DxvkBuffer>& Buffer) {
|
||||
if (!Buffer->canRelocate())
|
||||
return;
|
||||
|
||||
auto chunk = m_device->AllocCsChunk(DxvkCsChunkFlag::SingleUse);
|
||||
|
||||
chunk->push([cBuffer = Buffer] (DxvkContext* ctx) {
|
||||
ctx->ensureBufferAddress(cBuffer);
|
||||
});
|
||||
|
||||
m_device->GetContext()->InjectCsChunk(DxvkCsQueue::HighPriority, std::move(chunk), true);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
D3D11VideoDevice::D3D11VideoDevice(
|
||||
D3D11DXGIDevice* pContainer,
|
||||
|
@ -2985,6 +3058,198 @@ namespace dxvk {
|
|||
|
||||
|
||||
|
||||
D3D11ReflexDevice::D3D11ReflexDevice(
|
||||
D3D11DXGIDevice* pContainer,
|
||||
D3D11Device* pDevice)
|
||||
: m_container(pContainer), m_device(pDevice) {
|
||||
auto dxvkDevice = pDevice->GetDXVKDevice();
|
||||
|
||||
m_reflexEnabled = dxvkDevice->features().nvLowLatency2
|
||||
&& dxvkDevice->config().latencySleep == Tristate::Auto;
|
||||
}
|
||||
|
||||
|
||||
D3D11ReflexDevice::~D3D11ReflexDevice() {
|
||||
|
||||
}
|
||||
|
||||
|
||||
ULONG STDMETHODCALLTYPE D3D11ReflexDevice::AddRef() {
|
||||
return m_container->AddRef();
|
||||
}
|
||||
|
||||
|
||||
ULONG STDMETHODCALLTYPE D3D11ReflexDevice::Release() {
|
||||
return m_container->Release();
|
||||
}
|
||||
|
||||
|
||||
HRESULT STDMETHODCALLTYPE D3D11ReflexDevice::QueryInterface(
|
||||
REFIID riid,
|
||||
void** ppvObject) {
|
||||
return m_container->QueryInterface(riid, ppvObject);
|
||||
}
|
||||
|
||||
|
||||
BOOL STDMETHODCALLTYPE D3D11ReflexDevice::SupportsLowLatency() {
|
||||
return m_reflexEnabled;
|
||||
}
|
||||
|
||||
|
||||
HRESULT STDMETHODCALLTYPE D3D11ReflexDevice::LatencySleep() {
|
||||
if (!m_reflexEnabled)
|
||||
return DXGI_ERROR_INVALID_CALL;
|
||||
|
||||
// Don't keep object locked while sleeping
|
||||
Rc<DxvkReflexLatencyTrackerNv> tracker;
|
||||
|
||||
{ std::lock_guard lock(m_mutex);
|
||||
tracker = m_tracker;
|
||||
}
|
||||
|
||||
if (tracker)
|
||||
tracker->latencySleep();
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
HRESULT STDMETHODCALLTYPE D3D11ReflexDevice::SetLatencySleepMode(
|
||||
BOOL LowLatencyEnable,
|
||||
BOOL LowLatencyBoost,
|
||||
UINT32 MinIntervalUs) {
|
||||
if (!m_reflexEnabled)
|
||||
return DXGI_ERROR_INVALID_CALL;
|
||||
|
||||
std::lock_guard lock(m_mutex);
|
||||
|
||||
if (m_tracker) {
|
||||
m_tracker->setLatencySleepMode(
|
||||
LowLatencyEnable, LowLatencyBoost, MinIntervalUs);
|
||||
}
|
||||
|
||||
// Write back in case we have no swapchain yet
|
||||
m_enableLowLatency = LowLatencyEnable;
|
||||
m_enableBoost = LowLatencyBoost;
|
||||
m_minIntervalUs = MinIntervalUs;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
HRESULT STDMETHODCALLTYPE D3D11ReflexDevice::SetLatencyMarker(
|
||||
UINT64 FrameId,
|
||||
UINT32 MarkerType) {
|
||||
if (!m_reflexEnabled)
|
||||
return DXGI_ERROR_INVALID_CALL;
|
||||
|
||||
std::lock_guard lock(m_mutex);
|
||||
|
||||
if (m_tracker) {
|
||||
auto marker = VkLatencyMarkerNV(MarkerType);
|
||||
m_tracker->setLatencyMarker(FrameId, marker);
|
||||
|
||||
if (marker == VK_LATENCY_MARKER_RENDERSUBMIT_START_NV) {
|
||||
m_device->GetContext()->InjectCs(DxvkCsQueue::Ordered, [
|
||||
cTracker = m_tracker,
|
||||
cFrameId = FrameId
|
||||
] (DxvkContext* ctx) {
|
||||
uint64_t frameId = cTracker->frameIdFromAppFrameId(cFrameId);
|
||||
|
||||
if (frameId)
|
||||
ctx->beginLatencyTracking(cTracker, frameId);
|
||||
});
|
||||
} else if (marker == VK_LATENCY_MARKER_RENDERSUBMIT_END_NV) {
|
||||
m_device->GetContext()->InjectCs(DxvkCsQueue::Ordered, [
|
||||
cTracker = m_tracker
|
||||
] (DxvkContext* ctx) {
|
||||
ctx->endLatencyTracking(cTracker);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
HRESULT STDMETHODCALLTYPE D3D11ReflexDevice::GetLatencyInfo(
|
||||
D3D_LOW_LATENCY_RESULTS* pLowLatencyResults) {
|
||||
constexpr static size_t FrameCount = 64;
|
||||
|
||||
if (!pLowLatencyResults)
|
||||
return E_INVALIDARG;
|
||||
|
||||
for (size_t i = 0; i < FrameCount; i++)
|
||||
pLowLatencyResults->frameReports[i] = D3D_LOW_LATENCY_FRAME_REPORT();
|
||||
|
||||
if (!m_reflexEnabled)
|
||||
return DXGI_ERROR_INVALID_CALL;
|
||||
|
||||
std::lock_guard lock(m_mutex);
|
||||
|
||||
if (!m_tracker)
|
||||
return S_OK;
|
||||
|
||||
// Apparently we have to report all 64 frames, or nothing
|
||||
std::array<DxvkReflexFrameReport, FrameCount> reports = { };
|
||||
uint32_t reportCount = m_tracker->getFrameReports(FrameCount, reports.data());
|
||||
|
||||
if (reportCount < FrameCount)
|
||||
return S_OK;
|
||||
|
||||
for (uint32_t i = 0; i < FrameCount; i++) {
|
||||
auto& src = reports[i];
|
||||
auto& dst = pLowLatencyResults->frameReports[i];
|
||||
|
||||
dst.frameID = src.report.presentID;
|
||||
dst.inputSampleTime = src.report.inputSampleTimeUs;
|
||||
dst.simStartTime = src.report.simStartTimeUs;
|
||||
dst.simEndTime = src.report.simEndTimeUs;
|
||||
dst.renderSubmitStartTime = src.report.renderSubmitStartTimeUs;
|
||||
dst.renderSubmitEndTime = src.report.renderSubmitEndTimeUs;
|
||||
dst.presentStartTime = src.report.presentStartTimeUs;
|
||||
dst.presentEndTime = src.report.presentEndTimeUs;
|
||||
dst.driverStartTime = src.report.driverStartTimeUs;
|
||||
dst.driverEndTime = src.report.driverEndTimeUs;
|
||||
dst.osRenderQueueStartTime = src.report.osRenderQueueStartTimeUs;
|
||||
dst.osRenderQueueEndTime = src.report.osRenderQueueEndTimeUs;
|
||||
dst.gpuRenderStartTime = src.report.gpuRenderStartTimeUs;
|
||||
dst.gpuRenderEndTime = src.report.gpuRenderEndTimeUs;
|
||||
dst.gpuActiveRenderTimeUs = src.gpuActiveTimeUs;
|
||||
dst.gpuFrameTimeUs = 0;
|
||||
|
||||
if (i) {
|
||||
dst.gpuFrameTimeUs = reports[i - 0].report.gpuRenderEndTimeUs
|
||||
- reports[i - 1].report.gpuRenderEndTimeUs;
|
||||
}
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
void D3D11ReflexDevice::RegisterLatencyTracker(
|
||||
Rc<DxvkLatencyTracker> Tracker) {
|
||||
std::lock_guard lock(m_mutex);
|
||||
|
||||
if (m_tracker)
|
||||
return;
|
||||
|
||||
if ((m_tracker = dynamic_cast<DxvkReflexLatencyTrackerNv*>(Tracker.ptr())))
|
||||
m_tracker->setLatencySleepMode(m_enableLowLatency, m_enableBoost, m_minIntervalUs);
|
||||
}
|
||||
|
||||
|
||||
void D3D11ReflexDevice::UnregisterLatencyTracker(
|
||||
Rc<DxvkLatencyTracker> Tracker) {
|
||||
std::lock_guard lock(m_mutex);
|
||||
|
||||
if (m_tracker == Tracker)
|
||||
m_tracker = nullptr;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
DXGIVkSwapChainFactory::DXGIVkSwapChainFactory(
|
||||
D3D11DXGIDevice* pContainer,
|
||||
D3D11Device* pDevice)
|
||||
|
@ -3086,6 +3351,7 @@ namespace dxvk {
|
|||
m_d3d11DeviceExt(this, &m_d3d11Device),
|
||||
m_d3d11Interop (this, &m_d3d11Device),
|
||||
m_d3d11Video (this, &m_d3d11Device),
|
||||
m_d3d11Reflex (this, &m_d3d11Device),
|
||||
m_d3d11on12 (this, &m_d3d11Device, pD3D12Device, pD3D12Queue),
|
||||
m_metaDevice (this),
|
||||
m_dxvkFactory (this, &m_d3d11Device) {
|
||||
|
@ -3158,8 +3424,14 @@ namespace dxvk {
|
|||
return S_OK;
|
||||
}
|
||||
|
||||
if (riid == __uuidof(ID3DLowLatencyDevice)) {
|
||||
*ppvObject = ref(&m_d3d11Reflex);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
if (m_d3d11on12.Is11on12Device()) {
|
||||
if (riid == __uuidof(ID3D11On12Device)) {
|
||||
if (riid == __uuidof(ID3D11On12Device)
|
||||
|| riid == __uuidof(ID3D11On12Device1_DXVK)) {
|
||||
*ppvObject = ref(&m_d3d11on12);
|
||||
return S_OK;
|
||||
}
|
||||
|
@ -3411,8 +3683,9 @@ namespace dxvk {
|
|||
|
||||
|
||||
HRESULT STDMETHODCALLTYPE D3D11DXGIDevice::EnqueueSetEvent(HANDLE hEvent) {
|
||||
Logger::err("D3D11DXGIDevice::EnqueueSetEvent: Not implemented");
|
||||
return DXGI_ERROR_UNSUPPORTED;
|
||||
auto immediateContext = m_d3d11Device.GetContext();
|
||||
immediateContext->Flush1(D3D11_CONTEXT_TYPE_ALL, hEvent);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#include "../dxgi/dxgi_interfaces.h"
|
||||
|
||||
#include "../dxvk/dxvk_cs.h"
|
||||
#include "../dxvk/dxvk_latency_reflex.h"
|
||||
|
||||
#include "../d3d10/d3d10_device.h"
|
||||
|
||||
|
@ -87,6 +88,11 @@ namespace dxvk {
|
|||
const D3D11_SUBRESOURCE_DATA* pInitialData,
|
||||
ID3D11Texture2D1** ppTexture2D);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE CreateTexture2DBase(
|
||||
const D3D11_TEXTURE2D_DESC1* pDesc,
|
||||
const D3D11_SUBRESOURCE_DATA* pInitialData,
|
||||
ID3D11Texture2D1** ppTexture2D);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE CreateTexture3D(
|
||||
const D3D11_TEXTURE3D_DESC* pDesc,
|
||||
const D3D11_SUBRESOURCE_DATA* pInitialData,
|
||||
|
@ -97,6 +103,11 @@ namespace dxvk {
|
|||
const D3D11_SUBRESOURCE_DATA* pInitialData,
|
||||
ID3D11Texture3D1** ppTexture3D);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE CreateTexture3DBase(
|
||||
const D3D11_TEXTURE3D_DESC1* pDesc,
|
||||
const D3D11_SUBRESOURCE_DATA* pInitialData,
|
||||
ID3D11Texture3D1** ppTexture3D);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE CreateShaderResourceView(
|
||||
ID3D11Resource* pResource,
|
||||
const D3D11_SHADER_RESOURCE_VIEW_DESC* pDesc,
|
||||
|
@ -107,6 +118,11 @@ namespace dxvk {
|
|||
const D3D11_SHADER_RESOURCE_VIEW_DESC1* pDesc,
|
||||
ID3D11ShaderResourceView1** ppSRView);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE CreateShaderResourceViewBase(
|
||||
ID3D11Resource* pResource,
|
||||
const D3D11_SHADER_RESOURCE_VIEW_DESC1* pDesc,
|
||||
ID3D11ShaderResourceView1** ppSRView);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE CreateUnorderedAccessView(
|
||||
ID3D11Resource* pResource,
|
||||
const D3D11_UNORDERED_ACCESS_VIEW_DESC* pDesc,
|
||||
|
@ -117,6 +133,11 @@ namespace dxvk {
|
|||
const D3D11_UNORDERED_ACCESS_VIEW_DESC1* pDesc,
|
||||
ID3D11UnorderedAccessView1** ppUAView);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE CreateUnorderedAccessViewBase(
|
||||
ID3D11Resource* pResource,
|
||||
const D3D11_UNORDERED_ACCESS_VIEW_DESC1* pDesc,
|
||||
ID3D11UnorderedAccessView1** ppUAView);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE CreateRenderTargetView(
|
||||
ID3D11Resource* pResource,
|
||||
const D3D11_RENDER_TARGET_VIEW_DESC* pDesc,
|
||||
|
@ -127,6 +148,11 @@ namespace dxvk {
|
|||
const D3D11_RENDER_TARGET_VIEW_DESC1* pDesc,
|
||||
ID3D11RenderTargetView1** ppRTView);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE CreateRenderTargetViewBase(
|
||||
ID3D11Resource* pResource,
|
||||
const D3D11_RENDER_TARGET_VIEW_DESC1* pDesc,
|
||||
ID3D11RenderTargetView1** ppRTView);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE CreateDepthStencilView(
|
||||
ID3D11Resource* pResource,
|
||||
const D3D11_DEPTH_STENCIL_VIEW_DESC* pDesc,
|
||||
|
@ -225,6 +251,10 @@ namespace dxvk {
|
|||
const D3D11_QUERY_DESC1* pQueryDesc,
|
||||
ID3D11Query1** ppQuery);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE CreateQueryBase(
|
||||
const D3D11_QUERY_DESC1* pQueryDesc,
|
||||
ID3D11Query1** ppQuery);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE CreatePredicate(
|
||||
const D3D11_QUERY_DESC* pPredicateDesc,
|
||||
ID3D11Predicate** ppPredicate);
|
||||
|
@ -391,8 +421,21 @@ namespace dxvk {
|
|||
return m_dxvkDevice;
|
||||
}
|
||||
|
||||
void FlushInitContext();
|
||||
void FlushInitCommands() {
|
||||
m_initializer->FlushCsChunk();
|
||||
}
|
||||
|
||||
void NotifyContextFlush() {
|
||||
m_initializer->NotifyContextFlush();
|
||||
}
|
||||
|
||||
void InitShaderIcb(
|
||||
D3D11CommonShader* pShader,
|
||||
size_t IcbSize,
|
||||
const void* pIcbData) {
|
||||
return m_initializer->InitShaderIcb(pShader, IcbSize, pIcbData);
|
||||
}
|
||||
|
||||
VkPipelineStageFlags GetEnabledShaderStages() const {
|
||||
return m_dxvkDevice->getShaderPipelineStages();
|
||||
}
|
||||
|
@ -434,6 +477,18 @@ namespace dxvk {
|
|||
|
||||
static DxvkDeviceFeatures GetDeviceFeatures(
|
||||
const Rc<DxvkAdapter>& Adapter);
|
||||
|
||||
DxvkBarrierControlFlags GetOptionsBarrierControlFlags() {
|
||||
DxvkBarrierControlFlags barrierControl = 0u;
|
||||
|
||||
if (m_d3d11Options.relaxedBarriers)
|
||||
barrierControl.set(DxvkBarrierControl::ComputeAllowWriteOnlyOverlap);
|
||||
|
||||
if (m_d3d11Options.relaxedBarriers || m_d3d11Options.relaxedGraphicsBarriers)
|
||||
barrierControl.set(DxvkBarrierControl::GraphicsAllowReadWriteOverlap);
|
||||
|
||||
return barrierControl;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
|
@ -580,7 +635,14 @@ namespace dxvk {
|
|||
|
||||
ID3D11ShaderResourceView* HandleToSrvNVX(
|
||||
uint32_t Handle);
|
||||
|
||||
|
||||
bool LockImage(
|
||||
const Rc<DxvkImage>& Image,
|
||||
VkImageUsageFlags Usage);
|
||||
|
||||
void LockBuffer(
|
||||
const Rc<DxvkBuffer>& Buffer);
|
||||
|
||||
dxvk::mutex m_mapLock;
|
||||
std::unordered_map<uint32_t, ID3D11SamplerState*> m_samplerHandleToPtr;
|
||||
std::unordered_map<uint32_t, ID3D11ShaderResourceView*> m_srvHandleToPtr;
|
||||
|
@ -697,6 +759,66 @@ namespace dxvk {
|
|||
};
|
||||
|
||||
|
||||
/**
|
||||
* \brief Nvidia Reflex interop
|
||||
*/
|
||||
class D3D11ReflexDevice : public ID3DLowLatencyDevice {
|
||||
|
||||
public:
|
||||
|
||||
D3D11ReflexDevice(
|
||||
D3D11DXGIDevice* pContainer,
|
||||
D3D11Device* pDevice);
|
||||
|
||||
~D3D11ReflexDevice();
|
||||
|
||||
ULONG STDMETHODCALLTYPE AddRef();
|
||||
|
||||
ULONG STDMETHODCALLTYPE Release();
|
||||
|
||||
HRESULT STDMETHODCALLTYPE QueryInterface(
|
||||
REFIID riid,
|
||||
void** ppvObject);
|
||||
|
||||
BOOL STDMETHODCALLTYPE SupportsLowLatency();
|
||||
|
||||
HRESULT STDMETHODCALLTYPE LatencySleep();
|
||||
|
||||
HRESULT STDMETHODCALLTYPE SetLatencySleepMode(
|
||||
BOOL LowLatencyEnable,
|
||||
BOOL LowLatencyBoost,
|
||||
UINT32 MinIntervalUs);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE SetLatencyMarker(
|
||||
UINT64 FrameId,
|
||||
UINT32 MarkerType);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE GetLatencyInfo(
|
||||
D3D_LOW_LATENCY_RESULTS* pLowLatencyResults);
|
||||
|
||||
void RegisterLatencyTracker(
|
||||
Rc<DxvkLatencyTracker> Tracker);
|
||||
|
||||
void UnregisterLatencyTracker(
|
||||
Rc<DxvkLatencyTracker> Tracker);
|
||||
|
||||
private:
|
||||
|
||||
D3D11DXGIDevice* m_container;
|
||||
D3D11Device* m_device;
|
||||
|
||||
bool m_reflexEnabled = false;
|
||||
|
||||
dxvk::mutex m_mutex;
|
||||
|
||||
bool m_enableLowLatency = false;
|
||||
bool m_enableBoost = false;
|
||||
uint64_t m_minIntervalUs = 0u;
|
||||
|
||||
Rc<DxvkReflexLatencyTrackerNv> m_tracker;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* \brief DXVK swap chain factory
|
||||
*/
|
||||
|
@ -860,6 +982,7 @@ namespace dxvk {
|
|||
D3D11DeviceExt m_d3d11DeviceExt;
|
||||
D3D11VkInterop m_d3d11Interop;
|
||||
D3D11VideoDevice m_d3d11Video;
|
||||
D3D11ReflexDevice m_d3d11Reflex;
|
||||
D3D11on12Device m_d3d11on12;
|
||||
DXGIDXVKDevice m_metaDevice;
|
||||
|
||||
|
|
|
@ -19,24 +19,28 @@ namespace dxvk {
|
|||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE GetPrivateData(
|
||||
REFGUID guid,
|
||||
UINT *pDataSize,
|
||||
void *pData) final {
|
||||
REFGUID guid,
|
||||
UINT* pDataSize,
|
||||
void* pData) final {
|
||||
return m_privateData.getData(
|
||||
guid, pDataSize, pData);
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE SetPrivateData(
|
||||
REFGUID guid,
|
||||
UINT DataSize,
|
||||
const void *pData) final {
|
||||
REFGUID guid,
|
||||
UINT DataSize,
|
||||
const void* pData) final {
|
||||
// WKPDID_D3DDebugObjectName, can't use directly due to MSVC link errors
|
||||
if (guid == GUID{0x429b8c22,0x9188,0x4b0c,0x87,0x42,0xac,0xb0,0xbf,0x85,0xc2,0x00})
|
||||
SetDebugName(static_cast<const char*>(pData));
|
||||
|
||||
return m_privateData.setData(
|
||||
guid, DataSize, pData);
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE SetPrivateDataInterface(
|
||||
REFGUID guid,
|
||||
const IUnknown *pUnknown) final {
|
||||
REFGUID guid,
|
||||
const IUnknown* pUnknown) final {
|
||||
return m_privateData.setInterface(
|
||||
guid, pUnknown);
|
||||
}
|
||||
|
@ -46,6 +50,10 @@ namespace dxvk {
|
|||
*ppDevice = ref(GetParentInterface());
|
||||
}
|
||||
|
||||
virtual void STDMETHODCALLTYPE SetDebugName(const char* pName) {
|
||||
// No-op by default
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
ID3D11Device* GetParentInterface() const {
|
||||
|
|
|
@ -12,6 +12,7 @@ namespace dxvk {
|
|||
D3D11DeviceFeatures::D3D11DeviceFeatures(
|
||||
const Rc<DxvkInstance>& Instance,
|
||||
const Rc<DxvkAdapter>& Adapter,
|
||||
const D3D11Options& Options,
|
||||
D3D_FEATURE_LEVEL FeatureLevel)
|
||||
: m_features (Adapter->features()),
|
||||
m_properties (Adapter->devicePropertiesExt()) {
|
||||
|
@ -107,7 +108,7 @@ namespace dxvk {
|
|||
m_gpuVirtualAddress.MaxGPUVirtualAddressBitsPerProcess = 40;
|
||||
|
||||
// Marker support only depends on the debug utils extension
|
||||
m_marker.Profile = Instance->extensions().extDebugUtils;
|
||||
m_marker.Profile = static_cast<bool>(Instance->extensions().extDebugUtils);
|
||||
|
||||
// DXVK will keep all shaders in memory once created, and all Vulkan
|
||||
// drivers that we know of that can run DXVK have an on-disk cache.
|
||||
|
@ -118,11 +119,11 @@ namespace dxvk {
|
|||
m_shaderMinPrecision.PixelShaderMinPrecision = 0;
|
||||
m_shaderMinPrecision.AllOtherShaderStagesMinPrecision = 0;
|
||||
|
||||
// Report native support for command lists here so that we do not actually have
|
||||
// to re-implement the UpdateSubresource bug from the D3D11 runtime, see MSDN:
|
||||
// https://msdn.microsoft.com/en-us/library/windows/desktop/ff476486(v=vs.85).aspx)
|
||||
// Report native support for command lists by default. Deferred context
|
||||
// usage can be beneficial for us as ExecuteCommandList has low overhead,
|
||||
// and we avoid having to deal with known UpdateSubresource bugs this way.
|
||||
m_threading.DriverConcurrentCreates = TRUE;
|
||||
m_threading.DriverCommandLists = TRUE;
|
||||
m_threading.DriverCommandLists = Options.exposeDriverCommandLists;
|
||||
}
|
||||
|
||||
|
||||
|
@ -182,7 +183,8 @@ namespace dxvk {
|
|||
D3D_FEATURE_LEVEL D3D11DeviceFeatures::GetMaxFeatureLevel(
|
||||
const Rc<DxvkInstance>& Instance,
|
||||
const Rc<DxvkAdapter>& Adapter) {
|
||||
D3D11DeviceFeatures features(Instance, Adapter, D3D_FEATURE_LEVEL_12_1);
|
||||
D3D11Options options(Instance->config());
|
||||
D3D11DeviceFeatures features(Instance, Adapter, options, D3D_FEATURE_LEVEL_12_1);
|
||||
return features.GetMaxFeatureLevel();
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
#include "d3d11_include.h"
|
||||
#include "d3d11_options.h"
|
||||
|
||||
#include "../dxvk/dxvk_adapter.h"
|
||||
#include "../dxvk/dxvk_instance.h"
|
||||
|
@ -21,6 +22,7 @@ namespace dxvk {
|
|||
D3D11DeviceFeatures(
|
||||
const Rc<DxvkInstance>& Instance,
|
||||
const Rc<DxvkAdapter>& Adapter,
|
||||
const D3D11Options& Options,
|
||||
D3D_FEATURE_LEVEL FeatureLevel);
|
||||
|
||||
~D3D11DeviceFeatures();
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#include <cstring>
|
||||
|
||||
#include "d3d11_context_imm.h"
|
||||
#include "d3d11_device.h"
|
||||
#include "d3d11_initializer.h"
|
||||
|
||||
|
@ -9,9 +10,10 @@ namespace dxvk {
|
|||
D3D11Device* pParent)
|
||||
: m_parent(pParent),
|
||||
m_device(pParent->GetDXVKDevice()),
|
||||
m_context(m_device->createContext(DxvkContextType::Supplementary)) {
|
||||
m_context->beginRecording(
|
||||
m_device->createCommandList());
|
||||
m_stagingBuffer(m_device, StagingBufferSize),
|
||||
m_stagingSignal(new sync::Fence(0)),
|
||||
m_csChunk(m_parent->AllocCsChunk(DxvkCsChunkFlag::SingleUse)) {
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
@ -20,13 +22,12 @@ namespace dxvk {
|
|||
}
|
||||
|
||||
|
||||
void D3D11Initializer::Flush() {
|
||||
void D3D11Initializer::NotifyContextFlush() {
|
||||
std::lock_guard<dxvk::mutex> lock(m_mutex);
|
||||
|
||||
if (m_transferCommands != 0)
|
||||
FlushInternal();
|
||||
NotifyContextFlushLocked();
|
||||
}
|
||||
|
||||
|
||||
void D3D11Initializer::InitBuffer(
|
||||
D3D11Buffer* pBuffer,
|
||||
const D3D11_SUBRESOURCE_DATA* pInitialData) {
|
||||
|
@ -50,7 +51,7 @@ namespace dxvk {
|
|||
else
|
||||
InitDeviceLocalTexture(pTexture, pInitialData);
|
||||
|
||||
SyncKeyedMutex(pTexture->GetInterface());
|
||||
SyncSharedTexture(pTexture);
|
||||
}
|
||||
|
||||
|
||||
|
@ -61,18 +62,45 @@ namespace dxvk {
|
|||
if (counterView == nullptr)
|
||||
return;
|
||||
|
||||
auto counterSlice = counterView->slice();
|
||||
|
||||
std::lock_guard<dxvk::mutex> lock(m_mutex);
|
||||
m_transferCommands += 1;
|
||||
|
||||
const uint32_t zero = 0;
|
||||
m_context->updateBuffer(
|
||||
counterSlice.buffer(),
|
||||
counterSlice.offset(),
|
||||
sizeof(zero), &zero);
|
||||
EmitCs([
|
||||
cCounterSlice = DxvkBufferSlice(counterView)
|
||||
] (DxvkContext* ctx) {
|
||||
const uint32_t zero = 0;
|
||||
ctx->updateBuffer(
|
||||
cCounterSlice.buffer(),
|
||||
cCounterSlice.offset(),
|
||||
sizeof(zero), &zero);
|
||||
});
|
||||
}
|
||||
|
||||
FlushImplicit();
|
||||
|
||||
void D3D11Initializer::InitShaderIcb(
|
||||
D3D11CommonShader* pShader,
|
||||
size_t IcbSize,
|
||||
const void* pIcbData) {
|
||||
std::lock_guard<dxvk::mutex> lock(m_mutex);
|
||||
m_transferCommands += 1;
|
||||
|
||||
auto icbSlice = pShader->GetIcb();
|
||||
auto srcSlice = m_stagingBuffer.alloc(icbSlice.length());
|
||||
|
||||
std::memcpy(srcSlice.mapPtr(0), pIcbData, IcbSize);
|
||||
|
||||
if (IcbSize < icbSlice.length())
|
||||
std::memset(srcSlice.mapPtr(IcbSize), 0, icbSlice.length() - IcbSize);
|
||||
|
||||
EmitCs([
|
||||
cIcbSlice = std::move(icbSlice),
|
||||
cSrcSlice = std::move(srcSlice)
|
||||
] (DxvkContext* ctx) {
|
||||
ctx->copyBuffer(cIcbSlice.buffer(), cIcbSlice.offset(),
|
||||
cSrcSlice.buffer(), cSrcSlice.offset(), cIcbSlice.length());
|
||||
});
|
||||
|
||||
ThrottleAllocationLocked();
|
||||
}
|
||||
|
||||
|
||||
|
@ -81,23 +109,33 @@ namespace dxvk {
|
|||
const D3D11_SUBRESOURCE_DATA* pInitialData) {
|
||||
std::lock_guard<dxvk::mutex> lock(m_mutex);
|
||||
|
||||
DxvkBufferSlice bufferSlice = pBuffer->GetBufferSlice();
|
||||
Rc<DxvkBuffer> buffer = pBuffer->GetBuffer();
|
||||
|
||||
if (pInitialData != nullptr && pInitialData->pSysMem != nullptr) {
|
||||
m_transferMemory += bufferSlice.length();
|
||||
auto stagingSlice = m_stagingBuffer.alloc(buffer->info().size);
|
||||
std::memcpy(stagingSlice.mapPtr(0), pInitialData->pSysMem, stagingSlice.length());
|
||||
|
||||
m_transferCommands += 1;
|
||||
|
||||
m_context->uploadBuffer(
|
||||
bufferSlice.buffer(),
|
||||
pInitialData->pSysMem);
|
||||
|
||||
EmitCs([
|
||||
cBuffer = buffer,
|
||||
cStagingSlice = std::move(stagingSlice)
|
||||
] (DxvkContext* ctx) {
|
||||
ctx->uploadBuffer(cBuffer,
|
||||
cStagingSlice.buffer(),
|
||||
cStagingSlice.offset());
|
||||
});
|
||||
} else {
|
||||
m_transferCommands += 1;
|
||||
|
||||
m_context->initBuffer(
|
||||
bufferSlice.buffer());
|
||||
EmitCs([
|
||||
cBuffer = buffer
|
||||
] (DxvkContext* ctx) {
|
||||
ctx->initBuffer(cBuffer);
|
||||
});
|
||||
}
|
||||
|
||||
FlushImplicit();
|
||||
ThrottleAllocationLocked();
|
||||
}
|
||||
|
||||
|
||||
|
@ -107,18 +145,10 @@ namespace dxvk {
|
|||
// If the buffer is mapped, we can write data directly
|
||||
// to the mapped memory region instead of doing it on
|
||||
// the GPU. Same goes for zero-initialization.
|
||||
DxvkBufferSlice bufferSlice = pBuffer->GetBufferSlice();
|
||||
|
||||
if (pInitialData != nullptr && pInitialData->pSysMem != nullptr) {
|
||||
std::memcpy(
|
||||
bufferSlice.mapPtr(0),
|
||||
pInitialData->pSysMem,
|
||||
bufferSlice.length());
|
||||
} else {
|
||||
std::memset(
|
||||
bufferSlice.mapPtr(0), 0,
|
||||
bufferSlice.length());
|
||||
}
|
||||
if (pInitialData && pInitialData->pSysMem)
|
||||
std::memcpy(pBuffer->GetMapPtr(), pInitialData->pSysMem, pBuffer->Desc()->ByteWidth);
|
||||
else
|
||||
std::memset(pBuffer->GetMapPtr(), 0, pBuffer->Desc()->ByteWidth);
|
||||
}
|
||||
|
||||
|
||||
|
@ -127,87 +157,96 @@ namespace dxvk {
|
|||
const D3D11_SUBRESOURCE_DATA* pInitialData) {
|
||||
std::lock_guard<dxvk::mutex> lock(m_mutex);
|
||||
|
||||
// Image migt be null if this is a staging resource
|
||||
Rc<DxvkImage> image = pTexture->GetImage();
|
||||
|
||||
auto mapMode = pTexture->GetMapMode();
|
||||
auto desc = pTexture->Desc();
|
||||
|
||||
VkFormat packedFormat = m_parent->LookupPackedFormat(desc->Format, pTexture->GetFormatMode()).Format;
|
||||
auto formatInfo = lookupFormatInfo(packedFormat);
|
||||
|
||||
if (pInitialData != nullptr && pInitialData->pSysMem != nullptr) {
|
||||
// pInitialData is an array that stores an entry for
|
||||
// every single subresource. Since we will define all
|
||||
// subresources, this counts as initialization.
|
||||
for (uint32_t layer = 0; layer < desc->ArraySize; layer++) {
|
||||
for (uint32_t level = 0; level < desc->MipLevels; level++) {
|
||||
const uint32_t id = D3D11CalcSubresource(
|
||||
level, layer, desc->MipLevels);
|
||||
// Compute data size for all subresources and allocate staging buffer memory
|
||||
DxvkBufferSlice stagingSlice;
|
||||
|
||||
VkOffset3D mipLevelOffset = { 0, 0, 0 };
|
||||
VkExtent3D mipLevelExtent = pTexture->MipLevelExtent(level);
|
||||
if (pTexture->HasImage()) {
|
||||
VkDeviceSize dataSize = 0u;
|
||||
|
||||
for (uint32_t mip = 0; mip < image->info().mipLevels; mip++) {
|
||||
dataSize += image->info().numLayers * align(util::computeImageDataSize(
|
||||
packedFormat, image->mipLevelExtent(mip), formatInfo->aspectMask), CACHE_LINE_SIZE);
|
||||
}
|
||||
|
||||
stagingSlice = m_stagingBuffer.alloc(dataSize);
|
||||
}
|
||||
|
||||
// Copy initial data for each subresource into the staging buffer,
|
||||
// as well as the mapped per-subresource buffers if available.
|
||||
VkDeviceSize dataOffset = 0u;
|
||||
|
||||
for (uint32_t mip = 0; mip < desc->MipLevels; mip++) {
|
||||
for (uint32_t layer = 0; layer < desc->ArraySize; layer++) {
|
||||
uint32_t index = D3D11CalcSubresource(mip, layer, desc->MipLevels);
|
||||
VkExtent3D mipLevelExtent = pTexture->MipLevelExtent(mip);
|
||||
|
||||
if (pTexture->HasImage()) {
|
||||
VkDeviceSize mipSizePerLayer = util::computeImageDataSize(
|
||||
packedFormat, image->mipLevelExtent(mip), formatInfo->aspectMask);
|
||||
|
||||
if (mapMode != D3D11_COMMON_TEXTURE_MAP_MODE_STAGING) {
|
||||
m_transferCommands += 1;
|
||||
m_transferMemory += pTexture->GetSubresourceLayout(formatInfo->aspectMask, id).Size;
|
||||
|
||||
VkImageSubresourceLayers subresourceLayers;
|
||||
subresourceLayers.aspectMask = formatInfo->aspectMask;
|
||||
subresourceLayers.mipLevel = level;
|
||||
subresourceLayers.baseArrayLayer = layer;
|
||||
subresourceLayers.layerCount = 1;
|
||||
|
||||
if (formatInfo->aspectMask != (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) {
|
||||
m_context->uploadImage(
|
||||
image, subresourceLayers,
|
||||
pInitialData[id].pSysMem,
|
||||
pInitialData[id].SysMemPitch,
|
||||
pInitialData[id].SysMemSlicePitch);
|
||||
} else {
|
||||
m_context->updateDepthStencilImage(
|
||||
image, subresourceLayers,
|
||||
VkOffset2D { mipLevelOffset.x, mipLevelOffset.y },
|
||||
VkExtent2D { mipLevelExtent.width, mipLevelExtent.height },
|
||||
pInitialData[id].pSysMem,
|
||||
pInitialData[id].SysMemPitch,
|
||||
pInitialData[id].SysMemSlicePitch,
|
||||
packedFormat);
|
||||
}
|
||||
|
||||
util::packImageData(stagingSlice.mapPtr(dataOffset),
|
||||
pInitialData[index].pSysMem, pInitialData[index].SysMemPitch, pInitialData[index].SysMemSlicePitch,
|
||||
0, 0, pTexture->GetVkImageType(), mipLevelExtent, 1, formatInfo, formatInfo->aspectMask);
|
||||
|
||||
dataOffset += align(mipSizePerLayer, CACHE_LINE_SIZE);
|
||||
}
|
||||
|
||||
if (mapMode != D3D11_COMMON_TEXTURE_MAP_MODE_NONE) {
|
||||
util::packImageData(pTexture->GetMappedBuffer(id)->mapPtr(0),
|
||||
pInitialData[id].pSysMem, pInitialData[id].SysMemPitch, pInitialData[id].SysMemSlicePitch,
|
||||
if (pTexture->HasPersistentBuffers()) {
|
||||
util::packImageData(pTexture->GetMapPtr(index, 0),
|
||||
pInitialData[index].pSysMem, pInitialData[index].SysMemPitch, pInitialData[index].SysMemSlicePitch,
|
||||
0, 0, pTexture->GetVkImageType(), mipLevelExtent, 1, formatInfo, formatInfo->aspectMask);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Upload all subresources of the image in one go
|
||||
if (pTexture->HasImage()) {
|
||||
EmitCs([
|
||||
cImage = std::move(image),
|
||||
cStagingSlice = std::move(stagingSlice),
|
||||
cFormat = packedFormat
|
||||
] (DxvkContext* ctx) {
|
||||
ctx->uploadImage(cImage,
|
||||
cStagingSlice.buffer(),
|
||||
cStagingSlice.offset(),
|
||||
CACHE_LINE_SIZE, cFormat);
|
||||
});
|
||||
}
|
||||
} else {
|
||||
if (mapMode != D3D11_COMMON_TEXTURE_MAP_MODE_STAGING) {
|
||||
if (pTexture->HasImage()) {
|
||||
m_transferCommands += 1;
|
||||
|
||||
// While the Microsoft docs state that resource contents are
|
||||
// undefined if no initial data is provided, some applications
|
||||
// expect a resource to be pre-cleared.
|
||||
VkImageSubresourceRange subresources;
|
||||
subresources.aspectMask = formatInfo->aspectMask;
|
||||
subresources.baseMipLevel = 0;
|
||||
subresources.levelCount = desc->MipLevels;
|
||||
subresources.baseArrayLayer = 0;
|
||||
subresources.layerCount = desc->ArraySize;
|
||||
|
||||
m_context->initImage(image, subresources, VK_IMAGE_LAYOUT_UNDEFINED);
|
||||
EmitCs([
|
||||
cImage = std::move(image)
|
||||
] (DxvkContext* ctx) {
|
||||
ctx->initImage(cImage,
|
||||
cImage->getAvailableSubresources(),
|
||||
VK_IMAGE_LAYOUT_UNDEFINED);
|
||||
});
|
||||
}
|
||||
|
||||
if (mapMode != D3D11_COMMON_TEXTURE_MAP_MODE_NONE) {
|
||||
if (pTexture->HasPersistentBuffers()) {
|
||||
for (uint32_t i = 0; i < pTexture->CountSubresources(); i++) {
|
||||
auto buffer = pTexture->GetMappedBuffer(i);
|
||||
std::memset(buffer->mapPtr(0), 0, buffer->info().size);
|
||||
auto layout = pTexture->GetSubresourceLayout(formatInfo->aspectMask, i);
|
||||
std::memset(pTexture->GetMapPtr(i, layout.Offset), 0, layout.Size);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
FlushImplicit();
|
||||
ThrottleAllocationLocked();
|
||||
}
|
||||
|
||||
|
||||
|
@ -215,38 +254,47 @@ namespace dxvk {
|
|||
D3D11CommonTexture* pTexture,
|
||||
const D3D11_SUBRESOURCE_DATA* pInitialData) {
|
||||
Rc<DxvkImage> image = pTexture->GetImage();
|
||||
auto formatInfo = image->formatInfo();
|
||||
|
||||
for (uint32_t layer = 0; layer < pTexture->Desc()->ArraySize; layer++) {
|
||||
for (uint32_t level = 0; level < pTexture->Desc()->MipLevels; level++) {
|
||||
uint32_t subresourceIndex = D3D11CalcSubresource(level, layer, pTexture->Desc()->MipLevels);
|
||||
|
||||
for (uint32_t layer = 0; layer < image->info().numLayers; layer++) {
|
||||
for (uint32_t level = 0; level < image->info().mipLevels; level++) {
|
||||
VkImageSubresource subresource;
|
||||
subresource.aspectMask = image->formatInfo()->aspectMask;
|
||||
subresource.aspectMask = formatInfo->aspectMask;
|
||||
subresource.mipLevel = level;
|
||||
subresource.arrayLayer = layer;
|
||||
|
||||
VkExtent3D blockCount = util::computeBlockCount(
|
||||
image->mipLevelExtent(level),
|
||||
image->formatInfo()->blockSize);
|
||||
image->mipLevelExtent(level), formatInfo->blockSize);
|
||||
|
||||
VkSubresourceLayout layout = image->querySubresourceLayout(subresource);
|
||||
auto layout = pTexture->GetSubresourceLayout(
|
||||
subresource.aspectMask, subresourceIndex);
|
||||
|
||||
auto initialData = pInitialData
|
||||
? &pInitialData[D3D11CalcSubresource(level, layer, image->info().mipLevels)]
|
||||
: nullptr;
|
||||
if (pInitialData && pInitialData[subresourceIndex].pSysMem) {
|
||||
const auto& initialData = pInitialData[subresourceIndex];
|
||||
|
||||
for (uint32_t z = 0; z < blockCount.depth; z++) {
|
||||
for (uint32_t y = 0; y < blockCount.height; y++) {
|
||||
auto size = blockCount.width * image->formatInfo()->elementSize;
|
||||
auto dst = image->mapPtr(layout.offset + y * layout.rowPitch + z * layout.depthPitch);
|
||||
for (uint32_t z = 0; z < blockCount.depth; z++) {
|
||||
for (uint32_t y = 0; y < blockCount.height; y++) {
|
||||
auto size = blockCount.width * formatInfo->elementSize;
|
||||
|
||||
auto dst = pTexture->GetMapPtr(subresourceIndex, layout.Offset
|
||||
+ y * layout.RowPitch
|
||||
+ z * layout.DepthPitch);
|
||||
|
||||
auto src = reinterpret_cast<const char*>(initialData.pSysMem)
|
||||
+ y * initialData.SysMemPitch
|
||||
+ z * initialData.SysMemSlicePitch;
|
||||
|
||||
if (initialData) {
|
||||
auto src = reinterpret_cast<const char*>(initialData->pSysMem)
|
||||
+ y * initialData->SysMemPitch
|
||||
+ z * initialData->SysMemSlicePitch;
|
||||
std::memcpy(dst, src, size);
|
||||
} else {
|
||||
std::memset(dst, 0, size);
|
||||
|
||||
if (size < layout.RowPitch)
|
||||
std::memset(reinterpret_cast<char*>(dst) + size, 0, layout.RowPitch - size);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
void* dst = pTexture->GetMapPtr(subresourceIndex, layout.Offset);
|
||||
std::memset(dst, 0, layout.Size);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -254,46 +302,110 @@ namespace dxvk {
|
|||
// Initialize the image on the GPU
|
||||
std::lock_guard<dxvk::mutex> lock(m_mutex);
|
||||
|
||||
VkImageSubresourceRange subresources = image->getAvailableSubresources();
|
||||
|
||||
m_context->initImage(image, subresources, VK_IMAGE_LAYOUT_PREINITIALIZED);
|
||||
EmitCs([
|
||||
cImage = std::move(image)
|
||||
] (DxvkContext* ctx) {
|
||||
ctx->initImage(cImage,
|
||||
cImage->getAvailableSubresources(),
|
||||
VK_IMAGE_LAYOUT_PREINITIALIZED);
|
||||
});
|
||||
|
||||
m_transferCommands += 1;
|
||||
FlushImplicit();
|
||||
ThrottleAllocationLocked();
|
||||
}
|
||||
|
||||
|
||||
void D3D11Initializer::InitTiledTexture(
|
||||
D3D11CommonTexture* pTexture) {
|
||||
m_context->initSparseImage(pTexture->GetImage());
|
||||
std::lock_guard<dxvk::mutex> lock(m_mutex);
|
||||
|
||||
EmitCs([
|
||||
cImage = pTexture->GetImage()
|
||||
] (DxvkContext* ctx) {
|
||||
ctx->initSparseImage(cImage);
|
||||
});
|
||||
|
||||
m_transferCommands += 1;
|
||||
FlushImplicit();
|
||||
ThrottleAllocationLocked();
|
||||
}
|
||||
|
||||
|
||||
void D3D11Initializer::FlushImplicit() {
|
||||
if (m_transferCommands > MaxTransferCommands
|
||||
|| m_transferMemory > MaxTransferMemory)
|
||||
FlushInternal();
|
||||
void D3D11Initializer::ThrottleAllocationLocked() {
|
||||
DxvkStagingBufferStats stats = m_stagingBuffer.getStatistics();
|
||||
|
||||
// If the amount of memory in flight exceeds the limit, stall the
|
||||
// calling thread and wait for some memory to actually get released.
|
||||
VkDeviceSize stagingMemoryInFlight = stats.allocatedTotal - m_stagingSignal->value();
|
||||
|
||||
if (stagingMemoryInFlight > MaxMemoryInFlight) {
|
||||
ExecuteFlushLocked();
|
||||
|
||||
m_stagingSignal->wait(stats.allocatedTotal - MaxMemoryInFlight);
|
||||
} else if (m_transferCommands >= MaxCommandsPerSubmission || stats.allocatedSinceLastReset >= MaxMemoryPerSubmission) {
|
||||
// Flush pending commands if there are a lot of updates in flight
|
||||
// to keep both execution time and staging memory in check.
|
||||
ExecuteFlushLocked();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void D3D11Initializer::FlushInternal() {
|
||||
m_context->flushCommandList(nullptr);
|
||||
|
||||
m_transferCommands = 0;
|
||||
m_transferMemory = 0;
|
||||
void D3D11Initializer::ExecuteFlush() {
|
||||
std::lock_guard lock(m_mutex);
|
||||
|
||||
ExecuteFlushLocked();
|
||||
}
|
||||
|
||||
|
||||
void D3D11Initializer::SyncKeyedMutex(ID3D11Resource *pResource) {
|
||||
Com<IDXGIKeyedMutex> keyedMutex;
|
||||
if (pResource->QueryInterface(__uuidof(IDXGIKeyedMutex), reinterpret_cast<void**>(&keyedMutex)) != S_OK)
|
||||
void D3D11Initializer::ExecuteFlushLocked() {
|
||||
DxvkStagingBufferStats stats = m_stagingBuffer.getStatistics();
|
||||
|
||||
EmitCs([
|
||||
cSignal = m_stagingSignal,
|
||||
cSignalValue = stats.allocatedTotal
|
||||
] (DxvkContext* ctx) {
|
||||
ctx->signal(cSignal, cSignalValue);
|
||||
ctx->flushCommandList(nullptr, nullptr);
|
||||
});
|
||||
|
||||
FlushCsChunk();
|
||||
|
||||
NotifyContextFlushLocked();
|
||||
}
|
||||
|
||||
|
||||
void D3D11Initializer::SyncSharedTexture(D3D11CommonTexture* pResource) {
|
||||
if (!(pResource->Desc()->MiscFlags & (D3D11_RESOURCE_MISC_SHARED | D3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX | D3D11_RESOURCE_MISC_SHARED_NTHANDLE)))
|
||||
return;
|
||||
|
||||
keyedMutex->AcquireSync(0, 0);
|
||||
keyedMutex->ReleaseSync(0);
|
||||
// Ensure that initialization commands are submitted and waited on before
|
||||
// returning control to the application in order to avoid race conditions
|
||||
// in case the texture is used immediately on a secondary device.
|
||||
if (pResource->HasImage()) {
|
||||
ExecuteFlush();
|
||||
|
||||
m_device->waitForResource(*pResource->GetImage(), DxvkAccess::Write);
|
||||
}
|
||||
|
||||
// If a keyed mutex is used, initialize that to the correct state as well.
|
||||
Com<IDXGIKeyedMutex> keyedMutex;
|
||||
|
||||
if (SUCCEEDED(pResource->GetInterface()->QueryInterface(
|
||||
__uuidof(IDXGIKeyedMutex), reinterpret_cast<void**>(&keyedMutex)))) {
|
||||
keyedMutex->AcquireSync(0, 0);
|
||||
keyedMutex->ReleaseSync(0);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void D3D11Initializer::FlushCsChunkLocked() {
|
||||
m_parent->GetContext()->InjectCsChunk(DxvkCsQueue::HighPriority, std::move(m_csChunk), false);
|
||||
m_csChunk = m_parent->AllocCsChunk(DxvkCsChunkFlag::SingleUse);
|
||||
}
|
||||
|
||||
|
||||
void D3D11Initializer::NotifyContextFlushLocked() {
|
||||
m_stagingBuffer.reset();
|
||||
m_transferCommands = 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,7 +1,11 @@
|
|||
#pragma once
|
||||
|
||||
#include "../dxvk/dxvk_staging.h"
|
||||
|
||||
#include "d3d11_buffer.h"
|
||||
#include "d3d11_shader.h"
|
||||
#include "d3d11_texture.h"
|
||||
#include "d3d11_view_uav.h"
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
|
@ -16,16 +20,33 @@ namespace dxvk {
|
|||
* zero-initialization for buffers and images.
|
||||
*/
|
||||
class D3D11Initializer {
|
||||
constexpr static size_t MaxTransferMemory = 32 * 1024 * 1024;
|
||||
constexpr static size_t MaxTransferCommands = 512;
|
||||
// Use a staging buffer with a linear allocator to service small uploads
|
||||
constexpr static VkDeviceSize StagingBufferSize = 1ull << 20;
|
||||
public:
|
||||
|
||||
// Maximum number of copy and clear commands to record before flushing
|
||||
constexpr static size_t MaxCommandsPerSubmission = 512u;
|
||||
|
||||
// Maximum amount of staging memory to allocate before flushing
|
||||
constexpr static size_t MaxMemoryPerSubmission = (env::is32BitHostPlatform() ? 12u : 48u) << 20;
|
||||
|
||||
// Maximum amount of memory in flight. If there are pending uploads while
|
||||
// this limit is exceeded, further initialization will be stalled.
|
||||
constexpr static size_t MaxMemoryInFlight = 3u * MaxMemoryPerSubmission;
|
||||
|
||||
D3D11Initializer(
|
||||
D3D11Device* pParent);
|
||||
|
||||
~D3D11Initializer();
|
||||
|
||||
void Flush();
|
||||
void FlushCsChunk() {
|
||||
std::lock_guard<dxvk::mutex> lock(m_csMutex);
|
||||
|
||||
if (!m_csChunk->empty())
|
||||
FlushCsChunkLocked();
|
||||
}
|
||||
|
||||
void NotifyContextFlush();
|
||||
|
||||
void InitBuffer(
|
||||
D3D11Buffer* pBuffer,
|
||||
|
@ -38,16 +59,25 @@ namespace dxvk {
|
|||
void InitUavCounter(
|
||||
D3D11UnorderedAccessView* pUav);
|
||||
|
||||
void InitShaderIcb(
|
||||
D3D11CommonShader* pShader,
|
||||
size_t IcbSize,
|
||||
const void* pIcbData);
|
||||
|
||||
private:
|
||||
|
||||
dxvk::mutex m_mutex;
|
||||
|
||||
D3D11Device* m_parent;
|
||||
Rc<DxvkDevice> m_device;
|
||||
Rc<DxvkContext> m_context;
|
||||
|
||||
DxvkStagingBuffer m_stagingBuffer;
|
||||
Rc<sync::Fence> m_stagingSignal;
|
||||
|
||||
size_t m_transferCommands = 0;
|
||||
size_t m_transferMemory = 0;
|
||||
|
||||
dxvk::mutex m_csMutex;
|
||||
DxvkCsChunkRef m_csChunk;
|
||||
|
||||
void InitDeviceLocalBuffer(
|
||||
D3D11Buffer* pBuffer,
|
||||
|
@ -68,11 +98,30 @@ namespace dxvk {
|
|||
void InitTiledTexture(
|
||||
D3D11CommonTexture* pTexture);
|
||||
|
||||
void FlushImplicit();
|
||||
void FlushInternal();
|
||||
void ThrottleAllocationLocked();
|
||||
|
||||
void SyncKeyedMutex(ID3D11Resource *pResource);
|
||||
void ExecuteFlush();
|
||||
|
||||
void ExecuteFlushLocked();
|
||||
|
||||
void SyncSharedTexture(
|
||||
D3D11CommonTexture* pResource);
|
||||
|
||||
void FlushCsChunkLocked();
|
||||
|
||||
void NotifyContextFlushLocked();
|
||||
|
||||
template<typename Cmd>
|
||||
void EmitCs(Cmd&& command) {
|
||||
std::lock_guard<dxvk::mutex> lock(m_csMutex);
|
||||
|
||||
if (unlikely(!m_csChunk->push(command))) {
|
||||
FlushCsChunkLocked();
|
||||
|
||||
m_csChunk->push(command);
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,7 +24,9 @@ enum D3D11_VK_EXTENSION : uint32_t {
|
|||
*/
|
||||
enum D3D11_VK_BARRIER_CONTROL : uint32_t {
|
||||
D3D11_VK_BARRIER_CONTROL_IGNORE_WRITE_AFTER_WRITE = 1 << 0,
|
||||
D3D11_VK_BARRIER_CONTROL_IGNORE_GRAPHICS_UAV = 1 << 1,
|
||||
|
||||
// Removed:
|
||||
// D3D11_VK_BARRIER_CONTROL_IGNORE_GRAPHICS_UAV = 1 << 1,
|
||||
};
|
||||
|
||||
|
||||
|
@ -183,16 +185,70 @@ ID3D11VkExtContext1 : public ID3D11VkExtContext {
|
|||
};
|
||||
|
||||
|
||||
#ifdef _MSC_VER
|
||||
struct __declspec(uuid("bb8a4fb9-3935-4762-b44b-35189a26414a")) ID3D11VkExtShader;
|
||||
struct __declspec(uuid("8a6e3c42-f74c-45b7-8265-a231b677ca17")) ID3D11VkExtDevice;
|
||||
struct __declspec(uuid("cfcf64ef-9586-46d0-bca4-97cf2ca61b06")) ID3D11VkExtDevice1;
|
||||
struct __declspec(uuid("fd0bca13-5cb6-4c3a-987e-4750de2ca791")) ID3D11VkExtContext;
|
||||
struct __declspec(uuid("874b09b2-ae0b-41d8-8476-5f3b7a0e879d")) ID3D11VkExtContext1;
|
||||
#else
|
||||
/**
|
||||
* \brief Frame reports used for Reflex interop
|
||||
*/
|
||||
struct D3D_LOW_LATENCY_FRAME_REPORT
|
||||
{
|
||||
UINT64 frameID;
|
||||
UINT64 inputSampleTime;
|
||||
UINT64 simStartTime;
|
||||
UINT64 simEndTime;
|
||||
UINT64 renderSubmitStartTime;
|
||||
UINT64 renderSubmitEndTime;
|
||||
UINT64 presentStartTime;
|
||||
UINT64 presentEndTime;
|
||||
UINT64 driverStartTime;
|
||||
UINT64 driverEndTime;
|
||||
UINT64 osRenderQueueStartTime;
|
||||
UINT64 osRenderQueueEndTime;
|
||||
UINT64 gpuRenderStartTime;
|
||||
UINT64 gpuRenderEndTime;
|
||||
UINT32 gpuActiveRenderTimeUs;
|
||||
UINT32 gpuFrameTimeUs;
|
||||
UINT8 rsvd[120];
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* \brief Data structure used for Reflex interop
|
||||
*/
|
||||
struct D3D_LOW_LATENCY_RESULTS
|
||||
{
|
||||
UINT32 version;
|
||||
D3D_LOW_LATENCY_FRAME_REPORT frameReports[64];
|
||||
UINT8 rsvd[32];
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* \brief D3D interop interface for Nvidia Reflex
|
||||
*/
|
||||
MIDL_INTERFACE("f3112584-41f9-348d-a59b-00b7e1d285d6")
|
||||
ID3DLowLatencyDevice : public IUnknown {
|
||||
virtual BOOL STDMETHODCALLTYPE SupportsLowLatency() = 0;
|
||||
|
||||
virtual HRESULT STDMETHODCALLTYPE LatencySleep() = 0;
|
||||
|
||||
virtual HRESULT STDMETHODCALLTYPE SetLatencySleepMode(
|
||||
BOOL LowLatencyEnable,
|
||||
BOOL LowLatencyBoost,
|
||||
UINT32 MinIntervalUs) = 0;
|
||||
|
||||
virtual HRESULT STDMETHODCALLTYPE SetLatencyMarker(
|
||||
UINT64 FrameId,
|
||||
UINT32 MarkerType) = 0;
|
||||
|
||||
virtual HRESULT STDMETHODCALLTYPE GetLatencyInfo(
|
||||
D3D_LOW_LATENCY_RESULTS* pLowLatencyResults) = 0;
|
||||
};
|
||||
|
||||
|
||||
#ifndef _MSC_VER
|
||||
__CRT_UUID_DECL(ID3D11VkExtShader, 0xbb8a4fb9,0x3935,0x4762,0xb4,0x4b,0x35,0x18,0x9a,0x26,0x41,0x4a);
|
||||
__CRT_UUID_DECL(ID3D11VkExtDevice, 0x8a6e3c42,0xf74c,0x45b7,0x82,0x65,0xa2,0x31,0xb6,0x77,0xca,0x17);
|
||||
__CRT_UUID_DECL(ID3D11VkExtDevice1, 0xcfcf64ef,0x9586,0x46d0,0xbc,0xa4,0x97,0xcf,0x2c,0xa6,0x1b,0x06);
|
||||
__CRT_UUID_DECL(ID3D11VkExtContext, 0xfd0bca13,0x5cb6,0x4c3a,0x98,0x7e,0x47,0x50,0xde,0x2c,0xa7,0x91);
|
||||
__CRT_UUID_DECL(ID3D11VkExtContext1, 0x874b09b2,0xae0b,0x41d8,0x84,0x76,0x5f,0x3b,0x7a,0x0e,0x87,0x9d);
|
||||
__CRT_UUID_DECL(ID3DLowLatencyDevice, 0xf3112584,0x41f9,0x348d,0xa5,0x9b,0x00,0xb7,0xe1,0xd2,0x85,0xd6);
|
||||
#endif
|
||||
|
|
|
@ -38,7 +38,7 @@ extern "C" {
|
|||
DXGI_ADAPTER_DESC desc;
|
||||
pAdapter->GetDesc(&desc);
|
||||
|
||||
dxvkInstance = new DxvkInstance();
|
||||
dxvkInstance = new DxvkInstance(0);
|
||||
dxvkAdapter = dxvkInstance->findAdapterByLuid(&desc.AdapterLuid);
|
||||
|
||||
if (dxvkAdapter == nullptr)
|
||||
|
@ -376,7 +376,7 @@ extern "C" {
|
|||
instanceInfo.extensionCount = instanceExtensions.size();
|
||||
instanceInfo.extensionNames = instanceExtensions.data();
|
||||
|
||||
Rc<DxvkInstance> dxvkInstance = new DxvkInstance(instanceInfo);
|
||||
Rc<DxvkInstance> dxvkInstance = new DxvkInstance(instanceInfo, 0);
|
||||
|
||||
// Find adapter by physical device handle
|
||||
Rc<DxvkAdapter> dxvkAdapter;
|
||||
|
|
|
@ -147,4 +147,11 @@ namespace dxvk {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
HRESULT STDMETHODCALLTYPE D3D11on12Device::GetD3D12Device(
|
||||
REFIID riid,
|
||||
void** ppvDevice) {
|
||||
return m_d3d12Queue->GetDevice(riid, ppvDevice);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -4,6 +4,21 @@
|
|||
|
||||
#include "../util/log/log.h"
|
||||
|
||||
/**
|
||||
* \brief Declaration of the ID3D11On12Device1 interface
|
||||
*
|
||||
* Various different headers that we need to be compatible with
|
||||
* can't seem to agree on the signature of GetD3D12Device, and
|
||||
* older wine/mingw headers don't support this interface at all.
|
||||
*/
|
||||
MIDL_INTERFACE("bdb64df4-ea2f-4c70-b861-aaab1258bb5d")
|
||||
ID3D11On12Device1_DXVK : public ID3D11On12Device {
|
||||
virtual HRESULT STDMETHODCALLTYPE GetD3D12Device(
|
||||
REFIID riid,
|
||||
void** ppvDevice) = 0;
|
||||
};
|
||||
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
class D3D11Device;
|
||||
|
@ -22,7 +37,7 @@ namespace dxvk {
|
|||
};
|
||||
|
||||
|
||||
class D3D11on12Device : public ID3D11On12Device {
|
||||
class D3D11on12Device : public ID3D11On12Device1_DXVK {
|
||||
|
||||
public:
|
||||
|
||||
|
@ -58,6 +73,10 @@ namespace dxvk {
|
|||
ID3D11Resource* const* ppResources,
|
||||
UINT ResourceCount);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE GetD3D12Device(
|
||||
REFIID riid,
|
||||
void** ppvDevice);
|
||||
|
||||
bool Is11on12Device() const {
|
||||
return m_d3d12Device != nullptr;
|
||||
}
|
||||
|
@ -73,3 +92,7 @@ namespace dxvk {
|
|||
};
|
||||
|
||||
}
|
||||
|
||||
#ifndef _MSC_VER
|
||||
__CRT_UUID_DECL(ID3D11On12Device1_DXVK, 0xbdb64df4,0xea2f,0x4c70,0xb8,0x61,0xaa,0xab,0x12,0x58,0xbb,0x5d);
|
||||
#endif
|
||||
|
|
|
@ -49,8 +49,6 @@ ID3D12DXVKInteropDevice : public IUnknown {
|
|||
|
||||
};
|
||||
|
||||
#ifdef _MSC_VER
|
||||
struct __declspec(uuid("39da4e09-bd1c-4198-9fae-86bbe3be41fd")) ID3D12DXVKInteropDevice;
|
||||
#else
|
||||
#ifndef _MSC_VER
|
||||
__CRT_UUID_DECL(ID3D12DXVKInteropDevice, 0x39da4e09, 0xbd1c, 0x4198, 0x9f,0xae, 0x86,0xbb,0xe3,0xbe,0x41,0xfd)
|
||||
#endif
|
||||
|
|
|
@ -12,12 +12,12 @@ namespace dxvk {
|
|||
#endif
|
||||
}
|
||||
|
||||
D3D11Options::D3D11Options(const Config& config, const Rc<DxvkDevice>& device) {
|
||||
this->dcSingleUseMode = config.getOption<bool>("d3d11.dcSingleUseMode", true);
|
||||
D3D11Options::D3D11Options(const Config& config) {
|
||||
this->zeroInitWorkgroupMemory = config.getOption<bool>("d3d11.zeroInitWorkgroupMemory", false);
|
||||
this->forceVolatileTgsmAccess = config.getOption<bool>("d3d11.forceVolatileTgsmAccess", false);
|
||||
this->forceComputeUavBarriers = config.getOption<bool>("d3d11.forceComputeUavBarriers", false);
|
||||
this->relaxedBarriers = config.getOption<bool>("d3d11.relaxedBarriers", false);
|
||||
this->ignoreGraphicsBarriers = config.getOption<bool>("d3d11.ignoreGraphicsBarriers", false);
|
||||
this->relaxedGraphicsBarriers = config.getOption<bool>("d3d11.relaxedGraphicsBarriers", false);
|
||||
this->maxTessFactor = config.getOption<int32_t>("d3d11.maxTessFactor", 0);
|
||||
this->samplerAnisotropy = config.getOption<int32_t>("d3d11.samplerAnisotropy", -1);
|
||||
this->samplerLodBias = config.getOption<float>("d3d11.samplerLodBias", 0.0f);
|
||||
|
@ -28,24 +28,13 @@ namespace dxvk {
|
|||
this->disableMsaa = config.getOption<bool>("d3d11.disableMsaa", false);
|
||||
this->enableContextLock = config.getOption<bool>("d3d11.enableContextLock", false);
|
||||
this->deferSurfaceCreation = config.getOption<bool>("dxgi.deferSurfaceCreation", false);
|
||||
this->numBackBuffers = config.getOption<int32_t>("dxgi.numBackBuffers", 0);
|
||||
this->maxFrameLatency = config.getOption<int32_t>("dxgi.maxFrameLatency", 0);
|
||||
this->maxFrameRate = config.getOption<int32_t>("dxgi.maxFrameRate", 0);
|
||||
this->syncInterval = config.getOption<int32_t>("dxgi.syncInterval", -1);
|
||||
this->exposeDriverCommandLists = config.getOption<bool>("d3d11.exposeDriverCommandLists", true);
|
||||
this->reproducibleCommandStream = config.getOption<bool>("d3d11.reproducibleCommandStream", false);
|
||||
|
||||
// Clamp LOD bias so that people don't abuse this in unintended ways
|
||||
this->samplerLodBias = dxvk::fclamp(this->samplerLodBias, -2.0f, 1.0f);
|
||||
|
||||
int32_t maxImplicitDiscardSize = config.getOption<int32_t>("d3d11.maxImplicitDiscardSize", 256);
|
||||
this->maxImplicitDiscardSize = maxImplicitDiscardSize >= 0
|
||||
? VkDeviceSize(maxImplicitDiscardSize) << 10
|
||||
: VkDeviceSize(~0ull);
|
||||
|
||||
int32_t maxDynamicImageBufferSize = config.getOption<int32_t>("d3d11.maxDynamicImageBufferSize", -1);
|
||||
this->maxDynamicImageBufferSize = maxDynamicImageBufferSize >= 0
|
||||
? VkDeviceSize(maxDynamicImageBufferSize) << 10
|
||||
: VkDeviceSize(~0ull);
|
||||
|
||||
auto cachedDynamicResources = config.getOption<std::string>("d3d11.cachedDynamicResources", std::string());
|
||||
|
||||
if (IsAPITracingDXGI()) {
|
||||
|
@ -72,4 +61,4 @@ namespace dxvk {
|
|||
this->shaderDumpPath = env::getEnvVar("DXVK_SHADER_DUMP_PATH");
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,114 +11,107 @@
|
|||
namespace dxvk {
|
||||
|
||||
struct D3D11Options {
|
||||
D3D11Options(const Config& config, const Rc<DxvkDevice>& device);
|
||||
|
||||
/// Enables speed hack for mapping on deferred contexts
|
||||
///
|
||||
/// This can substantially speed up some games, but may
|
||||
/// cause issues if the game submits command lists more
|
||||
/// than once.
|
||||
bool dcSingleUseMode;
|
||||
D3D11Options(const Config& config);
|
||||
|
||||
/// Zero-initialize workgroup memory
|
||||
///
|
||||
/// Workargound for games that don't initialize
|
||||
/// TGSM in compute shaders before reading it.
|
||||
bool zeroInitWorkgroupMemory;
|
||||
bool zeroInitWorkgroupMemory = false;
|
||||
|
||||
/// Force thread-group shared memory accesses to be volatile
|
||||
///
|
||||
/// Workaround for compute shaders that read and
|
||||
/// write from the same shared memory location
|
||||
/// without explicit synchronization.
|
||||
bool forceVolatileTgsmAccess;
|
||||
bool forceVolatileTgsmAccess = false;
|
||||
|
||||
/// Force UAV synchronization insided compute shaders
|
||||
///
|
||||
/// Workaround for compute shaders that access overlapping
|
||||
/// memory regions within a UAV without proper workgroup
|
||||
/// synchroniation. Will have a negative performance impact.
|
||||
bool forceComputeUavBarriers = false;
|
||||
|
||||
/// Use relaxed memory barriers
|
||||
///
|
||||
/// May improve performance in some games,
|
||||
/// but might also cause rendering issues.
|
||||
bool relaxedBarriers;
|
||||
bool relaxedBarriers = false;
|
||||
|
||||
/// Ignore graphics barriers
|
||||
///
|
||||
/// May improve performance in some games,
|
||||
/// but might also cause rendering issues.
|
||||
bool ignoreGraphicsBarriers;
|
||||
bool relaxedGraphicsBarriers = false;
|
||||
|
||||
/// Maximum tessellation factor.
|
||||
///
|
||||
/// Limits tessellation factors in tessellation
|
||||
/// control shaders. Values from 8 to 64 are
|
||||
/// supported, other values will be ignored.
|
||||
int32_t maxTessFactor;
|
||||
int32_t maxTessFactor = 0;
|
||||
|
||||
/// Anisotropic filter override
|
||||
///
|
||||
/// Enforces anisotropic filtering with the
|
||||
/// given anisotropy value for all samplers.
|
||||
int32_t samplerAnisotropy;
|
||||
int32_t samplerAnisotropy = -1;
|
||||
|
||||
/// Mipmap LOD bias
|
||||
///
|
||||
/// Enforces the given LOD bias for all samplers.
|
||||
float samplerLodBias;
|
||||
float samplerLodBias = 0.0f;
|
||||
|
||||
/// Clamps negative LOD bias
|
||||
bool clampNegativeLodBias;
|
||||
bool clampNegativeLodBias = false;
|
||||
|
||||
/// Declare vertex positions in shaders as invariant
|
||||
bool invariantPosition;
|
||||
bool invariantPosition = true;
|
||||
|
||||
/// Enable float control bits
|
||||
bool floatControls;
|
||||
|
||||
/// Back buffer count for the Vulkan swap chain.
|
||||
/// Overrides DXGI_SWAP_CHAIN_DESC::BufferCount.
|
||||
int32_t numBackBuffers;
|
||||
|
||||
/// Sync interval. Overrides the value
|
||||
/// passed to IDXGISwapChain::Present.
|
||||
int32_t syncInterval;
|
||||
bool floatControls = true;
|
||||
|
||||
/// Override maximum frame latency if the app specifies
|
||||
/// a higher value. May help with frame timing issues.
|
||||
int32_t maxFrameLatency;
|
||||
|
||||
/// Limit frame rate
|
||||
int32_t maxFrameRate;
|
||||
|
||||
/// Limit discardable resource size
|
||||
VkDeviceSize maxImplicitDiscardSize;
|
||||
|
||||
/// Limit size of buffer-mapped images
|
||||
VkDeviceSize maxDynamicImageBufferSize;
|
||||
int32_t maxFrameLatency = 0;
|
||||
|
||||
/// Defer surface creation until first present call. This
|
||||
/// fixes issues with games that create multiple swap chains
|
||||
/// for a single window that may interfere with each other.
|
||||
bool deferSurfaceCreation;
|
||||
bool deferSurfaceCreation = false;
|
||||
|
||||
/// Enables sample rate shading by interpolating fragment shader
|
||||
/// inputs at the sample location rather than pixel center,
|
||||
/// unless otherwise specified by the application.
|
||||
bool forceSampleRateShading;
|
||||
bool forceSampleRateShading = false;
|
||||
|
||||
/// Forces the sample count of all textures to be 1, and
|
||||
/// performs the required shader and resolve fixups.
|
||||
bool disableMsaa;
|
||||
bool disableMsaa = false;
|
||||
|
||||
/// Dynamic resources with the given bind flags will be allocated
|
||||
/// in cached system memory. Enabled automatically when recording
|
||||
/// an api trace.
|
||||
uint32_t cachedDynamicResources;
|
||||
uint32_t cachedDynamicResources = 0;
|
||||
|
||||
/// Always lock immediate context on every API call. May be
|
||||
/// useful for debugging purposes or when applications have
|
||||
/// race conditions.
|
||||
bool enableContextLock;
|
||||
bool enableContextLock = false;
|
||||
|
||||
/// Whether to expose the driver command list feature. Enabled by
|
||||
/// default and generally beneficial, but some games may assume that
|
||||
/// this is not supported when running on an AMD GPU.
|
||||
bool exposeDriverCommandLists = true;
|
||||
|
||||
/// Ensure that for the same D3D commands the output VK commands
|
||||
/// don't change between runs. Useful for comparative benchmarking,
|
||||
/// can negatively affect performance.
|
||||
bool reproducibleCommandStream = false;
|
||||
|
||||
/// Shader dump path
|
||||
std::string shaderDumpPath;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -103,8 +103,8 @@ namespace dxvk {
|
|||
|
||||
D3D11_VK_QUERY_STATE m_state;
|
||||
|
||||
std::array<Rc<DxvkGpuQuery>, MaxGpuQueries> m_query;
|
||||
std::array<Rc<DxvkGpuEvent>, MaxGpuEvents> m_event;
|
||||
std::array<Rc<DxvkQuery>, MaxGpuQueries> m_query;
|
||||
std::array<Rc<DxvkEvent>, MaxGpuEvents> m_event;
|
||||
|
||||
D3D10Query m_d3d10;
|
||||
|
||||
|
|
|
@ -9,11 +9,10 @@
|
|||
namespace dxvk {
|
||||
|
||||
D3D11DXGIKeyedMutex::D3D11DXGIKeyedMutex(
|
||||
ID3D11Resource* pResource)
|
||||
: m_resource(pResource) {
|
||||
Com<ID3D11Device> device;
|
||||
m_resource->GetDevice(&device);
|
||||
m_device = static_cast<D3D11Device*>(device.ptr());
|
||||
ID3D11Resource* pResource,
|
||||
D3D11Device* pDevice)
|
||||
: m_resource(pResource),
|
||||
m_device(pDevice) {
|
||||
|
||||
m_supported = m_device->GetDXVKDevice()->features().khrWin32KeyedMutex
|
||||
&& m_device->GetDXVKDevice()->vkd()->wine_vkAcquireKeyedMutex != nullptr
|
||||
|
@ -96,7 +95,9 @@ namespace dxvk {
|
|||
D3D11CommonTexture* texture = GetCommonTexture(m_resource);
|
||||
Rc<DxvkDevice> dxvkDevice = m_device->GetDXVKDevice();
|
||||
|
||||
VkResult vr = dxvkDevice->vkd()->wine_vkAcquireKeyedMutex(dxvkDevice->handle(), texture->GetImage()->memory().memory(), Key, dwMilliseconds);
|
||||
VkResult vr = dxvkDevice->vkd()->wine_vkAcquireKeyedMutex(
|
||||
dxvkDevice->handle(), texture->GetImage()->getMemoryInfo().memory, Key, dwMilliseconds);
|
||||
|
||||
switch (vr) {
|
||||
case VK_SUCCESS: return S_OK;
|
||||
case VK_TIMEOUT: return WAIT_TIMEOUT;
|
||||
|
@ -112,17 +113,29 @@ namespace dxvk {
|
|||
D3D11CommonTexture* texture = GetCommonTexture(m_resource);
|
||||
Rc<DxvkDevice> dxvkDevice = m_device->GetDXVKDevice();
|
||||
|
||||
m_device->GetContext()->WaitForResource(texture->GetImage(), DxvkCsThread::SynchronizeAll, D3D11_MAP_READ_WRITE, 0);
|
||||
{
|
||||
D3D11ImmediateContext* context = m_device->GetContext();
|
||||
D3D10Multithread& multithread = context->GetMultithread();
|
||||
static bool s_errorShown = false;
|
||||
|
||||
return dxvkDevice->vkd()->wine_vkReleaseKeyedMutex(dxvkDevice->handle(), texture->GetImage()->memory().memory(), Key) == VK_SUCCESS
|
||||
? S_OK
|
||||
: DXGI_ERROR_INVALID_CALL;
|
||||
if (!multithread.GetMultithreadProtected() && !std::exchange(s_errorShown, true))
|
||||
Logger::warn("D3D11DXGIKeyedMutex::ReleaseSync: Called without context locking enabled.");
|
||||
|
||||
D3D10DeviceLock lock = context->LockContext();
|
||||
context->WaitForResource(*texture->GetImage(), DxvkCsThread::SynchronizeAll, D3D11_MAP_READ_WRITE, 0);
|
||||
}
|
||||
|
||||
VkResult vr = dxvkDevice->vkd()->wine_vkReleaseKeyedMutex(
|
||||
dxvkDevice->handle(), texture->GetImage()->getMemoryInfo().memory, Key);
|
||||
|
||||
return vr == VK_SUCCESS ? S_OK : DXGI_ERROR_INVALID_CALL;
|
||||
}
|
||||
|
||||
D3D11DXGIResource::D3D11DXGIResource(
|
||||
ID3D11Resource* pResource)
|
||||
ID3D11Resource* pResource,
|
||||
D3D11Device* pDevice)
|
||||
: m_resource(pResource),
|
||||
m_keyedMutex(pResource) {
|
||||
m_keyedMutex(pResource, pDevice) {
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -30,7 +30,8 @@ namespace dxvk {
|
|||
public:
|
||||
|
||||
D3D11DXGIKeyedMutex(
|
||||
ID3D11Resource* pResource);
|
||||
ID3D11Resource* pResource,
|
||||
D3D11Device* pDevice);
|
||||
|
||||
~D3D11DXGIKeyedMutex();
|
||||
|
||||
|
@ -88,7 +89,8 @@ namespace dxvk {
|
|||
public:
|
||||
|
||||
D3D11DXGIResource(
|
||||
ID3D11Resource* pResource);
|
||||
ID3D11Resource* pResource,
|
||||
D3D11Device* pDevice);
|
||||
|
||||
~D3D11DXGIResource();
|
||||
|
||||
|
|
|
@ -9,63 +9,58 @@ namespace dxvk {
|
|||
const D3D11_SAMPLER_DESC& desc)
|
||||
: D3D11StateObject<ID3D11SamplerState>(device),
|
||||
m_desc(desc), m_d3d10(this) {
|
||||
DxvkSamplerCreateInfo info;
|
||||
|
||||
DxvkSamplerKey info = { };
|
||||
|
||||
// While D3D11_FILTER is technically an enum, its value bits
|
||||
// can be used to decode the filter properties more efficiently.
|
||||
const uint32_t filterBits = uint32_t(desc.Filter);
|
||||
info.magFilter = (filterBits & 0x04) ? VK_FILTER_LINEAR : VK_FILTER_NEAREST;
|
||||
info.minFilter = (filterBits & 0x10) ? VK_FILTER_LINEAR : VK_FILTER_NEAREST;
|
||||
|
||||
|
||||
VkFilter minFilter = (filterBits & 0x10) ? VK_FILTER_LINEAR : VK_FILTER_NEAREST;
|
||||
VkFilter magFilter = (filterBits & 0x04) ? VK_FILTER_LINEAR : VK_FILTER_NEAREST;
|
||||
|
||||
info.setFilter(minFilter, magFilter,
|
||||
(filterBits & 0x01) ? VK_SAMPLER_MIPMAP_MODE_LINEAR : VK_SAMPLER_MIPMAP_MODE_NEAREST);
|
||||
|
||||
// Enforce LOD bias specified in the device options
|
||||
float lodBias = desc.MipLODBias;
|
||||
|
||||
if (minFilter == VK_FILTER_LINEAR && magFilter == VK_FILTER_LINEAR) {
|
||||
lodBias += device->GetOptions()->samplerLodBias;
|
||||
|
||||
if (device->GetOptions()->clampNegativeLodBias)
|
||||
lodBias = std::max(lodBias, 0.0f);
|
||||
}
|
||||
|
||||
info.setLodRange(desc.MinLOD, desc.MaxLOD, lodBias);
|
||||
|
||||
// Enforce anisotropy specified in the device options
|
||||
uint32_t anisotropy = (filterBits & 0x40) ? desc.MaxAnisotropy : 0u;
|
||||
int32_t samplerAnisotropyOption = device->GetOptions()->samplerAnisotropy;
|
||||
|
||||
if (samplerAnisotropyOption >= 0 && minFilter == VK_FILTER_LINEAR)
|
||||
anisotropy = samplerAnisotropyOption;
|
||||
|
||||
info.setAniso(anisotropy);
|
||||
|
||||
// Set up the remaining properties, which are
|
||||
// stored directly in the sampler description
|
||||
info.mipmapMode = (filterBits & 0x01) ? VK_SAMPLER_MIPMAP_MODE_LINEAR : VK_SAMPLER_MIPMAP_MODE_NEAREST;
|
||||
info.mipmapLodBias = desc.MipLODBias;
|
||||
info.mipmapLodMin = desc.MinLOD;
|
||||
info.mipmapLodMax = desc.MaxLOD;
|
||||
|
||||
info.useAnisotropy = (filterBits & 0x40) ? VK_TRUE : VK_FALSE;
|
||||
info.maxAnisotropy = float(desc.MaxAnisotropy);
|
||||
|
||||
info.addressModeU = DecodeAddressMode(desc.AddressU);
|
||||
info.addressModeV = DecodeAddressMode(desc.AddressV);
|
||||
info.addressModeW = DecodeAddressMode(desc.AddressW);
|
||||
|
||||
info.compareToDepth = (filterBits & 0x180) == 0x80 ? VK_TRUE : VK_FALSE;
|
||||
info.compareOp = DecodeCompareOp(desc.ComparisonFunc);
|
||||
info.setAddressModes(
|
||||
DecodeAddressMode(desc.AddressU),
|
||||
DecodeAddressMode(desc.AddressV),
|
||||
DecodeAddressMode(desc.AddressW));
|
||||
|
||||
info.reductionMode = DecodeReductionMode(filterBits);
|
||||
info.setDepthCompare((filterBits & 0x180) == 0x80,
|
||||
DecodeCompareOp(desc.ComparisonFunc));
|
||||
|
||||
info.setReduction(DecodeReductionMode(filterBits));
|
||||
|
||||
for (uint32_t i = 0; i < 4; i++)
|
||||
info.borderColor.float32[i] = desc.BorderColor[i];
|
||||
|
||||
info.usePixelCoord = VK_FALSE; // Not supported in D3D11
|
||||
info.nonSeamless = VK_FALSE;
|
||||
|
||||
// Make sure to use a valid anisotropy value
|
||||
if (desc.MaxAnisotropy < 1) info.maxAnisotropy = 1.0f;
|
||||
if (desc.MaxAnisotropy > 16) info.maxAnisotropy = 16.0f;
|
||||
|
||||
// Enforce LOD bias specified in the device options
|
||||
if (info.minFilter == VK_FILTER_LINEAR && info.magFilter == VK_FILTER_LINEAR) {
|
||||
info.mipmapLodBias += device->GetOptions()->samplerLodBias;
|
||||
|
||||
if (device->GetOptions()->clampNegativeLodBias)
|
||||
info.mipmapLodBias = std::max(info.mipmapLodBias, 0.0f);
|
||||
}
|
||||
|
||||
// Enforce anisotropy specified in the device options
|
||||
int32_t samplerAnisotropyOption = device->GetOptions()->samplerAnisotropy;
|
||||
|
||||
if (samplerAnisotropyOption >= 0 && info.minFilter == VK_FILTER_LINEAR) {
|
||||
info.useAnisotropy = samplerAnisotropyOption > 0;
|
||||
info.maxAnisotropy = float(samplerAnisotropyOption);
|
||||
}
|
||||
|
||||
m_sampler = device->GetDXVKDevice()->createSampler(info);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
D3D11SamplerState::~D3D11SamplerState() {
|
||||
|
||||
}
|
||||
|
|
|
@ -59,25 +59,33 @@ namespace dxvk {
|
|||
}
|
||||
|
||||
// Create shader constant buffer if necessary
|
||||
const DxvkShaderCreateInfo& shaderInfo = m_shader->info();
|
||||
auto icb = module.icbInfo();
|
||||
|
||||
if (shaderInfo.uniformSize) {
|
||||
DxvkBufferCreateInfo info;
|
||||
info.size = shaderInfo.uniformSize;
|
||||
info.usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT;
|
||||
info.stages = util::pipelineStages(shaderInfo.stage);
|
||||
info.access = VK_ACCESS_UNIFORM_READ_BIT;
|
||||
|
||||
VkMemoryPropertyFlags memFlags
|
||||
= VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT
|
||||
| VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT
|
||||
| VK_MEMORY_PROPERTY_HOST_COHERENT_BIT;
|
||||
|
||||
m_buffer = pDevice->GetDXVKDevice()->createBuffer(info, memFlags);
|
||||
std::memcpy(m_buffer->mapPtr(0), shaderInfo.uniformData, shaderInfo.uniformSize);
|
||||
if (icb.size) {
|
||||
DxvkBufferCreateInfo info = { };
|
||||
info.size = align(icb.size, 256u);
|
||||
info.usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT
|
||||
| VK_BUFFER_USAGE_TRANSFER_SRC_BIT
|
||||
| VK_BUFFER_USAGE_TRANSFER_DST_BIT;
|
||||
info.stages = util::pipelineStages(m_shader->info().stage);
|
||||
info.access = VK_ACCESS_UNIFORM_READ_BIT
|
||||
| VK_ACCESS_TRANSFER_READ_BIT
|
||||
| VK_ACCESS_TRANSFER_WRITE_BIT;
|
||||
info.debugName = "Icb";
|
||||
|
||||
m_buffer = pDevice->GetDXVKDevice()->createBuffer(info, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
|
||||
|
||||
// Upload immediate constant buffer to VRAM
|
||||
pDevice->InitShaderIcb(this, icb.size, icb.data);
|
||||
}
|
||||
|
||||
pDevice->GetDXVKDevice()->registerShader(m_shader);
|
||||
|
||||
// Write back binding mask
|
||||
auto bindings = module.bindings();
|
||||
|
||||
if (bindings)
|
||||
m_bindings = *bindings;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
namespace dxvk {
|
||||
|
||||
class D3D11Device;
|
||||
|
||||
|
||||
/**
|
||||
* \brief Common shader object
|
||||
*
|
||||
|
@ -52,12 +52,18 @@ namespace dxvk {
|
|||
std::string GetName() const {
|
||||
return m_shader->debugName();
|
||||
}
|
||||
|
||||
|
||||
DxbcBindingMask GetBindingMask() const {
|
||||
return m_bindings;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
|
||||
Rc<DxvkShader> m_shader;
|
||||
Rc<DxvkBuffer> m_buffer;
|
||||
|
||||
|
||||
DxbcBindingMask m_bindings = { };
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
#include "d3d11_device.h"
|
||||
#include "d3d11_swapchain.h"
|
||||
|
||||
#include "../dxvk/dxvk_latency_builtin.h"
|
||||
|
||||
#include "../util/util_win32_compat.h"
|
||||
|
||||
namespace dxvk {
|
||||
|
@ -63,16 +65,11 @@ namespace dxvk {
|
|||
m_surfaceFactory(pSurfaceFactory),
|
||||
m_desc(*pDesc),
|
||||
m_device(pDevice->GetDXVKDevice()),
|
||||
m_context(m_device->createContext(DxvkContextType::Supplementary)),
|
||||
m_frameLatencyCap(pDevice->GetOptions()->maxFrameLatency) {
|
||||
CreateFrameLatencyEvent();
|
||||
CreatePresenter();
|
||||
CreateBackBuffer();
|
||||
CreateBackBuffers();
|
||||
CreateBlitter();
|
||||
CreateHud();
|
||||
|
||||
if (!pDevice->GetOptions()->deferSurfaceCreation)
|
||||
RecreateSwapChain();
|
||||
}
|
||||
|
||||
|
||||
|
@ -82,10 +79,10 @@ namespace dxvk {
|
|||
if (this_thread::isInModuleDetachment())
|
||||
return;
|
||||
|
||||
m_device->waitForSubmission(&m_presentStatus);
|
||||
m_device->waitForIdle();
|
||||
m_presenter->destroyResources();
|
||||
|
||||
DestroyFrameLatencyEvent();
|
||||
DestroyLatencyTracker();
|
||||
}
|
||||
|
||||
|
||||
|
@ -99,7 +96,8 @@ namespace dxvk {
|
|||
|
||||
if (riid == __uuidof(IUnknown)
|
||||
|| riid == __uuidof(IDXGIVkSwapChain)
|
||||
|| riid == __uuidof(IDXGIVkSwapChain1)) {
|
||||
|| riid == __uuidof(IDXGIVkSwapChain1)
|
||||
|| riid == __uuidof(IDXGIVkSwapChain2)) {
|
||||
*ppvObject = ref(this);
|
||||
return S_OK;
|
||||
}
|
||||
|
@ -140,12 +138,12 @@ namespace dxvk {
|
|||
void** ppBuffer) {
|
||||
InitReturnPtr(ppBuffer);
|
||||
|
||||
if (BufferId > 0) {
|
||||
Logger::err("D3D11: GetImage: BufferId > 0 not supported");
|
||||
if (BufferId >= m_backBuffers.size()) {
|
||||
Logger::err("D3D11: GetImage: Invalid buffer ID");
|
||||
return DXGI_ERROR_UNSUPPORTED;
|
||||
}
|
||||
|
||||
return m_backBuffer->QueryInterface(riid, ppBuffer);
|
||||
return m_backBuffers[BufferId]->QueryInterface(riid, ppBuffer);
|
||||
}
|
||||
|
||||
|
||||
|
@ -177,14 +175,14 @@ namespace dxvk {
|
|||
const DXGI_SWAP_CHAIN_DESC1* pDesc,
|
||||
const UINT* pNodeMasks,
|
||||
IUnknown* const* ppPresentQueues) {
|
||||
m_dirty |= m_desc.Format != pDesc->Format
|
||||
|| m_desc.Width != pDesc->Width
|
||||
|| m_desc.Height != pDesc->Height
|
||||
|| m_desc.BufferCount != pDesc->BufferCount
|
||||
|| m_desc.Flags != pDesc->Flags;
|
||||
if (m_desc.Format != pDesc->Format)
|
||||
m_presenter->setSurfaceFormat(GetSurfaceFormat(pDesc->Format));
|
||||
|
||||
if (m_desc.Width != pDesc->Width || m_desc.Height != pDesc->Height)
|
||||
m_presenter->setSurfaceExtent({ m_desc.Width, m_desc.Height });
|
||||
|
||||
m_desc = *pDesc;
|
||||
CreateBackBuffer();
|
||||
CreateBackBuffers();
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
@ -254,38 +252,24 @@ namespace dxvk {
|
|||
UINT SyncInterval,
|
||||
UINT PresentFlags,
|
||||
const DXGI_PRESENT_PARAMETERS* pPresentParameters) {
|
||||
auto options = m_parent->GetOptions();
|
||||
|
||||
if (options->syncInterval >= 0)
|
||||
SyncInterval = options->syncInterval;
|
||||
|
||||
if (!(PresentFlags & DXGI_PRESENT_TEST))
|
||||
m_dirty |= m_presenter->setSyncInterval(SyncInterval) != VK_SUCCESS;
|
||||
|
||||
HRESULT hr = S_OK;
|
||||
|
||||
if (!m_presenter->hasSwapChain()) {
|
||||
RecreateSwapChain();
|
||||
m_dirty = false;
|
||||
}
|
||||
|
||||
if (!m_presenter->hasSwapChain())
|
||||
hr = DXGI_STATUS_OCCLUDED;
|
||||
|
||||
if (m_device->getDeviceStatus() != VK_SUCCESS)
|
||||
hr = DXGI_ERROR_DEVICE_RESET;
|
||||
|
||||
if (PresentFlags & DXGI_PRESENT_TEST)
|
||||
return hr;
|
||||
if (PresentFlags & DXGI_PRESENT_TEST) {
|
||||
if (hr != S_OK)
|
||||
return hr;
|
||||
|
||||
VkResult status = m_presenter->checkSwapChainStatus();
|
||||
return status == VK_SUCCESS ? S_OK : DXGI_STATUS_OCCLUDED;
|
||||
}
|
||||
|
||||
if (hr != S_OK) {
|
||||
SyncFrameLatency();
|
||||
return hr;
|
||||
}
|
||||
|
||||
if (std::exchange(m_dirty, false))
|
||||
RecreateSwapChain();
|
||||
|
||||
try {
|
||||
hr = PresentImage(SyncInterval);
|
||||
} catch (const DxvkError& e) {
|
||||
|
@ -298,6 +282,18 @@ namespace dxvk {
|
|||
// applications using the semaphore may deadlock. This works because
|
||||
// we do not increment the frame ID in those situations.
|
||||
SyncFrameLatency();
|
||||
|
||||
// Ignore latency stuff if presentation failed
|
||||
DxvkLatencyStats latencyStats = { };
|
||||
|
||||
if (hr == S_OK && m_latency) {
|
||||
latencyStats = m_latency->getStatistics(m_frameId);
|
||||
m_latency->sleepAndBeginFrame(m_frameId + 1, std::abs(m_targetFrameRate));
|
||||
}
|
||||
|
||||
if (m_latencyHud)
|
||||
m_latencyHud->accumulateStats(latencyStats);
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
|
@ -306,7 +302,8 @@ namespace dxvk {
|
|||
DXGI_COLOR_SPACE_TYPE ColorSpace) {
|
||||
UINT supportFlags = 0;
|
||||
|
||||
const VkColorSpaceKHR vkColorSpace = ConvertColorSpace(ColorSpace);
|
||||
VkColorSpaceKHR vkColorSpace = ConvertColorSpace(ColorSpace);
|
||||
|
||||
if (m_presenter->supportsColorSpace(vkColorSpace))
|
||||
supportFlags |= DXGI_SWAP_CHAIN_COLOR_SPACE_SUPPORT_FLAG_PRESENT;
|
||||
|
||||
|
@ -316,13 +313,14 @@ namespace dxvk {
|
|||
|
||||
HRESULT STDMETHODCALLTYPE D3D11SwapChain::SetColorSpace(
|
||||
DXGI_COLOR_SPACE_TYPE ColorSpace) {
|
||||
if (!(CheckColorSpaceSupport(ColorSpace) & DXGI_SWAP_CHAIN_COLOR_SPACE_SUPPORT_FLAG_PRESENT))
|
||||
VkColorSpaceKHR colorSpace = ConvertColorSpace(ColorSpace);
|
||||
|
||||
if (!m_presenter->supportsColorSpace(colorSpace))
|
||||
return E_INVALIDARG;
|
||||
|
||||
const VkColorSpaceKHR vkColorSpace = ConvertColorSpace(ColorSpace);
|
||||
m_dirty |= vkColorSpace != m_colorspace;
|
||||
m_colorspace = vkColorSpace;
|
||||
m_colorSpace = colorSpace;
|
||||
|
||||
m_presenter->setSurfaceFormat(GetSurfaceFormat(m_desc.Format));
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
@ -330,10 +328,8 @@ namespace dxvk {
|
|||
HRESULT STDMETHODCALLTYPE D3D11SwapChain::SetHDRMetaData(
|
||||
const DXGI_VK_HDR_METADATA* pMetaData) {
|
||||
// For some reason this call always seems to succeed on Windows
|
||||
if (pMetaData->Type == DXGI_HDR_METADATA_TYPE_HDR10) {
|
||||
m_hdrMetadata = ConvertHDRMetadata(pMetaData->HDR10);
|
||||
m_dirtyHdrMetadata = true;
|
||||
}
|
||||
if (pMetaData->Type == DXGI_HDR_METADATA_TYPE_HDR10)
|
||||
m_presenter->setHdrMetadata(ConvertHDRMetadata(pMetaData->HDR10));
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
@ -352,136 +348,146 @@ namespace dxvk {
|
|||
}
|
||||
|
||||
|
||||
void STDMETHODCALLTYPE D3D11SwapChain::SetTargetFrameRate(
|
||||
double FrameRate) {
|
||||
m_targetFrameRate = FrameRate;
|
||||
|
||||
if (m_presenter != nullptr)
|
||||
m_presenter->setFrameRateLimit(m_targetFrameRate, GetActualFrameLatency());
|
||||
}
|
||||
|
||||
|
||||
Rc<DxvkImageView> D3D11SwapChain::GetBackBufferView() {
|
||||
Rc<DxvkImage> image = GetCommonTexture(m_backBuffers[0].ptr())->GetImage();
|
||||
|
||||
DxvkImageViewKey key;
|
||||
key.viewType = VK_IMAGE_VIEW_TYPE_2D;
|
||||
key.usage = VK_IMAGE_USAGE_SAMPLED_BIT;
|
||||
key.format = image->info().format;
|
||||
key.aspects = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
key.mipIndex = 0u;
|
||||
key.mipCount = 1u;
|
||||
key.layerIndex = 0u;
|
||||
key.layerCount = 1u;
|
||||
|
||||
return image->createView(key);
|
||||
}
|
||||
|
||||
|
||||
HRESULT D3D11SwapChain::PresentImage(UINT SyncInterval) {
|
||||
// Flush pending rendering commands before
|
||||
auto immediateContext = m_parent->GetContext();
|
||||
immediateContext->EndFrame();
|
||||
immediateContext->Flush();
|
||||
auto immediateContextLock = immediateContext->LockContext();
|
||||
|
||||
for (uint32_t i = 0; i < SyncInterval || i < 1; i++) {
|
||||
SynchronizePresent();
|
||||
immediateContext->EndFrame(m_latency);
|
||||
immediateContext->ExecuteFlush(GpuFlushType::ExplicitFlush, nullptr, true);
|
||||
|
||||
if (!m_presenter->hasSwapChain())
|
||||
return i ? S_OK : DXGI_STATUS_OCCLUDED;
|
||||
m_presenter->setSyncInterval(SyncInterval);
|
||||
|
||||
// Presentation semaphores and WSI swap chain image
|
||||
PresenterInfo info = m_presenter->info();
|
||||
PresenterSync sync;
|
||||
// Presentation semaphores and WSI swap chain image
|
||||
if (m_latency)
|
||||
m_latency->notifyCpuPresentBegin(m_frameId + 1u);
|
||||
|
||||
uint32_t imageIndex = 0;
|
||||
PresenterSync sync;
|
||||
Rc<DxvkImage> backBuffer;
|
||||
|
||||
VkResult status = m_presenter->acquireNextImage(sync, imageIndex);
|
||||
VkResult status = m_presenter->acquireNextImage(sync, backBuffer);
|
||||
|
||||
while (status != VK_SUCCESS && status != VK_SUBOPTIMAL_KHR) {
|
||||
RecreateSwapChain();
|
||||
if (status != VK_SUCCESS && m_latency)
|
||||
m_latency->discardTimings();
|
||||
|
||||
if (!m_presenter->hasSwapChain())
|
||||
return i ? S_OK : DXGI_STATUS_OCCLUDED;
|
||||
|
||||
info = m_presenter->info();
|
||||
status = m_presenter->acquireNextImage(sync, imageIndex);
|
||||
if (status < 0)
|
||||
return E_FAIL;
|
||||
|
||||
if (status == VK_NOT_READY)
|
||||
return DXGI_STATUS_OCCLUDED;
|
||||
|
||||
m_frameId += 1;
|
||||
|
||||
// Present from CS thread so that we don't
|
||||
// have to synchronize with it first.
|
||||
DxvkImageViewKey viewInfo = { };
|
||||
viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
|
||||
viewInfo.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
|
||||
viewInfo.format = backBuffer->info().format;
|
||||
viewInfo.aspects = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
viewInfo.mipIndex = 0u;
|
||||
viewInfo.mipCount = 1u;
|
||||
viewInfo.layerIndex = 0u;
|
||||
viewInfo.layerCount = 1u;
|
||||
|
||||
immediateContext->EmitCs([
|
||||
cDevice = m_device,
|
||||
cBlitter = m_blitter,
|
||||
cBackBuffer = backBuffer->createView(viewInfo),
|
||||
cSwapImage = GetBackBufferView(),
|
||||
cSync = sync,
|
||||
cPresenter = m_presenter,
|
||||
cLatency = m_latency,
|
||||
cColorSpace = m_colorSpace,
|
||||
cFrameId = m_frameId
|
||||
] (DxvkContext* ctx) {
|
||||
// Update back buffer color space as necessary
|
||||
if (cSwapImage->image()->info().colorSpace != cColorSpace) {
|
||||
DxvkImageUsageInfo usage = { };
|
||||
usage.colorSpace = cColorSpace;
|
||||
|
||||
ctx->ensureImageCompatibility(cSwapImage->image(), usage);
|
||||
}
|
||||
|
||||
if (m_hdrMetadata && m_dirtyHdrMetadata) {
|
||||
m_presenter->setHdrMetadata(*m_hdrMetadata);
|
||||
m_dirtyHdrMetadata = false;
|
||||
// Blit the D3D back buffer onto the actual Vulkan
|
||||
// swap chain and render the HUD if we have one.
|
||||
auto contextObjects = ctx->beginExternalRendering();
|
||||
|
||||
cBlitter->present(contextObjects,
|
||||
cBackBuffer, VkRect2D(),
|
||||
cSwapImage, VkRect2D());
|
||||
|
||||
// Submit current command list and present
|
||||
ctx->synchronizeWsi(cSync);
|
||||
ctx->flushCommandList(nullptr, nullptr);
|
||||
|
||||
cDevice->presentImage(cPresenter, cLatency, cFrameId, nullptr);
|
||||
});
|
||||
|
||||
if (m_backBuffers.size() > 1u)
|
||||
RotateBackBuffers(immediateContext);
|
||||
|
||||
immediateContext->FlushCsChunk();
|
||||
|
||||
if (m_latency) {
|
||||
m_latency->notifyCpuPresentEnd(m_frameId);
|
||||
|
||||
if (m_latency->needsAutoMarkers()) {
|
||||
immediateContext->EmitCs([
|
||||
cLatency = m_latency,
|
||||
cFrameId = m_frameId
|
||||
] (DxvkContext* ctx) {
|
||||
ctx->beginLatencyTracking(cLatency, cFrameId + 1u);
|
||||
});
|
||||
}
|
||||
|
||||
m_context->beginRecording(
|
||||
m_device->createCommandList());
|
||||
|
||||
m_blitter->presentImage(m_context.ptr(),
|
||||
m_imageViews.at(imageIndex), VkRect2D(),
|
||||
m_swapImageView, VkRect2D());
|
||||
|
||||
if (m_hud != nullptr)
|
||||
m_hud->render(m_context, info.format, info.imageExtent);
|
||||
|
||||
SubmitPresent(immediateContext, sync, i);
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
void D3D11SwapChain::SubmitPresent(
|
||||
D3D11ImmediateContext* pContext,
|
||||
const PresenterSync& Sync,
|
||||
uint32_t Repeat) {
|
||||
auto lock = pContext->LockContext();
|
||||
void D3D11SwapChain::RotateBackBuffers(D3D11ImmediateContext* ctx) {
|
||||
small_vector<Rc<DxvkImage>, 4> images;
|
||||
|
||||
// Bump frame ID as necessary
|
||||
if (!Repeat)
|
||||
m_frameId += 1;
|
||||
for (uint32_t i = 0; i < m_backBuffers.size(); i++)
|
||||
images.push_back(GetCommonTexture(m_backBuffers[i].ptr())->GetImage());
|
||||
|
||||
// Present from CS thread so that we don't
|
||||
// have to synchronize with it first.
|
||||
m_presentStatus.result = VK_NOT_READY;
|
||||
|
||||
pContext->EmitCs([this,
|
||||
cRepeat = Repeat,
|
||||
cSync = Sync,
|
||||
cHud = m_hud,
|
||||
cPresentMode = m_presenter->info().presentMode,
|
||||
cFrameId = m_frameId,
|
||||
cCommandList = m_context->endRecording()
|
||||
ctx->EmitCs([
|
||||
cImages = std::move(images)
|
||||
] (DxvkContext* ctx) {
|
||||
cCommandList->setWsiSemaphores(cSync);
|
||||
m_device->submitCommandList(cCommandList, nullptr);
|
||||
auto allocation = cImages[0]->storage();
|
||||
|
||||
if (cHud != nullptr && !cRepeat)
|
||||
cHud->update();
|
||||
for (size_t i = 0u; i + 1 < cImages.size(); i++)
|
||||
ctx->invalidateImage(cImages[i], cImages[i + 1]->storage());
|
||||
|
||||
uint64_t frameId = cRepeat ? 0 : cFrameId;
|
||||
|
||||
m_device->presentImage(m_presenter,
|
||||
cPresentMode, frameId, &m_presentStatus);
|
||||
ctx->invalidateImage(cImages[cImages.size() - 1u], std::move(allocation));
|
||||
});
|
||||
|
||||
pContext->FlushCsChunk();
|
||||
}
|
||||
|
||||
|
||||
void D3D11SwapChain::SynchronizePresent() {
|
||||
// Recreate swap chain if the previous present call failed
|
||||
VkResult status = m_device->waitForSubmission(&m_presentStatus);
|
||||
|
||||
if (status != VK_SUCCESS)
|
||||
RecreateSwapChain();
|
||||
}
|
||||
|
||||
|
||||
void D3D11SwapChain::RecreateSwapChain() {
|
||||
// Ensure that we can safely destroy the swap chain
|
||||
m_device->waitForSubmission(&m_presentStatus);
|
||||
m_device->waitForIdle();
|
||||
|
||||
m_presentStatus.result = VK_SUCCESS;
|
||||
m_dirtyHdrMetadata = true;
|
||||
|
||||
PresenterDesc presenterDesc;
|
||||
presenterDesc.imageExtent = { m_desc.Width, m_desc.Height };
|
||||
presenterDesc.imageCount = PickImageCount(m_desc.BufferCount + 1);
|
||||
presenterDesc.numFormats = PickFormats(m_desc.Format, presenterDesc.formats);
|
||||
presenterDesc.fullScreenExclusive = PickFullscreenMode();
|
||||
|
||||
VkResult vr = m_presenter->recreateSwapChain(presenterDesc);
|
||||
|
||||
if (vr == VK_ERROR_SURFACE_LOST_KHR) {
|
||||
vr = m_presenter->recreateSurface([this] (VkSurfaceKHR* surface) {
|
||||
return CreateSurface(surface);
|
||||
});
|
||||
|
||||
if (vr)
|
||||
throw DxvkError(str::format("D3D11SwapChain: Failed to recreate surface: ", vr));
|
||||
|
||||
vr = m_presenter->recreateSwapChain(presenterDesc);
|
||||
}
|
||||
|
||||
if (vr)
|
||||
throw DxvkError(str::format("D3D11SwapChain: Failed to recreate swap chain: ", vr));
|
||||
|
||||
CreateRenderTargetViews();
|
||||
}
|
||||
|
||||
|
||||
|
@ -494,76 +500,37 @@ namespace dxvk {
|
|||
|
||||
|
||||
void D3D11SwapChain::CreatePresenter() {
|
||||
PresenterDesc presenterDesc;
|
||||
presenterDesc.imageExtent = { m_desc.Width, m_desc.Height };
|
||||
presenterDesc.imageCount = PickImageCount(m_desc.BufferCount + 1);
|
||||
presenterDesc.numFormats = PickFormats(m_desc.Format, presenterDesc.formats);
|
||||
presenterDesc.fullScreenExclusive = PickFullscreenMode();
|
||||
PresenterDesc presenterDesc = { };
|
||||
presenterDesc.deferSurfaceCreation = m_parent->GetOptions()->deferSurfaceCreation;
|
||||
|
||||
m_presenter = new Presenter(m_device, m_frameLatencySignal, presenterDesc);
|
||||
m_presenter->setFrameRateLimit(m_parent->GetOptions()->maxFrameRate);
|
||||
m_presenter = new Presenter(m_device, m_frameLatencySignal, presenterDesc, [
|
||||
cAdapter = m_device->adapter(),
|
||||
cFactory = m_surfaceFactory
|
||||
] (VkSurfaceKHR* surface) {
|
||||
return cFactory->CreateSurface(
|
||||
cAdapter->vki()->instance(),
|
||||
cAdapter->handle(), surface);
|
||||
});
|
||||
|
||||
m_presenter->setSurfaceFormat(GetSurfaceFormat(m_desc.Format));
|
||||
m_presenter->setSurfaceExtent({ m_desc.Width, m_desc.Height });
|
||||
m_presenter->setFrameRateLimit(m_targetFrameRate, GetActualFrameLatency());
|
||||
|
||||
m_latency = m_device->createLatencyTracker(m_presenter);
|
||||
|
||||
Com<D3D11ReflexDevice> reflex = GetReflexDevice();
|
||||
reflex->RegisterLatencyTracker(m_latency);
|
||||
}
|
||||
|
||||
|
||||
VkResult D3D11SwapChain::CreateSurface(VkSurfaceKHR* pSurface) {
|
||||
Rc<DxvkAdapter> adapter = m_device->adapter();
|
||||
|
||||
return m_surfaceFactory->CreateSurface(
|
||||
adapter->vki()->instance(),
|
||||
adapter->handle(), pSurface);
|
||||
}
|
||||
|
||||
|
||||
void D3D11SwapChain::CreateRenderTargetViews() {
|
||||
PresenterInfo info = m_presenter->info();
|
||||
|
||||
m_imageViews.clear();
|
||||
m_imageViews.resize(info.imageCount);
|
||||
|
||||
DxvkImageCreateInfo imageInfo;
|
||||
imageInfo.type = VK_IMAGE_TYPE_2D;
|
||||
imageInfo.format = info.format.format;
|
||||
imageInfo.flags = 0;
|
||||
imageInfo.sampleCount = VK_SAMPLE_COUNT_1_BIT;
|
||||
imageInfo.extent = { info.imageExtent.width, info.imageExtent.height, 1 };
|
||||
imageInfo.numLayers = 1;
|
||||
imageInfo.mipLevels = 1;
|
||||
imageInfo.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
|
||||
imageInfo.stages = 0;
|
||||
imageInfo.access = 0;
|
||||
imageInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
|
||||
imageInfo.layout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
|
||||
imageInfo.shared = VK_TRUE;
|
||||
|
||||
DxvkImageViewCreateInfo viewInfo;
|
||||
viewInfo.type = VK_IMAGE_VIEW_TYPE_2D;
|
||||
viewInfo.format = info.format.format;
|
||||
viewInfo.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
|
||||
viewInfo.aspect = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
viewInfo.minLevel = 0;
|
||||
viewInfo.numLevels = 1;
|
||||
viewInfo.minLayer = 0;
|
||||
viewInfo.numLayers = 1;
|
||||
|
||||
for (uint32_t i = 0; i < info.imageCount; i++) {
|
||||
VkImage imageHandle = m_presenter->getImage(i).image;
|
||||
|
||||
Rc<DxvkImage> image = new DxvkImage(
|
||||
m_device.ptr(), imageInfo, imageHandle,
|
||||
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
|
||||
|
||||
m_imageViews[i] = new DxvkImageView(
|
||||
m_device->vkd(), image, viewInfo);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void D3D11SwapChain::CreateBackBuffer() {
|
||||
void D3D11SwapChain::CreateBackBuffers() {
|
||||
// Explicitly destroy current swap image before
|
||||
// creating a new one to free up resources
|
||||
m_swapImage = nullptr;
|
||||
m_swapImageView = nullptr;
|
||||
m_backBuffer = nullptr;
|
||||
m_backBuffers.clear();
|
||||
|
||||
bool sequential = m_desc.SwapEffect == DXGI_SWAP_EFFECT_SEQUENTIAL ||
|
||||
m_desc.SwapEffect == DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL;
|
||||
uint32_t backBufferCount = sequential ? m_desc.BufferCount : 1u;
|
||||
|
||||
// Create new back buffer
|
||||
D3D11_COMMON_TEXTURE_DESC desc;
|
||||
|
@ -594,57 +561,49 @@ namespace dxvk {
|
|||
|
||||
DXGI_USAGE dxgiUsage = DXGI_USAGE_BACK_BUFFER;
|
||||
|
||||
if (m_desc.SwapEffect == DXGI_SWAP_EFFECT_DISCARD
|
||||
|| m_desc.SwapEffect == DXGI_SWAP_EFFECT_FLIP_DISCARD)
|
||||
dxgiUsage |= DXGI_USAGE_DISCARD_ON_PRESENT;
|
||||
for (uint32_t i = 0; i < backBufferCount; i++) {
|
||||
if (m_desc.SwapEffect == DXGI_SWAP_EFFECT_DISCARD
|
||||
|| m_desc.SwapEffect == DXGI_SWAP_EFFECT_FLIP_DISCARD)
|
||||
dxgiUsage |= DXGI_USAGE_DISCARD_ON_PRESENT;
|
||||
|
||||
m_backBuffer = new D3D11Texture2D(m_parent, this, &desc, dxgiUsage);
|
||||
m_swapImage = GetCommonTexture(m_backBuffer.ptr())->GetImage();
|
||||
m_backBuffers.push_back(new D3D11Texture2D(
|
||||
m_parent, this, &desc, dxgiUsage));
|
||||
|
||||
// Create an image view that allows the
|
||||
// image to be bound as a shader resource.
|
||||
DxvkImageViewCreateInfo viewInfo;
|
||||
viewInfo.type = VK_IMAGE_VIEW_TYPE_2D;
|
||||
viewInfo.format = m_swapImage->info().format;
|
||||
viewInfo.usage = VK_IMAGE_USAGE_SAMPLED_BIT;
|
||||
viewInfo.aspect = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
viewInfo.minLevel = 0;
|
||||
viewInfo.numLevels = 1;
|
||||
viewInfo.minLayer = 0;
|
||||
viewInfo.numLayers = 1;
|
||||
m_swapImageView = m_device->createImageView(m_swapImage, viewInfo);
|
||||
|
||||
// Initialize the image so that we can use it. Clearing
|
||||
dxgiUsage |= DXGI_USAGE_READ_ONLY;
|
||||
}
|
||||
|
||||
small_vector<Rc<DxvkImage>, 4> images;
|
||||
|
||||
for (uint32_t i = 0; i < backBufferCount; i++)
|
||||
images.push_back(GetCommonTexture(m_backBuffers[i].ptr())->GetImage());
|
||||
|
||||
// Initialize images so that we can use them. Clearing
|
||||
// to black prevents garbled output for the first frame.
|
||||
VkImageSubresourceRange subresources;
|
||||
subresources.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
subresources.baseMipLevel = 0;
|
||||
subresources.levelCount = 1;
|
||||
subresources.baseArrayLayer = 0;
|
||||
subresources.layerCount = 1;
|
||||
m_parent->GetContext()->InjectCs(DxvkCsQueue::HighPriority, [
|
||||
cImages = std::move(images)
|
||||
] (DxvkContext* ctx) {
|
||||
for (size_t i = 0; i < cImages.size(); i++) {
|
||||
ctx->setDebugName(cImages[i], str::format("Back buffer ", i).c_str());
|
||||
|
||||
m_context->beginRecording(
|
||||
m_device->createCommandList());
|
||||
|
||||
m_context->initImage(m_swapImage,
|
||||
subresources, VK_IMAGE_LAYOUT_UNDEFINED);
|
||||
|
||||
m_device->submitCommandList(
|
||||
m_context->endRecording(),
|
||||
nullptr);
|
||||
ctx->initImage(cImages[i],
|
||||
cImages[i]->getAvailableSubresources(),
|
||||
VK_IMAGE_LAYOUT_UNDEFINED);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
void D3D11SwapChain::CreateBlitter() {
|
||||
m_blitter = new DxvkSwapchainBlitter(m_device);
|
||||
}
|
||||
Rc<hud::Hud> hud = hud::Hud::createHud(m_device);
|
||||
|
||||
if (hud) {
|
||||
hud->addItem<hud::HudClientApiItem>("api", 1, GetApiName());
|
||||
|
||||
void D3D11SwapChain::CreateHud() {
|
||||
m_hud = hud::Hud::createHud(m_device);
|
||||
if (m_latency)
|
||||
m_latencyHud = hud->addItem<hud::HudLatencyItem>("latency", 4);
|
||||
}
|
||||
|
||||
if (m_hud != nullptr)
|
||||
m_hud->addItem<hud::HudClientApiItem>("api", 1, GetApiName());
|
||||
m_blitter = new DxvkSwapchainBlitter(m_device, std::move(hud));
|
||||
}
|
||||
|
||||
|
||||
|
@ -653,6 +612,20 @@ namespace dxvk {
|
|||
}
|
||||
|
||||
|
||||
void D3D11SwapChain::DestroyLatencyTracker() {
|
||||
// Need to make sure the context stops using
|
||||
// the tracker for submissions
|
||||
m_parent->GetContext()->InjectCs(DxvkCsQueue::Ordered, [
|
||||
cLatency = m_latency
|
||||
] (DxvkContext* ctx) {
|
||||
ctx->endLatencyTracking(cLatency);
|
||||
});
|
||||
|
||||
Com<D3D11ReflexDevice> reflex = GetReflexDevice();
|
||||
reflex->UnregisterLatencyTracker(m_latency);
|
||||
}
|
||||
|
||||
|
||||
void D3D11SwapChain::SyncFrameLatency() {
|
||||
// Wait for the sync event so that we respect the maximum frame latency
|
||||
m_frameLatencySignal->wait(m_frameId - GetActualFrameLatency());
|
||||
|
@ -688,53 +661,34 @@ namespace dxvk {
|
|||
}
|
||||
|
||||
|
||||
uint32_t D3D11SwapChain::PickFormats(
|
||||
DXGI_FORMAT Format,
|
||||
VkSurfaceFormatKHR* pDstFormats) {
|
||||
uint32_t n = 0;
|
||||
|
||||
VkSurfaceFormatKHR D3D11SwapChain::GetSurfaceFormat(DXGI_FORMAT Format) {
|
||||
switch (Format) {
|
||||
default:
|
||||
Logger::warn(str::format("D3D11SwapChain: Unexpected format: ", m_desc.Format));
|
||||
[[fallthrough]];
|
||||
|
||||
[[fallthrough]];
|
||||
|
||||
case DXGI_FORMAT_R8G8B8A8_UNORM:
|
||||
case DXGI_FORMAT_B8G8R8A8_UNORM: {
|
||||
pDstFormats[n++] = { VK_FORMAT_R8G8B8A8_UNORM, m_colorspace };
|
||||
pDstFormats[n++] = { VK_FORMAT_B8G8R8A8_UNORM, m_colorspace };
|
||||
} break;
|
||||
|
||||
case DXGI_FORMAT_B8G8R8A8_UNORM:
|
||||
return { VK_FORMAT_R8G8B8A8_UNORM, m_colorSpace };
|
||||
|
||||
case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB:
|
||||
case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB: {
|
||||
pDstFormats[n++] = { VK_FORMAT_R8G8B8A8_SRGB, m_colorspace };
|
||||
pDstFormats[n++] = { VK_FORMAT_B8G8R8A8_SRGB, m_colorspace };
|
||||
} break;
|
||||
|
||||
case DXGI_FORMAT_R10G10B10A2_UNORM: {
|
||||
pDstFormats[n++] = { VK_FORMAT_A2B10G10R10_UNORM_PACK32, m_colorspace };
|
||||
pDstFormats[n++] = { VK_FORMAT_A2R10G10B10_UNORM_PACK32, m_colorspace };
|
||||
} break;
|
||||
|
||||
case DXGI_FORMAT_R16G16B16A16_FLOAT: {
|
||||
pDstFormats[n++] = { VK_FORMAT_R16G16B16A16_SFLOAT, m_colorspace };
|
||||
} break;
|
||||
case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB:
|
||||
return { VK_FORMAT_R8G8B8A8_SRGB, m_colorSpace };
|
||||
|
||||
case DXGI_FORMAT_R10G10B10A2_UNORM:
|
||||
return { VK_FORMAT_A2B10G10R10_UNORM_PACK32, m_colorSpace };
|
||||
|
||||
case DXGI_FORMAT_R16G16B16A16_FLOAT:
|
||||
return { VK_FORMAT_R16G16B16A16_SFLOAT, m_colorSpace };
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
|
||||
uint32_t D3D11SwapChain::PickImageCount(
|
||||
UINT Preferred) {
|
||||
int32_t option = m_parent->GetOptions()->numBackBuffers;
|
||||
return option > 0 ? uint32_t(option) : uint32_t(Preferred);
|
||||
}
|
||||
Com<D3D11ReflexDevice> D3D11SwapChain::GetReflexDevice() {
|
||||
Com<ID3DLowLatencyDevice> llDevice;
|
||||
m_parent->QueryInterface(__uuidof(ID3DLowLatencyDevice), reinterpret_cast<void**>(&llDevice));
|
||||
|
||||
|
||||
VkFullScreenExclusiveEXT D3D11SwapChain::PickFullscreenMode() {
|
||||
return m_desc.Flags & DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH
|
||||
? VK_FULL_SCREEN_EXCLUSIVE_ALLOWED_EXT
|
||||
: VK_FULL_SCREEN_EXCLUSIVE_DISALLOWED_EXT;
|
||||
return static_cast<D3D11ReflexDevice*>(llDevice.ptr());
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
#include "../dxvk/hud/dxvk_hud.h"
|
||||
|
||||
#include "../dxvk/dxvk_latency.h"
|
||||
#include "../dxvk/dxvk_swapchain_blitter.h"
|
||||
|
||||
#include "../util/sync/sync_signal.h"
|
||||
|
@ -13,7 +14,7 @@ namespace dxvk {
|
|||
class D3D11Device;
|
||||
class D3D11DXGIDevice;
|
||||
|
||||
class D3D11SwapChain : public ComObject<IDXGIVkSwapChain1> {
|
||||
class D3D11SwapChain : public ComObject<IDXGIVkSwapChain2> {
|
||||
constexpr static uint32_t DefaultFrameLatency = 1;
|
||||
public:
|
||||
|
||||
|
@ -86,6 +87,9 @@ namespace dxvk {
|
|||
void STDMETHODCALLTYPE GetFrameStatistics(
|
||||
DXGI_VK_FRAME_STATISTICS* pFrameStatistics);
|
||||
|
||||
void STDMETHODCALLTYPE SetTargetFrameRate(
|
||||
double FrameRate);
|
||||
|
||||
private:
|
||||
|
||||
enum BindingIds : uint32_t {
|
||||
|
@ -101,76 +105,53 @@ namespace dxvk {
|
|||
DXGI_SWAP_CHAIN_DESC1 m_desc;
|
||||
|
||||
Rc<DxvkDevice> m_device;
|
||||
Rc<DxvkContext> m_context;
|
||||
|
||||
Rc<Presenter> m_presenter;
|
||||
|
||||
Rc<DxvkImage> m_swapImage;
|
||||
Rc<DxvkImageView> m_swapImageView;
|
||||
Rc<DxvkSwapchainBlitter> m_blitter;
|
||||
Rc<DxvkLatencyTracker> m_latency;
|
||||
|
||||
Rc<hud::Hud> m_hud;
|
||||
small_vector<Com<D3D11Texture2D, false>, 4> m_backBuffers;
|
||||
|
||||
Com<D3D11Texture2D, false> m_backBuffer;
|
||||
DxvkSubmitStatus m_presentStatus;
|
||||
uint64_t m_frameId = DXGI_MAX_SWAP_CHAIN_BUFFERS;
|
||||
uint32_t m_frameLatency = DefaultFrameLatency;
|
||||
uint32_t m_frameLatencyCap = 0;
|
||||
HANDLE m_frameLatencyEvent = nullptr;
|
||||
Rc<sync::CallbackFence> m_frameLatencySignal;
|
||||
|
||||
std::vector<Rc<DxvkImageView>> m_imageViews;
|
||||
VkColorSpaceKHR m_colorSpace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR;
|
||||
|
||||
uint64_t m_frameId = DXGI_MAX_SWAP_CHAIN_BUFFERS;
|
||||
uint32_t m_frameLatency = DefaultFrameLatency;
|
||||
uint32_t m_frameLatencyCap = 0;
|
||||
HANDLE m_frameLatencyEvent = nullptr;
|
||||
Rc<sync::CallbackFence> m_frameLatencySignal;
|
||||
|
||||
bool m_dirty = true;
|
||||
|
||||
VkColorSpaceKHR m_colorspace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR;
|
||||
|
||||
std::optional<VkHdrMetadataEXT> m_hdrMetadata;
|
||||
bool m_dirtyHdrMetadata = true;
|
||||
double m_targetFrameRate = 0.0;
|
||||
|
||||
dxvk::mutex m_frameStatisticsLock;
|
||||
DXGI_VK_FRAME_STATISTICS m_frameStatistics = { };
|
||||
|
||||
Rc<hud::HudLatencyItem> m_latencyHud;
|
||||
|
||||
Rc<DxvkImageView> GetBackBufferView();
|
||||
|
||||
HRESULT PresentImage(UINT SyncInterval);
|
||||
|
||||
void SubmitPresent(
|
||||
D3D11ImmediateContext* pContext,
|
||||
const PresenterSync& Sync,
|
||||
uint32_t Repeat);
|
||||
|
||||
void SynchronizePresent();
|
||||
|
||||
void RecreateSwapChain();
|
||||
void RotateBackBuffers(D3D11ImmediateContext* ctx);
|
||||
|
||||
void CreateFrameLatencyEvent();
|
||||
|
||||
void CreatePresenter();
|
||||
|
||||
VkResult CreateSurface(VkSurfaceKHR* pSurface);
|
||||
|
||||
void CreateRenderTargetViews();
|
||||
|
||||
void CreateBackBuffer();
|
||||
void CreateBackBuffers();
|
||||
|
||||
void CreateBlitter();
|
||||
|
||||
void CreateHud();
|
||||
|
||||
void DestroyFrameLatencyEvent();
|
||||
|
||||
void DestroyLatencyTracker();
|
||||
|
||||
void SyncFrameLatency();
|
||||
|
||||
uint32_t GetActualFrameLatency();
|
||||
|
||||
uint32_t PickFormats(
|
||||
DXGI_FORMAT Format,
|
||||
VkSurfaceFormatKHR* pDstFormats);
|
||||
|
||||
uint32_t PickImageCount(
|
||||
UINT Preferred);
|
||||
|
||||
VkFullScreenExclusiveEXT PickFullscreenMode();
|
||||
|
||||
VkSurfaceFormatKHR GetSurfaceFormat(DXGI_FORMAT Format);
|
||||
|
||||
Com<D3D11ReflexDevice> GetReflexDevice();
|
||||
|
||||
std::string GetApiName() const;
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
#include "d3d11_device.h"
|
||||
#include "d3d11_context_imm.h"
|
||||
#include "d3d11_gdi.h"
|
||||
#include "d3d11_texture.h"
|
||||
|
||||
|
@ -58,9 +59,6 @@ namespace dxvk {
|
|||
"\n MiscFlags: ", m_desc.MiscFlags,
|
||||
"\n FeatureLevel: ", pDevice->GetFeatureLevel()));
|
||||
|
||||
if (m_desc.MiscFlags & D3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX)
|
||||
Logger::warn("D3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX: not supported.");
|
||||
|
||||
imageInfo.shared = true;
|
||||
imageInfo.sharing.mode = hSharedHandle == INVALID_HANDLE_VALUE ? DxvkSharedHandleMode::Export : DxvkSharedHandleMode::Import;
|
||||
imageInfo.sharing.type = (m_desc.MiscFlags & D3D11_RESOURCE_MISC_SHARED_NTHANDLE)
|
||||
|
@ -171,7 +169,8 @@ namespace dxvk {
|
|||
imageInfo.tiling = VK_IMAGE_TILING_LINEAR;
|
||||
|
||||
// Determine map mode based on our findings
|
||||
m_mapMode = DetermineMapMode(&imageInfo);
|
||||
VkMemoryPropertyFlags memoryProperties = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
|
||||
std::tie(m_mapMode, memoryProperties) = DetermineMapMode(&imageInfo);
|
||||
|
||||
// If the image is mapped directly to host memory, we need
|
||||
// to enable linear tiling, and DXVK needs to be aware that
|
||||
|
@ -190,14 +189,25 @@ namespace dxvk {
|
|||
}
|
||||
|
||||
// If necessary, create the mapped linear buffer
|
||||
if (m_mapMode != D3D11_COMMON_TEXTURE_MAP_MODE_NONE) {
|
||||
for (uint32_t i = 0; i < m_desc.ArraySize; i++) {
|
||||
for (uint32_t j = 0; j < m_desc.MipLevels; j++) {
|
||||
if (m_mapMode != D3D11_COMMON_TEXTURE_MAP_MODE_DIRECT)
|
||||
m_buffers.push_back(CreateMappedBuffer(j));
|
||||
uint32_t subresourceCount = m_desc.ArraySize * m_desc.MipLevels;
|
||||
|
||||
m_mapInfo.push_back({ D3D11_MAP(~0u), 0ull });
|
||||
}
|
||||
if (m_mapMode != D3D11_COMMON_TEXTURE_MAP_MODE_NONE) {
|
||||
m_mapInfo.resize(subresourceCount);
|
||||
|
||||
for (uint32_t i = 0; i < subresourceCount; i++) {
|
||||
m_mapInfo[i].layout = DetermineSubresourceLayout(&imageInfo,
|
||||
GetSubresourceFromIndex(formatProperties->aspectMask, i));
|
||||
}
|
||||
}
|
||||
|
||||
if (m_mapMode == D3D11_COMMON_TEXTURE_MAP_MODE_BUFFER
|
||||
|| m_mapMode == D3D11_COMMON_TEXTURE_MAP_MODE_STAGING
|
||||
|| m_mapMode == D3D11_COMMON_TEXTURE_MAP_MODE_DYNAMIC) {
|
||||
m_buffers.resize(subresourceCount);
|
||||
|
||||
if (m_mapMode != D3D11_COMMON_TEXTURE_MAP_MODE_DYNAMIC) {
|
||||
for (uint32_t i = 0; i < subresourceCount; i++)
|
||||
CreateMappedBuffer(i);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -211,12 +221,6 @@ namespace dxvk {
|
|||
if (imageInfo.tiling == VK_IMAGE_TILING_OPTIMAL && !isMultiPlane && imageInfo.sharing.mode == DxvkSharedHandleMode::None)
|
||||
imageInfo.layout = OptimizeLayout(imageInfo.usage);
|
||||
|
||||
// For some formats, we need to enable sampled and/or
|
||||
// render target capabilities if available, but these
|
||||
// should in no way affect the default image layout
|
||||
imageInfo.usage |= EnableMetaCopyUsage(imageInfo.format, imageInfo.tiling);
|
||||
imageInfo.usage |= EnableMetaPackUsage(imageInfo.format, m_desc.CPUAccessFlags);
|
||||
|
||||
// Check if we can actually create the image
|
||||
if (!CheckImageSupport(&imageInfo, imageInfo.tiling)) {
|
||||
throw DxvkError(str::format(
|
||||
|
@ -231,14 +235,7 @@ namespace dxvk {
|
|||
"\n Usage: ", std::hex, m_desc.BindFlags,
|
||||
"\n Flags: ", std::hex, m_desc.MiscFlags));
|
||||
}
|
||||
|
||||
// Create the image on a host-visible memory type
|
||||
// in case it is going to be mapped directly.
|
||||
VkMemoryPropertyFlags memoryProperties = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
|
||||
|
||||
if (m_mapMode == D3D11_COMMON_TEXTURE_MAP_MODE_DIRECT)
|
||||
memoryProperties = GetMemoryFlags();
|
||||
|
||||
|
||||
if (m_11on12.Resource != nullptr)
|
||||
vkImage = VkImage(m_11on12.VulkanHandle);
|
||||
|
||||
|
@ -247,6 +244,9 @@ namespace dxvk {
|
|||
else
|
||||
m_image = m_device->GetDXVKDevice()->importImage(imageInfo, vkImage, memoryProperties);
|
||||
|
||||
if (m_mapMode == D3D11_COMMON_TEXTURE_MAP_MODE_DIRECT)
|
||||
m_mapPtr = m_image->mapPtr(0);
|
||||
|
||||
if (imageInfo.sharing.mode == DxvkSharedHandleMode::Export)
|
||||
ExportImageInfo();
|
||||
}
|
||||
|
@ -281,73 +281,24 @@ namespace dxvk {
|
|||
}
|
||||
|
||||
|
||||
VkImageSubresource D3D11CommonTexture::GetSubresourceFromIndex(
|
||||
VkImageAspectFlags Aspect,
|
||||
UINT Subresource) const {
|
||||
VkImageSubresource result;
|
||||
result.aspectMask = Aspect;
|
||||
result.mipLevel = Subresource % m_desc.MipLevels;
|
||||
result.arrayLayer = Subresource / m_desc.MipLevels;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
D3D11_COMMON_TEXTURE_SUBRESOURCE_LAYOUT D3D11CommonTexture::GetSubresourceLayout(
|
||||
VkImageAspectFlags AspectMask,
|
||||
UINT Subresource) const {
|
||||
// Color is mapped directly and depth-stencil are interleaved
|
||||
// in packed formats, so just use the cached subresource layout
|
||||
constexpr VkImageAspectFlags PlaneAspects = VK_IMAGE_ASPECT_PLANE_0_BIT
|
||||
| VK_IMAGE_ASPECT_PLANE_1_BIT | VK_IMAGE_ASPECT_PLANE_2_BIT;
|
||||
|
||||
if ((Subresource < m_mapInfo.size()) && !(AspectMask & PlaneAspects))
|
||||
return m_mapInfo[Subresource].layout;
|
||||
|
||||
// Safe-guard against invalid subresource index
|
||||
if (Subresource >= m_desc.ArraySize * m_desc.MipLevels)
|
||||
return D3D11_COMMON_TEXTURE_SUBRESOURCE_LAYOUT();
|
||||
|
||||
// Image info is only needed for direct-mapped images
|
||||
VkImageSubresource subresource = GetSubresourceFromIndex(AspectMask, Subresource);
|
||||
D3D11_COMMON_TEXTURE_SUBRESOURCE_LAYOUT layout = { };
|
||||
|
||||
switch (m_mapMode) {
|
||||
case D3D11_COMMON_TEXTURE_MAP_MODE_DIRECT: {
|
||||
auto vkLayout = m_image->querySubresourceLayout(subresource);
|
||||
layout.Offset = vkLayout.offset;
|
||||
layout.Size = vkLayout.size;
|
||||
layout.RowPitch = vkLayout.rowPitch;
|
||||
layout.DepthPitch = vkLayout.depthPitch;
|
||||
} break;
|
||||
|
||||
case D3D11_COMMON_TEXTURE_MAP_MODE_NONE:
|
||||
case D3D11_COMMON_TEXTURE_MAP_MODE_BUFFER:
|
||||
case D3D11_COMMON_TEXTURE_MAP_MODE_STAGING: {
|
||||
auto packedFormatInfo = lookupFormatInfo(m_packedFormat);
|
||||
|
||||
VkImageAspectFlags aspects = packedFormatInfo->aspectMask;
|
||||
VkExtent3D mipExtent = MipLevelExtent(subresource.mipLevel);
|
||||
|
||||
while (aspects) {
|
||||
auto aspect = vk::getNextAspect(aspects);
|
||||
auto extent = mipExtent;
|
||||
auto elementSize = packedFormatInfo->elementSize;
|
||||
|
||||
if (packedFormatInfo->flags.test(DxvkFormatFlag::MultiPlane)) {
|
||||
auto plane = &packedFormatInfo->planes[vk::getPlaneIndex(aspect)];
|
||||
extent.width /= plane->blockSize.width;
|
||||
extent.height /= plane->blockSize.height;
|
||||
elementSize = plane->elementSize;
|
||||
}
|
||||
|
||||
auto blockCount = util::computeBlockCount(extent, packedFormatInfo->blockSize);
|
||||
|
||||
if (!layout.RowPitch) {
|
||||
layout.RowPitch = elementSize * blockCount.width;
|
||||
layout.DepthPitch = elementSize * blockCount.width * blockCount.height;
|
||||
}
|
||||
|
||||
VkDeviceSize size = elementSize * blockCount.width * blockCount.height * blockCount.depth;
|
||||
|
||||
if (aspect & AspectMask)
|
||||
layout.Size += size;
|
||||
else if (!layout.Size)
|
||||
layout.Offset += size;
|
||||
}
|
||||
} break;
|
||||
}
|
||||
|
||||
// D3D wants us to return the total subresource size in some instances
|
||||
if (m_dimension < D3D11_RESOURCE_DIMENSION_TEXTURE2D) layout.RowPitch = layout.Size;
|
||||
if (m_dimension < D3D11_RESOURCE_DIMENSION_TEXTURE3D) layout.DepthPitch = layout.Size;
|
||||
return layout;
|
||||
return DetermineSubresourceLayout(nullptr, subresource);
|
||||
}
|
||||
|
||||
|
||||
|
@ -422,8 +373,31 @@ namespace dxvk {
|
|||
return viewFormat.Format == baseFormat.Format && planeCount == 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void D3D11CommonTexture::SetDebugName(const char* pName) {
|
||||
if (m_image) {
|
||||
m_device->GetContext()->InjectCs(DxvkCsQueue::HighPriority, [
|
||||
cImage = m_image,
|
||||
cName = std::string(pName ? pName : "")
|
||||
] (DxvkContext* ctx) {
|
||||
ctx->setDebugName(cImage, cName.c_str());
|
||||
});
|
||||
}
|
||||
|
||||
if (m_mapMode == D3D11_COMMON_TEXTURE_MAP_MODE_STAGING) {
|
||||
for (uint32_t i = 0; i < m_buffers.size(); i++) {
|
||||
m_device->GetContext()->InjectCs(DxvkCsQueue::HighPriority, [
|
||||
cBuffer = m_buffers[i].buffer,
|
||||
cName = std::string(pName ? pName : "")
|
||||
] (DxvkContext* ctx) {
|
||||
ctx->setDebugName(cBuffer, cName.c_str());
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
HRESULT D3D11CommonTexture::NormalizeTextureProperties(D3D11_COMMON_TEXTURE_DESC* pDesc) {
|
||||
if (pDesc->Width == 0 || pDesc->Height == 0 || pDesc->Depth == 0 || pDesc->ArraySize == 0)
|
||||
return E_INVALIDARG;
|
||||
|
@ -569,136 +543,178 @@ namespace dxvk {
|
|||
return (support.linear & Features) == Features
|
||||
|| (support.optimal & Features) == Features;
|
||||
}
|
||||
|
||||
|
||||
VkImageUsageFlags D3D11CommonTexture::EnableMetaCopyUsage(
|
||||
VkFormat Format,
|
||||
VkImageTiling Tiling) const {
|
||||
VkFormatFeatureFlags2 requestedFeatures = 0;
|
||||
|
||||
if (Format == VK_FORMAT_D16_UNORM || Format == VK_FORMAT_D32_SFLOAT) {
|
||||
requestedFeatures |= VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_BIT
|
||||
| VK_FORMAT_FEATURE_2_DEPTH_STENCIL_ATTACHMENT_BIT;
|
||||
}
|
||||
|
||||
if (Format == VK_FORMAT_R16_UNORM || Format == VK_FORMAT_R32_SFLOAT) {
|
||||
requestedFeatures |= VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_BIT
|
||||
| VK_FORMAT_FEATURE_2_COLOR_ATTACHMENT_BIT;
|
||||
}
|
||||
|
||||
if (Format == VK_FORMAT_D32_SFLOAT_S8_UINT || Format == VK_FORMAT_D24_UNORM_S8_UINT)
|
||||
requestedFeatures |= VK_FORMAT_FEATURE_2_DEPTH_STENCIL_ATTACHMENT_BIT;
|
||||
|
||||
if (!requestedFeatures)
|
||||
return 0;
|
||||
|
||||
// Enable usage flags for all supported and requested features
|
||||
DxvkFormatFeatures support = m_device->GetDXVKDevice()->getFormatFeatures(Format);
|
||||
|
||||
requestedFeatures &= Tiling == VK_IMAGE_TILING_OPTIMAL
|
||||
? support.optimal
|
||||
: support.linear;
|
||||
|
||||
VkImageUsageFlags requestedUsage = 0;
|
||||
|
||||
if (requestedFeatures & VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_BIT)
|
||||
requestedUsage |= VK_IMAGE_USAGE_SAMPLED_BIT;
|
||||
|
||||
if (requestedFeatures & VK_FORMAT_FEATURE_2_DEPTH_STENCIL_ATTACHMENT_BIT)
|
||||
requestedUsage |= VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
|
||||
|
||||
if (requestedFeatures & VK_FORMAT_FEATURE_2_COLOR_ATTACHMENT_BIT)
|
||||
requestedUsage |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
|
||||
|
||||
return requestedUsage;
|
||||
}
|
||||
|
||||
|
||||
VkImageUsageFlags D3D11CommonTexture::EnableMetaPackUsage(
|
||||
VkFormat Format,
|
||||
UINT CpuAccess) const {
|
||||
if ((CpuAccess & D3D11_CPU_ACCESS_READ) == 0)
|
||||
return 0;
|
||||
|
||||
const auto dsMask = VK_IMAGE_ASPECT_DEPTH_BIT
|
||||
| VK_IMAGE_ASPECT_STENCIL_BIT;
|
||||
|
||||
auto formatInfo = lookupFormatInfo(Format);
|
||||
|
||||
return formatInfo->aspectMask == dsMask
|
||||
? VK_IMAGE_USAGE_SAMPLED_BIT
|
||||
: 0;
|
||||
}
|
||||
|
||||
|
||||
VkMemoryPropertyFlags D3D11CommonTexture::GetMemoryFlags() const {
|
||||
std::pair<D3D11_COMMON_TEXTURE_MAP_MODE, VkMemoryPropertyFlags> D3D11CommonTexture::DetermineMapMode(
|
||||
const DxvkImageCreateInfo* pImageInfo) const {
|
||||
// Don't map an image unless the application requests it
|
||||
if (!m_desc.CPUAccessFlags)
|
||||
return { D3D11_COMMON_TEXTURE_MAP_MODE_NONE, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT };
|
||||
|
||||
// For default images, always use a persistent staging buffer. Readback
|
||||
// may cause a GPU sync, but nobody seems to be using this feature anyway.
|
||||
if (m_desc.Usage == D3D11_USAGE_DEFAULT)
|
||||
return { D3D11_COMMON_TEXTURE_MAP_MODE_BUFFER, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT };
|
||||
|
||||
// If the resource cannot be used in the actual rendering pipeline, we
|
||||
// do not need to create an actual image and can instead implement copy
|
||||
// functions as buffer-to-image and image-to-buffer copies.
|
||||
if (m_desc.Usage == D3D11_USAGE_STAGING)
|
||||
return { D3D11_COMMON_TEXTURE_MAP_MODE_STAGING, 0u };
|
||||
|
||||
// If the packed format and image format don't match, we need to use
|
||||
// a staging buffer and perform format conversion when mapping.
|
||||
if (m_packedFormat != pImageInfo->format)
|
||||
return { D3D11_COMMON_TEXTURE_MAP_MODE_DYNAMIC, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT };
|
||||
|
||||
// Multi-plane and depth-stencil images have a special memory layout
|
||||
// in D3D11, so we can't expose those directly to the app
|
||||
auto formatInfo = lookupFormatInfo(pImageInfo->format);
|
||||
|
||||
if (formatInfo->aspectMask != VK_IMAGE_ASPECT_COLOR_BIT)
|
||||
return { D3D11_COMMON_TEXTURE_MAP_MODE_DYNAMIC, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT };
|
||||
|
||||
// If we can't use linear tiling for this image, we have to use a buffer
|
||||
if (!CheckImageSupport(pImageInfo, VK_IMAGE_TILING_LINEAR))
|
||||
return { D3D11_COMMON_TEXTURE_MAP_MODE_DYNAMIC, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT };
|
||||
|
||||
// Determine memory flags for the actual image if we use direct mapping.
|
||||
// Depending on the concrete use case, we may fall back to different
|
||||
// memory types.
|
||||
VkMemoryPropertyFlags memoryFlags = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT
|
||||
| VK_MEMORY_PROPERTY_HOST_COHERENT_BIT;
|
||||
|
||||
bool useCached = (m_device->GetOptions()->cachedDynamicResources == ~0u)
|
||||
|| (m_device->GetOptions()->cachedDynamicResources & m_desc.BindFlags);
|
||||
|| (m_device->GetOptions()->cachedDynamicResources & m_desc.BindFlags)
|
||||
|| (m_desc.CPUAccessFlags & D3D11_CPU_ACCESS_READ);
|
||||
|
||||
if (m_desc.Usage == D3D11_USAGE_STAGING || useCached)
|
||||
memoryFlags |= VK_MEMORY_PROPERTY_HOST_CACHED_BIT;
|
||||
else if (m_desc.Usage == D3D11_USAGE_DEFAULT || m_desc.BindFlags)
|
||||
else if (m_desc.BindFlags)
|
||||
memoryFlags |= VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
|
||||
|
||||
return memoryFlags;
|
||||
// If there are multiple subresources, go through a buffer because
|
||||
// we can otherwise not really discard individual subresources.
|
||||
if (m_desc.ArraySize > 1u || m_desc.MipLevels != 1u)
|
||||
return { D3D11_COMMON_TEXTURE_MAP_MODE_DYNAMIC, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT };
|
||||
|
||||
// If the image is essentially linear already, expose it directly since
|
||||
// there won't be any tangible benefit to using optimal tiling anyway.
|
||||
VkExtent3D blockCount = util::computeBlockCount(pImageInfo->extent, formatInfo->blockSize);
|
||||
|
||||
if (blockCount.height == 1u && blockCount.depth == 1u)
|
||||
return { D3D11_COMMON_TEXTURE_MAP_MODE_DIRECT, memoryFlags };
|
||||
|
||||
// If the image looks like a video, we can generally expect it to get
|
||||
// updated and read once per frame. This is one of the most common use
|
||||
// cases for a mapped image, expose it directly in order to avoid copies.
|
||||
if (blockCount.depth == 1u && blockCount.height >= 160 && formatInfo->elementSize <= 4u) {
|
||||
static const std::array<std::pair<uint32_t, uint32_t>, 3> videoApectRatios = {{
|
||||
{ 4, 3 },
|
||||
{ 16, 9 },
|
||||
{ 21, 9 },
|
||||
}};
|
||||
|
||||
bool isVideoAspectRatio = false;
|
||||
|
||||
for (const auto& a : videoApectRatios) {
|
||||
// Due to codec limitations, video dimensions are often rounded to
|
||||
// a multiple of 8. Account for this when checking the size.
|
||||
isVideoAspectRatio |= blockCount.width > (a.first * (blockCount.height - 8u)) / a.second
|
||||
&& blockCount.width < (a.first * (blockCount.height + 8u)) / a.second;
|
||||
}
|
||||
|
||||
if (isVideoAspectRatio) {
|
||||
// Keep video images in system memory to not waste precious HVV space
|
||||
return { D3D11_COMMON_TEXTURE_MAP_MODE_DIRECT, memoryFlags & ~VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT };
|
||||
}
|
||||
}
|
||||
|
||||
// If the image exceeds a certain size, map it directly because the overhead
|
||||
// of potentially copying the whole thing every frame likely outweighs any
|
||||
// benefit we might get from faster memory and tiling. This solves such an
|
||||
// issue in Warhammer III, which discards a 48 MB texture every single frame.
|
||||
constexpr VkDeviceSize MaxImageStagingBufferSize = 1ull << 20;
|
||||
|
||||
VkDeviceSize imageSize = util::flattenImageExtent(blockCount) * formatInfo->elementSize;
|
||||
|
||||
if (imageSize > MaxImageStagingBufferSize)
|
||||
return { D3D11_COMMON_TEXTURE_MAP_MODE_DIRECT, memoryFlags };
|
||||
|
||||
// For smaller images, use a staging buffer. There are some common use
|
||||
// cases where the image will only get written once, e.g. SMAA look-up
|
||||
// tables in some games, which will benefit from faster GPU access.
|
||||
return { D3D11_COMMON_TEXTURE_MAP_MODE_DYNAMIC, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT };
|
||||
}
|
||||
|
||||
|
||||
D3D11_COMMON_TEXTURE_MAP_MODE D3D11CommonTexture::DetermineMapMode(
|
||||
const DxvkImageCreateInfo* pImageInfo) const {
|
||||
// Don't map an image unless the application requests it
|
||||
if (!m_desc.CPUAccessFlags)
|
||||
return D3D11_COMMON_TEXTURE_MAP_MODE_NONE;
|
||||
|
||||
// If the resource cannot be used in the actual rendering pipeline, we
|
||||
// do not need to create an actual image and can instead implement copy
|
||||
// functions as buffer-to-image and image-to-buffer copies.
|
||||
if (!m_desc.BindFlags && m_desc.Usage != D3D11_USAGE_DEFAULT)
|
||||
return D3D11_COMMON_TEXTURE_MAP_MODE_STAGING;
|
||||
D3D11_COMMON_TEXTURE_SUBRESOURCE_LAYOUT D3D11CommonTexture::DetermineSubresourceLayout(
|
||||
const DxvkImageCreateInfo* pImageInfo,
|
||||
const VkImageSubresource& subresource) const {
|
||||
auto formatInfo = lookupFormatInfo(m_packedFormat);
|
||||
|
||||
// Depth-stencil formats in D3D11 can be mapped and follow special
|
||||
// packing rules, so we need to copy that data into a buffer first
|
||||
if (GetPackedDepthStencilFormat(m_desc.Format))
|
||||
return D3D11_COMMON_TEXTURE_MAP_MODE_BUFFER;
|
||||
if (m_mapMode == D3D11_COMMON_TEXTURE_MAP_MODE_DIRECT) {
|
||||
VkSubresourceLayout vkLayout = m_device->GetDXVKDevice()->queryImageSubresourceLayout(*pImageInfo, subresource);
|
||||
|
||||
// Multi-plane images have a special memory layout in D3D11
|
||||
if (lookupFormatInfo(pImageInfo->format)->flags.test(DxvkFormatFlag::MultiPlane))
|
||||
return D3D11_COMMON_TEXTURE_MAP_MODE_BUFFER;
|
||||
D3D11_COMMON_TEXTURE_SUBRESOURCE_LAYOUT result = { };
|
||||
result.Offset = vkLayout.offset;
|
||||
result.RowPitch = vkLayout.rowPitch;
|
||||
result.DepthPitch = vkLayout.depthPitch;
|
||||
|
||||
// If we can't use linear tiling for this image, we have to use a buffer
|
||||
if (!this->CheckImageSupport(pImageInfo, VK_IMAGE_TILING_LINEAR))
|
||||
return D3D11_COMMON_TEXTURE_MAP_MODE_BUFFER;
|
||||
// We will only ever use direct mapping for single-aspect images,
|
||||
// so ignore any sort of multi-plane shenanigans on this path
|
||||
auto mipExtent = MipLevelExtent(subresource.mipLevel);
|
||||
auto blockCount = util::computeBlockCount(mipExtent, formatInfo->blockSize);
|
||||
|
||||
// If supported and requested, create a linear image. Default images
|
||||
// can be used for resolves and other operations regardless of bind
|
||||
// flags, so we need to use a proper image for those.
|
||||
if (m_desc.TextureLayout == D3D11_TEXTURE_LAYOUT_ROW_MAJOR)
|
||||
return D3D11_COMMON_TEXTURE_MAP_MODE_DIRECT;
|
||||
// If the image dimensions support it, try to look as close to a
|
||||
// linear buffer as we can. Some games use the depth pitch as a
|
||||
// subresource size and will crash if it includes any padding.
|
||||
if (blockCount.depth == 1u) {
|
||||
if (blockCount.height == 1u) {
|
||||
result.RowPitch = formatInfo->elementSize * blockCount.width;
|
||||
result.DepthPitch = result.RowPitch;
|
||||
} else {
|
||||
result.DepthPitch = vkLayout.rowPitch * blockCount.height;
|
||||
}
|
||||
}
|
||||
|
||||
// For default images, prefer direct mapping if the image is CPU readable
|
||||
// since mapping for reads would have to stall otherwise. If the image is
|
||||
// only writable, prefer a write-through buffer.
|
||||
if (m_desc.Usage == D3D11_USAGE_DEFAULT) {
|
||||
return (m_desc.CPUAccessFlags & D3D11_CPU_ACCESS_READ)
|
||||
? D3D11_COMMON_TEXTURE_MAP_MODE_DIRECT
|
||||
: D3D11_COMMON_TEXTURE_MAP_MODE_BUFFER;
|
||||
result.Size = blockCount.depth * result.DepthPitch;
|
||||
return result;
|
||||
} else {
|
||||
D3D11_COMMON_TEXTURE_SUBRESOURCE_LAYOUT result = { };
|
||||
|
||||
VkImageAspectFlags aspects = formatInfo->aspectMask;
|
||||
VkExtent3D mipExtent = MipLevelExtent(subresource.mipLevel);
|
||||
|
||||
while (aspects) {
|
||||
auto aspect = vk::getNextAspect(aspects);
|
||||
auto extent = mipExtent;
|
||||
auto elementSize = formatInfo->elementSize;
|
||||
|
||||
if (formatInfo->flags.test(DxvkFormatFlag::MultiPlane)) {
|
||||
auto plane = &formatInfo->planes[vk::getPlaneIndex(aspect)];
|
||||
extent.width /= plane->blockSize.width;
|
||||
extent.height /= plane->blockSize.height;
|
||||
elementSize = plane->elementSize;
|
||||
}
|
||||
|
||||
auto blockCount = util::computeBlockCount(extent, formatInfo->blockSize);
|
||||
|
||||
if (!result.RowPitch) {
|
||||
result.RowPitch = elementSize * blockCount.width;
|
||||
result.DepthPitch = elementSize * blockCount.width * blockCount.height;
|
||||
}
|
||||
|
||||
VkDeviceSize size = elementSize * blockCount.width * blockCount.height * blockCount.depth;
|
||||
|
||||
if (aspect & subresource.aspectMask)
|
||||
result.Size += size;
|
||||
else if (!result.Size)
|
||||
result.Offset += size;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// The overhead of frequently uploading large dynamic images may outweigh
|
||||
// the benefit of linear tiling, so use a linear image in those cases.
|
||||
VkDeviceSize threshold = m_device->GetOptions()->maxDynamicImageBufferSize;
|
||||
VkDeviceSize size = util::computeImageDataSize(pImageInfo->format, pImageInfo->extent);
|
||||
|
||||
if (size > threshold)
|
||||
return D3D11_COMMON_TEXTURE_MAP_MODE_DIRECT;
|
||||
|
||||
// Dynamic images that can be sampled by a shader should generally go
|
||||
// through a buffer to allow optimal tiling and to avoid running into
|
||||
// bugs where games ignore the pitch when mapping the image.
|
||||
return D3D11_COMMON_TEXTURE_MAP_MODE_BUFFER;
|
||||
}
|
||||
|
||||
|
||||
|
@ -744,23 +760,25 @@ namespace dxvk {
|
|||
}
|
||||
|
||||
|
||||
D3D11CommonTexture::MappedBuffer D3D11CommonTexture::CreateMappedBuffer(UINT MipLevel) const {
|
||||
void D3D11CommonTexture::CreateMappedBuffer(UINT Subresource) {
|
||||
const DxvkFormatInfo* formatInfo = lookupFormatInfo(
|
||||
m_device->LookupPackedFormat(m_desc.Format, GetFormatMode()).Format);
|
||||
|
||||
|
||||
DxvkBufferCreateInfo info;
|
||||
info.size = GetSubresourceLayout(formatInfo->aspectMask, MipLevel).Size;
|
||||
info.size = GetSubresourceLayout(formatInfo->aspectMask, Subresource).Size;
|
||||
info.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT
|
||||
| VK_BUFFER_USAGE_TRANSFER_DST_BIT
|
||||
| VK_BUFFER_USAGE_STORAGE_BUFFER_BIT
|
||||
| VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT
|
||||
| VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT;
|
||||
info.stages = VK_PIPELINE_STAGE_TRANSFER_BIT
|
||||
| VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
|
||||
| VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT
|
||||
| VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
|
||||
info.access = VK_ACCESS_TRANSFER_READ_BIT
|
||||
| VK_ACCESS_TRANSFER_WRITE_BIT
|
||||
| VK_ACCESS_SHADER_READ_BIT
|
||||
| VK_ACCESS_SHADER_WRITE_BIT;
|
||||
info.debugName = "Image buffer";
|
||||
|
||||
// We may read mapped buffers even if it is
|
||||
// marked as CPU write-only on the D3D11 side.
|
||||
|
@ -779,11 +797,18 @@ namespace dxvk {
|
|||
|
||||
if (m_desc.Usage == D3D11_USAGE_STAGING || useCached)
|
||||
memType |= VK_MEMORY_PROPERTY_HOST_CACHED_BIT;
|
||||
|
||||
MappedBuffer result;
|
||||
result.buffer = m_device->GetDXVKDevice()->createBuffer(info, memType);
|
||||
result.slice = result.buffer->getSliceHandle();
|
||||
return result;
|
||||
|
||||
auto& entry = m_buffers[Subresource];
|
||||
entry.buffer = m_device->GetDXVKDevice()->createBuffer(info, memType);
|
||||
entry.slice = entry.buffer->storage();
|
||||
}
|
||||
|
||||
|
||||
void D3D11CommonTexture::FreeMappedBuffer(
|
||||
UINT Subresource) {
|
||||
auto& entry = m_buffers[Subresource];
|
||||
entry.buffer = nullptr;
|
||||
entry.slice = nullptr;
|
||||
}
|
||||
|
||||
|
||||
|
@ -799,33 +824,34 @@ namespace dxvk {
|
|||
|
||||
VkImageLayout D3D11CommonTexture::OptimizeLayout(VkImageUsageFlags Usage) {
|
||||
const VkImageUsageFlags usageFlags = Usage;
|
||||
|
||||
|
||||
// Filter out unnecessary flags. Transfer operations
|
||||
// are handled by the backend in a transparent manner.
|
||||
Usage &= ~(VK_IMAGE_USAGE_TRANSFER_DST_BIT
|
||||
| VK_IMAGE_USAGE_TRANSFER_SRC_BIT);
|
||||
|
||||
|
||||
// Storage images require GENERAL.
|
||||
if (Usage & VK_IMAGE_USAGE_STORAGE_BIT)
|
||||
return VK_IMAGE_LAYOUT_GENERAL;
|
||||
|
||||
// Also use GENERAL if the image cannot be rendered to. This
|
||||
// should not harm any hardware in practice and may avoid some
|
||||
// redundant layout transitions for regular textures.
|
||||
if (Usage == VK_IMAGE_USAGE_SAMPLED_BIT)
|
||||
return VK_IMAGE_LAYOUT_GENERAL;
|
||||
|
||||
// If the image is used only as an attachment, we never
|
||||
// have to transform the image back to a different layout
|
||||
// have to transform the image back to a different layout.
|
||||
if (Usage == VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT)
|
||||
return VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
|
||||
|
||||
if (Usage == VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT)
|
||||
return VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
|
||||
|
||||
Usage &= ~(VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT
|
||||
| VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT);
|
||||
|
||||
// If the image is used for reading but not as a storage
|
||||
// image, we can optimize the image for texture access
|
||||
if (Usage == VK_IMAGE_USAGE_SAMPLED_BIT) {
|
||||
return usageFlags & VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT
|
||||
? VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL
|
||||
: VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
|
||||
}
|
||||
|
||||
// Otherwise, we have to stick with the default layout
|
||||
return VK_IMAGE_LAYOUT_GENERAL;
|
||||
|
||||
// Otherwise, pick a layout that can be used for reading.
|
||||
return usageFlags & VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT
|
||||
? VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL
|
||||
: VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
|
||||
}
|
||||
|
||||
|
||||
|
@ -1099,7 +1125,7 @@ namespace dxvk {
|
|||
m_texture (this, pDevice, pDesc, p11on12Info, D3D11_RESOURCE_DIMENSION_TEXTURE1D, 0, VK_NULL_HANDLE, nullptr),
|
||||
m_interop (this, &m_texture),
|
||||
m_surface (this, &m_texture),
|
||||
m_resource(this),
|
||||
m_resource(this, pDevice),
|
||||
m_d3d10 (this) {
|
||||
|
||||
}
|
||||
|
@ -1192,8 +1218,13 @@ namespace dxvk {
|
|||
pDesc->CPUAccessFlags = m_texture.Desc()->CPUAccessFlags;
|
||||
pDesc->MiscFlags = m_texture.Desc()->MiscFlags;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void STDMETHODCALLTYPE D3D11Texture1D::SetDebugName(const char* pName) {
|
||||
m_texture.SetDebugName(pName);
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////
|
||||
// D 3 D 1 1 T E X T U R E 2 D
|
||||
D3D11Texture2D::D3D11Texture2D(
|
||||
|
@ -1205,7 +1236,7 @@ namespace dxvk {
|
|||
m_texture (this, pDevice, pDesc, p11on12Info, D3D11_RESOURCE_DIMENSION_TEXTURE2D, 0, VK_NULL_HANDLE, hSharedHandle),
|
||||
m_interop (this, &m_texture),
|
||||
m_surface (this, &m_texture),
|
||||
m_resource (this),
|
||||
m_resource (this, pDevice),
|
||||
m_d3d10 (this),
|
||||
m_swapChain (nullptr) {
|
||||
}
|
||||
|
@ -1220,7 +1251,7 @@ namespace dxvk {
|
|||
m_texture (this, pDevice, pDesc, nullptr, D3D11_RESOURCE_DIMENSION_TEXTURE2D, DxgiUsage, vkImage, nullptr),
|
||||
m_interop (this, &m_texture),
|
||||
m_surface (this, &m_texture),
|
||||
m_resource (this),
|
||||
m_resource (this, pDevice),
|
||||
m_d3d10 (this),
|
||||
m_swapChain (nullptr) {
|
||||
|
||||
|
@ -1236,7 +1267,7 @@ namespace dxvk {
|
|||
m_texture (this, pDevice, pDesc, nullptr, D3D11_RESOURCE_DIMENSION_TEXTURE2D, DxgiUsage, VK_NULL_HANDLE, nullptr),
|
||||
m_interop (this, &m_texture),
|
||||
m_surface (this, &m_texture),
|
||||
m_resource (this),
|
||||
m_resource (this, pDevice),
|
||||
m_d3d10 (this),
|
||||
m_swapChain (pSwapChain) {
|
||||
|
||||
|
@ -1375,6 +1406,11 @@ namespace dxvk {
|
|||
}
|
||||
|
||||
|
||||
void STDMETHODCALLTYPE D3D11Texture2D::SetDebugName(const char* pName) {
|
||||
m_texture.SetDebugName(pName);
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////
|
||||
// D 3 D 1 1 T E X T U R E 3 D
|
||||
D3D11Texture3D::D3D11Texture3D(
|
||||
|
@ -1384,7 +1420,7 @@ namespace dxvk {
|
|||
: D3D11DeviceChild<ID3D11Texture3D1>(pDevice),
|
||||
m_texture (this, pDevice, pDesc, p11on12Info, D3D11_RESOURCE_DIMENSION_TEXTURE3D, 0, VK_NULL_HANDLE, nullptr),
|
||||
m_interop (this, &m_texture),
|
||||
m_resource(this),
|
||||
m_resource(this, pDevice),
|
||||
m_d3d10 (this) {
|
||||
|
||||
}
|
||||
|
@ -1486,6 +1522,11 @@ namespace dxvk {
|
|||
}
|
||||
|
||||
|
||||
void STDMETHODCALLTYPE D3D11Texture3D::SetDebugName(const char* pName) {
|
||||
m_texture.SetDebugName(pName);
|
||||
}
|
||||
|
||||
|
||||
D3D11CommonTexture* GetCommonTexture(ID3D11Resource* pResource) {
|
||||
D3D11_RESOURCE_DIMENSION dimension = D3D11_RESOURCE_DIMENSION_UNKNOWN;
|
||||
pResource->GetType(&dimension);
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
#include "../util/util_small_vector.h"
|
||||
|
||||
#include "../dxvk/dxvk_cs.h"
|
||||
#include "../dxvk/dxvk_device.h"
|
||||
|
||||
|
@ -24,6 +26,7 @@ namespace dxvk {
|
|||
enum D3D11_COMMON_TEXTURE_MAP_MODE {
|
||||
D3D11_COMMON_TEXTURE_MAP_MODE_NONE, ///< Not mapped
|
||||
D3D11_COMMON_TEXTURE_MAP_MODE_BUFFER, ///< Mapped through buffer
|
||||
D3D11_COMMON_TEXTURE_MAP_MODE_DYNAMIC, ///< Mapped through temporary buffer
|
||||
D3D11_COMMON_TEXTURE_MAP_MODE_DIRECT, ///< Directly mapped to host mem
|
||||
D3D11_COMMON_TEXTURE_MAP_MODE_STAGING, ///< Buffer only, no image
|
||||
};
|
||||
|
@ -81,7 +84,9 @@ namespace dxvk {
|
|||
class D3D11CommonTexture {
|
||||
|
||||
public:
|
||||
|
||||
|
||||
static constexpr uint32_t UnmappedSubresource = ~0u;
|
||||
|
||||
D3D11CommonTexture(
|
||||
ID3D11Resource* pInterface,
|
||||
D3D11Device* pDevice,
|
||||
|
@ -170,29 +175,73 @@ namespace dxvk {
|
|||
return m_mapMode;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Checks whether this texture has an image
|
||||
*
|
||||
* Staging textures will not use an image, only mapped buffers.
|
||||
* \returns \c true for non-staging textures.
|
||||
*/
|
||||
bool HasImage() const {
|
||||
return m_mapMode != D3D11_COMMON_TEXTURE_MAP_MODE_STAGING;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Checks whether this texture has persistent buffers
|
||||
* \returns \c true for buffer-mapped textures or staging textures.
|
||||
*/
|
||||
bool HasPersistentBuffers() const {
|
||||
return m_mapMode == D3D11_COMMON_TEXTURE_MAP_MODE_BUFFER
|
||||
|| m_mapMode == D3D11_COMMON_TEXTURE_MAP_MODE_STAGING;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Map type of a given subresource
|
||||
*
|
||||
* \param [in] Subresource Subresource index
|
||||
* \returns Current map mode of that subresource
|
||||
*/
|
||||
D3D11_MAP GetMapType(UINT Subresource) const {
|
||||
uint32_t GetMapType(UINT Subresource) const {
|
||||
return Subresource < m_mapInfo.size()
|
||||
? D3D11_MAP(m_mapInfo[Subresource].mapType)
|
||||
: D3D11_MAP(~0u);
|
||||
? m_mapInfo[Subresource].mapType
|
||||
: UnmappedSubresource;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Sets map type for a given subresource
|
||||
*
|
||||
*
|
||||
* Also ensures taht a staging buffer is created
|
||||
* in case of dynamic mapping.
|
||||
* \param [in] Subresource The subresource
|
||||
* \param [in] MapType The map type
|
||||
*/
|
||||
void SetMapType(UINT Subresource, D3D11_MAP MapType) {
|
||||
if (Subresource < m_mapInfo.size())
|
||||
m_mapInfo[Subresource].mapType = MapType;
|
||||
void NotifyMap(UINT Subresource, D3D11_MAP MapType) {
|
||||
if (likely(Subresource < m_mapInfo.size())) {
|
||||
m_mapInfo[Subresource].mapType = uint32_t(MapType);
|
||||
|
||||
if (m_mapMode == D3D11_COMMON_TEXTURE_MAP_MODE_DYNAMIC)
|
||||
CreateMappedBuffer(Subresource);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* \brief Resets map info for a given subresource
|
||||
*
|
||||
* For dynamic mapping, this will also free the
|
||||
* staging buffer.
|
||||
* \param [in] Subresource The subresource
|
||||
*/
|
||||
void NotifyUnmap(UINT Subresource) {
|
||||
if (likely(Subresource < m_mapInfo.size())) {
|
||||
m_mapInfo[Subresource].mapType = UnmappedSubresource;
|
||||
|
||||
if (m_mapMode == D3D11_COMMON_TEXTURE_MAP_MODE_DYNAMIC)
|
||||
FreeMappedBuffer(Subresource);
|
||||
|
||||
if (Subresource < m_buffers.size())
|
||||
m_buffers[Subresource].dirtyRegions.clear();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief The DXVK image
|
||||
* \returns The DXVK image
|
||||
|
@ -219,13 +268,13 @@ namespace dxvk {
|
|||
* \param [in] Subresource Subresource to discard
|
||||
* \returns Newly allocated mapped buffer slice
|
||||
*/
|
||||
DxvkBufferSliceHandle DiscardSlice(UINT Subresource) {
|
||||
Rc<DxvkResourceAllocation> DiscardSlice(UINT Subresource) {
|
||||
if (Subresource < m_buffers.size()) {
|
||||
DxvkBufferSliceHandle slice = m_buffers[Subresource].buffer->allocSlice();
|
||||
Rc<DxvkResourceAllocation> slice = m_buffers[Subresource].buffer->allocateStorage();
|
||||
m_buffers[Subresource].slice = slice;
|
||||
return slice;
|
||||
} else {
|
||||
return DxvkBufferSliceHandle();
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -235,10 +284,10 @@ namespace dxvk {
|
|||
* \param [in] Subresource Subresource index to query
|
||||
* \returns Currently mapped buffer slice
|
||||
*/
|
||||
DxvkBufferSliceHandle GetMappedSlice(UINT Subresource) const {
|
||||
Rc<DxvkResourceAllocation> GetMappedSlice(UINT Subresource) const {
|
||||
return Subresource < m_buffers.size()
|
||||
? m_buffers[Subresource].slice
|
||||
: DxvkBufferSliceHandle();
|
||||
: nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -261,17 +310,7 @@ namespace dxvk {
|
|||
* \returns \c true if tracking is supported for this resource
|
||||
*/
|
||||
bool HasSequenceNumber() const {
|
||||
if (m_mapMode == D3D11_COMMON_TEXTURE_MAP_MODE_NONE)
|
||||
return false;
|
||||
|
||||
// For buffer-mapped images we only need to track copies to
|
||||
// and from that buffer, so we can safely ignore bind flags
|
||||
if (m_mapMode == D3D11_COMMON_TEXTURE_MAP_MODE_BUFFER)
|
||||
return m_desc.Usage != D3D11_USAGE_DEFAULT;
|
||||
|
||||
// Otherwise we can only do accurate tracking if the
|
||||
// image cannot be used in the rendering pipeline.
|
||||
return m_desc.BindFlags == 0;
|
||||
return m_mapMode == D3D11_COMMON_TEXTURE_MAP_MODE_STAGING;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -303,6 +342,52 @@ namespace dxvk {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Allocates new backing storage
|
||||
* \returns New backing storage for the image
|
||||
*/
|
||||
Rc<DxvkResourceAllocation> AllocStorage() {
|
||||
return m_image->allocateStorage();
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Discards backing storage
|
||||
*
|
||||
* Also updates the mapped pointer if the image is mapped.
|
||||
* \returns New backing storage for the image
|
||||
*/
|
||||
Rc<DxvkResourceAllocation> DiscardStorage() {
|
||||
auto storage = m_image->allocateStorage();
|
||||
m_mapPtr = storage->mapPtr();
|
||||
return storage;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Queries map pointer of the raw image
|
||||
*
|
||||
* If the image is mapped directly, the returned pointer will
|
||||
* point directly to the image, otherwise it will point to a
|
||||
* buffer that contains image data.
|
||||
* \param [in] Subresource Subresource index
|
||||
* \param [in] Offset Offset derived from the subresource layout
|
||||
*/
|
||||
void* GetMapPtr(uint32_t Subresource, size_t Offset) const {
|
||||
switch (m_mapMode) {
|
||||
case D3D11_COMMON_TEXTURE_MAP_MODE_DIRECT:
|
||||
return reinterpret_cast<char*>(m_mapPtr) + Offset;
|
||||
|
||||
case D3D11_COMMON_TEXTURE_MAP_MODE_BUFFER:
|
||||
case D3D11_COMMON_TEXTURE_MAP_MODE_DYNAMIC:
|
||||
case D3D11_COMMON_TEXTURE_MAP_MODE_STAGING:
|
||||
return reinterpret_cast<char*>(m_buffers[Subresource].slice->mapPtr()) + Offset;
|
||||
|
||||
case D3D11_COMMON_TEXTURE_MAP_MODE_NONE:
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Adds a dirty region
|
||||
*
|
||||
|
@ -320,17 +405,6 @@ namespace dxvk {
|
|||
m_buffers[Subresource].dirtyRegions.push_back(region);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Clears dirty regions
|
||||
*
|
||||
* Removes all dirty regions from the given subresource.
|
||||
* \param [in] Subresource Subresource index
|
||||
*/
|
||||
void ClearDirtyRegions(UINT Subresource) {
|
||||
if (Subresource < m_buffers.size())
|
||||
m_buffers[Subresource].dirtyRegions.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Counts dirty regions
|
||||
*
|
||||
|
@ -390,7 +464,13 @@ namespace dxvk {
|
|||
*/
|
||||
VkImageSubresource GetSubresourceFromIndex(
|
||||
VkImageAspectFlags Aspect,
|
||||
UINT Subresource) const;
|
||||
UINT Subresource) const {
|
||||
VkImageSubresource result;
|
||||
result.aspectMask = Aspect;
|
||||
result.mipLevel = Subresource % m_desc.MipLevels;
|
||||
result.arrayLayer = Subresource / m_desc.MipLevels;
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Computes subresource layout for the given subresource
|
||||
|
@ -445,6 +525,14 @@ namespace dxvk {
|
|||
return m_11on12;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Sets debug name for texture
|
||||
*
|
||||
* Passes the given name to the backing image or buffer.
|
||||
* \param [in] name Debug name
|
||||
*/
|
||||
void SetDebugName(const char* pName);
|
||||
|
||||
/**
|
||||
* \brief Normalizes and validates texture description
|
||||
*
|
||||
|
@ -473,15 +561,16 @@ namespace dxvk {
|
|||
private:
|
||||
|
||||
struct MappedBuffer {
|
||||
Rc<DxvkBuffer> buffer;
|
||||
DxvkBufferSliceHandle slice;
|
||||
Rc<DxvkBuffer> buffer;
|
||||
Rc<DxvkResourceAllocation> slice;
|
||||
|
||||
std::vector<D3D11_COMMON_TEXTURE_REGION> dirtyRegions;
|
||||
};
|
||||
|
||||
struct MappedInfo {
|
||||
D3D11_MAP mapType;
|
||||
uint64_t seq;
|
||||
D3D11_COMMON_TEXTURE_SUBRESOURCE_LAYOUT layout = { };
|
||||
uint32_t mapType = UnmappedSubresource;
|
||||
uint64_t seq = 0u;
|
||||
};
|
||||
|
||||
ID3D11Resource* m_interface;
|
||||
|
@ -494,11 +583,16 @@ namespace dxvk {
|
|||
VkFormat m_packedFormat;
|
||||
|
||||
Rc<DxvkImage> m_image;
|
||||
std::vector<MappedBuffer> m_buffers;
|
||||
std::vector<MappedInfo> m_mapInfo;
|
||||
small_vector<MappedBuffer, 6> m_buffers;
|
||||
small_vector<MappedInfo, 6> m_mapInfo;
|
||||
|
||||
void* m_mapPtr = nullptr;
|
||||
|
||||
void CreateMappedBuffer(
|
||||
UINT Subresource);
|
||||
|
||||
MappedBuffer CreateMappedBuffer(
|
||||
UINT MipLevel) const;
|
||||
void FreeMappedBuffer(
|
||||
UINT Subresource);
|
||||
|
||||
BOOL CheckImageSupport(
|
||||
const DxvkImageCreateInfo* pImageInfo,
|
||||
|
@ -508,21 +602,15 @@ namespace dxvk {
|
|||
VkFormat Format,
|
||||
VkFormatFeatureFlags2 Features) const;
|
||||
|
||||
VkImageUsageFlags EnableMetaCopyUsage(
|
||||
VkFormat Format,
|
||||
VkImageTiling Tiling) const;
|
||||
|
||||
VkImageUsageFlags EnableMetaPackUsage(
|
||||
VkFormat Format,
|
||||
UINT CpuAccess) const;
|
||||
|
||||
VkMemoryPropertyFlags GetMemoryFlags() const;
|
||||
|
||||
D3D11_COMMON_TEXTURE_MAP_MODE DetermineMapMode(
|
||||
std::pair<D3D11_COMMON_TEXTURE_MAP_MODE, VkMemoryPropertyFlags> DetermineMapMode(
|
||||
const DxvkImageCreateInfo* pImageInfo) const;
|
||||
|
||||
D3D11_COMMON_TEXTURE_SUBRESOURCE_LAYOUT DetermineSubresourceLayout(
|
||||
const DxvkImageCreateInfo* pImageInfo,
|
||||
const VkImageSubresource& subresource) const;
|
||||
|
||||
void ExportImageInfo();
|
||||
|
||||
|
||||
static BOOL IsR32UavCompatibleFormat(
|
||||
DXGI_FORMAT Format);
|
||||
|
||||
|
@ -679,6 +767,8 @@ namespace dxvk {
|
|||
void STDMETHODCALLTYPE GetDesc(
|
||||
D3D11_TEXTURE1D_DESC *pDesc) final;
|
||||
|
||||
void STDMETHODCALLTYPE SetDebugName(const char* pName) final;
|
||||
|
||||
D3D11CommonTexture* GetCommonTexture() {
|
||||
return &m_texture;
|
||||
}
|
||||
|
@ -745,6 +835,8 @@ namespace dxvk {
|
|||
void STDMETHODCALLTYPE GetDesc1(
|
||||
D3D11_TEXTURE2D_DESC1* pDesc) final;
|
||||
|
||||
void STDMETHODCALLTYPE SetDebugName(const char* pName) final;
|
||||
|
||||
D3D11CommonTexture* GetCommonTexture() {
|
||||
return &m_texture;
|
||||
}
|
||||
|
@ -795,6 +887,8 @@ namespace dxvk {
|
|||
void STDMETHODCALLTYPE GetDesc1(
|
||||
D3D11_TEXTURE3D_DESC1* pDesc) final;
|
||||
|
||||
void STDMETHODCALLTYPE SetDebugName(const char* pName) final;
|
||||
|
||||
D3D11CommonTexture* GetCommonTexture() {
|
||||
return &m_texture;
|
||||
}
|
||||
|
|
|
@ -52,15 +52,15 @@ namespace dxvk {
|
|||
* \returns Corresponding Vulkan shader stage
|
||||
*/
|
||||
constexpr VkShaderStageFlagBits GetShaderStage(DxbcProgramType ProgramType) {
|
||||
switch (ProgramType) {
|
||||
case DxbcProgramType::VertexShader: return VK_SHADER_STAGE_VERTEX_BIT;
|
||||
case DxbcProgramType::HullShader: return VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT;
|
||||
case DxbcProgramType::DomainShader: return VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT;
|
||||
case DxbcProgramType::GeometryShader: return VK_SHADER_STAGE_GEOMETRY_BIT;
|
||||
case DxbcProgramType::PixelShader: return VK_SHADER_STAGE_FRAGMENT_BIT;
|
||||
case DxbcProgramType::ComputeShader: return VK_SHADER_STAGE_COMPUTE_BIT;
|
||||
default: return VkShaderStageFlagBits(0);
|
||||
}
|
||||
constexpr uint64_t lut
|
||||
= (uint64_t(VK_SHADER_STAGE_VERTEX_BIT) << (8u * uint32_t(DxbcProgramType::VertexShader)))
|
||||
| (uint64_t(VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT) << (8u * uint32_t(DxbcProgramType::HullShader)))
|
||||
| (uint64_t(VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT) << (8u * uint32_t(DxbcProgramType::DomainShader)))
|
||||
| (uint64_t(VK_SHADER_STAGE_GEOMETRY_BIT) << (8u * uint32_t(DxbcProgramType::GeometryShader)))
|
||||
| (uint64_t(VK_SHADER_STAGE_FRAGMENT_BIT) << (8u * uint32_t(DxbcProgramType::PixelShader)))
|
||||
| (uint64_t(VK_SHADER_STAGE_COMPUTE_BIT) << (8u * uint32_t(DxbcProgramType::ComputeShader)));
|
||||
|
||||
return VkShaderStageFlagBits((lut >> (8u * uint32_t(ProgramType))) & 0xff);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -173,35 +173,23 @@ namespace dxvk {
|
|||
|
||||
Rc<DxvkImage> dxvkImage = GetCommonTexture(pResource)->GetImage();
|
||||
|
||||
if (!(dxvkImage->info().usage & VK_IMAGE_USAGE_SAMPLED_BIT)) {
|
||||
DxvkImageCreateInfo info = dxvkImage->info();
|
||||
info.flags = VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT | VK_IMAGE_CREATE_EXTENDED_USAGE_BIT;
|
||||
info.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT;
|
||||
info.stages = VK_PIPELINE_STAGE_TRANSFER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
|
||||
info.access = VK_ACCESS_TRANSFER_WRITE_BIT | VK_ACCESS_SHADER_READ_BIT;
|
||||
info.tiling = VK_IMAGE_TILING_OPTIMAL;
|
||||
info.layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
|
||||
info.shared = VK_FALSE;
|
||||
dxvkImage = m_copy = pDevice->GetDXVKDevice()->createImage(info, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
|
||||
}
|
||||
|
||||
DXGI_VK_FORMAT_INFO formatInfo = pDevice->LookupFormat(resourceDesc.Format, DXGI_VK_FORMAT_MODE_COLOR);
|
||||
DXGI_VK_FORMAT_FAMILY formatFamily = pDevice->LookupFamily(resourceDesc.Format, DXGI_VK_FORMAT_MODE_COLOR);
|
||||
|
||||
VkImageAspectFlags aspectMask = lookupFormatInfo(formatInfo.Format)->aspectMask;
|
||||
|
||||
DxvkImageViewCreateInfo viewInfo;
|
||||
viewInfo.format = formatInfo.Format;
|
||||
viewInfo.swizzle = formatInfo.Swizzle;
|
||||
viewInfo.usage = VK_IMAGE_USAGE_SAMPLED_BIT;
|
||||
DxvkImageViewKey viewInfo;
|
||||
viewInfo.format = formatInfo.Format;
|
||||
viewInfo.usage = VK_IMAGE_USAGE_SAMPLED_BIT;
|
||||
viewInfo.packedSwizzle = DxvkImageViewKey::packSwizzle(formatInfo.Swizzle);
|
||||
|
||||
switch (m_desc.ViewDimension) {
|
||||
case D3D11_VPIV_DIMENSION_TEXTURE2D:
|
||||
viewInfo.type = VK_IMAGE_VIEW_TYPE_2D;
|
||||
viewInfo.minLevel = m_desc.Texture2D.MipSlice;
|
||||
viewInfo.numLevels = 1;
|
||||
viewInfo.minLayer = 0;
|
||||
viewInfo.numLayers = 1;
|
||||
viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
|
||||
viewInfo.mipIndex = m_desc.Texture2D.MipSlice;
|
||||
viewInfo.mipCount = 1;
|
||||
viewInfo.layerIndex = m_desc.Texture2D.ArraySlice;
|
||||
viewInfo.layerCount = 1;
|
||||
break;
|
||||
|
||||
case D3D11_VPIV_DIMENSION_UNKNOWN:
|
||||
|
@ -209,17 +197,17 @@ namespace dxvk {
|
|||
}
|
||||
|
||||
m_subresources.aspectMask = aspectMask;
|
||||
m_subresources.baseArrayLayer = viewInfo.minLayer;
|
||||
m_subresources.layerCount = viewInfo.numLayers;
|
||||
m_subresources.mipLevel = viewInfo.minLevel;
|
||||
m_subresources.baseArrayLayer = viewInfo.layerIndex;
|
||||
m_subresources.layerCount = viewInfo.layerCount;
|
||||
m_subresources.mipLevel = viewInfo.mipIndex;
|
||||
|
||||
for (uint32_t i = 0; aspectMask && i < m_views.size(); i++) {
|
||||
viewInfo.aspect = vk::getNextAspect(aspectMask);
|
||||
viewInfo.aspects = vk::getNextAspect(aspectMask);
|
||||
|
||||
if (viewInfo.aspect != VK_IMAGE_ASPECT_COLOR_BIT)
|
||||
if (viewInfo.aspects != VK_IMAGE_ASPECT_COLOR_BIT)
|
||||
viewInfo.format = formatFamily.Formats[i];
|
||||
|
||||
m_views[i] = pDevice->GetDXVKDevice()->createImageView(dxvkImage, viewInfo);
|
||||
m_views[i] = dxvkImage->createView(viewInfo);
|
||||
}
|
||||
|
||||
m_isYCbCr = IsYCbCrFormat(resourceDesc.Format);
|
||||
|
@ -287,35 +275,34 @@ namespace dxvk {
|
|||
DXGI_VK_FORMAT_INFO formatInfo = pDevice->LookupFormat(
|
||||
resourceDesc.Format, DXGI_VK_FORMAT_MODE_COLOR);
|
||||
|
||||
DxvkImageViewCreateInfo viewInfo;
|
||||
viewInfo.format = formatInfo.Format;
|
||||
viewInfo.aspect = lookupFormatInfo(viewInfo.format)->aspectMask;
|
||||
viewInfo.swizzle = formatInfo.Swizzle;
|
||||
viewInfo.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
|
||||
DxvkImageViewKey viewInfo;
|
||||
viewInfo.format = formatInfo.Format;
|
||||
viewInfo.aspects = lookupFormatInfo(viewInfo.format)->aspectMask;
|
||||
viewInfo.packedSwizzle = DxvkImageViewKey::packSwizzle(formatInfo.Swizzle);
|
||||
viewInfo.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
|
||||
|
||||
switch (m_desc.ViewDimension) {
|
||||
case D3D11_VPOV_DIMENSION_TEXTURE2D:
|
||||
viewInfo.type = VK_IMAGE_VIEW_TYPE_2D;
|
||||
viewInfo.minLevel = m_desc.Texture2D.MipSlice;
|
||||
viewInfo.numLevels = 1;
|
||||
viewInfo.minLayer = 0;
|
||||
viewInfo.numLayers = 1;
|
||||
viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
|
||||
viewInfo.mipIndex = m_desc.Texture2D.MipSlice;
|
||||
viewInfo.mipCount = 1;
|
||||
viewInfo.layerIndex = 0;
|
||||
viewInfo.layerCount = 1;
|
||||
break;
|
||||
|
||||
case D3D11_VPOV_DIMENSION_TEXTURE2DARRAY:
|
||||
viewInfo.type = VK_IMAGE_VIEW_TYPE_2D_ARRAY;
|
||||
viewInfo.minLevel = m_desc.Texture2DArray.MipSlice;
|
||||
viewInfo.numLevels = 1;
|
||||
viewInfo.minLayer = m_desc.Texture2DArray.FirstArraySlice;
|
||||
viewInfo.numLayers = m_desc.Texture2DArray.ArraySize;
|
||||
viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D_ARRAY;
|
||||
viewInfo.mipIndex = m_desc.Texture2DArray.MipSlice;
|
||||
viewInfo.mipCount = 1;
|
||||
viewInfo.layerIndex = m_desc.Texture2DArray.FirstArraySlice;
|
||||
viewInfo.layerCount = m_desc.Texture2DArray.ArraySize;
|
||||
break;
|
||||
|
||||
case D3D11_VPOV_DIMENSION_UNKNOWN:
|
||||
throw DxvkError("Invalid view dimension");
|
||||
}
|
||||
|
||||
m_view = pDevice->GetDXVKDevice()->createImageView(
|
||||
GetCommonTexture(pResource)->GetImage(), viewInfo);
|
||||
m_view = GetCommonTexture(pResource)->GetImage()->createView(viewInfo);
|
||||
}
|
||||
|
||||
|
||||
|
@ -1026,6 +1013,10 @@ namespace dxvk {
|
|||
const D3D11_VIDEO_PROCESSOR_STREAM* pStreams) {
|
||||
D3D10DeviceLock lock = m_ctx->LockContext();
|
||||
|
||||
m_ctx->EmitCs([] (DxvkContext* ctx) {
|
||||
ctx->beginDebugLabel(vk::makeLabel(0x59eaff, "Video blit"));
|
||||
});
|
||||
|
||||
auto videoProcessor = static_cast<D3D11VideoProcessor*>(pVideoProcessor);
|
||||
bool hasStreamsEnabled = false;
|
||||
|
||||
|
@ -1038,7 +1029,9 @@ namespace dxvk {
|
|||
continue;
|
||||
|
||||
if (!hasStreamsEnabled) {
|
||||
m_ctx->ResetDirtyTracking();
|
||||
m_ctx->ResetCommandListState();
|
||||
|
||||
BindOutputView(pOutputView);
|
||||
hasStreamsEnabled = true;
|
||||
}
|
||||
|
@ -1048,9 +1041,14 @@ namespace dxvk {
|
|||
|
||||
if (hasStreamsEnabled) {
|
||||
UnbindResources();
|
||||
|
||||
m_ctx->RestoreCommandListState();
|
||||
}
|
||||
|
||||
m_ctx->EmitCs([] (DxvkContext* ctx) {
|
||||
ctx->endDebugLabel();
|
||||
});
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
@ -1185,6 +1183,13 @@ namespace dxvk {
|
|||
auto dxvkView = static_cast<D3D11VideoProcessorOutputView*>(pOutputView)->GetView();
|
||||
|
||||
m_ctx->EmitCs([this, cView = dxvkView] (DxvkContext* ctx) {
|
||||
DxvkImageUsageInfo usage = { };
|
||||
usage.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
|
||||
usage.stages = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
|
||||
usage.access = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
|
||||
|
||||
ctx->ensureImageCompatibility(cView->image(), usage);
|
||||
|
||||
DxvkRenderTargets rt;
|
||||
rt.color[0].view = cView;
|
||||
rt.color[0].layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
|
||||
|
@ -1219,30 +1224,19 @@ namespace dxvk {
|
|||
|
||||
auto view = static_cast<D3D11VideoProcessorInputView*>(pStream->pInputSurface);
|
||||
|
||||
if (view->NeedsCopy()) {
|
||||
m_ctx->EmitCs([
|
||||
cDstImage = view->GetShadowCopy(),
|
||||
cSrcImage = view->GetImage(),
|
||||
cSrcLayers = view->GetImageSubresources()
|
||||
] (DxvkContext* ctx) {
|
||||
VkImageSubresourceLayers cDstLayers;
|
||||
cDstLayers.aspectMask = cSrcLayers.aspectMask;
|
||||
cDstLayers.baseArrayLayer = 0;
|
||||
cDstLayers.layerCount = cSrcLayers.layerCount;
|
||||
cDstLayers.mipLevel = cSrcLayers.mipLevel;
|
||||
|
||||
ctx->copyImage(
|
||||
cDstImage, cDstLayers, VkOffset3D(),
|
||||
cSrcImage, cSrcLayers, VkOffset3D(),
|
||||
cDstImage->info().extent);
|
||||
});
|
||||
}
|
||||
|
||||
m_ctx->EmitCs([this,
|
||||
cStreamState = *pStreamState,
|
||||
cImage = view->GetImage(),
|
||||
cViews = view->GetViews(),
|
||||
cIsYCbCr = view->IsYCbCr()
|
||||
] (DxvkContext* ctx) {
|
||||
DxvkImageUsageInfo usage = { };
|
||||
usage.usage = VK_IMAGE_USAGE_SAMPLED_BIT;
|
||||
usage.stages = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
|
||||
usage.access = VK_ACCESS_SHADER_READ_BIT;
|
||||
|
||||
ctx->ensureImageCompatibility(cImage, usage);
|
||||
|
||||
VkViewport viewport;
|
||||
viewport.x = 0.0f;
|
||||
viewport.y = 0.0f;
|
||||
|
@ -1262,12 +1256,28 @@ namespace dxvk {
|
|||
viewport.height = float(cStreamState.dstRect.bottom) - viewport.y;
|
||||
}
|
||||
|
||||
VkExtent3D viewExtent = cViews[0]->mipLevelExtent(0);
|
||||
|
||||
VkRect2D srcRect;
|
||||
srcRect.offset = { 0, 0 };
|
||||
srcRect.extent = { viewExtent.width, viewExtent.height };
|
||||
|
||||
if (cStreamState.srcRectEnabled) {
|
||||
srcRect.offset.x = cStreamState.srcRect.left;
|
||||
srcRect.offset.y = cStreamState.srcRect.top;
|
||||
srcRect.extent.width = cStreamState.srcRect.right - srcRect.offset.x;
|
||||
srcRect.extent.height = cStreamState.srcRect.bottom - srcRect.offset.y;
|
||||
}
|
||||
|
||||
UboData uboData = { };
|
||||
uboData.colorMatrix[0][0] = 1.0f;
|
||||
uboData.colorMatrix[1][1] = 1.0f;
|
||||
uboData.colorMatrix[2][2] = 1.0f;
|
||||
uboData.coordMatrix[0][0] = 1.0f;
|
||||
uboData.coordMatrix[1][1] = 1.0f;
|
||||
uboData.coordMatrix[0][0] = float(srcRect.extent.width) / float(viewExtent.width);
|
||||
uboData.coordMatrix[1][1] = float(srcRect.extent.height) / float(viewExtent.height);
|
||||
uboData.coordMatrix[2][0] = float(srcRect.offset.x) / float(viewExtent.width);
|
||||
uboData.coordMatrix[2][1] = float(srcRect.offset.y) / float(viewExtent.height);
|
||||
uboData.srcRect = srcRect;
|
||||
uboData.yMin = 0.0f;
|
||||
uboData.yMax = 1.0f;
|
||||
uboData.isPlanar = cViews[1] != nullptr;
|
||||
|
@ -1280,27 +1290,28 @@ namespace dxvk {
|
|||
uboData.yMax = 0.9215686f;
|
||||
}
|
||||
|
||||
DxvkBufferSliceHandle uboSlice = m_ubo->allocSlice();
|
||||
memcpy(uboSlice.mapPtr, &uboData, sizeof(uboData));
|
||||
Rc<DxvkResourceAllocation> uboSlice = m_ubo->allocateStorage();
|
||||
memcpy(uboSlice->mapPtr(), &uboData, sizeof(uboData));
|
||||
|
||||
ctx->invalidateBuffer(m_ubo, uboSlice);
|
||||
ctx->invalidateBuffer(m_ubo, std::move(uboSlice));
|
||||
ctx->setViewports(1, &viewport, &scissor);
|
||||
|
||||
ctx->bindShader<VK_SHADER_STAGE_VERTEX_BIT>(Rc<DxvkShader>(m_vs));
|
||||
ctx->bindShader<VK_SHADER_STAGE_FRAGMENT_BIT>(Rc<DxvkShader>(m_fs));
|
||||
|
||||
ctx->bindUniformBuffer(VK_SHADER_STAGE_FRAGMENT_BIT, 0, DxvkBufferSlice(m_ubo));
|
||||
ctx->bindResourceSampler(VK_SHADER_STAGE_FRAGMENT_BIT, 1, Rc<DxvkSampler>(m_sampler));
|
||||
|
||||
for (uint32_t i = 0; i < cViews.size(); i++)
|
||||
ctx->bindResourceImageView(VK_SHADER_STAGE_FRAGMENT_BIT, 2 + i, Rc<DxvkImageView>(cViews[i]));
|
||||
ctx->bindResourceImageView(VK_SHADER_STAGE_FRAGMENT_BIT, 1 + i, Rc<DxvkImageView>(cViews[i]));
|
||||
|
||||
ctx->draw(3, 1, 0, 0);
|
||||
VkDrawIndirectCommand draw = { };
|
||||
draw.vertexCount = 3u;
|
||||
draw.instanceCount = 1u;
|
||||
|
||||
ctx->bindResourceSampler(VK_SHADER_STAGE_FRAGMENT_BIT, 1, nullptr);
|
||||
ctx->draw(1, &draw);
|
||||
|
||||
for (uint32_t i = 0; i < cViews.size(); i++)
|
||||
ctx->bindResourceImageView(VK_SHADER_STAGE_FRAGMENT_BIT, 2 + i, nullptr);
|
||||
ctx->bindResourceImageView(VK_SHADER_STAGE_FRAGMENT_BIT, 1 + i, nullptr);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -1311,42 +1322,20 @@ namespace dxvk {
|
|||
bufferInfo.usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT;
|
||||
bufferInfo.stages = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
|
||||
bufferInfo.access = VK_ACCESS_UNIFORM_READ_BIT;
|
||||
bufferInfo.debugName = "Video blit parameters";
|
||||
|
||||
m_ubo = m_device->createBuffer(bufferInfo, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
|
||||
}
|
||||
|
||||
|
||||
void D3D11VideoContext::CreateSampler() {
|
||||
DxvkSamplerCreateInfo samplerInfo;
|
||||
samplerInfo.magFilter = VK_FILTER_LINEAR;
|
||||
samplerInfo.minFilter = VK_FILTER_LINEAR;
|
||||
samplerInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_NEAREST;
|
||||
samplerInfo.mipmapLodBias = 0.0f;
|
||||
samplerInfo.mipmapLodMin = 0.0f;
|
||||
samplerInfo.mipmapLodMax = 0.0f;
|
||||
samplerInfo.useAnisotropy = VK_FALSE;
|
||||
samplerInfo.maxAnisotropy = 1.0f;
|
||||
samplerInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
|
||||
samplerInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
|
||||
samplerInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
|
||||
samplerInfo.compareToDepth = VK_FALSE;
|
||||
samplerInfo.compareOp = VK_COMPARE_OP_ALWAYS;
|
||||
samplerInfo.reductionMode = VK_SAMPLER_REDUCTION_MODE_WEIGHTED_AVERAGE;
|
||||
samplerInfo.borderColor = VkClearColorValue();
|
||||
samplerInfo.usePixelCoord = VK_FALSE;
|
||||
samplerInfo.nonSeamless = VK_FALSE;
|
||||
m_sampler = m_device->createSampler(samplerInfo);
|
||||
}
|
||||
|
||||
|
||||
void D3D11VideoContext::CreateShaders() {
|
||||
SpirvCodeBuffer vsCode(d3d11_video_blit_vert);
|
||||
SpirvCodeBuffer fsCode(d3d11_video_blit_frag);
|
||||
|
||||
const std::array<DxvkBindingInfo, 4> fsBindings = {{
|
||||
const std::array<DxvkBindingInfo, 3> fsBindings = {{
|
||||
{ VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 0, VK_IMAGE_VIEW_TYPE_MAX_ENUM, VK_SHADER_STAGE_FRAGMENT_BIT, VK_ACCESS_UNIFORM_READ_BIT, VK_TRUE },
|
||||
{ VK_DESCRIPTOR_TYPE_SAMPLER, 1, VK_IMAGE_VIEW_TYPE_MAX_ENUM, VK_SHADER_STAGE_FRAGMENT_BIT, 0 },
|
||||
{ VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, 1, VK_IMAGE_VIEW_TYPE_2D, VK_SHADER_STAGE_FRAGMENT_BIT, VK_ACCESS_SHADER_READ_BIT },
|
||||
{ VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, 2, VK_IMAGE_VIEW_TYPE_2D, VK_SHADER_STAGE_FRAGMENT_BIT, VK_ACCESS_SHADER_READ_BIT },
|
||||
{ VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, 3, VK_IMAGE_VIEW_TYPE_2D, VK_SHADER_STAGE_FRAGMENT_BIT, VK_ACCESS_SHADER_READ_BIT },
|
||||
}};
|
||||
|
||||
DxvkShaderCreateInfo vsInfo;
|
||||
|
@ -1368,7 +1357,6 @@ namespace dxvk {
|
|||
if (std::exchange(m_resourcesCreated, true))
|
||||
return;
|
||||
|
||||
CreateSampler();
|
||||
CreateUniformBuffer();
|
||||
CreateShaders();
|
||||
}
|
||||
|
|
|
@ -138,10 +138,6 @@ namespace dxvk {
|
|||
return m_isYCbCr;
|
||||
}
|
||||
|
||||
bool NeedsCopy() const {
|
||||
return m_copy != nullptr;
|
||||
}
|
||||
|
||||
Rc<DxvkImage> GetImage() const {
|
||||
return GetCommonTexture(m_resource.ptr())->GetImage();
|
||||
}
|
||||
|
@ -150,10 +146,6 @@ namespace dxvk {
|
|||
return m_subresources;
|
||||
}
|
||||
|
||||
Rc<DxvkImage> GetShadowCopy() const {
|
||||
return m_copy;
|
||||
}
|
||||
|
||||
std::array<Rc<DxvkImageView>, 2> GetViews() const {
|
||||
return m_views;
|
||||
}
|
||||
|
@ -163,7 +155,6 @@ namespace dxvk {
|
|||
Com<ID3D11Resource> m_resource;
|
||||
D3D11_VIDEO_PROCESSOR_INPUT_VIEW_DESC m_desc;
|
||||
VkImageSubresourceLayers m_subresources;
|
||||
Rc<DxvkImage> m_copy;
|
||||
std::array<Rc<DxvkImageView>, 2> m_views;
|
||||
bool m_isYCbCr = false;
|
||||
|
||||
|
@ -584,6 +575,7 @@ namespace dxvk {
|
|||
struct alignas(16) UboData {
|
||||
float colorMatrix[3][4];
|
||||
float coordMatrix[3][2];
|
||||
VkRect2D srcRect;
|
||||
float yMin, yMax;
|
||||
VkBool32 isPlanar;
|
||||
};
|
||||
|
@ -593,7 +585,6 @@ namespace dxvk {
|
|||
Rc<DxvkDevice> m_device;
|
||||
Rc<DxvkShader> m_vs;
|
||||
Rc<DxvkShader> m_fs;
|
||||
Rc<DxvkSampler> m_sampler;
|
||||
Rc<DxvkBuffer> m_ubo;
|
||||
|
||||
VkExtent2D m_dstExtent = { 0u, 0u };
|
||||
|
@ -613,8 +604,6 @@ namespace dxvk {
|
|||
|
||||
void CreateUniformBuffer();
|
||||
|
||||
void CreateSampler();
|
||||
|
||||
void CreateShaders();
|
||||
|
||||
void CreateResources();
|
||||
|
|
|
@ -55,7 +55,7 @@ namespace dxvk {
|
|||
* \param [in] b Second view to check
|
||||
* \returns \c true if the views overlap
|
||||
*/
|
||||
inline bool CheckViewOverlap(const D3D11_VK_VIEW_INFO& a, const D3D11_VK_VIEW_INFO b) {
|
||||
inline bool CheckViewOverlap(const D3D11_VK_VIEW_INFO& a, const D3D11_VK_VIEW_INFO& b) {
|
||||
if (likely(a.pResource != b.pResource))
|
||||
return false;
|
||||
|
||||
|
@ -78,4 +78,4 @@ namespace dxvk {
|
|||
return a && b && CheckViewOverlap(a->GetViewInfo(), b->GetViewInfo());
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,58 +17,58 @@ namespace dxvk {
|
|||
D3D11_COMMON_RESOURCE_DESC resourceDesc;
|
||||
GetCommonResourceDesc(pResource, &resourceDesc);
|
||||
|
||||
DxvkImageViewCreateInfo viewInfo;
|
||||
DxvkImageViewKey viewInfo;
|
||||
viewInfo.format = pDevice->LookupFormat(pDesc->Format, DXGI_VK_FORMAT_MODE_DEPTH).Format;
|
||||
viewInfo.aspect = lookupFormatInfo(viewInfo.format)->aspectMask;
|
||||
viewInfo.usage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
|
||||
viewInfo.aspects = lookupFormatInfo(viewInfo.format)->aspectMask;
|
||||
viewInfo.usage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
|
||||
|
||||
switch (pDesc->ViewDimension) {
|
||||
case D3D11_DSV_DIMENSION_TEXTURE1D:
|
||||
viewInfo.type = VK_IMAGE_VIEW_TYPE_1D;
|
||||
viewInfo.minLevel = pDesc->Texture1D.MipSlice;
|
||||
viewInfo.numLevels = 1;
|
||||
viewInfo.minLayer = 0;
|
||||
viewInfo.numLayers = 1;
|
||||
viewInfo.viewType = VK_IMAGE_VIEW_TYPE_1D;
|
||||
viewInfo.mipIndex = pDesc->Texture1D.MipSlice;
|
||||
viewInfo.mipCount = 1;
|
||||
viewInfo.layerIndex = 0;
|
||||
viewInfo.layerCount = 1;
|
||||
break;
|
||||
|
||||
case D3D11_DSV_DIMENSION_TEXTURE1DARRAY:
|
||||
viewInfo.type = VK_IMAGE_VIEW_TYPE_1D_ARRAY;
|
||||
viewInfo.minLevel = pDesc->Texture1DArray.MipSlice;
|
||||
viewInfo.numLevels = 1;
|
||||
viewInfo.minLayer = pDesc->Texture1DArray.FirstArraySlice;
|
||||
viewInfo.numLayers = pDesc->Texture1DArray.ArraySize;
|
||||
viewInfo.viewType = VK_IMAGE_VIEW_TYPE_1D_ARRAY;
|
||||
viewInfo.mipIndex = pDesc->Texture1DArray.MipSlice;
|
||||
viewInfo.mipCount = 1;
|
||||
viewInfo.layerIndex = pDesc->Texture1DArray.FirstArraySlice;
|
||||
viewInfo.layerCount = pDesc->Texture1DArray.ArraySize;
|
||||
break;
|
||||
|
||||
case D3D11_DSV_DIMENSION_TEXTURE2D:
|
||||
viewInfo.type = VK_IMAGE_VIEW_TYPE_2D;
|
||||
viewInfo.minLevel = pDesc->Texture2D.MipSlice;
|
||||
viewInfo.numLevels = 1;
|
||||
viewInfo.minLayer = 0;
|
||||
viewInfo.numLayers = 1;
|
||||
viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
|
||||
viewInfo.mipIndex = pDesc->Texture2D.MipSlice;
|
||||
viewInfo.mipCount = 1;
|
||||
viewInfo.layerIndex = 0;
|
||||
viewInfo.layerCount = 1;
|
||||
break;
|
||||
|
||||
case D3D11_DSV_DIMENSION_TEXTURE2DARRAY:
|
||||
viewInfo.type = VK_IMAGE_VIEW_TYPE_2D_ARRAY;
|
||||
viewInfo.minLevel = pDesc->Texture2DArray.MipSlice;
|
||||
viewInfo.numLevels = 1;
|
||||
viewInfo.minLayer = pDesc->Texture2DArray.FirstArraySlice;
|
||||
viewInfo.numLayers = pDesc->Texture2DArray.ArraySize;
|
||||
viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D_ARRAY;
|
||||
viewInfo.mipIndex = pDesc->Texture2DArray.MipSlice;
|
||||
viewInfo.mipCount = 1;
|
||||
viewInfo.layerIndex = pDesc->Texture2DArray.FirstArraySlice;
|
||||
viewInfo.layerCount = pDesc->Texture2DArray.ArraySize;
|
||||
break;
|
||||
|
||||
case D3D11_DSV_DIMENSION_TEXTURE2DMS:
|
||||
viewInfo.type = VK_IMAGE_VIEW_TYPE_2D;
|
||||
viewInfo.minLevel = 0;
|
||||
viewInfo.numLevels = 1;
|
||||
viewInfo.minLayer = 0;
|
||||
viewInfo.numLayers = 1;
|
||||
viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
|
||||
viewInfo.mipIndex = 0;
|
||||
viewInfo.mipCount = 1;
|
||||
viewInfo.layerIndex = 0;
|
||||
viewInfo.layerCount = 1;
|
||||
break;
|
||||
|
||||
case D3D11_DSV_DIMENSION_TEXTURE2DMSARRAY:
|
||||
viewInfo.type = VK_IMAGE_VIEW_TYPE_2D_ARRAY;
|
||||
viewInfo.minLevel = 0;
|
||||
viewInfo.numLevels = 1;
|
||||
viewInfo.minLayer = pDesc->Texture2DMSArray.FirstArraySlice;
|
||||
viewInfo.numLayers = pDesc->Texture2DMSArray.ArraySize;
|
||||
viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D_ARRAY;
|
||||
viewInfo.mipIndex = 0;
|
||||
viewInfo.mipCount = 1;
|
||||
viewInfo.layerIndex = pDesc->Texture2DMSArray.FirstArraySlice;
|
||||
viewInfo.layerCount = pDesc->Texture2DMSArray.ArraySize;
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -77,20 +77,22 @@ namespace dxvk {
|
|||
|
||||
// Normalize view type so that we won't accidentally
|
||||
// bind 2D array views and 2D views at the same time
|
||||
if (viewInfo.numLayers == 1) {
|
||||
if (viewInfo.type == VK_IMAGE_VIEW_TYPE_1D_ARRAY) viewInfo.type = VK_IMAGE_VIEW_TYPE_1D;
|
||||
if (viewInfo.type == VK_IMAGE_VIEW_TYPE_2D_ARRAY) viewInfo.type = VK_IMAGE_VIEW_TYPE_2D;
|
||||
if (viewInfo.layerCount == 1) {
|
||||
if (viewInfo.viewType == VK_IMAGE_VIEW_TYPE_1D_ARRAY)
|
||||
viewInfo.viewType = VK_IMAGE_VIEW_TYPE_1D;
|
||||
if (viewInfo.viewType == VK_IMAGE_VIEW_TYPE_2D_ARRAY)
|
||||
viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
|
||||
}
|
||||
|
||||
// Populate view info struct
|
||||
m_info.pResource = pResource;
|
||||
m_info.Dimension = resourceDesc.Dim;
|
||||
m_info.BindFlags = resourceDesc.BindFlags;
|
||||
m_info.Image.Aspects = viewInfo.aspect;
|
||||
m_info.Image.MinLevel = viewInfo.minLevel;
|
||||
m_info.Image.MinLayer = viewInfo.minLayer;
|
||||
m_info.Image.NumLevels = viewInfo.numLevels;
|
||||
m_info.Image.NumLayers = viewInfo.numLayers;
|
||||
m_info.Image.Aspects = viewInfo.aspects;
|
||||
m_info.Image.MinLevel = viewInfo.mipIndex;
|
||||
m_info.Image.MinLayer = viewInfo.layerIndex;
|
||||
m_info.Image.NumLevels = viewInfo.mipCount;
|
||||
m_info.Image.NumLayers = viewInfo.layerCount;
|
||||
|
||||
if (m_desc.Flags & D3D11_DSV_READ_ONLY_DEPTH)
|
||||
m_info.Image.Aspects &= ~VK_IMAGE_ASPECT_DEPTH_BIT;
|
||||
|
@ -99,13 +101,15 @@ namespace dxvk {
|
|||
m_info.Image.Aspects &= ~VK_IMAGE_ASPECT_STENCIL_BIT;
|
||||
|
||||
// Create the underlying image view object
|
||||
m_view = pDevice->GetDXVKDevice()->createImageView(
|
||||
GetCommonTexture(pResource)->GetImage(), viewInfo);
|
||||
m_view = GetCommonTexture(pResource)->GetImage()->createView(viewInfo);
|
||||
}
|
||||
|
||||
|
||||
D3D11DepthStencilView::~D3D11DepthStencilView() {
|
||||
ResourceReleasePrivate(m_resource);
|
||||
m_resource = nullptr;
|
||||
|
||||
m_view = nullptr;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -50,24 +50,20 @@ namespace dxvk {
|
|||
}
|
||||
|
||||
VkImageLayout GetRenderLayout() const {
|
||||
if (m_view->imageInfo().tiling == VK_IMAGE_TILING_OPTIMAL) {
|
||||
switch (m_desc.Flags & (D3D11_DSV_READ_ONLY_DEPTH | D3D11_DSV_READ_ONLY_STENCIL)) {
|
||||
default: // case 0
|
||||
return VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
|
||||
case D3D11_DSV_READ_ONLY_DEPTH:
|
||||
return VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL_KHR;
|
||||
case D3D11_DSV_READ_ONLY_STENCIL:
|
||||
return VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL_KHR;
|
||||
case D3D11_DSV_READ_ONLY_DEPTH | D3D11_DSV_READ_ONLY_STENCIL:
|
||||
return VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL;
|
||||
}
|
||||
} else {
|
||||
return VK_IMAGE_LAYOUT_GENERAL;
|
||||
switch (m_desc.Flags & (D3D11_DSV_READ_ONLY_DEPTH | D3D11_DSV_READ_ONLY_STENCIL)) {
|
||||
default: // case 0
|
||||
return VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
|
||||
case D3D11_DSV_READ_ONLY_DEPTH:
|
||||
return VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL_KHR;
|
||||
case D3D11_DSV_READ_ONLY_STENCIL:
|
||||
return VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL_KHR;
|
||||
case D3D11_DSV_READ_ONLY_DEPTH | D3D11_DSV_READ_ONLY_STENCIL:
|
||||
return VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL;
|
||||
}
|
||||
}
|
||||
|
||||
UINT GetSampleCount() const {
|
||||
return UINT(m_view->imageInfo().sampleCount);
|
||||
return UINT(m_view->image()->info().sampleCount);
|
||||
}
|
||||
|
||||
VkImageAspectFlags GetWritableAspectMask() const {
|
||||
|
|
|
@ -22,67 +22,67 @@ namespace dxvk {
|
|||
DXGI_VK_FORMAT_INFO formatInfo = pDevice->LookupFormat(
|
||||
pDesc->Format, DXGI_VK_FORMAT_MODE_COLOR);
|
||||
|
||||
DxvkImageViewCreateInfo viewInfo;
|
||||
viewInfo.format = formatInfo.Format;
|
||||
viewInfo.aspect = lookupFormatInfo(viewInfo.format)->aspectMask;
|
||||
viewInfo.swizzle = formatInfo.Swizzle;
|
||||
viewInfo.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
|
||||
DxvkImageViewKey viewInfo;
|
||||
viewInfo.format = formatInfo.Format;
|
||||
viewInfo.aspects = lookupFormatInfo(viewInfo.format)->aspectMask;
|
||||
viewInfo.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
|
||||
viewInfo.packedSwizzle = DxvkImageViewKey::packSwizzle(formatInfo.Swizzle);
|
||||
|
||||
switch (pDesc->ViewDimension) {
|
||||
case D3D11_RTV_DIMENSION_TEXTURE1D:
|
||||
viewInfo.type = VK_IMAGE_VIEW_TYPE_1D;
|
||||
viewInfo.minLevel = pDesc->Texture1D.MipSlice;
|
||||
viewInfo.numLevels = 1;
|
||||
viewInfo.minLayer = 0;
|
||||
viewInfo.numLayers = 1;
|
||||
viewInfo.viewType = VK_IMAGE_VIEW_TYPE_1D;
|
||||
viewInfo.mipIndex = pDesc->Texture1D.MipSlice;
|
||||
viewInfo.mipCount = 1;
|
||||
viewInfo.layerIndex = 0;
|
||||
viewInfo.layerCount = 1;
|
||||
break;
|
||||
|
||||
case D3D11_RTV_DIMENSION_TEXTURE1DARRAY:
|
||||
viewInfo.type = VK_IMAGE_VIEW_TYPE_1D_ARRAY;
|
||||
viewInfo.minLevel = pDesc->Texture1DArray.MipSlice;
|
||||
viewInfo.numLevels = 1;
|
||||
viewInfo.minLayer = pDesc->Texture1DArray.FirstArraySlice;
|
||||
viewInfo.numLayers = pDesc->Texture1DArray.ArraySize;
|
||||
viewInfo.viewType = VK_IMAGE_VIEW_TYPE_1D_ARRAY;
|
||||
viewInfo.mipIndex = pDesc->Texture1DArray.MipSlice;
|
||||
viewInfo.mipCount = 1;
|
||||
viewInfo.layerIndex = pDesc->Texture1DArray.FirstArraySlice;
|
||||
viewInfo.layerCount = pDesc->Texture1DArray.ArraySize;
|
||||
break;
|
||||
|
||||
case D3D11_RTV_DIMENSION_TEXTURE2D:
|
||||
viewInfo.type = VK_IMAGE_VIEW_TYPE_2D;
|
||||
viewInfo.minLevel = pDesc->Texture2D.MipSlice;
|
||||
viewInfo.numLevels = 1;
|
||||
viewInfo.minLayer = 0;
|
||||
viewInfo.numLayers = 1;
|
||||
viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
|
||||
viewInfo.mipIndex = pDesc->Texture2D.MipSlice;
|
||||
viewInfo.mipCount = 1;
|
||||
viewInfo.layerIndex = 0;
|
||||
viewInfo.layerCount = 1;
|
||||
break;
|
||||
|
||||
case D3D11_RTV_DIMENSION_TEXTURE2DARRAY:
|
||||
viewInfo.type = VK_IMAGE_VIEW_TYPE_2D_ARRAY;
|
||||
viewInfo.minLevel = pDesc->Texture2DArray.MipSlice;
|
||||
viewInfo.numLevels = 1;
|
||||
viewInfo.minLayer = pDesc->Texture2DArray.FirstArraySlice;
|
||||
viewInfo.numLayers = pDesc->Texture2DArray.ArraySize;
|
||||
viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D_ARRAY;
|
||||
viewInfo.mipIndex = pDesc->Texture2DArray.MipSlice;
|
||||
viewInfo.mipCount = 1;
|
||||
viewInfo.layerIndex = pDesc->Texture2DArray.FirstArraySlice;
|
||||
viewInfo.layerCount = pDesc->Texture2DArray.ArraySize;
|
||||
break;
|
||||
|
||||
case D3D11_RTV_DIMENSION_TEXTURE2DMS:
|
||||
viewInfo.type = VK_IMAGE_VIEW_TYPE_2D;
|
||||
viewInfo.minLevel = 0;
|
||||
viewInfo.numLevels = 1;
|
||||
viewInfo.minLayer = 0;
|
||||
viewInfo.numLayers = 1;
|
||||
viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
|
||||
viewInfo.mipIndex = 0;
|
||||
viewInfo.mipCount = 1;
|
||||
viewInfo.layerIndex = 0;
|
||||
viewInfo.layerCount = 1;
|
||||
break;
|
||||
|
||||
case D3D11_RTV_DIMENSION_TEXTURE2DMSARRAY:
|
||||
viewInfo.type = VK_IMAGE_VIEW_TYPE_2D_ARRAY;
|
||||
viewInfo.minLevel = 0;
|
||||
viewInfo.numLevels = 1;
|
||||
viewInfo.minLayer = pDesc->Texture2DMSArray.FirstArraySlice;
|
||||
viewInfo.numLayers = pDesc->Texture2DMSArray.ArraySize;
|
||||
viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D_ARRAY;
|
||||
viewInfo.mipIndex = 0;
|
||||
viewInfo.mipCount = 1;
|
||||
viewInfo.layerIndex = pDesc->Texture2DMSArray.FirstArraySlice;
|
||||
viewInfo.layerCount = pDesc->Texture2DMSArray.ArraySize;
|
||||
break;
|
||||
|
||||
case D3D11_RTV_DIMENSION_TEXTURE3D:
|
||||
viewInfo.type = VK_IMAGE_VIEW_TYPE_2D_ARRAY;
|
||||
viewInfo.minLevel = pDesc->Texture3D.MipSlice;
|
||||
viewInfo.numLevels = 1;
|
||||
viewInfo.minLayer = pDesc->Texture3D.FirstWSlice;
|
||||
viewInfo.numLayers = pDesc->Texture3D.WSize;
|
||||
viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D_ARRAY;
|
||||
viewInfo.mipIndex = pDesc->Texture3D.MipSlice;
|
||||
viewInfo.mipCount = 1;
|
||||
viewInfo.layerIndex = pDesc->Texture3D.FirstWSlice;
|
||||
viewInfo.layerCount = pDesc->Texture3D.WSize;
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -90,32 +90,37 @@ namespace dxvk {
|
|||
}
|
||||
|
||||
if (texture->GetPlaneCount() > 1)
|
||||
viewInfo.aspect = vk::getPlaneAspect(GetPlaneSlice(pDesc));
|
||||
viewInfo.aspects = vk::getPlaneAspect(GetPlaneSlice(pDesc));
|
||||
|
||||
// Normalize view type so that we won't accidentally
|
||||
// bind 2D array views and 2D views at the same time
|
||||
if (viewInfo.numLayers == 1) {
|
||||
if (viewInfo.type == VK_IMAGE_VIEW_TYPE_1D_ARRAY) viewInfo.type = VK_IMAGE_VIEW_TYPE_1D;
|
||||
if (viewInfo.type == VK_IMAGE_VIEW_TYPE_2D_ARRAY) viewInfo.type = VK_IMAGE_VIEW_TYPE_2D;
|
||||
if (viewInfo.layerCount == 1) {
|
||||
if (viewInfo.viewType == VK_IMAGE_VIEW_TYPE_1D_ARRAY)
|
||||
viewInfo.viewType = VK_IMAGE_VIEW_TYPE_1D;
|
||||
if (viewInfo.viewType == VK_IMAGE_VIEW_TYPE_2D_ARRAY)
|
||||
viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
|
||||
}
|
||||
|
||||
// Populate view info struct
|
||||
m_info.pResource = pResource;
|
||||
m_info.Dimension = resourceDesc.Dim;
|
||||
m_info.BindFlags = resourceDesc.BindFlags;
|
||||
m_info.Image.Aspects = viewInfo.aspect;
|
||||
m_info.Image.MinLevel = viewInfo.minLevel;
|
||||
m_info.Image.MinLayer = viewInfo.minLayer;
|
||||
m_info.Image.NumLevels = viewInfo.numLevels;
|
||||
m_info.Image.NumLayers = viewInfo.numLayers;
|
||||
m_info.Image.Aspects = viewInfo.aspects;
|
||||
m_info.Image.MinLevel = viewInfo.mipIndex;
|
||||
m_info.Image.MinLayer = viewInfo.layerIndex;
|
||||
m_info.Image.NumLevels = viewInfo.mipCount;
|
||||
m_info.Image.NumLayers = viewInfo.layerCount;
|
||||
|
||||
// Create the underlying image view object
|
||||
m_view = pDevice->GetDXVKDevice()->createImageView(texture->GetImage(), viewInfo);
|
||||
m_view = texture->GetImage()->createView(viewInfo);
|
||||
}
|
||||
|
||||
|
||||
D3D11RenderTargetView::~D3D11RenderTargetView() {
|
||||
ResourceReleasePrivate(m_resource);
|
||||
m_resource = nullptr;
|
||||
|
||||
m_view = nullptr;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -52,13 +52,11 @@ namespace dxvk {
|
|||
}
|
||||
|
||||
VkImageLayout GetRenderLayout() const {
|
||||
return m_view->imageInfo().tiling == VK_IMAGE_TILING_OPTIMAL
|
||||
? VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL
|
||||
: VK_IMAGE_LAYOUT_GENERAL;
|
||||
return VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
|
||||
}
|
||||
|
||||
UINT GetSampleCount() const {
|
||||
return UINT(m_view->imageInfo().sampleCount);
|
||||
return UINT(m_view->image()->info().sampleCount);
|
||||
}
|
||||
|
||||
D3D10RenderTargetView* GetD3D10Iface() {
|
||||
|
|
|
@ -42,123 +42,123 @@ namespace dxvk {
|
|||
}
|
||||
|
||||
// Fill in buffer view info
|
||||
DxvkBufferViewCreateInfo viewInfo;
|
||||
DxvkBufferViewKey viewInfo;
|
||||
viewInfo.usage = VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT;
|
||||
|
||||
if (bufInfo.Flags & D3D11_BUFFEREX_SRV_FLAG_RAW) {
|
||||
// Raw buffer view. We'll represent this as a
|
||||
// uniform texel buffer with UINT32 elements.
|
||||
viewInfo.format = VK_FORMAT_R32_UINT;
|
||||
viewInfo.rangeOffset = sizeof(uint32_t) * bufInfo.FirstElement;
|
||||
viewInfo.rangeLength = sizeof(uint32_t) * bufInfo.NumElements;
|
||||
viewInfo.offset = sizeof(uint32_t) * bufInfo.FirstElement;
|
||||
viewInfo.size = sizeof(uint32_t) * bufInfo.NumElements;
|
||||
} else if (pDesc->Format == DXGI_FORMAT_UNKNOWN) {
|
||||
// Structured buffer view
|
||||
viewInfo.format = VK_FORMAT_R32_UINT;
|
||||
viewInfo.rangeOffset = buffer->Desc()->StructureByteStride * bufInfo.FirstElement;
|
||||
viewInfo.rangeLength = buffer->Desc()->StructureByteStride * bufInfo.NumElements;
|
||||
viewInfo.offset = buffer->Desc()->StructureByteStride * bufInfo.FirstElement;
|
||||
viewInfo.size = buffer->Desc()->StructureByteStride * bufInfo.NumElements;
|
||||
} else {
|
||||
viewInfo.format = pDevice->LookupFormat(pDesc->Format, DXGI_VK_FORMAT_MODE_COLOR).Format;
|
||||
|
||||
const DxvkFormatInfo* formatInfo = lookupFormatInfo(viewInfo.format);
|
||||
viewInfo.rangeOffset = formatInfo->elementSize * bufInfo.FirstElement;
|
||||
viewInfo.rangeLength = formatInfo->elementSize * bufInfo.NumElements;
|
||||
viewInfo.offset = formatInfo->elementSize * bufInfo.FirstElement;
|
||||
viewInfo.size = formatInfo->elementSize * bufInfo.NumElements;
|
||||
}
|
||||
|
||||
// Populate view info struct
|
||||
m_info.Buffer.Offset = viewInfo.rangeOffset;
|
||||
m_info.Buffer.Length = viewInfo.rangeLength;
|
||||
m_info.Buffer.Offset = viewInfo.offset;
|
||||
m_info.Buffer.Length = viewInfo.size;
|
||||
|
||||
// Create underlying buffer view object
|
||||
m_bufferView = pDevice->GetDXVKDevice()->createBufferView(
|
||||
buffer->GetBuffer(), viewInfo);
|
||||
m_bufferView = buffer->GetBuffer()->createView(viewInfo);
|
||||
} else {
|
||||
auto texture = GetCommonTexture(pResource);
|
||||
auto formatInfo = pDevice->LookupFormat(pDesc->Format, texture->GetFormatMode());
|
||||
|
||||
DxvkImageViewCreateInfo viewInfo;
|
||||
viewInfo.format = formatInfo.Format;
|
||||
viewInfo.aspect = formatInfo.Aspect;
|
||||
viewInfo.swizzle = formatInfo.Swizzle;
|
||||
viewInfo.usage = VK_IMAGE_USAGE_SAMPLED_BIT;
|
||||
DxvkImageViewKey viewInfo;
|
||||
viewInfo.format = formatInfo.Format;
|
||||
viewInfo.aspects = formatInfo.Aspect;
|
||||
viewInfo.usage = VK_IMAGE_USAGE_SAMPLED_BIT;
|
||||
viewInfo.packedSwizzle = DxvkImageViewKey::packSwizzle(formatInfo.Swizzle);
|
||||
|
||||
// Shaders expect the stencil value in the G component
|
||||
if (viewInfo.aspect == VK_IMAGE_ASPECT_STENCIL_BIT) {
|
||||
viewInfo.swizzle = VkComponentMapping {
|
||||
if (viewInfo.aspects == VK_IMAGE_ASPECT_STENCIL_BIT) {
|
||||
viewInfo.packedSwizzle = DxvkImageViewKey::packSwizzle({
|
||||
VK_COMPONENT_SWIZZLE_ZERO, VK_COMPONENT_SWIZZLE_R,
|
||||
VK_COMPONENT_SWIZZLE_ZERO, VK_COMPONENT_SWIZZLE_ZERO };
|
||||
VK_COMPONENT_SWIZZLE_ZERO, VK_COMPONENT_SWIZZLE_ZERO });
|
||||
}
|
||||
|
||||
switch (pDesc->ViewDimension) {
|
||||
case D3D11_SRV_DIMENSION_TEXTURE1D:
|
||||
viewInfo.type = VK_IMAGE_VIEW_TYPE_1D;
|
||||
viewInfo.minLevel = pDesc->Texture1D.MostDetailedMip;
|
||||
viewInfo.numLevels = pDesc->Texture1D.MipLevels;
|
||||
viewInfo.minLayer = 0;
|
||||
viewInfo.numLayers = 1;
|
||||
viewInfo.viewType = VK_IMAGE_VIEW_TYPE_1D;
|
||||
viewInfo.mipIndex = pDesc->Texture1D.MostDetailedMip;
|
||||
viewInfo.mipCount = pDesc->Texture1D.MipLevels;
|
||||
viewInfo.layerIndex = 0;
|
||||
viewInfo.layerCount = 1;
|
||||
break;
|
||||
|
||||
case D3D11_SRV_DIMENSION_TEXTURE1DARRAY:
|
||||
viewInfo.type = VK_IMAGE_VIEW_TYPE_1D_ARRAY;
|
||||
viewInfo.minLevel = pDesc->Texture1DArray.MostDetailedMip;
|
||||
viewInfo.numLevels = pDesc->Texture1DArray.MipLevels;
|
||||
viewInfo.minLayer = pDesc->Texture1DArray.FirstArraySlice;
|
||||
viewInfo.numLayers = pDesc->Texture1DArray.ArraySize;
|
||||
viewInfo.viewType = VK_IMAGE_VIEW_TYPE_1D_ARRAY;
|
||||
viewInfo.mipIndex = pDesc->Texture1DArray.MostDetailedMip;
|
||||
viewInfo.mipCount = pDesc->Texture1DArray.MipLevels;
|
||||
viewInfo.layerIndex = pDesc->Texture1DArray.FirstArraySlice;
|
||||
viewInfo.layerCount = pDesc->Texture1DArray.ArraySize;
|
||||
break;
|
||||
|
||||
case D3D11_SRV_DIMENSION_TEXTURE2D:
|
||||
viewInfo.type = VK_IMAGE_VIEW_TYPE_2D;
|
||||
viewInfo.minLevel = pDesc->Texture2D.MostDetailedMip;
|
||||
viewInfo.numLevels = pDesc->Texture2D.MipLevels;
|
||||
viewInfo.minLayer = 0;
|
||||
viewInfo.numLayers = 1;
|
||||
viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
|
||||
viewInfo.mipIndex = pDesc->Texture2D.MostDetailedMip;
|
||||
viewInfo.mipCount = pDesc->Texture2D.MipLevels;
|
||||
viewInfo.layerIndex = 0;
|
||||
viewInfo.layerCount = 1;
|
||||
break;
|
||||
|
||||
case D3D11_SRV_DIMENSION_TEXTURE2DARRAY:
|
||||
viewInfo.type = VK_IMAGE_VIEW_TYPE_2D_ARRAY;
|
||||
viewInfo.minLevel = pDesc->Texture2DArray.MostDetailedMip;
|
||||
viewInfo.numLevels = pDesc->Texture2DArray.MipLevels;
|
||||
viewInfo.minLayer = pDesc->Texture2DArray.FirstArraySlice;
|
||||
viewInfo.numLayers = pDesc->Texture2DArray.ArraySize;
|
||||
viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D_ARRAY;
|
||||
viewInfo.mipIndex = pDesc->Texture2DArray.MostDetailedMip;
|
||||
viewInfo.mipCount = pDesc->Texture2DArray.MipLevels;
|
||||
viewInfo.layerIndex = pDesc->Texture2DArray.FirstArraySlice;
|
||||
viewInfo.layerCount = pDesc->Texture2DArray.ArraySize;
|
||||
break;
|
||||
|
||||
case D3D11_SRV_DIMENSION_TEXTURE2DMS:
|
||||
viewInfo.type = VK_IMAGE_VIEW_TYPE_2D;
|
||||
viewInfo.minLevel = 0;
|
||||
viewInfo.numLevels = 1;
|
||||
viewInfo.minLayer = 0;
|
||||
viewInfo.numLayers = 1;
|
||||
viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
|
||||
viewInfo.mipIndex = 0;
|
||||
viewInfo.mipCount = 1;
|
||||
viewInfo.layerIndex = 0;
|
||||
viewInfo.layerCount = 1;
|
||||
break;
|
||||
|
||||
case D3D11_SRV_DIMENSION_TEXTURE2DMSARRAY:
|
||||
viewInfo.type = VK_IMAGE_VIEW_TYPE_2D_ARRAY;
|
||||
viewInfo.minLevel = 0;
|
||||
viewInfo.numLevels = 1;
|
||||
viewInfo.minLayer = pDesc->Texture2DMSArray.FirstArraySlice;
|
||||
viewInfo.numLayers = pDesc->Texture2DMSArray.ArraySize;
|
||||
viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D_ARRAY;
|
||||
viewInfo.mipIndex = 0;
|
||||
viewInfo.mipCount = 1;
|
||||
viewInfo.layerIndex = pDesc->Texture2DMSArray.FirstArraySlice;
|
||||
viewInfo.layerCount = pDesc->Texture2DMSArray.ArraySize;
|
||||
break;
|
||||
|
||||
case D3D11_SRV_DIMENSION_TEXTURE3D:
|
||||
viewInfo.type = VK_IMAGE_VIEW_TYPE_3D;
|
||||
viewInfo.minLevel = pDesc->Texture3D.MostDetailedMip;
|
||||
viewInfo.numLevels = pDesc->Texture3D.MipLevels;
|
||||
viewInfo.minLayer = 0;
|
||||
viewInfo.numLayers = 1;
|
||||
viewInfo.viewType = VK_IMAGE_VIEW_TYPE_3D;
|
||||
viewInfo.mipIndex = pDesc->Texture3D.MostDetailedMip;
|
||||
viewInfo.mipCount = pDesc->Texture3D.MipLevels;
|
||||
viewInfo.layerIndex = 0;
|
||||
viewInfo.layerCount = 1;
|
||||
break;
|
||||
|
||||
case D3D11_SRV_DIMENSION_TEXTURECUBE: {
|
||||
const bool cubeArraysEnabled = pDevice->GetDXVKDevice()->features().core.features.imageCubeArray;
|
||||
viewInfo.type = cubeArraysEnabled ? VK_IMAGE_VIEW_TYPE_CUBE_ARRAY : VK_IMAGE_VIEW_TYPE_CUBE;
|
||||
viewInfo.minLevel = pDesc->TextureCube.MostDetailedMip;
|
||||
viewInfo.numLevels = pDesc->TextureCube.MipLevels;
|
||||
viewInfo.minLayer = 0;
|
||||
viewInfo.numLayers = 6;
|
||||
viewInfo.viewType = cubeArraysEnabled ? VK_IMAGE_VIEW_TYPE_CUBE_ARRAY : VK_IMAGE_VIEW_TYPE_CUBE;
|
||||
viewInfo.mipIndex = pDesc->TextureCube.MostDetailedMip;
|
||||
viewInfo.mipCount = pDesc->TextureCube.MipLevels;
|
||||
viewInfo.layerIndex = 0;
|
||||
viewInfo.layerCount = 6;
|
||||
} break;
|
||||
|
||||
case D3D11_SRV_DIMENSION_TEXTURECUBEARRAY:
|
||||
viewInfo.type = VK_IMAGE_VIEW_TYPE_CUBE_ARRAY;
|
||||
viewInfo.minLevel = pDesc->TextureCubeArray.MostDetailedMip;
|
||||
viewInfo.numLevels = pDesc->TextureCubeArray.MipLevels;
|
||||
viewInfo.minLayer = pDesc->TextureCubeArray.First2DArrayFace;
|
||||
viewInfo.numLayers = pDesc->TextureCubeArray.NumCubes * 6;
|
||||
viewInfo.viewType = VK_IMAGE_VIEW_TYPE_CUBE_ARRAY;
|
||||
viewInfo.mipIndex = pDesc->TextureCubeArray.MostDetailedMip;
|
||||
viewInfo.mipCount = pDesc->TextureCubeArray.MipLevels;
|
||||
viewInfo.layerIndex = pDesc->TextureCubeArray.First2DArrayFace;
|
||||
viewInfo.layerCount = pDesc->TextureCubeArray.NumCubes * 6;
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -166,23 +166,27 @@ namespace dxvk {
|
|||
}
|
||||
|
||||
if (texture->GetPlaneCount() > 1)
|
||||
viewInfo.aspect = vk::getPlaneAspect(GetPlaneSlice(pDesc));
|
||||
viewInfo.aspects = vk::getPlaneAspect(GetPlaneSlice(pDesc));
|
||||
|
||||
// Populate view info struct
|
||||
m_info.Image.Aspects = viewInfo.aspect;
|
||||
m_info.Image.MinLevel = viewInfo.minLevel;
|
||||
m_info.Image.MinLayer = viewInfo.minLayer;
|
||||
m_info.Image.NumLevels = viewInfo.numLevels;
|
||||
m_info.Image.NumLayers = viewInfo.numLayers;
|
||||
m_info.Image.Aspects = viewInfo.aspects;
|
||||
m_info.Image.MinLevel = viewInfo.mipIndex;
|
||||
m_info.Image.MinLayer = viewInfo.layerIndex;
|
||||
m_info.Image.NumLevels = viewInfo.mipCount;
|
||||
m_info.Image.NumLayers = viewInfo.layerCount;
|
||||
|
||||
// Create the underlying image view object
|
||||
m_imageView = pDevice->GetDXVKDevice()->createImageView(texture->GetImage(), viewInfo);
|
||||
m_imageView = texture->GetImage()->createView(viewInfo);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
D3D11ShaderResourceView::~D3D11ShaderResourceView() {
|
||||
ResourceReleasePrivate(m_resource);
|
||||
m_resource = nullptr;
|
||||
|
||||
m_imageView = nullptr;
|
||||
m_bufferView = nullptr;
|
||||
}
|
||||
|
||||
|
||||
|
@ -298,7 +302,7 @@ namespace dxvk {
|
|||
D3D11_BUFFER_DESC bufferDesc;
|
||||
static_cast<D3D11Buffer*>(pResource)->GetDesc(&bufferDesc);
|
||||
|
||||
if (bufferDesc.MiscFlags == D3D11_RESOURCE_MISC_BUFFER_STRUCTURED) {
|
||||
if (bufferDesc.MiscFlags & D3D11_RESOURCE_MISC_BUFFER_STRUCTURED) {
|
||||
pDesc->Format = DXGI_FORMAT_UNKNOWN;
|
||||
pDesc->ViewDimension = D3D11_SRV_DIMENSION_BUFFER;
|
||||
pDesc->Buffer.FirstElement = 0;
|
||||
|
|
|
@ -25,86 +25,86 @@ namespace dxvk {
|
|||
if (resourceDesc.Dim == D3D11_RESOURCE_DIMENSION_BUFFER) {
|
||||
auto buffer = static_cast<D3D11Buffer*>(pResource);
|
||||
|
||||
DxvkBufferViewCreateInfo viewInfo;
|
||||
DxvkBufferViewKey viewInfo;
|
||||
viewInfo.usage = VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT;
|
||||
|
||||
if (pDesc->Buffer.Flags & D3D11_BUFFEREX_SRV_FLAG_RAW) {
|
||||
viewInfo.format = VK_FORMAT_R32_UINT;
|
||||
viewInfo.rangeOffset = sizeof(uint32_t) * pDesc->Buffer.FirstElement;
|
||||
viewInfo.rangeLength = sizeof(uint32_t) * pDesc->Buffer.NumElements;
|
||||
viewInfo.format = VK_FORMAT_R32_UINT;
|
||||
viewInfo.offset = sizeof(uint32_t) * pDesc->Buffer.FirstElement;
|
||||
viewInfo.size = sizeof(uint32_t) * pDesc->Buffer.NumElements;
|
||||
} else if (pDesc->Format == DXGI_FORMAT_UNKNOWN) {
|
||||
viewInfo.format = VK_FORMAT_R32_UINT;
|
||||
viewInfo.rangeOffset = buffer->Desc()->StructureByteStride * pDesc->Buffer.FirstElement;
|
||||
viewInfo.rangeLength = buffer->Desc()->StructureByteStride * pDesc->Buffer.NumElements;
|
||||
viewInfo.format = VK_FORMAT_R32_UINT;
|
||||
viewInfo.offset = buffer->Desc()->StructureByteStride * pDesc->Buffer.FirstElement;
|
||||
viewInfo.size = buffer->Desc()->StructureByteStride * pDesc->Buffer.NumElements;
|
||||
} else {
|
||||
viewInfo.format = pDevice->LookupFormat(pDesc->Format, DXGI_VK_FORMAT_MODE_COLOR).Format;
|
||||
|
||||
const DxvkFormatInfo* formatInfo = lookupFormatInfo(viewInfo.format);
|
||||
viewInfo.rangeOffset = formatInfo->elementSize * pDesc->Buffer.FirstElement;
|
||||
viewInfo.rangeLength = formatInfo->elementSize * pDesc->Buffer.NumElements;
|
||||
viewInfo.offset = formatInfo->elementSize * pDesc->Buffer.FirstElement;
|
||||
viewInfo.size = formatInfo->elementSize * pDesc->Buffer.NumElements;
|
||||
}
|
||||
|
||||
if (pDesc->Buffer.Flags & (D3D11_BUFFER_UAV_FLAG_APPEND | D3D11_BUFFER_UAV_FLAG_COUNTER))
|
||||
m_counterView = CreateCounterBufferView();
|
||||
|
||||
// Populate view info struct
|
||||
m_info.Buffer.Offset = viewInfo.rangeOffset;
|
||||
m_info.Buffer.Length = viewInfo.rangeLength;
|
||||
m_info.Buffer.Offset = viewInfo.offset;
|
||||
m_info.Buffer.Length = viewInfo.size;
|
||||
|
||||
m_bufferView = pDevice->GetDXVKDevice()->createBufferView(
|
||||
buffer->GetBuffer(), viewInfo);
|
||||
m_bufferView = buffer->GetBuffer()->createView(viewInfo);
|
||||
} else {
|
||||
auto texture = GetCommonTexture(pResource);
|
||||
auto formatInfo = pDevice->LookupFormat(pDesc->Format, texture->GetFormatMode());
|
||||
|
||||
DxvkImageViewCreateInfo viewInfo;
|
||||
viewInfo.format = formatInfo.Format;
|
||||
viewInfo.aspect = formatInfo.Aspect;
|
||||
viewInfo.usage = VK_IMAGE_USAGE_STORAGE_BIT;
|
||||
DxvkImageViewKey viewInfo;
|
||||
viewInfo.format = formatInfo.Format;
|
||||
viewInfo.aspects = formatInfo.Aspect;
|
||||
viewInfo.usage = VK_IMAGE_USAGE_STORAGE_BIT;
|
||||
|
||||
if (!util::isIdentityMapping(formatInfo.Swizzle))
|
||||
Logger::warn(str::format("UAV format ", pDesc->Format, " has non-identity swizzle, but UAV swizzles are not supported"));
|
||||
|
||||
switch (pDesc->ViewDimension) {
|
||||
case D3D11_UAV_DIMENSION_TEXTURE1D:
|
||||
viewInfo.type = VK_IMAGE_VIEW_TYPE_1D;
|
||||
viewInfo.minLevel = pDesc->Texture1D.MipSlice;
|
||||
viewInfo.numLevels = 1;
|
||||
viewInfo.minLayer = 0;
|
||||
viewInfo.numLayers = 1;
|
||||
viewInfo.viewType = VK_IMAGE_VIEW_TYPE_1D;
|
||||
viewInfo.mipIndex = pDesc->Texture1D.MipSlice;
|
||||
viewInfo.mipCount = 1;
|
||||
viewInfo.layerIndex = 0;
|
||||
viewInfo.layerCount = 1;
|
||||
break;
|
||||
|
||||
case D3D11_UAV_DIMENSION_TEXTURE1DARRAY:
|
||||
viewInfo.type = VK_IMAGE_VIEW_TYPE_1D_ARRAY;
|
||||
viewInfo.minLevel = pDesc->Texture1DArray.MipSlice;
|
||||
viewInfo.numLevels = 1;
|
||||
viewInfo.minLayer = pDesc->Texture1DArray.FirstArraySlice;
|
||||
viewInfo.numLayers = pDesc->Texture1DArray.ArraySize;
|
||||
viewInfo.viewType = VK_IMAGE_VIEW_TYPE_1D_ARRAY;
|
||||
viewInfo.mipIndex = pDesc->Texture1DArray.MipSlice;
|
||||
viewInfo.mipCount = 1;
|
||||
viewInfo.layerIndex = pDesc->Texture1DArray.FirstArraySlice;
|
||||
viewInfo.layerCount = pDesc->Texture1DArray.ArraySize;
|
||||
break;
|
||||
|
||||
case D3D11_UAV_DIMENSION_TEXTURE2D:
|
||||
viewInfo.type = VK_IMAGE_VIEW_TYPE_2D;
|
||||
viewInfo.minLevel = pDesc->Texture2D.MipSlice;
|
||||
viewInfo.numLevels = 1;
|
||||
viewInfo.minLayer = 0;
|
||||
viewInfo.numLayers = 1;
|
||||
viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
|
||||
viewInfo.mipIndex = pDesc->Texture2D.MipSlice;
|
||||
viewInfo.mipCount = 1;
|
||||
viewInfo.layerIndex = 0;
|
||||
viewInfo.layerCount = 1;
|
||||
break;
|
||||
|
||||
case D3D11_UAV_DIMENSION_TEXTURE2DARRAY:
|
||||
viewInfo.type = VK_IMAGE_VIEW_TYPE_2D_ARRAY;
|
||||
viewInfo.minLevel = pDesc->Texture2DArray.MipSlice;
|
||||
viewInfo.numLevels = 1;
|
||||
viewInfo.minLayer = pDesc->Texture2DArray.FirstArraySlice;
|
||||
viewInfo.numLayers = pDesc->Texture2DArray.ArraySize;
|
||||
viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D_ARRAY;
|
||||
viewInfo.mipIndex = pDesc->Texture2DArray.MipSlice;
|
||||
viewInfo.mipCount = 1;
|
||||
viewInfo.layerIndex = pDesc->Texture2DArray.FirstArraySlice;
|
||||
viewInfo.layerCount = pDesc->Texture2DArray.ArraySize;
|
||||
break;
|
||||
|
||||
case D3D11_UAV_DIMENSION_TEXTURE3D:
|
||||
// FIXME we actually have to map this to a
|
||||
// 2D array view in order to support W slices
|
||||
viewInfo.type = VK_IMAGE_VIEW_TYPE_3D;
|
||||
viewInfo.minLevel = pDesc->Texture3D.MipSlice;
|
||||
viewInfo.numLevels = 1;
|
||||
viewInfo.minLayer = 0;
|
||||
viewInfo.numLayers = 1;
|
||||
viewInfo.viewType = VK_IMAGE_VIEW_TYPE_3D;
|
||||
viewInfo.mipIndex = pDesc->Texture3D.MipSlice;
|
||||
viewInfo.mipCount = 1;
|
||||
viewInfo.layerIndex = 0;
|
||||
viewInfo.layerCount = 1;
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -112,23 +112,27 @@ namespace dxvk {
|
|||
}
|
||||
|
||||
if (texture->GetPlaneCount() > 1)
|
||||
viewInfo.aspect = vk::getPlaneAspect(GetPlaneSlice(pDesc));
|
||||
viewInfo.aspects = vk::getPlaneAspect(GetPlaneSlice(pDesc));
|
||||
|
||||
// Populate view info struct
|
||||
m_info.Image.Aspects = viewInfo.aspect;
|
||||
m_info.Image.MinLevel = viewInfo.minLevel;
|
||||
m_info.Image.MinLayer = viewInfo.minLayer;
|
||||
m_info.Image.NumLevels = viewInfo.numLevels;
|
||||
m_info.Image.NumLayers = viewInfo.numLayers;
|
||||
m_info.Image.Aspects = viewInfo.aspects;
|
||||
m_info.Image.MinLevel = viewInfo.mipIndex;
|
||||
m_info.Image.MinLayer = viewInfo.layerIndex;
|
||||
m_info.Image.NumLevels = viewInfo.mipCount;
|
||||
m_info.Image.NumLayers = viewInfo.layerCount;
|
||||
|
||||
m_imageView = pDevice->GetDXVKDevice()->createImageView(
|
||||
GetCommonTexture(pResource)->GetImage(), viewInfo);
|
||||
m_imageView = GetCommonTexture(pResource)->GetImage()->createView(viewInfo);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
D3D11UnorderedAccessView::~D3D11UnorderedAccessView() {
|
||||
ResourceReleasePrivate(m_resource);
|
||||
m_resource = nullptr;
|
||||
|
||||
m_bufferView = nullptr;
|
||||
m_counterView = nullptr;
|
||||
m_imageView = nullptr;
|
||||
}
|
||||
|
||||
|
||||
|
@ -214,7 +218,7 @@ namespace dxvk {
|
|||
D3D11_BUFFER_DESC bufferDesc;
|
||||
static_cast<D3D11Buffer*>(pResource)->GetDesc(&bufferDesc);
|
||||
|
||||
if (bufferDesc.MiscFlags == D3D11_RESOURCE_MISC_BUFFER_STRUCTURED) {
|
||||
if (bufferDesc.MiscFlags & D3D11_RESOURCE_MISC_BUFFER_STRUCTURED) {
|
||||
pDesc->Format = DXGI_FORMAT_UNKNOWN;
|
||||
pDesc->ViewDimension = D3D11_UAV_DIMENSION_BUFFER;
|
||||
pDesc->Buffer.FirstElement = 0;
|
||||
|
@ -446,15 +450,17 @@ namespace dxvk {
|
|||
| VK_ACCESS_TRANSFER_READ_BIT
|
||||
| VK_ACCESS_SHADER_WRITE_BIT
|
||||
| VK_ACCESS_SHADER_READ_BIT;
|
||||
info.debugName = "UAV counter";
|
||||
|
||||
Rc<DxvkBuffer> buffer = device->createBuffer(info, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
|
||||
|
||||
DxvkBufferViewCreateInfo viewInfo;
|
||||
DxvkBufferViewKey viewInfo;
|
||||
viewInfo.format = VK_FORMAT_UNDEFINED;
|
||||
viewInfo.rangeOffset = 0;
|
||||
viewInfo.rangeLength = sizeof(uint32_t);
|
||||
viewInfo.offset = 0;
|
||||
viewInfo.size = sizeof(uint32_t);
|
||||
viewInfo.usage = VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT;
|
||||
|
||||
return device->createBufferView(buffer, viewInfo);
|
||||
return buffer->createView(viewInfo);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -43,6 +43,10 @@ namespace dxvk {
|
|||
return m_info.BindFlags & Flags;
|
||||
}
|
||||
|
||||
BOOL HasCounter() const {
|
||||
return m_counterView != nullptr;
|
||||
}
|
||||
|
||||
D3D11_RESOURCE_DIMENSION GetResourceType() const {
|
||||
D3D11_RESOURCE_DIMENSION type;
|
||||
m_resource->GetType(&type);
|
||||
|
|
|
@ -77,18 +77,25 @@ else
|
|||
d3d11_dxgi_dep = dxgi_dep
|
||||
endif
|
||||
|
||||
d3d11_dll = shared_library('d3d11'+dll_ext, dxgi_common_src + d3d11_src + d3d10_src,
|
||||
d3d11_dll = shared_library(dxvk_name_prefix+'d3d11', dxgi_common_src + d3d11_src + d3d10_src,
|
||||
glsl_generator.process(d3d11_shaders), d3d11_res,
|
||||
name_prefix : dxvk_name_prefix,
|
||||
dependencies : [ d3d11_dxgi_dep, dxbc_dep, dxvk_dep ],
|
||||
include_directories : dxvk_include_path,
|
||||
install : true,
|
||||
vs_module_defs : 'd3d11'+def_spec_ext,
|
||||
link_args : d3d11_ld_args,
|
||||
link_depends : [ d3d11_link_depends ],
|
||||
kwargs : dxvk_so_version,
|
||||
)
|
||||
|
||||
d3d11_dep = declare_dependency(
|
||||
link_with : [ d3d11_dll ],
|
||||
include_directories : [ dxvk_include_path ],
|
||||
)
|
||||
|
||||
if platform != 'windows'
|
||||
pkg.generate(d3d11_dll,
|
||||
filebase: dxvk_pkg_prefix + 'd3d11',
|
||||
subdirs: 'dxvk',
|
||||
)
|
||||
endif
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
#version 450
|
||||
|
||||
#extension GL_EXT_samplerless_texture_functions : require
|
||||
|
||||
// Can't use matrix types here since even a two-row
|
||||
// matrix will be padded to 16 bytes per column for
|
||||
// absolutely no reason
|
||||
|
@ -11,6 +13,8 @@ uniform ubo_t {
|
|||
vec2 coord_matrix_c1;
|
||||
vec2 coord_matrix_c2;
|
||||
vec2 coord_matrix_c3;
|
||||
uvec2 src_offset;
|
||||
uvec2 src_extent;
|
||||
float y_min;
|
||||
float y_max;
|
||||
bool is_planar;
|
||||
|
@ -19,9 +23,8 @@ uniform ubo_t {
|
|||
layout(location = 0) in vec2 i_texcoord;
|
||||
layout(location = 0) out vec4 o_color;
|
||||
|
||||
layout(set = 0, binding = 1) uniform sampler s_sampler;
|
||||
layout(set = 0, binding = 2) uniform texture2D s_inputY;
|
||||
layout(set = 0, binding = 3) uniform texture2D s_inputCbCr;
|
||||
layout(set = 0, binding = 1) uniform texture2D s_inputY;
|
||||
layout(set = 0, binding = 2) uniform texture2D s_inputCbCr;
|
||||
|
||||
void main() {
|
||||
// Transform input texture coordinates to
|
||||
|
@ -31,25 +34,61 @@ void main() {
|
|||
coord_matrix_c2,
|
||||
coord_matrix_c3);
|
||||
|
||||
vec2 coord = coord_matrix * vec3(i_texcoord, 1.0f);
|
||||
|
||||
// Fetch source image color
|
||||
vec4 color = vec4(0.0f, 0.0f, 0.0f, 1.0f);
|
||||
|
||||
if (is_planar) {
|
||||
color.g = texture(sampler2D(s_inputY, s_sampler), coord).r;
|
||||
color.rb = texture(sampler2D(s_inputCbCr, s_sampler), coord).gr;
|
||||
color.g = clamp((color.g - y_min) / (y_max - y_min), 0.0f, 1.0f);
|
||||
} else {
|
||||
color = texture(sampler2D(s_inputY, s_sampler), coord);
|
||||
}
|
||||
|
||||
// Color space transformation
|
||||
// Load color space transform
|
||||
mat3x4 color_matrix = mat3x4(
|
||||
color_matrix_r1,
|
||||
color_matrix_r2,
|
||||
color_matrix_r3);
|
||||
|
||||
o_color.rgb = vec4(color.rgb, 1.0f) * color_matrix;
|
||||
o_color.a = color.a;
|
||||
// Compute actual pixel coordinates to sample. We filter
|
||||
// manually in order to avoid bleeding from pixels outside
|
||||
// the source rectangle.
|
||||
vec2 abs_size_y = vec2(textureSize(s_inputY, 0));
|
||||
vec2 abs_size_c = vec2(textureSize(s_inputCbCr, 0));
|
||||
|
||||
vec2 coord = coord_matrix * vec3(i_texcoord, 1.0f);
|
||||
coord -= 0.5f / abs_size_y;
|
||||
|
||||
vec2 size_factor = abs_size_c / abs_size_y;
|
||||
|
||||
vec2 src_lo = vec2(src_offset);
|
||||
vec2 src_hi = vec2(src_offset + src_extent - 1u);
|
||||
|
||||
vec2 abs_coord = coord * abs_size_y;
|
||||
vec2 fract_coord = fract(clamp(abs_coord, src_lo, src_hi));
|
||||
|
||||
vec4 accum = vec4(0.0f, 0.0f, 0.0f, 0.0f);
|
||||
|
||||
for (int i = 0; i < 4; i++) {
|
||||
ivec2 offset = ivec2(i & 1, i >> 1);
|
||||
|
||||
// Compute exact pixel coordinates for the current
|
||||
// iteration and clamp it to the source rectangle.
|
||||
vec2 fetch_coord = clamp(abs_coord + vec2(offset), src_lo, src_hi);
|
||||
|
||||
// Fetch actual pixel color in source color space
|
||||
vec4 color;
|
||||
|
||||
if (is_planar) {
|
||||
color.g = texelFetch(s_inputY, ivec2(fetch_coord), 0).r;
|
||||
color.rb = texelFetch(s_inputCbCr, ivec2(fetch_coord * size_factor), 0).gr;
|
||||
color.g = clamp((color.g - y_min) / (y_max - y_min), 0.0f, 1.0f);
|
||||
color.a = 1.0f;
|
||||
} else {
|
||||
color = texelFetch(s_inputY, ivec2(fetch_coord), 0);
|
||||
}
|
||||
|
||||
// Transform color space before accumulation
|
||||
color.rgb = vec4(color.rgb, 1.0f) * color_matrix;
|
||||
|
||||
// Filter and accumulate final pixel color
|
||||
vec2 factor = fract_coord;
|
||||
|
||||
if (offset.x == 0) factor.x = 1.0f - factor.x;
|
||||
if (offset.y == 0) factor.y = 1.0f - factor.y;
|
||||
|
||||
accum += factor.x * factor.y * color;
|
||||
}
|
||||
|
||||
o_color = accum;
|
||||
}
|
||||
|
|
6
src/d3d8/d3d8.def
Normal file
6
src/d3d8/d3d8.def
Normal file
|
@ -0,0 +1,6 @@
|
|||
LIBRARY D3D8.DLL
|
||||
EXPORTS
|
||||
ValidatePixelShader @ 2
|
||||
ValidateVertexShader @ 3
|
||||
DebugSetMute @ 4
|
||||
Direct3DCreate8 @ 5
|
10
src/d3d8/d3d8.sym
Normal file
10
src/d3d8/d3d8.sym
Normal file
|
@ -0,0 +1,10 @@
|
|||
{
|
||||
global:
|
||||
ValidatePixelShader;
|
||||
ValidateVertexShader;
|
||||
DebugSetMute;
|
||||
Direct3DCreate8;
|
||||
|
||||
local:
|
||||
*;
|
||||
};
|
250
src/d3d8/d3d8_batch.h
Normal file
250
src/d3d8/d3d8_batch.h
Normal file
|
@ -0,0 +1,250 @@
|
|||
#pragma once
|
||||
|
||||
#include "d3d8_include.h"
|
||||
#include "d3d8_buffer.h"
|
||||
#include "d3d8_format.h"
|
||||
|
||||
#include <vector>
|
||||
#include <cstdint>
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
inline constexpr size_t D3DPT_COUNT = size_t(D3DPT_TRIANGLEFAN) + 1;
|
||||
inline constexpr D3DPRIMITIVETYPE D3DPT_INVALID = D3DPRIMITIVETYPE(0);
|
||||
|
||||
// Vertex buffer that can handle many tiny locks while
|
||||
// still maintaing the lock ordering of direct-mapped buffers.
|
||||
class D3D8BatchBuffer final : public D3D8VertexBuffer {
|
||||
|
||||
public:
|
||||
|
||||
D3D8BatchBuffer(
|
||||
D3D8Device* pDevice,
|
||||
D3DPOOL Pool,
|
||||
DWORD Usage,
|
||||
UINT Length,
|
||||
DWORD FVF)
|
||||
: D3D8VertexBuffer(pDevice, nullptr, Pool, Usage)
|
||||
, m_data(Length)
|
||||
, m_fvf(FVF) {
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE Lock(
|
||||
UINT OffsetToLock,
|
||||
UINT SizeToLock,
|
||||
BYTE** ppbData,
|
||||
DWORD Flags) {
|
||||
*ppbData = m_data.data() + OffsetToLock;
|
||||
return D3D_OK;
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE Unlock() {
|
||||
return D3D_OK;
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE GetDesc(D3DVERTEXBUFFER_DESC* pDesc) {
|
||||
if (unlikely(pDesc == nullptr))
|
||||
return D3DERR_INVALIDCALL;
|
||||
|
||||
pDesc->Format = D3DFMT_VERTEXDATA;
|
||||
pDesc->Type = D3DRTYPE_VERTEXBUFFER;
|
||||
pDesc->Usage = m_usage;
|
||||
pDesc->Pool = m_pool;
|
||||
pDesc->Size = m_data.size();
|
||||
pDesc->FVF = m_fvf;
|
||||
|
||||
return D3D_OK;
|
||||
}
|
||||
|
||||
void STDMETHODCALLTYPE PreLoad() {
|
||||
}
|
||||
|
||||
const void* GetPtr(UINT byteOffset = 0) const {
|
||||
return m_data.data() + byteOffset;
|
||||
}
|
||||
|
||||
UINT Size() const {
|
||||
return m_data.size();
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
std::vector<BYTE> m_data;
|
||||
DWORD m_fvf;
|
||||
|
||||
};
|
||||
|
||||
|
||||
// Main handler for batching D3D8 draw calls.
|
||||
class D3D8Batcher {
|
||||
|
||||
struct Batch {
|
||||
D3DPRIMITIVETYPE PrimitiveType = D3DPT_INVALID;
|
||||
std::vector<uint16_t> Indices;
|
||||
UINT Offset = 0;
|
||||
UINT MinVertex = std::numeric_limits<uint32_t>::max();
|
||||
UINT MaxVertex = 0;
|
||||
UINT PrimitiveCount = 0;
|
||||
UINT DrawCallCount = 0;
|
||||
};
|
||||
|
||||
public:
|
||||
|
||||
D3D8Batcher(D3D8Device* pDevice8, Com<d3d9::IDirect3DDevice9>&& pDevice9)
|
||||
: m_device8(pDevice8)
|
||||
, m_device(std::move(pDevice9)) {
|
||||
}
|
||||
|
||||
inline D3D8BatchBuffer* CreateVertexBuffer(UINT Length, DWORD Usage, DWORD FVF, D3DPOOL Pool) {
|
||||
return ref(new D3D8BatchBuffer(m_device8, Pool, Usage, Length, FVF));
|
||||
}
|
||||
|
||||
inline void StateChange() {
|
||||
if (likely(m_batches.empty()))
|
||||
return;
|
||||
for (auto& draw : m_batches) {
|
||||
|
||||
if (draw.PrimitiveType == D3DPT_INVALID)
|
||||
continue;
|
||||
|
||||
for (auto& index : draw.Indices)
|
||||
index -= draw.MinVertex;
|
||||
|
||||
m_device->DrawIndexedPrimitiveUP(
|
||||
d3d9::D3DPRIMITIVETYPE(draw.PrimitiveType),
|
||||
0,
|
||||
draw.MaxVertex - draw.MinVertex,
|
||||
draw.PrimitiveCount,
|
||||
draw.Indices.data(),
|
||||
d3d9::D3DFMT_INDEX16,
|
||||
m_stream->GetPtr(draw.MinVertex * m_stride),
|
||||
m_stride);
|
||||
|
||||
m_device->SetStreamSource(0, D3D8VertexBuffer::GetD3D9Nullable(m_stream), 0, m_stride);
|
||||
m_device->SetIndices(D3D8IndexBuffer::GetD3D9Nullable(m_indices));
|
||||
|
||||
draw.PrimitiveType = D3DPRIMITIVETYPE(0);
|
||||
draw.Offset = 0;
|
||||
draw.MinVertex = std::numeric_limits<uint32_t>::max();
|
||||
draw.MaxVertex = 0;
|
||||
draw.PrimitiveCount = 0;
|
||||
draw.DrawCallCount = 0;
|
||||
}
|
||||
}
|
||||
|
||||
inline void EndFrame() {
|
||||
// Nothing to be done.
|
||||
}
|
||||
|
||||
inline HRESULT DrawPrimitive(
|
||||
D3DPRIMITIVETYPE PrimitiveType,
|
||||
UINT StartVertex,
|
||||
UINT PrimitiveCount) {
|
||||
|
||||
// None of this linestrip or fan malarkey
|
||||
D3DPRIMITIVETYPE batchedPrimType = PrimitiveType;
|
||||
switch (PrimitiveType) {
|
||||
case D3DPT_LINESTRIP: batchedPrimType = D3DPT_LINELIST; break;
|
||||
case D3DPT_TRIANGLEFAN: batchedPrimType = D3DPT_TRIANGLELIST; break;
|
||||
default: break;
|
||||
}
|
||||
|
||||
Batch* batch = &m_batches[size_t(batchedPrimType)];
|
||||
batch->PrimitiveType = batchedPrimType;
|
||||
|
||||
//UINT vertices = GetVertexCount8(PrimitiveType, PrimitiveCount);
|
||||
|
||||
switch (PrimitiveType) {
|
||||
case D3DPT_POINTLIST:
|
||||
batch->Indices.resize(batch->Offset + PrimitiveCount);
|
||||
for (UINT i = 0; i < PrimitiveCount; i++)
|
||||
batch->Indices[batch->Offset++] = (StartVertex + i);
|
||||
break;
|
||||
case D3DPT_LINELIST:
|
||||
batch->Indices.resize(batch->Offset + PrimitiveCount * 2);
|
||||
for (UINT i = 0; i < PrimitiveCount; i++) {
|
||||
batch->Indices[batch->Offset++] = (StartVertex + i * 2 + 0);
|
||||
batch->Indices[batch->Offset++] = (StartVertex + i * 2 + 1);
|
||||
}
|
||||
break;
|
||||
case D3DPT_LINESTRIP:
|
||||
batch->Indices.resize(batch->Offset + PrimitiveCount * 2);
|
||||
for (UINT i = 0; i < PrimitiveCount; i++) {
|
||||
batch->Indices[batch->Offset++] = (StartVertex + i + 0);
|
||||
batch->Indices[batch->Offset++] = (StartVertex + i + 1);
|
||||
}
|
||||
break;
|
||||
case D3DPT_TRIANGLELIST:
|
||||
batch->Indices.resize(batch->Offset + PrimitiveCount * 3);
|
||||
for (UINT i = 0; i < PrimitiveCount; i++) {
|
||||
batch->Indices[batch->Offset++] = (StartVertex + i * 3 + 0);
|
||||
batch->Indices[batch->Offset++] = (StartVertex + i * 3 + 1);
|
||||
batch->Indices[batch->Offset++] = (StartVertex + i * 3 + 2);
|
||||
}
|
||||
break;
|
||||
case D3DPT_TRIANGLESTRIP:
|
||||
// Join with degenerate triangle
|
||||
// 1 2 3, 3 4, 4 5 6
|
||||
batch->Indices.resize(batch->Offset + PrimitiveCount + 2);
|
||||
if (batch->Offset > 0) {
|
||||
batch->Indices[batch->Offset + 1] = batch->Indices[batch->Offset-2];
|
||||
batch->Indices[batch->Offset += 2] = StartVertex;
|
||||
}
|
||||
for (UINT i = 0; i < PrimitiveCount; i++) {
|
||||
batch->Indices[batch->Offset++] = (StartVertex + i + 0);
|
||||
}
|
||||
break;
|
||||
// 1 2 3 4 5 6 7 -> 1 2 3, 1 3 4, 1 4 5, 1 5 6, 1 6 7
|
||||
case D3DPT_TRIANGLEFAN:
|
||||
batch->Indices.resize(batch->Offset + PrimitiveCount * 3);
|
||||
for (UINT i = 0; i < PrimitiveCount; i++) {
|
||||
batch->Indices[batch->Offset++] = (StartVertex + 0);
|
||||
batch->Indices[batch->Offset++] = (StartVertex + i + 1);
|
||||
batch->Indices[batch->Offset++] = (StartVertex + i + 2);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return D3DERR_INVALIDCALL;
|
||||
}
|
||||
batch->MinVertex = std::min(batch->MinVertex, StartVertex);
|
||||
if (!batch->Indices.empty())
|
||||
batch->MaxVertex = std::max(batch->MaxVertex, UINT(batch->Indices.back() + 1));
|
||||
batch->PrimitiveCount += PrimitiveCount;
|
||||
batch->DrawCallCount++;
|
||||
return D3D_OK;
|
||||
}
|
||||
|
||||
inline void SetStream(UINT num, D3D8VertexBuffer* stream, UINT stride) {
|
||||
if (unlikely(num != 0)) {
|
||||
StateChange();
|
||||
return;
|
||||
}
|
||||
if (unlikely(m_stream != stream || m_stride != stride)) {
|
||||
StateChange();
|
||||
m_stream = static_cast<D3D8BatchBuffer*>(stream);
|
||||
m_stride = stride;
|
||||
}
|
||||
}
|
||||
|
||||
inline void SetIndices(D3D8IndexBuffer* indices, INT baseVertexIndex) {
|
||||
if (m_indices != indices || m_baseVertexIndex != baseVertexIndex) {
|
||||
StateChange();
|
||||
m_indices = indices;
|
||||
m_baseVertexIndex = baseVertexIndex;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
D3D8Device* m_device8;
|
||||
Com<d3d9::IDirect3DDevice9> m_device;
|
||||
|
||||
D3D8BatchBuffer* m_stream = nullptr;
|
||||
UINT m_stride = 0;
|
||||
D3D8IndexBuffer* m_indices = nullptr;
|
||||
INT m_baseVertexIndex = 0;
|
||||
std::array<Batch, D3DPT_COUNT> m_batches;
|
||||
|
||||
};
|
||||
|
||||
}
|
38
src/d3d8/d3d8_buffer.cpp
Normal file
38
src/d3d8/d3d8_buffer.cpp
Normal file
|
@ -0,0 +1,38 @@
|
|||
#include "d3d8_buffer.h"
|
||||
#include "d3d8_device.h"
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
// D3D8VertexBuffer
|
||||
|
||||
D3D8VertexBuffer::D3D8VertexBuffer(
|
||||
D3D8Device* pDevice,
|
||||
Com<d3d9::IDirect3DVertexBuffer9>&& pBuffer,
|
||||
D3DPOOL Pool,
|
||||
DWORD Usage)
|
||||
: D3D8VertexBufferBase(pDevice, std::move(pBuffer), Pool, Usage) {
|
||||
}
|
||||
|
||||
D3DRESOURCETYPE STDMETHODCALLTYPE D3D8VertexBuffer::GetType() { return D3DRTYPE_VERTEXBUFFER; }
|
||||
|
||||
HRESULT STDMETHODCALLTYPE D3D8VertexBuffer::GetDesc(D3DVERTEXBUFFER_DESC* pDesc) {
|
||||
return GetD3D9()->GetDesc(reinterpret_cast<d3d9::D3DVERTEXBUFFER_DESC*>(pDesc));
|
||||
}
|
||||
|
||||
// D3D8IndexBuffer
|
||||
|
||||
D3D8IndexBuffer::D3D8IndexBuffer(
|
||||
D3D8Device* pDevice,
|
||||
Com<d3d9::IDirect3DIndexBuffer9>&& pBuffer,
|
||||
D3DPOOL Pool,
|
||||
DWORD Usage)
|
||||
: D3D8IndexBufferBase(pDevice, std::move(pBuffer), Pool, Usage) {
|
||||
}
|
||||
|
||||
D3DRESOURCETYPE STDMETHODCALLTYPE D3D8IndexBuffer::GetType() { return D3DRTYPE_INDEXBUFFER; }
|
||||
|
||||
HRESULT STDMETHODCALLTYPE D3D8IndexBuffer::GetDesc(D3DINDEXBUFFER_DESC* pDesc) {
|
||||
return GetD3D9()->GetDesc(reinterpret_cast<d3d9::D3DINDEXBUFFER_DESC*>(pDesc));
|
||||
}
|
||||
|
||||
}
|
93
src/d3d8/d3d8_buffer.h
Normal file
93
src/d3d8/d3d8_buffer.h
Normal file
|
@ -0,0 +1,93 @@
|
|||
#pragma once
|
||||
|
||||
#include "d3d8_include.h"
|
||||
#include "d3d8_options.h"
|
||||
#include "d3d8_resource.h"
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
template <typename D3D9, typename D3D8>
|
||||
class D3D8Buffer : public D3D8Resource<D3D9, D3D8> {
|
||||
|
||||
public:
|
||||
|
||||
D3D8Buffer(
|
||||
D3D8Device* pDevice,
|
||||
Com<D3D9>&& pBuffer,
|
||||
D3DPOOL Pool,
|
||||
DWORD Usage)
|
||||
: D3D8Resource<D3D9, D3D8> (pDevice, Pool, std::move(pBuffer))
|
||||
, m_usage (Usage) {
|
||||
m_options = this->GetParent()->GetOptions();
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE Lock(
|
||||
UINT OffsetToLock,
|
||||
UINT SizeToLock,
|
||||
BYTE** ppbData,
|
||||
DWORD Flags) {
|
||||
|
||||
if (m_options->forceLegacyDiscard &&
|
||||
(Flags & D3DLOCK_DISCARD) &&
|
||||
!((m_usage & D3DUSAGE_DYNAMIC) &&
|
||||
(m_usage & D3DUSAGE_WRITEONLY)))
|
||||
Flags &= ~D3DLOCK_DISCARD;
|
||||
|
||||
return this->GetD3D9()->Lock(
|
||||
OffsetToLock,
|
||||
SizeToLock,
|
||||
reinterpret_cast<void**>(ppbData),
|
||||
Flags);
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE Unlock() {
|
||||
return this->GetD3D9()->Unlock();
|
||||
}
|
||||
|
||||
void STDMETHODCALLTYPE PreLoad() {
|
||||
this->GetD3D9()->PreLoad();
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
const D3D8Options* m_options;
|
||||
const DWORD m_usage;
|
||||
|
||||
};
|
||||
|
||||
|
||||
using D3D8VertexBufferBase = D3D8Buffer<d3d9::IDirect3DVertexBuffer9, IDirect3DVertexBuffer8>;
|
||||
class D3D8VertexBuffer : public D3D8VertexBufferBase {
|
||||
|
||||
public:
|
||||
|
||||
D3D8VertexBuffer(
|
||||
D3D8Device* pDevice,
|
||||
Com<d3d9::IDirect3DVertexBuffer9>&& pBuffer,
|
||||
D3DPOOL Pool,
|
||||
DWORD Usage);
|
||||
|
||||
D3DRESOURCETYPE STDMETHODCALLTYPE GetType() final;
|
||||
|
||||
HRESULT STDMETHODCALLTYPE GetDesc(D3DVERTEXBUFFER_DESC* pDesc);
|
||||
|
||||
};
|
||||
|
||||
using D3D8IndexBufferBase = D3D8Buffer<d3d9::IDirect3DIndexBuffer9, IDirect3DIndexBuffer8>;
|
||||
class D3D8IndexBuffer final : public D3D8IndexBufferBase {
|
||||
|
||||
public:
|
||||
|
||||
D3D8IndexBuffer(
|
||||
D3D8Device* pDevice,
|
||||
Com<d3d9::IDirect3DIndexBuffer9>&& pBuffer,
|
||||
D3DPOOL Pool,
|
||||
DWORD Usage);
|
||||
|
||||
D3DRESOURCETYPE STDMETHODCALLTYPE GetType() final;
|
||||
|
||||
HRESULT STDMETHODCALLTYPE GetDesc(D3DINDEXBUFFER_DESC* pDesc) final;
|
||||
|
||||
};
|
||||
|
||||
}
|
8
src/d3d8/d3d8_caps.h
Normal file
8
src/d3d8/d3d8_caps.h
Normal file
|
@ -0,0 +1,8 @@
|
|||
#pragma once
|
||||
|
||||
namespace dxvk::d8caps {
|
||||
|
||||
inline constexpr uint32_t MAX_TEXTURE_STAGES = 8;
|
||||
inline constexpr uint32_t MAX_STREAMS = 16;
|
||||
|
||||
}
|
194
src/d3d8/d3d8_d3d9_util.h
Normal file
194
src/d3d8/d3d8_d3d9_util.h
Normal file
|
@ -0,0 +1,194 @@
|
|||
#pragma once
|
||||
|
||||
// Utility functions for converting
|
||||
// between DirectX8 and DirectX9 types.
|
||||
|
||||
#include "d3d8_include.h"
|
||||
#include "d3d8_format.h"
|
||||
#include "d3d8_options.h"
|
||||
|
||||
#include <utility>
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
// (8<-9) D3DCAPSX: Writes to D3DCAPS8 from D3DCAPS9
|
||||
inline void ConvertCaps8(const d3d9::D3DCAPS9& caps9, D3DCAPS8* pCaps8) {
|
||||
|
||||
// should be aligned
|
||||
std::memcpy(pCaps8, &caps9, sizeof(D3DCAPS8));
|
||||
|
||||
// Max supported shader model is PS 1.4 and VS 1.1
|
||||
pCaps8->VertexShaderVersion = D3DVS_VERSION(1, 1);
|
||||
// Late fixed-function capable hardware will advertise VS 1.1
|
||||
// support, but will not advertise any support for PS
|
||||
if (likely(caps9.PixelShaderVersion != D3DPS_VERSION(0, 0)))
|
||||
pCaps8->PixelShaderVersion = D3DPS_VERSION(1, 4);
|
||||
|
||||
// Remove D3D9-specific caps:
|
||||
|
||||
pCaps8->Caps2 &= ~D3DCAPS2_CANAUTOGENMIPMAP;
|
||||
|
||||
pCaps8->Caps3 &= ~D3DCAPS3_LINEAR_TO_SRGB_PRESENTATION
|
||||
& ~D3DCAPS3_COPY_TO_VIDMEM
|
||||
& ~D3DCAPS3_COPY_TO_SYSTEMMEM;
|
||||
|
||||
pCaps8->PrimitiveMiscCaps &= ~D3DPMISCCAPS_INDEPENDENTWRITEMASKS
|
||||
& ~D3DPMISCCAPS_PERSTAGECONSTANT
|
||||
& ~D3DPMISCCAPS_FOGANDSPECULARALPHA
|
||||
& ~D3DPMISCCAPS_SEPARATEALPHABLEND
|
||||
& ~D3DPMISCCAPS_MRTINDEPENDENTBITDEPTHS
|
||||
& ~D3DPMISCCAPS_MRTPOSTPIXELSHADERBLENDING
|
||||
& ~D3DPMISCCAPS_FOGVERTEXCLAMPED
|
||||
& ~D3DPMISCCAPS_POSTBLENDSRGBCONVERT;
|
||||
|
||||
pCaps8->RasterCaps &= ~D3DPRASTERCAPS_SCISSORTEST
|
||||
& ~D3DPRASTERCAPS_SLOPESCALEDEPTHBIAS
|
||||
& ~D3DPRASTERCAPS_DEPTHBIAS
|
||||
& ~D3DPRASTERCAPS_MULTISAMPLE_TOGGLE;
|
||||
|
||||
pCaps8->SrcBlendCaps &= ~D3DPBLENDCAPS_BLENDFACTOR;
|
||||
|
||||
pCaps8->DestBlendCaps &= ~D3DPBLENDCAPS_BLENDFACTOR;
|
||||
|
||||
pCaps8->LineCaps &= ~D3DLINECAPS_ANTIALIAS;
|
||||
|
||||
pCaps8->StencilCaps &= ~D3DSTENCILCAPS_TWOSIDED;
|
||||
|
||||
pCaps8->VertexProcessingCaps &= ~D3DVTXPCAPS_TEXGEN_SPHEREMAP;
|
||||
|
||||
// Add D3D8-specific caps:
|
||||
|
||||
// Removed in D3D9, since it can always render windowed
|
||||
pCaps8->Caps2 |= D3DCAPS2_CANRENDERWINDOWED
|
||||
// A remnant from a bygone age of ddraw interop most likely
|
||||
/* | D3DCAPS2_NO2DDURING3DSCENE*/;
|
||||
|
||||
// Used in conjunction with D3DPRASTERCAPS_PAT, but generally unadvertised
|
||||
/*pCaps8->PrimitiveMiscCaps |= D3DPMISCCAPS_LINEPATTERNREP;*/
|
||||
|
||||
// Replaced by D3DPRASTERCAPS_DEPTHBIAS in D3D9
|
||||
pCaps8->RasterCaps |= D3DPRASTERCAPS_ZBIAS
|
||||
// Advertised on Nvidia cards by modern drivers, but not on AMD or Intel
|
||||
/* | D3DPRASTERCAPS_ANTIALIASEDGES*/
|
||||
// Advertised on Nvidia cards, but not on AMD or Intel
|
||||
/* | D3DPRASTERCAPS_STRETCHBLTMULTISAMPLE*/
|
||||
// TODO: Implement D3DRS_LINEPATTERN - vkCmdSetLineRasterizationModeEXT
|
||||
/* | D3DPRASTERCAPS_PAT*/;
|
||||
|
||||
// MAG only filter caps, generally unsupported
|
||||
/*pCaps8->TextureFilterCaps |= D3DPTFILTERCAPS_MAGFAFLATCUBIC*/
|
||||
/* | D3DPTFILTERCAPS_MAGFGAUSSIANCUBIC;*/
|
||||
/*pCaps8->CubeTextureFilterCaps = pCaps8->TextureFilterCaps;*/
|
||||
/*pCaps8->VolumeTextureFilterCaps = pCaps8->TextureFilterCaps;*/
|
||||
|
||||
// Not advertised on any modern hardware
|
||||
/*pCaps8->VertexProcessingCaps |= D3DVTXPCAPS_NO_VSDT_UBYTE4;*/
|
||||
}
|
||||
|
||||
// (9<-8) D3DD3DPRESENT_PARAMETERS: Returns D3D9's params given an input for D3D8
|
||||
inline d3d9::D3DPRESENT_PARAMETERS ConvertPresentParameters9(D3DPRESENT_PARAMETERS* pParams) {
|
||||
// A 0 back buffer count needs to be corrected and made visible to the D3D8 application as well
|
||||
pParams->BackBufferCount = std::max(pParams->BackBufferCount, 1u);
|
||||
|
||||
if (pParams->BackBufferFormat == D3DFMT_UNKNOWN)
|
||||
pParams->BackBufferFormat = D3DFMT_X8R8G8B8;
|
||||
|
||||
d3d9::D3DPRESENT_PARAMETERS params;
|
||||
params.BackBufferWidth = pParams->BackBufferWidth;
|
||||
params.BackBufferHeight = pParams->BackBufferHeight;
|
||||
params.BackBufferFormat = d3d9::D3DFORMAT(pParams->BackBufferFormat);
|
||||
params.BackBufferCount = pParams->BackBufferCount;
|
||||
|
||||
params.MultiSampleType = d3d9::D3DMULTISAMPLE_TYPE(pParams->MultiSampleType);
|
||||
// MultiSampleQuality is only used with D3DMULTISAMPLE_NONMASKABLE, which is not available in D3D8
|
||||
params.MultiSampleQuality = 0;
|
||||
|
||||
// If an application passes multiple D3DPRESENT_INTERVAL flags, this will be
|
||||
// validated appropriately by D3D9. Simply copy the values here.
|
||||
UINT PresentationInterval = pParams->FullScreen_PresentationInterval;
|
||||
|
||||
if (pParams->Windowed) {
|
||||
// D3D8: For windowed swap chain, the back buffer is copied to the window immediately.
|
||||
PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
|
||||
}
|
||||
|
||||
D3DSWAPEFFECT SwapEffect = pParams->SwapEffect;
|
||||
|
||||
if (SwapEffect == D3DSWAPEFFECT_COPY_VSYNC) {
|
||||
// D3DSWAPEFFECT_COPY_VSYNC has been removed from D3D9, use D3DSWAPEFFECT_COPY
|
||||
SwapEffect = D3DSWAPEFFECT_COPY;
|
||||
|
||||
// D3D8: In windowed mode, D3DSWAPEFFECT_COPY_VSYNC enables VSYNC.
|
||||
// In fullscreen, D3DPRESENT_INTERVAL_IMMEDIATE is meaningless.
|
||||
if (pParams->Windowed || PresentationInterval == D3DPRESENT_INTERVAL_IMMEDIATE) {
|
||||
PresentationInterval = D3DPRESENT_INTERVAL_ONE;
|
||||
}
|
||||
}
|
||||
|
||||
params.SwapEffect = d3d9::D3DSWAPEFFECT(SwapEffect);
|
||||
params.hDeviceWindow = pParams->hDeviceWindow;
|
||||
params.Windowed = pParams->Windowed;
|
||||
params.EnableAutoDepthStencil = pParams->EnableAutoDepthStencil;
|
||||
params.AutoDepthStencilFormat = d3d9::D3DFORMAT(pParams->AutoDepthStencilFormat);
|
||||
params.Flags = pParams->Flags;
|
||||
|
||||
// D3DPRESENT_RATE_UNLIMITED is unsupported, use D3DPRESENT_RATE_DEFAULT (or 0)
|
||||
if (unlikely(pParams->FullScreen_RefreshRateInHz == D3DPRESENT_RATE_UNLIMITED)) {
|
||||
params.FullScreen_RefreshRateInHz = D3DPRESENT_RATE_DEFAULT;
|
||||
} else {
|
||||
params.FullScreen_RefreshRateInHz = pParams->FullScreen_RefreshRateInHz;
|
||||
}
|
||||
|
||||
// FullScreen_PresentationInterval -> PresentationInterval
|
||||
params.PresentationInterval = PresentationInterval;
|
||||
|
||||
return params;
|
||||
}
|
||||
|
||||
// (8<-9) Convert D3DSURFACE_DESC
|
||||
inline void ConvertSurfaceDesc8(const d3d9::D3DSURFACE_DESC* pSurf9, D3DSURFACE_DESC* pSurf8) {
|
||||
pSurf8->Format = D3DFORMAT(pSurf9->Format);
|
||||
pSurf8->Type = D3DRESOURCETYPE(pSurf9->Type);
|
||||
pSurf8->Usage = pSurf9->Usage;
|
||||
pSurf8->Pool = D3DPOOL(pSurf9->Pool);
|
||||
pSurf8->Size = getSurfaceSize(pSurf8->Format, pSurf9->Width, pSurf9->Height);
|
||||
|
||||
pSurf8->MultiSampleType = D3DMULTISAMPLE_TYPE(pSurf9->MultiSampleType);
|
||||
// DX8: No multisample quality
|
||||
pSurf8->Width = pSurf9->Width;
|
||||
pSurf8->Height = pSurf9->Height;
|
||||
}
|
||||
|
||||
// (8<-9) Convert D3DVOLUME_DESC
|
||||
inline void ConvertVolumeDesc8(const d3d9::D3DVOLUME_DESC* pVol9, D3DVOLUME_DESC* pVol8) {
|
||||
pVol8->Format = D3DFORMAT(pVol9->Format);
|
||||
pVol8->Type = D3DRESOURCETYPE(pVol9->Type);
|
||||
pVol8->Usage = pVol9->Usage;
|
||||
pVol8->Pool = D3DPOOL(pVol9->Pool);
|
||||
pVol8->Size = getSurfaceSize(pVol8->Format, pVol9->Width, pVol9->Height) * pVol9->Depth;
|
||||
pVol8->Width = pVol9->Width;
|
||||
pVol8->Height = pVol9->Height;
|
||||
pVol8->Depth = pVol9->Depth;
|
||||
}
|
||||
|
||||
// If this D3DTEXTURESTAGESTATETYPE has been remapped to a d3d9::D3DSAMPLERSTATETYPE
|
||||
// it will be returned, otherwise returns -1u
|
||||
inline d3d9::D3DSAMPLERSTATETYPE GetSamplerStateType9(const D3DTEXTURESTAGESTATETYPE StageType) {
|
||||
switch (StageType) {
|
||||
// 13-21:
|
||||
case D3DTSS_ADDRESSU: return d3d9::D3DSAMP_ADDRESSU;
|
||||
case D3DTSS_ADDRESSV: return d3d9::D3DSAMP_ADDRESSV;
|
||||
case D3DTSS_BORDERCOLOR: return d3d9::D3DSAMP_BORDERCOLOR;
|
||||
case D3DTSS_MAGFILTER: return d3d9::D3DSAMP_MAGFILTER;
|
||||
case D3DTSS_MINFILTER: return d3d9::D3DSAMP_MINFILTER;
|
||||
case D3DTSS_MIPFILTER: return d3d9::D3DSAMP_MIPFILTER;
|
||||
case D3DTSS_MIPMAPLODBIAS: return d3d9::D3DSAMP_MIPMAPLODBIAS;
|
||||
case D3DTSS_MAXMIPLEVEL: return d3d9::D3DSAMP_MAXMIPLEVEL;
|
||||
case D3DTSS_MAXANISOTROPY: return d3d9::D3DSAMP_MAXANISOTROPY;
|
||||
// 25:
|
||||
case D3DTSS_ADDRESSW: return d3d9::D3DSAMP_ADDRESSW;
|
||||
default: return d3d9::D3DSAMPLERSTATETYPE(-1u);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
2188
src/d3d8/d3d8_device.cpp
Normal file
2188
src/d3d8/d3d8_device.cpp
Normal file
File diff suppressed because it is too large
Load diff
478
src/d3d8/d3d8_device.h
Normal file
478
src/d3d8/d3d8_device.h
Normal file
|
@ -0,0 +1,478 @@
|
|||
#pragma once
|
||||
|
||||
#include "d3d8_include.h"
|
||||
#include "d3d8_multithread.h"
|
||||
#include "d3d8_texture.h"
|
||||
#include "d3d8_buffer.h"
|
||||
#include "d3d8_swapchain.h"
|
||||
#include "d3d8_state_block.h"
|
||||
#include "d3d8_d3d9_util.h"
|
||||
#include "d3d8_caps.h"
|
||||
#include "d3d8_batch.h"
|
||||
|
||||
#include "../d3d9/d3d9_bridge.h"
|
||||
|
||||
#include <array>
|
||||
#include <vector>
|
||||
#include <type_traits>
|
||||
#include <unordered_map>
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
class D3D8Interface;
|
||||
|
||||
struct D3D8VertexShaderInfo;
|
||||
|
||||
using D3D8DeviceBase = D3D8WrappedObject<d3d9::IDirect3DDevice9, IDirect3DDevice8>;
|
||||
class D3D8Device final : public D3D8DeviceBase {
|
||||
|
||||
friend class D3D8StateBlock;
|
||||
|
||||
public:
|
||||
|
||||
D3D8Device(
|
||||
D3D8Interface* pParent,
|
||||
Com<d3d9::IDirect3DDevice9>&& pDevice,
|
||||
D3DDEVTYPE DeviceType,
|
||||
HWND hFocusWindow,
|
||||
DWORD BehaviorFlags,
|
||||
D3DPRESENT_PARAMETERS* pParams);
|
||||
|
||||
~D3D8Device();
|
||||
|
||||
HRESULT STDMETHODCALLTYPE TestCooperativeLevel();
|
||||
|
||||
UINT STDMETHODCALLTYPE GetAvailableTextureMem();
|
||||
|
||||
HRESULT STDMETHODCALLTYPE ResourceManagerDiscardBytes(DWORD bytes);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE GetDirect3D(IDirect3D8** ppD3D8);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE GetDeviceCaps(D3DCAPS8* pCaps);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE GetDisplayMode(D3DDISPLAYMODE* pMode);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE GetCreationParameters(D3DDEVICE_CREATION_PARAMETERS* pParameters);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE SetCursorProperties(
|
||||
UINT XHotSpot,
|
||||
UINT YHotSpot,
|
||||
IDirect3DSurface8* pCursorBitmap);
|
||||
|
||||
void STDMETHODCALLTYPE SetCursorPosition(UINT XScreenSpace, UINT YScreenSpace, DWORD Flags);
|
||||
|
||||
// Microsoft d3d8.h in the DirectX 9 SDK uses a different function signature...
|
||||
void STDMETHODCALLTYPE SetCursorPosition(int X, int Y, DWORD Flags);
|
||||
|
||||
BOOL STDMETHODCALLTYPE ShowCursor(BOOL bShow);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE CreateAdditionalSwapChain(
|
||||
D3DPRESENT_PARAMETERS* pPresentationParameters,
|
||||
IDirect3DSwapChain8** ppSwapChain);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE Reset(D3DPRESENT_PARAMETERS* pPresentationParameters);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE Present(
|
||||
const RECT* pSourceRect,
|
||||
const RECT* pDestRect,
|
||||
HWND hDestWindowOverride,
|
||||
const RGNDATA* pDirtyRegion);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE GetBackBuffer(
|
||||
UINT iBackBuffer,
|
||||
D3DBACKBUFFER_TYPE Type,
|
||||
IDirect3DSurface8** ppBackBuffer);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE GetRasterStatus(D3DRASTER_STATUS* pRasterStatus);
|
||||
|
||||
void STDMETHODCALLTYPE SetGammaRamp(DWORD Flags, const D3DGAMMARAMP* pRamp);
|
||||
|
||||
void STDMETHODCALLTYPE GetGammaRamp(D3DGAMMARAMP* pRamp);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE CreateTexture(
|
||||
UINT Width,
|
||||
UINT Height,
|
||||
UINT Levels,
|
||||
DWORD Usage,
|
||||
D3DFORMAT Format,
|
||||
D3DPOOL Pool,
|
||||
IDirect3DTexture8** ppTexture);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE CreateVolumeTexture(
|
||||
UINT Width,
|
||||
UINT Height,
|
||||
UINT Depth,
|
||||
UINT Levels,
|
||||
DWORD Usage,
|
||||
D3DFORMAT Format,
|
||||
D3DPOOL Pool,
|
||||
IDirect3DVolumeTexture8** ppVolumeTexture);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE CreateCubeTexture(
|
||||
UINT EdgeLength,
|
||||
UINT Levels,
|
||||
DWORD Usage,
|
||||
D3DFORMAT Format,
|
||||
D3DPOOL Pool,
|
||||
IDirect3DCubeTexture8** ppCubeTexture);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE CreateVertexBuffer(
|
||||
UINT Length,
|
||||
DWORD Usage,
|
||||
DWORD FVF,
|
||||
D3DPOOL Pool,
|
||||
IDirect3DVertexBuffer8** ppVertexBuffer);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE CreateIndexBuffer(
|
||||
UINT Length,
|
||||
DWORD Usage,
|
||||
D3DFORMAT Format,
|
||||
D3DPOOL Pool,
|
||||
IDirect3DIndexBuffer8** ppIndexBuffer);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE CreateRenderTarget(
|
||||
UINT Width,
|
||||
UINT Height,
|
||||
D3DFORMAT Format,
|
||||
D3DMULTISAMPLE_TYPE MultiSample,
|
||||
BOOL Lockable,
|
||||
IDirect3DSurface8** ppSurface);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE CreateDepthStencilSurface(
|
||||
UINT Width,
|
||||
UINT Height,
|
||||
D3DFORMAT Format,
|
||||
D3DMULTISAMPLE_TYPE MultiSample,
|
||||
IDirect3DSurface8** ppSurface);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE CreateImageSurface(UINT Width, UINT Height, D3DFORMAT Format, IDirect3DSurface8** ppSurface);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE CopyRects(
|
||||
IDirect3DSurface8* pSourceSurface,
|
||||
const RECT* pSourceRectsArray,
|
||||
UINT cRects,
|
||||
IDirect3DSurface8* pDestinationSurface,
|
||||
const POINT* pDestPointsArray);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE UpdateTexture(
|
||||
IDirect3DBaseTexture8* pSourceTexture,
|
||||
IDirect3DBaseTexture8* pDestinationTexture);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE GetFrontBuffer(IDirect3DSurface8* pDestSurface);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE SetRenderTarget(IDirect3DSurface8* pRenderTarget, IDirect3DSurface8* pNewZStencil);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE GetRenderTarget(IDirect3DSurface8** ppRenderTarget);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE GetDepthStencilSurface(IDirect3DSurface8** ppZStencilSurface);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE BeginScene();
|
||||
|
||||
HRESULT STDMETHODCALLTYPE EndScene();
|
||||
|
||||
HRESULT STDMETHODCALLTYPE Clear(
|
||||
DWORD Count,
|
||||
const D3DRECT* pRects,
|
||||
DWORD Flags,
|
||||
D3DCOLOR Color,
|
||||
float Z,
|
||||
DWORD Stencil);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE SetTransform(D3DTRANSFORMSTATETYPE State, const D3DMATRIX* pMatrix);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE GetTransform(D3DTRANSFORMSTATETYPE State, D3DMATRIX* pMatrix);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE MultiplyTransform(D3DTRANSFORMSTATETYPE TransformState, const D3DMATRIX* pMatrix);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE SetViewport(const D3DVIEWPORT8* pViewport);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE GetViewport(D3DVIEWPORT8* pViewport);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE SetMaterial(const D3DMATERIAL8* pMaterial);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE GetMaterial(D3DMATERIAL8* pMaterial);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE SetLight(DWORD Index, const D3DLIGHT8* pLight);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE GetLight(DWORD Index, D3DLIGHT8* pLight);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE LightEnable(DWORD Index, BOOL Enable);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE GetLightEnable(DWORD Index, BOOL* pEnable);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE SetClipPlane(DWORD Index, const float* pPlane);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE GetClipPlane(DWORD Index, float* pPlane);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE SetRenderState(D3DRENDERSTATETYPE State, DWORD Value);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE GetRenderState(D3DRENDERSTATETYPE State, DWORD* pValue);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE CreateStateBlock(
|
||||
D3DSTATEBLOCKTYPE Type,
|
||||
DWORD* pToken);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE CaptureStateBlock(DWORD Token);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE ApplyStateBlock(DWORD Token);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE DeleteStateBlock(DWORD Token);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE BeginStateBlock();
|
||||
|
||||
HRESULT STDMETHODCALLTYPE EndStateBlock(DWORD* pToken);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE SetClipStatus(const D3DCLIPSTATUS8* pClipStatus);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE GetClipStatus(D3DCLIPSTATUS8* pClipStatus);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE GetTexture(DWORD Stage, IDirect3DBaseTexture8** ppTexture);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE SetTexture(DWORD Stage, IDirect3DBaseTexture8* pTexture);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE GetTextureStageState(
|
||||
DWORD Stage,
|
||||
D3DTEXTURESTAGESTATETYPE Type,
|
||||
DWORD* pValue);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE SetTextureStageState(
|
||||
DWORD Stage,
|
||||
D3DTEXTURESTAGESTATETYPE Type,
|
||||
DWORD Value);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE ValidateDevice(DWORD* pNumPasses);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE GetInfo(DWORD DevInfoID, void* pDevInfoStruct, DWORD DevInfoStructSize);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE SetPaletteEntries(UINT PaletteNumber, const PALETTEENTRY* pEntries);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE GetPaletteEntries(UINT PaletteNumber, PALETTEENTRY* pEntries);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE SetCurrentTexturePalette(UINT PaletteNumber);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE GetCurrentTexturePalette(UINT* PaletteNumber);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE DrawPrimitive(
|
||||
D3DPRIMITIVETYPE PrimitiveType,
|
||||
UINT StartVertex,
|
||||
UINT PrimitiveCount);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE DrawIndexedPrimitive(
|
||||
D3DPRIMITIVETYPE PrimitiveType,
|
||||
UINT MinVertexIndex,
|
||||
UINT NumVertices,
|
||||
UINT StartIndex,
|
||||
UINT PrimitiveCount);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE DrawPrimitiveUP(
|
||||
D3DPRIMITIVETYPE PrimitiveType,
|
||||
UINT PrimitiveCount,
|
||||
const void* pVertexStreamZeroData,
|
||||
UINT VertexStreamZeroStride);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE DrawIndexedPrimitiveUP(
|
||||
D3DPRIMITIVETYPE PrimitiveType,
|
||||
UINT MinVertexIndex,
|
||||
UINT NumVertices,
|
||||
UINT PrimitiveCount,
|
||||
const void* pIndexData,
|
||||
D3DFORMAT IndexDataFormat,
|
||||
const void* pVertexStreamZeroData,
|
||||
UINT VertexStreamZeroStride);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE ProcessVertices(
|
||||
UINT SrcStartIndex,
|
||||
UINT DestIndex,
|
||||
UINT VertexCount,
|
||||
IDirect3DVertexBuffer8* pDestBuffer,
|
||||
DWORD Flags);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE CreateVertexShader(
|
||||
const DWORD* pDeclaration,
|
||||
const DWORD* pFunction,
|
||||
DWORD* pHandle,
|
||||
DWORD Usage);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE SetVertexShader(DWORD Handle);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE GetVertexShader(DWORD* pHandle);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE DeleteVertexShader(DWORD Handle);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE SetVertexShaderConstant(
|
||||
DWORD StartRegister,
|
||||
const void* pConstantData,
|
||||
DWORD ConstantCount);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE GetVertexShaderConstant(DWORD Register, void* pConstantData, DWORD ConstantCount);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE GetVertexShaderDeclaration(DWORD Handle, void* pData, DWORD* pSizeOfData);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE GetVertexShaderFunction(DWORD Handle, void* pData, DWORD* pSizeOfData);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE SetStreamSource(
|
||||
UINT StreamNumber,
|
||||
IDirect3DVertexBuffer8* pStreamData,
|
||||
UINT Stride);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE GetStreamSource(
|
||||
UINT StreamNumber,
|
||||
IDirect3DVertexBuffer8** ppStreamData,
|
||||
UINT* pStride);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE SetIndices(IDirect3DIndexBuffer8* pIndexData, UINT BaseVertexIndex);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE GetIndices(
|
||||
IDirect3DIndexBuffer8** ppIndexData,
|
||||
UINT* pBaseVertexIndex);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE CreatePixelShader(
|
||||
const DWORD* pFunction,
|
||||
DWORD* pHandle);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE SetPixelShader(DWORD Handle);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE GetPixelShader(DWORD* pHandle);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE DeletePixelShader(THIS_ DWORD Handle);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE GetPixelShaderConstant(DWORD Register, void* pConstantData, DWORD ConstantCount);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE SetPixelShaderConstant(
|
||||
DWORD StartRegister,
|
||||
const void* pConstantData,
|
||||
DWORD ConstantCount);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE GetPixelShaderFunction(DWORD Handle, void* pData, DWORD* pSizeOfData);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE DrawRectPatch(
|
||||
UINT Handle,
|
||||
const float* pNumSegs,
|
||||
const D3DRECTPATCH_INFO* pRectPatchInfo);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE DrawTriPatch(
|
||||
UINT Handle,
|
||||
const float* pNumSegs,
|
||||
const D3DTRIPATCH_INFO* pTriPatchInfo);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE DeletePatch(UINT Handle);
|
||||
|
||||
const D3D8Options* GetOptions() const {
|
||||
return &m_d3d8Options;
|
||||
}
|
||||
|
||||
inline bool ShouldRecord() { return m_recorder != nullptr; }
|
||||
inline bool ShouldBatch() { return m_batcher != nullptr; }
|
||||
|
||||
D3D8DeviceLock LockDevice() {
|
||||
return m_multithread.AcquireLock();
|
||||
}
|
||||
|
||||
/**
|
||||
* Marks any state change in the device, so we can signal
|
||||
* the batcher to emit draw calls. StateChange should be
|
||||
* called immediately before changing any D3D9 state.
|
||||
*/
|
||||
inline void StateChange() {
|
||||
if (ShouldBatch())
|
||||
m_batcher->StateChange();
|
||||
}
|
||||
|
||||
inline void ResetState() {
|
||||
// Mirrors how D3D9 handles the BackBufferCount
|
||||
m_presentParams.BackBufferCount = std::max(m_presentParams.BackBufferCount, 1u);
|
||||
|
||||
// Purge cached objects
|
||||
m_textures.fill(nullptr);
|
||||
m_streams.fill(D3D8VBO());
|
||||
m_indices = nullptr;
|
||||
m_renderTarget = nullptr;
|
||||
m_depthStencil = nullptr;
|
||||
|
||||
m_backBuffers.clear();
|
||||
m_backBuffers.resize(m_presentParams.BackBufferCount);
|
||||
|
||||
m_autoDepthStencil = nullptr;
|
||||
|
||||
m_shadowPerspectiveDivide = false;
|
||||
}
|
||||
|
||||
inline void RecreateBackBuffersAndAutoDepthStencil() {
|
||||
for (UINT i = 0; i < m_presentParams.BackBufferCount; i++) {
|
||||
Com<d3d9::IDirect3DSurface9> pSurface9;
|
||||
GetD3D9()->GetBackBuffer(0, i, d3d9::D3DBACKBUFFER_TYPE_MONO, &pSurface9);
|
||||
m_backBuffers[i] = new D3D8Surface(this, D3DPOOL_DEFAULT, std::move(pSurface9));
|
||||
}
|
||||
|
||||
Com<d3d9::IDirect3DSurface9> pStencil9;
|
||||
// This call will fail if the D3D9 device is created without
|
||||
// the EnableAutoDepthStencil presentation parameter set to TRUE.
|
||||
HRESULT res = GetD3D9()->GetDepthStencilSurface(&pStencil9);
|
||||
m_autoDepthStencil = FAILED(res) ? nullptr : new D3D8Surface(this, D3DPOOL_DEFAULT, std::move(pStencil9));
|
||||
|
||||
m_renderTarget = m_backBuffers[0];
|
||||
m_depthStencil = m_autoDepthStencil;
|
||||
}
|
||||
|
||||
friend d3d9::IDirect3DPixelShader9* getPixelShaderPtr(D3D8Device* device, DWORD Handle);
|
||||
friend D3D8VertexShaderInfo* getVertexShaderInfo(D3D8Device* device, DWORD Handle);
|
||||
|
||||
private:
|
||||
|
||||
Com<IDxvkD3D8Bridge> m_bridge;
|
||||
const D3D8Options& m_d3d8Options;
|
||||
|
||||
Com<D3D8Interface> m_parent;
|
||||
|
||||
D3DPRESENT_PARAMETERS m_presentParams;
|
||||
|
||||
// Value of D3DRS_LINEPATTERN
|
||||
D3DLINEPATTERN m_linePattern = {};
|
||||
// Value of D3DRS_ZVISIBLE (although the RS is not supported, its value is stored)
|
||||
DWORD m_zVisible = 0;
|
||||
// Value of D3DRS_PATCHSEGMENTS
|
||||
float m_patchSegments = 1.0f;
|
||||
|
||||
// Controls fixed-function exclusive mode (no PS support)
|
||||
bool m_isFixedFunctionOnly = false;
|
||||
|
||||
bool m_shadowPerspectiveDivide = false;
|
||||
|
||||
D3D8StateBlock* m_recorder = nullptr;
|
||||
DWORD m_recorderToken = 0;
|
||||
DWORD m_token = 0;
|
||||
std::unordered_map<DWORD, D3D8StateBlock> m_stateBlocks;
|
||||
D3D8Batcher* m_batcher = nullptr;
|
||||
|
||||
struct D3D8VBO {
|
||||
Com<D3D8VertexBuffer, false> buffer = nullptr;
|
||||
UINT stride = 0;
|
||||
};
|
||||
|
||||
std::array<Com<D3D8Texture2D, false>, d8caps::MAX_TEXTURE_STAGES> m_textures;
|
||||
std::array<D3D8VBO, d8caps::MAX_STREAMS> m_streams;
|
||||
|
||||
Com<D3D8IndexBuffer, false> m_indices;
|
||||
UINT m_baseVertexIndex = 0;
|
||||
|
||||
std::vector<Com<D3D8Surface, false>> m_backBuffers;
|
||||
Com<D3D8Surface, false> m_autoDepthStencil;
|
||||
|
||||
Com<D3D8Surface, false> m_renderTarget;
|
||||
Com<D3D8Surface, false> m_depthStencil;
|
||||
|
||||
std::vector<D3D8VertexShaderInfo> m_vertexShaders;
|
||||
std::vector<Com<d3d9::IDirect3DPixelShader9>> m_pixelShaders;
|
||||
DWORD m_currentVertexShader = 0; // can be FVF or vs index (marked by D3DFVF_RESERVED0)
|
||||
DWORD m_currentPixelShader = 0;
|
||||
|
||||
D3DDEVTYPE m_deviceType;
|
||||
HWND m_window;
|
||||
|
||||
DWORD m_behaviorFlags;
|
||||
|
||||
D3D8Multithread m_multithread;
|
||||
|
||||
};
|
||||
|
||||
}
|
83
src/d3d8/d3d8_device_child.h
Normal file
83
src/d3d8/d3d8_device_child.h
Normal file
|
@ -0,0 +1,83 @@
|
|||
#pragma once
|
||||
|
||||
// Common methods for device-tied objects.
|
||||
// - AddRef, Release from IUnknown
|
||||
// - GetDevice from various classes including IDirect3DResource8
|
||||
|
||||
#include "d3d8_include.h"
|
||||
#include "d3d8_wrapped_object.h"
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
class D3D8Device;
|
||||
|
||||
template <typename D3D9, typename D3D8>
|
||||
class D3D8DeviceChild : public D3D8WrappedObject<D3D9, D3D8> {
|
||||
|
||||
public:
|
||||
|
||||
D3D8DeviceChild(D3D8Device* pDevice, Com<D3D9>&& Object)
|
||||
: D3D8WrappedObject<D3D9, D3D8>(std::move(Object))
|
||||
, m_parent( pDevice ) { }
|
||||
|
||||
ULONG STDMETHODCALLTYPE AddRef() {
|
||||
uint32_t refCount = this->m_refCount++;
|
||||
if (unlikely(!refCount)) {
|
||||
this->AddRefPrivate();
|
||||
GetDevice()->AddRef();
|
||||
}
|
||||
|
||||
return refCount + 1;
|
||||
}
|
||||
|
||||
ULONG STDMETHODCALLTYPE Release() {
|
||||
uint32_t oldRefCount, refCount;
|
||||
|
||||
do {
|
||||
oldRefCount = this->m_refCount.load(std::memory_order_acquire);
|
||||
|
||||
// clamp value to 0 to prevent underruns
|
||||
if (unlikely(!oldRefCount))
|
||||
return 0;
|
||||
|
||||
refCount = oldRefCount - 1;
|
||||
|
||||
} while (!this->m_refCount.compare_exchange_weak(oldRefCount,
|
||||
refCount,
|
||||
std::memory_order_release,
|
||||
std::memory_order_acquire));
|
||||
|
||||
if (unlikely(!refCount)) {
|
||||
auto* pDevice = GetDevice();
|
||||
this->ReleasePrivate();
|
||||
pDevice->Release();
|
||||
}
|
||||
|
||||
return refCount;
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE GetDevice(IDirect3DDevice8** ppDevice) {
|
||||
InitReturnPtr(ppDevice);
|
||||
|
||||
if (ppDevice == nullptr)
|
||||
return D3DERR_INVALIDCALL;
|
||||
|
||||
*ppDevice = ref(GetDevice());
|
||||
return D3D_OK;
|
||||
}
|
||||
|
||||
IDirect3DDevice8* GetDevice() {
|
||||
return reinterpret_cast<IDirect3DDevice8*>(m_parent);
|
||||
}
|
||||
|
||||
D3D8Device* GetParent() {
|
||||
return m_parent;
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
D3D8Device* m_parent;
|
||||
|
||||
};
|
||||
|
||||
}
|
220
src/d3d8/d3d8_format.h
Normal file
220
src/d3d8/d3d8_format.h
Normal file
|
@ -0,0 +1,220 @@
|
|||
#pragma once
|
||||
|
||||
#include "d3d8_include.h"
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
constexpr bool isDXT(D3DFORMAT fmt) {
|
||||
return fmt == D3DFMT_DXT1
|
||||
|| fmt == D3DFMT_DXT2
|
||||
|| fmt == D3DFMT_DXT3
|
||||
|| fmt == D3DFMT_DXT4
|
||||
|| fmt == D3DFMT_DXT5;
|
||||
}
|
||||
|
||||
constexpr bool isDXT(d3d9::D3DFORMAT fmt) {
|
||||
return isDXT(D3DFORMAT(fmt));
|
||||
}
|
||||
|
||||
constexpr bool isUnsupportedSurfaceFormat(D3DFORMAT fmt) {
|
||||
// mirror what dxvk doesn't support in terms of d3d9 surface formats
|
||||
return fmt == D3DFMT_R8G8B8
|
||||
|| fmt == D3DFMT_R3G3B2
|
||||
|| fmt == D3DFMT_A8R3G3B2
|
||||
|| fmt == D3DFMT_A8P8
|
||||
|| fmt == D3DFMT_P8;
|
||||
// not included in the d3d8 spec
|
||||
//|| fmt == D3DFMT_CXV8U8;
|
||||
}
|
||||
|
||||
constexpr bool isSupportedDepthStencilFormat(D3DFORMAT fmt) {
|
||||
// native d3d8 doesn't support D3DFMT_D32, D3DFMT_D15S1 or D3DFMT_D24X4S4
|
||||
return fmt == D3DFMT_D16_LOCKABLE
|
||||
|| fmt == D3DFMT_D16
|
||||
//|| fmt == D3DFMT_D32
|
||||
//|| fmt == D3DFMT_D15S1
|
||||
//|| fmt == D3DFMT_D24X4S4
|
||||
|| fmt == D3DFMT_D24S8
|
||||
|| fmt == D3DFMT_D24X8;
|
||||
}
|
||||
|
||||
constexpr bool isDepthStencilFormat(D3DFORMAT fmt) {
|
||||
return fmt == D3DFMT_D16_LOCKABLE
|
||||
|| fmt == D3DFMT_D16
|
||||
|| fmt == D3DFMT_D32
|
||||
|| fmt == D3DFMT_D15S1
|
||||
|| fmt == D3DFMT_D24X4S4
|
||||
|| fmt == D3DFMT_D24S8
|
||||
|| fmt == D3DFMT_D24X8;
|
||||
}
|
||||
|
||||
// Get bytes per pixel (or 4x4 block for DXT)
|
||||
constexpr UINT getFormatStride(D3DFORMAT fmt) {
|
||||
switch (fmt) {
|
||||
default:
|
||||
case D3DFMT_UNKNOWN:
|
||||
return 0;
|
||||
case D3DFMT_R3G3B2:
|
||||
case D3DFMT_A8:
|
||||
case D3DFMT_P8:
|
||||
case D3DFMT_L8:
|
||||
case D3DFMT_A4L4:
|
||||
return 1;
|
||||
case D3DFMT_R5G6B5:
|
||||
case D3DFMT_X1R5G5B5:
|
||||
case D3DFMT_A1R5G5B5:
|
||||
case D3DFMT_A4R4G4B4:
|
||||
case D3DFMT_A8R3G3B2:
|
||||
case D3DFMT_X4R4G4B4:
|
||||
case D3DFMT_A8P8:
|
||||
case D3DFMT_A8L8:
|
||||
case D3DFMT_V8U8:
|
||||
case D3DFMT_L6V5U5:
|
||||
case D3DFMT_D16_LOCKABLE:
|
||||
case D3DFMT_D15S1:
|
||||
case D3DFMT_D16:
|
||||
case D3DFMT_UYVY:
|
||||
case D3DFMT_YUY2:
|
||||
return 2;
|
||||
case D3DFMT_R8G8B8:
|
||||
return 3;
|
||||
case D3DFMT_A8R8G8B8:
|
||||
case D3DFMT_X8R8G8B8:
|
||||
case D3DFMT_A2B10G10R10:
|
||||
//case D3DFMT_A8B8G8R8:
|
||||
//case D3DFMT_X8B8G8R8:
|
||||
case D3DFMT_G16R16:
|
||||
case D3DFMT_X8L8V8U8:
|
||||
case D3DFMT_Q8W8V8U8:
|
||||
case D3DFMT_V16U16:
|
||||
case D3DFMT_W11V11U10:
|
||||
case D3DFMT_A2W10V10U10:
|
||||
case D3DFMT_D32:
|
||||
case D3DFMT_D24S8:
|
||||
case D3DFMT_D24X8:
|
||||
case D3DFMT_D24X4S4:
|
||||
return 4;
|
||||
case D3DFMT_DXT1:
|
||||
return 8;
|
||||
case D3DFMT_DXT2:
|
||||
case D3DFMT_DXT3:
|
||||
case D3DFMT_DXT4:
|
||||
case D3DFMT_DXT5:
|
||||
return 16;
|
||||
}
|
||||
}
|
||||
|
||||
constexpr uint32_t GetVertexCount8(D3DPRIMITIVETYPE type, UINT count) {
|
||||
switch (type) {
|
||||
default:
|
||||
case D3DPT_TRIANGLELIST: return count * 3;
|
||||
case D3DPT_POINTLIST: return count;
|
||||
case D3DPT_LINELIST: return count * 2;
|
||||
case D3DPT_LINESTRIP: return count + 1;
|
||||
case D3DPT_TRIANGLESTRIP: return count + 2;
|
||||
case D3DPT_TRIANGLEFAN: return count + 2;
|
||||
}
|
||||
}
|
||||
|
||||
// Essentially the same logic as D3D9VertexDecl::SetFVF
|
||||
constexpr UINT GetFVFStride(DWORD FVF) {
|
||||
uint32_t texCount = 0;
|
||||
|
||||
uint32_t betas = 0;
|
||||
uint8_t betaIdx = 0xFF;
|
||||
|
||||
UINT size = 0;
|
||||
|
||||
switch (FVF & D3DFVF_POSITION_MASK) {
|
||||
case D3DFVF_XYZ:
|
||||
case D3DFVF_XYZB1:
|
||||
case D3DFVF_XYZB2:
|
||||
case D3DFVF_XYZB3:
|
||||
case D3DFVF_XYZB4:
|
||||
case D3DFVF_XYZB5:
|
||||
size += sizeof(float) * 3;
|
||||
|
||||
if ((FVF & D3DFVF_POSITION_MASK) == D3DFVF_XYZ)
|
||||
break;
|
||||
|
||||
betas = (((FVF & D3DFVF_XYZB5) - D3DFVF_XYZB1) >> 1) + 1;
|
||||
if (FVF & D3DFVF_LASTBETA_D3DCOLOR)
|
||||
betaIdx = sizeof(D3DCOLOR);
|
||||
else if (FVF & D3DFVF_LASTBETA_UBYTE4)
|
||||
betaIdx = sizeof(BYTE) * 4;
|
||||
else if ((FVF & D3DFVF_XYZB5) == D3DFVF_XYZB5)
|
||||
betaIdx = sizeof(float);
|
||||
|
||||
if (betaIdx != 0xFF)
|
||||
betas--;
|
||||
|
||||
if (betas > 0) {
|
||||
if (betas <= 4)
|
||||
size += sizeof(float) * betas;
|
||||
}
|
||||
|
||||
if (betaIdx != 0xFF) {
|
||||
size += betaIdx;
|
||||
}
|
||||
break;
|
||||
|
||||
case D3DFVF_XYZW:
|
||||
case D3DFVF_XYZRHW:
|
||||
size += sizeof(float) * 4;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (FVF & D3DFVF_NORMAL) {
|
||||
size += sizeof(float) * 3;
|
||||
}
|
||||
if (FVF & D3DFVF_PSIZE) {
|
||||
size += sizeof(float);
|
||||
}
|
||||
if (FVF & D3DFVF_DIFFUSE) {
|
||||
size += sizeof(D3DCOLOR);
|
||||
}
|
||||
if (FVF & D3DFVF_SPECULAR) {
|
||||
size += sizeof(D3DCOLOR);
|
||||
}
|
||||
|
||||
texCount = (FVF & D3DFVF_TEXCOUNT_MASK) >> D3DFVF_TEXCOUNT_SHIFT;
|
||||
texCount = std::min(texCount, 8u);
|
||||
|
||||
for (uint32_t i = 0; i < texCount; i++) {
|
||||
switch ((FVF >> (16 + i * 2)) & 0x3) {
|
||||
case D3DFVF_TEXTUREFORMAT1:
|
||||
size += sizeof(float);
|
||||
break;
|
||||
|
||||
case D3DFVF_TEXTUREFORMAT2:
|
||||
size += sizeof(float) * 2;
|
||||
break;
|
||||
|
||||
case D3DFVF_TEXTUREFORMAT3:
|
||||
size += sizeof(float) * 3;
|
||||
break;
|
||||
|
||||
case D3DFVF_TEXTUREFORMAT4:
|
||||
size += sizeof(float) * 4;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
constexpr UINT getSurfaceSize(D3DFORMAT Format, UINT Width, UINT Height) {
|
||||
if (isDXT(Format)) {
|
||||
Width = ((Width + 3) >> 2);
|
||||
Height = ((Height + 3) >> 2);
|
||||
}
|
||||
return Width * Height * getFormatStride(Format);
|
||||
}
|
||||
|
||||
}
|
206
src/d3d8/d3d8_include.h
Normal file
206
src/d3d8/d3d8_include.h
Normal file
|
@ -0,0 +1,206 @@
|
|||
#pragma once
|
||||
|
||||
#ifndef _MSC_VER
|
||||
#ifdef _WIN32_WINNT
|
||||
#undef _WIN32_WINNT
|
||||
#endif
|
||||
#define _WIN32_WINNT 0x0A00
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
#include <d3d8.h>
|
||||
|
||||
// Declare __uuidof for D3D8 interfaces
|
||||
#ifdef __CRT_UUID_DECL
|
||||
__CRT_UUID_DECL(IDirect3D8, 0x1DD9E8DA,0x1C77,0x4D40,0xB0,0xCF,0x98,0xFE,0xFD,0xFF,0x95,0x12);
|
||||
__CRT_UUID_DECL(IDirect3DDevice8, 0x7385E5DF,0x8FE8,0x41D5,0x86,0xB6,0xD7,0xB4,0x85,0x47,0xB6,0xCF);
|
||||
__CRT_UUID_DECL(IDirect3DResource8, 0x1B36BB7B,0x09B7,0x410A,0xB4,0x45,0x7D,0x14,0x30,0xD7,0xB3,0x3F);
|
||||
__CRT_UUID_DECL(IDirect3DVertexBuffer8, 0x8AEEEAC7,0x05F9,0x44D4,0xB5,0x91,0x00,0x0B,0x0D,0xF1,0xCB,0x95);
|
||||
__CRT_UUID_DECL(IDirect3DVolume8, 0xBD7349F5,0x14F1,0x42E4,0x9C,0x79,0x97,0x23,0x80,0xDB,0x40,0xC0);
|
||||
__CRT_UUID_DECL(IDirect3DSwapChain8, 0x928C088B,0x76B9,0x4C6B,0xA5,0x36,0xA5,0x90,0x85,0x38,0x76,0xCD);
|
||||
__CRT_UUID_DECL(IDirect3DSurface8, 0xB96EEBCA,0xB326,0x4EA5,0x88,0x2F,0x2F,0xF5,0xBA,0xE0,0x21,0xDD);
|
||||
__CRT_UUID_DECL(IDirect3DIndexBuffer8, 0x0E689C9A,0x053D,0x44A0,0x9D,0x92,0xDB,0x0E,0x3D,0x75,0x0F,0x86);
|
||||
__CRT_UUID_DECL(IDirect3DBaseTexture8, 0xB4211CFA,0x51B9,0x4A9F,0xAB,0x78,0xDB,0x99,0xB2,0xBB,0x67,0x8E);
|
||||
__CRT_UUID_DECL(IDirect3DTexture8, 0xE4CDD575,0x2866,0x4F01,0xB1,0x2E,0x7E,0xEC,0xE1,0xEC,0x93,0x58);
|
||||
__CRT_UUID_DECL(IDirect3DCubeTexture8, 0x3EE5B968,0x2ACA,0x4C34,0x8B,0xB5,0x7E,0x0C,0x3D,0x19,0xB7,0x50);
|
||||
__CRT_UUID_DECL(IDirect3DVolumeTexture8, 0x4B8AAAFA,0x140F,0x42BA,0x91,0x31,0x59,0x7E,0xAF,0xAA,0x2E,0xAD);
|
||||
#elif defined(_MSC_VER)
|
||||
interface DECLSPEC_UUID("1DD9E8DA-1C77-4D40-B0CF-98FEFDFF9512") IDirect3D8;
|
||||
interface DECLSPEC_UUID("7385E5DF-8FE8-41D5-86B6-D7B48547B6CF") IDirect3DDevice8;
|
||||
interface DECLSPEC_UUID("1B36BB7B-09B7-410A-B445-7D1430D7B33F") IDirect3DResource8;
|
||||
interface DECLSPEC_UUID("8AEEEAC7-05F9-44D4-B591-000B0DF1CB95") IDirect3DVertexBuffer8;
|
||||
interface DECLSPEC_UUID("BD7349F5-14F1-42E4-9C79-972380DB40C0") IDirect3DVolume8;
|
||||
interface DECLSPEC_UUID("928C088B-76B9-4C6B-A536-A590853876CD") IDirect3DSwapChain8;
|
||||
interface DECLSPEC_UUID("B96EEBCA-B326-4EA5-882F-2FF5BAE021DD") IDirect3DSurface8;
|
||||
interface DECLSPEC_UUID("0E689C9A-053D-44A0-9D92-DB0E3D750F86") IDirect3DIndexBuffer8;
|
||||
interface DECLSPEC_UUID("B4211CFA-51B9-4A9F-AB78-DB99B2BB678E") IDirect3DBaseTexture8;
|
||||
interface DECLSPEC_UUID("E4CDD575-2866-4F01-B12E-7EECE1EC9358") IDirect3DTexture8;
|
||||
interface DECLSPEC_UUID("3EE5B968-2ACA-4C34-8BB5-7E0C3D19B750") IDirect3DCubeTexture8;
|
||||
interface DECLSPEC_UUID("4B8AAAFA-140F-42BA-9131-597EAFAA2EAD") IDirect3DVolumeTexture8;
|
||||
#endif
|
||||
|
||||
// Undefine D3D8 macros
|
||||
#undef DIRECT3D_VERSION
|
||||
#undef D3D_SDK_VERSION
|
||||
|
||||
#undef D3DCS_ALL // parentheses added in D3D9
|
||||
#undef D3DFVF_POSITION_MASK // changed from 0x00E to 0x400E in D3D9
|
||||
#undef D3DFVF_RESERVED2 // reduced from 4 to 2 in DX9
|
||||
|
||||
#undef D3DSP_REGNUM_MASK // changed from 0x00000FFF to 0x000007FF in D3D9
|
||||
|
||||
|
||||
#if defined(__MINGW32__) || defined(__GNUC__)
|
||||
|
||||
// Avoid redundant definitions (add D3D*_DEFINED macros here)
|
||||
#define D3DRECT_DEFINED
|
||||
#define D3DMATRIX_DEFINED
|
||||
|
||||
// Temporarily override __CRT_UUID_DECL to allow usage in d3d9 namespace
|
||||
#pragma push_macro("__CRT_UUID_DECL")
|
||||
#ifdef __CRT_UUID_DECL
|
||||
#undef __CRT_UUID_DECL
|
||||
#endif
|
||||
|
||||
#ifdef __MINGW32__
|
||||
#define __CRT_UUID_DECL(type,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8) \
|
||||
} \
|
||||
extern "C++" template<> struct __mingw_uuidof_s<d3d9::type> { static constexpr IID __uuid_inst = {l,w1,w2, {b1,b2,b3,b4,b5,b6,b7,b8}}; }; \
|
||||
extern "C++" template<> constexpr const GUID &__mingw_uuidof<d3d9::type>() { return __mingw_uuidof_s<d3d9::type>::__uuid_inst; } \
|
||||
extern "C++" template<> constexpr const GUID &__mingw_uuidof<d3d9::type*>() { return __mingw_uuidof_s<d3d9::type>::__uuid_inst; } \
|
||||
namespace d3d9 {
|
||||
|
||||
#elif defined(__GNUC__)
|
||||
#define __CRT_UUID_DECL(type, a, b, c, d, e, f, g, h, i, j, k) \
|
||||
} \
|
||||
extern "C++" { template <> constexpr GUID __uuidof_helper<d3d9::type>() { return GUID{a,b,c,{d,e,f,g,h,i,j,k}}; } } \
|
||||
extern "C++" { template <> constexpr GUID __uuidof_helper<d3d9::type*>() { return __uuidof_helper<d3d9::type>(); } } \
|
||||
extern "C++" { template <> constexpr GUID __uuidof_helper<const d3d9::type*>() { return __uuidof_helper<d3d9::type>(); } } \
|
||||
extern "C++" { template <> constexpr GUID __uuidof_helper<d3d9::type&>() { return __uuidof_helper<d3d9::type>(); } } \
|
||||
extern "C++" { template <> constexpr GUID __uuidof_helper<const d3d9::type&>() { return __uuidof_helper<d3d9::type>(); } } \
|
||||
namespace d3d9 {
|
||||
#endif
|
||||
|
||||
#endif // defined(__MINGW32__) || defined(__GNUC__)
|
||||
|
||||
|
||||
/**
|
||||
* \brief Direct3D 9
|
||||
*
|
||||
* All D3D9 interfaces are included within
|
||||
* a namespace, so as not to collide with
|
||||
* D3D8 interfaces.
|
||||
*/
|
||||
namespace d3d9 {
|
||||
#include <d3d9.h>
|
||||
}
|
||||
|
||||
// Indicates d3d9:: namespace is in-use.
|
||||
#define DXVK_D3D9_NAMESPACE
|
||||
|
||||
#if defined(__MINGW32__) || defined(__GNUC__)
|
||||
#pragma pop_macro("__CRT_UUID_DECL")
|
||||
#endif
|
||||
|
||||
//for some reason we need to specify __declspec(dllexport) for MinGW
|
||||
#if defined(__WINE__) || !defined(_WIN32)
|
||||
#define DLLEXPORT __attribute__((visibility("default")))
|
||||
#else
|
||||
#define DLLEXPORT
|
||||
#endif
|
||||
|
||||
|
||||
#include "../util/com/com_guid.h"
|
||||
#include "../util/com/com_object.h"
|
||||
#include "../util/com/com_pointer.h"
|
||||
|
||||
#include "../util/log/log.h"
|
||||
#include "../util/log/log_debug.h"
|
||||
|
||||
#include "../util/sync/sync_recursive.h"
|
||||
|
||||
#include "../util/util_error.h"
|
||||
#include "../util/util_likely.h"
|
||||
#include "../util/util_string.h"
|
||||
|
||||
// Missed definitions in Wine/MinGW.
|
||||
|
||||
#ifndef D3DPRESENT_BACK_BUFFERS_MAX_EX
|
||||
#define D3DPRESENT_BACK_BUFFERS_MAX_EX 30
|
||||
#endif
|
||||
|
||||
#ifndef D3DSI_OPCODE_MASK
|
||||
#define D3DSI_OPCODE_MASK 0x0000FFFF
|
||||
#endif
|
||||
|
||||
#ifndef D3DSP_TEXTURETYPE_MASK
|
||||
#define D3DSP_TEXTURETYPE_MASK 0x78000000
|
||||
#endif
|
||||
|
||||
#ifndef D3DUSAGE_AUTOGENMIPMAP
|
||||
#define D3DUSAGE_AUTOGENMIPMAP 0x00000400L
|
||||
#endif
|
||||
|
||||
#ifndef D3DSP_DCL_USAGE_MASK
|
||||
#define D3DSP_DCL_USAGE_MASK 0x0000000f
|
||||
#endif
|
||||
|
||||
#ifndef D3DSP_OPCODESPECIFICCONTROL_MASK
|
||||
#define D3DSP_OPCODESPECIFICCONTROL_MASK 0x00ff0000
|
||||
#endif
|
||||
|
||||
#ifndef D3DSP_OPCODESPECIFICCONTROL_SHIFT
|
||||
#define D3DSP_OPCODESPECIFICCONTROL_SHIFT 16
|
||||
#endif
|
||||
|
||||
#ifndef D3DCURSOR_IMMEDIATE_UPDATE
|
||||
#define D3DCURSOR_IMMEDIATE_UPDATE 0x00000001L
|
||||
#endif
|
||||
|
||||
#ifndef D3DPRESENT_FORCEIMMEDIATE
|
||||
#define D3DPRESENT_FORCEIMMEDIATE 0x00000100L
|
||||
#endif
|
||||
|
||||
// From d3dtypes.h
|
||||
|
||||
#ifndef D3DDEVINFOID_TEXTUREMANAGER
|
||||
#define D3DDEVINFOID_TEXTUREMANAGER 1
|
||||
#endif
|
||||
|
||||
#ifndef D3DDEVINFOID_D3DTEXTUREMANAGER
|
||||
#define D3DDEVINFOID_D3DTEXTUREMANAGER 2
|
||||
#endif
|
||||
|
||||
#ifndef D3DDEVINFOID_TEXTURING
|
||||
#define D3DDEVINFOID_TEXTURING 3
|
||||
#endif
|
||||
|
||||
// From d3dhal.h
|
||||
|
||||
#ifndef D3DDEVINFOID_VCACHE
|
||||
#define D3DDEVINFOID_VCACHE 4
|
||||
#endif
|
||||
|
||||
// MinGW headers are broken. Who'dve guessed?
|
||||
#ifndef _MSC_VER
|
||||
|
||||
// Missing from d3d8types.h
|
||||
#ifndef D3DDEVINFOID_RESOURCEMANAGER
|
||||
#define D3DDEVINFOID_RESOURCEMANAGER 5
|
||||
#endif
|
||||
|
||||
#ifndef D3DDEVINFOID_VERTEXSTATS
|
||||
#define D3DDEVINFOID_VERTEXSTATS 6 // Aka D3DDEVINFOID_D3DVERTEXSTATS
|
||||
#endif
|
||||
|
||||
#ifndef D3DPRESENT_RATE_UNLIMITED
|
||||
#define D3DPRESENT_RATE_UNLIMITED 0x7FFFFFFF
|
||||
#endif
|
||||
|
||||
#else // _MSC_VER
|
||||
|
||||
// These are enum typedefs in the MinGW headers, but not defined by Microsoft
|
||||
#define D3DVSDT_TYPE DWORD
|
||||
#define D3DVSDE_REGISTER DWORD
|
||||
|
||||
#endif
|
159
src/d3d8/d3d8_interface.cpp
Normal file
159
src/d3d8/d3d8_interface.cpp
Normal file
|
@ -0,0 +1,159 @@
|
|||
#include "d3d8_interface.h"
|
||||
|
||||
#include "d3d8_device.h"
|
||||
#include "d3d8_texture.h"
|
||||
|
||||
#include <cstring>
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
D3D8Interface::D3D8Interface() {
|
||||
m_d3d9 = d3d9::Direct3DCreate9(D3D_SDK_VERSION);
|
||||
|
||||
// Get the bridge interface to D3D9.
|
||||
if (FAILED(m_d3d9->QueryInterface(__uuidof(IDxvkD3D8InterfaceBridge), (void**)&m_bridge))) {
|
||||
throw DxvkError("D3D8Interface: ERROR! Failed to get D3D9 Bridge. d3d9.dll might not be DXVK!");
|
||||
}
|
||||
|
||||
m_bridge->SetD3D8CompatibilityMode(true);
|
||||
|
||||
m_d3d8Options = D3D8Options(*m_bridge->GetConfig());
|
||||
|
||||
m_adapterCount = m_d3d9->GetAdapterCount();
|
||||
m_adapterModeCounts.resize(m_adapterCount);
|
||||
m_adapterModes.reserve(m_adapterCount);
|
||||
|
||||
for (UINT adapter = 0; adapter < m_adapterCount; adapter++) {
|
||||
m_adapterModes.emplace_back();
|
||||
|
||||
// cache adapter modes and mode counts for each d3d9 format
|
||||
for (d3d9::D3DFORMAT fmt : ADAPTER_FORMATS) {
|
||||
|
||||
const UINT modeCount = m_d3d9->GetAdapterModeCount(adapter, fmt);
|
||||
for (UINT mode = 0; mode < modeCount; mode++) {
|
||||
|
||||
m_adapterModes[adapter].emplace_back();
|
||||
m_d3d9->EnumAdapterModes(adapter, fmt, mode, &(m_adapterModes[adapter].back()));
|
||||
|
||||
// can't use modeCount as it's only for one fmt
|
||||
m_adapterModeCounts[adapter]++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE D3D8Interface::QueryInterface(REFIID riid, void** ppvObject) {
|
||||
if (ppvObject == nullptr)
|
||||
return E_POINTER;
|
||||
|
||||
*ppvObject = nullptr;
|
||||
|
||||
if (riid == __uuidof(IUnknown)
|
||||
|| riid == __uuidof(IDirect3D8)) {
|
||||
*ppvObject = ref(this);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
Logger::warn("D3D8Interface::QueryInterface: Unknown interface query");
|
||||
Logger::warn(str::format(riid));
|
||||
return E_NOINTERFACE;
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE D3D8Interface::GetAdapterIdentifier(
|
||||
UINT Adapter,
|
||||
DWORD Flags,
|
||||
D3DADAPTER_IDENTIFIER8* pIdentifier) {
|
||||
if (unlikely(pIdentifier == nullptr))
|
||||
return D3DERR_INVALIDCALL;
|
||||
|
||||
// This flag now has the opposite effect.
|
||||
// Either way, WHQLevel will be 1 with Direct3D9Ex
|
||||
if (Flags & D3DENUM_NO_WHQL_LEVEL)
|
||||
Flags &= ~D3DENUM_WHQL_LEVEL;
|
||||
else
|
||||
Flags |= D3DENUM_WHQL_LEVEL;
|
||||
|
||||
d3d9::D3DADAPTER_IDENTIFIER9 identifier9;
|
||||
HRESULT res = m_d3d9->GetAdapterIdentifier(Adapter, Flags, &identifier9);
|
||||
|
||||
if (likely(SUCCEEDED(res))) {
|
||||
strncpy(pIdentifier->Driver, identifier9.Driver, MAX_DEVICE_IDENTIFIER_STRING);
|
||||
strncpy(pIdentifier->Description, identifier9.Description, MAX_DEVICE_IDENTIFIER_STRING);
|
||||
|
||||
pIdentifier->DriverVersion = identifier9.DriverVersion;
|
||||
pIdentifier->VendorId = identifier9.VendorId;
|
||||
pIdentifier->DeviceId = identifier9.DeviceId;
|
||||
pIdentifier->SubSysId = identifier9.SubSysId;
|
||||
pIdentifier->Revision = identifier9.Revision;
|
||||
pIdentifier->DeviceIdentifier = identifier9.DeviceIdentifier;
|
||||
|
||||
pIdentifier->WHQLLevel = identifier9.WHQLLevel;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
HRESULT __stdcall D3D8Interface::EnumAdapterModes(
|
||||
UINT Adapter,
|
||||
UINT Mode,
|
||||
D3DDISPLAYMODE* pMode) {
|
||||
if (Adapter >= m_adapterCount || Mode >= m_adapterModeCounts[Adapter] || pMode == nullptr) {
|
||||
return D3DERR_INVALIDCALL;
|
||||
}
|
||||
|
||||
pMode->Width = m_adapterModes[Adapter][Mode].Width;
|
||||
pMode->Height = m_adapterModes[Adapter][Mode].Height;
|
||||
pMode->RefreshRate = m_adapterModes[Adapter][Mode].RefreshRate;
|
||||
pMode->Format = D3DFORMAT(m_adapterModes[Adapter][Mode].Format);
|
||||
|
||||
return D3D_OK;
|
||||
}
|
||||
|
||||
HRESULT __stdcall D3D8Interface::CreateDevice(
|
||||
UINT Adapter,
|
||||
D3DDEVTYPE DeviceType,
|
||||
HWND hFocusWindow,
|
||||
DWORD BehaviorFlags,
|
||||
D3DPRESENT_PARAMETERS* pPresentationParameters,
|
||||
IDirect3DDevice8** ppReturnedDeviceInterface) {
|
||||
InitReturnPtr(ppReturnedDeviceInterface);
|
||||
|
||||
if (unlikely(pPresentationParameters == nullptr ||
|
||||
ppReturnedDeviceInterface == nullptr))
|
||||
return D3DERR_INVALIDCALL;
|
||||
|
||||
// D3DSWAPEFFECT_COPY can not be used with more than one back buffer.
|
||||
// This is also technically true for D3DSWAPEFFECT_COPY_VSYNC, however
|
||||
// RC Cars depends on it not being rejected.
|
||||
if (unlikely(pPresentationParameters->SwapEffect == D3DSWAPEFFECT_COPY
|
||||
&& pPresentationParameters->BackBufferCount > 1))
|
||||
return D3DERR_INVALIDCALL;
|
||||
|
||||
// In D3D8 nothing except D3DPRESENT_INTERVAL_DEFAULT can be used
|
||||
// as a flag for windowed presentation.
|
||||
if (unlikely(pPresentationParameters->Windowed
|
||||
&& pPresentationParameters->FullScreen_PresentationInterval != D3DPRESENT_INTERVAL_DEFAULT))
|
||||
return D3DERR_INVALIDCALL;
|
||||
|
||||
Com<d3d9::IDirect3DDevice9> pDevice9 = nullptr;
|
||||
d3d9::D3DPRESENT_PARAMETERS params = ConvertPresentParameters9(pPresentationParameters);
|
||||
HRESULT res = m_d3d9->CreateDevice(
|
||||
Adapter,
|
||||
(d3d9::D3DDEVTYPE)DeviceType,
|
||||
hFocusWindow,
|
||||
BehaviorFlags,
|
||||
¶ms,
|
||||
&pDevice9
|
||||
);
|
||||
|
||||
if (likely(SUCCEEDED(res)))
|
||||
*ppReturnedDeviceInterface = ref(new D3D8Device(
|
||||
this, std::move(pDevice9),
|
||||
DeviceType, hFocusWindow, BehaviorFlags,
|
||||
pPresentationParameters
|
||||
));
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
}
|
172
src/d3d8/d3d8_interface.h
Normal file
172
src/d3d8/d3d8_interface.h
Normal file
|
@ -0,0 +1,172 @@
|
|||
#pragma once
|
||||
|
||||
#include "d3d8_include.h"
|
||||
#include "d3d8_d3d9_util.h"
|
||||
#include "d3d8_options.h"
|
||||
#include "d3d8_format.h"
|
||||
#include "../d3d9/d3d9_bridge.h"
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
/**
|
||||
* \brief D3D8 interface implementation
|
||||
*
|
||||
* Implements the IDirect3DDevice8 interfaces
|
||||
* which provides the way to get adapters and create other objects such as \ref IDirect3DDevice8.
|
||||
* similar to \ref DxgiFactory but for D3D8.
|
||||
*/
|
||||
class D3D8Interface final : public ComObjectClamp<IDirect3D8> {
|
||||
|
||||
static constexpr d3d9::D3DFORMAT ADAPTER_FORMATS[] = {
|
||||
d3d9::D3DFMT_A1R5G5B5,
|
||||
//d3d9::D3DFMT_A2R10G10B10, (not in D3D8)
|
||||
d3d9::D3DFMT_A8R8G8B8,
|
||||
d3d9::D3DFMT_R5G6B5,
|
||||
d3d9::D3DFMT_X1R5G5B5,
|
||||
d3d9::D3DFMT_X8R8G8B8
|
||||
};
|
||||
|
||||
public:
|
||||
D3D8Interface();
|
||||
|
||||
HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void** ppvObject);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE RegisterSoftwareDevice(void* pInitializeFunction) {
|
||||
return m_d3d9->RegisterSoftwareDevice(pInitializeFunction);
|
||||
}
|
||||
|
||||
UINT STDMETHODCALLTYPE GetAdapterCount() {
|
||||
return m_d3d9->GetAdapterCount();
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE GetAdapterIdentifier(
|
||||
UINT Adapter,
|
||||
DWORD Flags,
|
||||
D3DADAPTER_IDENTIFIER8* pIdentifier);
|
||||
|
||||
UINT STDMETHODCALLTYPE GetAdapterModeCount(UINT Adapter) {
|
||||
return m_adapterModeCounts[Adapter];
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE EnumAdapterModes(
|
||||
UINT Adapter,
|
||||
UINT Mode,
|
||||
D3DDISPLAYMODE* pMode);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE GetAdapterDisplayMode(UINT Adapter, D3DDISPLAYMODE* pMode) {
|
||||
return m_d3d9->GetAdapterDisplayMode(Adapter, (d3d9::D3DDISPLAYMODE*)pMode);
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE CheckDeviceType(
|
||||
UINT Adapter,
|
||||
D3DDEVTYPE DevType,
|
||||
D3DFORMAT AdapterFormat,
|
||||
D3DFORMAT BackBufferFormat,
|
||||
BOOL bWindowed) {
|
||||
// Ignore the bWindowed parameter when querying D3D9. D3D8 does
|
||||
// identical validations between windowed and fullscreen modes, adhering
|
||||
// to the stricter fullscreen adapter and back buffer format validations.
|
||||
return m_d3d9->CheckDeviceType(
|
||||
Adapter,
|
||||
(d3d9::D3DDEVTYPE)DevType,
|
||||
(d3d9::D3DFORMAT)AdapterFormat,
|
||||
(d3d9::D3DFORMAT)BackBufferFormat,
|
||||
FALSE
|
||||
);
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE CheckDeviceFormat(
|
||||
UINT Adapter,
|
||||
D3DDEVTYPE DeviceType,
|
||||
D3DFORMAT AdapterFormat,
|
||||
DWORD Usage,
|
||||
D3DRESOURCETYPE RType,
|
||||
D3DFORMAT CheckFormat) {
|
||||
return m_d3d9->CheckDeviceFormat(
|
||||
Adapter,
|
||||
(d3d9::D3DDEVTYPE)DeviceType,
|
||||
(d3d9::D3DFORMAT)AdapterFormat,
|
||||
Usage,
|
||||
(d3d9::D3DRESOURCETYPE)RType,
|
||||
(d3d9::D3DFORMAT)CheckFormat
|
||||
);
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE CheckDeviceMultiSampleType(
|
||||
UINT Adapter,
|
||||
D3DDEVTYPE DeviceType,
|
||||
D3DFORMAT SurfaceFormat,
|
||||
BOOL Windowed,
|
||||
D3DMULTISAMPLE_TYPE MultiSampleType) {
|
||||
DWORD* pQualityLevels = nullptr;
|
||||
return m_d3d9->CheckDeviceMultiSampleType(
|
||||
Adapter,
|
||||
(d3d9::D3DDEVTYPE)DeviceType,
|
||||
(d3d9::D3DFORMAT)SurfaceFormat,
|
||||
Windowed,
|
||||
(d3d9::D3DMULTISAMPLE_TYPE)MultiSampleType,
|
||||
pQualityLevels
|
||||
);
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE CheckDepthStencilMatch(
|
||||
UINT Adapter,
|
||||
D3DDEVTYPE DeviceType,
|
||||
D3DFORMAT AdapterFormat,
|
||||
D3DFORMAT RenderTargetFormat,
|
||||
D3DFORMAT DepthStencilFormat) {
|
||||
if (isSupportedDepthStencilFormat(DepthStencilFormat))
|
||||
return m_d3d9->CheckDepthStencilMatch(
|
||||
Adapter,
|
||||
(d3d9::D3DDEVTYPE)DeviceType,
|
||||
(d3d9::D3DFORMAT)AdapterFormat,
|
||||
(d3d9::D3DFORMAT)RenderTargetFormat,
|
||||
(d3d9::D3DFORMAT)DepthStencilFormat
|
||||
);
|
||||
|
||||
return D3DERR_NOTAVAILABLE;
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE GetDeviceCaps(
|
||||
UINT Adapter,
|
||||
D3DDEVTYPE DeviceType,
|
||||
D3DCAPS8* pCaps) {
|
||||
if (unlikely(pCaps == nullptr))
|
||||
return D3DERR_INVALIDCALL;
|
||||
|
||||
d3d9::D3DCAPS9 caps9;
|
||||
HRESULT res = m_d3d9->GetDeviceCaps(Adapter, (d3d9::D3DDEVTYPE)DeviceType, &caps9);
|
||||
|
||||
if (likely(SUCCEEDED(res)))
|
||||
ConvertCaps8(caps9, pCaps);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
HMONITOR STDMETHODCALLTYPE GetAdapterMonitor(UINT Adapter) {
|
||||
return m_d3d9->GetAdapterMonitor(Adapter);
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE CreateDevice(
|
||||
UINT Adapter,
|
||||
D3DDEVTYPE DeviceType,
|
||||
HWND hFocusWindow,
|
||||
DWORD BehaviorFlags,
|
||||
D3DPRESENT_PARAMETERS* pPresentationParameters,
|
||||
IDirect3DDevice8** ppReturnedDeviceInterface);
|
||||
|
||||
|
||||
const D3D8Options& GetOptions() { return m_d3d8Options; }
|
||||
|
||||
private:
|
||||
|
||||
UINT m_adapterCount;
|
||||
std::vector<UINT> m_adapterModeCounts;
|
||||
std::vector<std::vector<d3d9::D3DDISPLAYMODE>> m_adapterModes;
|
||||
|
||||
Com<d3d9::IDirect3D9> m_d3d9;
|
||||
Com<IDxvkD3D8InterfaceBridge> m_bridge;
|
||||
D3D8Options m_d3d8Options;
|
||||
};
|
||||
|
||||
}
|
124
src/d3d8/d3d8_main.cpp
Normal file
124
src/d3d8/d3d8_main.cpp
Normal file
|
@ -0,0 +1,124 @@
|
|||
#include "d3d8_interface.h"
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
Logger Logger::s_instance("d3d8.log");
|
||||
|
||||
HRESULT CreateD3D8(IDirect3D8** ppDirect3D8) {
|
||||
if (!ppDirect3D8)
|
||||
return D3DERR_INVALIDCALL;
|
||||
|
||||
*ppDirect3D8 = ref(new D3D8Interface());
|
||||
return D3D_OK;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
|
||||
DLLEXPORT HRESULT __stdcall ValidatePixelShader(
|
||||
const DWORD* pPixelShader,
|
||||
const D3DCAPS8* pCaps,
|
||||
BOOL ErrorReturn,
|
||||
char** pErrorString) {
|
||||
HRESULT res = S_OK;
|
||||
std::string errorMessage = "";
|
||||
|
||||
// ValidatePixelShader returns immediately in case of a NULL pPixelShader
|
||||
if (unlikely(pPixelShader == nullptr)) {
|
||||
dxvk::Logger::warn("D3D8: ValidatePixelShader: Null pPixelShader");
|
||||
return E_FAIL;
|
||||
} else {
|
||||
const uint32_t majorVersion = D3DSHADER_VERSION_MAJOR(pPixelShader[0]);
|
||||
const uint32_t minorVersion = D3DSHADER_VERSION_MINOR(pPixelShader[0]);
|
||||
|
||||
if (unlikely(majorVersion != 1 || minorVersion > 4)) {
|
||||
errorMessage = dxvk::str::format("D3D8: ValidatePixelShader: Unsupported PS version ",
|
||||
majorVersion, ".", minorVersion);
|
||||
res = E_FAIL;
|
||||
} else if (unlikely(pCaps && pPixelShader[0] > pCaps->PixelShaderVersion)) {
|
||||
errorMessage = dxvk::str::format("D3D8: ValidatePixelShader: Caps: Unsupported PS version ",
|
||||
majorVersion, ".", minorVersion);
|
||||
res = E_FAIL;
|
||||
}
|
||||
}
|
||||
|
||||
if (unlikely(res != S_OK)) {
|
||||
dxvk::Logger::warn(errorMessage);
|
||||
|
||||
if (!ErrorReturn)
|
||||
errorMessage = "";
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
if (pErrorString != nullptr) {
|
||||
const size_t errorMessageSize = errorMessage.size() + 1;
|
||||
// Wine tests call HeapFree() on the returned error string,
|
||||
// so the expectation is for it to be allocated on the heap.
|
||||
*pErrorString = (char*) HeapAlloc(GetProcessHeap(), 0, errorMessageSize);
|
||||
if (*pErrorString)
|
||||
memcpy(*pErrorString, errorMessage.c_str(), errorMessageSize);
|
||||
}
|
||||
#endif
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
DLLEXPORT HRESULT __stdcall ValidateVertexShader(
|
||||
const DWORD* pVertexShader,
|
||||
const DWORD* pVertexDecl,
|
||||
const D3DCAPS8* pCaps,
|
||||
BOOL ErrorReturn,
|
||||
char** pErrorString) {
|
||||
HRESULT res = S_OK;
|
||||
std::string errorMessage = "";
|
||||
|
||||
if (unlikely(pVertexShader == nullptr)) {
|
||||
errorMessage = "D3D8: ValidateVertexShader: Null pVertexShader";
|
||||
res = E_FAIL;
|
||||
} else {
|
||||
const uint32_t majorVersion = D3DSHADER_VERSION_MAJOR(pVertexShader[0]);
|
||||
const uint32_t minorVersion = D3DSHADER_VERSION_MINOR(pVertexShader[0]);
|
||||
|
||||
if (unlikely(majorVersion != 1 || minorVersion > 1)) {
|
||||
errorMessage = dxvk::str::format("D3D8: ValidateVertexShader: Unsupported VS version ",
|
||||
majorVersion, ".", minorVersion);
|
||||
res = E_FAIL;
|
||||
} else if (unlikely(pCaps && pVertexShader[0] > pCaps->VertexShaderVersion)) {
|
||||
errorMessage = dxvk::str::format("D3D8: ValidateVertexShader: Caps: Unsupported VS version ",
|
||||
majorVersion, ".", minorVersion);
|
||||
res = E_FAIL;
|
||||
}
|
||||
}
|
||||
|
||||
if (unlikely(res != S_OK)) {
|
||||
dxvk::Logger::warn(errorMessage);
|
||||
|
||||
if (!ErrorReturn)
|
||||
errorMessage = "";
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
if (pErrorString != nullptr) {
|
||||
const size_t errorMessageSize = errorMessage.size() + 1;
|
||||
// Wine tests call HeapFree() on the returned error string,
|
||||
// so the expectation is for it to be allocated on the heap.
|
||||
*pErrorString = (char*) HeapAlloc(GetProcessHeap(), 0, errorMessageSize);
|
||||
if (*pErrorString)
|
||||
memcpy(*pErrorString, errorMessage.c_str(), errorMessageSize);
|
||||
}
|
||||
#endif
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
DLLEXPORT void __stdcall DebugSetMute() {}
|
||||
|
||||
DLLEXPORT IDirect3D8* __stdcall Direct3DCreate8(UINT nSDKVersion) {
|
||||
IDirect3D8* pDirect3D = nullptr;
|
||||
dxvk::CreateD3D8(&pDirect3D);
|
||||
|
||||
return pDirect3D;
|
||||
}
|
||||
|
||||
}
|
9
src/d3d8/d3d8_multithread.cpp
Normal file
9
src/d3d8/d3d8_multithread.cpp
Normal file
|
@ -0,0 +1,9 @@
|
|||
#include "d3d8_device.h"
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
D3D8Multithread::D3D8Multithread(
|
||||
BOOL Protected)
|
||||
: m_protected( Protected ) { }
|
||||
|
||||
}
|
77
src/d3d8/d3d8_multithread.h
Normal file
77
src/d3d8/d3d8_multithread.h
Normal file
|
@ -0,0 +1,77 @@
|
|||
#pragma once
|
||||
|
||||
#include "d3d8_include.h"
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
/**
|
||||
* \brief Device lock
|
||||
*
|
||||
* Lightweight RAII wrapper that implements
|
||||
* a subset of the functionality provided by
|
||||
* \c std::unique_lock, with the goal of being
|
||||
* cheaper to construct and destroy.
|
||||
*/
|
||||
class D3D8DeviceLock {
|
||||
|
||||
public:
|
||||
|
||||
D3D8DeviceLock()
|
||||
: m_mutex(nullptr) { }
|
||||
|
||||
D3D8DeviceLock(sync::RecursiveSpinlock& mutex)
|
||||
: m_mutex(&mutex) {
|
||||
mutex.lock();
|
||||
}
|
||||
|
||||
D3D8DeviceLock(D3D8DeviceLock&& other)
|
||||
: m_mutex(other.m_mutex) {
|
||||
other.m_mutex = nullptr;
|
||||
}
|
||||
|
||||
D3D8DeviceLock& operator = (D3D8DeviceLock&& other) {
|
||||
if (m_mutex)
|
||||
m_mutex->unlock();
|
||||
|
||||
m_mutex = other.m_mutex;
|
||||
other.m_mutex = nullptr;
|
||||
return *this;
|
||||
}
|
||||
|
||||
~D3D8DeviceLock() {
|
||||
if (m_mutex != nullptr)
|
||||
m_mutex->unlock();
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
sync::RecursiveSpinlock* m_mutex;
|
||||
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* \brief D3D8 context lock
|
||||
*/
|
||||
class D3D8Multithread {
|
||||
|
||||
public:
|
||||
|
||||
D3D8Multithread(
|
||||
BOOL Protected);
|
||||
|
||||
D3D8DeviceLock AcquireLock() {
|
||||
return m_protected
|
||||
? D3D8DeviceLock(m_mutex)
|
||||
: D3D8DeviceLock();
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
BOOL m_protected;
|
||||
|
||||
sync::RecursiveSpinlock m_mutex;
|
||||
|
||||
};
|
||||
|
||||
}
|
57
src/d3d8/d3d8_options.cpp
Normal file
57
src/d3d8/d3d8_options.cpp
Normal file
|
@ -0,0 +1,57 @@
|
|||
#include "d3d8_options.h"
|
||||
|
||||
#include "../d3d9/d3d9_bridge.h"
|
||||
#include "../util/config/config.h"
|
||||
#include "../util/util_string.h"
|
||||
|
||||
#include <charconv>
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
static inline uint32_t parseDword(std::string_view str) {
|
||||
uint32_t value = std::numeric_limits<uint32_t>::max();
|
||||
std::from_chars(str.data(), str.data() + str.size(), value);
|
||||
return value;
|
||||
}
|
||||
|
||||
void D3D8Options::parseVsDecl(const std::string& decl) {
|
||||
if (decl.empty())
|
||||
return;
|
||||
|
||||
if (decl.find_first_of("0123456789") == std::string::npos) {
|
||||
Logger::warn(str::format("D3D8: Invalid forceVsDecl value: ", decl));
|
||||
Logger::warn("D3D8: Expected numbers.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (decl.find_first_of(":,;") == std::string::npos) {
|
||||
Logger::warn(str::format("D3D8: Invalid forceVsDecl value: ", decl));
|
||||
Logger::warn("D3D8: Expected a comma-separated list of colon-separated number pairs.");
|
||||
return;
|
||||
}
|
||||
|
||||
std::vector<std::string_view> decls = str::split(decl, ":,;");
|
||||
|
||||
if (decls.size() % 2 != 0) {
|
||||
Logger::warn(str::format("D3D8: Invalid forceVsDecl value: ", decl));
|
||||
Logger::warn("D3D8: Expected an even number of numbers.");
|
||||
return;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < decls.size(); i += 2) {
|
||||
uint32_t reg = parseDword(decls[i]);
|
||||
uint32_t type = parseDword(decls[i+1]);
|
||||
if (reg > D3DVSDE_NORMAL2) {
|
||||
Logger::warn(str::format("D3D8: Invalid forceVsDecl register number: ", decls[i]));
|
||||
return;
|
||||
}
|
||||
if (type > D3DVSDT_SHORT4) {
|
||||
Logger::warn(str::format("D3D8: Invalid forceVsDecl type: ", decls[i+1]));
|
||||
return;
|
||||
}
|
||||
|
||||
forceVsDecl.emplace_back(D3DVSDE_REGISTER(reg), D3DVSDT_TYPE(type));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
65
src/d3d8/d3d8_options.h
Normal file
65
src/d3d8/d3d8_options.h
Normal file
|
@ -0,0 +1,65 @@
|
|||
#pragma once
|
||||
|
||||
#include "d3d8_include.h"
|
||||
#include "../d3d9/d3d9_bridge.h"
|
||||
#include "../util/config/config.h"
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
struct D3D8Options {
|
||||
|
||||
/// Some games rely on undefined behavior by using undeclared vertex shader inputs.
|
||||
/// The simplest way to fix them is to simply modify their vertex shader decl.
|
||||
///
|
||||
/// This option takes a comma-separated list of colon-separated number pairs, where
|
||||
/// the first number is a D3DVSDE_REGISTER value, the second is a D3DVSDT_TYPE value.
|
||||
/// e.g. "0:2,3:2,7:1" for float3 position : v0, float3 normal : v3, float2 uv : v7
|
||||
std::vector<std::pair<D3DVSDE_REGISTER, D3DVSDT_TYPE>> forceVsDecl;
|
||||
|
||||
/// Specialized drawcall batcher, typically for games that draw a lot of similar
|
||||
/// geometry in separate drawcalls (sometimes even one triangle at a time).
|
||||
///
|
||||
/// May hurt performance outside of specifc games that benefit from it.
|
||||
bool batching = false;
|
||||
|
||||
/// The Lord of the Rings: The Fellowship of the Ring tries to create a P8 texture
|
||||
/// in D3DPOOL_MANAGED on Nvidia and Intel, which fails, but has a separate code
|
||||
/// path for ATI/AMD that creates it in D3DPOOL_SCRATCH instead, which works.
|
||||
///
|
||||
/// The internal logic determining this path doesn't seem to be d3d-related, but
|
||||
/// the game works universally if we mimic its own ATI/AMD workaround during P8
|
||||
/// texture creation.
|
||||
///
|
||||
/// Early Nvidia GPUs, such as the GeForce 4 generation cards, included and exposed
|
||||
/// P8 texture support. However, it was no longer advertised with cards in the FX series
|
||||
/// and above. Most likely ATI/AMD drivers never supported P8 in the first place.
|
||||
bool placeP8InScratch = false;
|
||||
|
||||
/// Rayman 3 relies on D3DLOCK_DISCARD being ignored for everything except D3DUSAGE_DYNAMIC +
|
||||
/// D3DUSAGE_WRITEONLY buffers, however this approach incurs a performance penalty.
|
||||
///
|
||||
/// Some titles might abuse this early D3D8 quirk, however at some point in its history
|
||||
/// it was brought in line with standard D3D9 behavior.
|
||||
bool forceLegacyDiscard = false;
|
||||
|
||||
/// Splinter Cell expects shadow map texture coordinates to be perspective divided
|
||||
/// even though D3DTTFF_PROJECTED is never set for any texture coordinates. This flag
|
||||
/// forces that flag for the necessary stages when a depth texture is bound to slot 0
|
||||
bool shadowPerspectiveDivide = false;
|
||||
|
||||
D3D8Options() {}
|
||||
|
||||
D3D8Options(const Config& config) {
|
||||
auto forceVsDeclStr = config.getOption<std::string>("d3d8.forceVsDecl", "");
|
||||
batching = config.getOption<bool> ("d3d8.batching", batching);
|
||||
placeP8InScratch = config.getOption<bool> ("d3d8.placeP8InScratch", placeP8InScratch);
|
||||
forceLegacyDiscard = config.getOption<bool> ("d3d8.forceLegacyDiscard", forceLegacyDiscard);
|
||||
shadowPerspectiveDivide = config.getOption<bool> ("d3d8.shadowPerspectiveDivide", shadowPerspectiveDivide);
|
||||
|
||||
parseVsDecl(forceVsDeclStr);
|
||||
}
|
||||
|
||||
void parseVsDecl(const std::string& decl);
|
||||
};
|
||||
|
||||
}
|
117
src/d3d8/d3d8_resource.h
Normal file
117
src/d3d8/d3d8_resource.h
Normal file
|
@ -0,0 +1,117 @@
|
|||
#pragma once
|
||||
|
||||
/** Implements IDirect3DResource8
|
||||
*
|
||||
* - SetPrivateData, GetPrivateData, FreePrivateData
|
||||
* - SetPriority, GetPriority
|
||||
*
|
||||
* - Subclasses provide: PreLoad, GetType
|
||||
*/
|
||||
|
||||
#include "d3d8_device_child.h"
|
||||
#include "../util/com/com_private_data.h"
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
template <typename D3D9, typename D3D8>
|
||||
class D3D8Resource : public D3D8DeviceChild<D3D9, D3D8> {
|
||||
|
||||
public:
|
||||
|
||||
D3D8Resource(D3D8Device* pDevice, D3DPOOL Pool, Com<D3D9>&& Object)
|
||||
: D3D8DeviceChild<D3D9, D3D8>(pDevice, std::move(Object))
|
||||
, m_pool ( Pool )
|
||||
, m_priority ( 0 ) { }
|
||||
|
||||
HRESULT STDMETHODCALLTYPE SetPrivateData(
|
||||
REFGUID refguid,
|
||||
const void* pData,
|
||||
DWORD SizeOfData,
|
||||
DWORD Flags) final {
|
||||
HRESULT hr;
|
||||
if (Flags & D3DSPD_IUNKNOWN) {
|
||||
if(unlikely(SizeOfData != sizeof(IUnknown*)))
|
||||
return D3DERR_INVALIDCALL;
|
||||
IUnknown* unknown =
|
||||
const_cast<IUnknown*>(
|
||||
reinterpret_cast<const IUnknown*>(pData));
|
||||
hr = m_privateData.setInterface(
|
||||
refguid, unknown);
|
||||
}
|
||||
else
|
||||
hr = m_privateData.setData(
|
||||
refguid, SizeOfData, pData);
|
||||
|
||||
if (unlikely(FAILED(hr)))
|
||||
return D3DERR_INVALIDCALL;
|
||||
|
||||
return D3D_OK;
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE GetPrivateData(
|
||||
REFGUID refguid,
|
||||
void* pData,
|
||||
DWORD* pSizeOfData) final {
|
||||
if (unlikely(pData == nullptr && pSizeOfData == nullptr))
|
||||
return D3DERR_NOTFOUND;
|
||||
|
||||
HRESULT hr = m_privateData.getData(
|
||||
refguid, reinterpret_cast<UINT*>(pSizeOfData), pData);
|
||||
|
||||
if (unlikely(FAILED(hr))) {
|
||||
if(hr == DXGI_ERROR_MORE_DATA)
|
||||
return D3DERR_MOREDATA;
|
||||
else if (hr == DXGI_ERROR_NOT_FOUND)
|
||||
return D3DERR_NOTFOUND;
|
||||
else
|
||||
return D3DERR_INVALIDCALL;
|
||||
}
|
||||
|
||||
return D3D_OK;
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE FreePrivateData(REFGUID refguid) final {
|
||||
HRESULT hr = m_privateData.setData(refguid, 0, nullptr);
|
||||
|
||||
if (unlikely(FAILED(hr)))
|
||||
return D3DERR_INVALIDCALL;
|
||||
|
||||
return D3D_OK;
|
||||
}
|
||||
|
||||
DWORD STDMETHODCALLTYPE SetPriority(DWORD PriorityNew) {
|
||||
// Priority can only be set for D3DPOOL_MANAGED resources
|
||||
if (likely(m_pool == D3DPOOL_MANAGED)) {
|
||||
DWORD oldPriority = m_priority;
|
||||
m_priority = PriorityNew;
|
||||
return oldPriority;
|
||||
}
|
||||
|
||||
return m_priority;
|
||||
}
|
||||
|
||||
DWORD STDMETHODCALLTYPE GetPriority() {
|
||||
return m_priority;
|
||||
}
|
||||
|
||||
virtual IUnknown* GetInterface(REFIID riid) override try {
|
||||
return D3D8DeviceChild<D3D9, D3D8>::GetInterface(riid);
|
||||
} catch (HRESULT err) {
|
||||
if (riid == __uuidof(IDirect3DResource8))
|
||||
return this;
|
||||
|
||||
throw err;
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
const D3DPOOL m_pool;
|
||||
DWORD m_priority;
|
||||
|
||||
private:
|
||||
|
||||
ComPrivateData m_privateData;
|
||||
|
||||
};
|
||||
|
||||
}
|
338
src/d3d8/d3d8_shader.cpp
Normal file
338
src/d3d8/d3d8_shader.cpp
Normal file
|
@ -0,0 +1,338 @@
|
|||
#include "d3d8_shader.h"
|
||||
|
||||
#define VSD_SHIFT_MASK(token, field) ((token & field ## MASK) >> field ## SHIFT)
|
||||
#define VSD_ENCODE(token, field) ((token << field ## _SHIFT) & field ## _MASK)
|
||||
|
||||
// Magic number from D3DVSD_SKIP(...)
|
||||
#define VSD_SKIP_FLAG 0x10000000
|
||||
|
||||
// This bit is set on all parameter (non-instruction) tokens.
|
||||
#define VS_BIT_PARAM 0x80000000
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
static constexpr int D3D8_NUM_VERTEX_INPUT_REGISTERS = 17;
|
||||
|
||||
/**
|
||||
* Standard mapping of vertex input registers v0-v16 to D3D9 usages and usage indices
|
||||
* (See D3DVSDE_REGISTER values in d3d8types.h or DirectX 8 docs for vertex shader input registers vN)
|
||||
*
|
||||
* \cite https://learn.microsoft.com/en-us/windows/win32/direct3d9/mapping-between-a-directx-9-declaration-and-directx-8
|
||||
*/
|
||||
static constexpr BYTE D3D8_VERTEX_INPUT_REGISTERS[D3D8_NUM_VERTEX_INPUT_REGISTERS][2] = {
|
||||
{d3d9::D3DDECLUSAGE_POSITION, 0}, // dcl_position v0
|
||||
{d3d9::D3DDECLUSAGE_BLENDWEIGHT, 0}, // dcl_blendweight v1
|
||||
{d3d9::D3DDECLUSAGE_BLENDINDICES, 0}, // dcl_blendindices v2
|
||||
{d3d9::D3DDECLUSAGE_NORMAL, 0}, // dcl_normal v3
|
||||
{d3d9::D3DDECLUSAGE_PSIZE, 0}, // dcl_psize v4
|
||||
{d3d9::D3DDECLUSAGE_COLOR, 0}, // dcl_color v5 ; diffuse
|
||||
{d3d9::D3DDECLUSAGE_COLOR, 1}, // dcl_color1 v6 ; specular
|
||||
{d3d9::D3DDECLUSAGE_TEXCOORD, 0}, // dcl_texcoord0 v7
|
||||
{d3d9::D3DDECLUSAGE_TEXCOORD, 1}, // dcl_texcoord1 v8
|
||||
{d3d9::D3DDECLUSAGE_TEXCOORD, 2}, // dcl_texcoord2 v9
|
||||
{d3d9::D3DDECLUSAGE_TEXCOORD, 3}, // dcl_texcoord3 v10
|
||||
{d3d9::D3DDECLUSAGE_TEXCOORD, 4}, // dcl_texcoord4 v11
|
||||
{d3d9::D3DDECLUSAGE_TEXCOORD, 5}, // dcl_texcoord5 v12
|
||||
{d3d9::D3DDECLUSAGE_TEXCOORD, 6}, // dcl_texcoord6 v13
|
||||
{d3d9::D3DDECLUSAGE_TEXCOORD, 7}, // dcl_texcoord7 v14
|
||||
{d3d9::D3DDECLUSAGE_POSITION, 1}, // dcl_position1 v15 ; position 2
|
||||
{d3d9::D3DDECLUSAGE_NORMAL, 1}, // dcl_normal1 v16 ; normal 2
|
||||
};
|
||||
|
||||
/** Width in bytes of each d3d9::D3DDECLTYPE or d3d8 D3DVSDT_TYPE */
|
||||
static constexpr BYTE D3D9_DECL_TYPE_SIZES[d3d9::MAXD3DDECLTYPE + 1] = {
|
||||
4, // FLOAT1
|
||||
8, // FLOAT2
|
||||
12, // FLOAT3
|
||||
16, // FLOAT4
|
||||
4, // D3DCOLOR
|
||||
|
||||
4, // UBYTE4
|
||||
4, // SHORT2
|
||||
8, // SHORT4
|
||||
|
||||
// The following are for vs2.0+ //
|
||||
4, // UBYTE4N
|
||||
4, // SHORT2N
|
||||
8, // SHORT4N
|
||||
4, // USHORT2N
|
||||
8, // USHORT4N
|
||||
6, // UDEC3
|
||||
6, // DEC3N
|
||||
8, // FLOAT16_2
|
||||
16, // FLOAT16_4
|
||||
|
||||
0 // UNUSED
|
||||
};
|
||||
|
||||
/**
|
||||
* Encodes a \ref DxsoShaderInstruction
|
||||
*
|
||||
* \param [in] opcode DxsoOpcode
|
||||
* \cite https://learn.microsoft.com/en-us/windows-hardware/drivers/display/instruction-token
|
||||
*/
|
||||
constexpr DWORD encodeInstruction(d3d9::D3DSHADER_INSTRUCTION_OPCODE_TYPE opcode) {
|
||||
DWORD token = 0;
|
||||
token |= opcode & 0xFFFF; // bits 0:15
|
||||
return token;
|
||||
}
|
||||
|
||||
/**
|
||||
* Encodes a \ref DxsoRegister
|
||||
*
|
||||
* \param [in] regType DxsoRegisterType
|
||||
* \cite https://learn.microsoft.com/en-us/windows-hardware/drivers/display/destination-parameter-token
|
||||
*/
|
||||
constexpr DWORD encodeDestRegister(d3d9::D3DSHADER_PARAM_REGISTER_TYPE type, UINT reg) {
|
||||
DWORD token = 0;
|
||||
token |= reg & 0x7FF; // bits 0:10 num
|
||||
token |= ((type & 0x07) << 28); // bits 28:30 type[0:2]
|
||||
token |= ((type & 0x18) >> 3) << 11; // bits 11:12 type[3:4]
|
||||
// UINT addrMode : 1; // bit 13 hasRelative
|
||||
token |= 0b1111 << 16; // bits 16:19 DxsoRegMask
|
||||
// UINT resultModifier : 3; // bits 20:23
|
||||
// UINT resultShift : 3; // bits 24:27
|
||||
token |= 1 << 31; // bit 31 always 1
|
||||
return token;
|
||||
}
|
||||
|
||||
/**
|
||||
* Encodes a \ref DxsoDeclaration
|
||||
*
|
||||
* \cite https://learn.microsoft.com/en-us/windows-hardware/drivers/display/dcl-instruction
|
||||
*/
|
||||
constexpr DWORD encodeDeclaration(d3d9::D3DDECLUSAGE usage, DWORD index) {
|
||||
DWORD token = 0;
|
||||
token |= VSD_ENCODE(usage, D3DSP_DCL_USAGE); // bits 0:4 DxsoUsage (TODO: missing MSB)
|
||||
token |= VSD_ENCODE(index, D3DSP_DCL_USAGEINDEX); // bits 16:19 usageIndex
|
||||
token |= 1 << 31; // bit 31 always 1
|
||||
return token;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a D3D8 vertex shader + declaration
|
||||
* to a D3D9 vertex shader + declaration.
|
||||
*/
|
||||
D3D9VertexShaderCode TranslateVertexShader8(
|
||||
const DWORD* pDeclaration,
|
||||
const DWORD* pFunction,
|
||||
const D3D8Options& options) {
|
||||
using d3d9::D3DDECLTYPE;
|
||||
using d3d9::D3DDECLTYPE_UNUSED;
|
||||
|
||||
D3D9VertexShaderCode result;
|
||||
|
||||
std::vector<DWORD>& tokens = result.function;
|
||||
std::vector<DWORD> defs; // Constant definitions
|
||||
|
||||
// shaderInputRegisters:
|
||||
// set bit N to enable input register vN
|
||||
DWORD shaderInputRegisters = 0;
|
||||
|
||||
d3d9::D3DVERTEXELEMENT9* vertexElements = result.declaration;
|
||||
unsigned int elementIdx = 0;
|
||||
|
||||
// These are used for pDeclaration and pFunction
|
||||
int i = 0;
|
||||
DWORD token;
|
||||
|
||||
std::stringstream dbg;
|
||||
dbg << "D3D8: Vertex Declaration Tokens:\n\t";
|
||||
|
||||
WORD currentStream = 0;
|
||||
WORD currentOffset = 0;
|
||||
|
||||
auto addVertexElement = [&] (D3DVSDE_REGISTER reg, D3DVSDT_TYPE type) {
|
||||
vertexElements[elementIdx].Stream = currentStream;
|
||||
vertexElements[elementIdx].Offset = currentOffset;
|
||||
vertexElements[elementIdx].Method = d3d9::D3DDECLMETHOD_DEFAULT;
|
||||
vertexElements[elementIdx].Type = D3DDECLTYPE(type); // (D3DVSDT_TYPE values map directly to D3DDECLTYPE)
|
||||
vertexElements[elementIdx].Usage = D3D8_VERTEX_INPUT_REGISTERS[reg][0];
|
||||
vertexElements[elementIdx].UsageIndex = D3D8_VERTEX_INPUT_REGISTERS[reg][1];
|
||||
|
||||
// Increase stream offset
|
||||
currentOffset += D3D9_DECL_TYPE_SIZES[type];
|
||||
|
||||
// Enable register vn
|
||||
shaderInputRegisters |= 1 << reg;
|
||||
|
||||
// Finished with this element
|
||||
elementIdx++;
|
||||
};
|
||||
|
||||
// Remap d3d8 decl tokens to d3d9 vertex elements,
|
||||
// and enable bits on shaderInputRegisters for each.
|
||||
if (options.forceVsDecl.size() == 0) do {
|
||||
token = pDeclaration[i++];
|
||||
|
||||
D3DVSD_TOKENTYPE tokenType = D3DVSD_TOKENTYPE(VSD_SHIFT_MASK(token, D3DVSD_TOKENTYPE));
|
||||
|
||||
switch (tokenType) {
|
||||
case D3DVSD_TOKEN_NOP:
|
||||
dbg << "NOP";
|
||||
break;
|
||||
case D3DVSD_TOKEN_STREAM: {
|
||||
dbg << "STREAM ";
|
||||
|
||||
// TODO: D3DVSD_STREAM_TESS
|
||||
if (token & D3DVSD_STREAMTESSMASK) {
|
||||
dbg << "TESS";
|
||||
}
|
||||
|
||||
DWORD streamNum = VSD_SHIFT_MASK(token, D3DVSD_STREAMNUMBER);
|
||||
|
||||
currentStream = WORD(streamNum);
|
||||
currentOffset = 0; // reset offset
|
||||
|
||||
dbg << ", num=" << streamNum;
|
||||
break;
|
||||
}
|
||||
case D3DVSD_TOKEN_STREAMDATA: {
|
||||
|
||||
dbg << "STREAMDATA ";
|
||||
|
||||
// D3DVSD_SKIP
|
||||
if (token & VSD_SKIP_FLAG) {
|
||||
auto skipCount = VSD_SHIFT_MASK(token, D3DVSD_SKIPCOUNT);
|
||||
dbg << "SKIP " << " count=" << skipCount;
|
||||
currentOffset += WORD(skipCount) * sizeof(DWORD);
|
||||
break;
|
||||
}
|
||||
|
||||
// D3DVSD_REG
|
||||
DWORD dataLoadType = VSD_SHIFT_MASK(token, D3DVSD_DATALOADTYPE);
|
||||
|
||||
if ( dataLoadType == 0 ) { // vertex
|
||||
D3DVSDT_TYPE type = D3DVSDT_TYPE(VSD_SHIFT_MASK(token, D3DVSD_DATATYPE));
|
||||
D3DVSDE_REGISTER reg = D3DVSDE_REGISTER(VSD_SHIFT_MASK(token, D3DVSD_VERTEXREG));
|
||||
|
||||
addVertexElement(reg, type);
|
||||
|
||||
dbg << "type=" << type << ", register=" << reg;
|
||||
} else {
|
||||
// TODO: When would this bit be 1?
|
||||
dbg << "D3DVSD_DATALOADTYPE " << dataLoadType;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case D3DVSD_TOKEN_TESSELLATOR:
|
||||
dbg << "TESSELLATOR " << std::hex << token;
|
||||
// TODO: D3DVSD_TOKEN_TESSELLATOR
|
||||
break;
|
||||
case D3DVSD_TOKEN_CONSTMEM: {
|
||||
dbg << "CONSTMEM ";
|
||||
DWORD count = VSD_SHIFT_MASK(token, D3DVSD_CONSTCOUNT);
|
||||
DWORD regCount = count * 4;
|
||||
DWORD addr = VSD_SHIFT_MASK(token, D3DVSD_CONSTADDRESS);
|
||||
DWORD rs = VSD_SHIFT_MASK(token, D3DVSD_CONSTRS);
|
||||
|
||||
dbg << "count=" << count << ", addr=" << addr << ", rs=" << rs;
|
||||
|
||||
// Add a DEF instruction for each constant
|
||||
for (DWORD j = 0; j < regCount; j += 4) {
|
||||
defs.push_back(encodeInstruction(d3d9::D3DSIO_DEF));
|
||||
defs.push_back(encodeDestRegister(d3d9::D3DSPR_CONST2, addr));
|
||||
defs.push_back(pDeclaration[i+j+0]);
|
||||
defs.push_back(pDeclaration[i+j+1]);
|
||||
defs.push_back(pDeclaration[i+j+2]);
|
||||
defs.push_back(pDeclaration[i+j+3]);
|
||||
addr++;
|
||||
}
|
||||
i += regCount;
|
||||
break;
|
||||
}
|
||||
case D3DVSD_TOKEN_EXT: {
|
||||
dbg << "EXT " << std::hex << token << " ";
|
||||
DWORD extInfo = VSD_SHIFT_MASK(token, D3DVSD_EXTINFO);
|
||||
DWORD extCount = VSD_SHIFT_MASK(token, D3DVSD_EXTCOUNT);
|
||||
dbg << "info=" << extInfo << ", count=" << extCount;
|
||||
break;
|
||||
}
|
||||
case D3DVSD_TOKEN_END: {
|
||||
vertexElements[elementIdx++] = D3DDECL_END();
|
||||
dbg << "END";
|
||||
break;
|
||||
}
|
||||
default:
|
||||
dbg << "UNKNOWN TYPE";
|
||||
break;
|
||||
}
|
||||
dbg << "\n\t";
|
||||
//dbg << std::hex << token << " ";
|
||||
} while (token != D3DVSD_END());
|
||||
|
||||
Logger::debug(dbg.str());
|
||||
|
||||
// If forceVsDecl is set, use that decl instead.
|
||||
if (options.forceVsDecl.size() > 0) {
|
||||
for (auto [reg, type] : options.forceVsDecl) {
|
||||
addVertexElement(reg, type);
|
||||
}
|
||||
vertexElements[elementIdx++] = D3DDECL_END();
|
||||
}
|
||||
|
||||
if (pFunction != nullptr) {
|
||||
// Copy first token (version)
|
||||
tokens.push_back(pFunction[0]);
|
||||
|
||||
DWORD vsMajor = D3DSHADER_VERSION_MAJOR(pFunction[0]);
|
||||
DWORD vsMinor = D3DSHADER_VERSION_MINOR(pFunction[0]);
|
||||
Logger::debug(str::format("VS version: ", vsMajor, ".", vsMinor));
|
||||
|
||||
// Insert dcl instructions
|
||||
for (int vn = 0; vn < D3D8_NUM_VERTEX_INPUT_REGISTERS; vn++) {
|
||||
|
||||
// If bit N is set then we need to dcl register vN
|
||||
if ((shaderInputRegisters & (1 << vn)) != 0) {
|
||||
|
||||
Logger::debug(str::format("\tShader Input Regsiter: v", vn));
|
||||
|
||||
DWORD usage = D3D8_VERTEX_INPUT_REGISTERS[vn][0];
|
||||
DWORD index = D3D8_VERTEX_INPUT_REGISTERS[vn][1];
|
||||
|
||||
tokens.push_back(encodeInstruction(d3d9::D3DSIO_DCL)); // dcl opcode
|
||||
tokens.push_back(encodeDeclaration(d3d9::D3DDECLUSAGE(usage), index)); // usage token
|
||||
tokens.push_back(encodeDestRegister(d3d9::D3DSPR_INPUT, vn)); // dest register num
|
||||
}
|
||||
}
|
||||
|
||||
// Copy constant defs
|
||||
for (DWORD def : defs) {
|
||||
tokens.push_back(def);
|
||||
}
|
||||
|
||||
// Copy shader tokens from input,
|
||||
// skip first token (we already copied it)
|
||||
i = 1;
|
||||
do {
|
||||
token = pFunction[i++];
|
||||
|
||||
DWORD opcode = token & D3DSI_OPCODE_MASK;
|
||||
|
||||
// Instructions
|
||||
if ((token & VS_BIT_PARAM) == 0) {
|
||||
|
||||
// Swizzle fixup for opcodes that require explicit use of a replicate swizzle.
|
||||
if (opcode == D3DSIO_RSQ || opcode == D3DSIO_RCP
|
||||
|| opcode == D3DSIO_EXP || opcode == D3DSIO_LOG
|
||||
|| opcode == D3DSIO_EXPP || opcode == D3DSIO_LOGP) {
|
||||
tokens.push_back(token); // instr
|
||||
tokens.push_back(token = pFunction[i++]); // dest
|
||||
token = pFunction[i++]; // src0
|
||||
|
||||
// If no swizzling is done, then use the w-component.
|
||||
// See d8vk#43 for more information as this may need to change in some cases.
|
||||
if (((token & D3DVS_NOSWIZZLE) == D3DVS_NOSWIZZLE)) {
|
||||
token &= ~D3DVS_SWIZZLE_MASK;
|
||||
token |= (D3DVS_X_W | D3DVS_Y_W | D3DVS_Z_W | D3DVS_W_W);
|
||||
}
|
||||
}
|
||||
}
|
||||
tokens.push_back(token);
|
||||
} while (token != D3DVS_END());
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
18
src/d3d8/d3d8_shader.h
Normal file
18
src/d3d8/d3d8_shader.h
Normal file
|
@ -0,0 +1,18 @@
|
|||
#pragma once
|
||||
|
||||
#include "d3d8_include.h"
|
||||
#include "d3d8_options.h"
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
struct D3D9VertexShaderCode {
|
||||
d3d9::D3DVERTEXELEMENT9 declaration[MAXD3DDECLLENGTH + 1];
|
||||
std::vector<DWORD> function;
|
||||
};
|
||||
|
||||
D3D9VertexShaderCode TranslateVertexShader8(
|
||||
const DWORD* pDeclaration,
|
||||
const DWORD* pFunction,
|
||||
const D3D8Options& overrides);
|
||||
|
||||
}
|
109
src/d3d8/d3d8_state_block.cpp
Normal file
109
src/d3d8/d3d8_state_block.cpp
Normal file
|
@ -0,0 +1,109 @@
|
|||
#include "d3d8_device.h"
|
||||
#include "d3d8_state_block.h"
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
D3D8StateBlock::D3D8StateBlock(
|
||||
D3D8Device* pDevice,
|
||||
D3DSTATEBLOCKTYPE Type,
|
||||
Com<d3d9::IDirect3DStateBlock9>&& pStateBlock)
|
||||
: m_device(pDevice)
|
||||
, m_stateBlock(std::move(pStateBlock))
|
||||
, m_type(Type)
|
||||
, m_isSWVP(pDevice->GetD3D9()->GetSoftwareVertexProcessing()) {
|
||||
if (Type == D3DSBT_VERTEXSTATE || Type == D3DSBT_ALL) {
|
||||
// Lights, D3DTSS_TEXCOORDINDEX and D3DTSS_TEXTURETRANSFORMFLAGS,
|
||||
// vertex shader, VS constants, and various render states.
|
||||
m_capture.vs = true;
|
||||
}
|
||||
|
||||
if (Type == D3DSBT_PIXELSTATE || Type == D3DSBT_ALL) {
|
||||
// Pixel shader, PS constants, and various RS/TSS states.
|
||||
m_capture.ps = true;
|
||||
}
|
||||
|
||||
if (Type == D3DSBT_ALL) {
|
||||
m_capture.indices = true;
|
||||
m_capture.swvp = true;
|
||||
m_capture.textures.setAll();
|
||||
m_capture.streams.setAll();
|
||||
}
|
||||
|
||||
m_textures.fill(nullptr);
|
||||
m_streams.fill(D3D8VBOP());
|
||||
}
|
||||
|
||||
// Construct a state block without a D3D9 object
|
||||
D3D8StateBlock::D3D8StateBlock(D3D8Device* pDevice)
|
||||
: D3D8StateBlock(pDevice, D3DSTATEBLOCKTYPE(0), nullptr) {
|
||||
}
|
||||
|
||||
// Attach a D3D9 object to a state block that doesn't have one yet
|
||||
void D3D8StateBlock::SetD3D9(Com<d3d9::IDirect3DStateBlock9>&& pStateBlock) {
|
||||
if (likely(m_stateBlock == nullptr)) {
|
||||
m_stateBlock = std::move(pStateBlock);
|
||||
} else {
|
||||
Logger::err("D3D8StateBlock::SetD3D9: m_stateBlock has already been initialized");
|
||||
}
|
||||
}
|
||||
|
||||
HRESULT D3D8StateBlock::Capture() {
|
||||
if (unlikely(m_stateBlock == nullptr))
|
||||
return D3DERR_INVALIDCALL;
|
||||
|
||||
if (m_capture.vs) m_device->GetVertexShader(&m_vertexShader);
|
||||
if (m_capture.ps) m_device->GetPixelShader(&m_pixelShader);
|
||||
|
||||
for (DWORD stage = 0; stage < m_textures.size(); stage++) {
|
||||
if (m_capture.textures.get(stage))
|
||||
m_textures[stage] = m_device->m_textures[stage].ptr();
|
||||
}
|
||||
|
||||
for (DWORD stream = 0; stream < m_streams.size(); stream++) {
|
||||
if (m_capture.streams.get(stream)) {
|
||||
m_streams[stream].buffer = m_device->m_streams[stream].buffer.ptr();
|
||||
m_streams[stream].stride = m_device->m_streams[stream].stride;
|
||||
}
|
||||
}
|
||||
|
||||
if (m_capture.indices) {
|
||||
m_baseVertexIndex = m_device->m_baseVertexIndex;
|
||||
m_indices = m_device->m_indices.ptr();
|
||||
}
|
||||
|
||||
if (m_capture.swvp)
|
||||
m_device->GetRenderState(D3DRS_SOFTWAREVERTEXPROCESSING, (DWORD*)&m_isSWVP);
|
||||
|
||||
return m_stateBlock->Capture();
|
||||
}
|
||||
|
||||
HRESULT D3D8StateBlock::Apply() {
|
||||
if (unlikely(m_stateBlock == nullptr))
|
||||
return D3DERR_INVALIDCALL;
|
||||
|
||||
HRESULT res = m_stateBlock->Apply();
|
||||
|
||||
if (m_capture.vs) m_device->SetVertexShader(m_vertexShader);
|
||||
if (m_capture.ps) m_device->SetPixelShader(m_pixelShader);
|
||||
|
||||
for (DWORD stage = 0; stage < m_textures.size(); stage++) {
|
||||
if (m_capture.textures.get(stage))
|
||||
m_device->SetTexture(stage, m_textures[stage]);
|
||||
}
|
||||
|
||||
for (DWORD stream = 0; stream < m_streams.size(); stream++) {
|
||||
if (m_capture.streams.get(stream))
|
||||
m_device->SetStreamSource(stream, m_streams[stream].buffer, m_streams[stream].stride);
|
||||
}
|
||||
|
||||
if (m_capture.indices)
|
||||
m_device->SetIndices(m_indices, m_baseVertexIndex);
|
||||
|
||||
// This was a very easy footgun for D3D8 applications.
|
||||
if (m_capture.swvp)
|
||||
m_device->SetRenderState(D3DRS_SOFTWAREVERTEXPROCESSING, m_isSWVP);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
}
|
120
src/d3d8/d3d8_state_block.h
Normal file
120
src/d3d8/d3d8_state_block.h
Normal file
|
@ -0,0 +1,120 @@
|
|||
#pragma once
|
||||
|
||||
#include "d3d8_caps.h"
|
||||
#include "d3d8_include.h"
|
||||
#include "d3d8_device.h"
|
||||
#include "d3d8_device_child.h"
|
||||
|
||||
#include "../util/util_bit.h"
|
||||
|
||||
#include <array>
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
struct D3D8StateCapture {
|
||||
bool vs : 1;
|
||||
bool ps : 1;
|
||||
bool indices : 1;
|
||||
bool swvp : 1;
|
||||
|
||||
bit::bitset<d8caps::MAX_TEXTURE_STAGES> textures;
|
||||
bit::bitset<d8caps::MAX_STREAMS> streams;
|
||||
|
||||
D3D8StateCapture()
|
||||
: vs(false)
|
||||
, ps(false)
|
||||
, indices(false)
|
||||
, swvp(false) {
|
||||
// Ensure all bits are initialized to false
|
||||
textures.clearAll();
|
||||
streams.clearAll();
|
||||
}
|
||||
};
|
||||
|
||||
// Wrapper class for D3D9 state blocks. Captures D3D8-specific state.
|
||||
class D3D8StateBlock {
|
||||
|
||||
public:
|
||||
|
||||
D3D8StateBlock(
|
||||
D3D8Device* pDevice,
|
||||
D3DSTATEBLOCKTYPE Type,
|
||||
Com<d3d9::IDirect3DStateBlock9>&& pStateBlock);
|
||||
|
||||
D3D8StateBlock(D3D8Device* pDevice);
|
||||
|
||||
void SetD3D9(Com<d3d9::IDirect3DStateBlock9>&& pStateBlock);
|
||||
|
||||
HRESULT Capture();
|
||||
|
||||
HRESULT Apply();
|
||||
|
||||
inline HRESULT SetVertexShader(DWORD Handle) {
|
||||
m_vertexShader = Handle;
|
||||
m_capture.vs = true;
|
||||
return D3D_OK;
|
||||
}
|
||||
|
||||
inline HRESULT SetPixelShader(DWORD Handle) {
|
||||
m_pixelShader = Handle;
|
||||
m_capture.ps = true;
|
||||
return D3D_OK;
|
||||
}
|
||||
|
||||
inline HRESULT SetTexture(DWORD Stage, IDirect3DBaseTexture8* pTexture) {
|
||||
m_textures[Stage] = pTexture;
|
||||
m_capture.textures.set(Stage, true);
|
||||
return D3D_OK;
|
||||
}
|
||||
|
||||
inline HRESULT SetStreamSource(UINT StreamNumber, IDirect3DVertexBuffer8* pStreamData, UINT Stride) {
|
||||
m_streams[StreamNumber].buffer = pStreamData;
|
||||
// The previous stride is preserved if pStreamData is NULL
|
||||
if (likely(pStreamData != nullptr))
|
||||
m_streams[StreamNumber].stride = Stride;
|
||||
m_capture.streams.set(StreamNumber, true);
|
||||
return D3D_OK;
|
||||
}
|
||||
|
||||
inline HRESULT SetIndices(IDirect3DIndexBuffer8* pIndexData, UINT BaseVertexIndex) {
|
||||
m_indices = pIndexData;
|
||||
m_baseVertexIndex = BaseVertexIndex;
|
||||
m_capture.indices = true;
|
||||
return D3D_OK;
|
||||
}
|
||||
|
||||
inline HRESULT SetSoftwareVertexProcessing(bool value) {
|
||||
m_isSWVP = value;
|
||||
m_capture.swvp = true;
|
||||
return D3D_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
D3D8Device* m_device;
|
||||
Com<d3d9::IDirect3DStateBlock9> m_stateBlock;
|
||||
D3DSTATEBLOCKTYPE m_type;
|
||||
|
||||
struct D3D8VBOP {
|
||||
IDirect3DVertexBuffer8* buffer = nullptr;
|
||||
UINT stride = 0;
|
||||
};
|
||||
|
||||
// State Data //
|
||||
|
||||
D3D8StateCapture m_capture;
|
||||
|
||||
DWORD m_vertexShader = 0;
|
||||
DWORD m_pixelShader = 0;
|
||||
|
||||
std::array<IDirect3DBaseTexture8*, d8caps::MAX_TEXTURE_STAGES> m_textures;
|
||||
std::array<D3D8VBOP, d8caps::MAX_STREAMS> m_streams;
|
||||
|
||||
IDirect3DIndexBuffer8* m_indices = nullptr;
|
||||
UINT m_baseVertexIndex = 0;
|
||||
|
||||
bool m_isSWVP; // D3DRS_SOFTWAREVERTEXPROCESSING
|
||||
|
||||
};
|
||||
|
||||
}
|
60
src/d3d8/d3d8_subresource.h
Normal file
60
src/d3d8/d3d8_subresource.h
Normal file
|
@ -0,0 +1,60 @@
|
|||
#pragma once
|
||||
|
||||
#include "d3d8_resource.h"
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
// Base class for Surfaces and Volumes,
|
||||
// which can be attached to Textures.
|
||||
|
||||
template <typename D3D9, typename D3D8>
|
||||
class D3D8Subresource : public D3D8Resource<D3D9, D3D8> {
|
||||
|
||||
using Resource = D3D8Resource<D3D9, D3D8>;
|
||||
|
||||
public:
|
||||
|
||||
D3D8Subresource(
|
||||
D3D8Device* pDevice,
|
||||
const D3DPOOL Pool,
|
||||
Com<D3D9>&& Object,
|
||||
IDirect3DBaseTexture8* pBaseTexture)
|
||||
: Resource(pDevice, Pool, std::move(Object)),
|
||||
m_container(pBaseTexture) {
|
||||
}
|
||||
|
||||
// Refing subresources implicitly refs the container texture,
|
||||
ULONG STDMETHODCALLTYPE AddRef() final {
|
||||
if (m_container != nullptr)
|
||||
return m_container->AddRef();
|
||||
|
||||
return Resource::AddRef();
|
||||
}
|
||||
|
||||
// and releasing them implicitly releases the texture.
|
||||
ULONG STDMETHODCALLTYPE Release() final {
|
||||
if (m_container != nullptr)
|
||||
return m_container->Release();
|
||||
|
||||
return Resource::Release();
|
||||
}
|
||||
|
||||
// Clients can grab the container if they want
|
||||
HRESULT STDMETHODCALLTYPE GetContainer(REFIID riid, void** ppContainer) final {
|
||||
if (m_container != nullptr)
|
||||
return m_container->QueryInterface(riid, ppContainer);
|
||||
|
||||
return this->GetDevice()->QueryInterface(riid, ppContainer);
|
||||
}
|
||||
|
||||
inline IDirect3DBaseTexture8* GetBaseTexture() {
|
||||
return m_container;
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
IDirect3DBaseTexture8* m_container;
|
||||
|
||||
};
|
||||
|
||||
}
|
78
src/d3d8/d3d8_surface.cpp
Normal file
78
src/d3d8/d3d8_surface.cpp
Normal file
|
@ -0,0 +1,78 @@
|
|||
#include "d3d8_surface.h"
|
||||
#include "d3d8_device.h"
|
||||
|
||||
#include "d3d8_d3d9_util.h"
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
D3D8Surface::D3D8Surface(
|
||||
D3D8Device* pDevice,
|
||||
const D3DPOOL Pool,
|
||||
IDirect3DBaseTexture8* pTexture,
|
||||
Com<d3d9::IDirect3DSurface9>&& pSurface)
|
||||
: D3D8SurfaceBase (pDevice, Pool, std::move(pSurface), pTexture) {
|
||||
}
|
||||
|
||||
// A surface does not need to be attached to a texture
|
||||
D3D8Surface::D3D8Surface(
|
||||
D3D8Device* pDevice,
|
||||
const D3DPOOL Pool,
|
||||
Com<d3d9::IDirect3DSurface9>&& pSurface)
|
||||
: D3D8Surface (pDevice, Pool, nullptr, std::move(pSurface)) {
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE D3D8Surface::GetDesc(D3DSURFACE_DESC* pDesc) {
|
||||
if (unlikely(pDesc == nullptr))
|
||||
return D3DERR_INVALIDCALL;
|
||||
|
||||
d3d9::D3DSURFACE_DESC desc;
|
||||
HRESULT res = GetD3D9()->GetDesc(&desc);
|
||||
|
||||
if (likely(SUCCEEDED(res)))
|
||||
ConvertSurfaceDesc8(&desc, pDesc);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE D3D8Surface::LockRect(
|
||||
D3DLOCKED_RECT* pLockedRect,
|
||||
CONST RECT* pRect,
|
||||
DWORD Flags) {
|
||||
return GetD3D9()->LockRect((d3d9::D3DLOCKED_RECT*)pLockedRect, pRect, Flags);
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE D3D8Surface::UnlockRect() {
|
||||
return GetD3D9()->UnlockRect();
|
||||
}
|
||||
|
||||
// TODO: Consider creating only one texture to
|
||||
// encompass all surface levels of a texture.
|
||||
Com<d3d9::IDirect3DSurface9> D3D8Surface::GetBlitImage() {
|
||||
if (unlikely(m_blitImage == nullptr)) {
|
||||
m_blitImage = CreateBlitImage();
|
||||
}
|
||||
|
||||
return m_blitImage;
|
||||
}
|
||||
|
||||
Com<d3d9::IDirect3DSurface9> D3D8Surface::CreateBlitImage() {
|
||||
d3d9::D3DSURFACE_DESC desc;
|
||||
GetD3D9()->GetDesc(&desc);
|
||||
|
||||
// NOTE: This adds a D3DPOOL_DEFAULT resource to the
|
||||
// device, which counts as losable during device reset
|
||||
Com<d3d9::IDirect3DSurface9> image = nullptr;
|
||||
HRESULT res = GetParent()->GetD3D9()->CreateRenderTarget(
|
||||
desc.Width, desc.Height, desc.Format,
|
||||
d3d9::D3DMULTISAMPLE_NONE, 0,
|
||||
FALSE,
|
||||
&image,
|
||||
NULL);
|
||||
|
||||
if (FAILED(res))
|
||||
throw new DxvkError("D3D8: Failed to create blit image");
|
||||
|
||||
return image;
|
||||
}
|
||||
|
||||
}
|
50
src/d3d8/d3d8_surface.h
Normal file
50
src/d3d8/d3d8_surface.h
Normal file
|
@ -0,0 +1,50 @@
|
|||
#pragma once
|
||||
|
||||
#include "d3d8_include.h"
|
||||
#include "d3d8_subresource.h"
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
// Note: IDirect3DSurface8 does not actually inherit from IDirect3DResource8,
|
||||
// however it does expose serveral of the methods typically found part of
|
||||
// IDirect3DResource8, such as Set/Get/FreePrivateData, so model it as such.
|
||||
using D3D8SurfaceBase = D3D8Subresource<d3d9::IDirect3DSurface9, IDirect3DSurface8>;
|
||||
class D3D8Surface final : public D3D8SurfaceBase {
|
||||
|
||||
public:
|
||||
|
||||
D3D8Surface(
|
||||
D3D8Device* pDevice,
|
||||
const D3DPOOL Pool,
|
||||
IDirect3DBaseTexture8* pTexture,
|
||||
Com<d3d9::IDirect3DSurface9>&& pSurface);
|
||||
|
||||
D3D8Surface(
|
||||
D3D8Device* pDevice,
|
||||
const D3DPOOL Pool,
|
||||
Com<d3d9::IDirect3DSurface9>&& pSurface);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE GetDesc(D3DSURFACE_DESC* pDesc) final;
|
||||
|
||||
HRESULT STDMETHODCALLTYPE LockRect(
|
||||
D3DLOCKED_RECT* pLockedRect,
|
||||
CONST RECT* pRect,
|
||||
DWORD Flags) final;
|
||||
|
||||
HRESULT STDMETHODCALLTYPE UnlockRect() final;
|
||||
|
||||
/**
|
||||
* \brief Allocate or reuse an image of the same size
|
||||
* as this texture for performing blit into system mem.
|
||||
*/
|
||||
Com<d3d9::IDirect3DSurface9> GetBlitImage();
|
||||
|
||||
private:
|
||||
|
||||
Com<d3d9::IDirect3DSurface9> CreateBlitImage();
|
||||
|
||||
Com<d3d9::IDirect3DSurface9> m_blitImage;
|
||||
|
||||
};
|
||||
|
||||
}
|
41
src/d3d8/d3d8_swapchain.cpp
Normal file
41
src/d3d8/d3d8_swapchain.cpp
Normal file
|
@ -0,0 +1,41 @@
|
|||
#include "d3d8_swapchain.h"
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
D3D8SwapChain::D3D8SwapChain(
|
||||
D3D8Device* pDevice,
|
||||
D3DPRESENT_PARAMETERS* pPresentationParameters,
|
||||
Com<d3d9::IDirect3DSwapChain9>&& pSwapChain)
|
||||
: D3D8SwapChainBase(pDevice, std::move(pSwapChain)) {
|
||||
m_backBuffers.resize(pPresentationParameters->BackBufferCount);
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE D3D8SwapChain::Present(const RECT *src, const RECT *dst, HWND hWnd, const RGNDATA *dirtyRegion) {
|
||||
return GetD3D9()->Present(src, dst, hWnd, dirtyRegion, 0);
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE D3D8SwapChain::GetBackBuffer(
|
||||
UINT BackBuffer,
|
||||
D3DBACKBUFFER_TYPE Type,
|
||||
IDirect3DSurface8** ppBackBuffer) {
|
||||
if (unlikely(ppBackBuffer == nullptr))
|
||||
return D3DERR_INVALIDCALL;
|
||||
|
||||
// Same logic as in D3D8Device::GetBackBuffer
|
||||
if (BackBuffer >= m_backBuffers.size() || m_backBuffers[BackBuffer] == nullptr) {
|
||||
Com<d3d9::IDirect3DSurface9> pSurface9;
|
||||
HRESULT res = GetD3D9()->GetBackBuffer(BackBuffer, (d3d9::D3DBACKBUFFER_TYPE)Type, &pSurface9);
|
||||
|
||||
if (likely(SUCCEEDED(res))) {
|
||||
m_backBuffers[BackBuffer] = new D3D8Surface(GetParent(), D3DPOOL_DEFAULT, std::move(pSurface9));
|
||||
*ppBackBuffer = m_backBuffers[BackBuffer].ref();
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
*ppBackBuffer = m_backBuffers[BackBuffer].ref();
|
||||
return D3D_OK;
|
||||
}
|
||||
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue