mirror of
https://github.com/doitsujin/dxvk.git
synced 2025-03-06 20:58:37 +01:00
Compare commits
1432 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 | ||
|
80e075406b | ||
|
a53f0e8168 | ||
|
4705de5725 | ||
|
9e26964a96 | ||
|
ce2f9f35ce | ||
|
a3fa9c26dc | ||
|
ff5507769a | ||
|
5c56fa0df4 | ||
|
7e10021eac | ||
|
bbd1d84cd0 | ||
|
02db89ac30 | ||
|
92dc61f161 | ||
|
6a5ed02db3 | ||
|
64828e2c6c | ||
|
a4f2a49a02 | ||
|
aa41a7a351 | ||
|
fb71c08d8c | ||
|
79f6239df3 | ||
|
53a68635b2 | ||
|
179c5ec998 | ||
|
d6e0107e23 | ||
|
428ca9416d | ||
|
c26f40229a | ||
|
8226690298 | ||
|
138f727fbb | ||
|
c2cd129b89 | ||
|
915244c00c | ||
|
6fce094942 | ||
|
740ebec7ee | ||
|
bcaaac4ad7 | ||
|
1130512db5 | ||
|
143eb8c710 | ||
|
4ae542e875 | ||
|
952c66fe2a | ||
|
b6a7714e67 | ||
|
037669f715 | ||
|
295a58afdf | ||
|
0746a3b91a | ||
|
429555a540 | ||
|
dfcd7aedd8 | ||
|
cbda22a040 | ||
|
549bd86f03 | ||
|
b0b46fd075 | ||
|
a62117cd13 | ||
|
e598dcd77e | ||
|
09857dcaa9 | ||
|
d66f8385c3 | ||
|
007e9f4c89 | ||
|
9b019d26ac | ||
|
228615b639 | ||
|
dfbebba6b5 | ||
|
4ed04268fd | ||
|
4ed1474030 | ||
|
13440a5d89 | ||
|
1daae75048 | ||
|
b4d87eaac0 | ||
|
1e11db98d0 | ||
|
f689ddd838 | ||
|
eed43c8524 | ||
|
d066fbbaed | ||
|
a67c99943a | ||
|
5ece97f769 | ||
|
228cd4c331 | ||
|
98f3887680 | ||
|
3a9a70b5f0 | ||
|
878da4984b | ||
|
c599f95e5d | ||
|
4893788d9b | ||
|
fc952a3ca3 | ||
|
01ad79278b | ||
|
48557886de | ||
|
8319793a98 | ||
|
886268fcf9 | ||
|
84e59fc9e5 | ||
|
6be1f6d7bd | ||
|
2f72115f91 | ||
|
026aa49ef8 | ||
|
3a368f4780 | ||
|
2ef41bdbf6 | ||
|
0f4458e173 | ||
|
ccb87d5ea9 | ||
|
022bf1d134 | ||
|
d6e7e3e780 | ||
|
b77928b6fe | ||
|
987df8a487 | ||
|
a7278cdab1 | ||
|
3b3ebc9350 | ||
|
00ae118655 | ||
|
55be12daa5 | ||
|
0e36a07a93 | ||
|
ff65599dba | ||
|
6b60de2d31 | ||
|
362743c1d6 | ||
|
7f302fc350 | ||
|
8704ed7af6 | ||
|
0895858901 | ||
|
80b27f95bc | ||
|
a791493d14 | ||
|
c768196251 | ||
|
3625c5d481 | ||
|
b3cbe36c08 | ||
|
166d90b04c | ||
|
60b6e98529 | ||
|
a20869fb93 | ||
|
a287566c65 | ||
|
28f48f9fdc | ||
|
e02a800c33 | ||
|
d7fa39c4eb | ||
|
d1e39be7e7 | ||
|
438c535fe7 | ||
|
7dbe4abb48 | ||
|
e99bc591df | ||
|
08363edb05 | ||
|
5d1196733b | ||
|
ca3492570c | ||
|
215c4f8f6f | ||
|
5a1ebfa4ee | ||
|
6f87ccdafc | ||
|
b30a4f0cc7 | ||
|
4e9853f608 | ||
|
5fbb0dd4ba | ||
|
77f6f2a84b | ||
|
0b9acf3a25 | ||
|
211d095ee4 | ||
|
77e7e8bfba | ||
|
42a0264e69 | ||
|
5d29140f74 | ||
|
0236e780a7 | ||
|
24dbcf8fd8 | ||
|
404c984f9c | ||
|
a79772322b | ||
|
36e6a7c2e5 | ||
|
c5ab5be48d | ||
|
af9bd16b8d | ||
|
2c014fdb34 | ||
|
6478c10a18 | ||
|
7388c243d2 | ||
|
bd575a4a46 | ||
|
3fce9886f5 | ||
|
5d134b877a | ||
|
c75ed86909 | ||
|
d1707026f9 | ||
|
b8d36eeacc | ||
|
8f740c53b4 | ||
|
52ac271acb | ||
|
a1a91dd766 | ||
|
22f6246fd6 | ||
|
9d6804e40a | ||
|
5fd025c513 | ||
|
d9d6316609 | ||
|
9b877cf623 | ||
|
2c3f2b9ad1 | ||
|
1850819483 | ||
|
1db2e3a6ec | ||
|
2efd3f3698 | ||
|
bbaf01d9e6 | ||
|
4a55047dde | ||
|
3fddc364ee | ||
|
f3fb5ba320 | ||
|
4d254b13be | ||
|
d241daa0b1 | ||
|
2e70a2b07d | ||
|
52f04ca3d4 | ||
|
c585ea251e | ||
|
ab00591297 | ||
|
85d52ccb88 | ||
|
e6be0cf996 | ||
|
1728d9e89d | ||
|
b1b0abdbbf | ||
|
be875cd7e6 | ||
|
0543956ea0 | ||
|
e9e0949717 | ||
|
8b6cbda6de | ||
|
4b10846008 | ||
|
e0654977c9 | ||
|
b5c18a02ae | ||
|
cafd104783 | ||
|
269bab2c34 | ||
|
075c0bf203 | ||
|
8560efa3c7 | ||
|
b9b2db510e | ||
|
d5c6ae2e4d | ||
|
633f6663a4 | ||
|
d2759c20ba | ||
|
1a2e724c16 | ||
|
6449f583f8 | ||
|
f2bb1d4b69 | ||
|
495dc75ab2 | ||
|
550e04c579 | ||
|
d4a7346198 | ||
|
99b367cdd6 | ||
|
65520fa18e | ||
|
f30376a1e4 | ||
|
cae0a1cef3 | ||
|
14eb469005 | ||
|
80f7d2abd8 | ||
|
2b09932d51 | ||
|
bef2ef69ab | ||
|
b08665c808 | ||
|
96e22e7c67 | ||
|
5443a2f9f5 | ||
|
83a294285e | ||
|
242ac20752 | ||
|
b357d16940 | ||
|
b4366db398 | ||
|
b5f43063b1 | ||
|
f140d2de0d | ||
|
20356148af | ||
|
b81536458f | ||
|
9ce1c4df0d | ||
|
860237e775 | ||
|
ceb3a7f8c6 | ||
|
a42643b235 | ||
|
5c8ed491ab | ||
|
b44c5bbd18 | ||
|
16d2a6045c | ||
|
1971a5d187 | ||
|
e074d83d0b | ||
|
990a720525 | ||
|
0cf563d5df | ||
|
01dc9ddc7d | ||
|
6b779206d9 | ||
|
8508633ba3 | ||
|
af0009c5de | ||
|
31af522cbc | ||
|
d9a6b40ae3 | ||
|
6d14fffdbd | ||
|
3ce3209e3e | ||
|
f212cc8f7d | ||
|
306919047b | ||
|
977669c613 | ||
|
631171cf45 | ||
|
1a5afc77b1 | ||
|
d11878e793 | ||
|
4b74d1a97b | ||
|
b0ed97e070 | ||
|
3d5becaf6a | ||
|
5595844f75 | ||
|
9bdad71dc6 | ||
|
3c99314332 | ||
|
fa8cf50263 | ||
|
3f9d2269f6 | ||
|
6432787ac3 | ||
|
da32453b42 | ||
|
27f3648a44 | ||
|
35895ba05b | ||
|
56a8fa2e6f | ||
|
d8f3a1c83d | ||
|
ef9d5048f3 | ||
|
f50f5bc9bc | ||
|
b06e82591e | ||
|
687d32cac5 | ||
|
243c2f3cf5 | ||
|
af811656bb | ||
|
05fb634f91 | ||
|
3a123222e5 | ||
|
4faa598e09 | ||
|
6783123654 | ||
|
d14dcf5d47 | ||
|
996acbe3f2 | ||
|
8ecd1b3b6b | ||
|
7f21a6c491 | ||
|
e430ff5cfd | ||
|
1acf885109 | ||
|
1c6fc7b5b8 | ||
|
5609c5e076 | ||
|
55e7cb1d54 | ||
|
4c78964679 | ||
|
cc78276897 | ||
|
aa92cf48f5 | ||
|
81440340ac | ||
|
2356d34f2e | ||
|
f4b91817fe | ||
|
2be0d6842e | ||
|
0d28be4ab8 | ||
|
081181313e | ||
|
caf31033d7 | ||
|
2263dcad95 | ||
|
41b1efd7ce | ||
|
c6111eaf61 |
444 changed files with 50385 additions and 18181 deletions
6
.github/ISSUE_TEMPLATE/bug_report.md
vendored
6
.github/ISSUE_TEMPLATE/bug_report.md
vendored
|
@ -26,6 +26,6 @@ Name of the game, settings used etc.
|
|||
For instructions on how to use apitrace, see: https://github.com/doitsujin/dxvk/wiki/Using-Apitrace
|
||||
|
||||
### Log files
|
||||
- d3d9.log:
|
||||
- d3d11.log:
|
||||
- dxgi.log:
|
||||
Please attach Proton or Wine logs as a text file:
|
||||
- When using Proton, set the Steam launch options for your game to `PROTON_LOG=1 %command%` and attach the corresponding `steam-xxxxx.log` file in your home directory.
|
||||
- When using regular Wine, use `wine game.exe > game.log 2>&1` and attach the resulting `game.log` file.
|
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
|
||||
|
|
39
.github/workflows/test-build-windows.yml
vendored
39
.github/workflows/test-build-windows.yml
vendored
|
@ -4,21 +4,21 @@ 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
|
||||
run: |
|
||||
choco install vulkan-sdk -y
|
||||
Write-Output "$([System.Environment]::GetEnvironmentVariable('VULKAN_SDK', 'Machine'))\Bin" `
|
||||
| Out-File -FilePath "${Env:GITHUB_PATH}" -Append
|
||||
Invoke-WebRequest -Uri "https://raw.githubusercontent.com/HansKristian-Work/vkd3d-proton-ci/main/glslangValidator.exe" -OutFile "glslangValidator.exe"
|
||||
Write-Output "$pwd" | Out-File -FilePath "${Env:GITHUB_PATH}" -Append
|
||||
|
||||
- name: Setup Meson
|
||||
shell: pwsh
|
||||
|
@ -33,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: |
|
||||
|
@ -50,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
|
||||
|
||||
|
|
179
README.md
179
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,18 +9,110 @@ 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:
|
||||
```
|
||||
WINEPREFIX=/path/to/wineprefix
|
||||
export WINEPREFIX=/path/to/wineprefix
|
||||
cp x64/*.dll $WINEPREFIX/drive_c/windows/system32
|
||||
cp x32/*.dll $WINEPREFIX/drive_c/windows/syswow64
|
||||
winecfg
|
||||
```
|
||||
|
||||
Verify that your application uses DXVK instead of wined3d by checking for the presence of the log file `d3d9.log` or `d3d11.log` in the application's directory, or by enabling the HUD (see notes below).
|
||||
For a pure 32-bit Wine prefix (non default) the 32-bit DLLs instead go to the `system32` directory:
|
||||
```
|
||||
export WINEPREFIX=/path/to/wineprefix
|
||||
cp x32/*.dll $WINEPREFIX/drive_c/windows/system32
|
||||
winecfg
|
||||
```
|
||||
|
||||
Verify that your application uses DXVK instead of wined3d by enabling the HUD (see notes below).
|
||||
|
||||
In order to remove DXVK from a prefix, remove the DLLs and DLL overrides, and run `wineboot -u` to restore the original DLL files.
|
||||
|
||||
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:
|
||||
|
@ -28,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
|
||||
|
||||
|
@ -62,61 +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`.
|
||||
|
||||
### 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.
|
||||
- `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`)
|
||||
|
||||
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.
|
||||
|
||||
### 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.
|
||||
|
||||
### 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_CONFIG_FILE=/xxx/dxvk.conf` Sets path to the configuration file.
|
||||
- `DXVK_DEBUG=markers|validation` Enables use of the `VK_EXT_debug_utils` extension for translating performance event markers, or to enable Vulkan validation, respecticely.
|
||||
|
||||
## 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.
|
||||
|
@ -134,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.1
|
||||
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@"
|
||||
|
361
dxvk.conf
361
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.
|
||||
#
|
||||
|
@ -61,18 +147,43 @@
|
|||
# d3d9.customDeviceDesc = ""
|
||||
|
||||
|
||||
# Report Nvidia GPUs as AMD GPUs by default. This is enabled by default
|
||||
# to work around issues with NVAPI, but may cause issues in some games.
|
||||
# Report Nvidia GPUs as AMD GPUs. Unless NVAPI support is explicitly
|
||||
# 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.
|
||||
#
|
||||
# Supported values: True, False
|
||||
# Supported values: Auto, True, False
|
||||
|
||||
# dxgi.nvapiHack = True
|
||||
# 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.
|
||||
#
|
||||
# Supported values: Auto, True, False
|
||||
|
||||
# dxgi.hideAmdGpu = Auto
|
||||
|
||||
|
||||
# Report Intel GPUs as AMD GPUs. This is only done for games that are
|
||||
# known to have issues with Intel-specific libraries such as XESS.
|
||||
#
|
||||
# Supported values: Auto, True, False
|
||||
|
||||
# dxgi.hideIntelGpu = Auto
|
||||
|
||||
|
||||
# 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.
|
||||
|
||||
|
@ -80,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
|
||||
|
@ -109,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,
|
||||
|
@ -122,17 +215,17 @@
|
|||
#
|
||||
# Supported values: Auto, True, False
|
||||
|
||||
# dxgi.tearFree = Auto
|
||||
# d3d9.tearFree = Auto
|
||||
# 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
|
||||
|
@ -153,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
|
||||
|
@ -190,6 +285,16 @@
|
|||
# Supported values: Any number between -2.0 and 1.0
|
||||
|
||||
# d3d11.samplerLodBias = 0.0
|
||||
# d3d9.samplerLodBias = 0.0
|
||||
|
||||
|
||||
# Clamps any negative LOD bias to 0. Applies after samplerLodBias has been
|
||||
# applied. May help with games that use a high negative LOD bias by default.
|
||||
#
|
||||
# Supported values: True, False
|
||||
|
||||
# d3d11.clampNegativeLodBias = False
|
||||
# d3d9.clampNegativeLodBias = False
|
||||
|
||||
|
||||
# Declares vertex positions as invariant in order to solve
|
||||
|
@ -227,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
|
||||
|
@ -266,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
|
||||
|
@ -322,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
|
||||
|
@ -337,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
|
||||
|
@ -416,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)
|
||||
|
@ -433,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.
|
||||
|
@ -455,18 +594,11 @@
|
|||
|
||||
# d3d9.deviceLocalConstantBuffers = False
|
||||
|
||||
# No Explicit Front Buffer
|
||||
#
|
||||
# Disables the front buffer
|
||||
#
|
||||
# Supported values:
|
||||
# - True/False
|
||||
|
||||
# d3d9.noExplicitFrontBuffer = False
|
||||
|
||||
# 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
|
||||
|
@ -485,26 +617,28 @@
|
|||
# Support X4R4G4B4
|
||||
#
|
||||
# Support the X4R4G4B4 format.
|
||||
# The Sims 2 is a horrible game made by complete morons.
|
||||
# The Sims 2 is a very broken game.
|
||||
#
|
||||
# Supported values:
|
||||
# - True/False
|
||||
|
||||
# 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
|
||||
#
|
||||
# Disable support for A8 format render targets
|
||||
# Once again, The Sims 2 is a horrible game made by complete morons.
|
||||
# Once again, The Sims 2 is a very broken game.
|
||||
#
|
||||
# Supported values:
|
||||
# - True/False
|
||||
|
@ -544,16 +678,6 @@
|
|||
|
||||
# d3d9.forceAspectRatio = ""
|
||||
|
||||
# Allow Discard
|
||||
#
|
||||
# Allow the discard lock flag to be used
|
||||
# Useful if some apps use this incorrectly.
|
||||
#
|
||||
# Supported values:
|
||||
# - True/False
|
||||
|
||||
# d3d9.allowDiscard = True
|
||||
|
||||
# Enumerate by Displays
|
||||
#
|
||||
# Whether we should enumerate D3D9 adapters by display (windows behaviour)
|
||||
|
@ -565,16 +689,17 @@
|
|||
|
||||
# d3d9.enumerateByDisplays = True
|
||||
|
||||
# APITrace Mode
|
||||
# Cached Dynamic Buffers
|
||||
#
|
||||
# Makes all host visible buffers cached and coherent
|
||||
# Improves performance when apitracing, but also can impact
|
||||
# some dumb games.
|
||||
# Allocates dynamic resources in D3DPOOL_DEFAULT in
|
||||
# cached system memory rather than uncached memory or host-visible
|
||||
# VRAM, in order to allow fast readback from the CPU. This is only
|
||||
# useful for buggy applications, and may reduce GPU-bound performance.
|
||||
#
|
||||
# Supported values:
|
||||
# - True/False
|
||||
|
||||
# d3d9.apitraceMode = False
|
||||
# d3d9.cachedDynamicBuffers = False
|
||||
|
||||
# Seamless Cubes
|
||||
#
|
||||
|
@ -604,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',
|
||||
)
|
|
@ -12,6 +12,10 @@ struct IUnknown {
|
|||
public:
|
||||
|
||||
virtual HRESULT QueryInterface(REFIID riid, void** ppvObject) = 0;
|
||||
template<class Q>
|
||||
HRESULT STDMETHODCALLTYPE QueryInterface(Q **pp) {
|
||||
return QueryInterface(__uuidof(Q), (void **)pp);
|
||||
}
|
||||
|
||||
virtual ULONG AddRef() = 0;
|
||||
virtual ULONG Release() = 0;
|
||||
|
|
|
@ -23,10 +23,16 @@ typedef uint32_t UINT;
|
|||
|
||||
typedef int32_t LONG;
|
||||
typedef uint32_t ULONG;
|
||||
typedef int32_t *LPLONG;
|
||||
|
||||
typedef int32_t HRESULT;
|
||||
|
||||
typedef wchar_t WCHAR;
|
||||
typedef WCHAR *NWPSTR, *LPWSTR, *PWSTR;
|
||||
typedef unsigned char UCHAR, *PUCHAR;
|
||||
|
||||
typedef char CHAR;
|
||||
typedef const CHAR *LPCSTR, *PCSTR;
|
||||
|
||||
typedef INT BOOL;
|
||||
typedef BOOL WINBOOL;
|
||||
|
@ -35,11 +41,13 @@ typedef uint16_t UINT16;
|
|||
typedef uint32_t UINT32;
|
||||
typedef uint64_t UINT64;
|
||||
typedef void VOID;
|
||||
typedef void* PVOID;
|
||||
typedef void* LPVOID;
|
||||
typedef const void* LPCVOID;
|
||||
|
||||
typedef size_t SIZE_T;
|
||||
|
||||
typedef int8_t INT8;
|
||||
typedef uint8_t UINT8;
|
||||
typedef uint8_t BYTE;
|
||||
|
||||
|
@ -47,7 +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;
|
||||
|
||||
|
@ -66,9 +80,11 @@ typedef GUID IID;
|
|||
#ifdef __cplusplus
|
||||
#define REFIID const IID&
|
||||
#define REFGUID const GUID&
|
||||
#define REFCLSID const GUID&
|
||||
#else
|
||||
#define REFIID const IID*
|
||||
#define REFGUID const GUID*
|
||||
#define REFCLSID const GUID* const
|
||||
#endif // __cplusplus
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
@ -86,6 +102,7 @@ inline bool operator!=(const GUID& a, const GUID& b) { return std::memcmp(&a, &b
|
|||
|
||||
typedef uint32_t DWORD;
|
||||
typedef uint16_t WORD;
|
||||
typedef DWORD *LPDWORD;
|
||||
|
||||
typedef void* HANDLE;
|
||||
typedef HANDLE HMONITOR;
|
||||
|
@ -107,6 +124,12 @@ typedef uint32_t UINT_PTR;
|
|||
typedef INT_PTR* PINT_PTR;
|
||||
typedef UINT_PTR* PUINT_PTR;
|
||||
|
||||
#ifdef STRICT
|
||||
#define DECLARE_HANDLE(a) typedef struct a##__ { int unused; } *a
|
||||
#else /*STRICT*/
|
||||
#define DECLARE_HANDLE(a) typedef HANDLE a
|
||||
#endif /*STRICT*/
|
||||
|
||||
typedef char* LPSTR;
|
||||
typedef wchar_t* LPWSTR;
|
||||
typedef const char* LPCSTR;
|
||||
|
@ -129,12 +152,12 @@ typedef struct RECT {
|
|||
LONG top;
|
||||
LONG right;
|
||||
LONG bottom;
|
||||
} RECT;
|
||||
} RECT,*PRECT,*NPRECT,*LPRECT;
|
||||
|
||||
typedef struct SIZE {
|
||||
LONG cx;
|
||||
LONG cy;
|
||||
} SIZE;
|
||||
} SIZE,*PSIZE,*LPSIZE;
|
||||
|
||||
typedef union {
|
||||
struct {
|
||||
|
@ -166,7 +189,7 @@ typedef struct PALETTEENTRY {
|
|||
BYTE peGreen;
|
||||
BYTE peBlue;
|
||||
BYTE peFlags;
|
||||
} PALETTEENTRY;
|
||||
} PALETTEENTRY, *PPALETTEENTRY, *LPPALETTEENTRY;
|
||||
|
||||
typedef struct RGNDATAHEADER {
|
||||
DWORD dwSize;
|
||||
|
@ -179,7 +202,7 @@ typedef struct RGNDATAHEADER {
|
|||
typedef struct RGNDATA {
|
||||
RGNDATAHEADER rdh;
|
||||
char Buffer[1];
|
||||
} RGNDATA;
|
||||
} RGNDATA,*PRGNDATA,*NPRGNDATA,*LPRGNDATA;
|
||||
|
||||
// Ignore these.
|
||||
#define STDMETHODCALLTYPE
|
||||
|
@ -191,6 +214,11 @@ typedef struct RGNDATA {
|
|||
#define TRUE 1
|
||||
#define FALSE 0
|
||||
|
||||
#define WAIT_TIMEOUT 0x00000102
|
||||
#define WAIT_FAILED 0xffffffff
|
||||
#define WAIT_OBJECT_0 0
|
||||
#define WAIT_ABANDONED 0x00000080
|
||||
|
||||
#define interface struct
|
||||
#define MIDL_INTERFACE(x) struct
|
||||
|
||||
|
@ -259,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
|
||||
|
||||
|
@ -278,6 +308,7 @@ typedef struct RGNDATA {
|
|||
#define THIS_
|
||||
#define THIS
|
||||
|
||||
#define __C89_NAMELESSSTRUCTNAME
|
||||
#define __C89_NAMELESSUNIONNAME
|
||||
#define __C89_NAMELESSUNIONNAME1
|
||||
#define __C89_NAMELESSUNIONNAME2
|
||||
|
@ -290,17 +321,35 @@ typedef struct RGNDATA {
|
|||
#define __C89_NAMELESS
|
||||
#define DUMMYUNIONNAME
|
||||
#define DUMMYSTRUCTNAME
|
||||
#define DUMMYUNIONNAME1
|
||||
#define DUMMYUNIONNAME2
|
||||
#define DUMMYUNIONNAME3
|
||||
#define DUMMYUNIONNAME4
|
||||
#define DUMMYUNIONNAME5
|
||||
#define DUMMYUNIONNAME6
|
||||
#define DUMMYUNIONNAME7
|
||||
#define DUMMYUNIONNAME8
|
||||
#define DUMMYUNIONNAME9
|
||||
|
||||
#ifdef __cplusplus
|
||||
#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
|
||||
|
||||
|
@ -327,3 +376,25 @@ typedef struct RGNDATA {
|
|||
|
||||
#define FAILED(hr) ((HRESULT)(hr) < 0)
|
||||
#define SUCCEEDED(hr) ((HRESULT)(hr) >= 0)
|
||||
|
||||
#define RtlZeroMemory(Destination,Length) memset((Destination),0,(Length))
|
||||
#define ZeroMemory RtlZeroMemory
|
||||
|
||||
#ifndef DEFINE_ENUM_FLAG_OPERATORS
|
||||
|
||||
#ifdef __cplusplus
|
||||
# define DEFINE_ENUM_FLAG_OPERATORS(type) \
|
||||
extern "C++" \
|
||||
{ \
|
||||
inline type operator &(type x, type y) { return (type)((int)x & (int)y); } \
|
||||
inline type operator &=(type &x, type y) { return (type &)((int &)x &= (int)y); } \
|
||||
inline type operator ~(type x) { return (type)~(int)x; } \
|
||||
inline type operator |(type x, type y) { return (type)((int)x | (int)y); } \
|
||||
inline type operator |=(type &x, type y) { return (type &)((int &)x |= (int)y); } \
|
||||
inline type operator ^(type x, type y) { return (type)((int)x ^ (int)y); } \
|
||||
inline type operator ^=(type &x, type y) { return (type &)((int &)x ^= (int)y); } \
|
||||
}
|
||||
#else
|
||||
# define DEFINE_ENUM_FLAG_OPERATORS(type)
|
||||
#endif
|
||||
#endif /* DEFINE_ENUM_FLAG_OPERATORS */
|
||||
|
|
|
@ -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 98f440ce6868c94f5ec6e198cc1adda4760e8849
|
||||
Subproject commit 234c4b7370a8ea3239a214c9e871e4b17c89f4ab
|
151
meson.build
151
meson.build
|
@ -1,11 +1,13 @@
|
|||
project('dxvk', ['c', 'cpp'], version : 'v2.1', 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,56 +36,77 @@ 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 dwarf2 symbols
|
||||
if get_option('debug')
|
||||
compiler_args += [
|
||||
'-gstrict-dwarf',
|
||||
'-gdwarf-2',
|
||||
]
|
||||
endif
|
||||
|
||||
# Enable stdcall fixup on 32-bit
|
||||
if cpu_family == 'x86'
|
||||
if not dxvk_is_msvc
|
||||
link_args += [
|
||||
'-Wl,--enable-stdcall-fixup',
|
||||
'-Wl,--add-stdcall-alias',
|
||||
]
|
||||
'-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
|
||||
|
||||
lib_d3d9 = cpp.find_library('d3d9')
|
||||
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')
|
||||
|
@ -99,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@' ] )
|
||||
|
||||
|
@ -112,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',
|
||||
|
@ -138,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('glslangValidator')
|
||||
glsl_compiler = find_program('glslang', 'glslangValidator')
|
||||
glsl_args = [
|
||||
'--quiet',
|
||||
'--target-env', 'vulkan1.2',
|
||||
'--target-env', 'vulkan1.3',
|
||||
'--vn', '@BASENAME@',
|
||||
'--depfile', '@DEPFILE@',
|
||||
'@INPUT@',
|
||||
|
@ -163,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
|
||||
|
|
|
@ -9,10 +9,14 @@ extern "C" {
|
|||
HRESULT __stdcall D3D11CoreCreateDevice(
|
||||
IDXGIFactory* pFactory,
|
||||
IDXGIAdapter* pAdapter,
|
||||
D3D_DRIVER_TYPE DriverType,
|
||||
HMODULE Software,
|
||||
UINT Flags,
|
||||
const D3D_FEATURE_LEVEL* pFeatureLevels,
|
||||
UINT FeatureLevels,
|
||||
ID3D11Device** ppDevice);
|
||||
UINT SDKVersion,
|
||||
ID3D11Device** ppDevice,
|
||||
D3D_FEATURE_LEVEL* pFeatureLevel);
|
||||
|
||||
|
||||
DLLEXPORT HRESULT __stdcall D3D10CoreCreateDevice(
|
||||
|
@ -31,8 +35,8 @@ extern "C" {
|
|||
if (FAILED(hr))
|
||||
return hr;
|
||||
|
||||
hr = D3D11CoreCreateDevice(pFactory, pAdapter,
|
||||
Flags, &FeatureLevel, 1, &d3d11Device);
|
||||
hr = D3D11CoreCreateDevice(pFactory, pAdapter, D3D_DRIVER_TYPE_UNKNOWN,
|
||||
nullptr, Flags, &FeatureLevel, 1, D3D11_SDK_VERSION, &d3d11Device, nullptr);
|
||||
|
||||
if (FAILED(hr))
|
||||
return hr;
|
||||
|
|
|
@ -7,21 +7,31 @@ d3d10_core_src = [
|
|||
d3d10_core_ld_args = []
|
||||
d3d10_core_link_depends = []
|
||||
|
||||
if platform != 'windows'
|
||||
if platform == 'windows'
|
||||
d3d10_d3d11_dep = lib_d3d11
|
||||
else
|
||||
d3d10_core_ld_args += [ '-Wl,--version-script', join_paths(meson.current_source_dir(), 'd3d10core.sym') ]
|
||||
d3d10_core_link_depends += files('d3d10core.sym')
|
||||
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,
|
||||
dependencies : [ d3d11_dep ],
|
||||
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;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -58,8 +58,11 @@ namespace dxvk {
|
|||
return S_OK;
|
||||
}
|
||||
|
||||
Logger::warn("D3D11BlendState::QueryInterface: Unknown interface query");
|
||||
Logger::warn(str::format(riid));
|
||||
if (logQueryInterfaceError(__uuidof(ID3D11BlendState), riid)) {
|
||||
Logger::warn("D3D11BlendState::QueryInterface: Unknown interface query");
|
||||
Logger::warn(str::format(riid));
|
||||
}
|
||||
|
||||
return E_NOINTERFACE;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,17 +1,17 @@
|
|||
#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(
|
||||
D3D11Device* pDevice,
|
||||
const D3D11_BUFFER_DESC* pDesc)
|
||||
const D3D11_BUFFER_DESC* pDesc,
|
||||
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;
|
||||
|
@ -83,29 +83,51 @@ namespace dxvk {
|
|||
info.access |= VK_ACCESS_HOST_WRITE_BIT;
|
||||
}
|
||||
|
||||
if (!(pDesc->MiscFlags & D3D11_RESOURCE_MISC_TILE_POOL)) {
|
||||
// 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;
|
||||
|
||||
DxvkBufferImportInfo importInfo;
|
||||
importInfo.buffer = VkBuffer(m_11on12.VulkanHandle);
|
||||
importInfo.offset = m_11on12.VulkanOffset;
|
||||
|
||||
if (m_desc.CPUAccessFlags)
|
||||
m_11on12.Resource->Map(0, nullptr, &importInfo.mapPtr);
|
||||
|
||||
m_buffer = m_parent->GetDXVKDevice()->importBuffer(info, importInfo, GetMemoryFlags());
|
||||
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();
|
||||
|
||||
// For Stream Output buffers we need a counter
|
||||
if (pDesc->BindFlags & D3D11_BIND_STREAM_OUTPUT)
|
||||
m_soCounter = CreateSoCounterBuffer();
|
||||
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;
|
||||
}
|
||||
|
||||
// For Stream Output buffers we need a counter
|
||||
if (pDesc->BindFlags & D3D11_BIND_STREAM_OUTPUT)
|
||||
m_soCounter = CreateSoCounterBuffer();
|
||||
}
|
||||
|
||||
|
||||
D3D11Buffer::~D3D11Buffer() {
|
||||
|
||||
if (m_desc.CPUAccessFlags && m_11on12.Resource != nullptr)
|
||||
m_11on12.Resource->Unmap(0, nullptr);
|
||||
}
|
||||
|
||||
|
||||
|
@ -138,8 +160,11 @@ namespace dxvk {
|
|||
return S_OK;
|
||||
}
|
||||
|
||||
Logger::warn("D3D11Buffer::QueryInterface: Unknown interface query");
|
||||
Logger::warn(str::format(riid));
|
||||
if (logQueryInterfaceError(__uuidof(ID3D11Buffer), riid)) {
|
||||
Logger::warn("D3D11Buffer::QueryInterface: Unknown interface query");
|
||||
Logger::warn(str::format(riid));
|
||||
}
|
||||
|
||||
return E_NOINTERFACE;
|
||||
}
|
||||
|
||||
|
@ -187,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))
|
||||
|
@ -238,6 +275,36 @@ namespace dxvk {
|
|||
}
|
||||
|
||||
|
||||
HRESULT D3D11Buffer::GetDescFromD3D12(
|
||||
ID3D12Resource* pResource,
|
||||
const D3D11_RESOURCE_FLAGS* pResourceFlags,
|
||||
D3D11_BUFFER_DESC* pBufferDesc) {
|
||||
D3D12_RESOURCE_DESC desc12 = pResource->GetDesc();
|
||||
|
||||
pBufferDesc->ByteWidth = desc12.Width;
|
||||
pBufferDesc->Usage = D3D11_USAGE_DEFAULT;
|
||||
pBufferDesc->BindFlags = D3D11_BIND_SHADER_RESOURCE;
|
||||
pBufferDesc->MiscFlags = 0;
|
||||
pBufferDesc->CPUAccessFlags = 0;
|
||||
pBufferDesc->StructureByteStride = 0;
|
||||
|
||||
if (desc12.Flags & D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET)
|
||||
pBufferDesc->BindFlags |= D3D11_BIND_RENDER_TARGET;
|
||||
|
||||
if (desc12.Flags & D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS)
|
||||
pBufferDesc->BindFlags |= D3D11_BIND_UNORDERED_ACCESS;
|
||||
|
||||
if (pResourceFlags) {
|
||||
pBufferDesc->BindFlags = pResourceFlags->BindFlags;
|
||||
pBufferDesc->MiscFlags |= pResourceFlags->MiscFlags;
|
||||
pBufferDesc->CPUAccessFlags = pResourceFlags->CPUAccessFlags;
|
||||
pBufferDesc->StructureByteStride = pResourceFlags->StructureByteStride;
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
BOOL D3D11Buffer::CheckFormatFeatureSupport(
|
||||
VkFormat Format,
|
||||
VkFormatFeatureFlags2 Features) const {
|
||||
|
@ -290,6 +357,7 @@ namespace dxvk {
|
|||
|| (m_parent->GetOptions()->cachedDynamicResources & m_desc.BindFlags);
|
||||
|
||||
if ((memoryFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) && useCached) {
|
||||
memoryFlags &= ~VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
|
||||
memoryFlags |= VK_MEMORY_PROPERTY_HOST_COHERENT_BIT
|
||||
| VK_MEMORY_PROPERTY_HOST_CACHED_BIT;
|
||||
}
|
||||
|
@ -315,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;
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
|
||||
#include "d3d11_device_child.h"
|
||||
#include "d3d11_interfaces.h"
|
||||
#include "d3d11_on_12.h"
|
||||
#include "d3d11_resource.h"
|
||||
|
||||
namespace dxvk {
|
||||
|
@ -41,7 +42,9 @@ namespace dxvk {
|
|||
|
||||
D3D11Buffer(
|
||||
D3D11Device* pDevice,
|
||||
const D3D11_BUFFER_DESC* pDesc);
|
||||
const D3D11_BUFFER_DESC* pDesc,
|
||||
const D3D11_ON_12_RESOURCE_INFO* p11on12Info);
|
||||
|
||||
~D3D11Buffer();
|
||||
|
||||
HRESULT STDMETHODCALLTYPE QueryInterface(
|
||||
|
@ -58,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;
|
||||
|
@ -74,6 +79,10 @@ namespace dxvk {
|
|||
return m_mapMode;
|
||||
}
|
||||
|
||||
uint64_t GetCookie() const {
|
||||
return m_cookie;
|
||||
}
|
||||
|
||||
Rc<DxvkBuffer> GetBuffer() const {
|
||||
return m_buffer;
|
||||
}
|
||||
|
@ -110,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() {
|
||||
|
@ -142,6 +152,14 @@ namespace dxvk {
|
|||
: DxvkCsThread::SynchronizeAll;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Retrieves D3D11on12 resource info
|
||||
* \returns 11on12 resource info
|
||||
*/
|
||||
D3D11_ON_12_RESOURCE_INFO Get11on12Info() const {
|
||||
return m_11on12;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Normalizes buffer description
|
||||
*
|
||||
|
@ -151,17 +169,34 @@ namespace dxvk {
|
|||
static HRESULT NormalizeBufferProperties(
|
||||
D3D11_BUFFER_DESC* pDesc);
|
||||
|
||||
/**
|
||||
* \brief Initializes D3D11 buffer description from D3D12
|
||||
*
|
||||
* \param [in] pResource D3D12 resource
|
||||
* \param [in] pResourceFlags D3D11 flag overrides
|
||||
* \param [out] pBufferDesc D3D11 buffer description
|
||||
* \returns \c S_OK if the parameters are valid
|
||||
*/
|
||||
static HRESULT GetDescFromD3D12(
|
||||
ID3D12Resource* pResource,
|
||||
const D3D11_RESOURCE_FLAGS* pResourceFlags,
|
||||
D3D11_BUFFER_DESC* pBufferDesc);
|
||||
|
||||
private:
|
||||
|
||||
D3D11_BUFFER_DESC m_desc;
|
||||
D3D11_ON_12_RESOURCE_INFO m_11on12;
|
||||
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;
|
||||
|
||||
|
@ -173,7 +208,8 @@ namespace dxvk {
|
|||
|
||||
Rc<DxvkBuffer> CreateSoCounterBuffer();
|
||||
|
||||
D3D11_COMMON_BUFFER_MAP_MODE DetermineMapMode();
|
||||
static D3D11_COMMON_BUFFER_MAP_MODE DetermineMapMode(
|
||||
VkMemoryPropertyFlags MemFlags);
|
||||
|
||||
};
|
||||
|
||||
|
|
|
@ -28,8 +28,11 @@ namespace dxvk {
|
|||
return S_OK;
|
||||
}
|
||||
|
||||
Logger::warn("D3D11ClassLinkage::QueryInterface: Unknown interface query");
|
||||
Logger::warn(str::format(riid));
|
||||
if (logQueryInterfaceError(__uuidof(ID3D11ClassLinkage), riid)) {
|
||||
Logger::warn("D3D11ClassLinkage::QueryInterface: Unknown interface query");
|
||||
Logger::warn(str::format(riid));
|
||||
}
|
||||
|
||||
return E_NOINTERFACE;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -30,8 +30,11 @@ namespace dxvk {
|
|||
return S_OK;
|
||||
}
|
||||
|
||||
Logger::warn("D3D11CommandList::QueryInterface: Unknown interface query");
|
||||
Logger::warn(str::format(riid));
|
||||
if (logQueryInterfaceError(__uuidof(ID3D11CommandList), riid)) {
|
||||
Logger::warn("D3D11CommandList::QueryInterface: Unknown interface query");
|
||||
Logger::warn(str::format(riid));
|
||||
}
|
||||
|
||||
return E_NOINTERFACE;
|
||||
}
|
||||
|
||||
|
@ -71,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;
|
||||
|
@ -99,8 +100,6 @@ namespace dxvk {
|
|||
while (j < m_resources.size() && m_resources[j].chunkId == i)
|
||||
TrackResourceSequenceNumber(m_resources[j++].ref, seq);
|
||||
}
|
||||
|
||||
MarkSubmitted();
|
||||
}
|
||||
|
||||
|
||||
|
@ -147,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();
|
||||
}
|
||||
|
@ -49,7 +45,7 @@ namespace dxvk {
|
|||
if (this_thread::isInModuleDetachment())
|
||||
return;
|
||||
|
||||
ExecuteFlush(GpuFlushType::ExplicitFlush, nullptr);
|
||||
ExecuteFlush(GpuFlushType::ExplicitFlush, nullptr, true);
|
||||
SynchronizeCsThread(DxvkCsThread::SynchronizeAll);
|
||||
SynchronizeDevice();
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -150,7 +150,7 @@ namespace dxvk {
|
|||
query->NotifyEnd();
|
||||
|
||||
if (query->IsStalling())
|
||||
ExecuteFlush(GpuFlushType::ImplicitSynchronization, nullptr);
|
||||
ExecuteFlush(GpuFlushType::ImplicitSynchronization, nullptr, false);
|
||||
else if (query->IsEvent())
|
||||
ConsiderFlush(GpuFlushType::ImplicitStrongHint);
|
||||
}
|
||||
|
@ -160,7 +160,10 @@ namespace dxvk {
|
|||
void STDMETHODCALLTYPE D3D11ImmediateContext::Flush() {
|
||||
D3D10DeviceLock lock = LockContext();
|
||||
|
||||
ExecuteFlush(GpuFlushType::ExplicitFlush, nullptr);
|
||||
if (unlikely(m_device->debugFlags().test(DxvkDebugFlag::Capture)))
|
||||
m_flushReason = "Explicit Flush";
|
||||
|
||||
ExecuteFlush(GpuFlushType::ExplicitFlush, nullptr, true);
|
||||
}
|
||||
|
||||
|
||||
|
@ -169,7 +172,10 @@ namespace dxvk {
|
|||
HANDLE hEvent) {
|
||||
D3D10DeviceLock lock = LockContext();
|
||||
|
||||
ExecuteFlush(GpuFlushType::ExplicitFlush, hEvent);
|
||||
if (unlikely(m_device->debugFlags().test(DxvkDebugFlag::Capture)))
|
||||
m_flushReason = "Explicit Flush";
|
||||
|
||||
ExecuteFlush(GpuFlushType::ExplicitFlush, hEvent, true);
|
||||
}
|
||||
|
||||
|
||||
|
@ -189,7 +195,10 @@ namespace dxvk {
|
|||
ctx->signalFence(cFence, cValue);
|
||||
});
|
||||
|
||||
ExecuteFlush(GpuFlushType::ExplicitFlush, nullptr);
|
||||
if (unlikely(m_device->debugFlags().test(DxvkDebugFlag::Capture)))
|
||||
m_flushReason = "Fence signal";
|
||||
|
||||
ExecuteFlush(GpuFlushType::ExplicitFlush, nullptr, true);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
@ -203,7 +212,10 @@ namespace dxvk {
|
|||
if (!fence)
|
||||
return E_INVALIDARG;
|
||||
|
||||
ExecuteFlush(GpuFlushType::ExplicitFlush, nullptr);
|
||||
if (unlikely(m_device->debugFlags().test(DxvkDebugFlag::Capture)))
|
||||
m_flushReason = "Fence wait";
|
||||
|
||||
ExecuteFlush(GpuFlushType::ExplicitFlush, nullptr, true);
|
||||
|
||||
EmitCs([
|
||||
cFence = fence->GetFence(),
|
||||
|
@ -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);
|
||||
|
@ -753,6 +801,74 @@ namespace dxvk {
|
|||
}
|
||||
|
||||
|
||||
void D3D11ImmediateContext::Acquire11on12Resource(
|
||||
ID3D11Resource* pResource,
|
||||
VkImageLayout SrcLayout) {
|
||||
D3D10DeviceLock lock = LockContext();
|
||||
|
||||
auto texture = GetCommonTexture(pResource);
|
||||
auto buffer = GetCommonBuffer(pResource);
|
||||
|
||||
if (buffer) {
|
||||
EmitCs([
|
||||
cBuffer = buffer->GetBuffer()
|
||||
] (DxvkContext* ctx) {
|
||||
ctx->emitBufferBarrier(cBuffer,
|
||||
VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
|
||||
VK_ACCESS_MEMORY_WRITE_BIT | VK_ACCESS_MEMORY_READ_BIT,
|
||||
cBuffer->info().stages,
|
||||
cBuffer->info().access);
|
||||
});
|
||||
} else if (texture) {
|
||||
EmitCs([
|
||||
cImage = texture->GetImage(),
|
||||
cLayout = SrcLayout
|
||||
] (DxvkContext* ctx) {
|
||||
ctx->emitImageBarrier(cImage, cLayout,
|
||||
VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
|
||||
VK_ACCESS_MEMORY_WRITE_BIT | VK_ACCESS_MEMORY_READ_BIT,
|
||||
cImage->info().layout,
|
||||
cImage->info().stages,
|
||||
cImage->info().access);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void D3D11ImmediateContext::Release11on12Resource(
|
||||
ID3D11Resource* pResource,
|
||||
VkImageLayout DstLayout) {
|
||||
D3D10DeviceLock lock = LockContext();
|
||||
|
||||
auto texture = GetCommonTexture(pResource);
|
||||
auto buffer = GetCommonBuffer(pResource);
|
||||
|
||||
if (buffer) {
|
||||
EmitCs([
|
||||
cBuffer = buffer->GetBuffer()
|
||||
] (DxvkContext* ctx) {
|
||||
ctx->emitBufferBarrier(cBuffer,
|
||||
cBuffer->info().stages,
|
||||
cBuffer->info().access,
|
||||
VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
|
||||
VK_ACCESS_MEMORY_WRITE_BIT | VK_ACCESS_MEMORY_READ_BIT);
|
||||
});
|
||||
} else if (texture) {
|
||||
EmitCs([
|
||||
cImage = texture->GetImage(),
|
||||
cLayout = DstLayout
|
||||
] (DxvkContext* ctx) {
|
||||
ctx->emitImageBarrier(cImage,
|
||||
cImage->info().layout,
|
||||
cImage->info().stages,
|
||||
cImage->info().access,
|
||||
cLayout, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
|
||||
VK_ACCESS_MEMORY_WRITE_BIT | VK_ACCESS_MEMORY_READ_BIT);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void D3D11ImmediateContext::SynchronizeCsThread(uint64_t SequenceNumber) {
|
||||
D3D10DeviceLock lock = LockContext();
|
||||
|
||||
|
@ -770,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) {
|
||||
|
@ -792,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);
|
||||
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));
|
||||
}
|
||||
|
||||
|
@ -859,28 +1001,130 @@ 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();
|
||||
|
||||
if (m_flushTracker.considerFlush(FlushType, chunkId, submissionId))
|
||||
ExecuteFlush(FlushType, nullptr);
|
||||
ExecuteFlush(FlushType, nullptr, false);
|
||||
}
|
||||
|
||||
|
||||
void D3D11ImmediateContext::ExecuteFlush(
|
||||
GpuFlushType FlushType,
|
||||
HANDLE hEvent) {
|
||||
// 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();
|
||||
HANDLE hEvent,
|
||||
BOOL Synchronize) {
|
||||
bool synchronizeSubmission = Synchronize && m_parent->Is11on12Device();
|
||||
|
||||
if (synchronizeSubmission)
|
||||
m_submitStatus.result = VK_NOT_READY;
|
||||
|
||||
// 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;
|
||||
|
||||
|
@ -892,10 +1136,17 @@ namespace dxvk {
|
|||
|
||||
EmitCs<false>([
|
||||
cSubmissionFence = m_submissionFence,
|
||||
cSubmissionId = submissionId
|
||||
cSubmissionId = submissionId,
|
||||
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();
|
||||
ctx->signal(cStagingFence, cStagingMemory);
|
||||
ctx->flushCommandList(&debugLabel, cSubmissionStatus);
|
||||
});
|
||||
|
||||
FlushCsChunk();
|
||||
|
@ -903,6 +1154,74 @@ namespace dxvk {
|
|||
// Notify flush tracker about the flush
|
||||
m_flushSeqNum = m_csSeqNum;
|
||||
m_flushTracker.notifyFlush(m_flushSeqNum, submissionId);
|
||||
|
||||
// If necessary, block calling thread until the
|
||||
// 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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -17,6 +17,7 @@ namespace dxvk {
|
|||
friend class D3D11CommonContext<D3D11ImmediateContext>;
|
||||
friend class D3D11SwapChain;
|
||||
friend class D3D11VideoContext;
|
||||
friend class D3D11DXGIKeyedMutex;
|
||||
public:
|
||||
|
||||
D3D11ImmediateContext(
|
||||
|
@ -77,13 +78,40 @@ namespace dxvk {
|
|||
ID3DDeviceContextState* pState,
|
||||
ID3DDeviceContextState** ppPreviousState);
|
||||
|
||||
void Acquire11on12Resource(
|
||||
ID3D11Resource* pResource,
|
||||
VkImageLayout SrcLayout);
|
||||
|
||||
void Release11on12Resource(
|
||||
ID3D11Resource* pResource,
|
||||
VkImageLayout DstLayout);
|
||||
|
||||
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;
|
||||
|
@ -91,19 +119,27 @@ namespace dxvk {
|
|||
|
||||
uint32_t m_mappedImageCount = 0u;
|
||||
|
||||
VkDeviceSize m_maxImplicitDiscardSize = 0ull;
|
||||
|
||||
Rc<sync::CallbackFence> m_submissionFence;
|
||||
uint64_t m_submissionId = 0ull;
|
||||
DxvkSubmitStatus m_submitStatus;
|
||||
|
||||
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,
|
||||
|
@ -139,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);
|
||||
|
@ -160,12 +197,26 @@ namespace dxvk {
|
|||
|
||||
uint64_t GetPendingCsChunks();
|
||||
|
||||
void ApplyDirtyNullBindings();
|
||||
|
||||
void ConsiderFlush(
|
||||
GpuFlushType FlushType);
|
||||
|
||||
void ExecuteFlush(
|
||||
GpuFlushType FlushType,
|
||||
HANDLE hEvent);
|
||||
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"
|
||||
|
|
|
@ -37,12 +37,15 @@ namespace dxvk {
|
|||
|
||||
if (riid == __uuidof(ID3D10DeviceChild)
|
||||
|| riid == __uuidof(ID3D10DepthStencilState)) {
|
||||
*ppvObject = ref(this);
|
||||
*ppvObject = ref(&m_d3d10);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
Logger::warn("D3D11DepthStencilState::QueryInterface: Unknown interface query");
|
||||
Logger::warn(str::format(riid));
|
||||
if (logQueryInterfaceError(__uuidof(ID3D11DepthStencilState), riid)) {
|
||||
Logger::warn("D3D11DepthStencilState::QueryInterface: Unknown interface query");
|
||||
Logger::warn(str::format(riid));
|
||||
}
|
||||
|
||||
return E_NOINTERFACE;
|
||||
}
|
||||
|
||||
|
|
|
@ -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());
|
||||
|
@ -100,7 +100,7 @@ namespace dxvk {
|
|||
return S_FALSE;
|
||||
|
||||
try {
|
||||
const Com<D3D11Buffer> buffer = new D3D11Buffer(this, &desc);
|
||||
const Com<D3D11Buffer> buffer = new D3D11Buffer(this, &desc, nullptr);
|
||||
|
||||
if (!(desc.MiscFlags & D3D11_RESOURCE_MISC_TILE_POOL))
|
||||
m_initializer->InitBuffer(buffer.ptr(), pInitialData);
|
||||
|
@ -149,7 +149,7 @@ namespace dxvk {
|
|||
return S_FALSE;
|
||||
|
||||
try {
|
||||
const Com<D3D11Texture1D> texture = new D3D11Texture1D(this, &desc);
|
||||
const Com<D3D11Texture1D> texture = new D3D11Texture1D(this, &desc, nullptr);
|
||||
m_initializer->InitTexture(texture->GetCommonTexture(), pInitialData);
|
||||
*ppTexture1D = texture.ref();
|
||||
return S_OK;
|
||||
|
@ -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;
|
||||
|
@ -229,7 +237,7 @@ namespace dxvk {
|
|||
return S_FALSE;
|
||||
|
||||
try {
|
||||
Com<D3D11Texture2D> texture = new D3D11Texture2D(this, &desc, nullptr);
|
||||
Com<D3D11Texture2D> texture = new D3D11Texture2D(this, &desc, nullptr, nullptr);
|
||||
m_initializer->InitTexture(texture->GetCommonTexture(), pInitialData);
|
||||
*ppTexture2D = texture.ref();
|
||||
return S_OK;
|
||||
|
@ -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;
|
||||
|
@ -308,7 +324,7 @@ namespace dxvk {
|
|||
return S_FALSE;
|
||||
|
||||
try {
|
||||
Com<D3D11Texture3D> texture = new D3D11Texture3D(this, &desc);
|
||||
Com<D3D11Texture3D> texture = new D3D11Texture3D(this, &desc, nullptr);
|
||||
m_initializer->InitTexture(texture->GetCommonTexture(), pInitialData);
|
||||
*ppTexture3D = texture.ref();
|
||||
return S_OK;
|
||||
|
@ -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(
|
||||
|
@ -1832,10 +1888,10 @@ namespace dxvk {
|
|||
DXGI_VK_FORMAT_MODE Mode) const {
|
||||
return m_d3d11Formats.GetFormatFamily(Format, Mode);
|
||||
}
|
||||
|
||||
|
||||
void D3D11Device::FlushInitContext() {
|
||||
m_initializer->Flush();
|
||||
|
||||
|
||||
bool D3D11Device::Is11on12Device() const {
|
||||
return m_container->Is11on12Device();
|
||||
}
|
||||
|
||||
|
||||
|
@ -1900,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;
|
||||
|
@ -1918,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
|
||||
|
@ -1948,6 +2001,11 @@ namespace dxvk {
|
|||
enabled.core.features.shaderFloat64 = supported.core.features.shaderFloat64;
|
||||
enabled.core.features.shaderInt64 = supported.core.features.shaderInt64;
|
||||
|
||||
// Depth bias control
|
||||
enabled.extDepthBiasControl.depthBiasControl = supported.extDepthBiasControl.depthBiasControl;
|
||||
enabled.extDepthBiasControl.depthBiasExact = supported.extDepthBiasControl.depthBiasExact;
|
||||
enabled.extDepthBiasControl.leastRepresentableValueForceUnormRepresentation = supported.extDepthBiasControl.leastRepresentableValueForceUnormRepresentation;
|
||||
|
||||
return enabled;
|
||||
}
|
||||
|
||||
|
@ -1959,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");
|
||||
|
||||
|
@ -2299,10 +2360,14 @@ namespace dxvk {
|
|||
d3d11Desc.CPUAccessFlags = metadata.CPUAccessFlags;
|
||||
d3d11Desc.MiscFlags = metadata.MiscFlags;
|
||||
d3d11Desc.TextureLayout = metadata.TextureLayout;
|
||||
if ((d3d11Desc.MiscFlags & D3D11_RESOURCE_MISC_SHARED_NTHANDLE) && !(d3d11Desc.MiscFlags & (D3D11_RESOURCE_MISC_SHARED | D3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX))) {
|
||||
Logger::warn("Fixing up wrong MiscFlags");
|
||||
d3d11Desc.MiscFlags |= D3D11_RESOURCE_MISC_SHARED;
|
||||
}
|
||||
|
||||
// Only 2D textures may be shared
|
||||
try {
|
||||
const Com<D3D11Texture2D> texture = new D3D11Texture2D(this, &d3d11Desc, hResource);
|
||||
const Com<D3D11Texture2D> texture = new D3D11Texture2D(this, &d3d11Desc, nullptr, hResource);
|
||||
texture->QueryInterface(ReturnedInterface, ppResource);
|
||||
return S_OK;
|
||||
}
|
||||
|
@ -2370,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
|
||||
|
@ -2478,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
|
||||
|
@ -2544,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;
|
||||
}
|
||||
|
||||
|
@ -2567,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)
|
||||
|
@ -2627,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;
|
||||
|
@ -2768,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,
|
||||
|
@ -2971,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)
|
||||
|
@ -3057,18 +3336,23 @@ namespace dxvk {
|
|||
|
||||
D3D11DXGIDevice::D3D11DXGIDevice(
|
||||
IDXGIAdapter* pAdapter,
|
||||
const Rc<DxvkInstance>& pDxvkInstance,
|
||||
const Rc<DxvkAdapter>& pDxvkAdapter,
|
||||
ID3D12Device* pD3D12Device,
|
||||
ID3D12CommandQueue* pD3D12Queue,
|
||||
Rc<DxvkInstance> pDxvkInstance,
|
||||
Rc<DxvkAdapter> pDxvkAdapter,
|
||||
Rc<DxvkDevice> pDxvkDevice,
|
||||
D3D_FEATURE_LEVEL FeatureLevel,
|
||||
UINT FeatureFlags)
|
||||
: m_dxgiAdapter (pAdapter),
|
||||
m_dxvkInstance (pDxvkInstance),
|
||||
m_dxvkAdapter (pDxvkAdapter),
|
||||
m_dxvkDevice (CreateDevice(FeatureLevel)),
|
||||
m_dxvkDevice (pDxvkDevice),
|
||||
m_d3d11Device (this, FeatureLevel, FeatureFlags),
|
||||
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) {
|
||||
|
||||
|
@ -3076,7 +3360,7 @@ namespace dxvk {
|
|||
|
||||
|
||||
D3D11DXGIDevice::~D3D11DXGIDevice() {
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
@ -3140,6 +3424,19 @@ namespace dxvk {
|
|||
return S_OK;
|
||||
}
|
||||
|
||||
if (riid == __uuidof(ID3DLowLatencyDevice)) {
|
||||
*ppvObject = ref(&m_d3d11Reflex);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
if (m_d3d11on12.Is11on12Device()) {
|
||||
if (riid == __uuidof(ID3D11On12Device)
|
||||
|| riid == __uuidof(ID3D11On12Device1_DXVK)) {
|
||||
*ppvObject = ref(&m_d3d11on12);
|
||||
return S_OK;
|
||||
}
|
||||
}
|
||||
|
||||
if (riid == __uuidof(ID3D10Multithread)) {
|
||||
Com<ID3D11DeviceContext> context;
|
||||
m_d3d11Device.GetImmediateContext(&context);
|
||||
|
@ -3153,8 +3450,11 @@ namespace dxvk {
|
|||
if (riid == GUID{0xd56e2a4c,0x5127,0x8437,{0x65,0x8a,0x98,0xc5,0xbb,0x78,0x94,0x98}})
|
||||
return E_NOINTERFACE;
|
||||
|
||||
Logger::warn("D3D11DXGIDevice::QueryInterface: Unknown interface query");
|
||||
Logger::warn(str::format(riid));
|
||||
if (logQueryInterfaceError(__uuidof(IDXGIDXVKDevice), riid)) {
|
||||
Logger::warn("D3D11DXGIDevice::QueryInterface: Unknown interface query");
|
||||
Logger::warn(str::format(riid));
|
||||
}
|
||||
|
||||
return E_NOINTERFACE;
|
||||
}
|
||||
|
||||
|
@ -3383,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;
|
||||
}
|
||||
|
||||
|
||||
|
@ -3400,10 +3701,4 @@ namespace dxvk {
|
|||
return m_dxvkDevice;
|
||||
}
|
||||
|
||||
|
||||
Rc<DxvkDevice> D3D11DXGIDevice::CreateDevice(D3D_FEATURE_LEVEL FeatureLevel) {
|
||||
DxvkDeviceFeatures deviceFeatures = D3D11Device::GetDeviceFeatures(m_dxvkAdapter);
|
||||
return m_dxvkAdapter->createDevice(m_dxvkInstance, deviceFeatures);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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"
|
||||
|
||||
|
@ -20,6 +21,7 @@
|
|||
#include "d3d11_initializer.h"
|
||||
#include "d3d11_interfaces.h"
|
||||
#include "d3d11_interop.h"
|
||||
#include "d3d11_on_12.h"
|
||||
#include "d3d11_options.h"
|
||||
#include "d3d11_shader.h"
|
||||
#include "d3d11_state.h"
|
||||
|
@ -86,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,
|
||||
|
@ -96,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,
|
||||
|
@ -106,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,
|
||||
|
@ -116,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,
|
||||
|
@ -126,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,
|
||||
|
@ -224,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);
|
||||
|
@ -390,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();
|
||||
}
|
||||
|
@ -420,17 +464,35 @@ namespace dxvk {
|
|||
D3D10Device* GetD3D10Interface() const {
|
||||
return m_d3d10Device;
|
||||
}
|
||||
|
||||
|
||||
D3D11ImmediateContext* GetContext() const {
|
||||
return m_context.ptr();
|
||||
}
|
||||
|
||||
bool Is11on12Device() const;
|
||||
|
||||
static D3D_FEATURE_LEVEL GetMaxFeatureLevel(
|
||||
const Rc<DxvkInstance>& Instance,
|
||||
const Rc<DxvkAdapter>& Adapter);
|
||||
|
||||
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:
|
||||
|
||||
IDXGIObject* m_container;
|
||||
D3D11DXGIDevice* m_container;
|
||||
|
||||
D3D_FEATURE_LEVEL m_featureLevel;
|
||||
UINT m_featureFlags;
|
||||
|
@ -573,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;
|
||||
|
@ -690,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
|
||||
*/
|
||||
|
@ -764,8 +893,11 @@ namespace dxvk {
|
|||
|
||||
D3D11DXGIDevice(
|
||||
IDXGIAdapter* pAdapter,
|
||||
const Rc<DxvkInstance>& pDxvkInstance,
|
||||
const Rc<DxvkAdapter>& pDxvkAdapter,
|
||||
ID3D12Device* pD3D12Device,
|
||||
ID3D12CommandQueue* pD3D12Queue,
|
||||
Rc<DxvkInstance> pDxvkInstance,
|
||||
Rc<DxvkAdapter> pDxvkAdapter,
|
||||
Rc<DxvkDevice> pDxvkDevice,
|
||||
D3D_FEATURE_LEVEL FeatureLevel,
|
||||
UINT FeatureFlags);
|
||||
|
||||
|
@ -834,6 +966,10 @@ namespace dxvk {
|
|||
|
||||
Rc<DxvkDevice> STDMETHODCALLTYPE GetDXVKDevice();
|
||||
|
||||
BOOL Is11on12Device() const {
|
||||
return m_d3d11on12.Is11on12Device();
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
Com<IDXGIAdapter> m_dxgiAdapter;
|
||||
|
@ -846,14 +982,14 @@ namespace dxvk {
|
|||
D3D11DeviceExt m_d3d11DeviceExt;
|
||||
D3D11VkInterop m_d3d11Interop;
|
||||
D3D11VideoDevice m_d3d11Video;
|
||||
D3D11ReflexDevice m_d3d11Reflex;
|
||||
D3D11on12Device m_d3d11on12;
|
||||
DXGIDXVKDevice m_metaDevice;
|
||||
|
||||
DXGIVkSwapChainFactory m_dxvkFactory;
|
||||
|
||||
uint32_t m_frameLatency = DefaultFrameLatency;
|
||||
|
||||
Rc<DxvkDevice> CreateDevice(D3D_FEATURE_LEVEL FeatureLevel);
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -48,8 +48,11 @@ namespace dxvk {
|
|||
return S_OK;
|
||||
}
|
||||
|
||||
Logger::warn("D3D11Fence: Unknown interface query");
|
||||
Logger::warn(str::format(riid));
|
||||
if (logQueryInterfaceError(__uuidof(ID3D11Fence), riid)) {
|
||||
Logger::warn("D3D11Fence: Unknown interface query");
|
||||
Logger::warn(str::format(riid));
|
||||
}
|
||||
|
||||
return E_NOINTERFACE;
|
||||
}
|
||||
|
||||
|
|
|
@ -150,11 +150,8 @@ namespace dxvk {
|
|||
HRESULT D3D11GDISurface::CreateReadbackResource() {
|
||||
auto tex = GetCommonTexture(m_resource);
|
||||
|
||||
Com<ID3D11Device> device;
|
||||
Com<ID3D11DeviceContext> context;
|
||||
|
||||
Com<ID3D11Device> device;
|
||||
m_resource->GetDevice(&device);
|
||||
device->GetImmediateContext(&context);
|
||||
|
||||
D3D11_RESOURCE_DIMENSION dim = { };
|
||||
m_resource->GetType(&dim);
|
||||
|
|
|
@ -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) {
|
||||
|
@ -49,6 +50,8 @@ namespace dxvk {
|
|||
InitHostVisibleTexture(pTexture, pInitialData);
|
||||
else
|
||||
InitDeviceLocalTexture(pTexture, pInitialData);
|
||||
|
||||
SyncSharedTexture(pTexture);
|
||||
}
|
||||
|
||||
|
||||
|
@ -59,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();
|
||||
}
|
||||
|
||||
|
||||
|
@ -79,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();
|
||||
}
|
||||
|
||||
|
||||
|
@ -105,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);
|
||||
}
|
||||
|
||||
|
||||
|
@ -125,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();
|
||||
}
|
||||
|
||||
|
||||
|
@ -213,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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -252,36 +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();
|
||||
|
||||
void D3D11Initializer::ExecuteFlush() {
|
||||
std::lock_guard lock(m_mutex);
|
||||
|
||||
ExecuteFlushLocked();
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
|
||||
// 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;
|
||||
m_transferMemory = 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,9 +98,30 @@ namespace dxvk {
|
|||
void InitTiledTexture(
|
||||
D3D11CommonTexture* pTexture);
|
||||
|
||||
void FlushImplicit();
|
||||
void FlushInternal();
|
||||
void ThrottleAllocationLocked();
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -46,8 +46,11 @@ namespace dxvk {
|
|||
return S_OK;
|
||||
}
|
||||
|
||||
Logger::warn("D3D11InputLayout::QueryInterface: Unknown interface query");
|
||||
Logger::warn(str::format(riid));
|
||||
if (logQueryInterfaceError(__uuidof(ID3D11InputLayout), riid)) {
|
||||
Logger::warn("D3D11InputLayout::QueryInterface: Unknown interface query");
|
||||
Logger::warn(str::format(riid));
|
||||
}
|
||||
|
||||
return E_NOINTERFACE;
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -75,21 +75,15 @@ namespace dxvk {
|
|||
const VkImageSubresourceRange* pSubresources,
|
||||
VkImageLayout OldLayout,
|
||||
VkImageLayout NewLayout) {
|
||||
Com<ID3D11DeviceContext> deviceContext = nullptr;
|
||||
m_device->GetImmediateContext(&deviceContext);
|
||||
|
||||
auto immediateContext = static_cast<D3D11ImmediateContext*>(deviceContext.ptr());
|
||||
|
||||
auto immediateContext = m_device->GetContext();
|
||||
|
||||
immediateContext->TransitionSurfaceLayout(
|
||||
pSurface, pSubresources, OldLayout, NewLayout);
|
||||
}
|
||||
|
||||
|
||||
void STDMETHODCALLTYPE D3D11VkInterop::FlushRenderingCommands() {
|
||||
Com<ID3D11DeviceContext> deviceContext = nullptr;
|
||||
m_device->GetImmediateContext(&deviceContext);
|
||||
|
||||
auto immediateContext = static_cast<D3D11ImmediateContext*>(deviceContext.ptr());
|
||||
auto immediateContext = m_device->GetContext();
|
||||
immediateContext->Flush();
|
||||
immediateContext->SynchronizeCsThread(DxvkCsThread::SynchronizeAll);
|
||||
}
|
||||
|
|
|
@ -15,7 +15,7 @@ namespace dxvk {
|
|||
extern "C" {
|
||||
using namespace dxvk;
|
||||
|
||||
DLLEXPORT HRESULT __stdcall D3D11CoreCreateDevice(
|
||||
HRESULT D3D11InternalCreateDevice(
|
||||
IDXGIFactory* pFactory,
|
||||
IDXGIAdapter* pAdapter,
|
||||
UINT Flags,
|
||||
|
@ -34,11 +34,11 @@ extern "C" {
|
|||
dxvkAdapter = dxgiVkAdapter->GetDXVKAdapter();
|
||||
dxvkInstance = dxgiVkAdapter->GetDXVKInstance();
|
||||
} else {
|
||||
Logger::warn("D3D11CoreCreateDevice: Adapter is not a DXVK adapter");
|
||||
Logger::warn("D3D11InternalCreateDevice: Adapter is not a DXVK adapter");
|
||||
DXGI_ADAPTER_DESC desc;
|
||||
pAdapter->GetDesc(&desc);
|
||||
|
||||
dxvkInstance = new DxvkInstance();
|
||||
dxvkInstance = new DxvkInstance(0);
|
||||
dxvkAdapter = dxvkInstance->findAdapterByLuid(&desc.AdapterLuid);
|
||||
|
||||
if (dxvkAdapter == nullptr)
|
||||
|
@ -70,7 +70,7 @@ extern "C" {
|
|||
D3D_FEATURE_LEVEL minFeatureLevel = D3D_FEATURE_LEVEL();
|
||||
D3D_FEATURE_LEVEL devFeatureLevel = D3D_FEATURE_LEVEL();
|
||||
|
||||
Logger::info(str::format("D3D11CoreCreateDevice: Maximum supported feature level: ", maxFeatureLevel));
|
||||
Logger::info(str::format("D3D11InternalCreateDevice: Maximum supported feature level: ", maxFeatureLevel));
|
||||
|
||||
for (uint32_t flId = 0 ; flId < FeatureLevels; flId++) {
|
||||
minFeatureLevel = pFeatureLevels[flId];
|
||||
|
@ -82,21 +82,26 @@ extern "C" {
|
|||
}
|
||||
|
||||
if (!devFeatureLevel) {
|
||||
Logger::err(str::format("D3D11CoreCreateDevice: Minimum required feature level ", minFeatureLevel, " not supported"));
|
||||
Logger::err(str::format("D3D11InternalCreateDevice: Minimum required feature level ", minFeatureLevel, " not supported"));
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
|
||||
try {
|
||||
Logger::info(str::format("D3D11CoreCreateDevice: Using feature level ", devFeatureLevel));
|
||||
Logger::info(str::format("D3D11InternalCreateDevice: Using feature level ", devFeatureLevel));
|
||||
|
||||
DxvkDeviceFeatures deviceFeatures = D3D11Device::GetDeviceFeatures(dxvkAdapter);
|
||||
Rc<DxvkDevice> dxvkDevice = dxvkAdapter->createDevice(dxvkInstance, deviceFeatures);
|
||||
|
||||
Com<D3D11DXGIDevice> device = new D3D11DXGIDevice(
|
||||
pAdapter, dxvkInstance, dxvkAdapter, devFeatureLevel, Flags);
|
||||
pAdapter, nullptr, nullptr,
|
||||
dxvkInstance, dxvkAdapter, dxvkDevice,
|
||||
devFeatureLevel, Flags);
|
||||
|
||||
return device->QueryInterface(
|
||||
__uuidof(ID3D11Device),
|
||||
reinterpret_cast<void**>(ppDevice));
|
||||
} catch (const DxvkError& e) {
|
||||
Logger::err("D3D11CoreCreateDevice: Failed to create D3D11 device");
|
||||
Logger::err("D3D11InternalCreateDevice: Failed to create D3D11 device");
|
||||
return E_FAIL;
|
||||
}
|
||||
}
|
||||
|
@ -168,7 +173,7 @@ extern "C" {
|
|||
}
|
||||
|
||||
// Create the actual device
|
||||
hr = D3D11CoreCreateDevice(
|
||||
hr = D3D11InternalCreateDevice(
|
||||
dxgiFactory.ptr(), dxgiAdapter.ptr(),
|
||||
Flags, pFeatureLevels, FeatureLevels,
|
||||
&device);
|
||||
|
@ -207,6 +212,25 @@ extern "C" {
|
|||
}
|
||||
|
||||
|
||||
DLLEXPORT HRESULT __stdcall D3D11CoreCreateDevice(
|
||||
IDXGIFactory* pFactory,
|
||||
IDXGIAdapter* pAdapter,
|
||||
D3D_DRIVER_TYPE DriverType,
|
||||
HMODULE Software,
|
||||
UINT Flags,
|
||||
const D3D_FEATURE_LEVEL* pFeatureLevels,
|
||||
UINT FeatureLevels,
|
||||
UINT SDKVersion,
|
||||
ID3D11Device** ppDevice,
|
||||
D3D_FEATURE_LEVEL* pFeatureLevel) {
|
||||
return D3D11InternalCreateDeviceAndSwapChain(
|
||||
pAdapter, DriverType, Software, Flags,
|
||||
pFeatureLevels, FeatureLevels, SDKVersion,
|
||||
nullptr, nullptr,
|
||||
ppDevice, pFeatureLevel, nullptr);
|
||||
}
|
||||
|
||||
|
||||
DLLEXPORT HRESULT __stdcall D3D11CreateDevice(
|
||||
IDXGIAdapter* pAdapter,
|
||||
D3D_DRIVER_TYPE DriverType,
|
||||
|
@ -258,12 +282,169 @@ extern "C" {
|
|||
ID3D11Device** ppDevice,
|
||||
ID3D11DeviceContext** ppImmediateContext,
|
||||
D3D_FEATURE_LEVEL* pChosenFeatureLevel) {
|
||||
static bool s_errorShown = false;
|
||||
InitReturnPtr(ppDevice);
|
||||
InitReturnPtr(ppImmediateContext);
|
||||
|
||||
if (!std::exchange(s_errorShown, true))
|
||||
Logger::err("D3D11On12CreateDevice: Not implemented");
|
||||
if (pChosenFeatureLevel)
|
||||
*pChosenFeatureLevel = D3D_FEATURE_LEVEL(0);
|
||||
|
||||
return E_NOTIMPL;
|
||||
if (!pDevice)
|
||||
return E_INVALIDARG;
|
||||
|
||||
// Figure out D3D12 objects
|
||||
Com<ID3D12Device> d3d12Device;
|
||||
Com<ID3D12CommandQueue> d3d12Queue;
|
||||
|
||||
if (FAILED(pDevice->QueryInterface(__uuidof(ID3D12Device), reinterpret_cast<void**>(&d3d12Device)))) {
|
||||
Logger::err("D3D11On12CreateDevice: Device is not a valid D3D12 device");
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
|
||||
if (NodeMask & (NodeMask - 1)) {
|
||||
Logger::err("D3D11On12CreateDevice: Invalid node mask");
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
|
||||
if (!NumQueues || !ppCommandQueues || !ppCommandQueues[0]) {
|
||||
Logger::err("D3D11On12CreateDevice: No command queue specified");
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
|
||||
if (NumQueues > 1) {
|
||||
// Not sure what to do with more than one graphics queue
|
||||
Logger::warn("D3D11On12CreateDevice: Only one queue supported");
|
||||
}
|
||||
|
||||
if (FAILED(ppCommandQueues[0]->QueryInterface(__uuidof(ID3D12CommandQueue), reinterpret_cast<void**>(&d3d12Queue)))) {
|
||||
Logger::err("D3D11On12CreateDevice: Queue is not a valid D3D12 command queue");
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
|
||||
// Determine feature level for the D3D11 device
|
||||
std::array<D3D_FEATURE_LEVEL, 4> defaultFeatureLevels = {{
|
||||
D3D_FEATURE_LEVEL_11_0, D3D_FEATURE_LEVEL_11_1,
|
||||
D3D_FEATURE_LEVEL_12_0, D3D_FEATURE_LEVEL_12_1,
|
||||
}};
|
||||
|
||||
D3D12_FEATURE_DATA_FEATURE_LEVELS featureLevel = { };
|
||||
|
||||
if (!FeatureLevels || !pFeatureLevels) {
|
||||
featureLevel.NumFeatureLevels = defaultFeatureLevels.size();
|
||||
featureLevel.pFeatureLevelsRequested = defaultFeatureLevels.data();
|
||||
} else {
|
||||
featureLevel.NumFeatureLevels = FeatureLevels;
|
||||
featureLevel.pFeatureLevelsRequested = pFeatureLevels;
|
||||
}
|
||||
|
||||
HRESULT hr = d3d12Device->CheckFeatureSupport(D3D12_FEATURE_FEATURE_LEVELS, &featureLevel, sizeof(featureLevel));
|
||||
|
||||
if (FAILED(hr) || !featureLevel.MaxSupportedFeatureLevel) {
|
||||
Logger::err(str::format("D3D11On12CreateDevice: Minimum required feature level not supported"));
|
||||
return hr;
|
||||
}
|
||||
|
||||
Logger::info(str::format("D3D11On12CreateDevice: Chosen feature level: ", featureLevel.MaxSupportedFeatureLevel));
|
||||
|
||||
Com<ID3D12DXVKInteropDevice> interopDevice;
|
||||
|
||||
if (FAILED(d3d12Device->QueryInterface(__uuidof(ID3D12DXVKInteropDevice), reinterpret_cast<void**>(&interopDevice)))) {
|
||||
Logger::err("D3D11On12CreateDevice: Device not a vkd3d-proton device.");
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
|
||||
Com<IDXGIAdapter> dxgiAdapter;
|
||||
|
||||
if (FAILED(interopDevice->GetDXGIAdapter(IID_PPV_ARGS(&dxgiAdapter)))) {
|
||||
Logger::err("D3D11On12CreateDevice: Failed to query DXGI adapter.");
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
|
||||
try {
|
||||
// Initialize DXVK instance
|
||||
DxvkInstanceImportInfo instanceInfo = { };
|
||||
DxvkDeviceImportInfo deviceInfo = { };
|
||||
VkPhysicalDevice vulkanAdapter = VK_NULL_HANDLE;
|
||||
|
||||
interopDevice->GetVulkanHandles(&instanceInfo.instance, &vulkanAdapter, &deviceInfo.device);
|
||||
|
||||
uint32_t instanceExtensionCount = 0;
|
||||
interopDevice->GetInstanceExtensions(&instanceExtensionCount, nullptr);
|
||||
|
||||
std::vector<const char*> instanceExtensions(instanceExtensionCount);
|
||||
interopDevice->GetInstanceExtensions(&instanceExtensionCount, instanceExtensions.data());
|
||||
|
||||
instanceInfo.extensionCount = instanceExtensions.size();
|
||||
instanceInfo.extensionNames = instanceExtensions.data();
|
||||
|
||||
Rc<DxvkInstance> dxvkInstance = new DxvkInstance(instanceInfo, 0);
|
||||
|
||||
// Find adapter by physical device handle
|
||||
Rc<DxvkAdapter> dxvkAdapter;
|
||||
|
||||
for (uint32_t i = 0; i < dxvkInstance->adapterCount(); i++) {
|
||||
Rc<DxvkAdapter> curr = dxvkInstance->enumAdapters(i);
|
||||
|
||||
if (curr->handle() == vulkanAdapter)
|
||||
dxvkAdapter = std::move(curr);
|
||||
}
|
||||
|
||||
if (dxvkAdapter == nullptr) {
|
||||
Logger::err("D3D11On12CreateDevice: No matching adapter found");
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
|
||||
interopDevice->GetVulkanQueueInfo(d3d12Queue.ptr(), &deviceInfo.queue, &deviceInfo.queueFamily);
|
||||
interopDevice->GetDeviceFeatures(&deviceInfo.features);
|
||||
|
||||
uint32_t deviceExtensionCount = 0;
|
||||
interopDevice->GetDeviceExtensions(&deviceExtensionCount, nullptr);
|
||||
|
||||
std::vector<const char*> deviceExtensions(deviceExtensionCount);
|
||||
interopDevice->GetDeviceExtensions(&deviceExtensionCount, deviceExtensions.data());
|
||||
|
||||
deviceInfo.extensionCount = deviceExtensions.size();
|
||||
deviceInfo.extensionNames = deviceExtensions.data();
|
||||
|
||||
deviceInfo.queueCallback = [
|
||||
cDevice = interopDevice,
|
||||
cQueue = d3d12Queue
|
||||
] (bool doLock) {
|
||||
HRESULT hr = doLock
|
||||
? cDevice->LockCommandQueue(cQueue.ptr())
|
||||
: cDevice->UnlockCommandQueue(cQueue.ptr());
|
||||
|
||||
if (FAILED(hr))
|
||||
Logger::err(str::format("Failed to lock vkd3d-proton device queue: ", hr));
|
||||
};
|
||||
|
||||
Rc<DxvkDevice> dxvkDevice = dxvkAdapter->importDevice(dxvkInstance, deviceInfo);
|
||||
|
||||
// Create and return the actual D3D11 device
|
||||
Com<D3D11DXGIDevice> device = new D3D11DXGIDevice(
|
||||
dxgiAdapter.ptr(), d3d12Device.ptr(), d3d12Queue.ptr(),
|
||||
dxvkInstance, dxvkAdapter, dxvkDevice,
|
||||
featureLevel.MaxSupportedFeatureLevel, Flags);
|
||||
|
||||
Com<ID3D11Device> d3d11Device;
|
||||
device->QueryInterface(__uuidof(ID3D11Device), reinterpret_cast<void**>(&d3d11Device));
|
||||
|
||||
if (ppDevice)
|
||||
*ppDevice = d3d11Device.ref();
|
||||
|
||||
if (ppImmediateContext)
|
||||
d3d11Device->GetImmediateContext(ppImmediateContext);
|
||||
|
||||
if (pChosenFeatureLevel)
|
||||
*pChosenFeatureLevel = d3d11Device->GetFeatureLevel();
|
||||
|
||||
if (!ppDevice && !ppImmediateContext)
|
||||
return S_FALSE;
|
||||
|
||||
return S_OK;
|
||||
} catch (const DxvkError& e) {
|
||||
Logger::err("D3D11On12CreateDevice: Failed to create D3D11 device");
|
||||
return E_FAIL;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
157
src/d3d11/d3d11_on_12.cpp
Normal file
157
src/d3d11/d3d11_on_12.cpp
Normal file
|
@ -0,0 +1,157 @@
|
|||
#include "d3d11_context_imm.h"
|
||||
#include "d3d11_device.h"
|
||||
#include "d3d11_on_12.h"
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
D3D11on12Device::D3D11on12Device(
|
||||
D3D11DXGIDevice* pContainer,
|
||||
D3D11Device* pDevice,
|
||||
ID3D12Device* pD3D12Device,
|
||||
ID3D12CommandQueue* pD3D12Queue)
|
||||
: m_container (pContainer),
|
||||
m_device (pDevice),
|
||||
m_d3d12Device (pD3D12Device),
|
||||
m_d3d12Queue (pD3D12Queue) {
|
||||
|
||||
}
|
||||
|
||||
|
||||
D3D11on12Device::~D3D11on12Device() {
|
||||
|
||||
}
|
||||
|
||||
|
||||
ULONG STDMETHODCALLTYPE D3D11on12Device::AddRef() {
|
||||
return m_container->AddRef();
|
||||
}
|
||||
|
||||
|
||||
ULONG STDMETHODCALLTYPE D3D11on12Device::Release() {
|
||||
return m_container->Release();
|
||||
}
|
||||
|
||||
|
||||
HRESULT STDMETHODCALLTYPE D3D11on12Device::QueryInterface(
|
||||
REFIID riid,
|
||||
void** ppvObject) {
|
||||
return m_container->QueryInterface(riid, ppvObject);
|
||||
}
|
||||
|
||||
|
||||
HRESULT STDMETHODCALLTYPE D3D11on12Device::CreateWrappedResource(
|
||||
IUnknown* pResource12,
|
||||
const D3D11_RESOURCE_FLAGS* pResourceFlags,
|
||||
D3D12_RESOURCE_STATES InputState,
|
||||
D3D12_RESOURCE_STATES OutputState,
|
||||
REFIID riid,
|
||||
void** ppResource11) {
|
||||
Com<ID3D12DXVKInteropDevice> interopDevice;
|
||||
m_d3d12Device->QueryInterface(__uuidof(ID3D12DXVKInteropDevice), reinterpret_cast<void**>(&interopDevice));
|
||||
|
||||
D3D11_ON_12_RESOURCE_INFO info = { };
|
||||
info.InputState = InputState;
|
||||
info.OutputState = OutputState;
|
||||
info.IsWrappedResource = TRUE;
|
||||
|
||||
// 11on12 technically allows importing D3D12 heaps as tile pools,
|
||||
// but we don't support importing sparse resources at this time.
|
||||
if (FAILED(pResource12->QueryInterface(__uuidof(ID3D12Resource), reinterpret_cast<void**>(&info.Resource)))) {
|
||||
Logger::err("D3D11on12Device::CreateWrappedResource: Resource not a valid D3D12 resource");
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
|
||||
// Query Vulkan resource handle and buffer offset as necessary
|
||||
if (FAILED(interopDevice->GetVulkanResourceInfo(info.Resource.ptr(), &info.VulkanHandle, &info.VulkanOffset))) {
|
||||
Logger::err("D3D11on12Device::CreateWrappedResource: Failed to retrieve Vulkan resource info");
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
|
||||
Com<ID3D11Resource> resource;
|
||||
D3D12_RESOURCE_DESC desc = info.Resource->GetDesc();
|
||||
|
||||
if (desc.Dimension == D3D12_RESOURCE_DIMENSION_BUFFER) {
|
||||
D3D11_BUFFER_DESC bufferDesc;
|
||||
|
||||
if (FAILED(D3D11Buffer::GetDescFromD3D12(info.Resource.ptr(), pResourceFlags, &bufferDesc)))
|
||||
return E_INVALIDARG;
|
||||
|
||||
resource = new D3D11Buffer(m_device, &bufferDesc, &info);
|
||||
} else {
|
||||
D3D11_COMMON_TEXTURE_DESC textureDesc;
|
||||
|
||||
if (FAILED(D3D11CommonTexture::GetDescFromD3D12(info.Resource.ptr(), pResourceFlags, &textureDesc)))
|
||||
return E_INVALIDARG;
|
||||
|
||||
switch (desc.Dimension) {
|
||||
case D3D12_RESOURCE_DIMENSION_TEXTURE1D:
|
||||
resource = new D3D11Texture1D(m_device, &textureDesc, &info);
|
||||
break;
|
||||
|
||||
case D3D12_RESOURCE_DIMENSION_TEXTURE2D:
|
||||
resource = new D3D11Texture2D(m_device, &textureDesc, &info, nullptr);
|
||||
break;
|
||||
|
||||
case D3D12_RESOURCE_DIMENSION_TEXTURE3D:
|
||||
resource = new D3D11Texture3D(m_device, &textureDesc, &info);
|
||||
break;
|
||||
|
||||
default:
|
||||
Logger::err("D3D11on12Device::CreateWrappedResource: Unhandled resource dimension");
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
}
|
||||
|
||||
return resource->QueryInterface(riid, ppResource11);
|
||||
}
|
||||
|
||||
|
||||
void STDMETHODCALLTYPE D3D11on12Device::ReleaseWrappedResources(
|
||||
ID3D11Resource* const* ppResources,
|
||||
UINT ResourceCount) {
|
||||
Com<ID3D12DXVKInteropDevice> interopDevice;
|
||||
m_d3d12Device->QueryInterface(__uuidof(ID3D12DXVKInteropDevice), reinterpret_cast<void**>(&interopDevice));
|
||||
|
||||
for (uint32_t i = 0; i < ResourceCount; i++) {
|
||||
D3D11_ON_12_RESOURCE_INFO info;
|
||||
|
||||
if (FAILED(GetResource11on12Info(ppResources[i], &info)) || !info.IsWrappedResource) {
|
||||
Logger::warn("D3D11on12Device::ReleaseWrappedResources: Resource not a wrapped resource, skipping");
|
||||
continue;
|
||||
}
|
||||
|
||||
VkImageLayout layout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||
interopDevice->GetVulkanImageLayout(info.Resource.ptr(), info.OutputState, &layout);
|
||||
m_device->GetContext()->Release11on12Resource(ppResources[i], layout);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void STDMETHODCALLTYPE D3D11on12Device::AcquireWrappedResources(
|
||||
ID3D11Resource* const* ppResources,
|
||||
UINT ResourceCount) {
|
||||
Com<ID3D12DXVKInteropDevice> interopDevice;
|
||||
m_d3d12Device->QueryInterface(__uuidof(ID3D12DXVKInteropDevice), reinterpret_cast<void**>(&interopDevice));
|
||||
|
||||
for (uint32_t i = 0; i < ResourceCount; i++) {
|
||||
D3D11_ON_12_RESOURCE_INFO info;
|
||||
|
||||
if (FAILED(GetResource11on12Info(ppResources[i], &info)) || !info.IsWrappedResource) {
|
||||
Logger::warn("D3D11on12Device::AcquireWrappedResources: Resource not a wrapped resource, skipping");
|
||||
continue;
|
||||
}
|
||||
|
||||
VkImageLayout layout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||
interopDevice->GetVulkanImageLayout(info.Resource.ptr(), info.InputState, &layout);
|
||||
m_device->GetContext()->Acquire11on12Resource(ppResources[i], layout);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
HRESULT STDMETHODCALLTYPE D3D11on12Device::GetD3D12Device(
|
||||
REFIID riid,
|
||||
void** ppvDevice) {
|
||||
return m_d3d12Queue->GetDevice(riid, ppvDevice);
|
||||
}
|
||||
|
||||
}
|
98
src/d3d11/d3d11_on_12.h
Normal file
98
src/d3d11/d3d11_on_12.h
Normal file
|
@ -0,0 +1,98 @@
|
|||
#pragma once
|
||||
|
||||
#include "d3d11_on_12_interfaces.h"
|
||||
|
||||
#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;
|
||||
class D3D11DXGIDevice;
|
||||
|
||||
/**
|
||||
* \brief Resource info for 11on12 resources
|
||||
*/
|
||||
struct D3D11_ON_12_RESOURCE_INFO {
|
||||
Com<ID3D12Resource> Resource;
|
||||
UINT64 VulkanHandle = 0;
|
||||
UINT64 VulkanOffset = 0;
|
||||
BOOL IsWrappedResource = FALSE;
|
||||
D3D12_RESOURCE_STATES InputState = D3D12_RESOURCE_STATE_COMMON;
|
||||
D3D12_RESOURCE_STATES OutputState = D3D12_RESOURCE_STATE_COMMON;
|
||||
};
|
||||
|
||||
|
||||
class D3D11on12Device : public ID3D11On12Device1_DXVK {
|
||||
|
||||
public:
|
||||
|
||||
D3D11on12Device(
|
||||
D3D11DXGIDevice* pContainer,
|
||||
D3D11Device* pDevice,
|
||||
ID3D12Device* pD3D12Device,
|
||||
ID3D12CommandQueue* pD3D12Queue);
|
||||
|
||||
~D3D11on12Device();
|
||||
|
||||
ULONG STDMETHODCALLTYPE AddRef();
|
||||
|
||||
ULONG STDMETHODCALLTYPE Release();
|
||||
|
||||
HRESULT STDMETHODCALLTYPE QueryInterface(
|
||||
REFIID riid,
|
||||
void** ppvObject);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE CreateWrappedResource(
|
||||
IUnknown* pResource12,
|
||||
const D3D11_RESOURCE_FLAGS* pResourceFlags,
|
||||
D3D12_RESOURCE_STATES InputState,
|
||||
D3D12_RESOURCE_STATES OutputState,
|
||||
REFIID riid,
|
||||
void** ppResource11);
|
||||
|
||||
void STDMETHODCALLTYPE ReleaseWrappedResources(
|
||||
ID3D11Resource* const* ppResources,
|
||||
UINT ResourceCount);
|
||||
|
||||
void STDMETHODCALLTYPE AcquireWrappedResources(
|
||||
ID3D11Resource* const* ppResources,
|
||||
UINT ResourceCount);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE GetD3D12Device(
|
||||
REFIID riid,
|
||||
void** ppvDevice);
|
||||
|
||||
bool Is11on12Device() const {
|
||||
return m_d3d12Device != nullptr;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
D3D11DXGIDevice* m_container;
|
||||
D3D11Device* m_device;
|
||||
|
||||
Com<ID3D12Device> m_d3d12Device;
|
||||
Com<ID3D12CommandQueue> m_d3d12Queue;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#ifndef _MSC_VER
|
||||
__CRT_UUID_DECL(ID3D11On12Device1_DXVK, 0xbdb64df4,0xea2f,0x4c70,0xb8,0x61,0xaa,0xab,0x12,0x58,0xbb,0x5d);
|
||||
#endif
|
54
src/d3d11/d3d11_on_12_interfaces.h
Normal file
54
src/d3d11/d3d11_on_12_interfaces.h
Normal file
|
@ -0,0 +1,54 @@
|
|||
#pragma once
|
||||
|
||||
#include "../vulkan/vulkan_loader.h"
|
||||
|
||||
#include <d3d11on12.h>
|
||||
|
||||
MIDL_INTERFACE("39da4e09-bd1c-4198-9fae-86bbe3be41fd")
|
||||
ID3D12DXVKInteropDevice : public IUnknown {
|
||||
virtual HRESULT STDMETHODCALLTYPE GetDXGIAdapter(
|
||||
REFIID iid,
|
||||
void** ppvObject) = 0;
|
||||
|
||||
virtual HRESULT STDMETHODCALLTYPE GetInstanceExtensions(
|
||||
UINT* pExtensionCount,
|
||||
const char** ppExtensions) = 0;
|
||||
|
||||
virtual HRESULT STDMETHODCALLTYPE GetDeviceExtensions(
|
||||
UINT* pExtensionCount,
|
||||
const char** ppExtensions) = 0;
|
||||
|
||||
virtual HRESULT STDMETHODCALLTYPE GetDeviceFeatures(
|
||||
const VkPhysicalDeviceFeatures2** ppFeatures) = 0;
|
||||
|
||||
virtual HRESULT STDMETHODCALLTYPE GetVulkanHandles(
|
||||
VkInstance* pVkInstance,
|
||||
VkPhysicalDevice* pVkPhysicalDevice,
|
||||
VkDevice* pVkDevice) = 0;
|
||||
|
||||
virtual HRESULT STDMETHODCALLTYPE GetVulkanQueueInfo(
|
||||
ID3D12CommandQueue* pCommandQueue,
|
||||
VkQueue* pVkQueue,
|
||||
UINT32* pVkQueueFamily) = 0;
|
||||
|
||||
virtual void STDMETHODCALLTYPE GetVulkanImageLayout(
|
||||
ID3D12Resource* pResource,
|
||||
D3D12_RESOURCE_STATES State,
|
||||
VkImageLayout* pVkLayout) = 0;
|
||||
|
||||
virtual HRESULT STDMETHODCALLTYPE GetVulkanResourceInfo(
|
||||
ID3D12Resource* pResource,
|
||||
UINT64* pVkHandle,
|
||||
UINT64* pBufferOffset) = 0;
|
||||
|
||||
virtual HRESULT STDMETHODCALLTYPE LockCommandQueue(
|
||||
ID3D12CommandQueue* pCommandQueue) = 0;
|
||||
|
||||
virtual HRESULT STDMETHODCALLTYPE UnlockCommandQueue(
|
||||
ID3D12CommandQueue* pCommandQueue) = 0;
|
||||
|
||||
};
|
||||
|
||||
#ifndef _MSC_VER
|
||||
__CRT_UUID_DECL(ID3D12DXVKInteropDevice, 0x39da4e09, 0xbd1c, 0x4198, 0x9f,0xae, 0x86,0xbb,0xe3,0xbe,0x41,0xfd)
|
||||
#endif
|
|
@ -12,40 +12,29 @@ 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);
|
||||
this->clampNegativeLodBias = config.getOption<bool>("d3d11.clampNegativeLodBias", false);
|
||||
this->invariantPosition = config.getOption<bool>("d3d11.invariantPosition", true);
|
||||
this->floatControls = config.getOption<bool>("d3d11.floatControls", true);
|
||||
this->forceSampleRateShading = config.getOption<bool>("d3d11.forceSampleRateShading", false);
|
||||
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->tearFree = config.getOption<Tristate>("dxgi.tearFree", Tristate::Auto);
|
||||
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,115 +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 = 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;
|
||||
|
||||
/// Tear-free mode if vsync is disabled
|
||||
/// Tearing mode if vsync is enabled
|
||||
Tristate tearFree;
|
||||
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;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -120,8 +120,11 @@ namespace dxvk {
|
|||
}
|
||||
}
|
||||
|
||||
Logger::warn("D3D11Query: Unknown interface query");
|
||||
Logger::warn(str::format(riid));
|
||||
if (logQueryInterfaceError(__uuidof(ID3D11Query), riid)) {
|
||||
Logger::warn("D3D11Query: Unknown interface query");
|
||||
Logger::warn(str::format(riid));
|
||||
}
|
||||
|
||||
return E_NOINTERFACE;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -38,13 +38,22 @@ namespace dxvk {
|
|||
m_state.conservativeMode = DecodeConservativeRasterizationMode(desc.ConservativeRaster);
|
||||
m_state.sampleCount = VkSampleCountFlags(desc.ForcedSampleCount);
|
||||
m_state.flatShading = VK_FALSE;
|
||||
m_state.lineMode = VK_LINE_RASTERIZATION_MODE_DEFAULT_EXT;
|
||||
|
||||
m_depthBias.depthBiasConstant = float(desc.DepthBias);
|
||||
m_depthBias.depthBiasSlope = desc.SlopeScaledDepthBias;
|
||||
m_depthBias.depthBiasClamp = desc.DepthBiasClamp;
|
||||
|
||||
if (desc.AntialiasedLineEnable)
|
||||
Logger::err("D3D11RasterizerState: Antialiased lines not supported");
|
||||
// Set up line rasterization mode
|
||||
const auto& features = device->GetDXVKDevice()->features();
|
||||
|
||||
if (desc.MultisampleEnable) {
|
||||
if (features.extLineRasterization.rectangularLines)
|
||||
m_state.lineMode = VK_LINE_RASTERIZATION_MODE_RECTANGULAR_EXT;
|
||||
} else if (desc.AntialiasedLineEnable) {
|
||||
if (features.extLineRasterization.smoothLines)
|
||||
m_state.lineMode = VK_LINE_RASTERIZATION_MODE_RECTANGULAR_SMOOTH_EXT;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -74,8 +83,11 @@ namespace dxvk {
|
|||
return S_OK;
|
||||
}
|
||||
|
||||
Logger::warn("D3D11RasterizerState::QueryInterface: Unknown interface query");
|
||||
Logger::warn(str::format(riid));
|
||||
if (logQueryInterfaceError(__uuidof(ID3D11RasterizerState), riid)) {
|
||||
Logger::warn("D3D11RasterizerState::QueryInterface: Unknown interface query");
|
||||
Logger::warn(str::format(riid));
|
||||
}
|
||||
|
||||
return E_NOINTERFACE;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,14 +1,141 @@
|
|||
#include "d3d11_buffer.h"
|
||||
#include "d3d11_texture.h"
|
||||
#include "d3d11_resource.h"
|
||||
#include "d3d11_context_imm.h"
|
||||
#include "d3d11_device.h"
|
||||
|
||||
#include "../util/util_shared_res.h"
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
D3D11DXGIKeyedMutex::D3D11DXGIKeyedMutex(
|
||||
ID3D11Resource* pResource,
|
||||
D3D11Device* pDevice)
|
||||
: m_resource(pResource),
|
||||
m_device(pDevice) {
|
||||
|
||||
m_supported = m_device->GetDXVKDevice()->features().khrWin32KeyedMutex
|
||||
&& m_device->GetDXVKDevice()->vkd()->wine_vkAcquireKeyedMutex != nullptr
|
||||
&& m_device->GetDXVKDevice()->vkd()->wine_vkReleaseKeyedMutex != nullptr;
|
||||
}
|
||||
|
||||
|
||||
D3D11DXGIKeyedMutex::~D3D11DXGIKeyedMutex() {
|
||||
|
||||
}
|
||||
|
||||
|
||||
ULONG STDMETHODCALLTYPE D3D11DXGIKeyedMutex::AddRef() {
|
||||
return m_resource->AddRef();
|
||||
}
|
||||
|
||||
|
||||
ULONG STDMETHODCALLTYPE D3D11DXGIKeyedMutex::Release() {
|
||||
return m_resource->Release();
|
||||
}
|
||||
|
||||
|
||||
HRESULT STDMETHODCALLTYPE D3D11DXGIKeyedMutex::QueryInterface(
|
||||
REFIID riid,
|
||||
void** ppvObject) {
|
||||
return m_resource->QueryInterface(riid, ppvObject);
|
||||
}
|
||||
|
||||
|
||||
HRESULT STDMETHODCALLTYPE D3D11DXGIKeyedMutex::GetPrivateData(
|
||||
REFGUID Name,
|
||||
UINT* pDataSize,
|
||||
void* pData) {
|
||||
return m_resource->GetPrivateData(Name, pDataSize, pData);
|
||||
}
|
||||
|
||||
|
||||
HRESULT STDMETHODCALLTYPE D3D11DXGIKeyedMutex::SetPrivateData(
|
||||
REFGUID Name,
|
||||
UINT DataSize,
|
||||
const void* pData) {
|
||||
return m_resource->SetPrivateData(Name, DataSize, pData);
|
||||
}
|
||||
|
||||
|
||||
HRESULT STDMETHODCALLTYPE D3D11DXGIKeyedMutex::SetPrivateDataInterface(
|
||||
REFGUID Name,
|
||||
const IUnknown* pUnknown) {
|
||||
return m_resource->SetPrivateDataInterface(Name, pUnknown);
|
||||
}
|
||||
|
||||
|
||||
HRESULT STDMETHODCALLTYPE D3D11DXGIKeyedMutex::GetParent(
|
||||
REFIID riid,
|
||||
void** ppParent) {
|
||||
return GetDevice(riid, ppParent);
|
||||
}
|
||||
|
||||
|
||||
HRESULT STDMETHODCALLTYPE D3D11DXGIKeyedMutex::GetDevice(
|
||||
REFIID riid,
|
||||
void** ppDevice) {
|
||||
Com<ID3D11Device> device;
|
||||
m_resource->GetDevice(&device);
|
||||
return device->QueryInterface(riid, ppDevice);
|
||||
}
|
||||
|
||||
|
||||
HRESULT STDMETHODCALLTYPE D3D11DXGIKeyedMutex::AcquireSync(
|
||||
UINT64 Key,
|
||||
DWORD dwMilliseconds) {
|
||||
if (!m_supported) {
|
||||
if (!m_warned) {
|
||||
m_warned = true;
|
||||
Logger::err("D3D11DXGIKeyedMutex::AcquireSync: Not supported");
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
D3D11CommonTexture* texture = GetCommonTexture(m_resource);
|
||||
Rc<DxvkDevice> dxvkDevice = m_device->GetDXVKDevice();
|
||||
|
||||
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;
|
||||
default: return DXGI_ERROR_INVALID_CALL;
|
||||
}
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE D3D11DXGIKeyedMutex::ReleaseSync(
|
||||
UINT64 Key) {
|
||||
if (!m_supported)
|
||||
return S_OK;
|
||||
|
||||
D3D11CommonTexture* texture = GetCommonTexture(m_resource);
|
||||
Rc<DxvkDevice> dxvkDevice = m_device->GetDXVKDevice();
|
||||
|
||||
{
|
||||
D3D11ImmediateContext* context = m_device->GetContext();
|
||||
D3D10Multithread& multithread = context->GetMultithread();
|
||||
static bool s_errorShown = false;
|
||||
|
||||
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)
|
||||
: m_resource(pResource) {
|
||||
ID3D11Resource* pResource,
|
||||
D3D11Device* pDevice)
|
||||
: m_resource(pResource),
|
||||
m_keyedMutex(pResource, pDevice) {
|
||||
|
||||
}
|
||||
|
||||
|
@ -84,9 +211,15 @@ namespace dxvk {
|
|||
HRESULT STDMETHODCALLTYPE D3D11DXGIResource::GetSharedHandle(
|
||||
HANDLE* pSharedHandle) {
|
||||
auto texture = GetCommonTexture(m_resource);
|
||||
if (texture == nullptr || pSharedHandle == nullptr || !(texture->Desc()->MiscFlags & D3D11_RESOURCE_MISC_SHARED))
|
||||
if (texture == nullptr || pSharedHandle == nullptr ||
|
||||
(texture->Desc()->MiscFlags & D3D11_RESOURCE_MISC_SHARED_NTHANDLE))
|
||||
return E_INVALIDARG;
|
||||
|
||||
if (!(texture->Desc()->MiscFlags & (D3D11_RESOURCE_MISC_SHARED | D3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX))) {
|
||||
*pSharedHandle = NULL;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HANDLE kmtHandle = texture->GetImage()->sharedHandle();
|
||||
|
||||
if (kmtHandle == INVALID_HANDLE_VALUE)
|
||||
|
@ -143,8 +276,9 @@ namespace dxvk {
|
|||
LPCWSTR lpName,
|
||||
HANDLE* pHandle) {
|
||||
auto texture = GetCommonTexture(m_resource);
|
||||
if (pHandle) *pHandle = nullptr;
|
||||
if (texture == nullptr || pHandle == nullptr ||
|
||||
!(texture->Desc()->MiscFlags & (D3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX | D3D11_RESOURCE_MISC_SHARED_NTHANDLE)))
|
||||
!(texture->Desc()->MiscFlags & D3D11_RESOURCE_MISC_SHARED_NTHANDLE))
|
||||
return E_INVALIDARG;
|
||||
|
||||
if (lpName)
|
||||
|
@ -155,9 +289,6 @@ namespace dxvk {
|
|||
if (handle == INVALID_HANDLE_VALUE)
|
||||
return E_INVALIDARG;
|
||||
|
||||
if (texture->Desc()->MiscFlags & D3D11_RESOURCE_MISC_SHARED)
|
||||
handle = openKmtHandle( handle );
|
||||
|
||||
*pHandle = handle;
|
||||
return S_OK;
|
||||
}
|
||||
|
@ -172,6 +303,36 @@ namespace dxvk {
|
|||
}
|
||||
|
||||
|
||||
HRESULT D3D11DXGIResource::GetKeyedMutex(
|
||||
void **ppvObject) {
|
||||
auto texture = GetCommonTexture(m_resource);
|
||||
if (texture == nullptr || !(texture->Desc()->MiscFlags & D3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX))
|
||||
return E_NOINTERFACE;
|
||||
*ppvObject = ref(&m_keyedMutex);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
HRESULT GetResource11on12Info(
|
||||
ID3D11Resource* pResource,
|
||||
D3D11_ON_12_RESOURCE_INFO* p11on12Info) {
|
||||
auto buffer = GetCommonBuffer (pResource);
|
||||
auto texture = GetCommonTexture(pResource);
|
||||
|
||||
if (buffer != nullptr)
|
||||
*p11on12Info = buffer->Get11on12Info();
|
||||
else if (texture != nullptr)
|
||||
*p11on12Info = texture->Get11on12Info();
|
||||
else
|
||||
return E_INVALIDARG;
|
||||
|
||||
if (p11on12Info->Resource == nullptr)
|
||||
return E_INVALIDARG;
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
HRESULT GetCommonResourceDesc(
|
||||
ID3D11Resource* pResource,
|
||||
D3D11_COMMON_RESOURCE_DESC* pDesc) {
|
||||
|
|
|
@ -22,6 +22,65 @@ namespace dxvk {
|
|||
};
|
||||
|
||||
|
||||
/**
|
||||
* \brief IDXGIKeyedMutex implementation
|
||||
*/
|
||||
class D3D11DXGIKeyedMutex : public IDXGIKeyedMutex {
|
||||
|
||||
public:
|
||||
|
||||
D3D11DXGIKeyedMutex(
|
||||
ID3D11Resource* pResource,
|
||||
D3D11Device* pDevice);
|
||||
|
||||
~D3D11DXGIKeyedMutex();
|
||||
|
||||
ULONG STDMETHODCALLTYPE AddRef();
|
||||
|
||||
ULONG STDMETHODCALLTYPE Release();
|
||||
|
||||
HRESULT STDMETHODCALLTYPE QueryInterface(
|
||||
REFIID riid,
|
||||
void** ppvObject);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE GetPrivateData(
|
||||
REFGUID Name,
|
||||
UINT* pDataSize,
|
||||
void* pData);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE SetPrivateData(
|
||||
REFGUID Name,
|
||||
UINT DataSize,
|
||||
const void* pData);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE SetPrivateDataInterface(
|
||||
REFGUID Name,
|
||||
const IUnknown* pUnknown);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE GetParent(
|
||||
REFIID riid,
|
||||
void** ppParent);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE GetDevice(
|
||||
REFIID riid,
|
||||
void** ppDevice);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE AcquireSync(
|
||||
UINT64 Key,
|
||||
DWORD dwMilliseconds);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE ReleaseSync(
|
||||
UINT64 Key);
|
||||
|
||||
private:
|
||||
|
||||
ID3D11Resource* m_resource;
|
||||
D3D11Device* m_device;
|
||||
bool m_warned = false;
|
||||
bool m_supported = false;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* \brief IDXGIResource implementation for D3D11 resources
|
||||
*/
|
||||
|
@ -30,7 +89,8 @@ namespace dxvk {
|
|||
public:
|
||||
|
||||
D3D11DXGIResource(
|
||||
ID3D11Resource* pResource);
|
||||
ID3D11Resource* pResource,
|
||||
D3D11Device* pDevice);
|
||||
|
||||
~D3D11DXGIResource();
|
||||
|
||||
|
@ -86,13 +146,27 @@ namespace dxvk {
|
|||
UINT index,
|
||||
IDXGISurface2** ppSurface);
|
||||
|
||||
HRESULT GetKeyedMutex(void **ppvObject);
|
||||
|
||||
private:
|
||||
|
||||
ID3D11Resource* m_resource;
|
||||
D3D11DXGIKeyedMutex m_keyedMutex;
|
||||
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* \brief Queries D3D11on12 resource info
|
||||
*
|
||||
* \param [in] pResource The resource to query
|
||||
* \param [out] p11on12Info 11on12 info
|
||||
* \returns \c S_OK on success, or \c E_INVALIDARG
|
||||
*/
|
||||
HRESULT GetResource11on12Info(
|
||||
ID3D11Resource* pResource,
|
||||
D3D11_ON_12_RESOURCE_INFO* p11on12Info);
|
||||
|
||||
/**
|
||||
* \brief Queries common resource description
|
||||
*
|
||||
|
@ -261,4 +335,4 @@ namespace dxvk {
|
|||
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,59 +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;
|
||||
|
||||
// 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() {
|
||||
|
||||
}
|
||||
|
@ -86,8 +85,11 @@ namespace dxvk {
|
|||
return S_OK;
|
||||
}
|
||||
|
||||
Logger::warn("D3D11SamplerState::QueryInterface: Unknown interface query");
|
||||
Logger::warn(str::format(riid));
|
||||
if (logQueryInterfaceError(__uuidof(ID3D11SamplerState), riid)) {
|
||||
Logger::warn("D3D11SamplerState::QueryInterface: Unknown interface query");
|
||||
Logger::warn(str::format(riid));
|
||||
}
|
||||
|
||||
return E_NOINTERFACE;
|
||||
}
|
||||
|
||||
|
|
|
@ -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 = { };
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
@ -134,7 +140,11 @@ namespace dxvk {
|
|||
return S_OK;
|
||||
}
|
||||
|
||||
Logger::warn("D3D11Shader::QueryInterface: Unknown interface query");
|
||||
if (logQueryInterfaceError(__uuidof(D3D11Interface), riid)) {
|
||||
Logger::warn("D3D11Shader::QueryInterface: Unknown interface query");
|
||||
Logger::warn(str::format(riid));
|
||||
}
|
||||
|
||||
return E_NOINTERFACE;
|
||||
}
|
||||
|
||||
|
|
|
@ -29,8 +29,11 @@ namespace dxvk {
|
|||
return S_OK;
|
||||
}
|
||||
|
||||
Logger::warn("D3D11DeviceContextState::QueryInterface: Unknown interface query");
|
||||
Logger::warn(str::format(riid));
|
||||
if (logQueryInterfaceError(__uuidof(ID3DDeviceContextState), riid)) {
|
||||
Logger::warn("D3D11DeviceContextState::QueryInterface: Unknown interface query");
|
||||
Logger::warn(str::format(riid));
|
||||
}
|
||||
|
||||
return E_NOINTERFACE;
|
||||
}
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
@ -32,7 +34,7 @@ namespace dxvk {
|
|||
}
|
||||
|
||||
static float ConvertMinLuminance(UINT dxgiLuminance) {
|
||||
return float(dxgiLuminance) / 0.0001f;
|
||||
return float(dxgiLuminance) * 0.0001f;
|
||||
}
|
||||
|
||||
static float ConvertLevel(UINT16 dxgiLevel) {
|
||||
|
@ -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(false);
|
||||
}
|
||||
|
||||
|
||||
|
@ -82,10 +79,10 @@ namespace dxvk {
|
|||
if (this_thread::isInModuleDetachment())
|
||||
return;
|
||||
|
||||
m_device->waitForSubmission(&m_presentStatus);
|
||||
m_device->waitForIdle();
|
||||
m_presenter->destroyResources();
|
||||
|
||||
DestroyFrameLatencyEvent();
|
||||
DestroyLatencyTracker();
|
||||
}
|
||||
|
||||
|
||||
|
@ -98,12 +95,18 @@ namespace dxvk {
|
|||
InitReturnPtr(ppvObject);
|
||||
|
||||
if (riid == __uuidof(IUnknown)
|
||||
|| riid == __uuidof(IDXGIVkSwapChain)) {
|
||||
|| riid == __uuidof(IDXGIVkSwapChain)
|
||||
|| riid == __uuidof(IDXGIVkSwapChain1)
|
||||
|| riid == __uuidof(IDXGIVkSwapChain2)) {
|
||||
*ppvObject = ref(this);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
Logger::warn("D3D11SwapChain::QueryInterface: Unknown interface query");
|
||||
if (logQueryInterfaceError(__uuidof(IDXGIVkSwapChain), riid)) {
|
||||
Logger::warn("D3D11SwapChain::QueryInterface: Unknown interface query");
|
||||
Logger::warn(str::format(riid));
|
||||
}
|
||||
|
||||
return E_NOINTERFACE;
|
||||
}
|
||||
|
||||
|
@ -135,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);
|
||||
}
|
||||
|
||||
|
||||
|
@ -156,12 +159,10 @@ namespace dxvk {
|
|||
|
||||
HANDLE STDMETHODCALLTYPE D3D11SwapChain::GetFrameLatencyEvent() {
|
||||
HANDLE result = nullptr;
|
||||
HANDLE processHandle = GetCurrentProcess();
|
||||
|
||||
if (!m_processHandle)
|
||||
m_processHandle = GetCurrentProcess();
|
||||
|
||||
if (!DuplicateHandle(m_processHandle, m_frameLatencyEvent,
|
||||
m_processHandle, &result, 0, FALSE, DUPLICATE_SAME_ACCESS)) {
|
||||
if (!DuplicateHandle(processHandle, m_frameLatencyEvent,
|
||||
processHandle, &result, 0, FALSE, DUPLICATE_SAME_ACCESS)) {
|
||||
Logger::err("DxgiSwapChain::GetFrameLatencyWaitableObject: DuplicateHandle failed");
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -174,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;
|
||||
}
|
||||
|
||||
|
@ -251,44 +252,48 @@ 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)) {
|
||||
bool vsync = SyncInterval != 0;
|
||||
|
||||
m_dirty |= vsync != m_vsync;
|
||||
m_vsync = vsync;
|
||||
}
|
||||
|
||||
HRESULT hr = S_OK;
|
||||
|
||||
if (!m_presenter->hasSwapChain()) {
|
||||
RecreateSwapChain(m_vsync);
|
||||
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) || hr != S_OK)
|
||||
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(m_vsync);
|
||||
|
||||
try {
|
||||
PresentImage(SyncInterval);
|
||||
hr = PresentImage(SyncInterval);
|
||||
} catch (const DxvkError& e) {
|
||||
Logger::err(e.message());
|
||||
hr = E_FAIL;
|
||||
}
|
||||
|
||||
// Ensure to synchronize and release the frame latency semaphore
|
||||
// even if presentation failed with STATUS_OCCLUDED, or otherwise
|
||||
// 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;
|
||||
}
|
||||
|
||||
|
@ -297,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;
|
||||
|
||||
|
@ -307,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;
|
||||
}
|
||||
|
||||
|
@ -321,149 +328,166 @@ 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;
|
||||
}
|
||||
|
||||
|
||||
void STDMETHODCALLTYPE D3D11SwapChain::GetLastPresentCount(
|
||||
UINT64* pLastPresentCount) {
|
||||
*pLastPresentCount = UINT64(m_frameId - DXGI_MAX_SWAP_CHAIN_BUFFERS);
|
||||
}
|
||||
|
||||
|
||||
void STDMETHODCALLTYPE D3D11SwapChain::GetFrameStatistics(
|
||||
DXGI_VK_FRAME_STATISTICS* pFrameStatistics) {
|
||||
std::lock_guard<dxvk::mutex> lock(m_frameStatisticsLock);
|
||||
*pFrameStatistics = m_frameStatistics;
|
||||
}
|
||||
|
||||
|
||||
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) {
|
||||
Com<ID3D11DeviceContext> deviceContext = nullptr;
|
||||
m_parent->GetImmediateContext(&deviceContext);
|
||||
|
||||
// Flush pending rendering commands before
|
||||
auto immediateContext = static_cast<D3D11ImmediateContext*>(deviceContext.ptr());
|
||||
immediateContext->EndFrame();
|
||||
immediateContext->Flush();
|
||||
auto immediateContext = m_parent->GetContext();
|
||||
auto immediateContextLock = immediateContext->LockContext();
|
||||
|
||||
// Bump our frame id.
|
||||
++m_frameId;
|
||||
|
||||
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 DXGI_STATUS_OCCLUDED;
|
||||
m_presenter->setSyncInterval(SyncInterval);
|
||||
|
||||
// Presentation semaphores and WSI swap chain image
|
||||
vk::PresenterInfo info = m_presenter->info();
|
||||
vk::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(m_vsync);
|
||||
if (status != VK_SUCCESS && m_latency)
|
||||
m_latency->discardTimings();
|
||||
|
||||
if (!m_presenter->hasSwapChain())
|
||||
return 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);
|
||||
});
|
||||
}
|
||||
|
||||
// Resolve back buffer if it is multisampled. We
|
||||
// only have to do it only for the first frame.
|
||||
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);
|
||||
|
||||
if (i + 1 >= SyncInterval)
|
||||
m_context->signal(m_frameLatencySignal, m_frameId);
|
||||
|
||||
SubmitPresent(immediateContext, sync, i);
|
||||
}
|
||||
|
||||
SyncFrameLatency();
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
void D3D11SwapChain::SubmitPresent(
|
||||
D3D11ImmediateContext* pContext,
|
||||
const vk::PresenterSync& Sync,
|
||||
uint32_t FrameId) {
|
||||
auto lock = pContext->LockContext();
|
||||
void D3D11SwapChain::RotateBackBuffers(D3D11ImmediateContext* ctx) {
|
||||
small_vector<Rc<DxvkImage>, 4> images;
|
||||
|
||||
// Present from CS thread so that we don't
|
||||
// have to synchronize with it first.
|
||||
m_presentStatus.result = VK_NOT_READY;
|
||||
for (uint32_t i = 0; i < m_backBuffers.size(); i++)
|
||||
images.push_back(GetCommonTexture(m_backBuffers[i].ptr())->GetImage());
|
||||
|
||||
pContext->EmitCs([this,
|
||||
cFrameId = FrameId,
|
||||
cSync = Sync,
|
||||
cHud = m_hud,
|
||||
cCommandList = m_context->endRecording()
|
||||
ctx->EmitCs([
|
||||
cImages = std::move(images)
|
||||
] (DxvkContext* ctx) {
|
||||
cCommandList->setWsiSemaphores(cSync);
|
||||
m_device->submitCommandList(cCommandList);
|
||||
auto allocation = cImages[0]->storage();
|
||||
|
||||
if (cHud != nullptr && !cFrameId)
|
||||
cHud->update();
|
||||
for (size_t i = 0u; i + 1 < cImages.size(); i++)
|
||||
ctx->invalidateImage(cImages[i], cImages[i + 1]->storage());
|
||||
|
||||
m_device->presentImage(m_presenter, &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(m_vsync);
|
||||
}
|
||||
|
||||
|
||||
void D3D11SwapChain::RecreateSwapChain(BOOL Vsync) {
|
||||
// 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;
|
||||
|
||||
vk::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.numPresentModes = PickPresentModes(Vsync, presenterDesc.presentModes);
|
||||
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();
|
||||
}
|
||||
|
||||
|
||||
|
@ -476,90 +500,37 @@ namespace dxvk {
|
|||
|
||||
|
||||
void D3D11SwapChain::CreatePresenter() {
|
||||
DxvkDeviceQueue graphicsQueue = m_device->queues().graphics;
|
||||
PresenterDesc presenterDesc = { };
|
||||
presenterDesc.deferSurfaceCreation = m_parent->GetOptions()->deferSurfaceCreation;
|
||||
|
||||
vk::PresenterDevice presenterDevice;
|
||||
presenterDevice.queueFamily = graphicsQueue.queueFamily;
|
||||
presenterDevice.queue = graphicsQueue.queueHandle;
|
||||
presenterDevice.adapter = m_device->adapter()->handle();
|
||||
presenterDevice.features.fullScreenExclusive = m_device->features().extFullScreenExclusive;
|
||||
presenterDevice.features.hdrMetadata = m_device->features().extHdrMetadata;
|
||||
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);
|
||||
});
|
||||
|
||||
vk::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.numPresentModes = PickPresentModes(false, presenterDesc.presentModes);
|
||||
presenterDesc.fullScreenExclusive = PickFullscreenMode();
|
||||
m_presenter->setSurfaceFormat(GetSurfaceFormat(m_desc.Format));
|
||||
m_presenter->setSurfaceExtent({ m_desc.Width, m_desc.Height });
|
||||
m_presenter->setFrameRateLimit(m_targetFrameRate, GetActualFrameLatency());
|
||||
|
||||
m_presenter = new vk::Presenter(
|
||||
m_device->adapter()->vki(),
|
||||
m_device->vkd(),
|
||||
presenterDevice,
|
||||
presenterDesc);
|
||||
|
||||
m_presenter->setFrameRateLimit(m_parent->GetOptions()->maxFrameRate);
|
||||
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() {
|
||||
vk::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);
|
||||
|
||||
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;
|
||||
|
@ -590,56 +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());
|
||||
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));
|
||||
}
|
||||
|
||||
|
||||
|
@ -648,15 +612,35 @@ 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());
|
||||
|
||||
if (m_frameLatencyEvent) {
|
||||
m_frameLatencySignal->setCallback(m_frameId, [cFrameLatencyEvent = m_frameLatencyEvent] () {
|
||||
m_frameLatencySignal->setCallback(m_frameId, [this,
|
||||
cFrameId = m_frameId,
|
||||
cFrameLatencyEvent = m_frameLatencyEvent
|
||||
] () {
|
||||
if (cFrameLatencyEvent)
|
||||
ReleaseSemaphore(cFrameLatencyEvent, 1, nullptr);
|
||||
});
|
||||
}
|
||||
|
||||
std::lock_guard<dxvk::mutex> lock(m_frameStatisticsLock);
|
||||
m_frameStatistics.PresentCount = cFrameId - DXGI_MAX_SWAP_CHAIN_BUFFERS;
|
||||
m_frameStatistics.PresentQPCTime = dxvk::high_resolution_clock::get_counter();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
@ -672,77 +656,39 @@ namespace dxvk {
|
|||
if (m_frameLatencyCap)
|
||||
maxFrameLatency = std::min(maxFrameLatency, m_frameLatencyCap);
|
||||
|
||||
maxFrameLatency = std::min(maxFrameLatency, m_desc.BufferCount + 1);
|
||||
maxFrameLatency = std::min(maxFrameLatency, m_desc.BufferCount);
|
||||
return maxFrameLatency;
|
||||
}
|
||||
|
||||
|
||||
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::PickPresentModes(
|
||||
BOOL Vsync,
|
||||
VkPresentModeKHR* pDstModes) {
|
||||
uint32_t n = 0;
|
||||
Com<D3D11ReflexDevice> D3D11SwapChain::GetReflexDevice() {
|
||||
Com<ID3DLowLatencyDevice> llDevice;
|
||||
m_parent->QueryInterface(__uuidof(ID3DLowLatencyDevice), reinterpret_cast<void**>(&llDevice));
|
||||
|
||||
if (Vsync) {
|
||||
if (m_parent->GetOptions()->tearFree == Tristate::False)
|
||||
pDstModes[n++] = VK_PRESENT_MODE_FIFO_RELAXED_KHR;
|
||||
pDstModes[n++] = VK_PRESENT_MODE_FIFO_KHR;
|
||||
} else {
|
||||
if (m_parent->GetOptions()->tearFree != Tristate::True)
|
||||
pDstModes[n++] = VK_PRESENT_MODE_IMMEDIATE_KHR;
|
||||
pDstModes[n++] = VK_PRESENT_MODE_MAILBOX_KHR;
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
|
||||
uint32_t D3D11SwapChain::PickImageCount(
|
||||
UINT Preferred) {
|
||||
int32_t option = m_parent->GetOptions()->numBackBuffers;
|
||||
return option > 0 ? uint32_t(option) : uint32_t(Preferred);
|
||||
}
|
||||
|
||||
|
||||
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<IDXGIVkSwapChain> {
|
||||
class D3D11SwapChain : public ComObject<IDXGIVkSwapChain2> {
|
||||
constexpr static uint32_t DefaultFrameLatency = 1;
|
||||
public:
|
||||
|
||||
|
@ -80,6 +81,15 @@ namespace dxvk {
|
|||
HRESULT STDMETHODCALLTYPE SetHDRMetaData(
|
||||
const DXGI_VK_HDR_METADATA* pMetaData);
|
||||
|
||||
void STDMETHODCALLTYPE GetLastPresentCount(
|
||||
UINT64* pLastPresentCount);
|
||||
|
||||
void STDMETHODCALLTYPE GetFrameStatistics(
|
||||
DXGI_VK_FRAME_STATISTICS* pFrameStatistics);
|
||||
|
||||
void STDMETHODCALLTYPE SetTargetFrameRate(
|
||||
double FrameRate);
|
||||
|
||||
private:
|
||||
|
||||
enum BindingIds : uint32_t {
|
||||
|
@ -95,81 +105,53 @@ namespace dxvk {
|
|||
DXGI_SWAP_CHAIN_DESC1 m_desc;
|
||||
|
||||
Rc<DxvkDevice> m_device;
|
||||
Rc<DxvkContext> m_context;
|
||||
Rc<Presenter> m_presenter;
|
||||
|
||||
Rc<vk::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;
|
||||
double m_targetFrameRate = 0.0;
|
||||
|
||||
HANDLE m_processHandle = nullptr;
|
||||
dxvk::mutex m_frameStatisticsLock;
|
||||
DXGI_VK_FRAME_STATISTICS m_frameStatistics = { };
|
||||
|
||||
bool m_dirty = true;
|
||||
bool m_vsync = true;
|
||||
Rc<hud::HudLatencyItem> m_latencyHud;
|
||||
|
||||
VkColorSpaceKHR m_colorspace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR;
|
||||
|
||||
std::optional<VkHdrMetadataEXT> m_hdrMetadata;
|
||||
bool m_dirtyHdrMetadata = true;
|
||||
Rc<DxvkImageView> GetBackBufferView();
|
||||
|
||||
HRESULT PresentImage(UINT SyncInterval);
|
||||
|
||||
void SubmitPresent(
|
||||
D3D11ImmediateContext* pContext,
|
||||
const vk::PresenterSync& Sync,
|
||||
uint32_t FrameId);
|
||||
|
||||
void SynchronizePresent();
|
||||
|
||||
void RecreateSwapChain(
|
||||
BOOL Vsync);
|
||||
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 PickPresentModes(
|
||||
BOOL Vsync,
|
||||
VkPresentModeKHR* pDstModes);
|
||||
|
||||
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"
|
||||
|
||||
|
@ -11,11 +12,13 @@ namespace dxvk {
|
|||
ID3D11Resource* pInterface,
|
||||
D3D11Device* pDevice,
|
||||
const D3D11_COMMON_TEXTURE_DESC* pDesc,
|
||||
const D3D11_ON_12_RESOURCE_INFO* p11on12Info,
|
||||
D3D11_RESOURCE_DIMENSION Dimension,
|
||||
DXGI_USAGE DxgiUsage,
|
||||
VkImage vkImage,
|
||||
HANDLE hSharedHandle)
|
||||
: m_interface(pInterface), m_device(pDevice), m_dimension(Dimension), m_desc(*pDesc), m_dxgiUsage(DxgiUsage) {
|
||||
: m_interface(pInterface), m_device(pDevice), m_dimension(Dimension), m_desc(*pDesc),
|
||||
m_11on12(p11on12Info ? *p11on12Info : D3D11_ON_12_RESOURCE_INFO()), m_dxgiUsage(DxgiUsage) {
|
||||
DXGI_VK_FORMAT_MODE formatMode = GetFormatMode();
|
||||
DXGI_VK_FORMAT_INFO formatInfo = m_device->LookupFormat(m_desc.Format, formatMode);
|
||||
DXGI_VK_FORMAT_FAMILY formatFamily = m_device->LookupFamily(m_desc.Format, formatMode);
|
||||
|
@ -46,15 +49,21 @@ namespace dxvk {
|
|||
if (hSharedHandle == nullptr)
|
||||
hSharedHandle = INVALID_HANDLE_VALUE;
|
||||
|
||||
if (m_desc.MiscFlags & (D3D11_RESOURCE_MISC_SHARED|D3D11_RESOURCE_MISC_SHARED_NTHANDLE)) {
|
||||
if (m_desc.MiscFlags & D3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX)
|
||||
Logger::warn("D3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX: not supported.");
|
||||
const auto sharingFlags = D3D11_RESOURCE_MISC_SHARED|D3D11_RESOURCE_MISC_SHARED_NTHANDLE|D3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX;
|
||||
|
||||
if (m_desc.MiscFlags & sharingFlags) {
|
||||
if (pDevice->GetFeatureLevel() < D3D_FEATURE_LEVEL_10_0 ||
|
||||
(m_desc.MiscFlags & (D3D11_RESOURCE_MISC_SHARED|D3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX)) == (D3D11_RESOURCE_MISC_SHARED|D3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX) ||
|
||||
(m_desc.MiscFlags & sharingFlags) == D3D11_RESOURCE_MISC_SHARED_NTHANDLE)
|
||||
throw DxvkError(str::format("D3D11: Cannot create shared texture:",
|
||||
"\n MiscFlags: ", m_desc.MiscFlags,
|
||||
"\n FeatureLevel: ", pDevice->GetFeatureLevel()));
|
||||
|
||||
imageInfo.shared = true;
|
||||
imageInfo.sharing.mode = hSharedHandle == INVALID_HANDLE_VALUE ? DxvkSharedHandleMode::Export : DxvkSharedHandleMode::Import;
|
||||
imageInfo.sharing.type = (m_desc.MiscFlags & D3D11_RESOURCE_MISC_SHARED)
|
||||
? VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT
|
||||
: VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT;
|
||||
imageInfo.sharing.type = (m_desc.MiscFlags & D3D11_RESOURCE_MISC_SHARED_NTHANDLE)
|
||||
? VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT
|
||||
: VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT;
|
||||
imageInfo.sharing.handle = hSharedHandle;
|
||||
}
|
||||
|
||||
|
@ -160,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
|
||||
|
@ -179,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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -200,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(
|
||||
|
@ -220,18 +235,17 @@ 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 (vkImage == VK_NULL_HANDLE)
|
||||
|
||||
if (m_11on12.Resource != nullptr)
|
||||
vkImage = VkImage(m_11on12.VulkanHandle);
|
||||
|
||||
if (!vkImage)
|
||||
m_image = m_device->GetDXVKDevice()->createImage(imageInfo, memoryProperties);
|
||||
else
|
||||
m_image = m_device->GetDXVKDevice()->createImageFromVkImage(imageInfo, vkImage);
|
||||
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();
|
||||
|
@ -267,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);
|
||||
}
|
||||
|
||||
|
||||
|
@ -408,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;
|
||||
|
@ -469,9 +457,60 @@ namespace dxvk {
|
|||
}
|
||||
|
||||
|
||||
HRESULT D3D11CommonTexture::GetDescFromD3D12(
|
||||
ID3D12Resource* pResource,
|
||||
const D3D11_RESOURCE_FLAGS* pResourceFlags,
|
||||
D3D11_COMMON_TEXTURE_DESC* pTextureDesc) {
|
||||
D3D12_RESOURCE_DESC desc12 = pResource->GetDesc();
|
||||
|
||||
pTextureDesc->Width = desc12.Width;
|
||||
pTextureDesc->Height = desc12.Height;
|
||||
|
||||
if (desc12.Dimension == D3D12_RESOURCE_DIMENSION_TEXTURE3D) {
|
||||
pTextureDesc->Depth = desc12.DepthOrArraySize;
|
||||
pTextureDesc->ArraySize = 1;
|
||||
} else {
|
||||
pTextureDesc->Depth = 1;
|
||||
pTextureDesc->ArraySize = desc12.DepthOrArraySize;
|
||||
}
|
||||
|
||||
pTextureDesc->MipLevels = desc12.MipLevels;
|
||||
pTextureDesc->Format = desc12.Format;
|
||||
pTextureDesc->SampleDesc = desc12.SampleDesc;
|
||||
pTextureDesc->Usage = D3D11_USAGE_DEFAULT;
|
||||
pTextureDesc->BindFlags = 0;
|
||||
pTextureDesc->CPUAccessFlags = 0;
|
||||
pTextureDesc->MiscFlags = 0;
|
||||
|
||||
if (!(desc12.Flags & D3D12_RESOURCE_FLAG_DENY_SHADER_RESOURCE))
|
||||
pTextureDesc->BindFlags |= D3D11_BIND_SHADER_RESOURCE;
|
||||
|
||||
if (desc12.Flags & D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET)
|
||||
pTextureDesc->BindFlags |= D3D11_BIND_RENDER_TARGET;
|
||||
|
||||
if (desc12.Flags & D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL)
|
||||
pTextureDesc->BindFlags |= D3D11_BIND_DEPTH_STENCIL;
|
||||
|
||||
if (desc12.Flags & D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS)
|
||||
pTextureDesc->BindFlags |= D3D11_BIND_UNORDERED_ACCESS;
|
||||
|
||||
if (pResourceFlags) {
|
||||
pTextureDesc->BindFlags = pResourceFlags->BindFlags;
|
||||
pTextureDesc->MiscFlags |= pResourceFlags->MiscFlags;
|
||||
pTextureDesc->CPUAccessFlags = pResourceFlags->CPUAccessFlags;
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
BOOL D3D11CommonTexture::CheckImageSupport(
|
||||
const DxvkImageCreateInfo* pImageInfo,
|
||||
VkImageTiling Tiling) const {
|
||||
// D3D12 images always use optimal tiling
|
||||
if (m_11on12.Resource != nullptr && Tiling != VK_IMAGE_TILING_OPTIMAL)
|
||||
return FALSE;
|
||||
|
||||
DxvkFormatQuery formatQuery = { };
|
||||
formatQuery.format = pImageInfo->format;
|
||||
formatQuery.type = pImageInfo->type;
|
||||
|
@ -486,7 +525,7 @@ namespace dxvk {
|
|||
|
||||
if (!properties)
|
||||
return FALSE;
|
||||
|
||||
|
||||
return (pImageInfo->extent.width <= properties->maxExtent.width)
|
||||
&& (pImageInfo->extent.height <= properties->maxExtent.height)
|
||||
&& (pImageInfo->extent.depth <= properties->maxExtent.depth)
|
||||
|
@ -504,146 +543,188 @@ 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;
|
||||
}
|
||||
|
||||
|
||||
void D3D11CommonTexture::ExportImageInfo() {
|
||||
HANDLE hSharedHandle;
|
||||
|
||||
if (m_desc.MiscFlags & D3D11_RESOURCE_MISC_SHARED)
|
||||
hSharedHandle = openKmtHandle( m_image->sharedHandle() );
|
||||
else
|
||||
if (m_desc.MiscFlags & D3D11_RESOURCE_MISC_SHARED_NTHANDLE)
|
||||
hSharedHandle = m_image->sharedHandle();
|
||||
else
|
||||
hSharedHandle = openKmtHandle( m_image->sharedHandle() );
|
||||
|
||||
DxvkSharedTextureMetadata metadata;
|
||||
|
||||
|
@ -663,7 +744,7 @@ namespace dxvk {
|
|||
Logger::warn("D3D11: Failed to write shared resource info for a texture");
|
||||
}
|
||||
|
||||
if ((m_desc.MiscFlags & D3D11_RESOURCE_MISC_SHARED) && hSharedHandle != INVALID_HANDLE_VALUE)
|
||||
if (hSharedHandle != INVALID_HANDLE_VALUE)
|
||||
CloseHandle(hSharedHandle);
|
||||
}
|
||||
|
||||
|
@ -679,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.
|
||||
|
@ -714,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;
|
||||
}
|
||||
|
||||
|
||||
|
@ -734,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;
|
||||
}
|
||||
|
||||
|
||||
|
@ -1028,12 +1119,13 @@ namespace dxvk {
|
|||
// D 3 D 1 1 T E X T U R E 1 D
|
||||
D3D11Texture1D::D3D11Texture1D(
|
||||
D3D11Device* pDevice,
|
||||
const D3D11_COMMON_TEXTURE_DESC* pDesc)
|
||||
const D3D11_COMMON_TEXTURE_DESC* pDesc,
|
||||
const D3D11_ON_12_RESOURCE_INFO* p11on12Info)
|
||||
: D3D11DeviceChild<ID3D11Texture1D>(pDevice),
|
||||
m_texture (this, pDevice, pDesc, D3D11_RESOURCE_DIMENSION_TEXTURE1D, 0, VK_NULL_HANDLE, nullptr),
|
||||
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) {
|
||||
|
||||
}
|
||||
|
@ -1080,14 +1172,20 @@ namespace dxvk {
|
|||
*ppvObject = ref(&m_resource);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
if (riid == __uuidof(IDXGIKeyedMutex))
|
||||
return m_resource.GetKeyedMutex(ppvObject);
|
||||
|
||||
if (riid == __uuidof(IDXGIVkInteropSurface)) {
|
||||
*ppvObject = ref(&m_interop);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
Logger::warn("D3D11Texture1D::QueryInterface: Unknown interface query");
|
||||
Logger::warn(str::format(riid));
|
||||
if (logQueryInterfaceError(__uuidof(ID3D10Texture1D), riid)) {
|
||||
Logger::warn("D3D11Texture1D::QueryInterface: Unknown interface query");
|
||||
Logger::warn(str::format(riid));
|
||||
}
|
||||
|
||||
return E_NOINTERFACE;
|
||||
}
|
||||
|
||||
|
@ -1120,19 +1218,25 @@ 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(
|
||||
D3D11Device* pDevice,
|
||||
const D3D11_COMMON_TEXTURE_DESC* pDesc,
|
||||
const D3D11_ON_12_RESOURCE_INFO* p11on12Info,
|
||||
HANDLE hSharedHandle)
|
||||
: D3D11DeviceChild<ID3D11Texture2D1>(pDevice),
|
||||
m_texture (this, pDevice, pDesc, D3D11_RESOURCE_DIMENSION_TEXTURE2D, 0, VK_NULL_HANDLE, hSharedHandle),
|
||||
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) {
|
||||
}
|
||||
|
@ -1144,10 +1248,10 @@ namespace dxvk {
|
|||
DXGI_USAGE DxgiUsage,
|
||||
VkImage vkImage)
|
||||
: D3D11DeviceChild<ID3D11Texture2D1>(pDevice),
|
||||
m_texture (this, pDevice, pDesc, D3D11_RESOURCE_DIMENSION_TEXTURE2D, DxgiUsage, vkImage, nullptr),
|
||||
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) {
|
||||
|
||||
|
@ -1160,10 +1264,10 @@ namespace dxvk {
|
|||
const D3D11_COMMON_TEXTURE_DESC* pDesc,
|
||||
DXGI_USAGE DxgiUsage)
|
||||
: D3D11DeviceChild<ID3D11Texture2D1>(pDevice),
|
||||
m_texture (this, pDevice, pDesc, D3D11_RESOURCE_DIMENSION_TEXTURE2D, DxgiUsage, VK_NULL_HANDLE, nullptr),
|
||||
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) {
|
||||
|
||||
|
@ -1237,14 +1341,20 @@ namespace dxvk {
|
|||
*ppvObject = ref(&m_resource);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
if (riid == __uuidof(IDXGIKeyedMutex))
|
||||
return m_resource.GetKeyedMutex(ppvObject);
|
||||
|
||||
if (riid == __uuidof(IDXGIVkInteropSurface)) {
|
||||
*ppvObject = ref(&m_interop);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
Logger::warn("D3D11Texture2D::QueryInterface: Unknown interface query");
|
||||
Logger::warn(str::format(riid));
|
||||
if (logQueryInterfaceError(__uuidof(ID3D10Texture2D), riid)) {
|
||||
Logger::warn("D3D11Texture2D::QueryInterface: Unknown interface query");
|
||||
Logger::warn(str::format(riid));
|
||||
}
|
||||
|
||||
return E_NOINTERFACE;
|
||||
}
|
||||
|
||||
|
@ -1296,15 +1406,21 @@ 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(
|
||||
D3D11Device* pDevice,
|
||||
const D3D11_COMMON_TEXTURE_DESC* pDesc)
|
||||
const D3D11_COMMON_TEXTURE_DESC* pDesc,
|
||||
const D3D11_ON_12_RESOURCE_INFO* p11on12Info)
|
||||
: D3D11DeviceChild<ID3D11Texture3D1>(pDevice),
|
||||
m_texture (this, pDevice, pDesc, D3D11_RESOURCE_DIMENSION_TEXTURE3D, 0, VK_NULL_HANDLE, nullptr),
|
||||
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) {
|
||||
|
||||
}
|
||||
|
@ -1344,14 +1460,20 @@ namespace dxvk {
|
|||
*ppvObject = ref(&m_resource);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
if (riid == __uuidof(IDXGIKeyedMutex))
|
||||
return m_resource.GetKeyedMutex(ppvObject);
|
||||
|
||||
if (riid == __uuidof(IDXGIVkInteropSurface)) {
|
||||
*ppvObject = ref(&m_interop);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
Logger::warn("D3D11Texture3D::QueryInterface: Unknown interface query");
|
||||
Logger::warn(str::format(riid));
|
||||
if (logQueryInterfaceError(__uuidof(ID3D10Texture3D), riid)) {
|
||||
Logger::warn("D3D11Texture3D::QueryInterface: Unknown interface query");
|
||||
Logger::warn(str::format(riid));
|
||||
}
|
||||
|
||||
return E_NOINTERFACE;
|
||||
}
|
||||
|
||||
|
@ -1400,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"
|
||||
|
||||
|
@ -7,6 +9,7 @@
|
|||
|
||||
#include "d3d11_device_child.h"
|
||||
#include "d3d11_interfaces.h"
|
||||
#include "d3d11_on_12.h"
|
||||
#include "d3d11_resource.h"
|
||||
|
||||
namespace dxvk {
|
||||
|
@ -23,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
|
||||
};
|
||||
|
@ -80,11 +84,14 @@ namespace dxvk {
|
|||
class D3D11CommonTexture {
|
||||
|
||||
public:
|
||||
|
||||
|
||||
static constexpr uint32_t UnmappedSubresource = ~0u;
|
||||
|
||||
D3D11CommonTexture(
|
||||
ID3D11Resource* pInterface,
|
||||
D3D11Device* pDevice,
|
||||
const D3D11_COMMON_TEXTURE_DESC* pDesc,
|
||||
const D3D11_ON_12_RESOURCE_INFO* p11on12Info,
|
||||
D3D11_RESOURCE_DIMENSION Dimension,
|
||||
DXGI_USAGE DxgiUsage,
|
||||
VkImage vkImage,
|
||||
|
@ -168,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
|
||||
|
@ -217,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;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -233,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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -259,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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -301,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
|
||||
*
|
||||
|
@ -318,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
|
||||
*
|
||||
|
@ -388,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
|
||||
|
@ -435,6 +517,22 @@ namespace dxvk {
|
|||
DXGI_FORMAT Format,
|
||||
UINT Plane) const;
|
||||
|
||||
/**
|
||||
* \brief Retrieves D3D11on12 resource info
|
||||
* \returns 11on12 resource info
|
||||
*/
|
||||
D3D11_ON_12_RESOURCE_INFO Get11on12Info() const {
|
||||
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
|
||||
*
|
||||
|
@ -447,34 +545,54 @@ namespace dxvk {
|
|||
static HRESULT NormalizeTextureProperties(
|
||||
D3D11_COMMON_TEXTURE_DESC* pDesc);
|
||||
|
||||
/**
|
||||
* \brief Initializes D3D11 texture description from D3D12
|
||||
*
|
||||
* \param [in] pResource D3D12 resource
|
||||
* \param [in] pResourceFlags D3D11 flag overrides
|
||||
* \param [out] pTextureDesc D3D11 buffer description
|
||||
* \returns \c S_OK if the parameters are valid
|
||||
*/
|
||||
static HRESULT GetDescFromD3D12(
|
||||
ID3D12Resource* pResource,
|
||||
const D3D11_RESOURCE_FLAGS* pResourceFlags,
|
||||
D3D11_COMMON_TEXTURE_DESC* pTextureDesc);
|
||||
|
||||
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;
|
||||
D3D11Device* m_device;
|
||||
D3D11_RESOURCE_DIMENSION m_dimension;
|
||||
D3D11_COMMON_TEXTURE_DESC m_desc;
|
||||
D3D11_ON_12_RESOURCE_INFO m_11on12;
|
||||
D3D11_COMMON_TEXTURE_MAP_MODE m_mapMode;
|
||||
DXGI_USAGE m_dxgiUsage;
|
||||
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,
|
||||
|
@ -484,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);
|
||||
|
||||
|
@ -636,7 +748,8 @@ namespace dxvk {
|
|||
|
||||
D3D11Texture1D(
|
||||
D3D11Device* pDevice,
|
||||
const D3D11_COMMON_TEXTURE_DESC* pDesc);
|
||||
const D3D11_COMMON_TEXTURE_DESC* pDesc,
|
||||
const D3D11_ON_12_RESOURCE_INFO* p11on12Info);
|
||||
|
||||
~D3D11Texture1D();
|
||||
|
||||
|
@ -654,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;
|
||||
}
|
||||
|
@ -682,6 +797,7 @@ namespace dxvk {
|
|||
D3D11Texture2D(
|
||||
D3D11Device* pDevice,
|
||||
const D3D11_COMMON_TEXTURE_DESC* pDesc,
|
||||
const D3D11_ON_12_RESOURCE_INFO* p11on12Info,
|
||||
HANDLE hSharedHandle);
|
||||
|
||||
D3D11Texture2D(
|
||||
|
@ -719,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;
|
||||
}
|
||||
|
@ -747,7 +865,8 @@ namespace dxvk {
|
|||
|
||||
D3D11Texture3D(
|
||||
D3D11Device* pDevice,
|
||||
const D3D11_COMMON_TEXTURE_DESC* pDesc);
|
||||
const D3D11_COMMON_TEXTURE_DESC* pDesc,
|
||||
const D3D11_ON_12_RESOURCE_INFO* p11on12Info);
|
||||
|
||||
~D3D11Texture3D();
|
||||
|
||||
|
@ -768,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);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -32,8 +32,11 @@ namespace dxvk {
|
|||
return S_OK;
|
||||
}
|
||||
|
||||
Logger::warn("D3D11VideoProcessorEnumerator::QueryInterface: Unknown interface query");
|
||||
Logger::warn(str::format(riid));
|
||||
if (logQueryInterfaceError(__uuidof(ID3D11VideoProcessorEnumerator), riid)) {
|
||||
Logger::warn("D3D11VideoProcessorEnumerator::QueryInterface: Unknown interface query");
|
||||
Logger::warn(str::format(riid));
|
||||
}
|
||||
|
||||
return E_NOINTERFACE;
|
||||
}
|
||||
|
||||
|
@ -48,23 +51,47 @@ namespace dxvk {
|
|||
HRESULT STDMETHODCALLTYPE D3D11VideoProcessorEnumerator::CheckVideoProcessorFormat(
|
||||
DXGI_FORMAT Format,
|
||||
UINT* pFlags) {
|
||||
Logger::err("D3D11VideoProcessorEnumerator::CheckVideoProcessorFormat: Stub");
|
||||
return E_NOTIMPL;
|
||||
Logger::err(str::format("D3D11VideoProcessorEnumerator::CheckVideoProcessorFormat: stub, format ", Format));
|
||||
|
||||
if (!pFlags)
|
||||
return E_INVALIDARG;
|
||||
|
||||
*pFlags = D3D11_VIDEO_PROCESSOR_FORMAT_SUPPORT_INPUT | D3D11_VIDEO_PROCESSOR_FORMAT_SUPPORT_OUTPUT;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
HRESULT STDMETHODCALLTYPE D3D11VideoProcessorEnumerator::GetVideoProcessorCaps(
|
||||
D3D11_VIDEO_PROCESSOR_CAPS* pCaps) {
|
||||
Logger::err("D3D11VideoProcessorEnumerator::GetVideoProcessorCaps: Stub");
|
||||
return E_NOTIMPL;
|
||||
Logger::err("D3D11VideoProcessorEnumerator::GetVideoProcessorCaps: semi-stub");
|
||||
|
||||
if (!pCaps)
|
||||
return E_INVALIDARG;
|
||||
|
||||
*pCaps = {};
|
||||
pCaps->RateConversionCapsCount = 1;
|
||||
pCaps->MaxInputStreams = 52;
|
||||
pCaps->MaxStreamStates = 52;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
HRESULT STDMETHODCALLTYPE D3D11VideoProcessorEnumerator::GetVideoProcessorRateConversionCaps(
|
||||
UINT TypeIndex,
|
||||
D3D11_VIDEO_PROCESSOR_RATE_CONVERSION_CAPS* pCaps) {
|
||||
Logger::err("D3D11VideoProcessorEnumerator::GetVideoProcessorRateConversionCaps: Stub");
|
||||
return E_NOTIMPL;
|
||||
Logger::err("D3D11VideoProcessorEnumerator::GetVideoProcessorRateConversionCaps: semi-stub");
|
||||
if (!pCaps || TypeIndex)
|
||||
return E_INVALIDARG;
|
||||
|
||||
*pCaps = {};
|
||||
if (m_desc.InputFrameFormat == D3D11_VIDEO_FRAME_FORMAT_PROGRESSIVE) {
|
||||
pCaps->ProcessorCaps = D3D11_VIDEO_PROCESSOR_PROCESSOR_CAPS_FRAME_RATE_CONVERSION;
|
||||
} else {
|
||||
pCaps->ProcessorCaps = D3D11_VIDEO_PROCESSOR_PROCESSOR_CAPS_DEINTERLACE_BOB;
|
||||
pCaps->PastFrames = 1;
|
||||
pCaps->FutureFrames = 1;
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
|
@ -112,8 +139,11 @@ namespace dxvk {
|
|||
return S_OK;
|
||||
}
|
||||
|
||||
Logger::warn("D3D11VideoProcessor::QueryInterface: Unknown interface query");
|
||||
Logger::warn(str::format(riid));
|
||||
if (logQueryInterfaceError(__uuidof(ID3D11VideoProcessor), riid)) {
|
||||
Logger::warn("D3D11VideoProcessor::QueryInterface: Unknown interface query");
|
||||
Logger::warn(str::format(riid));
|
||||
}
|
||||
|
||||
return E_NOINTERFACE;
|
||||
}
|
||||
|
||||
|
@ -143,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:
|
||||
|
@ -179,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);
|
||||
|
@ -223,8 +241,11 @@ namespace dxvk {
|
|||
return S_OK;
|
||||
}
|
||||
|
||||
Logger::warn("D3D11VideoProcessorInputView::QueryInterface: Unknown interface query");
|
||||
Logger::warn(str::format(riid));
|
||||
if (logQueryInterfaceError(__uuidof(ID3D11VideoProcessorInputView), riid)) {
|
||||
Logger::warn("D3D11VideoProcessorInputView::QueryInterface: Unknown interface query");
|
||||
Logger::warn(str::format(riid));
|
||||
}
|
||||
|
||||
return E_NOINTERFACE;
|
||||
}
|
||||
|
||||
|
@ -254,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);
|
||||
}
|
||||
|
||||
|
||||
|
@ -302,8 +322,11 @@ namespace dxvk {
|
|||
return S_OK;
|
||||
}
|
||||
|
||||
Logger::warn("D3D11VideoProcessorOutputView::QueryInterface: Unknown interface query");
|
||||
Logger::warn(str::format(riid));
|
||||
if (logQueryInterfaceError(__uuidof(ID3D11VideoProcessorOutputView), riid)) {
|
||||
Logger::warn("D3D11VideoProcessorOutputView::QueryInterface: Unknown interface query");
|
||||
Logger::warn(str::format(riid));
|
||||
}
|
||||
|
||||
return E_NOINTERFACE;
|
||||
}
|
||||
|
||||
|
@ -324,56 +347,8 @@ namespace dxvk {
|
|||
D3D11VideoContext::D3D11VideoContext(
|
||||
D3D11ImmediateContext* pContext,
|
||||
const Rc<DxvkDevice>& Device)
|
||||
: m_ctx(pContext) {
|
||||
SpirvCodeBuffer vsCode(d3d11_video_blit_vert);
|
||||
SpirvCodeBuffer fsCode(d3d11_video_blit_frag);
|
||||
: m_ctx(pContext), m_device(Device) {
|
||||
|
||||
const std::array<DxvkBindingInfo, 4> 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, 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;
|
||||
vsInfo.stage = VK_SHADER_STAGE_VERTEX_BIT;
|
||||
vsInfo.outputMask = 0x1;
|
||||
m_vs = new DxvkShader(vsInfo, std::move(vsCode));
|
||||
|
||||
DxvkShaderCreateInfo fsInfo;
|
||||
fsInfo.stage = VK_SHADER_STAGE_FRAGMENT_BIT;
|
||||
fsInfo.bindingCount = fsBindings.size();
|
||||
fsInfo.bindings = fsBindings.data();
|
||||
fsInfo.inputMask = 0x1;
|
||||
fsInfo.outputMask = 0x1;
|
||||
m_fs = new DxvkShader(fsInfo, std::move(fsCode));
|
||||
|
||||
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 = Device->createSampler(samplerInfo);
|
||||
|
||||
DxvkBufferCreateInfo bufferInfo;
|
||||
bufferInfo.size = sizeof(UboData);
|
||||
bufferInfo.usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT;
|
||||
bufferInfo.stages = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
|
||||
bufferInfo.access = VK_ACCESS_UNIFORM_READ_BIT;
|
||||
m_ubo = Device->createBuffer(bufferInfo, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
|
||||
}
|
||||
|
||||
|
||||
|
@ -603,7 +578,9 @@ namespace dxvk {
|
|||
D3D11_VIDEO_PROCESSOR_OUTPUT_RATE Rate,
|
||||
BOOL Repeat,
|
||||
const DXGI_RATIONAL* CustomRate) {
|
||||
Logger::err("D3D11VideoContext::VideoProcessorSetStreamOutputRate: Stub");
|
||||
Logger::err(str::format("D3D11VideoContext::VideoProcessorSetStreamOutputRate: Stub, Rate ", Rate));
|
||||
if (CustomRate)
|
||||
Logger::err(str::format("CustomRate ", CustomRate->Numerator, "/", CustomRate->Denominator));
|
||||
}
|
||||
|
||||
|
||||
|
@ -1036,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;
|
||||
|
||||
|
@ -1048,7 +1029,9 @@ namespace dxvk {
|
|||
continue;
|
||||
|
||||
if (!hasStreamsEnabled) {
|
||||
m_ctx->ResetDirtyTracking();
|
||||
m_ctx->ResetCommandListState();
|
||||
|
||||
BindOutputView(pOutputView);
|
||||
hasStreamsEnabled = true;
|
||||
}
|
||||
|
@ -1058,9 +1041,14 @@ namespace dxvk {
|
|||
|
||||
if (hasStreamsEnabled) {
|
||||
UnbindResources();
|
||||
|
||||
m_ctx->RestoreCommandListState();
|
||||
}
|
||||
|
||||
m_ctx->EmitCs([] (DxvkContext* ctx) {
|
||||
ctx->endDebugLabel();
|
||||
});
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
@ -1195,14 +1183,18 @@ 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;
|
||||
|
||||
ctx->bindRenderTargets(std::move(rt), 0u);
|
||||
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));
|
||||
|
||||
DxvkInputAssemblyState iaState;
|
||||
iaState.primitiveTopology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
|
||||
|
@ -1219,6 +1211,8 @@ namespace dxvk {
|
|||
void D3D11VideoContext::BlitStream(
|
||||
const D3D11VideoProcessorStreamState* pStreamState,
|
||||
const D3D11_VIDEO_PROCESSOR_STREAM* pStream) {
|
||||
CreateResources();
|
||||
|
||||
if (pStream->PastFrames || pStream->FutureFrames)
|
||||
Logger::err("D3D11VideoContext: Ignoring non-zero PastFrames and FutureFrames");
|
||||
|
||||
|
@ -1230,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;
|
||||
|
@ -1273,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;
|
||||
|
@ -1291,26 +1290,78 @@ 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->bindResourceSampler(VK_SHADER_STAGE_FRAGMENT_BIT, 1, Rc<DxvkSampler>(m_sampler));
|
||||
|
||||
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));
|
||||
|
||||
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);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
void D3D11VideoContext::CreateUniformBuffer() {
|
||||
DxvkBufferCreateInfo bufferInfo;
|
||||
bufferInfo.size = sizeof(UboData);
|
||||
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::CreateShaders() {
|
||||
SpirvCodeBuffer vsCode(d3d11_video_blit_vert);
|
||||
SpirvCodeBuffer fsCode(d3d11_video_blit_frag);
|
||||
|
||||
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_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 },
|
||||
}};
|
||||
|
||||
DxvkShaderCreateInfo vsInfo;
|
||||
vsInfo.stage = VK_SHADER_STAGE_VERTEX_BIT;
|
||||
vsInfo.outputMask = 0x1;
|
||||
m_vs = new DxvkShader(vsInfo, std::move(vsCode));
|
||||
|
||||
DxvkShaderCreateInfo fsInfo;
|
||||
fsInfo.stage = VK_SHADER_STAGE_FRAGMENT_BIT;
|
||||
fsInfo.bindingCount = fsBindings.size();
|
||||
fsInfo.bindings = fsBindings.data();
|
||||
fsInfo.inputMask = 0x1;
|
||||
fsInfo.outputMask = 0x1;
|
||||
m_fs = new DxvkShader(fsInfo, std::move(fsCode));
|
||||
}
|
||||
|
||||
|
||||
void D3D11VideoContext::CreateResources() {
|
||||
if (std::exchange(m_resourcesCreated, true))
|
||||
return;
|
||||
|
||||
CreateUniformBuffer();
|
||||
CreateShaders();
|
||||
}
|
||||
|
||||
|
||||
void D3D11VideoContext::UnbindResources() {
|
||||
m_ctx->EmitCs([] (DxvkContext* ctx) {
|
||||
ctx->bindRenderTargets(DxvkRenderTargets(), 0u);
|
||||
|
|
|
@ -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,19 +575,22 @@ namespace dxvk {
|
|||
struct alignas(16) UboData {
|
||||
float colorMatrix[3][4];
|
||||
float coordMatrix[3][2];
|
||||
VkRect2D srcRect;
|
||||
float yMin, yMax;
|
||||
VkBool32 isPlanar;
|
||||
};
|
||||
|
||||
D3D11ImmediateContext* m_ctx;
|
||||
D3D11ImmediateContext* m_ctx;
|
||||
|
||||
Rc<DxvkSampler> m_sampler;
|
||||
Rc<DxvkShader> m_vs;
|
||||
Rc<DxvkShader> m_fs;
|
||||
Rc<DxvkBuffer> m_ubo;
|
||||
Rc<DxvkDevice> m_device;
|
||||
Rc<DxvkShader> m_vs;
|
||||
Rc<DxvkShader> m_fs;
|
||||
Rc<DxvkBuffer> m_ubo;
|
||||
|
||||
VkExtent2D m_dstExtent = { 0u, 0u };
|
||||
|
||||
bool m_resourcesCreated = false;
|
||||
|
||||
void ApplyColorMatrix(float pDst[3][4], const float pSrc[3][4]);
|
||||
|
||||
void ApplyYCbCrMatrix(float pColorMatrix[3][4], bool UseBt709);
|
||||
|
@ -608,6 +602,12 @@ namespace dxvk {
|
|||
const D3D11VideoProcessorStreamState* pStreamState,
|
||||
const D3D11_VIDEO_PROCESSOR_STREAM* pStream);
|
||||
|
||||
void CreateUniformBuffer();
|
||||
|
||||
void CreateShaders();
|
||||
|
||||
void CreateResources();
|
||||
|
||||
void UnbindResources();
|
||||
|
||||
};
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
@ -126,12 +130,15 @@ namespace dxvk {
|
|||
if (riid == __uuidof(ID3D10DeviceChild)
|
||||
|| riid == __uuidof(ID3D10View)
|
||||
|| riid == __uuidof(ID3D10DepthStencilView)) {
|
||||
*ppvObject = ref(this);
|
||||
*ppvObject = ref(&m_d3d10);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
Logger::warn("D3D11DepthStencilView::QueryInterface: Unknown interface query");
|
||||
Logger::warn(str::format(riid));
|
||||
if (logQueryInterfaceError(__uuidof(ID3D11DepthStencilView), riid)) {
|
||||
Logger::warn("D3D11DepthStencilView::QueryInterface: Unknown interface query");
|
||||
Logger::warn(str::format(riid));
|
||||
}
|
||||
|
||||
return E_NOINTERFACE;
|
||||
}
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
@ -77,6 +73,10 @@ namespace dxvk {
|
|||
return mask;
|
||||
}
|
||||
|
||||
DXGI_FORMAT GetViewFormat() const {
|
||||
return m_desc.Format;
|
||||
}
|
||||
|
||||
D3D10DepthStencilView* GetD3D10Iface() {
|
||||
return &m_d3d10;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
@ -137,12 +142,15 @@ namespace dxvk {
|
|||
if (riid == __uuidof(ID3D10DeviceChild)
|
||||
|| riid == __uuidof(ID3D10View)
|
||||
|| riid == __uuidof(ID3D10RenderTargetView)) {
|
||||
*ppvObject = ref(this);
|
||||
*ppvObject = ref(&m_d3d10);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
Logger::warn("D3D11RenderTargetView::QueryInterface: Unknown interface query");
|
||||
Logger::warn(str::format(riid));
|
||||
if (logQueryInterfaceError(__uuidof(ID3D11RenderTargetView), riid)) {
|
||||
Logger::warn("D3D11RenderTargetView::QueryInterface: Unknown interface query");
|
||||
Logger::warn(str::format(riid));
|
||||
}
|
||||
|
||||
return E_NOINTERFACE;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
@ -205,12 +209,15 @@ namespace dxvk {
|
|||
|| riid == __uuidof(ID3D10View)
|
||||
|| riid == __uuidof(ID3D10ShaderResourceView)
|
||||
|| riid == __uuidof(ID3D10ShaderResourceView1)) {
|
||||
*ppvObject = ref(this);
|
||||
*ppvObject = ref(&m_d3d10);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
Logger::warn("D3D11ShaderResourceView::QueryInterface: Unknown interface query");
|
||||
Logger::warn(str::format(riid));
|
||||
if (logQueryInterfaceError(__uuidof(ID3D11ShaderResourceView), riid)) {
|
||||
Logger::warn("D3D11ShaderResourceView::QueryInterface: Unknown interface query");
|
||||
Logger::warn(str::format(riid));
|
||||
}
|
||||
|
||||
return E_NOINTERFACE;
|
||||
}
|
||||
|
||||
|
@ -295,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;
|
||||
}
|
||||
|
||||
|
||||
|
@ -147,8 +151,11 @@ namespace dxvk {
|
|||
return S_OK;
|
||||
}
|
||||
|
||||
Logger::warn("D3D11UnorderedAccessView::QueryInterface: Unknown interface query");
|
||||
Logger::warn(str::format(riid));
|
||||
if (logQueryInterfaceError(__uuidof(ID3D11UnorderedAccessView), riid)) {
|
||||
Logger::warn("D3D11UnorderedAccessView::QueryInterface: Unknown interface query");
|
||||
Logger::warn(str::format(riid));
|
||||
}
|
||||
|
||||
return E_NOINTERFACE;
|
||||
}
|
||||
|
||||
|
@ -211,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;
|
||||
|
@ -443,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);
|
||||
|
|
|
@ -42,6 +42,7 @@ d3d11_src = [
|
|||
'd3d11_input_layout.cpp',
|
||||
'd3d11_interop.cpp',
|
||||
'd3d11_main.cpp',
|
||||
'd3d11_on_12.cpp',
|
||||
'd3d11_options.cpp',
|
||||
'd3d11_query.cpp',
|
||||
'd3d11_rasterizer.cpp',
|
||||
|
@ -68,23 +69,33 @@ d3d11_shaders = files([
|
|||
d3d11_ld_args = []
|
||||
d3d11_link_depends = []
|
||||
|
||||
if platform != 'windows'
|
||||
if platform == 'windows'
|
||||
d3d11_dxgi_dep = lib_dxgi
|
||||
else
|
||||
d3d11_ld_args += [ '-Wl,--version-script', join_paths(meson.current_source_dir(), 'd3d11.sym') ]
|
||||
d3d11_link_depends += files('d3d11.sym')
|
||||
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 : [ dxgi_dep, dxbc_dep, dxvk_dep ],
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue