mirror of
https://github.com/doitsujin/dxvk.git
synced 2025-03-06 20:58:37 +01:00
Compare commits
919 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 |
360 changed files with 36937 additions and 16919 deletions
6
.github/workflows/artifacts.yml
vendored
6
.github/workflows/artifacts.yml
vendored
|
@ -4,7 +4,7 @@ on: [push, pull_request, workflow_dispatch]
|
|||
|
||||
jobs:
|
||||
artifacts-mingw-w64:
|
||||
runs-on: ubuntu-20.04
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
|
@ -35,7 +35,7 @@ jobs:
|
|||
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:
|
||||
|
@ -66,7 +66,7 @@ jobs:
|
|||
if-no-files-found: error
|
||||
|
||||
merge-artifacts:
|
||||
runs-on: ubuntu-20.04
|
||||
runs-on: ubuntu-latest
|
||||
needs: [artifacts-mingw-w64, artifacts-steamrt-sniper]
|
||||
steps:
|
||||
- name: Get version
|
||||
|
|
25
.github/workflows/test-build-windows.yml
vendored
25
.github/workflows/test-build-windows.yml
vendored
|
@ -4,7 +4,7 @@ on: [push, pull_request, workflow_dispatch]
|
|||
|
||||
jobs:
|
||||
build-set-windows:
|
||||
runs-on: windows-2022
|
||||
runs-on: windows-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
|
@ -12,6 +12,7 @@ jobs:
|
|||
uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: recursive
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Setup glslangValidator
|
||||
shell: pwsh
|
||||
|
@ -38,6 +39,12 @@ jobs:
|
|||
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
|
||||
|
@ -56,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\*
|
||||
|
|
157
README.md
157
README.md
|
@ -9,7 +9,7 @@ The most recent development builds can be found [here](https://github.com/doitsu
|
|||
Release builds can be found [here](https://github.com/doitsujin/dxvk/releases).
|
||||
|
||||
## How to use
|
||||
In order to install a DXVK package obtained from the [release](https://github.com/doitsujin/dxvk/releases) page into a given wine prefix, copy or symlink the DLLs into the following directories as follows, then open `winecfg` and manually add DLL overrides for `d3d11`, `d3d10core`, `dxgi`, `d3d9` and `d3d8`.
|
||||
In order to install a DXVK package obtained from the [release](https://github.com/doitsujin/dxvk/releases) page into a given wine prefix, copy or symlink the DLLs into the following directories as follows, then open `winecfg` and manually add `native` DLL overrides for `d3d8`, `d3d9`, `d3d10core`, `d3d11` and `dxgi` under the Libraries tab.
|
||||
|
||||
In a default Wine prefix that would be as follows:
|
||||
```
|
||||
|
@ -32,9 +32,87 @@ In order to remove DXVK from a prefix, remove the DLLs and DLL overrides, and ru
|
|||
|
||||
Tools such as Steam Play, Lutris, Bottles, Heroic Launcher, etc will automatically handle setup of dxvk on their own when enabled.
|
||||
|
||||
#### DLL dependencies
|
||||
Listed below are the DLL requirements for using DXVK with any single API.
|
||||
|
||||
- d3d8: `d3d8.dll` and `d3d9.dll`
|
||||
- d3d9: `d3d9.dll`
|
||||
- d3d10: `d3d10core.dll`, `d3d11.dll` and `dxgi.dll`
|
||||
- d3d11: `d3d11.dll` and `dxgi.dll`
|
||||
|
||||
### Notes on Vulkan drivers
|
||||
Before reporting an issue, please check the [Wiki](https://github.com/doitsujin/dxvk/wiki/Driver-support) page on the current driver status and make sure you run a recent enough driver version for your hardware.
|
||||
|
||||
### Online multi-player games
|
||||
Manipulation of Direct3D libraries in multi-player games may be considered cheating and can get your account **banned**. This may also apply to single-player games with an embedded or dedicated multiplayer portion. **Use at your own risk.**
|
||||
|
||||
### HUD
|
||||
The `DXVK_HUD` environment variable controls a HUD which can display the framerate and some stat counters. It accepts a comma-separated list of the following options:
|
||||
- `devinfo`: Displays the name of the GPU and the driver version.
|
||||
- `fps`: Shows the current frame rate.
|
||||
- `frametimes`: Shows a frame time graph.
|
||||
- `submissions`: Shows the number of command buffers submitted per frame.
|
||||
- `drawcalls`: Shows the number of draw calls and render passes per frame.
|
||||
- `pipelines`: Shows the total number of graphics and compute pipelines.
|
||||
- `descriptors`: Shows the number of descriptor pools and descriptor sets.
|
||||
- `memory`: Shows the amount of device memory allocated and used.
|
||||
- `allocations`: Shows detailed memory chunk suballocation info.
|
||||
- `gpuload`: Shows estimated GPU load. May be inaccurate.
|
||||
- `version`: Shows DXVK version.
|
||||
- `api`: Shows the D3D feature level used by the application.
|
||||
- `cs`: Shows worker thread statistics.
|
||||
- `compiler`: Shows shader compiler activity
|
||||
- `samplers`: Shows the current number of sampler pairs used *[D3D9 Only]*
|
||||
- `ffshaders`: Shows the current number of shaders generated from fixed function state *[D3D9 Only]*
|
||||
- `swvp`: Shows whether or not the device is running in software vertex processing mode *[D3D9 Only]*
|
||||
- `scale=x`: Scales the HUD by a factor of `x` (e.g. `1.5`)
|
||||
- `opacity=y`: Adjusts the HUD opacity by a factor of `y` (e.g. `0.5`, `1.0` being fully opaque).
|
||||
|
||||
Additionally, `DXVK_HUD=1` has the same effect as `DXVK_HUD=devinfo,fps`, and `DXVK_HUD=full` enables all available HUD elements.
|
||||
|
||||
### Logs
|
||||
When used with Wine, DXVK will print log messages to `stderr`. Additionally, standalone log files can optionally be generated by setting the `DXVK_LOG_PATH` variable, where log files in the given directory will be called `app_d3d11.log`, `app_dxgi.log` etc., where `app` is the name of the game executable.
|
||||
|
||||
On Windows, log files will be created in the game's working directory by default, which is usually next to the game executable.
|
||||
|
||||
### Frame rate limit
|
||||
The `DXVK_FRAME_RATE` environment variable can be used to limit the frame rate. A value of `0` uncaps the frame rate, while any positive value will limit rendering to the given number of frames per second. Alternatively, the configuration file can be used.
|
||||
|
||||
### Device filter
|
||||
Some applications do not provide a method to select a different GPU. In that case, DXVK can be forced to use a given device:
|
||||
- `DXVK_FILTER_DEVICE_NAME="Device Name"` Selects devices with a matching Vulkan device name, which can be retrieved with tools such as `vulkaninfo`. Matches on substrings, so "VEGA" or "AMD RADV VEGA10" is supported if the full device name is "AMD RADV VEGA10 (LLVM 9.0.0)", for example. If the substring matches more than one device, the first device matched will be used.
|
||||
|
||||
**Note:** If the device filter is configured incorrectly, it may filter out all devices and applications will be unable to create a D3D device.
|
||||
|
||||
### Debugging
|
||||
The following environment variables can be used for **debugging** purposes.
|
||||
- `VK_INSTANCE_LAYERS=VK_LAYER_KHRONOS_validation` Enables Vulkan debug layers. Highly recommended for troubleshooting rendering issues and driver crashes. Requires the Vulkan SDK to be installed on the host system.
|
||||
- `DXVK_LOG_LEVEL=none|error|warn|info|debug` Controls message logging.
|
||||
- `DXVK_LOG_PATH=/some/directory` Changes path where log files are stored. Set to `none` to disable log file creation entirely, without disabling logging.
|
||||
- `DXVK_DEBUG=markers|validation` Enables use of the `VK_EXT_debug_utils` extension for translating performance event markers, or to enable Vulkan validation, respecticely.
|
||||
- `DXVK_CONFIG_FILE=/xxx/dxvk.conf` Sets path to the configuration file.
|
||||
- `DXVK_CONFIG="dxgi.hideAmdGpu = True; dxgi.syncInterval = 0"` Can be used to set config variables through the environment instead of a configuration file using the same syntax. `;` is used as a seperator.
|
||||
|
||||
### Graphics Pipeline Library
|
||||
On drivers which support `VK_EXT_graphics_pipeline_library` Vulkan shaders will be compiled at the time the game loads its D3D shaders, rather than at draw time. This reduces or eliminates shader compile stutter in many games when compared to the previous system.
|
||||
|
||||
In games that load their shaders during loading screens or in the menu, this can lead to prolonged periods of very high CPU utilization, especially on weaker CPUs. For affected games it is recommended to wait for shader compilation to finish before starting the game to avoid stutter and low performance. Shader compiler activity can be monitored with `DXVK_HUD=compiler`.
|
||||
|
||||
This feature largely replaces the state cache.
|
||||
|
||||
**Note:** Games which only load their D3D shaders at draw time (e.g. most Unreal Engine games) will still exhibit some stutter, although it should still be less severe than without this feature.
|
||||
|
||||
### State cache
|
||||
DXVK caches pipeline state by default, so that shaders can be recompiled ahead of time on subsequent runs of an application, even if the driver's own shader cache got invalidated in the meantime. This cache is enabled by default, and generally reduces stuttering.
|
||||
|
||||
The following environment variables can be used to control the cache:
|
||||
- `DXVK_STATE_CACHE`: Controls the state cache. The following values are supported:
|
||||
- `disable`: Disables the cache entirely.
|
||||
- `reset`: Clears the cache file.
|
||||
- `DXVK_STATE_CACHE_PATH=/some/directory` Specifies a directory where to put the cache files. Defaults to the current working directory of the application.
|
||||
|
||||
This feature is mostly only relevant on systems without support for `VK_EXT_graphics_pipeline_library`
|
||||
|
||||
## Build instructions
|
||||
|
||||
In order to pull in all submodules that are needed for building, clone the repository using the following command:
|
||||
|
@ -42,11 +120,9 @@ In order to pull in all submodules that are needed for building, clone the repos
|
|||
git clone --recursive https://github.com/doitsujin/dxvk.git
|
||||
```
|
||||
|
||||
|
||||
|
||||
### Requirements:
|
||||
- [wine 7.1](https://www.winehq.org/) or newer
|
||||
- [Meson](https://mesonbuild.com/) build system (at least version 0.49)
|
||||
- [Meson](https://mesonbuild.com/) build system (at least version 0.58)
|
||||
- [Mingw-w64](https://www.mingw-w64.org) compiler and headers (at least version 10.0)
|
||||
- [glslang](https://github.com/KhronosGroup/glslang) compiler
|
||||
|
||||
|
@ -76,76 +152,9 @@ cd build.w64
|
|||
ninja install
|
||||
```
|
||||
|
||||
The D3D9, D3D10, D3D11 and DXGI DLLs will be located in `/your/dxvk/directory/bin`. Setup has to be done manually in this case.
|
||||
The D3D8, D3D9, D3D10, D3D11 and DXGI DLLs will be located in `/your/dxvk/directory/bin`.
|
||||
|
||||
### Online multi-player games
|
||||
Manipulation of Direct3D libraries in multi-player games may be considered cheating and can get your account **banned**. This may also apply to single-player games with an embedded or dedicated multiplayer portion. **Use at your own risk.**
|
||||
|
||||
### Logs
|
||||
When used with Wine, DXVK will print log messages to `stderr`. Additionally, standalone log files can optionally be generated by setting the `DXVK_LOG_PATH` variable, where log files in the given directory will be called `app_d3d11.log`, `app_dxgi.log` etc., where `app` is the name of the game executable.
|
||||
|
||||
On Windows, log files will be created in the game's working directory by default, which is usually next to the game executable.
|
||||
|
||||
### HUD
|
||||
The `DXVK_HUD` environment variable controls a HUD which can display the framerate and some stat counters. It accepts a comma-separated list of the following options:
|
||||
- `devinfo`: Displays the name of the GPU and the driver version.
|
||||
- `fps`: Shows the current frame rate.
|
||||
- `frametimes`: Shows a frame time graph.
|
||||
- `submissions`: Shows the number of command buffers submitted per frame.
|
||||
- `drawcalls`: Shows the number of draw calls and render passes per frame.
|
||||
- `pipelines`: Shows the total number of graphics and compute pipelines.
|
||||
- `descriptors`: Shows the number of descriptor pools and descriptor sets.
|
||||
- `memory`: Shows the amount of device memory allocated and used.
|
||||
- `gpuload`: Shows estimated GPU load. May be inaccurate.
|
||||
- `version`: Shows DXVK version.
|
||||
- `api`: Shows the D3D feature level used by the application.
|
||||
- `cs`: Shows worker thread statistics.
|
||||
- `compiler`: Shows shader compiler activity
|
||||
- `samplers`: Shows the current number of sampler pairs used *[D3D9 Only]*
|
||||
- `scale=x`: Scales the HUD by a factor of `x` (e.g. `1.5`)
|
||||
- `opacity=y`: Adjusts the HUD opacity by a factor of `y` (e.g. `0.5`, `1.0` being fully opaque).
|
||||
|
||||
Additionally, `DXVK_HUD=1` has the same effect as `DXVK_HUD=devinfo,fps`, and `DXVK_HUD=full` enables all available HUD elements.
|
||||
|
||||
### Frame rate limit
|
||||
The `DXVK_FRAME_RATE` environment variable can be used to limit the frame rate. A value of `0` uncaps the frame rate, while any positive value will limit rendering to the given number of frames per second. Alternatively, the configuration file can be used.
|
||||
|
||||
### Device filter
|
||||
Some applications do not provide a method to select a different GPU. In that case, DXVK can be forced to use a given device:
|
||||
- `DXVK_FILTER_DEVICE_NAME="Device Name"` Selects devices with a matching Vulkan device name, which can be retrieved with tools such as `vulkaninfo`. Matches on substrings, so "VEGA" or "AMD RADV VEGA10" is supported if the full device name is "AMD RADV VEGA10 (LLVM 9.0.0)", for example. If the substring matches more than one device, the first device matched will be used.
|
||||
|
||||
**Note:** If the device filter is configured incorrectly, it may filter out all devices and applications will be unable to create a D3D device.
|
||||
|
||||
### Graphics Pipeline Library
|
||||
On drivers which support `VK_EXT_graphics_pipeline_library` Vulkan shaders will be compiled at the time the game loads its D3D shaders, rather than at draw time. This reduces or eliminates shader compile stutter in many games when compared to the previous system.
|
||||
|
||||
In games that load their shaders during loading screens or in the menu, this can lead to prolonged periods of very high CPU utilization, especially on weaker CPUs. For affected games it is recommended to wait for shader compilation to finish before starting the game to avoid stutter and low performance. Shader compiler activity can be monitored with `DXVK_HUD=compiler`.
|
||||
|
||||
This feature largely replaces the state cache.
|
||||
|
||||
**Note:** Games which only load their D3D shaders at draw time (e.g. most Unreal Engine games) will still exhibit some stutter, although it should still be less severe than without this feature.
|
||||
|
||||
### State cache
|
||||
DXVK caches pipeline state by default, so that shaders can be recompiled ahead of time on subsequent runs of an application, even if the driver's own shader cache got invalidated in the meantime. This cache is enabled by default, and generally reduces stuttering.
|
||||
|
||||
The following environment variables can be used to control the cache:
|
||||
- `DXVK_STATE_CACHE`: Controls the state cache. The following values are supported:
|
||||
- `disable`: Disables the cache entirely.
|
||||
- `reset`: Clears the cache file.
|
||||
- `DXVK_STATE_CACHE_PATH=/some/directory` Specifies a directory where to put the cache files. Defaults to the current working directory of the application.
|
||||
|
||||
This feature is mostly only relevant on systems without support for `VK_EXT_graphics_pipeline_library`
|
||||
|
||||
### Debugging
|
||||
The following environment variables can be used for **debugging** purposes.
|
||||
- `VK_INSTANCE_LAYERS=VK_LAYER_KHRONOS_validation` Enables Vulkan debug layers. Highly recommended for troubleshooting rendering issues and driver crashes. Requires the Vulkan SDK to be installed on the host system.
|
||||
- `DXVK_LOG_LEVEL=none|error|warn|info|debug` Controls message logging.
|
||||
- `DXVK_LOG_PATH=/some/directory` Changes path where log files are stored. Set to `none` to disable log file creation entirely, without disabling logging.
|
||||
- `DXVK_DEBUG=markers|validation` Enables use of the `VK_EXT_debug_utils` extension for translating performance event markers, or to enable Vulkan validation, respecticely.
|
||||
- `DXVK_CONFIG_FILE=/xxx/dxvk.conf` Sets path to the configuration file.
|
||||
- `DXVK_CONFIG="dxgi.hideAmdGpu = True; dxgi.syncInterval = 0"` Can be used to set config variables through the environment instead of a configuration file using the same syntax. `;` is used as a seperator.
|
||||
|
||||
## Troubleshooting
|
||||
### Build troubleshooting
|
||||
DXVK requires threading support from your mingw-w64 build environment. If you
|
||||
are missing this, you may see "error: ‘std::cv_status’ has not been declared"
|
||||
or similar threading related errors.
|
||||
|
@ -177,7 +186,7 @@ This is primarily useful for game and application ports to either avoid having t
|
|||
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 `SDL2` and `GLFW`.
|
||||
**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:
|
||||
|
|
2
RELEASE
2
RELEASE
|
@ -1 +1 @@
|
|||
2.4
|
||||
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@"
|
||||
|
219
dxvk.conf
219
dxvk.conf
|
@ -18,6 +18,39 @@
|
|||
# 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,
|
||||
|
@ -54,6 +87,46 @@
|
|||
# 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.
|
||||
#
|
||||
|
@ -118,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
|
||||
|
@ -147,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,
|
||||
|
@ -163,13 +218,14 @@
|
|||
# dxvk.tearFree = Auto
|
||||
|
||||
|
||||
# Assume single-use mode for command lists created on deferred contexts.
|
||||
# This may need to be disabled for some applications to avoid rendering
|
||||
# issues, which may come at a significant performance cost.
|
||||
# Controls tiler optimizations. Enabling these will alter the behaviour of
|
||||
# submission heuristics and enables some non-default behaviour in DXVK.
|
||||
# This option is only intended to be changed for performance testing and
|
||||
# debugging purposes.
|
||||
#
|
||||
# Supported values: True, False
|
||||
# Supported values: Auto, True, False
|
||||
|
||||
# d3d11.dcSingleUseMode = True
|
||||
# dxvk.tilerMode = Auto
|
||||
|
||||
|
||||
# Override the maximum feature level that a D3D11 device can be created
|
||||
|
@ -190,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
|
||||
|
@ -274,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
|
||||
|
@ -367,17 +438,6 @@
|
|||
# dxvk.useRawSsbo = Auto
|
||||
|
||||
|
||||
# Changes memory chunk size.
|
||||
#
|
||||
# Can be used to override the maximum memory chunk size.
|
||||
#
|
||||
# Supported values:
|
||||
# - 0 to use the defaults
|
||||
# - any positive integer to limit the chunk size, in MiB
|
||||
|
||||
# dxvk.maxChunkSize = 0
|
||||
|
||||
|
||||
# Controls graphics pipeline library behaviour
|
||||
#
|
||||
# Can be used to change VK_EXT_graphics_pipeline_library usage for
|
||||
|
@ -406,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
|
||||
|
@ -421,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
|
||||
|
@ -500,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)
|
||||
|
@ -517,18 +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
|
||||
|
||||
# d3d11.longMad = False
|
||||
# d3d9.longMad = False
|
||||
|
||||
# Device Local Constant Buffers
|
||||
#
|
||||
# Enables using device local, host accessible memory for constant buffers in D3D9.
|
||||
|
@ -709,16 +763,3 @@
|
|||
# - True/False
|
||||
|
||||
# d3d9.countLosableResources = True
|
||||
|
||||
# Use NVIDIA Shadow Buffers
|
||||
#
|
||||
# Vendor behavior for GeForce3 and GeForce4 cards that allows
|
||||
# sampling depth textures with non-normalized Z coordinates
|
||||
# and applies hardware shadow filtering.
|
||||
#
|
||||
# Supported values:
|
||||
# - True/False
|
||||
|
||||
# d3d8.useShadowBuffers = False
|
||||
|
||||
|
||||
|
|
|
@ -13,6 +13,7 @@ install_subdir(
|
|||
|
||||
install_headers(
|
||||
'wsi/native_wsi.h',
|
||||
'wsi/native_sdl3.h',
|
||||
'wsi/native_sdl2.h',
|
||||
'wsi/native_glfw.h',
|
||||
subdir: 'dxvk/wsi',
|
||||
|
|
|
@ -287,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
|
||||
|
||||
|
|
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 46dc0f6e514f5730784bb2cac2a7c731636839e8
|
||||
Subproject commit 234c4b7370a8ea3239a214c9e871e4b17c89f4ab
|
39
meson.build
39
meson.build
|
@ -1,4 +1,4 @@
|
|||
project('dxvk', ['c', 'cpp'], version : 'v2.4.0', meson_version : '>= 0.58', 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()
|
||||
|
@ -18,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',
|
||||
|
@ -79,16 +80,26 @@ if platform == 'windows'
|
|||
]
|
||||
endif
|
||||
|
||||
# Enable stdcall fixup on 32-bit
|
||||
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
|
||||
|
||||
|
@ -96,12 +107,6 @@ if platform == 'windows'
|
|||
lib_d3d11 = cpp.find_library('d3d11')
|
||||
lib_dxgi = cpp.find_library('dxgi')
|
||||
|
||||
if dxvk_is_msvc
|
||||
lib_d3dcompiler_47 = cpp.find_library('d3dcompiler')
|
||||
else
|
||||
lib_d3dcompiler_47 = cpp.find_library('d3dcompiler_47')
|
||||
endif
|
||||
|
||||
if dxvk_is_msvc
|
||||
res_ext = '.res'
|
||||
wrc = find_program('rc')
|
||||
|
@ -142,16 +147,20 @@ else
|
|||
'./include/native/directx'
|
||||
]
|
||||
|
||||
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']
|
||||
endif
|
||||
if lib_glfw.found()
|
||||
compiler_args += ['-DDXVK_WSI_GLFW']
|
||||
endif
|
||||
if (not lib_sdl2.found() and not lib_glfw.found())
|
||||
error('SDL2 or GLFW are required to build dxvk-native')
|
||||
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 = 'dxvk_'
|
||||
|
@ -195,6 +204,16 @@ 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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -37,8 +37,8 @@ namespace dxvk {
|
|||
D3D11UserDefinedAnnotation<ContextType>::D3D11UserDefinedAnnotation(
|
||||
ContextType* container,
|
||||
const Rc<DxvkDevice>& dxvkDevice)
|
||||
: m_container(container), m_eventDepth(0),
|
||||
m_annotationsEnabled(dxvkDevice->instance()->extensions().extDebugUtils) {
|
||||
: m_container(container),
|
||||
m_annotationsEnabled(dxvkDevice->debugFlags().test(DxvkDebugFlag::Markers)) {
|
||||
if (!IsDeferred && m_annotationsEnabled)
|
||||
RegisterUserDefinedAnnotation<true>(this);
|
||||
}
|
||||
|
@ -75,19 +75,16 @@ namespace dxvk {
|
|||
INT STDMETHODCALLTYPE D3D11UserDefinedAnnotation<ContextType>::BeginEvent(
|
||||
D3DCOLOR Color,
|
||||
LPCWSTR Name) {
|
||||
if (!m_annotationsEnabled)
|
||||
if (!m_annotationsEnabled || !Name)
|
||||
return -1;
|
||||
|
||||
D3D10DeviceLock lock = m_container->LockContext();
|
||||
|
||||
m_container->EmitCs([color = Color, labelName = dxvk::str::fromws(Name)](DxvkContext *ctx) {
|
||||
VkDebugUtilsLabelEXT label;
|
||||
label.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT;
|
||||
label.pNext = nullptr;
|
||||
label.pLabelName = labelName.c_str();
|
||||
DecodeD3DCOLOR(color, label.color);
|
||||
|
||||
ctx->beginDebugLabel(&label);
|
||||
m_container->EmitCs([
|
||||
cColor = Color,
|
||||
cLabel = dxvk::str::fromws(Name)
|
||||
] (DxvkContext* ctx) {
|
||||
ctx->beginDebugLabel(vk::makeLabel(cColor, cLabel.c_str()));
|
||||
});
|
||||
|
||||
return m_eventDepth++;
|
||||
|
@ -101,11 +98,14 @@ namespace dxvk {
|
|||
|
||||
D3D10DeviceLock lock = m_container->LockContext();
|
||||
|
||||
m_container->EmitCs([](DxvkContext *ctx) {
|
||||
if (!m_eventDepth)
|
||||
return 0;
|
||||
|
||||
m_container->EmitCs([] (DxvkContext* ctx) {
|
||||
ctx->endDebugLabel();
|
||||
});
|
||||
|
||||
return m_eventDepth--;
|
||||
return --m_eventDepth;
|
||||
}
|
||||
|
||||
|
||||
|
@ -113,19 +113,16 @@ namespace dxvk {
|
|||
void STDMETHODCALLTYPE D3D11UserDefinedAnnotation<ContextType>::SetMarker(
|
||||
D3DCOLOR Color,
|
||||
LPCWSTR Name) {
|
||||
if (!m_annotationsEnabled)
|
||||
if (!m_annotationsEnabled || !Name)
|
||||
return;
|
||||
|
||||
D3D10DeviceLock lock = m_container->LockContext();
|
||||
|
||||
m_container->EmitCs([color = Color, labelName = dxvk::str::fromws(Name)](DxvkContext *ctx) {
|
||||
VkDebugUtilsLabelEXT label;
|
||||
label.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT;
|
||||
label.pNext = nullptr;
|
||||
label.pLabelName = labelName.c_str();
|
||||
DecodeD3DCOLOR(color, label.color);
|
||||
|
||||
ctx->insertDebugLabel(&label);
|
||||
m_container->EmitCs([
|
||||
cColor = Color,
|
||||
cLabel = dxvk::str::fromws(Name)
|
||||
] (DxvkContext* ctx) {
|
||||
ctx->insertDebugLabel(vk::makeLabel(cColor, cLabel.c_str()));
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -48,9 +48,10 @@ namespace dxvk {
|
|||
|
||||
private:
|
||||
|
||||
ContextType* m_container;
|
||||
int32_t m_eventDepth;
|
||||
bool m_annotationsEnabled;
|
||||
ContextType* m_container = nullptr;
|
||||
int32_t m_eventDepth = 0u;
|
||||
bool m_annotationsEnabled = false;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -1,9 +1,8 @@
|
|||
#include "d3d11_buffer.h"
|
||||
#include "d3d11_context.h"
|
||||
#include "d3d11_context_imm.h"
|
||||
#include "d3d11_device.h"
|
||||
|
||||
#include "../dxvk/dxvk_data.h"
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
D3D11Buffer::D3D11Buffer(
|
||||
|
@ -84,6 +83,10 @@ namespace dxvk {
|
|||
info.access |= VK_ACCESS_HOST_WRITE_BIT;
|
||||
}
|
||||
|
||||
// Always enable BDA usage if available so that CUDA interop can work
|
||||
if (m_parent->GetDXVKDevice()->features().vk12.bufferDeviceAddress)
|
||||
info.usage |= VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT;
|
||||
|
||||
if (p11on12Info) {
|
||||
m_11on12 = *p11on12Info;
|
||||
|
||||
|
@ -95,21 +98,24 @@ namespace dxvk {
|
|||
m_11on12.Resource->Map(0, nullptr, &importInfo.mapPtr);
|
||||
|
||||
m_buffer = m_parent->GetDXVKDevice()->importBuffer(info, importInfo, GetMemoryFlags());
|
||||
m_mapped = m_buffer->getSliceHandle();
|
||||
|
||||
m_mapMode = DetermineMapMode();
|
||||
m_cookie = m_buffer->cookie();
|
||||
m_mapPtr = m_buffer->mapPtr(0);
|
||||
m_mapMode = DetermineMapMode(m_buffer->memFlags());
|
||||
} else if (!(pDesc->MiscFlags & D3D11_RESOURCE_MISC_TILE_POOL)) {
|
||||
VkMemoryPropertyFlags memoryFlags = GetMemoryFlags();
|
||||
m_mapMode = DetermineMapMode(memoryFlags);
|
||||
|
||||
// Create the buffer and set the entire buffer slice as mapped,
|
||||
// so that we only have to update it when invalidating the buffer
|
||||
m_buffer = m_parent->GetDXVKDevice()->createBuffer(info, GetMemoryFlags());
|
||||
m_mapped = m_buffer->getSliceHandle();
|
||||
|
||||
m_mapMode = DetermineMapMode();
|
||||
m_buffer = m_parent->GetDXVKDevice()->createBuffer(info, memoryFlags);
|
||||
m_cookie = m_buffer->cookie();
|
||||
m_mapPtr = m_buffer->mapPtr(0);
|
||||
} else {
|
||||
m_sparseAllocator = m_parent->GetDXVKDevice()->createSparsePageAllocator();
|
||||
m_sparseAllocator->setCapacity(info.size / SparseMemoryPageSize);
|
||||
|
||||
m_mapped = DxvkBufferSliceHandle();
|
||||
m_cookie = 0u;
|
||||
m_mapPtr = nullptr;
|
||||
m_mapMode = D3D11_COMMON_BUFFER_MAP_MODE_NONE;
|
||||
}
|
||||
|
||||
|
@ -206,6 +212,18 @@ namespace dxvk {
|
|||
}
|
||||
|
||||
|
||||
void D3D11Buffer::SetDebugName(const char* pName) {
|
||||
if (m_buffer) {
|
||||
m_parent->GetContext()->InjectCs(DxvkCsQueue::HighPriority, [
|
||||
cBuffer = m_buffer,
|
||||
cName = std::string(pName ? pName : "")
|
||||
] (DxvkContext* ctx) {
|
||||
ctx->setDebugName(cBuffer, cName.c_str());
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
HRESULT D3D11Buffer::NormalizeBufferProperties(D3D11_BUFFER_DESC* pDesc) {
|
||||
// Zero-sized buffers are illegal
|
||||
if (!pDesc->ByteWidth && !(pDesc->MiscFlags & D3D11_RESOURCE_MISC_TILE_POOL))
|
||||
|
@ -365,12 +383,14 @@ namespace dxvk {
|
|||
| VK_ACCESS_INDIRECT_COMMAND_READ_BIT
|
||||
| VK_ACCESS_TRANSFORM_FEEDBACK_COUNTER_READ_BIT_EXT
|
||||
| VK_ACCESS_TRANSFORM_FEEDBACK_COUNTER_WRITE_BIT_EXT;
|
||||
info.debugName = "SO counter";
|
||||
|
||||
return device->createBuffer(info, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
|
||||
}
|
||||
|
||||
|
||||
D3D11_COMMON_BUFFER_MAP_MODE D3D11Buffer::DetermineMapMode() {
|
||||
return (m_buffer->memFlags() & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT)
|
||||
D3D11_COMMON_BUFFER_MAP_MODE D3D11Buffer::DetermineMapMode(VkMemoryPropertyFlags MemFlags) {
|
||||
return (MemFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT)
|
||||
? D3D11_COMMON_BUFFER_MAP_MODE_DIRECT
|
||||
: D3D11_COMMON_BUFFER_MAP_MODE_NONE;
|
||||
}
|
||||
|
|
|
@ -61,6 +61,8 @@ namespace dxvk {
|
|||
void STDMETHODCALLTYPE GetDesc(
|
||||
D3D11_BUFFER_DESC *pDesc) final;
|
||||
|
||||
void STDMETHODCALLTYPE SetDebugName(const char* pName) final;
|
||||
|
||||
bool CheckViewCompatibility(
|
||||
UINT BindFlags,
|
||||
DXGI_FORMAT Format) const;
|
||||
|
@ -77,6 +79,10 @@ namespace dxvk {
|
|||
return m_mapMode;
|
||||
}
|
||||
|
||||
uint64_t GetCookie() const {
|
||||
return m_cookie;
|
||||
}
|
||||
|
||||
Rc<DxvkBuffer> GetBuffer() const {
|
||||
return m_buffer;
|
||||
}
|
||||
|
@ -113,17 +119,18 @@ namespace dxvk {
|
|||
: DxvkBufferSlice();
|
||||
}
|
||||
|
||||
DxvkBufferSliceHandle AllocSlice() {
|
||||
return m_buffer->allocSlice();
|
||||
Rc<DxvkResourceAllocation> AllocSlice(DxvkLocalAllocationCache* cache) {
|
||||
return m_buffer->allocateStorage(cache);
|
||||
}
|
||||
|
||||
DxvkBufferSliceHandle DiscardSlice() {
|
||||
m_mapped = m_buffer->allocSlice();
|
||||
return m_mapped;
|
||||
Rc<DxvkResourceAllocation> DiscardSlice(DxvkLocalAllocationCache* cache) {
|
||||
auto allocation = m_buffer->allocateStorage(cache);
|
||||
m_mapPtr = allocation->mapPtr();
|
||||
return allocation;
|
||||
}
|
||||
|
||||
DxvkBufferSliceHandle GetMappedSlice() const {
|
||||
return m_mapped;
|
||||
void* GetMapPtr() const {
|
||||
return m_mapPtr;
|
||||
}
|
||||
|
||||
D3D10Buffer* GetD3D10Iface() {
|
||||
|
@ -182,11 +189,14 @@ namespace dxvk {
|
|||
D3D11_COMMON_BUFFER_MAP_MODE m_mapMode;
|
||||
|
||||
Rc<DxvkBuffer> m_buffer;
|
||||
uint64_t m_cookie = 0u;
|
||||
|
||||
Rc<DxvkBuffer> m_soCounter;
|
||||
Rc<DxvkSparsePageAllocator> m_sparseAllocator;
|
||||
DxvkBufferSliceHandle m_mapped;
|
||||
uint64_t m_seq = 0ull;
|
||||
|
||||
void* m_mapPtr = nullptr;
|
||||
|
||||
D3D11DXGIResource m_resource;
|
||||
D3D10Buffer m_d3d10;
|
||||
|
||||
|
@ -198,7 +208,8 @@ namespace dxvk {
|
|||
|
||||
Rc<DxvkBuffer> CreateSoCounterBuffer();
|
||||
|
||||
D3D11_COMMON_BUFFER_MAP_MODE DetermineMapMode();
|
||||
static D3D11_COMMON_BUFFER_MAP_MODE DetermineMapMode(
|
||||
VkMemoryPropertyFlags MemFlags);
|
||||
|
||||
};
|
||||
|
||||
|
|
|
@ -10,20 +10,12 @@ namespace dxvk {
|
|||
* Used to identify the type of command
|
||||
* data most recently added to a CS chunk.
|
||||
*/
|
||||
enum class D3D11CmdType {
|
||||
enum class D3D11CmdType : uint32_t {
|
||||
None,
|
||||
DrawIndirect,
|
||||
DrawIndirectIndexed,
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* \brief Command data header
|
||||
*
|
||||
* Stores the command type. All command
|
||||
* data structs must inherit this struct.
|
||||
*/
|
||||
struct D3D11CmdData {
|
||||
D3D11CmdType type;
|
||||
Draw,
|
||||
DrawIndexed,
|
||||
};
|
||||
|
||||
|
||||
|
@ -34,10 +26,10 @@ namespace dxvk {
|
|||
* the first draw, as well as the number of
|
||||
* draws to execute.
|
||||
*/
|
||||
struct D3D11CmdDrawIndirectData : public D3D11CmdData {
|
||||
struct D3D11CmdDrawIndirectData {
|
||||
uint32_t offset;
|
||||
uint32_t count;
|
||||
uint32_t stride;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -74,8 +74,6 @@ namespace dxvk {
|
|||
m_resources.push_back(std::move(entry));
|
||||
}
|
||||
|
||||
pCommandList->MarkSubmitted();
|
||||
|
||||
// Return ID of the last chunk added. The command list
|
||||
// added can never be empty, so do not handle zero.
|
||||
return m_chunks.size() - 1;
|
||||
|
@ -102,8 +100,6 @@ namespace dxvk {
|
|||
while (j < m_resources.size() && m_resources[j].chunkId == i)
|
||||
TrackResourceSequenceNumber(m_resources[j++].ref, seq);
|
||||
}
|
||||
|
||||
MarkSubmitted();
|
||||
}
|
||||
|
||||
|
||||
|
@ -150,15 +146,5 @@ namespace dxvk {
|
|||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void D3D11CommandList::MarkSubmitted() {
|
||||
if (m_submitted.exchange(true) && !m_warned.exchange(true)
|
||||
&& m_parent->GetOptions()->dcSingleUseMode) {
|
||||
Logger::warn(
|
||||
"D3D11: Command list submitted multiple times,\n"
|
||||
" but d3d11.dcSingleUseMode is enabled");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -55,14 +55,9 @@ namespace dxvk {
|
|||
std::vector<Com<D3D11Query, false>> m_queries;
|
||||
std::vector<TrackedResource> m_resources;
|
||||
|
||||
std::atomic<bool> m_submitted = { false };
|
||||
std::atomic<bool> m_warned = { false };
|
||||
|
||||
void TrackResourceSequenceNumber(
|
||||
const D3D11ResourceRef& Resource,
|
||||
uint64_t Seq);
|
||||
|
||||
void MarkSubmitted();
|
||||
|
||||
};
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -72,7 +72,14 @@ namespace dxvk {
|
|||
template<typename T> friend class D3D11DeviceContextExt;
|
||||
template<typename T> friend class D3D11UserDefinedAnnotation;
|
||||
|
||||
constexpr static VkDeviceSize StagingBufferSize = 4ull << 20;
|
||||
// Use a local staging buffer to handle tiny uploads, most
|
||||
// of the time we're fine with hitting the global allocator
|
||||
constexpr static VkDeviceSize StagingBufferSize = 256ull << 10;
|
||||
|
||||
protected:
|
||||
// Compile-time debug flag to force lazy binding on (True) or off (False)
|
||||
constexpr static Tristate DebugLazyBinding = Tristate::Auto;
|
||||
|
||||
public:
|
||||
|
||||
D3D11CommonContext(
|
||||
|
@ -102,6 +109,11 @@ namespace dxvk {
|
|||
const D3D11_RECT* pRects,
|
||||
UINT NumRects);
|
||||
|
||||
void STDMETHODCALLTYPE DiscardViewBase(
|
||||
ID3D11View* pResourceView,
|
||||
const D3D11_RECT* pRects,
|
||||
UINT NumRects);
|
||||
|
||||
void STDMETHODCALLTYPE CopySubresourceRegion(
|
||||
ID3D11Resource* pDstResource,
|
||||
UINT DstSubresource,
|
||||
|
@ -123,6 +135,17 @@ namespace dxvk {
|
|||
const D3D11_BOX* pSrcBox,
|
||||
UINT CopyFlags);
|
||||
|
||||
void STDMETHODCALLTYPE CopySubresourceRegionBase(
|
||||
ID3D11Resource* pDstResource,
|
||||
UINT DstSubresource,
|
||||
UINT DstX,
|
||||
UINT DstY,
|
||||
UINT DstZ,
|
||||
ID3D11Resource* pSrcResource,
|
||||
UINT SrcSubresource,
|
||||
const D3D11_BOX* pSrcBox,
|
||||
UINT CopyFlags);
|
||||
|
||||
void STDMETHODCALLTYPE CopyResource(
|
||||
ID3D11Resource* pDstResource,
|
||||
ID3D11Resource* pSrcResource);
|
||||
|
@ -769,19 +792,44 @@ namespace dxvk {
|
|||
UINT m_flags;
|
||||
|
||||
DxvkStagingBuffer m_staging;
|
||||
Rc<DxvkDataBuffer> m_updateBuffer;
|
||||
|
||||
D3D11CmdType m_csDataType = D3D11CmdType::None;
|
||||
|
||||
DxvkCsChunkFlags m_csFlags;
|
||||
DxvkCsChunkRef m_csChunk;
|
||||
D3D11CmdData* m_cmdData;
|
||||
DxvkCsDataBlock* m_csData = nullptr;
|
||||
|
||||
DxvkLocalAllocationCache m_allocationCache;
|
||||
|
||||
DxvkCsChunkRef AllocCsChunk();
|
||||
|
||||
DxvkDataSlice AllocUpdateBufferSlice(size_t Size);
|
||||
|
||||
DxvkBufferSlice AllocStagingBuffer(
|
||||
VkDeviceSize Size);
|
||||
|
||||
void ApplyDirtyConstantBuffers(
|
||||
DxbcProgramType Stage,
|
||||
const DxbcBindingMask& BoundMask,
|
||||
DxbcBindingMask& DirtyMask);
|
||||
|
||||
void ApplyDirtySamplers(
|
||||
DxbcProgramType Stage,
|
||||
const DxbcBindingMask& BoundMask,
|
||||
DxbcBindingMask& DirtyMask);
|
||||
|
||||
void ApplyDirtyShaderResources(
|
||||
DxbcProgramType Stage,
|
||||
const DxbcBindingMask& BoundMask,
|
||||
DxbcBindingMask& DirtyMask);
|
||||
|
||||
void ApplyDirtyUnorderedAccessViews(
|
||||
DxbcProgramType Stage,
|
||||
const DxbcBindingMask& BoundMask,
|
||||
DxbcBindingMask& DirtyMask);
|
||||
|
||||
void ApplyDirtyGraphicsBindings();
|
||||
|
||||
void ApplyDirtyComputeBindings();
|
||||
|
||||
void ApplyInputLayout();
|
||||
|
||||
void ApplyPrimitiveTopology();
|
||||
|
@ -800,6 +848,12 @@ namespace dxvk {
|
|||
|
||||
void ApplyViewportState();
|
||||
|
||||
void BatchDraw(
|
||||
const VkDrawIndirectCommand& draw);
|
||||
|
||||
void BatchDrawIndexed(
|
||||
const VkDrawIndexedIndirectCommand& draw);
|
||||
|
||||
template<DxbcProgramType ShaderStage>
|
||||
void BindShader(
|
||||
const D3D11CommonShader* pShaderModule);
|
||||
|
@ -837,35 +891,33 @@ namespace dxvk {
|
|||
D3D11Buffer* pBuffer,
|
||||
UINT Offset);
|
||||
|
||||
template<DxbcProgramType ShaderStage>
|
||||
void BindConstantBuffer(
|
||||
DxbcProgramType ShaderStage,
|
||||
UINT Slot,
|
||||
D3D11Buffer* pBuffer,
|
||||
UINT Offset,
|
||||
UINT Length);
|
||||
|
||||
template<DxbcProgramType ShaderStage>
|
||||
void BindConstantBufferRange(
|
||||
DxbcProgramType ShaderStage,
|
||||
UINT Slot,
|
||||
UINT Offset,
|
||||
UINT Length);
|
||||
|
||||
template<DxbcProgramType ShaderStage>
|
||||
void BindSampler(
|
||||
DxbcProgramType ShaderStage,
|
||||
UINT Slot,
|
||||
D3D11SamplerState* pSampler);
|
||||
|
||||
template<DxbcProgramType ShaderStage>
|
||||
void BindShaderResource(
|
||||
DxbcProgramType ShaderStage,
|
||||
UINT Slot,
|
||||
D3D11ShaderResourceView* pResource);
|
||||
|
||||
template<DxbcProgramType ShaderStage>
|
||||
void BindUnorderedAccessView(
|
||||
UINT UavSlot,
|
||||
D3D11UnorderedAccessView* pUav,
|
||||
UINT CtrSlot,
|
||||
UINT Counter);
|
||||
DxbcProgramType ShaderStage,
|
||||
UINT Slot,
|
||||
D3D11UnorderedAccessView* pUav);
|
||||
|
||||
VkClearValue ConvertColorValue(
|
||||
const FLOAT Color[4],
|
||||
|
@ -894,6 +946,36 @@ namespace dxvk {
|
|||
DxvkBufferSlice BufferSlice,
|
||||
UINT Flags);
|
||||
|
||||
template<typename T>
|
||||
bool DirtyBindingGeneric(
|
||||
DxbcProgramType ShaderStage,
|
||||
T BoundMask,
|
||||
T& DirtyMask,
|
||||
T DirtyBit,
|
||||
bool IsNull);
|
||||
|
||||
bool DirtyConstantBuffer(
|
||||
DxbcProgramType ShaderStage,
|
||||
uint32_t Slot,
|
||||
bool IsNull);
|
||||
|
||||
bool DirtySampler(
|
||||
DxbcProgramType ShaderStage,
|
||||
uint32_t Slot,
|
||||
bool IsNull);
|
||||
|
||||
bool DirtyShaderResource(
|
||||
DxbcProgramType ShaderStage,
|
||||
uint32_t Slot,
|
||||
bool IsNull);
|
||||
|
||||
bool DirtyComputeUnorderedAccessView(
|
||||
uint32_t Slot,
|
||||
bool IsNull);
|
||||
|
||||
bool DirtyGraphicsUnorderedAccessView(
|
||||
uint32_t Slot);
|
||||
|
||||
void DiscardBuffer(
|
||||
ID3D11Resource* pResource);
|
||||
|
||||
|
@ -926,10 +1008,16 @@ namespace dxvk {
|
|||
|
||||
D3D11MaxUsedBindings GetMaxUsedBindings();
|
||||
|
||||
bool HasDirtyComputeBindings();
|
||||
|
||||
bool HasDirtyGraphicsBindings();
|
||||
|
||||
void ResetCommandListState();
|
||||
|
||||
void ResetContextState();
|
||||
|
||||
void ResetDirtyTracking();
|
||||
|
||||
void ResetStagingBuffer();
|
||||
|
||||
template<DxbcProgramType ShaderStage, typename T>
|
||||
|
@ -952,18 +1040,18 @@ namespace dxvk {
|
|||
|
||||
void RestoreCommandListState();
|
||||
|
||||
template<DxbcProgramType Stage>
|
||||
void RestoreConstantBuffers();
|
||||
|
||||
template<DxbcProgramType Stage>
|
||||
void RestoreSamplers();
|
||||
|
||||
template<DxbcProgramType Stage>
|
||||
void RestoreShaderResources();
|
||||
|
||||
template<DxbcProgramType Stage>
|
||||
void RestoreUnorderedAccessViews();
|
||||
void RestoreConstantBuffers(
|
||||
DxbcProgramType Stage);
|
||||
|
||||
void RestoreSamplers(
|
||||
DxbcProgramType Stage);
|
||||
|
||||
void RestoreShaderResources(
|
||||
DxbcProgramType Stage);
|
||||
|
||||
void RestoreUnorderedAccessViews(
|
||||
DxbcProgramType Stage);
|
||||
|
||||
template<DxbcProgramType ShaderStage>
|
||||
void SetConstantBuffers(
|
||||
UINT StartSlot,
|
||||
|
@ -1046,6 +1134,10 @@ namespace dxvk {
|
|||
UINT SrcDepthPitch,
|
||||
UINT CopyFlags);
|
||||
|
||||
void UpdateUnorderedAccessViewCounter(
|
||||
D3D11UnorderedAccessView* pUav,
|
||||
uint32_t CounterValue);
|
||||
|
||||
bool ValidateRenderTargets(
|
||||
UINT NumViews,
|
||||
ID3D11RenderTargetView* const* ppRenderTargetViews,
|
||||
|
@ -1066,48 +1158,49 @@ namespace dxvk {
|
|||
DxvkMultisampleState* pMsState,
|
||||
UINT SampleMask);
|
||||
|
||||
template<bool AllowFlush = !IsDeferred, typename Cmd>
|
||||
template<bool AllowFlush = true, typename Cmd>
|
||||
void EmitCs(Cmd&& command) {
|
||||
m_cmdData = nullptr;
|
||||
if (unlikely(m_csDataType != D3D11CmdType::None)) {
|
||||
m_csData = nullptr;
|
||||
m_csDataType = D3D11CmdType::None;
|
||||
}
|
||||
|
||||
if (unlikely(!m_csChunk->push(command))) {
|
||||
GetTypedContext()->EmitCsChunk(std::move(m_csChunk));
|
||||
m_csChunk = AllocCsChunk();
|
||||
|
||||
if constexpr (AllowFlush)
|
||||
if constexpr (!IsDeferred && AllowFlush)
|
||||
GetTypedContext()->ConsiderFlush(GpuFlushType::ImplicitWeakHint);
|
||||
|
||||
m_csChunk->push(command);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename M, bool AllowFlush = !IsDeferred, typename Cmd, typename... Args>
|
||||
M* EmitCsCmd(Cmd&& command, Args&&... args) {
|
||||
M* data = m_csChunk->pushCmd<M, Cmd, Args...>(
|
||||
command, std::forward<Args>(args)...);
|
||||
template<typename M, bool AllowFlush = true, typename Cmd>
|
||||
void EmitCsCmd(D3D11CmdType type, size_t count, Cmd&& command) {
|
||||
m_csDataType = type;
|
||||
m_csData = m_csChunk->pushCmd<M, Cmd>(command, count);
|
||||
|
||||
if (unlikely(!data)) {
|
||||
if (unlikely(!m_csData)) {
|
||||
GetTypedContext()->EmitCsChunk(std::move(m_csChunk));
|
||||
m_csChunk = AllocCsChunk();
|
||||
|
||||
if constexpr (AllowFlush)
|
||||
if constexpr (!IsDeferred && AllowFlush)
|
||||
GetTypedContext()->ConsiderFlush(GpuFlushType::ImplicitWeakHint);
|
||||
|
||||
// We must record this command after the potential
|
||||
// flush since the caller may still access the data
|
||||
data = m_csChunk->pushCmd<M, Cmd, Args...>(
|
||||
command, std::forward<Args>(args)...);
|
||||
m_csData = m_csChunk->pushCmd<M, Cmd>(command, count);
|
||||
}
|
||||
|
||||
m_cmdData = data;
|
||||
return data;
|
||||
}
|
||||
|
||||
void FlushCsChunk() {
|
||||
if (likely(!m_csChunk->empty())) {
|
||||
m_csData = nullptr;
|
||||
m_csDataType = D3D11CmdType::None;
|
||||
|
||||
GetTypedContext()->EmitCsChunk(std::move(m_csChunk));
|
||||
m_csChunk = AllocCsChunk();
|
||||
m_cmdData = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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,29 +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(pParent->GetOptions()->reproducibleCommandStream),
|
||||
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();
|
||||
}
|
||||
|
@ -102,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);
|
||||
}
|
||||
|
||||
|
@ -161,6 +160,9 @@ namespace dxvk {
|
|||
void STDMETHODCALLTYPE D3D11ImmediateContext::Flush() {
|
||||
D3D10DeviceLock lock = LockContext();
|
||||
|
||||
if (unlikely(m_device->debugFlags().test(DxvkDebugFlag::Capture)))
|
||||
m_flushReason = "Explicit Flush";
|
||||
|
||||
ExecuteFlush(GpuFlushType::ExplicitFlush, nullptr, true);
|
||||
}
|
||||
|
||||
|
@ -170,6 +172,9 @@ namespace dxvk {
|
|||
HANDLE hEvent) {
|
||||
D3D10DeviceLock lock = LockContext();
|
||||
|
||||
if (unlikely(m_device->debugFlags().test(DxvkDebugFlag::Capture)))
|
||||
m_flushReason = "Explicit Flush";
|
||||
|
||||
ExecuteFlush(GpuFlushType::ExplicitFlush, hEvent, true);
|
||||
}
|
||||
|
||||
|
@ -190,6 +195,9 @@ namespace dxvk {
|
|||
ctx->signalFence(cFence, cValue);
|
||||
});
|
||||
|
||||
if (unlikely(m_device->debugFlags().test(DxvkDebugFlag::Capture)))
|
||||
m_flushReason = "Fence signal";
|
||||
|
||||
ExecuteFlush(GpuFlushType::ExplicitFlush, nullptr, true);
|
||||
return S_OK;
|
||||
}
|
||||
|
@ -204,6 +212,9 @@ namespace dxvk {
|
|||
if (!fence)
|
||||
return E_INVALIDARG;
|
||||
|
||||
if (unlikely(m_device->debugFlags().test(DxvkDebugFlag::Capture)))
|
||||
m_flushReason = "Fence wait";
|
||||
|
||||
ExecuteFlush(GpuFlushType::ExplicitFlush, nullptr, true);
|
||||
|
||||
EmitCs([
|
||||
|
@ -223,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
|
||||
|
@ -284,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;
|
||||
}
|
||||
|
||||
|
||||
|
@ -332,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;
|
||||
}
|
||||
|
||||
|
@ -341,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;
|
||||
|
@ -373,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);
|
||||
|
@ -386,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;
|
||||
|
@ -421,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
|
||||
|
@ -450,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);
|
||||
|
@ -504,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;
|
||||
|
@ -531,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
|
||||
|
@ -553,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;
|
||||
}
|
||||
|
@ -579,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);
|
||||
}
|
||||
|
||||
|
||||
|
@ -619,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())
|
||||
|
@ -677,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);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -705,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);
|
||||
}
|
||||
|
||||
|
||||
|
@ -732,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);
|
||||
|
@ -839,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) {
|
||||
|
@ -861,37 +919,52 @@ namespace dxvk {
|
|||
// Wait for any CS chunk using the resource to execute, since
|
||||
// otherwise we cannot accurately determine if the resource is
|
||||
// actually being used by the GPU right now.
|
||||
bool isInUse = Resource->isInUse(access);
|
||||
|
||||
if (!isInUse) {
|
||||
if (!Resource.isInUse(access)) {
|
||||
SynchronizeCsThread(SequenceNumber);
|
||||
isInUse = Resource->isInUse(access);
|
||||
|
||||
if (!Resource.isInUse(access))
|
||||
return true;
|
||||
}
|
||||
|
||||
if (unlikely(m_device->debugFlags().test(DxvkDebugFlag::Capture))) {
|
||||
m_flushReason = str::format("Map ", Resource.getDebugName(), " (MAP",
|
||||
MapType != D3D11_MAP_WRITE ? "_READ" : "",
|
||||
MapType != D3D11_MAP_READ ? "_WRITE" : "", ")");
|
||||
}
|
||||
|
||||
if (MapFlags & D3D11_MAP_FLAG_DO_NOT_WAIT) {
|
||||
if (isInUse) {
|
||||
// We don't have to wait, but misbehaving games may
|
||||
// still try to spin on `Map` until the resource is
|
||||
// idle, so we should flush pending commands
|
||||
ConsiderFlush(GpuFlushType::ImplicitSynchronization);
|
||||
return false;
|
||||
}
|
||||
// We don't have to wait, but misbehaving games may
|
||||
// still try to spin on `Map` until the resource is
|
||||
// idle, so we should flush pending commands
|
||||
ConsiderFlush(GpuFlushType::ImplicitSynchronization);
|
||||
return false;
|
||||
} else {
|
||||
if (isInUse) {
|
||||
// Make sure pending commands using the resource get
|
||||
// executed on the the GPU if we have to wait for it
|
||||
ExecuteFlush(GpuFlushType::ImplicitSynchronization, nullptr, false);
|
||||
SynchronizeCsThread(SequenceNumber);
|
||||
// Make sure pending commands using the resource get
|
||||
// executed on the the GPU if we have to wait for it
|
||||
ExecuteFlush(GpuFlushType::ImplicitSynchronization, nullptr, false);
|
||||
SynchronizeCsThread(SequenceNumber);
|
||||
|
||||
m_device->waitForResource(Resource, access);
|
||||
}
|
||||
m_device->waitForResource(Resource, access);
|
||||
return true;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void D3D11ImmediateContext::InjectCsChunk(
|
||||
DxvkCsQueue Queue,
|
||||
DxvkCsChunkRef&& Chunk,
|
||||
bool Synchronize) {
|
||||
// Do not update the sequence number when emitting a chunk
|
||||
// from an external source since that would break tracking
|
||||
m_csThread.injectChunk(Queue, std::move(Chunk), Synchronize);
|
||||
}
|
||||
|
||||
|
||||
void D3D11ImmediateContext::EmitCsChunk(DxvkCsChunkRef&& chunk) {
|
||||
// Flush init commands so that the CS thread
|
||||
// can processe them before the first use.
|
||||
m_parent->FlushInitCommands();
|
||||
|
||||
m_csSeqNum = m_csThread.dispatchChunk(std::move(chunk));
|
||||
}
|
||||
|
||||
|
@ -928,8 +1001,106 @@ namespace dxvk {
|
|||
}
|
||||
|
||||
|
||||
void D3D11ImmediateContext::ApplyDirtyNullBindings() {
|
||||
// At the end of a submission, set all bindings that have not been applied yet
|
||||
// to null on the DXVK context. This way, we avoid keeping resources alive that
|
||||
// are bound to the DXVK context but not to the immediate context.
|
||||
//
|
||||
// Note: This requires that all methods that may modify dirty bindings on the
|
||||
// DXVK context also reset the corresponding dirty bits *before* performing the
|
||||
// bind operation, or otherwise an implicit flush can potentially override them.
|
||||
auto& dirtyState = m_state.lazy.bindingsDirty;
|
||||
|
||||
EmitCs<false>([
|
||||
cDirtyState = dirtyState
|
||||
] (DxvkContext* ctx) {
|
||||
for (uint32_t i = 0; i < uint32_t(DxbcProgramType::Count); i++) {
|
||||
auto dxStage = DxbcProgramType(i);
|
||||
auto vkStage = GetShaderStage(dxStage);
|
||||
|
||||
// Unbind all dirty constant buffers
|
||||
auto cbvSlot = computeConstantBufferBinding(dxStage, 0);
|
||||
|
||||
for (uint32_t index : bit::BitMask(cDirtyState[dxStage].cbvMask))
|
||||
ctx->bindUniformBuffer(vkStage, cbvSlot + index, DxvkBufferSlice());
|
||||
|
||||
// Unbind all dirty samplers
|
||||
auto samplerSlot = computeSamplerBinding(dxStage, 0);
|
||||
|
||||
for (uint32_t index : bit::BitMask(cDirtyState[dxStage].samplerMask))
|
||||
ctx->bindResourceSampler(vkStage, samplerSlot + index, nullptr);
|
||||
|
||||
// Unbind all dirty shader resource views
|
||||
auto srvSlot = computeSrvBinding(dxStage, 0);
|
||||
|
||||
for (uint32_t m = 0; m < cDirtyState[dxStage].srvMask.size(); m++) {
|
||||
for (uint32_t index : bit::BitMask(cDirtyState[dxStage].srvMask[m]))
|
||||
ctx->bindResourceImageView(vkStage, srvSlot + index + m * 64u, nullptr);
|
||||
}
|
||||
|
||||
// Unbind all dirty unordered access views
|
||||
VkShaderStageFlags uavStages = 0u;
|
||||
|
||||
if (dxStage == DxbcProgramType::ComputeShader)
|
||||
uavStages = VK_SHADER_STAGE_COMPUTE_BIT;
|
||||
else if (dxStage == DxbcProgramType::PixelShader)
|
||||
uavStages = VK_SHADER_STAGE_ALL_GRAPHICS;
|
||||
|
||||
if (uavStages) {
|
||||
auto uavSlot = computeUavBinding(dxStage, 0);
|
||||
auto ctrSlot = computeUavCounterBinding(dxStage, 0);
|
||||
|
||||
for (uint32_t index : bit::BitMask(cDirtyState[dxStage].uavMask)) {
|
||||
ctx->bindResourceImageView(vkStage, uavSlot + index, nullptr);
|
||||
ctx->bindResourceBufferView(vkStage, ctrSlot + index, nullptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Since we set the DXVK context bindings to null, any bindings that are null
|
||||
// on the D3D context are no longer dirty, so we can clear the respective bits.
|
||||
for (uint32_t i = 0; i < uint32_t(DxbcProgramType::Count); i++) {
|
||||
auto stage = DxbcProgramType(i);
|
||||
|
||||
for (uint32_t index : bit::BitMask(dirtyState[stage].cbvMask)) {
|
||||
if (!m_state.cbv[stage].buffers[index].buffer.ptr())
|
||||
dirtyState[stage].cbvMask &= ~(1u << index);
|
||||
}
|
||||
|
||||
for (uint32_t index : bit::BitMask(dirtyState[stage].samplerMask)) {
|
||||
if (!m_state.samplers[stage].samplers[index])
|
||||
dirtyState[stage].samplerMask &= ~(1u << index);
|
||||
}
|
||||
|
||||
for (uint32_t m = 0; m < dirtyState[stage].srvMask.size(); m++) {
|
||||
for (uint32_t index : bit::BitMask(dirtyState[stage].srvMask[m])) {
|
||||
if (!m_state.srv[stage].views[index + m * 64u].ptr())
|
||||
dirtyState[stage].srvMask[m] &= ~(uint64_t(1u) << index);
|
||||
}
|
||||
}
|
||||
|
||||
if (stage == DxbcProgramType::ComputeShader || stage == DxbcProgramType::PixelShader) {
|
||||
auto& uavs = stage == DxbcProgramType::ComputeShader ? m_state.uav.views : m_state.om.uavs;
|
||||
|
||||
for (uint32_t index : bit::BitMask(dirtyState[stage].uavMask)) {
|
||||
if (!uavs[index].ptr())
|
||||
dirtyState[stage].uavMask &= ~(uint64_t(1u) << index);
|
||||
}
|
||||
}
|
||||
|
||||
if (dirtyState[stage].empty())
|
||||
m_state.lazy.shadersDirty.clr(stage);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void D3D11ImmediateContext::ConsiderFlush(
|
||||
GpuFlushType FlushType) {
|
||||
// In stress test mode, behave as if this would always flush
|
||||
if (DebugLazyBinding == Tristate::True)
|
||||
ApplyDirtyNullBindings();
|
||||
|
||||
uint64_t chunkId = GetCurrentSequenceNumber();
|
||||
uint64_t submissionId = m_submissionFence->value();
|
||||
|
||||
|
@ -947,15 +1118,13 @@ namespace dxvk {
|
|||
if (synchronizeSubmission)
|
||||
m_submitStatus.result = VK_NOT_READY;
|
||||
|
||||
// Flush init context so that new resources are fully initialized
|
||||
// before the app can access them in any way. This has to happen
|
||||
// unconditionally since we may otherwise deadlock on Map.
|
||||
m_parent->FlushInitContext();
|
||||
|
||||
// Exit early if there's nothing to do
|
||||
if (!GetPendingCsChunks() && !hEvent)
|
||||
return;
|
||||
|
||||
// Unbind unused resources
|
||||
ApplyDirtyNullBindings();
|
||||
|
||||
// Signal the submission fence and flush the command list
|
||||
uint64_t submissionId = ++m_submissionId;
|
||||
|
||||
|
@ -968,10 +1137,16 @@ namespace dxvk {
|
|||
EmitCs<false>([
|
||||
cSubmissionFence = m_submissionFence,
|
||||
cSubmissionId = submissionId,
|
||||
cSubmissionStatus = synchronizeSubmission ? &m_submitStatus : nullptr
|
||||
cSubmissionStatus = synchronizeSubmission ? &m_submitStatus : nullptr,
|
||||
cStagingFence = m_stagingBufferFence,
|
||||
cStagingMemory = GetStagingMemoryStatistics().allocatedTotal,
|
||||
cFlushReason = std::exchange(m_flushReason, std::string())
|
||||
] (DxvkContext* ctx) {
|
||||
auto debugLabel = vk::makeLabel(0xff5959, cFlushReason.c_str());
|
||||
|
||||
ctx->signal(cSubmissionFence, cSubmissionId);
|
||||
ctx->flushCommandList(cSubmissionStatus);
|
||||
ctx->signal(cStagingFence, cStagingMemory);
|
||||
ctx->flushCommandList(&debugLabel, cSubmissionStatus);
|
||||
});
|
||||
|
||||
FlushCsChunk();
|
||||
|
@ -984,6 +1159,69 @@ namespace dxvk {
|
|||
// Vulkan queue submission is performed.
|
||||
if (synchronizeSubmission)
|
||||
m_device->waitForSubmission(&m_submitStatus);
|
||||
|
||||
// Free local staging buffer so that we don't
|
||||
// end up with a persistent allocation
|
||||
ResetStagingBuffer();
|
||||
|
||||
// Reset counter for discarded memory in flight
|
||||
m_discardMemoryOnFlush = m_discardMemoryCounter;
|
||||
|
||||
// Notify the device that the context has been flushed,
|
||||
// this resets some resource initialization heuristics.
|
||||
m_parent->NotifyContextFlush();
|
||||
|
||||
// No point in tracking this across submissions
|
||||
m_hasPendingMsaaResolve = false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void D3D11ImmediateContext::ThrottleAllocation() {
|
||||
DxvkStagingBufferStats stats = GetStagingMemoryStatistics();
|
||||
|
||||
VkDeviceSize stagingMemoryInFlight = stats.allocatedTotal - m_stagingBufferFence->value();
|
||||
|
||||
if (stagingMemoryInFlight > stats.allocatedSinceLastReset + D3D11Initializer::MaxMemoryInFlight) {
|
||||
// Stall calling thread to avoid situation where we keep growing the staging
|
||||
// buffer indefinitely, but ignore the newly allocated amount so that we don't
|
||||
// wait for the GPU to go fully idle in case of a large allocation.
|
||||
ExecuteFlush(GpuFlushType::ExplicitFlush, nullptr, false);
|
||||
|
||||
m_device->waitForFence(*m_stagingBufferFence, stats.allocatedTotal -
|
||||
stats.allocatedSinceLastReset - D3D11Initializer::MaxMemoryInFlight);
|
||||
} else if (stats.allocatedSinceLastReset >= D3D11Initializer::MaxMemoryPerSubmission) {
|
||||
// Flush somewhat aggressively if there's a lot of memory in flight
|
||||
ExecuteFlush(GpuFlushType::ExplicitFlush, nullptr, false);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void D3D11ImmediateContext::ThrottleDiscard(
|
||||
VkDeviceSize Size) {
|
||||
m_discardMemoryCounter += Size;
|
||||
|
||||
if (m_discardMemoryCounter - m_discardMemoryOnFlush >= D3D11Initializer::MaxMemoryPerSubmission)
|
||||
ThrottleAllocation();
|
||||
}
|
||||
|
||||
|
||||
DxvkStagingBufferStats D3D11ImmediateContext::GetStagingMemoryStatistics() {
|
||||
DxvkStagingBufferStats stats = m_staging.getStatistics();
|
||||
stats.allocatedTotal += m_discardMemoryCounter;
|
||||
stats.allocatedSinceLastReset += m_discardMemoryCounter - m_discardMemoryOnFlush;
|
||||
return stats;
|
||||
}
|
||||
|
||||
|
||||
GpuFlushType D3D11ImmediateContext::GetMaxFlushType(
|
||||
D3D11Device* pParent,
|
||||
const Rc<DxvkDevice>& Device) {
|
||||
if (pParent->GetOptions()->reproducibleCommandStream)
|
||||
return GpuFlushType::ExplicitFlush;
|
||||
else if (Device->perfHints().preferRenderPassOps)
|
||||
return GpuFlushType::ImplicitMediumHint;
|
||||
else
|
||||
return GpuFlushType::ImplicitWeakHint;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -97,6 +97,21 @@ namespace dxvk {
|
|||
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;
|
||||
|
@ -104,8 +119,6 @@ namespace dxvk {
|
|||
|
||||
uint32_t m_mappedImageCount = 0u;
|
||||
|
||||
VkDeviceSize m_maxImplicitDiscardSize = 0ull;
|
||||
|
||||
Rc<sync::CallbackFence> m_submissionFence;
|
||||
uint64_t m_submissionId = 0ull;
|
||||
DxvkSubmitStatus m_submitStatus;
|
||||
|
@ -113,11 +126,20 @@ namespace dxvk {
|
|||
uint64_t m_flushSeqNum = 0ull;
|
||||
GpuFlushTracker m_flushTracker;
|
||||
|
||||
Rc<sync::Fence> m_stagingBufferFence;
|
||||
|
||||
VkDeviceSize m_discardMemoryCounter = 0u;
|
||||
VkDeviceSize m_discardMemoryOnFlush = 0u;
|
||||
|
||||
bool m_hasPendingMsaaResolve = false;
|
||||
|
||||
D3D10Multithread m_multithread;
|
||||
D3D11VideoContext m_videoContext;
|
||||
|
||||
Com<D3D11DeviceContextState, false> m_stateObject;
|
||||
|
||||
|
||||
std::string m_flushReason;
|
||||
|
||||
HRESULT MapBuffer(
|
||||
D3D11Buffer* pResource,
|
||||
D3D11_MAP MapType,
|
||||
|
@ -153,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);
|
||||
|
@ -174,6 +197,8 @@ namespace dxvk {
|
|||
|
||||
uint64_t GetPendingCsChunks();
|
||||
|
||||
void ApplyDirtyNullBindings();
|
||||
|
||||
void ConsiderFlush(
|
||||
GpuFlushType FlushType);
|
||||
|
||||
|
@ -182,6 +207,17 @@ namespace dxvk {
|
|||
HANDLE hEvent,
|
||||
BOOL Synchronize);
|
||||
|
||||
void ThrottleAllocation();
|
||||
|
||||
void ThrottleDiscard(
|
||||
VkDeviceSize Size);
|
||||
|
||||
DxvkStagingBufferStats GetStagingMemoryStatistics();
|
||||
|
||||
static GpuFlushType GetMaxFlushType(
|
||||
D3D11Device* pParent,
|
||||
const Rc<DxvkDevice>& Device);
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -199,10 +199,11 @@ namespace dxvk {
|
|||
UINT stencilRef = D3D11_DEFAULT_STENCIL_REFERENCE;
|
||||
|
||||
UINT maxRtv = 0u;
|
||||
UINT minUav = D3D11_1_UAV_SLOT_COUNT;
|
||||
UINT maxUav = 0u;
|
||||
|
||||
void reset() {
|
||||
for (uint32_t i = 0; i < maxUav; i++)
|
||||
for (uint32_t i = minUav; i < maxUav; i++)
|
||||
uavs[i] = nullptr;
|
||||
|
||||
for (uint32_t i = 0; i < maxRtv; i++)
|
||||
|
@ -220,8 +221,9 @@ namespace dxvk {
|
|||
sampleMask = D3D11_DEFAULT_SAMPLE_MASK;
|
||||
stencilRef = D3D11_DEFAULT_STENCIL_REFERENCE;
|
||||
|
||||
maxRtv = 0;
|
||||
maxUav = 0;
|
||||
maxRtv = 0u;
|
||||
minUav = D3D11_1_UAV_SLOT_COUNT;
|
||||
maxUav = 0u;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -232,12 +234,12 @@ namespace dxvk {
|
|||
* argument and draw count buffer.
|
||||
*/
|
||||
struct D3D11ContextStateID {
|
||||
Com<D3D11Buffer, false> argBuffer = nullptr;
|
||||
Com<D3D11Buffer, false> cntBuffer = nullptr;
|
||||
uint64_t argBufferCookie = 0u;
|
||||
uint64_t cntBufferCookie = 0u;
|
||||
|
||||
void reset() {
|
||||
argBuffer = nullptr;
|
||||
cntBuffer = nullptr;
|
||||
argBufferCookie = 0u;
|
||||
cntBufferCookie = 0u;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -302,6 +304,32 @@ namespace dxvk {
|
|||
predicateValue = false;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* \brief Lazy binding state
|
||||
*
|
||||
* Keeps track of what state needs to be
|
||||
* re-applied to the context.
|
||||
*/
|
||||
struct D3D11LazyBindings {
|
||||
DxbcProgramTypeFlags shadersUsed = 0u;
|
||||
DxbcProgramTypeFlags shadersDirty = 0u;
|
||||
DxbcProgramTypeFlags graphicsUavShaders = 0u;
|
||||
|
||||
D3D11ShaderStageState<DxbcBindingMask> bindingsUsed;
|
||||
D3D11ShaderStageState<DxbcBindingMask> bindingsDirty;
|
||||
|
||||
void reset() {
|
||||
shadersUsed = 0u;
|
||||
shadersDirty = 0u;
|
||||
graphicsUavShaders = 0u;
|
||||
|
||||
bindingsUsed.reset();
|
||||
bindingsDirty.reset();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* \brief Context state
|
||||
|
@ -325,6 +353,8 @@ namespace dxvk {
|
|||
D3D11SrvBindings srv;
|
||||
D3D11UavBindings uav;
|
||||
D3D11SamplerBindings samplers;
|
||||
|
||||
D3D11LazyBindings lazy;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -342,9 +372,9 @@ namespace dxvk {
|
|||
* \brief Maximum used binding numbers for all context state
|
||||
*/
|
||||
struct D3D11MaxUsedBindings {
|
||||
std::array<D3D11MaxUsedStageBindings, 6> stages;
|
||||
std::array<D3D11MaxUsedStageBindings, uint32_t(DxbcProgramType::Count)> stages;
|
||||
uint32_t vbCount;
|
||||
uint32_t soCount;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,7 +3,8 @@
|
|||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "../dxvk/dxvk_resource.h"
|
||||
#include "../dxvk/dxvk_memory.h"
|
||||
#include "../dxvk/dxvk_sparse.h"
|
||||
|
||||
#include "../util/com/com_guid.h"
|
||||
#include "../util/com/com_object.h"
|
||||
|
|
|
@ -183,7 +183,7 @@ namespace dxvk {
|
|||
desc.TextureLayout = D3D11_TEXTURE_LAYOUT_UNDEFINED;
|
||||
|
||||
ID3D11Texture2D1* texture2D = nullptr;
|
||||
HRESULT hr = CreateTexture2D1(&desc, pInitialData, ppTexture2D ? &texture2D : nullptr);
|
||||
HRESULT hr = CreateTexture2DBase(&desc, pInitialData, ppTexture2D ? &texture2D : nullptr);
|
||||
|
||||
if (hr != S_OK)
|
||||
return hr;
|
||||
|
@ -202,6 +202,14 @@ namespace dxvk {
|
|||
if (!pDesc)
|
||||
return E_INVALIDARG;
|
||||
|
||||
return CreateTexture2DBase(pDesc, pInitialData, ppTexture2D);
|
||||
}
|
||||
|
||||
|
||||
HRESULT STDMETHODCALLTYPE D3D11Device::CreateTexture2DBase(
|
||||
const D3D11_TEXTURE2D_DESC1* pDesc,
|
||||
const D3D11_SUBRESOURCE_DATA* pInitialData,
|
||||
ID3D11Texture2D1** ppTexture2D) {
|
||||
D3D11_COMMON_TEXTURE_DESC desc;
|
||||
desc.Width = pDesc->Width;
|
||||
desc.Height = pDesc->Height;
|
||||
|
@ -262,7 +270,7 @@ namespace dxvk {
|
|||
desc.TextureLayout = D3D11_TEXTURE_LAYOUT_UNDEFINED;
|
||||
|
||||
ID3D11Texture3D1* texture3D = nullptr;
|
||||
HRESULT hr = CreateTexture3D1(&desc, pInitialData, ppTexture3D ? &texture3D : nullptr);
|
||||
HRESULT hr = CreateTexture3DBase(&desc, pInitialData, ppTexture3D ? &texture3D : nullptr);
|
||||
|
||||
if (hr != S_OK)
|
||||
return hr;
|
||||
|
@ -280,7 +288,15 @@ namespace dxvk {
|
|||
|
||||
if (!pDesc)
|
||||
return E_INVALIDARG;
|
||||
|
||||
|
||||
return CreateTexture3DBase(pDesc, pInitialData, ppTexture3D);
|
||||
}
|
||||
|
||||
|
||||
HRESULT STDMETHODCALLTYPE D3D11Device::CreateTexture3DBase(
|
||||
const D3D11_TEXTURE3D_DESC1* pDesc,
|
||||
const D3D11_SUBRESOURCE_DATA* pInitialData,
|
||||
ID3D11Texture3D1** ppTexture3D) {
|
||||
D3D11_COMMON_TEXTURE_DESC desc;
|
||||
desc.Width = pDesc->Width;
|
||||
desc.Height = pDesc->Height;
|
||||
|
@ -325,6 +341,9 @@ namespace dxvk {
|
|||
ID3D11ShaderResourceView** ppSRView) {
|
||||
InitReturnPtr(ppSRView);
|
||||
|
||||
if (!pResource)
|
||||
return E_INVALIDARG;
|
||||
|
||||
uint32_t plane = GetViewPlaneIndex(pResource, pDesc ? pDesc->Format : DXGI_FORMAT_UNKNOWN);
|
||||
|
||||
D3D11_SHADER_RESOURCE_VIEW_DESC1 desc = pDesc
|
||||
|
@ -333,7 +352,7 @@ namespace dxvk {
|
|||
|
||||
ID3D11ShaderResourceView1* view = nullptr;
|
||||
|
||||
HRESULT hr = CreateShaderResourceView1(pResource,
|
||||
HRESULT hr = CreateShaderResourceViewBase(pResource,
|
||||
pDesc ? &desc : nullptr,
|
||||
ppSRView ? &view : nullptr);
|
||||
|
||||
|
@ -353,7 +372,15 @@ namespace dxvk {
|
|||
|
||||
if (!pResource)
|
||||
return E_INVALIDARG;
|
||||
|
||||
|
||||
return CreateShaderResourceViewBase(pResource, pDesc, ppSRView);
|
||||
}
|
||||
|
||||
|
||||
HRESULT STDMETHODCALLTYPE D3D11Device::CreateShaderResourceViewBase(
|
||||
ID3D11Resource* pResource,
|
||||
const D3D11_SHADER_RESOURCE_VIEW_DESC1* pDesc,
|
||||
ID3D11ShaderResourceView1** ppSRView) {
|
||||
D3D11_COMMON_RESOURCE_DESC resourceDesc;
|
||||
GetCommonResourceDesc(pResource, &resourceDesc);
|
||||
|
||||
|
@ -402,21 +429,24 @@ namespace dxvk {
|
|||
ID3D11UnorderedAccessView** ppUAView) {
|
||||
InitReturnPtr(ppUAView);
|
||||
|
||||
if (!pResource)
|
||||
return E_INVALIDARG;
|
||||
|
||||
uint32_t plane = GetViewPlaneIndex(pResource, pDesc ? pDesc->Format : DXGI_FORMAT_UNKNOWN);
|
||||
|
||||
D3D11_UNORDERED_ACCESS_VIEW_DESC1 desc = pDesc
|
||||
? D3D11UnorderedAccessView::PromoteDesc(pDesc, plane)
|
||||
: D3D11_UNORDERED_ACCESS_VIEW_DESC1();
|
||||
|
||||
|
||||
ID3D11UnorderedAccessView1* view = nullptr;
|
||||
|
||||
HRESULT hr = CreateUnorderedAccessView1(pResource,
|
||||
HRESULT hr = CreateUnorderedAccessViewBase(pResource,
|
||||
pDesc ? &desc : nullptr,
|
||||
ppUAView ? &view : nullptr);
|
||||
|
||||
|
||||
if (hr != S_OK)
|
||||
return hr;
|
||||
|
||||
|
||||
*ppUAView = view;
|
||||
return S_OK;
|
||||
}
|
||||
|
@ -430,7 +460,15 @@ namespace dxvk {
|
|||
|
||||
if (!pResource)
|
||||
return E_INVALIDARG;
|
||||
|
||||
|
||||
return CreateUnorderedAccessViewBase(pResource, pDesc, ppUAView);
|
||||
}
|
||||
|
||||
|
||||
HRESULT STDMETHODCALLTYPE D3D11Device::CreateUnorderedAccessViewBase(
|
||||
ID3D11Resource* pResource,
|
||||
const D3D11_UNORDERED_ACCESS_VIEW_DESC1* pDesc,
|
||||
ID3D11UnorderedAccessView1** ppUAView) {
|
||||
D3D11_COMMON_RESOURCE_DESC resourceDesc;
|
||||
GetCommonResourceDesc(pResource, &resourceDesc);
|
||||
|
||||
|
@ -481,6 +519,9 @@ namespace dxvk {
|
|||
ID3D11RenderTargetView** ppRTView) {
|
||||
InitReturnPtr(ppRTView);
|
||||
|
||||
if (!pResource)
|
||||
return E_INVALIDARG;
|
||||
|
||||
uint32_t plane = GetViewPlaneIndex(pResource, pDesc ? pDesc->Format : DXGI_FORMAT_UNKNOWN);
|
||||
|
||||
D3D11_RENDER_TARGET_VIEW_DESC1 desc = pDesc
|
||||
|
@ -489,7 +530,7 @@ namespace dxvk {
|
|||
|
||||
ID3D11RenderTargetView1* view = nullptr;
|
||||
|
||||
HRESULT hr = CreateRenderTargetView1(pResource,
|
||||
HRESULT hr = CreateRenderTargetViewBase(pResource,
|
||||
pDesc ? &desc : nullptr,
|
||||
ppRTView ? &view : nullptr);
|
||||
|
||||
|
@ -509,7 +550,15 @@ namespace dxvk {
|
|||
|
||||
if (!pResource)
|
||||
return E_INVALIDARG;
|
||||
|
||||
|
||||
return CreateRenderTargetViewBase(pResource, pDesc, ppRTView);
|
||||
}
|
||||
|
||||
|
||||
HRESULT STDMETHODCALLTYPE D3D11Device::CreateRenderTargetViewBase(
|
||||
ID3D11Resource* pResource,
|
||||
const D3D11_RENDER_TARGET_VIEW_DESC1* pDesc,
|
||||
ID3D11RenderTargetView1** ppRTView) {
|
||||
// DXVK only supports render target views for image resources
|
||||
D3D11_COMMON_RESOURCE_DESC resourceDesc;
|
||||
GetCommonResourceDesc(pResource, &resourceDesc);
|
||||
|
@ -1202,7 +1251,7 @@ namespace dxvk {
|
|||
desc.ContextType = D3D11_CONTEXT_TYPE_ALL;
|
||||
|
||||
ID3D11Query1* query = nullptr;
|
||||
HRESULT hr = CreateQuery1(&desc, ppQuery ? &query : nullptr);
|
||||
HRESULT hr = CreateQueryBase(&desc, ppQuery ? &query : nullptr);
|
||||
|
||||
if (hr != S_OK)
|
||||
return hr;
|
||||
|
@ -1219,7 +1268,14 @@ namespace dxvk {
|
|||
|
||||
if (!pQueryDesc)
|
||||
return E_INVALIDARG;
|
||||
|
||||
|
||||
return CreateQueryBase(pQueryDesc, ppQuery);
|
||||
}
|
||||
|
||||
|
||||
HRESULT STDMETHODCALLTYPE D3D11Device::CreateQueryBase(
|
||||
const D3D11_QUERY_DESC1* pQueryDesc,
|
||||
ID3D11Query1** ppQuery) {
|
||||
HRESULT hr = D3D11Query::ValidateDesc(pQueryDesc);
|
||||
|
||||
if (FAILED(hr))
|
||||
|
@ -1396,10 +1452,10 @@ namespace dxvk {
|
|||
|| texture->CountSubresources() <= SrcSubresource)
|
||||
return;
|
||||
|
||||
D3D11_MAP map = texture->GetMapType(SrcSubresource);
|
||||
uint32_t map = texture->GetMapType(SrcSubresource);
|
||||
|
||||
if (map != D3D11_MAP_READ
|
||||
&& map != D3D11_MAP_READ_WRITE)
|
||||
if (map != uint32_t(D3D11_MAP_READ)
|
||||
&& map != uint32_t(D3D11_MAP_READ_WRITE))
|
||||
return;
|
||||
|
||||
CopySubresourceData(
|
||||
|
@ -1425,11 +1481,11 @@ namespace dxvk {
|
|||
|| texture->CountSubresources() <= DstSubresource)
|
||||
return;
|
||||
|
||||
D3D11_MAP map = texture->GetMapType(DstSubresource);
|
||||
uint32_t map = texture->GetMapType(DstSubresource);
|
||||
|
||||
if (map != D3D11_MAP_WRITE
|
||||
&& map != D3D11_MAP_WRITE_NO_OVERWRITE
|
||||
&& map != D3D11_MAP_READ_WRITE)
|
||||
if (map != uint32_t(D3D11_MAP_WRITE)
|
||||
&& map != uint32_t(D3D11_MAP_WRITE_NO_OVERWRITE)
|
||||
&& map != uint32_t(D3D11_MAP_READ_WRITE))
|
||||
return;
|
||||
|
||||
CopySubresourceData(
|
||||
|
@ -1839,11 +1895,6 @@ namespace dxvk {
|
|||
}
|
||||
|
||||
|
||||
void D3D11Device::FlushInitContext() {
|
||||
m_initializer->Flush();
|
||||
}
|
||||
|
||||
|
||||
D3D_FEATURE_LEVEL D3D11Device::GetMaxFeatureLevel(
|
||||
const Rc<DxvkInstance>& Instance,
|
||||
const Rc<DxvkAdapter>& Adapter) {
|
||||
|
@ -1905,8 +1956,6 @@ namespace dxvk {
|
|||
enabled.core.features.shaderImageGatherExtended = VK_TRUE;
|
||||
enabled.core.features.textureCompressionBC = VK_TRUE;
|
||||
|
||||
enabled.vk11.shaderDrawParameters = VK_TRUE;
|
||||
|
||||
enabled.vk12.samplerMirrorClampToEdge = VK_TRUE;
|
||||
|
||||
enabled.vk13.shaderDemoteToHelperInvocation = VK_TRUE;
|
||||
|
@ -1923,7 +1972,6 @@ namespace dxvk {
|
|||
// Required for Feature Level 11_0
|
||||
enabled.core.features.drawIndirectFirstInstance = supported.core.features.drawIndirectFirstInstance;
|
||||
enabled.core.features.fragmentStoresAndAtomics = supported.core.features.fragmentStoresAndAtomics;
|
||||
enabled.core.features.multiDrawIndirect = supported.core.features.multiDrawIndirect;
|
||||
enabled.core.features.tessellationShader = supported.core.features.tessellationShader;
|
||||
|
||||
// Required for Feature Level 11_1
|
||||
|
@ -1969,6 +2017,9 @@ namespace dxvk {
|
|||
size_t BytecodeLength,
|
||||
ID3D11ClassLinkage* pClassLinkage,
|
||||
const DxbcModuleInfo* pModuleInfo) {
|
||||
if (!BytecodeLength || !pShaderBytecode)
|
||||
return E_INVALIDARG;
|
||||
|
||||
if (pClassLinkage != nullptr)
|
||||
Logger::warn("D3D11Device::CreateShaderModule: Class linkage not supported");
|
||||
|
||||
|
@ -2384,11 +2435,7 @@ namespace dxvk {
|
|||
D3D11_COMMON_TEXTURE_SUBRESOURCE_LAYOUT layout = pTexture->GetSubresourceLayout(aspect, Subresource);
|
||||
|
||||
// Compute actual map pointer, accounting for the region offset
|
||||
VkDeviceSize mapOffset = pTexture->ComputeMappedOffset(Subresource, i, offset);
|
||||
|
||||
void* mapPtr = pTexture->GetMapMode() == D3D11_COMMON_TEXTURE_MAP_MODE_BUFFER
|
||||
? pTexture->GetMappedBuffer(Subresource)->mapPtr(mapOffset)
|
||||
: image->mapPtr(mapOffset);
|
||||
void* mapPtr = pTexture->GetMapPtr(Subresource, pTexture->ComputeMappedOffset(Subresource, i, offset));
|
||||
|
||||
if constexpr (std::is_const<Void>::value) {
|
||||
// WriteToSubresource
|
||||
|
@ -2492,15 +2539,15 @@ namespace dxvk {
|
|||
|
||||
D3D11SamplerState* pSS = static_cast<D3D11SamplerState*>(samplerState);
|
||||
Rc<DxvkSampler> pDSS = pSS->GetDXVKSampler();
|
||||
VkSampler vkSampler = pDSS->handle();
|
||||
|
||||
D3D11ShaderResourceView* pSRV = static_cast<D3D11ShaderResourceView*>(srv);
|
||||
Rc<DxvkImageView> pIV = pSRV->GetImageView();
|
||||
VkImageView vkImageView = pIV->handle();
|
||||
|
||||
VkImageViewHandleInfoNVX imageViewHandleInfo = {VK_STRUCTURE_TYPE_IMAGE_VIEW_HANDLE_INFO_NVX};
|
||||
imageViewHandleInfo.imageView = vkImageView;
|
||||
imageViewHandleInfo.sampler = vkSampler;
|
||||
LockImage(pIV->image(), 0u);
|
||||
|
||||
VkImageViewHandleInfoNVX imageViewHandleInfo = { VK_STRUCTURE_TYPE_IMAGE_VIEW_HANDLE_INFO_NVX };
|
||||
imageViewHandleInfo.imageView = pIV->handle();
|
||||
imageViewHandleInfo.sampler = pDSS->handle();
|
||||
imageViewHandleInfo.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
|
||||
|
||||
// note: there's no implicit lifetime management here; it's up to the
|
||||
|
@ -2558,21 +2605,9 @@ namespace dxvk {
|
|||
ID3D11Resource* pResource = static_cast<ID3D11Resource*>(hObject);
|
||||
|
||||
D3D11_COMMON_RESOURCE_DESC resourceDesc;
|
||||
if (FAILED(GetCommonResourceDesc(pResource, &resourceDesc))) {
|
||||
Logger::warn("GetResourceHandleGPUVirtualAddressAndSize() - GetCommonResourceDesc() failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (resourceDesc.Dim) {
|
||||
case D3D11_RESOURCE_DIMENSION_BUFFER:
|
||||
case D3D11_RESOURCE_DIMENSION_TEXTURE2D:
|
||||
// okay - we can deal with those two dimensions
|
||||
break;
|
||||
case D3D11_RESOURCE_DIMENSION_TEXTURE1D:
|
||||
case D3D11_RESOURCE_DIMENSION_TEXTURE3D:
|
||||
case D3D11_RESOURCE_DIMENSION_UNKNOWN:
|
||||
default:
|
||||
Logger::warn(str::format("GetResourceHandleGPUVirtualAddressAndSize(?) - failure - unsupported dimension: ", resourceDesc.Dim));
|
||||
if (FAILED(GetCommonResourceDesc(pResource, &resourceDesc))) {
|
||||
Logger::warn("GetResourceHandleGPUVirtualAddressAndSize: Invalid resource");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -2581,57 +2616,49 @@ namespace dxvk {
|
|||
|
||||
if (resourceDesc.Dim == D3D11_RESOURCE_DIMENSION_TEXTURE2D) {
|
||||
D3D11CommonTexture *texture = GetCommonTexture(pResource);
|
||||
|
||||
// Ensure that the image has a stable GPU address and
|
||||
// won't be relocated by the backend going forward
|
||||
Rc<DxvkImage> dxvkImage = texture->GetImage();
|
||||
if (0 == (dxvkImage->info().usage & (VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_SAMPLED_BIT))) {
|
||||
Logger::warn(str::format("GetResourceHandleGPUVirtualAddressAndSize(res=", pResource,") image info missing required usage bit(s); can't be used for vkGetImageViewHandleNVX - failure"));
|
||||
|
||||
if (!LockImage(dxvkImage, VK_IMAGE_USAGE_SAMPLED_BIT))
|
||||
return false;
|
||||
}
|
||||
|
||||
// The d3d11 nvapi provides us a texture but vulkan only lets us get the GPU address from an imageview. So, make a private imageview and get the address from that...
|
||||
// The d3d11 nvapi provides us a texture, but vulkan only lets us
|
||||
// get the GPU address from an image view. So, make a private image
|
||||
// view and get the address from that.
|
||||
DxvkImageViewKey viewInfo;
|
||||
viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
|
||||
viewInfo.format = dxvkImage->info().format;
|
||||
viewInfo.aspects = dxvkImage->formatInfo()->aspectMask;
|
||||
viewInfo.mipIndex = 0;
|
||||
viewInfo.mipCount = dxvkImage->info().mipLevels;
|
||||
viewInfo.layerIndex = 0;
|
||||
viewInfo.layerCount = 1;
|
||||
viewInfo.usage = VK_IMAGE_USAGE_SAMPLED_BIT;
|
||||
|
||||
D3D11_SHADER_RESOURCE_VIEW_DESC resourceViewDesc;
|
||||
auto dxvkView = dxvkImage->createView(viewInfo);
|
||||
VkImageViewAddressPropertiesNVX imageViewAddressProperties = { VK_STRUCTURE_TYPE_IMAGE_VIEW_ADDRESS_PROPERTIES_NVX };
|
||||
|
||||
const D3D11_COMMON_TEXTURE_DESC *texDesc = texture->Desc();
|
||||
if (texDesc->ArraySize != 1) {
|
||||
Logger::debug(str::format("GetResourceHandleGPUVirtualAddressAndSize(?) - unexpected array size: ", texDesc->ArraySize));
|
||||
}
|
||||
resourceViewDesc.Format = texDesc->Format;
|
||||
resourceViewDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
|
||||
resourceViewDesc.Texture2D.MostDetailedMip = 0;
|
||||
resourceViewDesc.Texture2D.MipLevels = texDesc->MipLevels;
|
||||
VkResult vr = dxvkDevice->vkd()->vkGetImageViewAddressNVX(vkDevice,
|
||||
dxvkView->handle(), &imageViewAddressProperties);
|
||||
|
||||
Com<ID3D11ShaderResourceView> pNewSRV;
|
||||
HRESULT hr = m_device->CreateShaderResourceView(pResource, &resourceViewDesc, &pNewSRV);
|
||||
if (FAILED(hr)) {
|
||||
Logger::warn("GetResourceHandleGPUVirtualAddressAndSize() - private CreateShaderResourceView() failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
Rc<DxvkImageView> dxvkImageView = static_cast<D3D11ShaderResourceView*>(pNewSRV.ptr())->GetImageView();
|
||||
VkImageView vkImageView = dxvkImageView->handle();
|
||||
|
||||
VkImageViewAddressPropertiesNVX imageViewAddressProperties = {VK_STRUCTURE_TYPE_IMAGE_VIEW_ADDRESS_PROPERTIES_NVX};
|
||||
|
||||
VkResult res = dxvkDevice->vkd()->vkGetImageViewAddressNVX(vkDevice, vkImageView, &imageViewAddressProperties);
|
||||
if (res != VK_SUCCESS) {
|
||||
Logger::warn(str::format("GetResourceHandleGPUVirtualAddressAndSize(): vkGetImageViewAddressNVX() result is failure: ", res));
|
||||
if (vr != VK_SUCCESS) {
|
||||
Logger::warn(str::format("GetResourceHandleGPUVirtualAddressAndSize(): Failed: vr = ", vr));
|
||||
return false;
|
||||
}
|
||||
|
||||
*gpuVAStart = imageViewAddressProperties.deviceAddress;
|
||||
*gpuVASize = imageViewAddressProperties.size;
|
||||
}
|
||||
else if (resourceDesc.Dim == D3D11_RESOURCE_DIMENSION_BUFFER) {
|
||||
D3D11Buffer *buffer = GetCommonBuffer(pResource);
|
||||
const DxvkBufferSliceHandle bufSliceHandle = buffer->GetBuffer()->getSliceHandle();
|
||||
VkBuffer vkBuffer = bufSliceHandle.handle;
|
||||
} else if (resourceDesc.Dim == D3D11_RESOURCE_DIMENSION_BUFFER) {
|
||||
Rc<DxvkBuffer> dxvkBuffer = GetCommonBuffer(pResource)->GetBuffer();
|
||||
LockBuffer(dxvkBuffer);
|
||||
|
||||
VkBufferDeviceAddressInfo bdaInfo = { VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO };
|
||||
bdaInfo.buffer = vkBuffer;
|
||||
|
||||
VkDeviceAddress bufAddr = dxvkDevice->vkd()->vkGetBufferDeviceAddress(vkDevice, &bdaInfo);
|
||||
*gpuVAStart = uint64_t(bufAddr) + bufSliceHandle.offset;
|
||||
*gpuVASize = bufSliceHandle.length;
|
||||
*gpuVAStart = dxvkBuffer->gpuAddress();
|
||||
*gpuVASize = dxvkBuffer->info().size;
|
||||
} else {
|
||||
Logger::warn(str::format("GetResourceHandleGPUVirtualAddressAndSize(): Unsupported resource type: ", resourceDesc.Dim));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!*gpuVAStart)
|
||||
|
@ -2641,102 +2668,99 @@ namespace dxvk {
|
|||
}
|
||||
|
||||
|
||||
bool STDMETHODCALLTYPE D3D11DeviceExt::CreateUnorderedAccessViewAndGetDriverHandleNVX(ID3D11Resource* pResource, const D3D11_UNORDERED_ACCESS_VIEW_DESC* pDesc, ID3D11UnorderedAccessView** ppUAV, uint32_t* pDriverHandle) {
|
||||
D3D11_COMMON_RESOURCE_DESC resourceDesc;
|
||||
if (!SUCCEEDED(GetCommonResourceDesc(pResource, &resourceDesc))) {
|
||||
Logger::warn("CreateUnorderedAccessViewAndGetDriverHandleNVX() - GetCommonResourceDesc() failed");
|
||||
return false;
|
||||
}
|
||||
bool STDMETHODCALLTYPE D3D11DeviceExt::CreateUnorderedAccessViewAndGetDriverHandleNVX(
|
||||
ID3D11Resource* pResource,
|
||||
const D3D11_UNORDERED_ACCESS_VIEW_DESC* pDesc,
|
||||
ID3D11UnorderedAccessView** ppUAV,
|
||||
uint32_t* pDriverHandle) {
|
||||
D3D11_COMMON_RESOURCE_DESC resourceDesc = { };
|
||||
GetCommonResourceDesc(pResource, &resourceDesc);
|
||||
|
||||
if (resourceDesc.Dim != D3D11_RESOURCE_DIMENSION_TEXTURE2D) {
|
||||
Logger::warn(str::format("CreateUnorderedAccessViewAndGetDriverHandleNVX() - failure - unsupported dimension: ", resourceDesc.Dim));
|
||||
Logger::warn(str::format("CreateUnorderedAccessViewAndGetDriverHandleNVX(): Unsupported dimension: ", resourceDesc.Dim));
|
||||
return false;
|
||||
}
|
||||
|
||||
auto texture = GetCommonTexture(pResource);
|
||||
Rc<DxvkImage> dxvkImage = texture->GetImage();
|
||||
if (0 == (dxvkImage->info().usage & (VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_SAMPLED_BIT))) {
|
||||
Logger::warn(str::format("CreateUnorderedAccessViewAndGetDriverHandleNVX(res=", pResource, ") image info missing required usage bit(s); can't be used for vkGetImageViewHandleNVX - failure"));
|
||||
Rc<DxvkImage> dxvkImage = GetCommonTexture(pResource)->GetImage();
|
||||
|
||||
if (!(dxvkImage->info().usage & VK_IMAGE_USAGE_STORAGE_BIT)) {
|
||||
Logger::warn(str::format("CreateUnorderedAccessViewAndGetDriverHandleNVX(res=", pResource, "): Image not UAV compatible"));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!SUCCEEDED(m_device->CreateUnorderedAccessView(pResource, pDesc, ppUAV))) {
|
||||
return false;
|
||||
}
|
||||
Com<ID3D11UnorderedAccessView> uav;
|
||||
|
||||
D3D11UnorderedAccessView *pUAV = static_cast<D3D11UnorderedAccessView *>(*ppUAV);
|
||||
Rc<DxvkDevice> dxvkDevice = m_device->GetDXVKDevice();
|
||||
VkDevice vkDevice = dxvkDevice->handle();
|
||||
if (FAILED(m_device->CreateUnorderedAccessView(pResource, pDesc, &uav)))
|
||||
return false;
|
||||
|
||||
Rc<DxvkImageView> dxvkImageView = static_cast<D3D11UnorderedAccessView*>(uav.ptr())->GetImageView();
|
||||
LockImage(dxvkImageView->image(), 0u);
|
||||
|
||||
VkImageViewHandleInfoNVX imageViewHandleInfo = {VK_STRUCTURE_TYPE_IMAGE_VIEW_HANDLE_INFO_NVX};
|
||||
Rc<DxvkImageView> dxvkImageView = pUAV->GetImageView();
|
||||
VkImageView vkImageView = dxvkImageView->handle();
|
||||
|
||||
imageViewHandleInfo.imageView = vkImageView;
|
||||
imageViewHandleInfo.imageView = dxvkImageView->handle();
|
||||
imageViewHandleInfo.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE;
|
||||
|
||||
*pDriverHandle = dxvkDevice->vkd()->vkGetImageViewHandleNVX(vkDevice, &imageViewHandleInfo);
|
||||
Rc<DxvkDevice> dxvkDevice = m_device->GetDXVKDevice();
|
||||
*pDriverHandle = dxvkDevice->vkd()->vkGetImageViewHandleNVX(
|
||||
dxvkDevice->handle(), &imageViewHandleInfo);
|
||||
|
||||
if (!*pDriverHandle) {
|
||||
Logger::warn("CreateUnorderedAccessViewAndGetDriverHandleNVX() handle==0 - failure");
|
||||
pUAV->Release();
|
||||
Logger::warn("CreateUnorderedAccessViewAndGetDriverHandleNVX(): Handle is 0");
|
||||
return false;
|
||||
}
|
||||
|
||||
*ppUAV = uav.ref();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool STDMETHODCALLTYPE D3D11DeviceExt::CreateShaderResourceViewAndGetDriverHandleNVX(ID3D11Resource* pResource, const D3D11_SHADER_RESOURCE_VIEW_DESC* pDesc, ID3D11ShaderResourceView** ppSRV, uint32_t* pDriverHandle) {
|
||||
D3D11_COMMON_RESOURCE_DESC resourceDesc;
|
||||
if (!SUCCEEDED(GetCommonResourceDesc(pResource, &resourceDesc))) {
|
||||
Logger::warn("CreateShaderResourceViewAndGetDriverHandleNVX() - GetCommonResourceDesc() failed");
|
||||
return false;
|
||||
}
|
||||
D3D11_COMMON_RESOURCE_DESC resourceDesc = { };
|
||||
GetCommonResourceDesc(pResource, &resourceDesc);
|
||||
|
||||
if (resourceDesc.Dim != D3D11_RESOURCE_DIMENSION_TEXTURE2D) {
|
||||
Logger::warn(str::format("CreateShaderResourceViewAndGetDriverHandleNVX() - failure - unsupported dimension: ", resourceDesc.Dim));
|
||||
Logger::warn(str::format("CreateShaderResourceViewAndGetDriverHandleNVX(): Unsupported dimension: ", resourceDesc.Dim));
|
||||
return false;
|
||||
}
|
||||
|
||||
auto texture = GetCommonTexture(pResource);
|
||||
Rc<DxvkImage> dxvkImage = texture->GetImage();
|
||||
if (0 == (dxvkImage->info().usage & (VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_SAMPLED_BIT))) {
|
||||
Logger::warn(str::format("CreateShaderResourceViewAndGetDriverHandleNVX(res=", pResource, ") image info missing required usage bit(s); can't be used for vkGetImageViewHandleNVX - failure"));
|
||||
Rc<DxvkImage> dxvkImage = GetCommonTexture(pResource)->GetImage();
|
||||
|
||||
if (!(dxvkImage->info().usage & VK_IMAGE_USAGE_SAMPLED_BIT)) {
|
||||
Logger::warn(str::format("CreateShaderResourceViewAndGetDriverHandleNVX(res=", pResource, "): Image not SRV compatible"));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!SUCCEEDED(m_device->CreateShaderResourceView(pResource, pDesc, ppSRV))) {
|
||||
return false;
|
||||
}
|
||||
Com<ID3D11ShaderResourceView> srv;
|
||||
|
||||
D3D11ShaderResourceView* pSRV = static_cast<D3D11ShaderResourceView*>(*ppSRV);
|
||||
Rc<DxvkDevice> dxvkDevice = m_device->GetDXVKDevice();
|
||||
VkDevice vkDevice = dxvkDevice->handle();
|
||||
if (FAILED(m_device->CreateShaderResourceView(pResource, pDesc, &srv)))
|
||||
return false;
|
||||
|
||||
Rc<DxvkImageView> dxvkImageView = static_cast<D3D11ShaderResourceView*>(srv.ptr())->GetImageView();
|
||||
LockImage(dxvkImageView->image(), 0u);
|
||||
|
||||
VkImageViewHandleInfoNVX imageViewHandleInfo = {VK_STRUCTURE_TYPE_IMAGE_VIEW_HANDLE_INFO_NVX};
|
||||
Rc<DxvkImageView> dxvkImageView = pSRV->GetImageView();
|
||||
VkImageView vkImageView = dxvkImageView->handle();
|
||||
|
||||
imageViewHandleInfo.imageView = vkImageView;
|
||||
imageViewHandleInfo.imageView = dxvkImageView->handle();
|
||||
imageViewHandleInfo.descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE;
|
||||
|
||||
*pDriverHandle = dxvkDevice->vkd()->vkGetImageViewHandleNVX(vkDevice, &imageViewHandleInfo);
|
||||
Rc<DxvkDevice> dxvkDevice = m_device->GetDXVKDevice();
|
||||
*pDriverHandle = dxvkDevice->vkd()->vkGetImageViewHandleNVX(
|
||||
dxvkDevice->handle(), &imageViewHandleInfo);
|
||||
|
||||
if (!*pDriverHandle) {
|
||||
Logger::warn("CreateShaderResourceViewAndGetDriverHandleNVX() handle==0 - failure");
|
||||
pSRV->Release();
|
||||
Logger::warn("CreateShaderResourceViewAndGetDriverHandleNVX(): Handle is 0");
|
||||
return false;
|
||||
}
|
||||
|
||||
// will need to look-up resource from uint32 handle later
|
||||
AddSrvAndHandleNVX(*ppSRV, *pDriverHandle);
|
||||
*ppSRV = srv.ref();
|
||||
AddSrvAndHandleNVX(srv.ptr(), *pDriverHandle);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool STDMETHODCALLTYPE D3D11DeviceExt::CreateSamplerStateAndGetDriverHandleNVX(const D3D11_SAMPLER_DESC* pSamplerDesc, ID3D11SamplerState** ppSamplerState, uint32_t* pDriverHandle) {
|
||||
if (!SUCCEEDED(m_device->CreateSamplerState(pSamplerDesc, ppSamplerState))) {
|
||||
if (FAILED(m_device->CreateSamplerState(pSamplerDesc, ppSamplerState)))
|
||||
return false;
|
||||
}
|
||||
|
||||
// for our purposes the actual value doesn't matter, only its uniqueness
|
||||
static std::atomic<ULONG> s_seqNum = 0;
|
||||
|
@ -2782,8 +2806,57 @@ namespace dxvk {
|
|||
}
|
||||
|
||||
|
||||
bool D3D11DeviceExt::LockImage(
|
||||
const Rc<DxvkImage>& Image,
|
||||
VkImageUsageFlags Usage) {
|
||||
if (!Image->canRelocate() && (Image->info().usage & Usage))
|
||||
return true;
|
||||
|
||||
bool feedback = false;
|
||||
|
||||
auto chunk = m_device->AllocCsChunk(DxvkCsChunkFlag::SingleUse);
|
||||
|
||||
chunk->push([
|
||||
cImage = Image,
|
||||
cUsage = Usage,
|
||||
&feedback
|
||||
] (DxvkContext* ctx) {
|
||||
DxvkImageUsageInfo usageInfo;
|
||||
usageInfo.usage = cUsage;
|
||||
usageInfo.stableGpuAddress = VK_TRUE;
|
||||
|
||||
feedback = ctx->ensureImageCompatibility(cImage, usageInfo);
|
||||
});
|
||||
|
||||
m_device->GetContext()->InjectCsChunk(DxvkCsQueue::HighPriority, std::move(chunk), true);
|
||||
|
||||
if (!feedback) {
|
||||
Logger::err(str::format("Failed to lock image:"
|
||||
"\n Image format: ", Image->info().format,
|
||||
"\n Image usage: ", std::hex, Image->info().usage,
|
||||
"\n Desired usage: ", std::hex, Usage));
|
||||
}
|
||||
|
||||
return feedback;
|
||||
}
|
||||
|
||||
|
||||
void D3D11DeviceExt::LockBuffer(
|
||||
const Rc<DxvkBuffer>& Buffer) {
|
||||
if (!Buffer->canRelocate())
|
||||
return;
|
||||
|
||||
auto chunk = m_device->AllocCsChunk(DxvkCsChunkFlag::SingleUse);
|
||||
|
||||
chunk->push([cBuffer = Buffer] (DxvkContext* ctx) {
|
||||
ctx->ensureBufferAddress(cBuffer);
|
||||
});
|
||||
|
||||
m_device->GetContext()->InjectCsChunk(DxvkCsQueue::HighPriority, std::move(chunk), true);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
D3D11VideoDevice::D3D11VideoDevice(
|
||||
D3D11DXGIDevice* pContainer,
|
||||
|
@ -2985,6 +3058,198 @@ namespace dxvk {
|
|||
|
||||
|
||||
|
||||
D3D11ReflexDevice::D3D11ReflexDevice(
|
||||
D3D11DXGIDevice* pContainer,
|
||||
D3D11Device* pDevice)
|
||||
: m_container(pContainer), m_device(pDevice) {
|
||||
auto dxvkDevice = pDevice->GetDXVKDevice();
|
||||
|
||||
m_reflexEnabled = dxvkDevice->features().nvLowLatency2
|
||||
&& dxvkDevice->config().latencySleep == Tristate::Auto;
|
||||
}
|
||||
|
||||
|
||||
D3D11ReflexDevice::~D3D11ReflexDevice() {
|
||||
|
||||
}
|
||||
|
||||
|
||||
ULONG STDMETHODCALLTYPE D3D11ReflexDevice::AddRef() {
|
||||
return m_container->AddRef();
|
||||
}
|
||||
|
||||
|
||||
ULONG STDMETHODCALLTYPE D3D11ReflexDevice::Release() {
|
||||
return m_container->Release();
|
||||
}
|
||||
|
||||
|
||||
HRESULT STDMETHODCALLTYPE D3D11ReflexDevice::QueryInterface(
|
||||
REFIID riid,
|
||||
void** ppvObject) {
|
||||
return m_container->QueryInterface(riid, ppvObject);
|
||||
}
|
||||
|
||||
|
||||
BOOL STDMETHODCALLTYPE D3D11ReflexDevice::SupportsLowLatency() {
|
||||
return m_reflexEnabled;
|
||||
}
|
||||
|
||||
|
||||
HRESULT STDMETHODCALLTYPE D3D11ReflexDevice::LatencySleep() {
|
||||
if (!m_reflexEnabled)
|
||||
return DXGI_ERROR_INVALID_CALL;
|
||||
|
||||
// Don't keep object locked while sleeping
|
||||
Rc<DxvkReflexLatencyTrackerNv> tracker;
|
||||
|
||||
{ std::lock_guard lock(m_mutex);
|
||||
tracker = m_tracker;
|
||||
}
|
||||
|
||||
if (tracker)
|
||||
tracker->latencySleep();
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
HRESULT STDMETHODCALLTYPE D3D11ReflexDevice::SetLatencySleepMode(
|
||||
BOOL LowLatencyEnable,
|
||||
BOOL LowLatencyBoost,
|
||||
UINT32 MinIntervalUs) {
|
||||
if (!m_reflexEnabled)
|
||||
return DXGI_ERROR_INVALID_CALL;
|
||||
|
||||
std::lock_guard lock(m_mutex);
|
||||
|
||||
if (m_tracker) {
|
||||
m_tracker->setLatencySleepMode(
|
||||
LowLatencyEnable, LowLatencyBoost, MinIntervalUs);
|
||||
}
|
||||
|
||||
// Write back in case we have no swapchain yet
|
||||
m_enableLowLatency = LowLatencyEnable;
|
||||
m_enableBoost = LowLatencyBoost;
|
||||
m_minIntervalUs = MinIntervalUs;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
HRESULT STDMETHODCALLTYPE D3D11ReflexDevice::SetLatencyMarker(
|
||||
UINT64 FrameId,
|
||||
UINT32 MarkerType) {
|
||||
if (!m_reflexEnabled)
|
||||
return DXGI_ERROR_INVALID_CALL;
|
||||
|
||||
std::lock_guard lock(m_mutex);
|
||||
|
||||
if (m_tracker) {
|
||||
auto marker = VkLatencyMarkerNV(MarkerType);
|
||||
m_tracker->setLatencyMarker(FrameId, marker);
|
||||
|
||||
if (marker == VK_LATENCY_MARKER_RENDERSUBMIT_START_NV) {
|
||||
m_device->GetContext()->InjectCs(DxvkCsQueue::Ordered, [
|
||||
cTracker = m_tracker,
|
||||
cFrameId = FrameId
|
||||
] (DxvkContext* ctx) {
|
||||
uint64_t frameId = cTracker->frameIdFromAppFrameId(cFrameId);
|
||||
|
||||
if (frameId)
|
||||
ctx->beginLatencyTracking(cTracker, frameId);
|
||||
});
|
||||
} else if (marker == VK_LATENCY_MARKER_RENDERSUBMIT_END_NV) {
|
||||
m_device->GetContext()->InjectCs(DxvkCsQueue::Ordered, [
|
||||
cTracker = m_tracker
|
||||
] (DxvkContext* ctx) {
|
||||
ctx->endLatencyTracking(cTracker);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
HRESULT STDMETHODCALLTYPE D3D11ReflexDevice::GetLatencyInfo(
|
||||
D3D_LOW_LATENCY_RESULTS* pLowLatencyResults) {
|
||||
constexpr static size_t FrameCount = 64;
|
||||
|
||||
if (!pLowLatencyResults)
|
||||
return E_INVALIDARG;
|
||||
|
||||
for (size_t i = 0; i < FrameCount; i++)
|
||||
pLowLatencyResults->frameReports[i] = D3D_LOW_LATENCY_FRAME_REPORT();
|
||||
|
||||
if (!m_reflexEnabled)
|
||||
return DXGI_ERROR_INVALID_CALL;
|
||||
|
||||
std::lock_guard lock(m_mutex);
|
||||
|
||||
if (!m_tracker)
|
||||
return S_OK;
|
||||
|
||||
// Apparently we have to report all 64 frames, or nothing
|
||||
std::array<DxvkReflexFrameReport, FrameCount> reports = { };
|
||||
uint32_t reportCount = m_tracker->getFrameReports(FrameCount, reports.data());
|
||||
|
||||
if (reportCount < FrameCount)
|
||||
return S_OK;
|
||||
|
||||
for (uint32_t i = 0; i < FrameCount; i++) {
|
||||
auto& src = reports[i];
|
||||
auto& dst = pLowLatencyResults->frameReports[i];
|
||||
|
||||
dst.frameID = src.report.presentID;
|
||||
dst.inputSampleTime = src.report.inputSampleTimeUs;
|
||||
dst.simStartTime = src.report.simStartTimeUs;
|
||||
dst.simEndTime = src.report.simEndTimeUs;
|
||||
dst.renderSubmitStartTime = src.report.renderSubmitStartTimeUs;
|
||||
dst.renderSubmitEndTime = src.report.renderSubmitEndTimeUs;
|
||||
dst.presentStartTime = src.report.presentStartTimeUs;
|
||||
dst.presentEndTime = src.report.presentEndTimeUs;
|
||||
dst.driverStartTime = src.report.driverStartTimeUs;
|
||||
dst.driverEndTime = src.report.driverEndTimeUs;
|
||||
dst.osRenderQueueStartTime = src.report.osRenderQueueStartTimeUs;
|
||||
dst.osRenderQueueEndTime = src.report.osRenderQueueEndTimeUs;
|
||||
dst.gpuRenderStartTime = src.report.gpuRenderStartTimeUs;
|
||||
dst.gpuRenderEndTime = src.report.gpuRenderEndTimeUs;
|
||||
dst.gpuActiveRenderTimeUs = src.gpuActiveTimeUs;
|
||||
dst.gpuFrameTimeUs = 0;
|
||||
|
||||
if (i) {
|
||||
dst.gpuFrameTimeUs = reports[i - 0].report.gpuRenderEndTimeUs
|
||||
- reports[i - 1].report.gpuRenderEndTimeUs;
|
||||
}
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
void D3D11ReflexDevice::RegisterLatencyTracker(
|
||||
Rc<DxvkLatencyTracker> Tracker) {
|
||||
std::lock_guard lock(m_mutex);
|
||||
|
||||
if (m_tracker)
|
||||
return;
|
||||
|
||||
if ((m_tracker = dynamic_cast<DxvkReflexLatencyTrackerNv*>(Tracker.ptr())))
|
||||
m_tracker->setLatencySleepMode(m_enableLowLatency, m_enableBoost, m_minIntervalUs);
|
||||
}
|
||||
|
||||
|
||||
void D3D11ReflexDevice::UnregisterLatencyTracker(
|
||||
Rc<DxvkLatencyTracker> Tracker) {
|
||||
std::lock_guard lock(m_mutex);
|
||||
|
||||
if (m_tracker == Tracker)
|
||||
m_tracker = nullptr;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
DXGIVkSwapChainFactory::DXGIVkSwapChainFactory(
|
||||
D3D11DXGIDevice* pContainer,
|
||||
D3D11Device* pDevice)
|
||||
|
@ -3086,6 +3351,7 @@ namespace dxvk {
|
|||
m_d3d11DeviceExt(this, &m_d3d11Device),
|
||||
m_d3d11Interop (this, &m_d3d11Device),
|
||||
m_d3d11Video (this, &m_d3d11Device),
|
||||
m_d3d11Reflex (this, &m_d3d11Device),
|
||||
m_d3d11on12 (this, &m_d3d11Device, pD3D12Device, pD3D12Queue),
|
||||
m_metaDevice (this),
|
||||
m_dxvkFactory (this, &m_d3d11Device) {
|
||||
|
@ -3158,8 +3424,14 @@ namespace dxvk {
|
|||
return S_OK;
|
||||
}
|
||||
|
||||
if (riid == __uuidof(ID3DLowLatencyDevice)) {
|
||||
*ppvObject = ref(&m_d3d11Reflex);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
if (m_d3d11on12.Is11on12Device()) {
|
||||
if (riid == __uuidof(ID3D11On12Device)) {
|
||||
if (riid == __uuidof(ID3D11On12Device)
|
||||
|| riid == __uuidof(ID3D11On12Device1_DXVK)) {
|
||||
*ppvObject = ref(&m_d3d11on12);
|
||||
return S_OK;
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#include "../dxgi/dxgi_interfaces.h"
|
||||
|
||||
#include "../dxvk/dxvk_cs.h"
|
||||
#include "../dxvk/dxvk_latency_reflex.h"
|
||||
|
||||
#include "../d3d10/d3d10_device.h"
|
||||
|
||||
|
@ -87,6 +88,11 @@ namespace dxvk {
|
|||
const D3D11_SUBRESOURCE_DATA* pInitialData,
|
||||
ID3D11Texture2D1** ppTexture2D);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE CreateTexture2DBase(
|
||||
const D3D11_TEXTURE2D_DESC1* pDesc,
|
||||
const D3D11_SUBRESOURCE_DATA* pInitialData,
|
||||
ID3D11Texture2D1** ppTexture2D);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE CreateTexture3D(
|
||||
const D3D11_TEXTURE3D_DESC* pDesc,
|
||||
const D3D11_SUBRESOURCE_DATA* pInitialData,
|
||||
|
@ -97,6 +103,11 @@ namespace dxvk {
|
|||
const D3D11_SUBRESOURCE_DATA* pInitialData,
|
||||
ID3D11Texture3D1** ppTexture3D);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE CreateTexture3DBase(
|
||||
const D3D11_TEXTURE3D_DESC1* pDesc,
|
||||
const D3D11_SUBRESOURCE_DATA* pInitialData,
|
||||
ID3D11Texture3D1** ppTexture3D);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE CreateShaderResourceView(
|
||||
ID3D11Resource* pResource,
|
||||
const D3D11_SHADER_RESOURCE_VIEW_DESC* pDesc,
|
||||
|
@ -107,6 +118,11 @@ namespace dxvk {
|
|||
const D3D11_SHADER_RESOURCE_VIEW_DESC1* pDesc,
|
||||
ID3D11ShaderResourceView1** ppSRView);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE CreateShaderResourceViewBase(
|
||||
ID3D11Resource* pResource,
|
||||
const D3D11_SHADER_RESOURCE_VIEW_DESC1* pDesc,
|
||||
ID3D11ShaderResourceView1** ppSRView);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE CreateUnorderedAccessView(
|
||||
ID3D11Resource* pResource,
|
||||
const D3D11_UNORDERED_ACCESS_VIEW_DESC* pDesc,
|
||||
|
@ -117,6 +133,11 @@ namespace dxvk {
|
|||
const D3D11_UNORDERED_ACCESS_VIEW_DESC1* pDesc,
|
||||
ID3D11UnorderedAccessView1** ppUAView);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE CreateUnorderedAccessViewBase(
|
||||
ID3D11Resource* pResource,
|
||||
const D3D11_UNORDERED_ACCESS_VIEW_DESC1* pDesc,
|
||||
ID3D11UnorderedAccessView1** ppUAView);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE CreateRenderTargetView(
|
||||
ID3D11Resource* pResource,
|
||||
const D3D11_RENDER_TARGET_VIEW_DESC* pDesc,
|
||||
|
@ -127,6 +148,11 @@ namespace dxvk {
|
|||
const D3D11_RENDER_TARGET_VIEW_DESC1* pDesc,
|
||||
ID3D11RenderTargetView1** ppRTView);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE CreateRenderTargetViewBase(
|
||||
ID3D11Resource* pResource,
|
||||
const D3D11_RENDER_TARGET_VIEW_DESC1* pDesc,
|
||||
ID3D11RenderTargetView1** ppRTView);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE CreateDepthStencilView(
|
||||
ID3D11Resource* pResource,
|
||||
const D3D11_DEPTH_STENCIL_VIEW_DESC* pDesc,
|
||||
|
@ -225,6 +251,10 @@ namespace dxvk {
|
|||
const D3D11_QUERY_DESC1* pQueryDesc,
|
||||
ID3D11Query1** ppQuery);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE CreateQueryBase(
|
||||
const D3D11_QUERY_DESC1* pQueryDesc,
|
||||
ID3D11Query1** ppQuery);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE CreatePredicate(
|
||||
const D3D11_QUERY_DESC* pPredicateDesc,
|
||||
ID3D11Predicate** ppPredicate);
|
||||
|
@ -391,8 +421,21 @@ namespace dxvk {
|
|||
return m_dxvkDevice;
|
||||
}
|
||||
|
||||
void FlushInitContext();
|
||||
void FlushInitCommands() {
|
||||
m_initializer->FlushCsChunk();
|
||||
}
|
||||
|
||||
void NotifyContextFlush() {
|
||||
m_initializer->NotifyContextFlush();
|
||||
}
|
||||
|
||||
void InitShaderIcb(
|
||||
D3D11CommonShader* pShader,
|
||||
size_t IcbSize,
|
||||
const void* pIcbData) {
|
||||
return m_initializer->InitShaderIcb(pShader, IcbSize, pIcbData);
|
||||
}
|
||||
|
||||
VkPipelineStageFlags GetEnabledShaderStages() const {
|
||||
return m_dxvkDevice->getShaderPipelineStages();
|
||||
}
|
||||
|
@ -434,6 +477,18 @@ namespace dxvk {
|
|||
|
||||
static DxvkDeviceFeatures GetDeviceFeatures(
|
||||
const Rc<DxvkAdapter>& Adapter);
|
||||
|
||||
DxvkBarrierControlFlags GetOptionsBarrierControlFlags() {
|
||||
DxvkBarrierControlFlags barrierControl = 0u;
|
||||
|
||||
if (m_d3d11Options.relaxedBarriers)
|
||||
barrierControl.set(DxvkBarrierControl::ComputeAllowWriteOnlyOverlap);
|
||||
|
||||
if (m_d3d11Options.relaxedBarriers || m_d3d11Options.relaxedGraphicsBarriers)
|
||||
barrierControl.set(DxvkBarrierControl::GraphicsAllowReadWriteOverlap);
|
||||
|
||||
return barrierControl;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
|
@ -580,7 +635,14 @@ namespace dxvk {
|
|||
|
||||
ID3D11ShaderResourceView* HandleToSrvNVX(
|
||||
uint32_t Handle);
|
||||
|
||||
|
||||
bool LockImage(
|
||||
const Rc<DxvkImage>& Image,
|
||||
VkImageUsageFlags Usage);
|
||||
|
||||
void LockBuffer(
|
||||
const Rc<DxvkBuffer>& Buffer);
|
||||
|
||||
dxvk::mutex m_mapLock;
|
||||
std::unordered_map<uint32_t, ID3D11SamplerState*> m_samplerHandleToPtr;
|
||||
std::unordered_map<uint32_t, ID3D11ShaderResourceView*> m_srvHandleToPtr;
|
||||
|
@ -697,6 +759,66 @@ namespace dxvk {
|
|||
};
|
||||
|
||||
|
||||
/**
|
||||
* \brief Nvidia Reflex interop
|
||||
*/
|
||||
class D3D11ReflexDevice : public ID3DLowLatencyDevice {
|
||||
|
||||
public:
|
||||
|
||||
D3D11ReflexDevice(
|
||||
D3D11DXGIDevice* pContainer,
|
||||
D3D11Device* pDevice);
|
||||
|
||||
~D3D11ReflexDevice();
|
||||
|
||||
ULONG STDMETHODCALLTYPE AddRef();
|
||||
|
||||
ULONG STDMETHODCALLTYPE Release();
|
||||
|
||||
HRESULT STDMETHODCALLTYPE QueryInterface(
|
||||
REFIID riid,
|
||||
void** ppvObject);
|
||||
|
||||
BOOL STDMETHODCALLTYPE SupportsLowLatency();
|
||||
|
||||
HRESULT STDMETHODCALLTYPE LatencySleep();
|
||||
|
||||
HRESULT STDMETHODCALLTYPE SetLatencySleepMode(
|
||||
BOOL LowLatencyEnable,
|
||||
BOOL LowLatencyBoost,
|
||||
UINT32 MinIntervalUs);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE SetLatencyMarker(
|
||||
UINT64 FrameId,
|
||||
UINT32 MarkerType);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE GetLatencyInfo(
|
||||
D3D_LOW_LATENCY_RESULTS* pLowLatencyResults);
|
||||
|
||||
void RegisterLatencyTracker(
|
||||
Rc<DxvkLatencyTracker> Tracker);
|
||||
|
||||
void UnregisterLatencyTracker(
|
||||
Rc<DxvkLatencyTracker> Tracker);
|
||||
|
||||
private:
|
||||
|
||||
D3D11DXGIDevice* m_container;
|
||||
D3D11Device* m_device;
|
||||
|
||||
bool m_reflexEnabled = false;
|
||||
|
||||
dxvk::mutex m_mutex;
|
||||
|
||||
bool m_enableLowLatency = false;
|
||||
bool m_enableBoost = false;
|
||||
uint64_t m_minIntervalUs = 0u;
|
||||
|
||||
Rc<DxvkReflexLatencyTrackerNv> m_tracker;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* \brief DXVK swap chain factory
|
||||
*/
|
||||
|
@ -860,6 +982,7 @@ namespace dxvk {
|
|||
D3D11DeviceExt m_d3d11DeviceExt;
|
||||
D3D11VkInterop m_d3d11Interop;
|
||||
D3D11VideoDevice m_d3d11Video;
|
||||
D3D11ReflexDevice m_d3d11Reflex;
|
||||
D3D11on12Device m_d3d11on12;
|
||||
DXGIDXVKDevice m_metaDevice;
|
||||
|
||||
|
|
|
@ -19,24 +19,28 @@ namespace dxvk {
|
|||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE GetPrivateData(
|
||||
REFGUID guid,
|
||||
UINT *pDataSize,
|
||||
void *pData) final {
|
||||
REFGUID guid,
|
||||
UINT* pDataSize,
|
||||
void* pData) final {
|
||||
return m_privateData.getData(
|
||||
guid, pDataSize, pData);
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE SetPrivateData(
|
||||
REFGUID guid,
|
||||
UINT DataSize,
|
||||
const void *pData) final {
|
||||
REFGUID guid,
|
||||
UINT DataSize,
|
||||
const void* pData) final {
|
||||
// WKPDID_D3DDebugObjectName, can't use directly due to MSVC link errors
|
||||
if (guid == GUID{0x429b8c22,0x9188,0x4b0c,0x87,0x42,0xac,0xb0,0xbf,0x85,0xc2,0x00})
|
||||
SetDebugName(static_cast<const char*>(pData));
|
||||
|
||||
return m_privateData.setData(
|
||||
guid, DataSize, pData);
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE SetPrivateDataInterface(
|
||||
REFGUID guid,
|
||||
const IUnknown *pUnknown) final {
|
||||
REFGUID guid,
|
||||
const IUnknown* pUnknown) final {
|
||||
return m_privateData.setInterface(
|
||||
guid, pUnknown);
|
||||
}
|
||||
|
@ -46,6 +50,10 @@ namespace dxvk {
|
|||
*ppDevice = ref(GetParentInterface());
|
||||
}
|
||||
|
||||
virtual void STDMETHODCALLTYPE SetDebugName(const char* pName) {
|
||||
// No-op by default
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
ID3D11Device* GetParentInterface() const {
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#include <cstring>
|
||||
|
||||
#include "d3d11_context_imm.h"
|
||||
#include "d3d11_device.h"
|
||||
#include "d3d11_initializer.h"
|
||||
|
||||
|
@ -9,9 +10,10 @@ namespace dxvk {
|
|||
D3D11Device* pParent)
|
||||
: m_parent(pParent),
|
||||
m_device(pParent->GetDXVKDevice()),
|
||||
m_context(m_device->createContext(DxvkContextType::Supplementary)) {
|
||||
m_context->beginRecording(
|
||||
m_device->createCommandList());
|
||||
m_stagingBuffer(m_device, StagingBufferSize),
|
||||
m_stagingSignal(new sync::Fence(0)),
|
||||
m_csChunk(m_parent->AllocCsChunk(DxvkCsChunkFlag::SingleUse)) {
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
@ -20,13 +22,12 @@ namespace dxvk {
|
|||
}
|
||||
|
||||
|
||||
void D3D11Initializer::Flush() {
|
||||
void D3D11Initializer::NotifyContextFlush() {
|
||||
std::lock_guard<dxvk::mutex> lock(m_mutex);
|
||||
|
||||
if (m_transferCommands != 0)
|
||||
FlushInternal();
|
||||
NotifyContextFlushLocked();
|
||||
}
|
||||
|
||||
|
||||
void D3D11Initializer::InitBuffer(
|
||||
D3D11Buffer* pBuffer,
|
||||
const D3D11_SUBRESOURCE_DATA* pInitialData) {
|
||||
|
@ -50,7 +51,7 @@ namespace dxvk {
|
|||
else
|
||||
InitDeviceLocalTexture(pTexture, pInitialData);
|
||||
|
||||
SyncKeyedMutex(pTexture->GetInterface());
|
||||
SyncSharedTexture(pTexture);
|
||||
}
|
||||
|
||||
|
||||
|
@ -61,18 +62,45 @@ namespace dxvk {
|
|||
if (counterView == nullptr)
|
||||
return;
|
||||
|
||||
auto counterSlice = counterView->slice();
|
||||
|
||||
std::lock_guard<dxvk::mutex> lock(m_mutex);
|
||||
m_transferCommands += 1;
|
||||
|
||||
const uint32_t zero = 0;
|
||||
m_context->updateBuffer(
|
||||
counterSlice.buffer(),
|
||||
counterSlice.offset(),
|
||||
sizeof(zero), &zero);
|
||||
EmitCs([
|
||||
cCounterSlice = DxvkBufferSlice(counterView)
|
||||
] (DxvkContext* ctx) {
|
||||
const uint32_t zero = 0;
|
||||
ctx->updateBuffer(
|
||||
cCounterSlice.buffer(),
|
||||
cCounterSlice.offset(),
|
||||
sizeof(zero), &zero);
|
||||
});
|
||||
}
|
||||
|
||||
FlushImplicit();
|
||||
|
||||
void D3D11Initializer::InitShaderIcb(
|
||||
D3D11CommonShader* pShader,
|
||||
size_t IcbSize,
|
||||
const void* pIcbData) {
|
||||
std::lock_guard<dxvk::mutex> lock(m_mutex);
|
||||
m_transferCommands += 1;
|
||||
|
||||
auto icbSlice = pShader->GetIcb();
|
||||
auto srcSlice = m_stagingBuffer.alloc(icbSlice.length());
|
||||
|
||||
std::memcpy(srcSlice.mapPtr(0), pIcbData, IcbSize);
|
||||
|
||||
if (IcbSize < icbSlice.length())
|
||||
std::memset(srcSlice.mapPtr(IcbSize), 0, icbSlice.length() - IcbSize);
|
||||
|
||||
EmitCs([
|
||||
cIcbSlice = std::move(icbSlice),
|
||||
cSrcSlice = std::move(srcSlice)
|
||||
] (DxvkContext* ctx) {
|
||||
ctx->copyBuffer(cIcbSlice.buffer(), cIcbSlice.offset(),
|
||||
cSrcSlice.buffer(), cSrcSlice.offset(), cIcbSlice.length());
|
||||
});
|
||||
|
||||
ThrottleAllocationLocked();
|
||||
}
|
||||
|
||||
|
||||
|
@ -81,23 +109,33 @@ namespace dxvk {
|
|||
const D3D11_SUBRESOURCE_DATA* pInitialData) {
|
||||
std::lock_guard<dxvk::mutex> lock(m_mutex);
|
||||
|
||||
DxvkBufferSlice bufferSlice = pBuffer->GetBufferSlice();
|
||||
Rc<DxvkBuffer> buffer = pBuffer->GetBuffer();
|
||||
|
||||
if (pInitialData != nullptr && pInitialData->pSysMem != nullptr) {
|
||||
m_transferMemory += bufferSlice.length();
|
||||
auto stagingSlice = m_stagingBuffer.alloc(buffer->info().size);
|
||||
std::memcpy(stagingSlice.mapPtr(0), pInitialData->pSysMem, stagingSlice.length());
|
||||
|
||||
m_transferCommands += 1;
|
||||
|
||||
m_context->uploadBuffer(
|
||||
bufferSlice.buffer(),
|
||||
pInitialData->pSysMem);
|
||||
|
||||
EmitCs([
|
||||
cBuffer = buffer,
|
||||
cStagingSlice = std::move(stagingSlice)
|
||||
] (DxvkContext* ctx) {
|
||||
ctx->uploadBuffer(cBuffer,
|
||||
cStagingSlice.buffer(),
|
||||
cStagingSlice.offset());
|
||||
});
|
||||
} else {
|
||||
m_transferCommands += 1;
|
||||
|
||||
m_context->initBuffer(
|
||||
bufferSlice.buffer());
|
||||
EmitCs([
|
||||
cBuffer = buffer
|
||||
] (DxvkContext* ctx) {
|
||||
ctx->initBuffer(cBuffer);
|
||||
});
|
||||
}
|
||||
|
||||
FlushImplicit();
|
||||
ThrottleAllocationLocked();
|
||||
}
|
||||
|
||||
|
||||
|
@ -107,18 +145,10 @@ namespace dxvk {
|
|||
// If the buffer is mapped, we can write data directly
|
||||
// to the mapped memory region instead of doing it on
|
||||
// the GPU. Same goes for zero-initialization.
|
||||
DxvkBufferSlice bufferSlice = pBuffer->GetBufferSlice();
|
||||
|
||||
if (pInitialData != nullptr && pInitialData->pSysMem != nullptr) {
|
||||
std::memcpy(
|
||||
bufferSlice.mapPtr(0),
|
||||
pInitialData->pSysMem,
|
||||
bufferSlice.length());
|
||||
} else {
|
||||
std::memset(
|
||||
bufferSlice.mapPtr(0), 0,
|
||||
bufferSlice.length());
|
||||
}
|
||||
if (pInitialData && pInitialData->pSysMem)
|
||||
std::memcpy(pBuffer->GetMapPtr(), pInitialData->pSysMem, pBuffer->Desc()->ByteWidth);
|
||||
else
|
||||
std::memset(pBuffer->GetMapPtr(), 0, pBuffer->Desc()->ByteWidth);
|
||||
}
|
||||
|
||||
|
||||
|
@ -127,87 +157,96 @@ namespace dxvk {
|
|||
const D3D11_SUBRESOURCE_DATA* pInitialData) {
|
||||
std::lock_guard<dxvk::mutex> lock(m_mutex);
|
||||
|
||||
// Image migt be null if this is a staging resource
|
||||
Rc<DxvkImage> image = pTexture->GetImage();
|
||||
|
||||
auto mapMode = pTexture->GetMapMode();
|
||||
auto desc = pTexture->Desc();
|
||||
|
||||
VkFormat packedFormat = m_parent->LookupPackedFormat(desc->Format, pTexture->GetFormatMode()).Format;
|
||||
auto formatInfo = lookupFormatInfo(packedFormat);
|
||||
|
||||
if (pInitialData != nullptr && pInitialData->pSysMem != nullptr) {
|
||||
// pInitialData is an array that stores an entry for
|
||||
// every single subresource. Since we will define all
|
||||
// subresources, this counts as initialization.
|
||||
for (uint32_t layer = 0; layer < desc->ArraySize; layer++) {
|
||||
for (uint32_t level = 0; level < desc->MipLevels; level++) {
|
||||
const uint32_t id = D3D11CalcSubresource(
|
||||
level, layer, desc->MipLevels);
|
||||
// Compute data size for all subresources and allocate staging buffer memory
|
||||
DxvkBufferSlice stagingSlice;
|
||||
|
||||
VkOffset3D mipLevelOffset = { 0, 0, 0 };
|
||||
VkExtent3D mipLevelExtent = pTexture->MipLevelExtent(level);
|
||||
if (pTexture->HasImage()) {
|
||||
VkDeviceSize dataSize = 0u;
|
||||
|
||||
for (uint32_t mip = 0; mip < image->info().mipLevels; mip++) {
|
||||
dataSize += image->info().numLayers * align(util::computeImageDataSize(
|
||||
packedFormat, image->mipLevelExtent(mip), formatInfo->aspectMask), CACHE_LINE_SIZE);
|
||||
}
|
||||
|
||||
stagingSlice = m_stagingBuffer.alloc(dataSize);
|
||||
}
|
||||
|
||||
// Copy initial data for each subresource into the staging buffer,
|
||||
// as well as the mapped per-subresource buffers if available.
|
||||
VkDeviceSize dataOffset = 0u;
|
||||
|
||||
for (uint32_t mip = 0; mip < desc->MipLevels; mip++) {
|
||||
for (uint32_t layer = 0; layer < desc->ArraySize; layer++) {
|
||||
uint32_t index = D3D11CalcSubresource(mip, layer, desc->MipLevels);
|
||||
VkExtent3D mipLevelExtent = pTexture->MipLevelExtent(mip);
|
||||
|
||||
if (pTexture->HasImage()) {
|
||||
VkDeviceSize mipSizePerLayer = util::computeImageDataSize(
|
||||
packedFormat, image->mipLevelExtent(mip), formatInfo->aspectMask);
|
||||
|
||||
if (mapMode != D3D11_COMMON_TEXTURE_MAP_MODE_STAGING) {
|
||||
m_transferCommands += 1;
|
||||
m_transferMemory += pTexture->GetSubresourceLayout(formatInfo->aspectMask, id).Size;
|
||||
|
||||
VkImageSubresourceLayers subresourceLayers;
|
||||
subresourceLayers.aspectMask = formatInfo->aspectMask;
|
||||
subresourceLayers.mipLevel = level;
|
||||
subresourceLayers.baseArrayLayer = layer;
|
||||
subresourceLayers.layerCount = 1;
|
||||
|
||||
if (formatInfo->aspectMask != (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) {
|
||||
m_context->uploadImage(
|
||||
image, subresourceLayers,
|
||||
pInitialData[id].pSysMem,
|
||||
pInitialData[id].SysMemPitch,
|
||||
pInitialData[id].SysMemSlicePitch);
|
||||
} else {
|
||||
m_context->updateDepthStencilImage(
|
||||
image, subresourceLayers,
|
||||
VkOffset2D { mipLevelOffset.x, mipLevelOffset.y },
|
||||
VkExtent2D { mipLevelExtent.width, mipLevelExtent.height },
|
||||
pInitialData[id].pSysMem,
|
||||
pInitialData[id].SysMemPitch,
|
||||
pInitialData[id].SysMemSlicePitch,
|
||||
packedFormat);
|
||||
}
|
||||
|
||||
util::packImageData(stagingSlice.mapPtr(dataOffset),
|
||||
pInitialData[index].pSysMem, pInitialData[index].SysMemPitch, pInitialData[index].SysMemSlicePitch,
|
||||
0, 0, pTexture->GetVkImageType(), mipLevelExtent, 1, formatInfo, formatInfo->aspectMask);
|
||||
|
||||
dataOffset += align(mipSizePerLayer, CACHE_LINE_SIZE);
|
||||
}
|
||||
|
||||
if (mapMode != D3D11_COMMON_TEXTURE_MAP_MODE_NONE) {
|
||||
util::packImageData(pTexture->GetMappedBuffer(id)->mapPtr(0),
|
||||
pInitialData[id].pSysMem, pInitialData[id].SysMemPitch, pInitialData[id].SysMemSlicePitch,
|
||||
if (pTexture->HasPersistentBuffers()) {
|
||||
util::packImageData(pTexture->GetMapPtr(index, 0),
|
||||
pInitialData[index].pSysMem, pInitialData[index].SysMemPitch, pInitialData[index].SysMemSlicePitch,
|
||||
0, 0, pTexture->GetVkImageType(), mipLevelExtent, 1, formatInfo, formatInfo->aspectMask);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Upload all subresources of the image in one go
|
||||
if (pTexture->HasImage()) {
|
||||
EmitCs([
|
||||
cImage = std::move(image),
|
||||
cStagingSlice = std::move(stagingSlice),
|
||||
cFormat = packedFormat
|
||||
] (DxvkContext* ctx) {
|
||||
ctx->uploadImage(cImage,
|
||||
cStagingSlice.buffer(),
|
||||
cStagingSlice.offset(),
|
||||
CACHE_LINE_SIZE, cFormat);
|
||||
});
|
||||
}
|
||||
} else {
|
||||
if (mapMode != D3D11_COMMON_TEXTURE_MAP_MODE_STAGING) {
|
||||
if (pTexture->HasImage()) {
|
||||
m_transferCommands += 1;
|
||||
|
||||
// While the Microsoft docs state that resource contents are
|
||||
// undefined if no initial data is provided, some applications
|
||||
// expect a resource to be pre-cleared.
|
||||
VkImageSubresourceRange subresources;
|
||||
subresources.aspectMask = formatInfo->aspectMask;
|
||||
subresources.baseMipLevel = 0;
|
||||
subresources.levelCount = desc->MipLevels;
|
||||
subresources.baseArrayLayer = 0;
|
||||
subresources.layerCount = desc->ArraySize;
|
||||
|
||||
m_context->initImage(image, subresources, VK_IMAGE_LAYOUT_UNDEFINED);
|
||||
EmitCs([
|
||||
cImage = std::move(image)
|
||||
] (DxvkContext* ctx) {
|
||||
ctx->initImage(cImage,
|
||||
cImage->getAvailableSubresources(),
|
||||
VK_IMAGE_LAYOUT_UNDEFINED);
|
||||
});
|
||||
}
|
||||
|
||||
if (mapMode != D3D11_COMMON_TEXTURE_MAP_MODE_NONE) {
|
||||
if (pTexture->HasPersistentBuffers()) {
|
||||
for (uint32_t i = 0; i < pTexture->CountSubresources(); i++) {
|
||||
auto buffer = pTexture->GetMappedBuffer(i);
|
||||
std::memset(buffer->mapPtr(0), 0, buffer->info().size);
|
||||
auto layout = pTexture->GetSubresourceLayout(formatInfo->aspectMask, i);
|
||||
std::memset(pTexture->GetMapPtr(i, layout.Offset), 0, layout.Size);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
FlushImplicit();
|
||||
ThrottleAllocationLocked();
|
||||
}
|
||||
|
||||
|
||||
|
@ -215,38 +254,47 @@ namespace dxvk {
|
|||
D3D11CommonTexture* pTexture,
|
||||
const D3D11_SUBRESOURCE_DATA* pInitialData) {
|
||||
Rc<DxvkImage> image = pTexture->GetImage();
|
||||
auto formatInfo = image->formatInfo();
|
||||
|
||||
for (uint32_t layer = 0; layer < pTexture->Desc()->ArraySize; layer++) {
|
||||
for (uint32_t level = 0; level < pTexture->Desc()->MipLevels; level++) {
|
||||
uint32_t subresourceIndex = D3D11CalcSubresource(level, layer, pTexture->Desc()->MipLevels);
|
||||
|
||||
for (uint32_t layer = 0; layer < image->info().numLayers; layer++) {
|
||||
for (uint32_t level = 0; level < image->info().mipLevels; level++) {
|
||||
VkImageSubresource subresource;
|
||||
subresource.aspectMask = image->formatInfo()->aspectMask;
|
||||
subresource.aspectMask = formatInfo->aspectMask;
|
||||
subresource.mipLevel = level;
|
||||
subresource.arrayLayer = layer;
|
||||
|
||||
VkExtent3D blockCount = util::computeBlockCount(
|
||||
image->mipLevelExtent(level),
|
||||
image->formatInfo()->blockSize);
|
||||
image->mipLevelExtent(level), formatInfo->blockSize);
|
||||
|
||||
VkSubresourceLayout layout = image->querySubresourceLayout(subresource);
|
||||
auto layout = pTexture->GetSubresourceLayout(
|
||||
subresource.aspectMask, subresourceIndex);
|
||||
|
||||
auto initialData = pInitialData
|
||||
? &pInitialData[D3D11CalcSubresource(level, layer, image->info().mipLevels)]
|
||||
: nullptr;
|
||||
if (pInitialData && pInitialData[subresourceIndex].pSysMem) {
|
||||
const auto& initialData = pInitialData[subresourceIndex];
|
||||
|
||||
for (uint32_t z = 0; z < blockCount.depth; z++) {
|
||||
for (uint32_t y = 0; y < blockCount.height; y++) {
|
||||
auto size = blockCount.width * image->formatInfo()->elementSize;
|
||||
auto dst = image->mapPtr(layout.offset + y * layout.rowPitch + z * layout.depthPitch);
|
||||
for (uint32_t z = 0; z < blockCount.depth; z++) {
|
||||
for (uint32_t y = 0; y < blockCount.height; y++) {
|
||||
auto size = blockCount.width * formatInfo->elementSize;
|
||||
|
||||
auto dst = pTexture->GetMapPtr(subresourceIndex, layout.Offset
|
||||
+ y * layout.RowPitch
|
||||
+ z * layout.DepthPitch);
|
||||
|
||||
auto src = reinterpret_cast<const char*>(initialData.pSysMem)
|
||||
+ y * initialData.SysMemPitch
|
||||
+ z * initialData.SysMemSlicePitch;
|
||||
|
||||
if (initialData) {
|
||||
auto src = reinterpret_cast<const char*>(initialData->pSysMem)
|
||||
+ y * initialData->SysMemPitch
|
||||
+ z * initialData->SysMemSlicePitch;
|
||||
std::memcpy(dst, src, size);
|
||||
} else {
|
||||
std::memset(dst, 0, size);
|
||||
|
||||
if (size < layout.RowPitch)
|
||||
std::memset(reinterpret_cast<char*>(dst) + size, 0, layout.RowPitch - size);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
void* dst = pTexture->GetMapPtr(subresourceIndex, layout.Offset);
|
||||
std::memset(dst, 0, layout.Size);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -254,46 +302,110 @@ namespace dxvk {
|
|||
// Initialize the image on the GPU
|
||||
std::lock_guard<dxvk::mutex> lock(m_mutex);
|
||||
|
||||
VkImageSubresourceRange subresources = image->getAvailableSubresources();
|
||||
|
||||
m_context->initImage(image, subresources, VK_IMAGE_LAYOUT_PREINITIALIZED);
|
||||
EmitCs([
|
||||
cImage = std::move(image)
|
||||
] (DxvkContext* ctx) {
|
||||
ctx->initImage(cImage,
|
||||
cImage->getAvailableSubresources(),
|
||||
VK_IMAGE_LAYOUT_PREINITIALIZED);
|
||||
});
|
||||
|
||||
m_transferCommands += 1;
|
||||
FlushImplicit();
|
||||
ThrottleAllocationLocked();
|
||||
}
|
||||
|
||||
|
||||
void D3D11Initializer::InitTiledTexture(
|
||||
D3D11CommonTexture* pTexture) {
|
||||
m_context->initSparseImage(pTexture->GetImage());
|
||||
std::lock_guard<dxvk::mutex> lock(m_mutex);
|
||||
|
||||
EmitCs([
|
||||
cImage = pTexture->GetImage()
|
||||
] (DxvkContext* ctx) {
|
||||
ctx->initSparseImage(cImage);
|
||||
});
|
||||
|
||||
m_transferCommands += 1;
|
||||
FlushImplicit();
|
||||
ThrottleAllocationLocked();
|
||||
}
|
||||
|
||||
|
||||
void D3D11Initializer::FlushImplicit() {
|
||||
if (m_transferCommands > MaxTransferCommands
|
||||
|| m_transferMemory > MaxTransferMemory)
|
||||
FlushInternal();
|
||||
void D3D11Initializer::ThrottleAllocationLocked() {
|
||||
DxvkStagingBufferStats stats = m_stagingBuffer.getStatistics();
|
||||
|
||||
// If the amount of memory in flight exceeds the limit, stall the
|
||||
// calling thread and wait for some memory to actually get released.
|
||||
VkDeviceSize stagingMemoryInFlight = stats.allocatedTotal - m_stagingSignal->value();
|
||||
|
||||
if (stagingMemoryInFlight > MaxMemoryInFlight) {
|
||||
ExecuteFlushLocked();
|
||||
|
||||
m_stagingSignal->wait(stats.allocatedTotal - MaxMemoryInFlight);
|
||||
} else if (m_transferCommands >= MaxCommandsPerSubmission || stats.allocatedSinceLastReset >= MaxMemoryPerSubmission) {
|
||||
// Flush pending commands if there are a lot of updates in flight
|
||||
// to keep both execution time and staging memory in check.
|
||||
ExecuteFlushLocked();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void D3D11Initializer::FlushInternal() {
|
||||
m_context->flushCommandList(nullptr);
|
||||
|
||||
m_transferCommands = 0;
|
||||
m_transferMemory = 0;
|
||||
void D3D11Initializer::ExecuteFlush() {
|
||||
std::lock_guard lock(m_mutex);
|
||||
|
||||
ExecuteFlushLocked();
|
||||
}
|
||||
|
||||
|
||||
void D3D11Initializer::SyncKeyedMutex(ID3D11Resource *pResource) {
|
||||
Com<IDXGIKeyedMutex> keyedMutex;
|
||||
if (pResource->QueryInterface(__uuidof(IDXGIKeyedMutex), reinterpret_cast<void**>(&keyedMutex)) != S_OK)
|
||||
void D3D11Initializer::ExecuteFlushLocked() {
|
||||
DxvkStagingBufferStats stats = m_stagingBuffer.getStatistics();
|
||||
|
||||
EmitCs([
|
||||
cSignal = m_stagingSignal,
|
||||
cSignalValue = stats.allocatedTotal
|
||||
] (DxvkContext* ctx) {
|
||||
ctx->signal(cSignal, cSignalValue);
|
||||
ctx->flushCommandList(nullptr, nullptr);
|
||||
});
|
||||
|
||||
FlushCsChunk();
|
||||
|
||||
NotifyContextFlushLocked();
|
||||
}
|
||||
|
||||
|
||||
void D3D11Initializer::SyncSharedTexture(D3D11CommonTexture* pResource) {
|
||||
if (!(pResource->Desc()->MiscFlags & (D3D11_RESOURCE_MISC_SHARED | D3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX | D3D11_RESOURCE_MISC_SHARED_NTHANDLE)))
|
||||
return;
|
||||
|
||||
keyedMutex->AcquireSync(0, 0);
|
||||
keyedMutex->ReleaseSync(0);
|
||||
// Ensure that initialization commands are submitted and waited on before
|
||||
// returning control to the application in order to avoid race conditions
|
||||
// in case the texture is used immediately on a secondary device.
|
||||
if (pResource->HasImage()) {
|
||||
ExecuteFlush();
|
||||
|
||||
m_device->waitForResource(*pResource->GetImage(), DxvkAccess::Write);
|
||||
}
|
||||
|
||||
// If a keyed mutex is used, initialize that to the correct state as well.
|
||||
Com<IDXGIKeyedMutex> keyedMutex;
|
||||
|
||||
if (SUCCEEDED(pResource->GetInterface()->QueryInterface(
|
||||
__uuidof(IDXGIKeyedMutex), reinterpret_cast<void**>(&keyedMutex)))) {
|
||||
keyedMutex->AcquireSync(0, 0);
|
||||
keyedMutex->ReleaseSync(0);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void D3D11Initializer::FlushCsChunkLocked() {
|
||||
m_parent->GetContext()->InjectCsChunk(DxvkCsQueue::HighPriority, std::move(m_csChunk), false);
|
||||
m_csChunk = m_parent->AllocCsChunk(DxvkCsChunkFlag::SingleUse);
|
||||
}
|
||||
|
||||
|
||||
void D3D11Initializer::NotifyContextFlushLocked() {
|
||||
m_stagingBuffer.reset();
|
||||
m_transferCommands = 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,7 +1,11 @@
|
|||
#pragma once
|
||||
|
||||
#include "../dxvk/dxvk_staging.h"
|
||||
|
||||
#include "d3d11_buffer.h"
|
||||
#include "d3d11_shader.h"
|
||||
#include "d3d11_texture.h"
|
||||
#include "d3d11_view_uav.h"
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
|
@ -16,16 +20,33 @@ namespace dxvk {
|
|||
* zero-initialization for buffers and images.
|
||||
*/
|
||||
class D3D11Initializer {
|
||||
constexpr static size_t MaxTransferMemory = 32 * 1024 * 1024;
|
||||
constexpr static size_t MaxTransferCommands = 512;
|
||||
// Use a staging buffer with a linear allocator to service small uploads
|
||||
constexpr static VkDeviceSize StagingBufferSize = 1ull << 20;
|
||||
public:
|
||||
|
||||
// Maximum number of copy and clear commands to record before flushing
|
||||
constexpr static size_t MaxCommandsPerSubmission = 512u;
|
||||
|
||||
// Maximum amount of staging memory to allocate before flushing
|
||||
constexpr static size_t MaxMemoryPerSubmission = (env::is32BitHostPlatform() ? 12u : 48u) << 20;
|
||||
|
||||
// Maximum amount of memory in flight. If there are pending uploads while
|
||||
// this limit is exceeded, further initialization will be stalled.
|
||||
constexpr static size_t MaxMemoryInFlight = 3u * MaxMemoryPerSubmission;
|
||||
|
||||
D3D11Initializer(
|
||||
D3D11Device* pParent);
|
||||
|
||||
~D3D11Initializer();
|
||||
|
||||
void Flush();
|
||||
void FlushCsChunk() {
|
||||
std::lock_guard<dxvk::mutex> lock(m_csMutex);
|
||||
|
||||
if (!m_csChunk->empty())
|
||||
FlushCsChunkLocked();
|
||||
}
|
||||
|
||||
void NotifyContextFlush();
|
||||
|
||||
void InitBuffer(
|
||||
D3D11Buffer* pBuffer,
|
||||
|
@ -38,16 +59,25 @@ namespace dxvk {
|
|||
void InitUavCounter(
|
||||
D3D11UnorderedAccessView* pUav);
|
||||
|
||||
void InitShaderIcb(
|
||||
D3D11CommonShader* pShader,
|
||||
size_t IcbSize,
|
||||
const void* pIcbData);
|
||||
|
||||
private:
|
||||
|
||||
dxvk::mutex m_mutex;
|
||||
|
||||
D3D11Device* m_parent;
|
||||
Rc<DxvkDevice> m_device;
|
||||
Rc<DxvkContext> m_context;
|
||||
|
||||
DxvkStagingBuffer m_stagingBuffer;
|
||||
Rc<sync::Fence> m_stagingSignal;
|
||||
|
||||
size_t m_transferCommands = 0;
|
||||
size_t m_transferMemory = 0;
|
||||
|
||||
dxvk::mutex m_csMutex;
|
||||
DxvkCsChunkRef m_csChunk;
|
||||
|
||||
void InitDeviceLocalBuffer(
|
||||
D3D11Buffer* pBuffer,
|
||||
|
@ -68,11 +98,30 @@ namespace dxvk {
|
|||
void InitTiledTexture(
|
||||
D3D11CommonTexture* pTexture);
|
||||
|
||||
void FlushImplicit();
|
||||
void FlushInternal();
|
||||
void ThrottleAllocationLocked();
|
||||
|
||||
void SyncKeyedMutex(ID3D11Resource *pResource);
|
||||
void ExecuteFlush();
|
||||
|
||||
void ExecuteFlushLocked();
|
||||
|
||||
void SyncSharedTexture(
|
||||
D3D11CommonTexture* pResource);
|
||||
|
||||
void FlushCsChunkLocked();
|
||||
|
||||
void NotifyContextFlushLocked();
|
||||
|
||||
template<typename Cmd>
|
||||
void EmitCs(Cmd&& command) {
|
||||
std::lock_guard<dxvk::mutex> lock(m_csMutex);
|
||||
|
||||
if (unlikely(!m_csChunk->push(command))) {
|
||||
FlushCsChunkLocked();
|
||||
|
||||
m_csChunk->push(command);
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,7 +24,9 @@ enum D3D11_VK_EXTENSION : uint32_t {
|
|||
*/
|
||||
enum D3D11_VK_BARRIER_CONTROL : uint32_t {
|
||||
D3D11_VK_BARRIER_CONTROL_IGNORE_WRITE_AFTER_WRITE = 1 << 0,
|
||||
D3D11_VK_BARRIER_CONTROL_IGNORE_GRAPHICS_UAV = 1 << 1,
|
||||
|
||||
// Removed:
|
||||
// D3D11_VK_BARRIER_CONTROL_IGNORE_GRAPHICS_UAV = 1 << 1,
|
||||
};
|
||||
|
||||
|
||||
|
@ -183,10 +185,70 @@ ID3D11VkExtContext1 : public ID3D11VkExtContext {
|
|||
};
|
||||
|
||||
|
||||
/**
|
||||
* \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
|
||||
|
|
|
@ -147,4 +147,11 @@ namespace dxvk {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
HRESULT STDMETHODCALLTYPE D3D11on12Device::GetD3D12Device(
|
||||
REFIID riid,
|
||||
void** ppvDevice) {
|
||||
return m_d3d12Queue->GetDevice(riid, ppvDevice);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -4,6 +4,21 @@
|
|||
|
||||
#include "../util/log/log.h"
|
||||
|
||||
/**
|
||||
* \brief Declaration of the ID3D11On12Device1 interface
|
||||
*
|
||||
* Various different headers that we need to be compatible with
|
||||
* can't seem to agree on the signature of GetD3D12Device, and
|
||||
* older wine/mingw headers don't support this interface at all.
|
||||
*/
|
||||
MIDL_INTERFACE("bdb64df4-ea2f-4c70-b861-aaab1258bb5d")
|
||||
ID3D11On12Device1_DXVK : public ID3D11On12Device {
|
||||
virtual HRESULT STDMETHODCALLTYPE GetD3D12Device(
|
||||
REFIID riid,
|
||||
void** ppvDevice) = 0;
|
||||
};
|
||||
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
class D3D11Device;
|
||||
|
@ -22,7 +37,7 @@ namespace dxvk {
|
|||
};
|
||||
|
||||
|
||||
class D3D11on12Device : public ID3D11On12Device {
|
||||
class D3D11on12Device : public ID3D11On12Device1_DXVK {
|
||||
|
||||
public:
|
||||
|
||||
|
@ -58,6 +73,10 @@ namespace dxvk {
|
|||
ID3D11Resource* const* ppResources,
|
||||
UINT ResourceCount);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE GetD3D12Device(
|
||||
REFIID riid,
|
||||
void** ppvDevice);
|
||||
|
||||
bool Is11on12Device() const {
|
||||
return m_d3d12Device != nullptr;
|
||||
}
|
||||
|
@ -73,3 +92,7 @@ namespace dxvk {
|
|||
};
|
||||
|
||||
}
|
||||
|
||||
#ifndef _MSC_VER
|
||||
__CRT_UUID_DECL(ID3D11On12Device1_DXVK, 0xbdb64df4,0xea2f,0x4c70,0xb8,0x61,0xaa,0xab,0x12,0x58,0xbb,0x5d);
|
||||
#endif
|
||||
|
|
|
@ -13,11 +13,11 @@ namespace dxvk {
|
|||
}
|
||||
|
||||
D3D11Options::D3D11Options(const Config& config) {
|
||||
this->dcSingleUseMode = config.getOption<bool>("d3d11.dcSingleUseMode", true);
|
||||
this->zeroInitWorkgroupMemory = config.getOption<bool>("d3d11.zeroInitWorkgroupMemory", false);
|
||||
this->forceVolatileTgsmAccess = config.getOption<bool>("d3d11.forceVolatileTgsmAccess", false);
|
||||
this->forceComputeUavBarriers = config.getOption<bool>("d3d11.forceComputeUavBarriers", false);
|
||||
this->relaxedBarriers = config.getOption<bool>("d3d11.relaxedBarriers", false);
|
||||
this->ignoreGraphicsBarriers = config.getOption<bool>("d3d11.ignoreGraphicsBarriers", false);
|
||||
this->relaxedGraphicsBarriers = config.getOption<bool>("d3d11.relaxedGraphicsBarriers", false);
|
||||
this->maxTessFactor = config.getOption<int32_t>("d3d11.maxTessFactor", 0);
|
||||
this->samplerAnisotropy = config.getOption<int32_t>("d3d11.samplerAnisotropy", -1);
|
||||
this->samplerLodBias = config.getOption<float>("d3d11.samplerLodBias", 0.0f);
|
||||
|
@ -28,25 +28,13 @@ namespace dxvk {
|
|||
this->disableMsaa = config.getOption<bool>("d3d11.disableMsaa", false);
|
||||
this->enableContextLock = config.getOption<bool>("d3d11.enableContextLock", false);
|
||||
this->deferSurfaceCreation = config.getOption<bool>("dxgi.deferSurfaceCreation", false);
|
||||
this->numBackBuffers = config.getOption<int32_t>("dxgi.numBackBuffers", 0);
|
||||
this->maxFrameLatency = config.getOption<int32_t>("dxgi.maxFrameLatency", 0);
|
||||
this->exposeDriverCommandLists = config.getOption<bool>("d3d11.exposeDriverCommandLists", true);
|
||||
this->longMad = config.getOption<bool>("d3d11.longMad", false);
|
||||
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()) {
|
||||
|
@ -73,4 +61,4 @@ namespace dxvk {
|
|||
this->shaderDumpPath = env::getEnvVar("DXVK_SHADER_DUMP_PATH");
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,118 +13,105 @@ namespace dxvk {
|
|||
struct D3D11Options {
|
||||
D3D11Options(const Config& config);
|
||||
|
||||
/// 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;
|
||||
|
||||
/// Zero-initialize workgroup memory
|
||||
///
|
||||
/// Workargound for games that don't initialize
|
||||
/// TGSM in compute shaders before reading it.
|
||||
bool zeroInitWorkgroupMemory;
|
||||
bool zeroInitWorkgroupMemory = false;
|
||||
|
||||
/// Force thread-group shared memory accesses to be volatile
|
||||
///
|
||||
/// Workaround for compute shaders that read and
|
||||
/// write from the same shared memory location
|
||||
/// without explicit synchronization.
|
||||
bool forceVolatileTgsmAccess;
|
||||
bool forceVolatileTgsmAccess = false;
|
||||
|
||||
/// Force UAV synchronization insided compute shaders
|
||||
///
|
||||
/// Workaround for compute shaders that access overlapping
|
||||
/// memory regions within a UAV without proper workgroup
|
||||
/// synchroniation. Will have a negative performance impact.
|
||||
bool forceComputeUavBarriers = false;
|
||||
|
||||
/// Use relaxed memory barriers
|
||||
///
|
||||
/// May improve performance in some games,
|
||||
/// but might also cause rendering issues.
|
||||
bool relaxedBarriers;
|
||||
bool relaxedBarriers = false;
|
||||
|
||||
/// Ignore graphics barriers
|
||||
///
|
||||
/// May improve performance in some games,
|
||||
/// but might also cause rendering issues.
|
||||
bool ignoreGraphicsBarriers;
|
||||
bool relaxedGraphicsBarriers = false;
|
||||
|
||||
/// Maximum tessellation factor.
|
||||
///
|
||||
/// Limits tessellation factors in tessellation
|
||||
/// control shaders. Values from 8 to 64 are
|
||||
/// supported, other values will be ignored.
|
||||
int32_t maxTessFactor;
|
||||
int32_t maxTessFactor = 0;
|
||||
|
||||
/// Anisotropic filter override
|
||||
///
|
||||
/// Enforces anisotropic filtering with the
|
||||
/// given anisotropy value for all samplers.
|
||||
int32_t samplerAnisotropy;
|
||||
int32_t samplerAnisotropy = -1;
|
||||
|
||||
/// Mipmap LOD bias
|
||||
///
|
||||
/// Enforces the given LOD bias for all samplers.
|
||||
float samplerLodBias;
|
||||
float samplerLodBias = 0.0f;
|
||||
|
||||
/// Clamps negative LOD bias
|
||||
bool clampNegativeLodBias;
|
||||
bool clampNegativeLodBias = false;
|
||||
|
||||
/// Declare vertex positions in shaders as invariant
|
||||
bool invariantPosition;
|
||||
bool invariantPosition = true;
|
||||
|
||||
/// Enable float control bits
|
||||
bool floatControls;
|
||||
|
||||
/// Back buffer count for the Vulkan swap chain.
|
||||
/// Overrides DXGI_SWAP_CHAIN_DESC::BufferCount.
|
||||
int32_t numBackBuffers;
|
||||
bool floatControls = true;
|
||||
|
||||
/// Override maximum frame latency if the app specifies
|
||||
/// a higher value. May help with frame timing issues.
|
||||
int32_t maxFrameLatency;
|
||||
|
||||
/// 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;
|
||||
|
||||
/// Shader dump path
|
||||
std::string shaderDumpPath;
|
||||
|
||||
/// Should we make our Mads a FFma or do it the long way with an FMul and an FAdd?
|
||||
bool longMad;
|
||||
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;
|
||||
bool reproducibleCommandStream = false;
|
||||
|
||||
/// Shader dump path
|
||||
std::string shaderDumpPath;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -103,8 +103,8 @@ namespace dxvk {
|
|||
|
||||
D3D11_VK_QUERY_STATE m_state;
|
||||
|
||||
std::array<Rc<DxvkGpuQuery>, MaxGpuQueries> m_query;
|
||||
std::array<Rc<DxvkGpuEvent>, MaxGpuEvents> m_event;
|
||||
std::array<Rc<DxvkQuery>, MaxGpuQueries> m_query;
|
||||
std::array<Rc<DxvkEvent>, MaxGpuEvents> m_event;
|
||||
|
||||
D3D10Query m_d3d10;
|
||||
|
||||
|
|
|
@ -95,7 +95,9 @@ namespace dxvk {
|
|||
D3D11CommonTexture* texture = GetCommonTexture(m_resource);
|
||||
Rc<DxvkDevice> dxvkDevice = m_device->GetDXVKDevice();
|
||||
|
||||
VkResult vr = dxvkDevice->vkd()->wine_vkAcquireKeyedMutex(dxvkDevice->handle(), texture->GetImage()->memory().memory(), Key, dwMilliseconds);
|
||||
VkResult vr = dxvkDevice->vkd()->wine_vkAcquireKeyedMutex(
|
||||
dxvkDevice->handle(), texture->GetImage()->getMemoryInfo().memory, Key, dwMilliseconds);
|
||||
|
||||
switch (vr) {
|
||||
case VK_SUCCESS: return S_OK;
|
||||
case VK_TIMEOUT: return WAIT_TIMEOUT;
|
||||
|
@ -120,12 +122,13 @@ namespace dxvk {
|
|||
Logger::warn("D3D11DXGIKeyedMutex::ReleaseSync: Called without context locking enabled.");
|
||||
|
||||
D3D10DeviceLock lock = context->LockContext();
|
||||
context->WaitForResource(texture->GetImage(), DxvkCsThread::SynchronizeAll, D3D11_MAP_READ_WRITE, 0);
|
||||
context->WaitForResource(*texture->GetImage(), DxvkCsThread::SynchronizeAll, D3D11_MAP_READ_WRITE, 0);
|
||||
}
|
||||
|
||||
return dxvkDevice->vkd()->wine_vkReleaseKeyedMutex(dxvkDevice->handle(), texture->GetImage()->memory().memory(), Key) == VK_SUCCESS
|
||||
? S_OK
|
||||
: DXGI_ERROR_INVALID_CALL;
|
||||
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(
|
||||
|
|
|
@ -9,63 +9,58 @@ namespace dxvk {
|
|||
const D3D11_SAMPLER_DESC& desc)
|
||||
: D3D11StateObject<ID3D11SamplerState>(device),
|
||||
m_desc(desc), m_d3d10(this) {
|
||||
DxvkSamplerCreateInfo info;
|
||||
|
||||
DxvkSamplerKey info = { };
|
||||
|
||||
// While D3D11_FILTER is technically an enum, its value bits
|
||||
// can be used to decode the filter properties more efficiently.
|
||||
const uint32_t filterBits = uint32_t(desc.Filter);
|
||||
info.magFilter = (filterBits & 0x04) ? VK_FILTER_LINEAR : VK_FILTER_NEAREST;
|
||||
info.minFilter = (filterBits & 0x10) ? VK_FILTER_LINEAR : VK_FILTER_NEAREST;
|
||||
|
||||
|
||||
VkFilter minFilter = (filterBits & 0x10) ? VK_FILTER_LINEAR : VK_FILTER_NEAREST;
|
||||
VkFilter magFilter = (filterBits & 0x04) ? VK_FILTER_LINEAR : VK_FILTER_NEAREST;
|
||||
|
||||
info.setFilter(minFilter, magFilter,
|
||||
(filterBits & 0x01) ? VK_SAMPLER_MIPMAP_MODE_LINEAR : VK_SAMPLER_MIPMAP_MODE_NEAREST);
|
||||
|
||||
// Enforce LOD bias specified in the device options
|
||||
float lodBias = desc.MipLODBias;
|
||||
|
||||
if (minFilter == VK_FILTER_LINEAR && magFilter == VK_FILTER_LINEAR) {
|
||||
lodBias += device->GetOptions()->samplerLodBias;
|
||||
|
||||
if (device->GetOptions()->clampNegativeLodBias)
|
||||
lodBias = std::max(lodBias, 0.0f);
|
||||
}
|
||||
|
||||
info.setLodRange(desc.MinLOD, desc.MaxLOD, lodBias);
|
||||
|
||||
// Enforce anisotropy specified in the device options
|
||||
uint32_t anisotropy = (filterBits & 0x40) ? desc.MaxAnisotropy : 0u;
|
||||
int32_t samplerAnisotropyOption = device->GetOptions()->samplerAnisotropy;
|
||||
|
||||
if (samplerAnisotropyOption >= 0 && minFilter == VK_FILTER_LINEAR)
|
||||
anisotropy = samplerAnisotropyOption;
|
||||
|
||||
info.setAniso(anisotropy);
|
||||
|
||||
// Set up the remaining properties, which are
|
||||
// stored directly in the sampler description
|
||||
info.mipmapMode = (filterBits & 0x01) ? VK_SAMPLER_MIPMAP_MODE_LINEAR : VK_SAMPLER_MIPMAP_MODE_NEAREST;
|
||||
info.mipmapLodBias = desc.MipLODBias;
|
||||
info.mipmapLodMin = desc.MinLOD;
|
||||
info.mipmapLodMax = desc.MaxLOD;
|
||||
|
||||
info.useAnisotropy = (filterBits & 0x40) ? VK_TRUE : VK_FALSE;
|
||||
info.maxAnisotropy = float(desc.MaxAnisotropy);
|
||||
|
||||
info.addressModeU = DecodeAddressMode(desc.AddressU);
|
||||
info.addressModeV = DecodeAddressMode(desc.AddressV);
|
||||
info.addressModeW = DecodeAddressMode(desc.AddressW);
|
||||
|
||||
info.compareToDepth = (filterBits & 0x180) == 0x80 ? VK_TRUE : VK_FALSE;
|
||||
info.compareOp = DecodeCompareOp(desc.ComparisonFunc);
|
||||
info.setAddressModes(
|
||||
DecodeAddressMode(desc.AddressU),
|
||||
DecodeAddressMode(desc.AddressV),
|
||||
DecodeAddressMode(desc.AddressW));
|
||||
|
||||
info.reductionMode = DecodeReductionMode(filterBits);
|
||||
info.setDepthCompare((filterBits & 0x180) == 0x80,
|
||||
DecodeCompareOp(desc.ComparisonFunc));
|
||||
|
||||
info.setReduction(DecodeReductionMode(filterBits));
|
||||
|
||||
for (uint32_t i = 0; i < 4; i++)
|
||||
info.borderColor.float32[i] = desc.BorderColor[i];
|
||||
|
||||
info.usePixelCoord = VK_FALSE; // Not supported in D3D11
|
||||
info.nonSeamless = VK_FALSE;
|
||||
|
||||
// Make sure to use a valid anisotropy value
|
||||
if (desc.MaxAnisotropy < 1) info.maxAnisotropy = 1.0f;
|
||||
if (desc.MaxAnisotropy > 16) info.maxAnisotropy = 16.0f;
|
||||
|
||||
// Enforce LOD bias specified in the device options
|
||||
if (info.minFilter == VK_FILTER_LINEAR && info.magFilter == VK_FILTER_LINEAR) {
|
||||
info.mipmapLodBias += device->GetOptions()->samplerLodBias;
|
||||
|
||||
if (device->GetOptions()->clampNegativeLodBias)
|
||||
info.mipmapLodBias = std::max(info.mipmapLodBias, 0.0f);
|
||||
}
|
||||
|
||||
// Enforce anisotropy specified in the device options
|
||||
int32_t samplerAnisotropyOption = device->GetOptions()->samplerAnisotropy;
|
||||
|
||||
if (samplerAnisotropyOption >= 0 && info.minFilter == VK_FILTER_LINEAR) {
|
||||
info.useAnisotropy = samplerAnisotropyOption > 0;
|
||||
info.maxAnisotropy = float(samplerAnisotropyOption);
|
||||
}
|
||||
|
||||
m_sampler = device->GetDXVKDevice()->createSampler(info);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
D3D11SamplerState::~D3D11SamplerState() {
|
||||
|
||||
}
|
||||
|
|
|
@ -59,25 +59,33 @@ namespace dxvk {
|
|||
}
|
||||
|
||||
// Create shader constant buffer if necessary
|
||||
const DxvkShaderCreateInfo& shaderInfo = m_shader->info();
|
||||
auto icb = module.icbInfo();
|
||||
|
||||
if (shaderInfo.uniformSize) {
|
||||
DxvkBufferCreateInfo info;
|
||||
info.size = shaderInfo.uniformSize;
|
||||
info.usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT;
|
||||
info.stages = util::pipelineStages(shaderInfo.stage);
|
||||
info.access = VK_ACCESS_UNIFORM_READ_BIT;
|
||||
|
||||
VkMemoryPropertyFlags memFlags
|
||||
= VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT
|
||||
| VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT
|
||||
| VK_MEMORY_PROPERTY_HOST_COHERENT_BIT;
|
||||
|
||||
m_buffer = pDevice->GetDXVKDevice()->createBuffer(info, memFlags);
|
||||
std::memcpy(m_buffer->mapPtr(0), shaderInfo.uniformData, shaderInfo.uniformSize);
|
||||
if (icb.size) {
|
||||
DxvkBufferCreateInfo info = { };
|
||||
info.size = align(icb.size, 256u);
|
||||
info.usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT
|
||||
| VK_BUFFER_USAGE_TRANSFER_SRC_BIT
|
||||
| VK_BUFFER_USAGE_TRANSFER_DST_BIT;
|
||||
info.stages = util::pipelineStages(m_shader->info().stage);
|
||||
info.access = VK_ACCESS_UNIFORM_READ_BIT
|
||||
| VK_ACCESS_TRANSFER_READ_BIT
|
||||
| VK_ACCESS_TRANSFER_WRITE_BIT;
|
||||
info.debugName = "Icb";
|
||||
|
||||
m_buffer = pDevice->GetDXVKDevice()->createBuffer(info, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
|
||||
|
||||
// Upload immediate constant buffer to VRAM
|
||||
pDevice->InitShaderIcb(this, icb.size, icb.data);
|
||||
}
|
||||
|
||||
pDevice->GetDXVKDevice()->registerShader(m_shader);
|
||||
|
||||
// Write back binding mask
|
||||
auto bindings = module.bindings();
|
||||
|
||||
if (bindings)
|
||||
m_bindings = *bindings;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
namespace dxvk {
|
||||
|
||||
class D3D11Device;
|
||||
|
||||
|
||||
/**
|
||||
* \brief Common shader object
|
||||
*
|
||||
|
@ -52,12 +52,18 @@ namespace dxvk {
|
|||
std::string GetName() const {
|
||||
return m_shader->debugName();
|
||||
}
|
||||
|
||||
|
||||
DxbcBindingMask GetBindingMask() const {
|
||||
return m_bindings;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
|
||||
Rc<DxvkShader> m_shader;
|
||||
Rc<DxvkBuffer> m_buffer;
|
||||
|
||||
|
||||
DxbcBindingMask m_bindings = { };
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
#include "d3d11_device.h"
|
||||
#include "d3d11_swapchain.h"
|
||||
|
||||
#include "../dxvk/dxvk_latency_builtin.h"
|
||||
|
||||
#include "../util/util_win32_compat.h"
|
||||
|
||||
namespace dxvk {
|
||||
|
@ -63,16 +65,11 @@ namespace dxvk {
|
|||
m_surfaceFactory(pSurfaceFactory),
|
||||
m_desc(*pDesc),
|
||||
m_device(pDevice->GetDXVKDevice()),
|
||||
m_context(m_device->createContext(DxvkContextType::Supplementary)),
|
||||
m_frameLatencyCap(pDevice->GetOptions()->maxFrameLatency) {
|
||||
CreateFrameLatencyEvent();
|
||||
CreatePresenter();
|
||||
CreateBackBuffer();
|
||||
CreateBackBuffers();
|
||||
CreateBlitter();
|
||||
CreateHud();
|
||||
|
||||
if (!pDevice->GetOptions()->deferSurfaceCreation)
|
||||
RecreateSwapChain();
|
||||
}
|
||||
|
||||
|
||||
|
@ -82,10 +79,10 @@ namespace dxvk {
|
|||
if (this_thread::isInModuleDetachment())
|
||||
return;
|
||||
|
||||
m_device->waitForSubmission(&m_presentStatus);
|
||||
m_device->waitForIdle();
|
||||
m_presenter->destroyResources();
|
||||
|
||||
DestroyFrameLatencyEvent();
|
||||
DestroyLatencyTracker();
|
||||
}
|
||||
|
||||
|
||||
|
@ -141,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);
|
||||
}
|
||||
|
||||
|
||||
|
@ -178,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;
|
||||
}
|
||||
|
||||
|
@ -255,33 +252,24 @@ namespace dxvk {
|
|||
UINT SyncInterval,
|
||||
UINT PresentFlags,
|
||||
const DXGI_PRESENT_PARAMETERS* pPresentParameters) {
|
||||
if (!(PresentFlags & DXGI_PRESENT_TEST))
|
||||
m_dirty |= m_presenter->setSyncInterval(SyncInterval) != VK_SUCCESS;
|
||||
|
||||
HRESULT hr = S_OK;
|
||||
|
||||
if (!m_presenter->hasSwapChain()) {
|
||||
RecreateSwapChain();
|
||||
m_dirty = false;
|
||||
}
|
||||
|
||||
if (!m_presenter->hasSwapChain())
|
||||
hr = DXGI_STATUS_OCCLUDED;
|
||||
|
||||
if (m_device->getDeviceStatus() != VK_SUCCESS)
|
||||
hr = DXGI_ERROR_DEVICE_RESET;
|
||||
|
||||
if (PresentFlags & DXGI_PRESENT_TEST)
|
||||
return hr;
|
||||
if (PresentFlags & DXGI_PRESENT_TEST) {
|
||||
if (hr != S_OK)
|
||||
return hr;
|
||||
|
||||
VkResult status = m_presenter->checkSwapChainStatus();
|
||||
return status == VK_SUCCESS ? S_OK : DXGI_STATUS_OCCLUDED;
|
||||
}
|
||||
|
||||
if (hr != S_OK) {
|
||||
SyncFrameLatency();
|
||||
return hr;
|
||||
}
|
||||
|
||||
if (std::exchange(m_dirty, false))
|
||||
RecreateSwapChain();
|
||||
|
||||
try {
|
||||
hr = PresentImage(SyncInterval);
|
||||
} catch (const DxvkError& e) {
|
||||
|
@ -294,6 +282,18 @@ namespace dxvk {
|
|||
// applications using the semaphore may deadlock. This works because
|
||||
// we do not increment the frame ID in those situations.
|
||||
SyncFrameLatency();
|
||||
|
||||
// Ignore latency stuff if presentation failed
|
||||
DxvkLatencyStats latencyStats = { };
|
||||
|
||||
if (hr == S_OK && m_latency) {
|
||||
latencyStats = m_latency->getStatistics(m_frameId);
|
||||
m_latency->sleepAndBeginFrame(m_frameId + 1, std::abs(m_targetFrameRate));
|
||||
}
|
||||
|
||||
if (m_latencyHud)
|
||||
m_latencyHud->accumulateStats(latencyStats);
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
|
@ -302,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;
|
||||
|
||||
|
@ -312,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;
|
||||
}
|
||||
|
||||
|
@ -326,10 +328,8 @@ namespace dxvk {
|
|||
HRESULT STDMETHODCALLTYPE D3D11SwapChain::SetHDRMetaData(
|
||||
const DXGI_VK_HDR_METADATA* pMetaData) {
|
||||
// For some reason this call always seems to succeed on Windows
|
||||
if (pMetaData->Type == DXGI_HDR_METADATA_TYPE_HDR10) {
|
||||
m_hdrMetadata = ConvertHDRMetadata(pMetaData->HDR10);
|
||||
m_dirtyHdrMetadata = true;
|
||||
}
|
||||
if (pMetaData->Type == DXGI_HDR_METADATA_TYPE_HDR10)
|
||||
m_presenter->setHdrMetadata(ConvertHDRMetadata(pMetaData->HDR10));
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
@ -353,140 +353,141 @@ namespace dxvk {
|
|||
m_targetFrameRate = FrameRate;
|
||||
|
||||
if (m_presenter != nullptr)
|
||||
m_presenter->setFrameRateLimit(m_targetFrameRate);
|
||||
m_presenter->setFrameRateLimit(m_targetFrameRate, GetActualFrameLatency());
|
||||
}
|
||||
|
||||
|
||||
Rc<DxvkImageView> D3D11SwapChain::GetBackBufferView() {
|
||||
Rc<DxvkImage> image = GetCommonTexture(m_backBuffers[0].ptr())->GetImage();
|
||||
|
||||
DxvkImageViewKey key;
|
||||
key.viewType = VK_IMAGE_VIEW_TYPE_2D;
|
||||
key.usage = VK_IMAGE_USAGE_SAMPLED_BIT;
|
||||
key.format = image->info().format;
|
||||
key.aspects = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
key.mipIndex = 0u;
|
||||
key.mipCount = 1u;
|
||||
key.layerIndex = 0u;
|
||||
key.layerCount = 1u;
|
||||
|
||||
return image->createView(key);
|
||||
}
|
||||
|
||||
|
||||
HRESULT D3D11SwapChain::PresentImage(UINT SyncInterval) {
|
||||
// Flush pending rendering commands before
|
||||
auto immediateContext = m_parent->GetContext();
|
||||
immediateContext->EndFrame();
|
||||
immediateContext->Flush();
|
||||
auto immediateContextLock = immediateContext->LockContext();
|
||||
|
||||
for (uint32_t i = 0; i < SyncInterval || i < 1; i++) {
|
||||
SynchronizePresent();
|
||||
immediateContext->EndFrame(m_latency);
|
||||
immediateContext->ExecuteFlush(GpuFlushType::ExplicitFlush, nullptr, true);
|
||||
|
||||
if (!m_presenter->hasSwapChain())
|
||||
return i ? S_OK : DXGI_STATUS_OCCLUDED;
|
||||
m_presenter->setSyncInterval(SyncInterval);
|
||||
|
||||
// Presentation semaphores and WSI swap chain image
|
||||
PresenterInfo info = m_presenter->info();
|
||||
PresenterSync sync;
|
||||
// Presentation semaphores and WSI swap chain image
|
||||
if (m_latency)
|
||||
m_latency->notifyCpuPresentBegin(m_frameId + 1u);
|
||||
|
||||
uint32_t imageIndex = 0;
|
||||
PresenterSync sync;
|
||||
Rc<DxvkImage> backBuffer;
|
||||
|
||||
VkResult status = m_presenter->acquireNextImage(sync, imageIndex);
|
||||
VkResult status = m_presenter->acquireNextImage(sync, backBuffer);
|
||||
|
||||
while (status != VK_SUCCESS && status != VK_SUBOPTIMAL_KHR) {
|
||||
RecreateSwapChain();
|
||||
if (status != VK_SUCCESS && m_latency)
|
||||
m_latency->discardTimings();
|
||||
|
||||
if (!m_presenter->hasSwapChain())
|
||||
return i ? S_OK : DXGI_STATUS_OCCLUDED;
|
||||
|
||||
info = m_presenter->info();
|
||||
status = m_presenter->acquireNextImage(sync, imageIndex);
|
||||
if (status < 0)
|
||||
return E_FAIL;
|
||||
|
||||
if (status == VK_NOT_READY)
|
||||
return DXGI_STATUS_OCCLUDED;
|
||||
|
||||
m_frameId += 1;
|
||||
|
||||
// Present from CS thread so that we don't
|
||||
// have to synchronize with it first.
|
||||
DxvkImageViewKey viewInfo = { };
|
||||
viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
|
||||
viewInfo.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
|
||||
viewInfo.format = backBuffer->info().format;
|
||||
viewInfo.aspects = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
viewInfo.mipIndex = 0u;
|
||||
viewInfo.mipCount = 1u;
|
||||
viewInfo.layerIndex = 0u;
|
||||
viewInfo.layerCount = 1u;
|
||||
|
||||
immediateContext->EmitCs([
|
||||
cDevice = m_device,
|
||||
cBlitter = m_blitter,
|
||||
cBackBuffer = backBuffer->createView(viewInfo),
|
||||
cSwapImage = GetBackBufferView(),
|
||||
cSync = sync,
|
||||
cPresenter = m_presenter,
|
||||
cLatency = m_latency,
|
||||
cColorSpace = m_colorSpace,
|
||||
cFrameId = m_frameId
|
||||
] (DxvkContext* ctx) {
|
||||
// Update back buffer color space as necessary
|
||||
if (cSwapImage->image()->info().colorSpace != cColorSpace) {
|
||||
DxvkImageUsageInfo usage = { };
|
||||
usage.colorSpace = cColorSpace;
|
||||
|
||||
ctx->ensureImageCompatibility(cSwapImage->image(), usage);
|
||||
}
|
||||
|
||||
if (m_hdrMetadata && m_dirtyHdrMetadata) {
|
||||
m_presenter->setHdrMetadata(*m_hdrMetadata);
|
||||
m_dirtyHdrMetadata = false;
|
||||
// Blit the D3D back buffer onto the actual Vulkan
|
||||
// swap chain and render the HUD if we have one.
|
||||
auto contextObjects = ctx->beginExternalRendering();
|
||||
|
||||
cBlitter->present(contextObjects,
|
||||
cBackBuffer, VkRect2D(),
|
||||
cSwapImage, VkRect2D());
|
||||
|
||||
// Submit current command list and present
|
||||
ctx->synchronizeWsi(cSync);
|
||||
ctx->flushCommandList(nullptr, nullptr);
|
||||
|
||||
cDevice->presentImage(cPresenter, cLatency, cFrameId, nullptr);
|
||||
});
|
||||
|
||||
if (m_backBuffers.size() > 1u)
|
||||
RotateBackBuffers(immediateContext);
|
||||
|
||||
immediateContext->FlushCsChunk();
|
||||
|
||||
if (m_latency) {
|
||||
m_latency->notifyCpuPresentEnd(m_frameId);
|
||||
|
||||
if (m_latency->needsAutoMarkers()) {
|
||||
immediateContext->EmitCs([
|
||||
cLatency = m_latency,
|
||||
cFrameId = m_frameId
|
||||
] (DxvkContext* ctx) {
|
||||
ctx->beginLatencyTracking(cLatency, cFrameId + 1u);
|
||||
});
|
||||
}
|
||||
|
||||
m_context->beginRecording(
|
||||
m_device->createCommandList());
|
||||
|
||||
m_blitter->presentImage(m_context.ptr(),
|
||||
m_imageViews.at(imageIndex), VkRect2D(),
|
||||
m_swapImageView, VkRect2D());
|
||||
|
||||
if (m_hud != nullptr)
|
||||
m_hud->render(m_context, info.format, info.imageExtent);
|
||||
|
||||
SubmitPresent(immediateContext, sync, i);
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
void D3D11SwapChain::SubmitPresent(
|
||||
D3D11ImmediateContext* pContext,
|
||||
const PresenterSync& Sync,
|
||||
uint32_t Repeat) {
|
||||
auto lock = pContext->LockContext();
|
||||
void D3D11SwapChain::RotateBackBuffers(D3D11ImmediateContext* ctx) {
|
||||
small_vector<Rc<DxvkImage>, 4> images;
|
||||
|
||||
// Bump frame ID as necessary
|
||||
if (!Repeat)
|
||||
m_frameId += 1;
|
||||
for (uint32_t i = 0; i < m_backBuffers.size(); i++)
|
||||
images.push_back(GetCommonTexture(m_backBuffers[i].ptr())->GetImage());
|
||||
|
||||
// Present from CS thread so that we don't
|
||||
// have to synchronize with it first.
|
||||
m_presentStatus.result = VK_NOT_READY;
|
||||
|
||||
pContext->EmitCs([this,
|
||||
cRepeat = Repeat,
|
||||
cSync = Sync,
|
||||
cHud = m_hud,
|
||||
cPresentMode = m_presenter->info().presentMode,
|
||||
cFrameId = m_frameId,
|
||||
cCommandList = m_context->endRecording()
|
||||
ctx->EmitCs([
|
||||
cImages = std::move(images)
|
||||
] (DxvkContext* ctx) {
|
||||
cCommandList->setWsiSemaphores(cSync);
|
||||
m_device->submitCommandList(cCommandList, nullptr);
|
||||
auto allocation = cImages[0]->storage();
|
||||
|
||||
if (cHud != nullptr && !cRepeat)
|
||||
cHud->update();
|
||||
for (size_t i = 0u; i + 1 < cImages.size(); i++)
|
||||
ctx->invalidateImage(cImages[i], cImages[i + 1]->storage());
|
||||
|
||||
uint64_t frameId = cRepeat ? 0 : cFrameId;
|
||||
|
||||
m_device->presentImage(m_presenter,
|
||||
cPresentMode, frameId, &m_presentStatus);
|
||||
ctx->invalidateImage(cImages[cImages.size() - 1u], std::move(allocation));
|
||||
});
|
||||
|
||||
pContext->FlushCsChunk();
|
||||
}
|
||||
|
||||
|
||||
void D3D11SwapChain::SynchronizePresent() {
|
||||
// Recreate swap chain if the previous present call failed
|
||||
VkResult status = m_device->waitForSubmission(&m_presentStatus);
|
||||
|
||||
if (status != VK_SUCCESS)
|
||||
RecreateSwapChain();
|
||||
}
|
||||
|
||||
|
||||
void D3D11SwapChain::RecreateSwapChain() {
|
||||
// Ensure that we can safely destroy the swap chain
|
||||
m_device->waitForSubmission(&m_presentStatus);
|
||||
m_device->waitForIdle();
|
||||
|
||||
m_presentStatus.result = VK_SUCCESS;
|
||||
m_dirtyHdrMetadata = true;
|
||||
|
||||
PresenterDesc presenterDesc;
|
||||
presenterDesc.imageExtent = { m_desc.Width, m_desc.Height };
|
||||
presenterDesc.imageCount = PickImageCount(m_desc.BufferCount + 1);
|
||||
presenterDesc.numFormats = PickFormats(m_desc.Format, presenterDesc.formats);
|
||||
presenterDesc.fullScreenExclusive = PickFullscreenMode();
|
||||
|
||||
VkResult vr = m_presenter->recreateSwapChain(presenterDesc);
|
||||
|
||||
if (vr == VK_ERROR_SURFACE_LOST_KHR) {
|
||||
vr = m_presenter->recreateSurface([this] (VkSurfaceKHR* surface) {
|
||||
return CreateSurface(surface);
|
||||
});
|
||||
|
||||
if (vr)
|
||||
throw DxvkError(str::format("D3D11SwapChain: Failed to recreate surface: ", vr));
|
||||
|
||||
vr = m_presenter->recreateSwapChain(presenterDesc);
|
||||
}
|
||||
|
||||
if (vr)
|
||||
throw DxvkError(str::format("D3D11SwapChain: Failed to recreate swap chain: ", vr));
|
||||
|
||||
CreateRenderTargetViews();
|
||||
}
|
||||
|
||||
|
||||
|
@ -499,76 +500,37 @@ namespace dxvk {
|
|||
|
||||
|
||||
void D3D11SwapChain::CreatePresenter() {
|
||||
PresenterDesc presenterDesc;
|
||||
presenterDesc.imageExtent = { m_desc.Width, m_desc.Height };
|
||||
presenterDesc.imageCount = PickImageCount(m_desc.BufferCount + 1);
|
||||
presenterDesc.numFormats = PickFormats(m_desc.Format, presenterDesc.formats);
|
||||
presenterDesc.fullScreenExclusive = PickFullscreenMode();
|
||||
PresenterDesc presenterDesc = { };
|
||||
presenterDesc.deferSurfaceCreation = m_parent->GetOptions()->deferSurfaceCreation;
|
||||
|
||||
m_presenter = new Presenter(m_device, m_frameLatencySignal, presenterDesc);
|
||||
m_presenter->setFrameRateLimit(m_targetFrameRate);
|
||||
m_presenter = new Presenter(m_device, m_frameLatencySignal, presenterDesc, [
|
||||
cAdapter = m_device->adapter(),
|
||||
cFactory = m_surfaceFactory
|
||||
] (VkSurfaceKHR* surface) {
|
||||
return cFactory->CreateSurface(
|
||||
cAdapter->vki()->instance(),
|
||||
cAdapter->handle(), surface);
|
||||
});
|
||||
|
||||
m_presenter->setSurfaceFormat(GetSurfaceFormat(m_desc.Format));
|
||||
m_presenter->setSurfaceExtent({ m_desc.Width, m_desc.Height });
|
||||
m_presenter->setFrameRateLimit(m_targetFrameRate, GetActualFrameLatency());
|
||||
|
||||
m_latency = m_device->createLatencyTracker(m_presenter);
|
||||
|
||||
Com<D3D11ReflexDevice> reflex = GetReflexDevice();
|
||||
reflex->RegisterLatencyTracker(m_latency);
|
||||
}
|
||||
|
||||
|
||||
VkResult D3D11SwapChain::CreateSurface(VkSurfaceKHR* pSurface) {
|
||||
Rc<DxvkAdapter> adapter = m_device->adapter();
|
||||
|
||||
return m_surfaceFactory->CreateSurface(
|
||||
adapter->vki()->instance(),
|
||||
adapter->handle(), pSurface);
|
||||
}
|
||||
|
||||
|
||||
void D3D11SwapChain::CreateRenderTargetViews() {
|
||||
PresenterInfo info = m_presenter->info();
|
||||
|
||||
m_imageViews.clear();
|
||||
m_imageViews.resize(info.imageCount);
|
||||
|
||||
DxvkImageCreateInfo imageInfo;
|
||||
imageInfo.type = VK_IMAGE_TYPE_2D;
|
||||
imageInfo.format = info.format.format;
|
||||
imageInfo.flags = 0;
|
||||
imageInfo.sampleCount = VK_SAMPLE_COUNT_1_BIT;
|
||||
imageInfo.extent = { info.imageExtent.width, info.imageExtent.height, 1 };
|
||||
imageInfo.numLayers = 1;
|
||||
imageInfo.mipLevels = 1;
|
||||
imageInfo.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
|
||||
imageInfo.stages = 0;
|
||||
imageInfo.access = 0;
|
||||
imageInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
|
||||
imageInfo.layout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
|
||||
imageInfo.shared = VK_TRUE;
|
||||
|
||||
DxvkImageViewCreateInfo viewInfo;
|
||||
viewInfo.type = VK_IMAGE_VIEW_TYPE_2D;
|
||||
viewInfo.format = info.format.format;
|
||||
viewInfo.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
|
||||
viewInfo.aspect = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
viewInfo.minLevel = 0;
|
||||
viewInfo.numLevels = 1;
|
||||
viewInfo.minLayer = 0;
|
||||
viewInfo.numLayers = 1;
|
||||
|
||||
for (uint32_t i = 0; i < info.imageCount; i++) {
|
||||
VkImage imageHandle = m_presenter->getImage(i).image;
|
||||
|
||||
Rc<DxvkImage> image = new DxvkImage(
|
||||
m_device.ptr(), imageInfo, imageHandle,
|
||||
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
|
||||
|
||||
m_imageViews[i] = new DxvkImageView(
|
||||
m_device->vkd(), image, viewInfo);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void D3D11SwapChain::CreateBackBuffer() {
|
||||
void D3D11SwapChain::CreateBackBuffers() {
|
||||
// Explicitly destroy current swap image before
|
||||
// creating a new one to free up resources
|
||||
m_swapImage = nullptr;
|
||||
m_swapImageView = nullptr;
|
||||
m_backBuffer = nullptr;
|
||||
m_backBuffers.clear();
|
||||
|
||||
bool sequential = m_desc.SwapEffect == DXGI_SWAP_EFFECT_SEQUENTIAL ||
|
||||
m_desc.SwapEffect == DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL;
|
||||
uint32_t backBufferCount = sequential ? m_desc.BufferCount : 1u;
|
||||
|
||||
// Create new back buffer
|
||||
D3D11_COMMON_TEXTURE_DESC desc;
|
||||
|
@ -599,57 +561,49 @@ namespace dxvk {
|
|||
|
||||
DXGI_USAGE dxgiUsage = DXGI_USAGE_BACK_BUFFER;
|
||||
|
||||
if (m_desc.SwapEffect == DXGI_SWAP_EFFECT_DISCARD
|
||||
|| m_desc.SwapEffect == DXGI_SWAP_EFFECT_FLIP_DISCARD)
|
||||
dxgiUsage |= DXGI_USAGE_DISCARD_ON_PRESENT;
|
||||
for (uint32_t i = 0; i < backBufferCount; i++) {
|
||||
if (m_desc.SwapEffect == DXGI_SWAP_EFFECT_DISCARD
|
||||
|| m_desc.SwapEffect == DXGI_SWAP_EFFECT_FLIP_DISCARD)
|
||||
dxgiUsage |= DXGI_USAGE_DISCARD_ON_PRESENT;
|
||||
|
||||
m_backBuffer = new D3D11Texture2D(m_parent, this, &desc, dxgiUsage);
|
||||
m_swapImage = GetCommonTexture(m_backBuffer.ptr())->GetImage();
|
||||
m_backBuffers.push_back(new D3D11Texture2D(
|
||||
m_parent, this, &desc, dxgiUsage));
|
||||
|
||||
// Create an image view that allows the
|
||||
// image to be bound as a shader resource.
|
||||
DxvkImageViewCreateInfo viewInfo;
|
||||
viewInfo.type = VK_IMAGE_VIEW_TYPE_2D;
|
||||
viewInfo.format = m_swapImage->info().format;
|
||||
viewInfo.usage = VK_IMAGE_USAGE_SAMPLED_BIT;
|
||||
viewInfo.aspect = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
viewInfo.minLevel = 0;
|
||||
viewInfo.numLevels = 1;
|
||||
viewInfo.minLayer = 0;
|
||||
viewInfo.numLayers = 1;
|
||||
m_swapImageView = m_device->createImageView(m_swapImage, viewInfo);
|
||||
|
||||
// Initialize the image so that we can use it. Clearing
|
||||
dxgiUsage |= DXGI_USAGE_READ_ONLY;
|
||||
}
|
||||
|
||||
small_vector<Rc<DxvkImage>, 4> images;
|
||||
|
||||
for (uint32_t i = 0; i < backBufferCount; i++)
|
||||
images.push_back(GetCommonTexture(m_backBuffers[i].ptr())->GetImage());
|
||||
|
||||
// Initialize images so that we can use them. Clearing
|
||||
// to black prevents garbled output for the first frame.
|
||||
VkImageSubresourceRange subresources;
|
||||
subresources.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
subresources.baseMipLevel = 0;
|
||||
subresources.levelCount = 1;
|
||||
subresources.baseArrayLayer = 0;
|
||||
subresources.layerCount = 1;
|
||||
m_parent->GetContext()->InjectCs(DxvkCsQueue::HighPriority, [
|
||||
cImages = std::move(images)
|
||||
] (DxvkContext* ctx) {
|
||||
for (size_t i = 0; i < cImages.size(); i++) {
|
||||
ctx->setDebugName(cImages[i], str::format("Back buffer ", i).c_str());
|
||||
|
||||
m_context->beginRecording(
|
||||
m_device->createCommandList());
|
||||
|
||||
m_context->initImage(m_swapImage,
|
||||
subresources, VK_IMAGE_LAYOUT_UNDEFINED);
|
||||
|
||||
m_device->submitCommandList(
|
||||
m_context->endRecording(),
|
||||
nullptr);
|
||||
ctx->initImage(cImages[i],
|
||||
cImages[i]->getAvailableSubresources(),
|
||||
VK_IMAGE_LAYOUT_UNDEFINED);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
void D3D11SwapChain::CreateBlitter() {
|
||||
m_blitter = new DxvkSwapchainBlitter(m_device);
|
||||
}
|
||||
Rc<hud::Hud> hud = hud::Hud::createHud(m_device);
|
||||
|
||||
if (hud) {
|
||||
hud->addItem<hud::HudClientApiItem>("api", 1, GetApiName());
|
||||
|
||||
void D3D11SwapChain::CreateHud() {
|
||||
m_hud = hud::Hud::createHud(m_device);
|
||||
if (m_latency)
|
||||
m_latencyHud = hud->addItem<hud::HudLatencyItem>("latency", 4);
|
||||
}
|
||||
|
||||
if (m_hud != nullptr)
|
||||
m_hud->addItem<hud::HudClientApiItem>("api", 1, GetApiName());
|
||||
m_blitter = new DxvkSwapchainBlitter(m_device, std::move(hud));
|
||||
}
|
||||
|
||||
|
||||
|
@ -658,6 +612,20 @@ namespace dxvk {
|
|||
}
|
||||
|
||||
|
||||
void D3D11SwapChain::DestroyLatencyTracker() {
|
||||
// Need to make sure the context stops using
|
||||
// the tracker for submissions
|
||||
m_parent->GetContext()->InjectCs(DxvkCsQueue::Ordered, [
|
||||
cLatency = m_latency
|
||||
] (DxvkContext* ctx) {
|
||||
ctx->endLatencyTracking(cLatency);
|
||||
});
|
||||
|
||||
Com<D3D11ReflexDevice> reflex = GetReflexDevice();
|
||||
reflex->UnregisterLatencyTracker(m_latency);
|
||||
}
|
||||
|
||||
|
||||
void D3D11SwapChain::SyncFrameLatency() {
|
||||
// Wait for the sync event so that we respect the maximum frame latency
|
||||
m_frameLatencySignal->wait(m_frameId - GetActualFrameLatency());
|
||||
|
@ -693,53 +661,34 @@ namespace dxvk {
|
|||
}
|
||||
|
||||
|
||||
uint32_t D3D11SwapChain::PickFormats(
|
||||
DXGI_FORMAT Format,
|
||||
VkSurfaceFormatKHR* pDstFormats) {
|
||||
uint32_t n = 0;
|
||||
|
||||
VkSurfaceFormatKHR D3D11SwapChain::GetSurfaceFormat(DXGI_FORMAT Format) {
|
||||
switch (Format) {
|
||||
default:
|
||||
Logger::warn(str::format("D3D11SwapChain: Unexpected format: ", m_desc.Format));
|
||||
[[fallthrough]];
|
||||
|
||||
[[fallthrough]];
|
||||
|
||||
case DXGI_FORMAT_R8G8B8A8_UNORM:
|
||||
case DXGI_FORMAT_B8G8R8A8_UNORM: {
|
||||
pDstFormats[n++] = { VK_FORMAT_R8G8B8A8_UNORM, m_colorspace };
|
||||
pDstFormats[n++] = { VK_FORMAT_B8G8R8A8_UNORM, m_colorspace };
|
||||
} break;
|
||||
|
||||
case DXGI_FORMAT_B8G8R8A8_UNORM:
|
||||
return { VK_FORMAT_R8G8B8A8_UNORM, m_colorSpace };
|
||||
|
||||
case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB:
|
||||
case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB: {
|
||||
pDstFormats[n++] = { VK_FORMAT_R8G8B8A8_SRGB, m_colorspace };
|
||||
pDstFormats[n++] = { VK_FORMAT_B8G8R8A8_SRGB, m_colorspace };
|
||||
} break;
|
||||
|
||||
case DXGI_FORMAT_R10G10B10A2_UNORM: {
|
||||
pDstFormats[n++] = { VK_FORMAT_A2B10G10R10_UNORM_PACK32, m_colorspace };
|
||||
pDstFormats[n++] = { VK_FORMAT_A2R10G10B10_UNORM_PACK32, m_colorspace };
|
||||
} break;
|
||||
|
||||
case DXGI_FORMAT_R16G16B16A16_FLOAT: {
|
||||
pDstFormats[n++] = { VK_FORMAT_R16G16B16A16_SFLOAT, m_colorspace };
|
||||
} break;
|
||||
case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB:
|
||||
return { VK_FORMAT_R8G8B8A8_SRGB, m_colorSpace };
|
||||
|
||||
case DXGI_FORMAT_R10G10B10A2_UNORM:
|
||||
return { VK_FORMAT_A2B10G10R10_UNORM_PACK32, m_colorSpace };
|
||||
|
||||
case DXGI_FORMAT_R16G16B16A16_FLOAT:
|
||||
return { VK_FORMAT_R16G16B16A16_SFLOAT, m_colorSpace };
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
|
||||
uint32_t D3D11SwapChain::PickImageCount(
|
||||
UINT Preferred) {
|
||||
int32_t option = m_parent->GetOptions()->numBackBuffers;
|
||||
return option > 0 ? uint32_t(option) : uint32_t(Preferred);
|
||||
}
|
||||
Com<D3D11ReflexDevice> D3D11SwapChain::GetReflexDevice() {
|
||||
Com<ID3DLowLatencyDevice> llDevice;
|
||||
m_parent->QueryInterface(__uuidof(ID3DLowLatencyDevice), reinterpret_cast<void**>(&llDevice));
|
||||
|
||||
|
||||
VkFullScreenExclusiveEXT D3D11SwapChain::PickFullscreenMode() {
|
||||
return m_desc.Flags & DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH
|
||||
? VK_FULL_SCREEN_EXCLUSIVE_ALLOWED_EXT
|
||||
: VK_FULL_SCREEN_EXCLUSIVE_DISALLOWED_EXT;
|
||||
return static_cast<D3D11ReflexDevice*>(llDevice.ptr());
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
#include "../dxvk/hud/dxvk_hud.h"
|
||||
|
||||
#include "../dxvk/dxvk_latency.h"
|
||||
#include "../dxvk/dxvk_swapchain_blitter.h"
|
||||
|
||||
#include "../util/sync/sync_signal.h"
|
||||
|
@ -104,20 +105,12 @@ namespace dxvk {
|
|||
DXGI_SWAP_CHAIN_DESC1 m_desc;
|
||||
|
||||
Rc<DxvkDevice> m_device;
|
||||
Rc<DxvkContext> m_context;
|
||||
|
||||
Rc<Presenter> m_presenter;
|
||||
|
||||
Rc<DxvkImage> m_swapImage;
|
||||
Rc<DxvkImageView> m_swapImageView;
|
||||
Rc<DxvkSwapchainBlitter> m_blitter;
|
||||
Rc<DxvkLatencyTracker> m_latency;
|
||||
|
||||
Rc<hud::Hud> m_hud;
|
||||
|
||||
Com<D3D11Texture2D, false> m_backBuffer;
|
||||
DxvkSubmitStatus m_presentStatus;
|
||||
|
||||
std::vector<Rc<DxvkImageView>> m_imageViews;
|
||||
small_vector<Com<D3D11Texture2D, false>, 4> m_backBuffers;
|
||||
|
||||
uint64_t m_frameId = DXGI_MAX_SWAP_CHAIN_BUFFERS;
|
||||
uint32_t m_frameLatency = DefaultFrameLatency;
|
||||
|
@ -125,57 +118,40 @@ namespace dxvk {
|
|||
HANDLE m_frameLatencyEvent = nullptr;
|
||||
Rc<sync::CallbackFence> m_frameLatencySignal;
|
||||
|
||||
bool m_dirty = true;
|
||||
|
||||
VkColorSpaceKHR m_colorspace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR;
|
||||
|
||||
std::optional<VkHdrMetadataEXT> m_hdrMetadata;
|
||||
bool m_dirtyHdrMetadata = true;
|
||||
VkColorSpaceKHR m_colorSpace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR;
|
||||
|
||||
double m_targetFrameRate = 0.0;
|
||||
|
||||
dxvk::mutex m_frameStatisticsLock;
|
||||
DXGI_VK_FRAME_STATISTICS m_frameStatistics = { };
|
||||
|
||||
Rc<hud::HudLatencyItem> m_latencyHud;
|
||||
|
||||
Rc<DxvkImageView> GetBackBufferView();
|
||||
|
||||
HRESULT PresentImage(UINT SyncInterval);
|
||||
|
||||
void SubmitPresent(
|
||||
D3D11ImmediateContext* pContext,
|
||||
const PresenterSync& Sync,
|
||||
uint32_t Repeat);
|
||||
|
||||
void SynchronizePresent();
|
||||
|
||||
void RecreateSwapChain();
|
||||
void RotateBackBuffers(D3D11ImmediateContext* ctx);
|
||||
|
||||
void CreateFrameLatencyEvent();
|
||||
|
||||
void CreatePresenter();
|
||||
|
||||
VkResult CreateSurface(VkSurfaceKHR* pSurface);
|
||||
|
||||
void CreateRenderTargetViews();
|
||||
|
||||
void CreateBackBuffer();
|
||||
void CreateBackBuffers();
|
||||
|
||||
void CreateBlitter();
|
||||
|
||||
void CreateHud();
|
||||
|
||||
void DestroyFrameLatencyEvent();
|
||||
|
||||
void DestroyLatencyTracker();
|
||||
|
||||
void SyncFrameLatency();
|
||||
|
||||
uint32_t GetActualFrameLatency();
|
||||
|
||||
uint32_t PickFormats(
|
||||
DXGI_FORMAT Format,
|
||||
VkSurfaceFormatKHR* pDstFormats);
|
||||
|
||||
uint32_t PickImageCount(
|
||||
UINT Preferred);
|
||||
|
||||
VkFullScreenExclusiveEXT PickFullscreenMode();
|
||||
|
||||
VkSurfaceFormatKHR GetSurfaceFormat(DXGI_FORMAT Format);
|
||||
|
||||
Com<D3D11ReflexDevice> GetReflexDevice();
|
||||
|
||||
std::string GetApiName() const;
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
#include "d3d11_device.h"
|
||||
#include "d3d11_context_imm.h"
|
||||
#include "d3d11_gdi.h"
|
||||
#include "d3d11_texture.h"
|
||||
|
||||
|
@ -168,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
|
||||
|
@ -187,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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -208,15 +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 |= EnableMetaPackUsage(imageInfo.format, m_desc.CPUAccessFlags);
|
||||
imageInfo.usage |= EnableMetaCopyUsage(imageInfo.format, imageInfo.tiling);
|
||||
|
||||
for (uint32_t i = 0; i < imageInfo.viewFormatCount; i++)
|
||||
imageInfo.usage |= EnableMetaCopyUsage(imageInfo.viewFormats[i], imageInfo.tiling);
|
||||
|
||||
// Check if we can actually create the image
|
||||
if (!CheckImageSupport(&imageInfo, imageInfo.tiling)) {
|
||||
throw DxvkError(str::format(
|
||||
|
@ -231,14 +235,7 @@ namespace dxvk {
|
|||
"\n Usage: ", std::hex, m_desc.BindFlags,
|
||||
"\n Flags: ", std::hex, m_desc.MiscFlags));
|
||||
}
|
||||
|
||||
// Create the image on a host-visible memory type
|
||||
// in case it is going to be mapped directly.
|
||||
VkMemoryPropertyFlags memoryProperties = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
|
||||
|
||||
if (m_mapMode == D3D11_COMMON_TEXTURE_MAP_MODE_DIRECT)
|
||||
memoryProperties = GetMemoryFlags();
|
||||
|
||||
|
||||
if (m_11on12.Resource != nullptr)
|
||||
vkImage = VkImage(m_11on12.VulkanHandle);
|
||||
|
||||
|
@ -247,6 +244,9 @@ namespace dxvk {
|
|||
else
|
||||
m_image = m_device->GetDXVKDevice()->importImage(imageInfo, vkImage, memoryProperties);
|
||||
|
||||
if (m_mapMode == D3D11_COMMON_TEXTURE_MAP_MODE_DIRECT)
|
||||
m_mapPtr = m_image->mapPtr(0);
|
||||
|
||||
if (imageInfo.sharing.mode == DxvkSharedHandleMode::Export)
|
||||
ExportImageInfo();
|
||||
}
|
||||
|
@ -281,73 +281,24 @@ namespace dxvk {
|
|||
}
|
||||
|
||||
|
||||
VkImageSubresource D3D11CommonTexture::GetSubresourceFromIndex(
|
||||
VkImageAspectFlags Aspect,
|
||||
UINT Subresource) const {
|
||||
VkImageSubresource result;
|
||||
result.aspectMask = Aspect;
|
||||
result.mipLevel = Subresource % m_desc.MipLevels;
|
||||
result.arrayLayer = Subresource / m_desc.MipLevels;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
D3D11_COMMON_TEXTURE_SUBRESOURCE_LAYOUT D3D11CommonTexture::GetSubresourceLayout(
|
||||
VkImageAspectFlags AspectMask,
|
||||
UINT Subresource) const {
|
||||
// Color is mapped directly and depth-stencil are interleaved
|
||||
// in packed formats, so just use the cached subresource layout
|
||||
constexpr VkImageAspectFlags PlaneAspects = VK_IMAGE_ASPECT_PLANE_0_BIT
|
||||
| VK_IMAGE_ASPECT_PLANE_1_BIT | VK_IMAGE_ASPECT_PLANE_2_BIT;
|
||||
|
||||
if ((Subresource < m_mapInfo.size()) && !(AspectMask & PlaneAspects))
|
||||
return m_mapInfo[Subresource].layout;
|
||||
|
||||
// Safe-guard against invalid subresource index
|
||||
if (Subresource >= m_desc.ArraySize * m_desc.MipLevels)
|
||||
return D3D11_COMMON_TEXTURE_SUBRESOURCE_LAYOUT();
|
||||
|
||||
// Image info is only needed for direct-mapped images
|
||||
VkImageSubresource subresource = GetSubresourceFromIndex(AspectMask, Subresource);
|
||||
D3D11_COMMON_TEXTURE_SUBRESOURCE_LAYOUT layout = { };
|
||||
|
||||
switch (m_mapMode) {
|
||||
case D3D11_COMMON_TEXTURE_MAP_MODE_DIRECT: {
|
||||
auto vkLayout = m_image->querySubresourceLayout(subresource);
|
||||
layout.Offset = vkLayout.offset;
|
||||
layout.Size = vkLayout.size;
|
||||
layout.RowPitch = vkLayout.rowPitch;
|
||||
layout.DepthPitch = vkLayout.depthPitch;
|
||||
} break;
|
||||
|
||||
case D3D11_COMMON_TEXTURE_MAP_MODE_NONE:
|
||||
case D3D11_COMMON_TEXTURE_MAP_MODE_BUFFER:
|
||||
case D3D11_COMMON_TEXTURE_MAP_MODE_STAGING: {
|
||||
auto packedFormatInfo = lookupFormatInfo(m_packedFormat);
|
||||
|
||||
VkImageAspectFlags aspects = packedFormatInfo->aspectMask;
|
||||
VkExtent3D mipExtent = MipLevelExtent(subresource.mipLevel);
|
||||
|
||||
while (aspects) {
|
||||
auto aspect = vk::getNextAspect(aspects);
|
||||
auto extent = mipExtent;
|
||||
auto elementSize = packedFormatInfo->elementSize;
|
||||
|
||||
if (packedFormatInfo->flags.test(DxvkFormatFlag::MultiPlane)) {
|
||||
auto plane = &packedFormatInfo->planes[vk::getPlaneIndex(aspect)];
|
||||
extent.width /= plane->blockSize.width;
|
||||
extent.height /= plane->blockSize.height;
|
||||
elementSize = plane->elementSize;
|
||||
}
|
||||
|
||||
auto blockCount = util::computeBlockCount(extent, packedFormatInfo->blockSize);
|
||||
|
||||
if (!layout.RowPitch) {
|
||||
layout.RowPitch = elementSize * blockCount.width;
|
||||
layout.DepthPitch = elementSize * blockCount.width * blockCount.height;
|
||||
}
|
||||
|
||||
VkDeviceSize size = elementSize * blockCount.width * blockCount.height * blockCount.depth;
|
||||
|
||||
if (aspect & AspectMask)
|
||||
layout.Size += size;
|
||||
else if (!layout.Size)
|
||||
layout.Offset += size;
|
||||
}
|
||||
} break;
|
||||
}
|
||||
|
||||
// D3D wants us to return the total subresource size in some instances
|
||||
if (m_dimension < D3D11_RESOURCE_DIMENSION_TEXTURE2D) layout.RowPitch = layout.Size;
|
||||
if (m_dimension < D3D11_RESOURCE_DIMENSION_TEXTURE3D) layout.DepthPitch = layout.Size;
|
||||
return layout;
|
||||
return DetermineSubresourceLayout(nullptr, subresource);
|
||||
}
|
||||
|
||||
|
||||
|
@ -422,8 +373,31 @@ namespace dxvk {
|
|||
return viewFormat.Format == baseFormat.Format && planeCount == 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void D3D11CommonTexture::SetDebugName(const char* pName) {
|
||||
if (m_image) {
|
||||
m_device->GetContext()->InjectCs(DxvkCsQueue::HighPriority, [
|
||||
cImage = m_image,
|
||||
cName = std::string(pName ? pName : "")
|
||||
] (DxvkContext* ctx) {
|
||||
ctx->setDebugName(cImage, cName.c_str());
|
||||
});
|
||||
}
|
||||
|
||||
if (m_mapMode == D3D11_COMMON_TEXTURE_MAP_MODE_STAGING) {
|
||||
for (uint32_t i = 0; i < m_buffers.size(); i++) {
|
||||
m_device->GetContext()->InjectCs(DxvkCsQueue::HighPriority, [
|
||||
cBuffer = m_buffers[i].buffer,
|
||||
cName = std::string(pName ? pName : "")
|
||||
] (DxvkContext* ctx) {
|
||||
ctx->setDebugName(cBuffer, cName.c_str());
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
HRESULT D3D11CommonTexture::NormalizeTextureProperties(D3D11_COMMON_TEXTURE_DESC* pDesc) {
|
||||
if (pDesc->Width == 0 || pDesc->Height == 0 || pDesc->Depth == 0 || pDesc->ArraySize == 0)
|
||||
return E_INVALIDARG;
|
||||
|
@ -569,136 +543,178 @@ namespace dxvk {
|
|||
return (support.linear & Features) == Features
|
||||
|| (support.optimal & Features) == Features;
|
||||
}
|
||||
|
||||
|
||||
VkImageUsageFlags D3D11CommonTexture::EnableMetaCopyUsage(
|
||||
VkFormat Format,
|
||||
VkImageTiling Tiling) const {
|
||||
VkFormatFeatureFlags2 requestedFeatures = 0;
|
||||
|
||||
if (Format == VK_FORMAT_D16_UNORM || Format == VK_FORMAT_D32_SFLOAT) {
|
||||
requestedFeatures |= VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_BIT
|
||||
| VK_FORMAT_FEATURE_2_DEPTH_STENCIL_ATTACHMENT_BIT;
|
||||
}
|
||||
|
||||
if (Format == VK_FORMAT_R16_UNORM || Format == VK_FORMAT_R32_SFLOAT) {
|
||||
requestedFeatures |= VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_BIT
|
||||
| VK_FORMAT_FEATURE_2_COLOR_ATTACHMENT_BIT;
|
||||
}
|
||||
|
||||
if (Format == VK_FORMAT_D32_SFLOAT_S8_UINT || Format == VK_FORMAT_D24_UNORM_S8_UINT)
|
||||
requestedFeatures |= VK_FORMAT_FEATURE_2_DEPTH_STENCIL_ATTACHMENT_BIT;
|
||||
|
||||
if (!requestedFeatures)
|
||||
return 0;
|
||||
|
||||
// Enable usage flags for all supported and requested features
|
||||
DxvkFormatFeatures support = m_device->GetDXVKDevice()->getFormatFeatures(Format);
|
||||
|
||||
requestedFeatures &= Tiling == VK_IMAGE_TILING_OPTIMAL
|
||||
? support.optimal
|
||||
: support.linear;
|
||||
|
||||
VkImageUsageFlags requestedUsage = 0;
|
||||
|
||||
if (requestedFeatures & VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_BIT)
|
||||
requestedUsage |= VK_IMAGE_USAGE_SAMPLED_BIT;
|
||||
|
||||
if (requestedFeatures & VK_FORMAT_FEATURE_2_DEPTH_STENCIL_ATTACHMENT_BIT)
|
||||
requestedUsage |= VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
|
||||
|
||||
if (requestedFeatures & VK_FORMAT_FEATURE_2_COLOR_ATTACHMENT_BIT)
|
||||
requestedUsage |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
|
||||
|
||||
return requestedUsage;
|
||||
}
|
||||
|
||||
|
||||
VkImageUsageFlags D3D11CommonTexture::EnableMetaPackUsage(
|
||||
VkFormat Format,
|
||||
UINT CpuAccess) const {
|
||||
if ((CpuAccess & D3D11_CPU_ACCESS_READ) == 0)
|
||||
return 0;
|
||||
|
||||
const auto dsMask = VK_IMAGE_ASPECT_DEPTH_BIT
|
||||
| VK_IMAGE_ASPECT_STENCIL_BIT;
|
||||
|
||||
auto formatInfo = lookupFormatInfo(Format);
|
||||
|
||||
return formatInfo->aspectMask == dsMask
|
||||
? VK_IMAGE_USAGE_SAMPLED_BIT
|
||||
: 0;
|
||||
}
|
||||
|
||||
|
||||
VkMemoryPropertyFlags D3D11CommonTexture::GetMemoryFlags() const {
|
||||
std::pair<D3D11_COMMON_TEXTURE_MAP_MODE, VkMemoryPropertyFlags> D3D11CommonTexture::DetermineMapMode(
|
||||
const DxvkImageCreateInfo* pImageInfo) const {
|
||||
// Don't map an image unless the application requests it
|
||||
if (!m_desc.CPUAccessFlags)
|
||||
return { D3D11_COMMON_TEXTURE_MAP_MODE_NONE, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT };
|
||||
|
||||
// For default images, always use a persistent staging buffer. Readback
|
||||
// may cause a GPU sync, but nobody seems to be using this feature anyway.
|
||||
if (m_desc.Usage == D3D11_USAGE_DEFAULT)
|
||||
return { D3D11_COMMON_TEXTURE_MAP_MODE_BUFFER, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT };
|
||||
|
||||
// If the resource cannot be used in the actual rendering pipeline, we
|
||||
// do not need to create an actual image and can instead implement copy
|
||||
// functions as buffer-to-image and image-to-buffer copies.
|
||||
if (m_desc.Usage == D3D11_USAGE_STAGING)
|
||||
return { D3D11_COMMON_TEXTURE_MAP_MODE_STAGING, 0u };
|
||||
|
||||
// If the packed format and image format don't match, we need to use
|
||||
// a staging buffer and perform format conversion when mapping.
|
||||
if (m_packedFormat != pImageInfo->format)
|
||||
return { D3D11_COMMON_TEXTURE_MAP_MODE_DYNAMIC, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT };
|
||||
|
||||
// Multi-plane and depth-stencil images have a special memory layout
|
||||
// in D3D11, so we can't expose those directly to the app
|
||||
auto formatInfo = lookupFormatInfo(pImageInfo->format);
|
||||
|
||||
if (formatInfo->aspectMask != VK_IMAGE_ASPECT_COLOR_BIT)
|
||||
return { D3D11_COMMON_TEXTURE_MAP_MODE_DYNAMIC, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT };
|
||||
|
||||
// If we can't use linear tiling for this image, we have to use a buffer
|
||||
if (!CheckImageSupport(pImageInfo, VK_IMAGE_TILING_LINEAR))
|
||||
return { D3D11_COMMON_TEXTURE_MAP_MODE_DYNAMIC, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT };
|
||||
|
||||
// Determine memory flags for the actual image if we use direct mapping.
|
||||
// Depending on the concrete use case, we may fall back to different
|
||||
// memory types.
|
||||
VkMemoryPropertyFlags memoryFlags = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT
|
||||
| VK_MEMORY_PROPERTY_HOST_COHERENT_BIT;
|
||||
|
||||
bool useCached = (m_device->GetOptions()->cachedDynamicResources == ~0u)
|
||||
|| (m_device->GetOptions()->cachedDynamicResources & m_desc.BindFlags);
|
||||
|| (m_device->GetOptions()->cachedDynamicResources & m_desc.BindFlags)
|
||||
|| (m_desc.CPUAccessFlags & D3D11_CPU_ACCESS_READ);
|
||||
|
||||
if (m_desc.Usage == D3D11_USAGE_STAGING || useCached)
|
||||
memoryFlags |= VK_MEMORY_PROPERTY_HOST_CACHED_BIT;
|
||||
else if (m_desc.Usage == D3D11_USAGE_DEFAULT || m_desc.BindFlags)
|
||||
else if (m_desc.BindFlags)
|
||||
memoryFlags |= VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
|
||||
|
||||
return memoryFlags;
|
||||
// If there are multiple subresources, go through a buffer because
|
||||
// we can otherwise not really discard individual subresources.
|
||||
if (m_desc.ArraySize > 1u || m_desc.MipLevels != 1u)
|
||||
return { D3D11_COMMON_TEXTURE_MAP_MODE_DYNAMIC, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT };
|
||||
|
||||
// If the image is essentially linear already, expose it directly since
|
||||
// there won't be any tangible benefit to using optimal tiling anyway.
|
||||
VkExtent3D blockCount = util::computeBlockCount(pImageInfo->extent, formatInfo->blockSize);
|
||||
|
||||
if (blockCount.height == 1u && blockCount.depth == 1u)
|
||||
return { D3D11_COMMON_TEXTURE_MAP_MODE_DIRECT, memoryFlags };
|
||||
|
||||
// If the image looks like a video, we can generally expect it to get
|
||||
// updated and read once per frame. This is one of the most common use
|
||||
// cases for a mapped image, expose it directly in order to avoid copies.
|
||||
if (blockCount.depth == 1u && blockCount.height >= 160 && formatInfo->elementSize <= 4u) {
|
||||
static const std::array<std::pair<uint32_t, uint32_t>, 3> videoApectRatios = {{
|
||||
{ 4, 3 },
|
||||
{ 16, 9 },
|
||||
{ 21, 9 },
|
||||
}};
|
||||
|
||||
bool isVideoAspectRatio = false;
|
||||
|
||||
for (const auto& a : videoApectRatios) {
|
||||
// Due to codec limitations, video dimensions are often rounded to
|
||||
// a multiple of 8. Account for this when checking the size.
|
||||
isVideoAspectRatio |= blockCount.width > (a.first * (blockCount.height - 8u)) / a.second
|
||||
&& blockCount.width < (a.first * (blockCount.height + 8u)) / a.second;
|
||||
}
|
||||
|
||||
if (isVideoAspectRatio) {
|
||||
// Keep video images in system memory to not waste precious HVV space
|
||||
return { D3D11_COMMON_TEXTURE_MAP_MODE_DIRECT, memoryFlags & ~VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT };
|
||||
}
|
||||
}
|
||||
|
||||
// If the image exceeds a certain size, map it directly because the overhead
|
||||
// of potentially copying the whole thing every frame likely outweighs any
|
||||
// benefit we might get from faster memory and tiling. This solves such an
|
||||
// issue in Warhammer III, which discards a 48 MB texture every single frame.
|
||||
constexpr VkDeviceSize MaxImageStagingBufferSize = 1ull << 20;
|
||||
|
||||
VkDeviceSize imageSize = util::flattenImageExtent(blockCount) * formatInfo->elementSize;
|
||||
|
||||
if (imageSize > MaxImageStagingBufferSize)
|
||||
return { D3D11_COMMON_TEXTURE_MAP_MODE_DIRECT, memoryFlags };
|
||||
|
||||
// For smaller images, use a staging buffer. There are some common use
|
||||
// cases where the image will only get written once, e.g. SMAA look-up
|
||||
// tables in some games, which will benefit from faster GPU access.
|
||||
return { D3D11_COMMON_TEXTURE_MAP_MODE_DYNAMIC, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT };
|
||||
}
|
||||
|
||||
|
||||
D3D11_COMMON_TEXTURE_MAP_MODE D3D11CommonTexture::DetermineMapMode(
|
||||
const DxvkImageCreateInfo* pImageInfo) const {
|
||||
// Don't map an image unless the application requests it
|
||||
if (!m_desc.CPUAccessFlags)
|
||||
return D3D11_COMMON_TEXTURE_MAP_MODE_NONE;
|
||||
|
||||
// If the resource cannot be used in the actual rendering pipeline, we
|
||||
// do not need to create an actual image and can instead implement copy
|
||||
// functions as buffer-to-image and image-to-buffer copies.
|
||||
if (!m_desc.BindFlags && m_desc.Usage != D3D11_USAGE_DEFAULT)
|
||||
return D3D11_COMMON_TEXTURE_MAP_MODE_STAGING;
|
||||
D3D11_COMMON_TEXTURE_SUBRESOURCE_LAYOUT D3D11CommonTexture::DetermineSubresourceLayout(
|
||||
const DxvkImageCreateInfo* pImageInfo,
|
||||
const VkImageSubresource& subresource) const {
|
||||
auto formatInfo = lookupFormatInfo(m_packedFormat);
|
||||
|
||||
// Depth-stencil formats in D3D11 can be mapped and follow special
|
||||
// packing rules, so we need to copy that data into a buffer first
|
||||
if (GetPackedDepthStencilFormat(m_desc.Format))
|
||||
return D3D11_COMMON_TEXTURE_MAP_MODE_BUFFER;
|
||||
if (m_mapMode == D3D11_COMMON_TEXTURE_MAP_MODE_DIRECT) {
|
||||
VkSubresourceLayout vkLayout = m_device->GetDXVKDevice()->queryImageSubresourceLayout(*pImageInfo, subresource);
|
||||
|
||||
// Multi-plane images have a special memory layout in D3D11
|
||||
if (lookupFormatInfo(pImageInfo->format)->flags.test(DxvkFormatFlag::MultiPlane))
|
||||
return D3D11_COMMON_TEXTURE_MAP_MODE_BUFFER;
|
||||
D3D11_COMMON_TEXTURE_SUBRESOURCE_LAYOUT result = { };
|
||||
result.Offset = vkLayout.offset;
|
||||
result.RowPitch = vkLayout.rowPitch;
|
||||
result.DepthPitch = vkLayout.depthPitch;
|
||||
|
||||
// If we can't use linear tiling for this image, we have to use a buffer
|
||||
if (!this->CheckImageSupport(pImageInfo, VK_IMAGE_TILING_LINEAR))
|
||||
return D3D11_COMMON_TEXTURE_MAP_MODE_BUFFER;
|
||||
// We will only ever use direct mapping for single-aspect images,
|
||||
// so ignore any sort of multi-plane shenanigans on this path
|
||||
auto mipExtent = MipLevelExtent(subresource.mipLevel);
|
||||
auto blockCount = util::computeBlockCount(mipExtent, formatInfo->blockSize);
|
||||
|
||||
// If supported and requested, create a linear image. Default images
|
||||
// can be used for resolves and other operations regardless of bind
|
||||
// flags, so we need to use a proper image for those.
|
||||
if (m_desc.TextureLayout == D3D11_TEXTURE_LAYOUT_ROW_MAJOR)
|
||||
return D3D11_COMMON_TEXTURE_MAP_MODE_DIRECT;
|
||||
// If the image dimensions support it, try to look as close to a
|
||||
// linear buffer as we can. Some games use the depth pitch as a
|
||||
// subresource size and will crash if it includes any padding.
|
||||
if (blockCount.depth == 1u) {
|
||||
if (blockCount.height == 1u) {
|
||||
result.RowPitch = formatInfo->elementSize * blockCount.width;
|
||||
result.DepthPitch = result.RowPitch;
|
||||
} else {
|
||||
result.DepthPitch = vkLayout.rowPitch * blockCount.height;
|
||||
}
|
||||
}
|
||||
|
||||
// For default images, prefer direct mapping if the image is CPU readable
|
||||
// since mapping for reads would have to stall otherwise. If the image is
|
||||
// only writable, prefer a write-through buffer.
|
||||
if (m_desc.Usage == D3D11_USAGE_DEFAULT) {
|
||||
return (m_desc.CPUAccessFlags & D3D11_CPU_ACCESS_READ)
|
||||
? D3D11_COMMON_TEXTURE_MAP_MODE_DIRECT
|
||||
: D3D11_COMMON_TEXTURE_MAP_MODE_BUFFER;
|
||||
result.Size = blockCount.depth * result.DepthPitch;
|
||||
return result;
|
||||
} else {
|
||||
D3D11_COMMON_TEXTURE_SUBRESOURCE_LAYOUT result = { };
|
||||
|
||||
VkImageAspectFlags aspects = formatInfo->aspectMask;
|
||||
VkExtent3D mipExtent = MipLevelExtent(subresource.mipLevel);
|
||||
|
||||
while (aspects) {
|
||||
auto aspect = vk::getNextAspect(aspects);
|
||||
auto extent = mipExtent;
|
||||
auto elementSize = formatInfo->elementSize;
|
||||
|
||||
if (formatInfo->flags.test(DxvkFormatFlag::MultiPlane)) {
|
||||
auto plane = &formatInfo->planes[vk::getPlaneIndex(aspect)];
|
||||
extent.width /= plane->blockSize.width;
|
||||
extent.height /= plane->blockSize.height;
|
||||
elementSize = plane->elementSize;
|
||||
}
|
||||
|
||||
auto blockCount = util::computeBlockCount(extent, formatInfo->blockSize);
|
||||
|
||||
if (!result.RowPitch) {
|
||||
result.RowPitch = elementSize * blockCount.width;
|
||||
result.DepthPitch = elementSize * blockCount.width * blockCount.height;
|
||||
}
|
||||
|
||||
VkDeviceSize size = elementSize * blockCount.width * blockCount.height * blockCount.depth;
|
||||
|
||||
if (aspect & subresource.aspectMask)
|
||||
result.Size += size;
|
||||
else if (!result.Size)
|
||||
result.Offset += size;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// The overhead of frequently uploading large dynamic images may outweigh
|
||||
// the benefit of linear tiling, so use a linear image in those cases.
|
||||
VkDeviceSize threshold = m_device->GetOptions()->maxDynamicImageBufferSize;
|
||||
VkDeviceSize size = util::computeImageDataSize(pImageInfo->format, pImageInfo->extent);
|
||||
|
||||
if (size > threshold)
|
||||
return D3D11_COMMON_TEXTURE_MAP_MODE_DIRECT;
|
||||
|
||||
// Dynamic images that can be sampled by a shader should generally go
|
||||
// through a buffer to allow optimal tiling and to avoid running into
|
||||
// bugs where games ignore the pitch when mapping the image.
|
||||
return D3D11_COMMON_TEXTURE_MAP_MODE_BUFFER;
|
||||
}
|
||||
|
||||
|
||||
|
@ -744,23 +760,25 @@ namespace dxvk {
|
|||
}
|
||||
|
||||
|
||||
D3D11CommonTexture::MappedBuffer D3D11CommonTexture::CreateMappedBuffer(UINT MipLevel) const {
|
||||
void D3D11CommonTexture::CreateMappedBuffer(UINT Subresource) {
|
||||
const DxvkFormatInfo* formatInfo = lookupFormatInfo(
|
||||
m_device->LookupPackedFormat(m_desc.Format, GetFormatMode()).Format);
|
||||
|
||||
|
||||
DxvkBufferCreateInfo info;
|
||||
info.size = GetSubresourceLayout(formatInfo->aspectMask, MipLevel).Size;
|
||||
info.size = GetSubresourceLayout(formatInfo->aspectMask, Subresource).Size;
|
||||
info.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT
|
||||
| VK_BUFFER_USAGE_TRANSFER_DST_BIT
|
||||
| VK_BUFFER_USAGE_STORAGE_BUFFER_BIT
|
||||
| VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT
|
||||
| VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT;
|
||||
info.stages = VK_PIPELINE_STAGE_TRANSFER_BIT
|
||||
| VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
|
||||
| VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT
|
||||
| VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
|
||||
info.access = VK_ACCESS_TRANSFER_READ_BIT
|
||||
| VK_ACCESS_TRANSFER_WRITE_BIT
|
||||
| VK_ACCESS_SHADER_READ_BIT
|
||||
| VK_ACCESS_SHADER_WRITE_BIT;
|
||||
info.debugName = "Image buffer";
|
||||
|
||||
// We may read mapped buffers even if it is
|
||||
// marked as CPU write-only on the D3D11 side.
|
||||
|
@ -779,11 +797,18 @@ namespace dxvk {
|
|||
|
||||
if (m_desc.Usage == D3D11_USAGE_STAGING || useCached)
|
||||
memType |= VK_MEMORY_PROPERTY_HOST_CACHED_BIT;
|
||||
|
||||
MappedBuffer result;
|
||||
result.buffer = m_device->GetDXVKDevice()->createBuffer(info, memType);
|
||||
result.slice = result.buffer->getSliceHandle();
|
||||
return result;
|
||||
|
||||
auto& entry = m_buffers[Subresource];
|
||||
entry.buffer = m_device->GetDXVKDevice()->createBuffer(info, memType);
|
||||
entry.slice = entry.buffer->storage();
|
||||
}
|
||||
|
||||
|
||||
void D3D11CommonTexture::FreeMappedBuffer(
|
||||
UINT Subresource) {
|
||||
auto& entry = m_buffers[Subresource];
|
||||
entry.buffer = nullptr;
|
||||
entry.slice = nullptr;
|
||||
}
|
||||
|
||||
|
||||
|
@ -799,33 +824,34 @@ namespace dxvk {
|
|||
|
||||
VkImageLayout D3D11CommonTexture::OptimizeLayout(VkImageUsageFlags Usage) {
|
||||
const VkImageUsageFlags usageFlags = Usage;
|
||||
|
||||
|
||||
// Filter out unnecessary flags. Transfer operations
|
||||
// are handled by the backend in a transparent manner.
|
||||
Usage &= ~(VK_IMAGE_USAGE_TRANSFER_DST_BIT
|
||||
| VK_IMAGE_USAGE_TRANSFER_SRC_BIT);
|
||||
|
||||
|
||||
// Storage images require GENERAL.
|
||||
if (Usage & VK_IMAGE_USAGE_STORAGE_BIT)
|
||||
return VK_IMAGE_LAYOUT_GENERAL;
|
||||
|
||||
// Also use GENERAL if the image cannot be rendered to. This
|
||||
// should not harm any hardware in practice and may avoid some
|
||||
// redundant layout transitions for regular textures.
|
||||
if (Usage == VK_IMAGE_USAGE_SAMPLED_BIT)
|
||||
return VK_IMAGE_LAYOUT_GENERAL;
|
||||
|
||||
// If the image is used only as an attachment, we never
|
||||
// have to transform the image back to a different layout
|
||||
// have to transform the image back to a different layout.
|
||||
if (Usage == VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT)
|
||||
return VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
|
||||
|
||||
if (Usage == VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT)
|
||||
return VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
|
||||
|
||||
Usage &= ~(VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT
|
||||
| VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT);
|
||||
|
||||
// If the image is used for reading but not as a storage
|
||||
// image, we can optimize the image for texture access
|
||||
if (Usage == VK_IMAGE_USAGE_SAMPLED_BIT) {
|
||||
return usageFlags & VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT
|
||||
? VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL
|
||||
: VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
|
||||
}
|
||||
|
||||
// Otherwise, we have to stick with the default layout
|
||||
return VK_IMAGE_LAYOUT_GENERAL;
|
||||
|
||||
// Otherwise, pick a layout that can be used for reading.
|
||||
return usageFlags & VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT
|
||||
? VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL
|
||||
: VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
|
||||
}
|
||||
|
||||
|
||||
|
@ -1192,8 +1218,13 @@ namespace dxvk {
|
|||
pDesc->CPUAccessFlags = m_texture.Desc()->CPUAccessFlags;
|
||||
pDesc->MiscFlags = m_texture.Desc()->MiscFlags;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void STDMETHODCALLTYPE D3D11Texture1D::SetDebugName(const char* pName) {
|
||||
m_texture.SetDebugName(pName);
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////
|
||||
// D 3 D 1 1 T E X T U R E 2 D
|
||||
D3D11Texture2D::D3D11Texture2D(
|
||||
|
@ -1375,6 +1406,11 @@ namespace dxvk {
|
|||
}
|
||||
|
||||
|
||||
void STDMETHODCALLTYPE D3D11Texture2D::SetDebugName(const char* pName) {
|
||||
m_texture.SetDebugName(pName);
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////
|
||||
// D 3 D 1 1 T E X T U R E 3 D
|
||||
D3D11Texture3D::D3D11Texture3D(
|
||||
|
@ -1486,6 +1522,11 @@ namespace dxvk {
|
|||
}
|
||||
|
||||
|
||||
void STDMETHODCALLTYPE D3D11Texture3D::SetDebugName(const char* pName) {
|
||||
m_texture.SetDebugName(pName);
|
||||
}
|
||||
|
||||
|
||||
D3D11CommonTexture* GetCommonTexture(ID3D11Resource* pResource) {
|
||||
D3D11_RESOURCE_DIMENSION dimension = D3D11_RESOURCE_DIMENSION_UNKNOWN;
|
||||
pResource->GetType(&dimension);
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
#include "../util/util_small_vector.h"
|
||||
|
||||
#include "../dxvk/dxvk_cs.h"
|
||||
#include "../dxvk/dxvk_device.h"
|
||||
|
||||
|
@ -24,6 +26,7 @@ namespace dxvk {
|
|||
enum D3D11_COMMON_TEXTURE_MAP_MODE {
|
||||
D3D11_COMMON_TEXTURE_MAP_MODE_NONE, ///< Not mapped
|
||||
D3D11_COMMON_TEXTURE_MAP_MODE_BUFFER, ///< Mapped through buffer
|
||||
D3D11_COMMON_TEXTURE_MAP_MODE_DYNAMIC, ///< Mapped through temporary buffer
|
||||
D3D11_COMMON_TEXTURE_MAP_MODE_DIRECT, ///< Directly mapped to host mem
|
||||
D3D11_COMMON_TEXTURE_MAP_MODE_STAGING, ///< Buffer only, no image
|
||||
};
|
||||
|
@ -81,7 +84,9 @@ namespace dxvk {
|
|||
class D3D11CommonTexture {
|
||||
|
||||
public:
|
||||
|
||||
|
||||
static constexpr uint32_t UnmappedSubresource = ~0u;
|
||||
|
||||
D3D11CommonTexture(
|
||||
ID3D11Resource* pInterface,
|
||||
D3D11Device* pDevice,
|
||||
|
@ -170,29 +175,73 @@ namespace dxvk {
|
|||
return m_mapMode;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Checks whether this texture has an image
|
||||
*
|
||||
* Staging textures will not use an image, only mapped buffers.
|
||||
* \returns \c true for non-staging textures.
|
||||
*/
|
||||
bool HasImage() const {
|
||||
return m_mapMode != D3D11_COMMON_TEXTURE_MAP_MODE_STAGING;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Checks whether this texture has persistent buffers
|
||||
* \returns \c true for buffer-mapped textures or staging textures.
|
||||
*/
|
||||
bool HasPersistentBuffers() const {
|
||||
return m_mapMode == D3D11_COMMON_TEXTURE_MAP_MODE_BUFFER
|
||||
|| m_mapMode == D3D11_COMMON_TEXTURE_MAP_MODE_STAGING;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Map type of a given subresource
|
||||
*
|
||||
* \param [in] Subresource Subresource index
|
||||
* \returns Current map mode of that subresource
|
||||
*/
|
||||
D3D11_MAP GetMapType(UINT Subresource) const {
|
||||
uint32_t GetMapType(UINT Subresource) const {
|
||||
return Subresource < m_mapInfo.size()
|
||||
? D3D11_MAP(m_mapInfo[Subresource].mapType)
|
||||
: D3D11_MAP(~0u);
|
||||
? m_mapInfo[Subresource].mapType
|
||||
: UnmappedSubresource;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Sets map type for a given subresource
|
||||
*
|
||||
*
|
||||
* Also ensures taht a staging buffer is created
|
||||
* in case of dynamic mapping.
|
||||
* \param [in] Subresource The subresource
|
||||
* \param [in] MapType The map type
|
||||
*/
|
||||
void SetMapType(UINT Subresource, D3D11_MAP MapType) {
|
||||
if (Subresource < m_mapInfo.size())
|
||||
m_mapInfo[Subresource].mapType = MapType;
|
||||
void NotifyMap(UINT Subresource, D3D11_MAP MapType) {
|
||||
if (likely(Subresource < m_mapInfo.size())) {
|
||||
m_mapInfo[Subresource].mapType = uint32_t(MapType);
|
||||
|
||||
if (m_mapMode == D3D11_COMMON_TEXTURE_MAP_MODE_DYNAMIC)
|
||||
CreateMappedBuffer(Subresource);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* \brief Resets map info for a given subresource
|
||||
*
|
||||
* For dynamic mapping, this will also free the
|
||||
* staging buffer.
|
||||
* \param [in] Subresource The subresource
|
||||
*/
|
||||
void NotifyUnmap(UINT Subresource) {
|
||||
if (likely(Subresource < m_mapInfo.size())) {
|
||||
m_mapInfo[Subresource].mapType = UnmappedSubresource;
|
||||
|
||||
if (m_mapMode == D3D11_COMMON_TEXTURE_MAP_MODE_DYNAMIC)
|
||||
FreeMappedBuffer(Subresource);
|
||||
|
||||
if (Subresource < m_buffers.size())
|
||||
m_buffers[Subresource].dirtyRegions.clear();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief The DXVK image
|
||||
* \returns The DXVK image
|
||||
|
@ -219,13 +268,13 @@ namespace dxvk {
|
|||
* \param [in] Subresource Subresource to discard
|
||||
* \returns Newly allocated mapped buffer slice
|
||||
*/
|
||||
DxvkBufferSliceHandle DiscardSlice(UINT Subresource) {
|
||||
Rc<DxvkResourceAllocation> DiscardSlice(UINT Subresource) {
|
||||
if (Subresource < m_buffers.size()) {
|
||||
DxvkBufferSliceHandle slice = m_buffers[Subresource].buffer->allocSlice();
|
||||
Rc<DxvkResourceAllocation> slice = m_buffers[Subresource].buffer->allocateStorage();
|
||||
m_buffers[Subresource].slice = slice;
|
||||
return slice;
|
||||
} else {
|
||||
return DxvkBufferSliceHandle();
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -235,10 +284,10 @@ namespace dxvk {
|
|||
* \param [in] Subresource Subresource index to query
|
||||
* \returns Currently mapped buffer slice
|
||||
*/
|
||||
DxvkBufferSliceHandle GetMappedSlice(UINT Subresource) const {
|
||||
Rc<DxvkResourceAllocation> GetMappedSlice(UINT Subresource) const {
|
||||
return Subresource < m_buffers.size()
|
||||
? m_buffers[Subresource].slice
|
||||
: DxvkBufferSliceHandle();
|
||||
: nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -261,17 +310,7 @@ namespace dxvk {
|
|||
* \returns \c true if tracking is supported for this resource
|
||||
*/
|
||||
bool HasSequenceNumber() const {
|
||||
if (m_mapMode == D3D11_COMMON_TEXTURE_MAP_MODE_NONE)
|
||||
return false;
|
||||
|
||||
// For buffer-mapped images we only need to track copies to
|
||||
// and from that buffer, so we can safely ignore bind flags
|
||||
if (m_mapMode == D3D11_COMMON_TEXTURE_MAP_MODE_BUFFER)
|
||||
return m_desc.Usage != D3D11_USAGE_DEFAULT;
|
||||
|
||||
// Otherwise we can only do accurate tracking if the
|
||||
// image cannot be used in the rendering pipeline.
|
||||
return m_desc.BindFlags == 0;
|
||||
return m_mapMode == D3D11_COMMON_TEXTURE_MAP_MODE_STAGING;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -303,6 +342,52 @@ namespace dxvk {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Allocates new backing storage
|
||||
* \returns New backing storage for the image
|
||||
*/
|
||||
Rc<DxvkResourceAllocation> AllocStorage() {
|
||||
return m_image->allocateStorage();
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Discards backing storage
|
||||
*
|
||||
* Also updates the mapped pointer if the image is mapped.
|
||||
* \returns New backing storage for the image
|
||||
*/
|
||||
Rc<DxvkResourceAllocation> DiscardStorage() {
|
||||
auto storage = m_image->allocateStorage();
|
||||
m_mapPtr = storage->mapPtr();
|
||||
return storage;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Queries map pointer of the raw image
|
||||
*
|
||||
* If the image is mapped directly, the returned pointer will
|
||||
* point directly to the image, otherwise it will point to a
|
||||
* buffer that contains image data.
|
||||
* \param [in] Subresource Subresource index
|
||||
* \param [in] Offset Offset derived from the subresource layout
|
||||
*/
|
||||
void* GetMapPtr(uint32_t Subresource, size_t Offset) const {
|
||||
switch (m_mapMode) {
|
||||
case D3D11_COMMON_TEXTURE_MAP_MODE_DIRECT:
|
||||
return reinterpret_cast<char*>(m_mapPtr) + Offset;
|
||||
|
||||
case D3D11_COMMON_TEXTURE_MAP_MODE_BUFFER:
|
||||
case D3D11_COMMON_TEXTURE_MAP_MODE_DYNAMIC:
|
||||
case D3D11_COMMON_TEXTURE_MAP_MODE_STAGING:
|
||||
return reinterpret_cast<char*>(m_buffers[Subresource].slice->mapPtr()) + Offset;
|
||||
|
||||
case D3D11_COMMON_TEXTURE_MAP_MODE_NONE:
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Adds a dirty region
|
||||
*
|
||||
|
@ -320,17 +405,6 @@ namespace dxvk {
|
|||
m_buffers[Subresource].dirtyRegions.push_back(region);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Clears dirty regions
|
||||
*
|
||||
* Removes all dirty regions from the given subresource.
|
||||
* \param [in] Subresource Subresource index
|
||||
*/
|
||||
void ClearDirtyRegions(UINT Subresource) {
|
||||
if (Subresource < m_buffers.size())
|
||||
m_buffers[Subresource].dirtyRegions.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Counts dirty regions
|
||||
*
|
||||
|
@ -390,7 +464,13 @@ namespace dxvk {
|
|||
*/
|
||||
VkImageSubresource GetSubresourceFromIndex(
|
||||
VkImageAspectFlags Aspect,
|
||||
UINT Subresource) const;
|
||||
UINT Subresource) const {
|
||||
VkImageSubresource result;
|
||||
result.aspectMask = Aspect;
|
||||
result.mipLevel = Subresource % m_desc.MipLevels;
|
||||
result.arrayLayer = Subresource / m_desc.MipLevels;
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Computes subresource layout for the given subresource
|
||||
|
@ -445,6 +525,14 @@ namespace dxvk {
|
|||
return m_11on12;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Sets debug name for texture
|
||||
*
|
||||
* Passes the given name to the backing image or buffer.
|
||||
* \param [in] name Debug name
|
||||
*/
|
||||
void SetDebugName(const char* pName);
|
||||
|
||||
/**
|
||||
* \brief Normalizes and validates texture description
|
||||
*
|
||||
|
@ -473,15 +561,16 @@ namespace dxvk {
|
|||
private:
|
||||
|
||||
struct MappedBuffer {
|
||||
Rc<DxvkBuffer> buffer;
|
||||
DxvkBufferSliceHandle slice;
|
||||
Rc<DxvkBuffer> buffer;
|
||||
Rc<DxvkResourceAllocation> slice;
|
||||
|
||||
std::vector<D3D11_COMMON_TEXTURE_REGION> dirtyRegions;
|
||||
};
|
||||
|
||||
struct MappedInfo {
|
||||
D3D11_MAP mapType;
|
||||
uint64_t seq;
|
||||
D3D11_COMMON_TEXTURE_SUBRESOURCE_LAYOUT layout = { };
|
||||
uint32_t mapType = UnmappedSubresource;
|
||||
uint64_t seq = 0u;
|
||||
};
|
||||
|
||||
ID3D11Resource* m_interface;
|
||||
|
@ -494,11 +583,16 @@ namespace dxvk {
|
|||
VkFormat m_packedFormat;
|
||||
|
||||
Rc<DxvkImage> m_image;
|
||||
std::vector<MappedBuffer> m_buffers;
|
||||
std::vector<MappedInfo> m_mapInfo;
|
||||
small_vector<MappedBuffer, 6> m_buffers;
|
||||
small_vector<MappedInfo, 6> m_mapInfo;
|
||||
|
||||
void* m_mapPtr = nullptr;
|
||||
|
||||
void CreateMappedBuffer(
|
||||
UINT Subresource);
|
||||
|
||||
MappedBuffer CreateMappedBuffer(
|
||||
UINT MipLevel) const;
|
||||
void FreeMappedBuffer(
|
||||
UINT Subresource);
|
||||
|
||||
BOOL CheckImageSupport(
|
||||
const DxvkImageCreateInfo* pImageInfo,
|
||||
|
@ -508,21 +602,15 @@ namespace dxvk {
|
|||
VkFormat Format,
|
||||
VkFormatFeatureFlags2 Features) const;
|
||||
|
||||
VkImageUsageFlags EnableMetaCopyUsage(
|
||||
VkFormat Format,
|
||||
VkImageTiling Tiling) const;
|
||||
|
||||
VkImageUsageFlags EnableMetaPackUsage(
|
||||
VkFormat Format,
|
||||
UINT CpuAccess) const;
|
||||
|
||||
VkMemoryPropertyFlags GetMemoryFlags() const;
|
||||
|
||||
D3D11_COMMON_TEXTURE_MAP_MODE DetermineMapMode(
|
||||
std::pair<D3D11_COMMON_TEXTURE_MAP_MODE, VkMemoryPropertyFlags> DetermineMapMode(
|
||||
const DxvkImageCreateInfo* pImageInfo) const;
|
||||
|
||||
D3D11_COMMON_TEXTURE_SUBRESOURCE_LAYOUT DetermineSubresourceLayout(
|
||||
const DxvkImageCreateInfo* pImageInfo,
|
||||
const VkImageSubresource& subresource) const;
|
||||
|
||||
void ExportImageInfo();
|
||||
|
||||
|
||||
static BOOL IsR32UavCompatibleFormat(
|
||||
DXGI_FORMAT Format);
|
||||
|
||||
|
@ -679,6 +767,8 @@ namespace dxvk {
|
|||
void STDMETHODCALLTYPE GetDesc(
|
||||
D3D11_TEXTURE1D_DESC *pDesc) final;
|
||||
|
||||
void STDMETHODCALLTYPE SetDebugName(const char* pName) final;
|
||||
|
||||
D3D11CommonTexture* GetCommonTexture() {
|
||||
return &m_texture;
|
||||
}
|
||||
|
@ -745,6 +835,8 @@ namespace dxvk {
|
|||
void STDMETHODCALLTYPE GetDesc1(
|
||||
D3D11_TEXTURE2D_DESC1* pDesc) final;
|
||||
|
||||
void STDMETHODCALLTYPE SetDebugName(const char* pName) final;
|
||||
|
||||
D3D11CommonTexture* GetCommonTexture() {
|
||||
return &m_texture;
|
||||
}
|
||||
|
@ -795,6 +887,8 @@ namespace dxvk {
|
|||
void STDMETHODCALLTYPE GetDesc1(
|
||||
D3D11_TEXTURE3D_DESC1* pDesc) final;
|
||||
|
||||
void STDMETHODCALLTYPE SetDebugName(const char* pName) final;
|
||||
|
||||
D3D11CommonTexture* GetCommonTexture() {
|
||||
return &m_texture;
|
||||
}
|
||||
|
|
|
@ -52,15 +52,15 @@ namespace dxvk {
|
|||
* \returns Corresponding Vulkan shader stage
|
||||
*/
|
||||
constexpr VkShaderStageFlagBits GetShaderStage(DxbcProgramType ProgramType) {
|
||||
switch (ProgramType) {
|
||||
case DxbcProgramType::VertexShader: return VK_SHADER_STAGE_VERTEX_BIT;
|
||||
case DxbcProgramType::HullShader: return VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT;
|
||||
case DxbcProgramType::DomainShader: return VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT;
|
||||
case DxbcProgramType::GeometryShader: return VK_SHADER_STAGE_GEOMETRY_BIT;
|
||||
case DxbcProgramType::PixelShader: return VK_SHADER_STAGE_FRAGMENT_BIT;
|
||||
case DxbcProgramType::ComputeShader: return VK_SHADER_STAGE_COMPUTE_BIT;
|
||||
default: return VkShaderStageFlagBits(0);
|
||||
}
|
||||
constexpr uint64_t lut
|
||||
= (uint64_t(VK_SHADER_STAGE_VERTEX_BIT) << (8u * uint32_t(DxbcProgramType::VertexShader)))
|
||||
| (uint64_t(VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT) << (8u * uint32_t(DxbcProgramType::HullShader)))
|
||||
| (uint64_t(VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT) << (8u * uint32_t(DxbcProgramType::DomainShader)))
|
||||
| (uint64_t(VK_SHADER_STAGE_GEOMETRY_BIT) << (8u * uint32_t(DxbcProgramType::GeometryShader)))
|
||||
| (uint64_t(VK_SHADER_STAGE_FRAGMENT_BIT) << (8u * uint32_t(DxbcProgramType::PixelShader)))
|
||||
| (uint64_t(VK_SHADER_STAGE_COMPUTE_BIT) << (8u * uint32_t(DxbcProgramType::ComputeShader)));
|
||||
|
||||
return VkShaderStageFlagBits((lut >> (8u * uint32_t(ProgramType))) & 0xff);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -173,35 +173,23 @@ namespace dxvk {
|
|||
|
||||
Rc<DxvkImage> dxvkImage = GetCommonTexture(pResource)->GetImage();
|
||||
|
||||
if (!(dxvkImage->info().usage & VK_IMAGE_USAGE_SAMPLED_BIT)) {
|
||||
DxvkImageCreateInfo info = dxvkImage->info();
|
||||
info.flags = VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT | VK_IMAGE_CREATE_EXTENDED_USAGE_BIT;
|
||||
info.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT;
|
||||
info.stages = VK_PIPELINE_STAGE_TRANSFER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
|
||||
info.access = VK_ACCESS_TRANSFER_WRITE_BIT | VK_ACCESS_SHADER_READ_BIT;
|
||||
info.tiling = VK_IMAGE_TILING_OPTIMAL;
|
||||
info.layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
|
||||
info.shared = VK_FALSE;
|
||||
dxvkImage = m_copy = pDevice->GetDXVKDevice()->createImage(info, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
|
||||
}
|
||||
|
||||
DXGI_VK_FORMAT_INFO formatInfo = pDevice->LookupFormat(resourceDesc.Format, DXGI_VK_FORMAT_MODE_COLOR);
|
||||
DXGI_VK_FORMAT_FAMILY formatFamily = pDevice->LookupFamily(resourceDesc.Format, DXGI_VK_FORMAT_MODE_COLOR);
|
||||
|
||||
VkImageAspectFlags aspectMask = lookupFormatInfo(formatInfo.Format)->aspectMask;
|
||||
|
||||
DxvkImageViewCreateInfo viewInfo;
|
||||
viewInfo.format = formatInfo.Format;
|
||||
viewInfo.swizzle = formatInfo.Swizzle;
|
||||
viewInfo.usage = VK_IMAGE_USAGE_SAMPLED_BIT;
|
||||
DxvkImageViewKey viewInfo;
|
||||
viewInfo.format = formatInfo.Format;
|
||||
viewInfo.usage = VK_IMAGE_USAGE_SAMPLED_BIT;
|
||||
viewInfo.packedSwizzle = DxvkImageViewKey::packSwizzle(formatInfo.Swizzle);
|
||||
|
||||
switch (m_desc.ViewDimension) {
|
||||
case D3D11_VPIV_DIMENSION_TEXTURE2D:
|
||||
viewInfo.type = VK_IMAGE_VIEW_TYPE_2D;
|
||||
viewInfo.minLevel = m_desc.Texture2D.MipSlice;
|
||||
viewInfo.numLevels = 1;
|
||||
viewInfo.minLayer = 0;
|
||||
viewInfo.numLayers = 1;
|
||||
viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
|
||||
viewInfo.mipIndex = m_desc.Texture2D.MipSlice;
|
||||
viewInfo.mipCount = 1;
|
||||
viewInfo.layerIndex = m_desc.Texture2D.ArraySlice;
|
||||
viewInfo.layerCount = 1;
|
||||
break;
|
||||
|
||||
case D3D11_VPIV_DIMENSION_UNKNOWN:
|
||||
|
@ -209,17 +197,17 @@ namespace dxvk {
|
|||
}
|
||||
|
||||
m_subresources.aspectMask = aspectMask;
|
||||
m_subresources.baseArrayLayer = viewInfo.minLayer;
|
||||
m_subresources.layerCount = viewInfo.numLayers;
|
||||
m_subresources.mipLevel = viewInfo.minLevel;
|
||||
m_subresources.baseArrayLayer = viewInfo.layerIndex;
|
||||
m_subresources.layerCount = viewInfo.layerCount;
|
||||
m_subresources.mipLevel = viewInfo.mipIndex;
|
||||
|
||||
for (uint32_t i = 0; aspectMask && i < m_views.size(); i++) {
|
||||
viewInfo.aspect = vk::getNextAspect(aspectMask);
|
||||
viewInfo.aspects = vk::getNextAspect(aspectMask);
|
||||
|
||||
if (viewInfo.aspect != VK_IMAGE_ASPECT_COLOR_BIT)
|
||||
if (viewInfo.aspects != VK_IMAGE_ASPECT_COLOR_BIT)
|
||||
viewInfo.format = formatFamily.Formats[i];
|
||||
|
||||
m_views[i] = pDevice->GetDXVKDevice()->createImageView(dxvkImage, viewInfo);
|
||||
m_views[i] = dxvkImage->createView(viewInfo);
|
||||
}
|
||||
|
||||
m_isYCbCr = IsYCbCrFormat(resourceDesc.Format);
|
||||
|
@ -287,35 +275,34 @@ namespace dxvk {
|
|||
DXGI_VK_FORMAT_INFO formatInfo = pDevice->LookupFormat(
|
||||
resourceDesc.Format, DXGI_VK_FORMAT_MODE_COLOR);
|
||||
|
||||
DxvkImageViewCreateInfo viewInfo;
|
||||
viewInfo.format = formatInfo.Format;
|
||||
viewInfo.aspect = lookupFormatInfo(viewInfo.format)->aspectMask;
|
||||
viewInfo.swizzle = formatInfo.Swizzle;
|
||||
viewInfo.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
|
||||
DxvkImageViewKey viewInfo;
|
||||
viewInfo.format = formatInfo.Format;
|
||||
viewInfo.aspects = lookupFormatInfo(viewInfo.format)->aspectMask;
|
||||
viewInfo.packedSwizzle = DxvkImageViewKey::packSwizzle(formatInfo.Swizzle);
|
||||
viewInfo.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
|
||||
|
||||
switch (m_desc.ViewDimension) {
|
||||
case D3D11_VPOV_DIMENSION_TEXTURE2D:
|
||||
viewInfo.type = VK_IMAGE_VIEW_TYPE_2D;
|
||||
viewInfo.minLevel = m_desc.Texture2D.MipSlice;
|
||||
viewInfo.numLevels = 1;
|
||||
viewInfo.minLayer = 0;
|
||||
viewInfo.numLayers = 1;
|
||||
viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
|
||||
viewInfo.mipIndex = m_desc.Texture2D.MipSlice;
|
||||
viewInfo.mipCount = 1;
|
||||
viewInfo.layerIndex = 0;
|
||||
viewInfo.layerCount = 1;
|
||||
break;
|
||||
|
||||
case D3D11_VPOV_DIMENSION_TEXTURE2DARRAY:
|
||||
viewInfo.type = VK_IMAGE_VIEW_TYPE_2D_ARRAY;
|
||||
viewInfo.minLevel = m_desc.Texture2DArray.MipSlice;
|
||||
viewInfo.numLevels = 1;
|
||||
viewInfo.minLayer = m_desc.Texture2DArray.FirstArraySlice;
|
||||
viewInfo.numLayers = m_desc.Texture2DArray.ArraySize;
|
||||
viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D_ARRAY;
|
||||
viewInfo.mipIndex = m_desc.Texture2DArray.MipSlice;
|
||||
viewInfo.mipCount = 1;
|
||||
viewInfo.layerIndex = m_desc.Texture2DArray.FirstArraySlice;
|
||||
viewInfo.layerCount = m_desc.Texture2DArray.ArraySize;
|
||||
break;
|
||||
|
||||
case D3D11_VPOV_DIMENSION_UNKNOWN:
|
||||
throw DxvkError("Invalid view dimension");
|
||||
}
|
||||
|
||||
m_view = pDevice->GetDXVKDevice()->createImageView(
|
||||
GetCommonTexture(pResource)->GetImage(), viewInfo);
|
||||
m_view = GetCommonTexture(pResource)->GetImage()->createView(viewInfo);
|
||||
}
|
||||
|
||||
|
||||
|
@ -1026,6 +1013,10 @@ namespace dxvk {
|
|||
const D3D11_VIDEO_PROCESSOR_STREAM* pStreams) {
|
||||
D3D10DeviceLock lock = m_ctx->LockContext();
|
||||
|
||||
m_ctx->EmitCs([] (DxvkContext* ctx) {
|
||||
ctx->beginDebugLabel(vk::makeLabel(0x59eaff, "Video blit"));
|
||||
});
|
||||
|
||||
auto videoProcessor = static_cast<D3D11VideoProcessor*>(pVideoProcessor);
|
||||
bool hasStreamsEnabled = false;
|
||||
|
||||
|
@ -1038,7 +1029,9 @@ namespace dxvk {
|
|||
continue;
|
||||
|
||||
if (!hasStreamsEnabled) {
|
||||
m_ctx->ResetDirtyTracking();
|
||||
m_ctx->ResetCommandListState();
|
||||
|
||||
BindOutputView(pOutputView);
|
||||
hasStreamsEnabled = true;
|
||||
}
|
||||
|
@ -1048,9 +1041,14 @@ namespace dxvk {
|
|||
|
||||
if (hasStreamsEnabled) {
|
||||
UnbindResources();
|
||||
|
||||
m_ctx->RestoreCommandListState();
|
||||
}
|
||||
|
||||
m_ctx->EmitCs([] (DxvkContext* ctx) {
|
||||
ctx->endDebugLabel();
|
||||
});
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
@ -1185,6 +1183,13 @@ namespace dxvk {
|
|||
auto dxvkView = static_cast<D3D11VideoProcessorOutputView*>(pOutputView)->GetView();
|
||||
|
||||
m_ctx->EmitCs([this, cView = dxvkView] (DxvkContext* ctx) {
|
||||
DxvkImageUsageInfo usage = { };
|
||||
usage.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
|
||||
usage.stages = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
|
||||
usage.access = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
|
||||
|
||||
ctx->ensureImageCompatibility(cView->image(), usage);
|
||||
|
||||
DxvkRenderTargets rt;
|
||||
rt.color[0].view = cView;
|
||||
rt.color[0].layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
|
||||
|
@ -1219,30 +1224,19 @@ namespace dxvk {
|
|||
|
||||
auto view = static_cast<D3D11VideoProcessorInputView*>(pStream->pInputSurface);
|
||||
|
||||
if (view->NeedsCopy()) {
|
||||
m_ctx->EmitCs([
|
||||
cDstImage = view->GetShadowCopy(),
|
||||
cSrcImage = view->GetImage(),
|
||||
cSrcLayers = view->GetImageSubresources()
|
||||
] (DxvkContext* ctx) {
|
||||
VkImageSubresourceLayers cDstLayers;
|
||||
cDstLayers.aspectMask = cSrcLayers.aspectMask;
|
||||
cDstLayers.baseArrayLayer = 0;
|
||||
cDstLayers.layerCount = cSrcLayers.layerCount;
|
||||
cDstLayers.mipLevel = cSrcLayers.mipLevel;
|
||||
|
||||
ctx->copyImage(
|
||||
cDstImage, cDstLayers, VkOffset3D(),
|
||||
cSrcImage, cSrcLayers, VkOffset3D(),
|
||||
cDstImage->info().extent);
|
||||
});
|
||||
}
|
||||
|
||||
m_ctx->EmitCs([this,
|
||||
cStreamState = *pStreamState,
|
||||
cImage = view->GetImage(),
|
||||
cViews = view->GetViews(),
|
||||
cIsYCbCr = view->IsYCbCr()
|
||||
] (DxvkContext* ctx) {
|
||||
DxvkImageUsageInfo usage = { };
|
||||
usage.usage = VK_IMAGE_USAGE_SAMPLED_BIT;
|
||||
usage.stages = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
|
||||
usage.access = VK_ACCESS_SHADER_READ_BIT;
|
||||
|
||||
ctx->ensureImageCompatibility(cImage, usage);
|
||||
|
||||
VkViewport viewport;
|
||||
viewport.x = 0.0f;
|
||||
viewport.y = 0.0f;
|
||||
|
@ -1296,10 +1290,10 @@ namespace dxvk {
|
|||
uboData.yMax = 0.9215686f;
|
||||
}
|
||||
|
||||
DxvkBufferSliceHandle uboSlice = m_ubo->allocSlice();
|
||||
memcpy(uboSlice.mapPtr, &uboData, sizeof(uboData));
|
||||
Rc<DxvkResourceAllocation> uboSlice = m_ubo->allocateStorage();
|
||||
memcpy(uboSlice->mapPtr(), &uboData, sizeof(uboData));
|
||||
|
||||
ctx->invalidateBuffer(m_ubo, uboSlice);
|
||||
ctx->invalidateBuffer(m_ubo, std::move(uboSlice));
|
||||
ctx->setViewports(1, &viewport, &scissor);
|
||||
|
||||
ctx->bindShader<VK_SHADER_STAGE_VERTEX_BIT>(Rc<DxvkShader>(m_vs));
|
||||
|
@ -1310,7 +1304,11 @@ namespace dxvk {
|
|||
for (uint32_t i = 0; i < cViews.size(); 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->draw(1, &draw);
|
||||
|
||||
for (uint32_t i = 0; i < cViews.size(); i++)
|
||||
ctx->bindResourceImageView(VK_SHADER_STAGE_FRAGMENT_BIT, 1 + i, nullptr);
|
||||
|
@ -1324,6 +1322,8 @@ namespace dxvk {
|
|||
bufferInfo.usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT;
|
||||
bufferInfo.stages = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
|
||||
bufferInfo.access = VK_ACCESS_UNIFORM_READ_BIT;
|
||||
bufferInfo.debugName = "Video blit parameters";
|
||||
|
||||
m_ubo = m_device->createBuffer(bufferInfo, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -55,7 +55,7 @@ namespace dxvk {
|
|||
* \param [in] b Second view to check
|
||||
* \returns \c true if the views overlap
|
||||
*/
|
||||
inline bool CheckViewOverlap(const D3D11_VK_VIEW_INFO& a, const D3D11_VK_VIEW_INFO b) {
|
||||
inline bool CheckViewOverlap(const D3D11_VK_VIEW_INFO& a, const D3D11_VK_VIEW_INFO& b) {
|
||||
if (likely(a.pResource != b.pResource))
|
||||
return false;
|
||||
|
||||
|
@ -78,4 +78,4 @@ namespace dxvk {
|
|||
return a && b && CheckViewOverlap(a->GetViewInfo(), b->GetViewInfo());
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,58 +17,58 @@ namespace dxvk {
|
|||
D3D11_COMMON_RESOURCE_DESC resourceDesc;
|
||||
GetCommonResourceDesc(pResource, &resourceDesc);
|
||||
|
||||
DxvkImageViewCreateInfo viewInfo;
|
||||
DxvkImageViewKey viewInfo;
|
||||
viewInfo.format = pDevice->LookupFormat(pDesc->Format, DXGI_VK_FORMAT_MODE_DEPTH).Format;
|
||||
viewInfo.aspect = lookupFormatInfo(viewInfo.format)->aspectMask;
|
||||
viewInfo.usage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
|
||||
viewInfo.aspects = lookupFormatInfo(viewInfo.format)->aspectMask;
|
||||
viewInfo.usage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
|
||||
|
||||
switch (pDesc->ViewDimension) {
|
||||
case D3D11_DSV_DIMENSION_TEXTURE1D:
|
||||
viewInfo.type = VK_IMAGE_VIEW_TYPE_1D;
|
||||
viewInfo.minLevel = pDesc->Texture1D.MipSlice;
|
||||
viewInfo.numLevels = 1;
|
||||
viewInfo.minLayer = 0;
|
||||
viewInfo.numLayers = 1;
|
||||
viewInfo.viewType = VK_IMAGE_VIEW_TYPE_1D;
|
||||
viewInfo.mipIndex = pDesc->Texture1D.MipSlice;
|
||||
viewInfo.mipCount = 1;
|
||||
viewInfo.layerIndex = 0;
|
||||
viewInfo.layerCount = 1;
|
||||
break;
|
||||
|
||||
case D3D11_DSV_DIMENSION_TEXTURE1DARRAY:
|
||||
viewInfo.type = VK_IMAGE_VIEW_TYPE_1D_ARRAY;
|
||||
viewInfo.minLevel = pDesc->Texture1DArray.MipSlice;
|
||||
viewInfo.numLevels = 1;
|
||||
viewInfo.minLayer = pDesc->Texture1DArray.FirstArraySlice;
|
||||
viewInfo.numLayers = pDesc->Texture1DArray.ArraySize;
|
||||
viewInfo.viewType = VK_IMAGE_VIEW_TYPE_1D_ARRAY;
|
||||
viewInfo.mipIndex = pDesc->Texture1DArray.MipSlice;
|
||||
viewInfo.mipCount = 1;
|
||||
viewInfo.layerIndex = pDesc->Texture1DArray.FirstArraySlice;
|
||||
viewInfo.layerCount = pDesc->Texture1DArray.ArraySize;
|
||||
break;
|
||||
|
||||
case D3D11_DSV_DIMENSION_TEXTURE2D:
|
||||
viewInfo.type = VK_IMAGE_VIEW_TYPE_2D;
|
||||
viewInfo.minLevel = pDesc->Texture2D.MipSlice;
|
||||
viewInfo.numLevels = 1;
|
||||
viewInfo.minLayer = 0;
|
||||
viewInfo.numLayers = 1;
|
||||
viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
|
||||
viewInfo.mipIndex = pDesc->Texture2D.MipSlice;
|
||||
viewInfo.mipCount = 1;
|
||||
viewInfo.layerIndex = 0;
|
||||
viewInfo.layerCount = 1;
|
||||
break;
|
||||
|
||||
case D3D11_DSV_DIMENSION_TEXTURE2DARRAY:
|
||||
viewInfo.type = VK_IMAGE_VIEW_TYPE_2D_ARRAY;
|
||||
viewInfo.minLevel = pDesc->Texture2DArray.MipSlice;
|
||||
viewInfo.numLevels = 1;
|
||||
viewInfo.minLayer = pDesc->Texture2DArray.FirstArraySlice;
|
||||
viewInfo.numLayers = pDesc->Texture2DArray.ArraySize;
|
||||
viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D_ARRAY;
|
||||
viewInfo.mipIndex = pDesc->Texture2DArray.MipSlice;
|
||||
viewInfo.mipCount = 1;
|
||||
viewInfo.layerIndex = pDesc->Texture2DArray.FirstArraySlice;
|
||||
viewInfo.layerCount = pDesc->Texture2DArray.ArraySize;
|
||||
break;
|
||||
|
||||
case D3D11_DSV_DIMENSION_TEXTURE2DMS:
|
||||
viewInfo.type = VK_IMAGE_VIEW_TYPE_2D;
|
||||
viewInfo.minLevel = 0;
|
||||
viewInfo.numLevels = 1;
|
||||
viewInfo.minLayer = 0;
|
||||
viewInfo.numLayers = 1;
|
||||
viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
|
||||
viewInfo.mipIndex = 0;
|
||||
viewInfo.mipCount = 1;
|
||||
viewInfo.layerIndex = 0;
|
||||
viewInfo.layerCount = 1;
|
||||
break;
|
||||
|
||||
case D3D11_DSV_DIMENSION_TEXTURE2DMSARRAY:
|
||||
viewInfo.type = VK_IMAGE_VIEW_TYPE_2D_ARRAY;
|
||||
viewInfo.minLevel = 0;
|
||||
viewInfo.numLevels = 1;
|
||||
viewInfo.minLayer = pDesc->Texture2DMSArray.FirstArraySlice;
|
||||
viewInfo.numLayers = pDesc->Texture2DMSArray.ArraySize;
|
||||
viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D_ARRAY;
|
||||
viewInfo.mipIndex = 0;
|
||||
viewInfo.mipCount = 1;
|
||||
viewInfo.layerIndex = pDesc->Texture2DMSArray.FirstArraySlice;
|
||||
viewInfo.layerCount = pDesc->Texture2DMSArray.ArraySize;
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -77,20 +77,22 @@ namespace dxvk {
|
|||
|
||||
// Normalize view type so that we won't accidentally
|
||||
// bind 2D array views and 2D views at the same time
|
||||
if (viewInfo.numLayers == 1) {
|
||||
if (viewInfo.type == VK_IMAGE_VIEW_TYPE_1D_ARRAY) viewInfo.type = VK_IMAGE_VIEW_TYPE_1D;
|
||||
if (viewInfo.type == VK_IMAGE_VIEW_TYPE_2D_ARRAY) viewInfo.type = VK_IMAGE_VIEW_TYPE_2D;
|
||||
if (viewInfo.layerCount == 1) {
|
||||
if (viewInfo.viewType == VK_IMAGE_VIEW_TYPE_1D_ARRAY)
|
||||
viewInfo.viewType = VK_IMAGE_VIEW_TYPE_1D;
|
||||
if (viewInfo.viewType == VK_IMAGE_VIEW_TYPE_2D_ARRAY)
|
||||
viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
|
||||
}
|
||||
|
||||
// Populate view info struct
|
||||
m_info.pResource = pResource;
|
||||
m_info.Dimension = resourceDesc.Dim;
|
||||
m_info.BindFlags = resourceDesc.BindFlags;
|
||||
m_info.Image.Aspects = viewInfo.aspect;
|
||||
m_info.Image.MinLevel = viewInfo.minLevel;
|
||||
m_info.Image.MinLayer = viewInfo.minLayer;
|
||||
m_info.Image.NumLevels = viewInfo.numLevels;
|
||||
m_info.Image.NumLayers = viewInfo.numLayers;
|
||||
m_info.Image.Aspects = viewInfo.aspects;
|
||||
m_info.Image.MinLevel = viewInfo.mipIndex;
|
||||
m_info.Image.MinLayer = viewInfo.layerIndex;
|
||||
m_info.Image.NumLevels = viewInfo.mipCount;
|
||||
m_info.Image.NumLayers = viewInfo.layerCount;
|
||||
|
||||
if (m_desc.Flags & D3D11_DSV_READ_ONLY_DEPTH)
|
||||
m_info.Image.Aspects &= ~VK_IMAGE_ASPECT_DEPTH_BIT;
|
||||
|
@ -99,13 +101,15 @@ namespace dxvk {
|
|||
m_info.Image.Aspects &= ~VK_IMAGE_ASPECT_STENCIL_BIT;
|
||||
|
||||
// Create the underlying image view object
|
||||
m_view = pDevice->GetDXVKDevice()->createImageView(
|
||||
GetCommonTexture(pResource)->GetImage(), viewInfo);
|
||||
m_view = GetCommonTexture(pResource)->GetImage()->createView(viewInfo);
|
||||
}
|
||||
|
||||
|
||||
D3D11DepthStencilView::~D3D11DepthStencilView() {
|
||||
ResourceReleasePrivate(m_resource);
|
||||
m_resource = nullptr;
|
||||
|
||||
m_view = nullptr;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -50,24 +50,20 @@ namespace dxvk {
|
|||
}
|
||||
|
||||
VkImageLayout GetRenderLayout() const {
|
||||
if (m_view->imageInfo().tiling == VK_IMAGE_TILING_OPTIMAL) {
|
||||
switch (m_desc.Flags & (D3D11_DSV_READ_ONLY_DEPTH | D3D11_DSV_READ_ONLY_STENCIL)) {
|
||||
default: // case 0
|
||||
return VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
|
||||
case D3D11_DSV_READ_ONLY_DEPTH:
|
||||
return VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL_KHR;
|
||||
case D3D11_DSV_READ_ONLY_STENCIL:
|
||||
return VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL_KHR;
|
||||
case D3D11_DSV_READ_ONLY_DEPTH | D3D11_DSV_READ_ONLY_STENCIL:
|
||||
return VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL;
|
||||
}
|
||||
} else {
|
||||
return VK_IMAGE_LAYOUT_GENERAL;
|
||||
switch (m_desc.Flags & (D3D11_DSV_READ_ONLY_DEPTH | D3D11_DSV_READ_ONLY_STENCIL)) {
|
||||
default: // case 0
|
||||
return VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
|
||||
case D3D11_DSV_READ_ONLY_DEPTH:
|
||||
return VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL_KHR;
|
||||
case D3D11_DSV_READ_ONLY_STENCIL:
|
||||
return VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL_KHR;
|
||||
case D3D11_DSV_READ_ONLY_DEPTH | D3D11_DSV_READ_ONLY_STENCIL:
|
||||
return VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL;
|
||||
}
|
||||
}
|
||||
|
||||
UINT GetSampleCount() const {
|
||||
return UINT(m_view->imageInfo().sampleCount);
|
||||
return UINT(m_view->image()->info().sampleCount);
|
||||
}
|
||||
|
||||
VkImageAspectFlags GetWritableAspectMask() const {
|
||||
|
|
|
@ -22,67 +22,67 @@ namespace dxvk {
|
|||
DXGI_VK_FORMAT_INFO formatInfo = pDevice->LookupFormat(
|
||||
pDesc->Format, DXGI_VK_FORMAT_MODE_COLOR);
|
||||
|
||||
DxvkImageViewCreateInfo viewInfo;
|
||||
viewInfo.format = formatInfo.Format;
|
||||
viewInfo.aspect = lookupFormatInfo(viewInfo.format)->aspectMask;
|
||||
viewInfo.swizzle = formatInfo.Swizzle;
|
||||
viewInfo.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
|
||||
DxvkImageViewKey viewInfo;
|
||||
viewInfo.format = formatInfo.Format;
|
||||
viewInfo.aspects = lookupFormatInfo(viewInfo.format)->aspectMask;
|
||||
viewInfo.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
|
||||
viewInfo.packedSwizzle = DxvkImageViewKey::packSwizzle(formatInfo.Swizzle);
|
||||
|
||||
switch (pDesc->ViewDimension) {
|
||||
case D3D11_RTV_DIMENSION_TEXTURE1D:
|
||||
viewInfo.type = VK_IMAGE_VIEW_TYPE_1D;
|
||||
viewInfo.minLevel = pDesc->Texture1D.MipSlice;
|
||||
viewInfo.numLevels = 1;
|
||||
viewInfo.minLayer = 0;
|
||||
viewInfo.numLayers = 1;
|
||||
viewInfo.viewType = VK_IMAGE_VIEW_TYPE_1D;
|
||||
viewInfo.mipIndex = pDesc->Texture1D.MipSlice;
|
||||
viewInfo.mipCount = 1;
|
||||
viewInfo.layerIndex = 0;
|
||||
viewInfo.layerCount = 1;
|
||||
break;
|
||||
|
||||
case D3D11_RTV_DIMENSION_TEXTURE1DARRAY:
|
||||
viewInfo.type = VK_IMAGE_VIEW_TYPE_1D_ARRAY;
|
||||
viewInfo.minLevel = pDesc->Texture1DArray.MipSlice;
|
||||
viewInfo.numLevels = 1;
|
||||
viewInfo.minLayer = pDesc->Texture1DArray.FirstArraySlice;
|
||||
viewInfo.numLayers = pDesc->Texture1DArray.ArraySize;
|
||||
viewInfo.viewType = VK_IMAGE_VIEW_TYPE_1D_ARRAY;
|
||||
viewInfo.mipIndex = pDesc->Texture1DArray.MipSlice;
|
||||
viewInfo.mipCount = 1;
|
||||
viewInfo.layerIndex = pDesc->Texture1DArray.FirstArraySlice;
|
||||
viewInfo.layerCount = pDesc->Texture1DArray.ArraySize;
|
||||
break;
|
||||
|
||||
case D3D11_RTV_DIMENSION_TEXTURE2D:
|
||||
viewInfo.type = VK_IMAGE_VIEW_TYPE_2D;
|
||||
viewInfo.minLevel = pDesc->Texture2D.MipSlice;
|
||||
viewInfo.numLevels = 1;
|
||||
viewInfo.minLayer = 0;
|
||||
viewInfo.numLayers = 1;
|
||||
viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
|
||||
viewInfo.mipIndex = pDesc->Texture2D.MipSlice;
|
||||
viewInfo.mipCount = 1;
|
||||
viewInfo.layerIndex = 0;
|
||||
viewInfo.layerCount = 1;
|
||||
break;
|
||||
|
||||
case D3D11_RTV_DIMENSION_TEXTURE2DARRAY:
|
||||
viewInfo.type = VK_IMAGE_VIEW_TYPE_2D_ARRAY;
|
||||
viewInfo.minLevel = pDesc->Texture2DArray.MipSlice;
|
||||
viewInfo.numLevels = 1;
|
||||
viewInfo.minLayer = pDesc->Texture2DArray.FirstArraySlice;
|
||||
viewInfo.numLayers = pDesc->Texture2DArray.ArraySize;
|
||||
viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D_ARRAY;
|
||||
viewInfo.mipIndex = pDesc->Texture2DArray.MipSlice;
|
||||
viewInfo.mipCount = 1;
|
||||
viewInfo.layerIndex = pDesc->Texture2DArray.FirstArraySlice;
|
||||
viewInfo.layerCount = pDesc->Texture2DArray.ArraySize;
|
||||
break;
|
||||
|
||||
case D3D11_RTV_DIMENSION_TEXTURE2DMS:
|
||||
viewInfo.type = VK_IMAGE_VIEW_TYPE_2D;
|
||||
viewInfo.minLevel = 0;
|
||||
viewInfo.numLevels = 1;
|
||||
viewInfo.minLayer = 0;
|
||||
viewInfo.numLayers = 1;
|
||||
viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
|
||||
viewInfo.mipIndex = 0;
|
||||
viewInfo.mipCount = 1;
|
||||
viewInfo.layerIndex = 0;
|
||||
viewInfo.layerCount = 1;
|
||||
break;
|
||||
|
||||
case D3D11_RTV_DIMENSION_TEXTURE2DMSARRAY:
|
||||
viewInfo.type = VK_IMAGE_VIEW_TYPE_2D_ARRAY;
|
||||
viewInfo.minLevel = 0;
|
||||
viewInfo.numLevels = 1;
|
||||
viewInfo.minLayer = pDesc->Texture2DMSArray.FirstArraySlice;
|
||||
viewInfo.numLayers = pDesc->Texture2DMSArray.ArraySize;
|
||||
viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D_ARRAY;
|
||||
viewInfo.mipIndex = 0;
|
||||
viewInfo.mipCount = 1;
|
||||
viewInfo.layerIndex = pDesc->Texture2DMSArray.FirstArraySlice;
|
||||
viewInfo.layerCount = pDesc->Texture2DMSArray.ArraySize;
|
||||
break;
|
||||
|
||||
case D3D11_RTV_DIMENSION_TEXTURE3D:
|
||||
viewInfo.type = VK_IMAGE_VIEW_TYPE_2D_ARRAY;
|
||||
viewInfo.minLevel = pDesc->Texture3D.MipSlice;
|
||||
viewInfo.numLevels = 1;
|
||||
viewInfo.minLayer = pDesc->Texture3D.FirstWSlice;
|
||||
viewInfo.numLayers = pDesc->Texture3D.WSize;
|
||||
viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D_ARRAY;
|
||||
viewInfo.mipIndex = pDesc->Texture3D.MipSlice;
|
||||
viewInfo.mipCount = 1;
|
||||
viewInfo.layerIndex = pDesc->Texture3D.FirstWSlice;
|
||||
viewInfo.layerCount = pDesc->Texture3D.WSize;
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -90,32 +90,37 @@ namespace dxvk {
|
|||
}
|
||||
|
||||
if (texture->GetPlaneCount() > 1)
|
||||
viewInfo.aspect = vk::getPlaneAspect(GetPlaneSlice(pDesc));
|
||||
viewInfo.aspects = vk::getPlaneAspect(GetPlaneSlice(pDesc));
|
||||
|
||||
// Normalize view type so that we won't accidentally
|
||||
// bind 2D array views and 2D views at the same time
|
||||
if (viewInfo.numLayers == 1) {
|
||||
if (viewInfo.type == VK_IMAGE_VIEW_TYPE_1D_ARRAY) viewInfo.type = VK_IMAGE_VIEW_TYPE_1D;
|
||||
if (viewInfo.type == VK_IMAGE_VIEW_TYPE_2D_ARRAY) viewInfo.type = VK_IMAGE_VIEW_TYPE_2D;
|
||||
if (viewInfo.layerCount == 1) {
|
||||
if (viewInfo.viewType == VK_IMAGE_VIEW_TYPE_1D_ARRAY)
|
||||
viewInfo.viewType = VK_IMAGE_VIEW_TYPE_1D;
|
||||
if (viewInfo.viewType == VK_IMAGE_VIEW_TYPE_2D_ARRAY)
|
||||
viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
|
||||
}
|
||||
|
||||
// Populate view info struct
|
||||
m_info.pResource = pResource;
|
||||
m_info.Dimension = resourceDesc.Dim;
|
||||
m_info.BindFlags = resourceDesc.BindFlags;
|
||||
m_info.Image.Aspects = viewInfo.aspect;
|
||||
m_info.Image.MinLevel = viewInfo.minLevel;
|
||||
m_info.Image.MinLayer = viewInfo.minLayer;
|
||||
m_info.Image.NumLevels = viewInfo.numLevels;
|
||||
m_info.Image.NumLayers = viewInfo.numLayers;
|
||||
m_info.Image.Aspects = viewInfo.aspects;
|
||||
m_info.Image.MinLevel = viewInfo.mipIndex;
|
||||
m_info.Image.MinLayer = viewInfo.layerIndex;
|
||||
m_info.Image.NumLevels = viewInfo.mipCount;
|
||||
m_info.Image.NumLayers = viewInfo.layerCount;
|
||||
|
||||
// Create the underlying image view object
|
||||
m_view = pDevice->GetDXVKDevice()->createImageView(texture->GetImage(), viewInfo);
|
||||
m_view = texture->GetImage()->createView(viewInfo);
|
||||
}
|
||||
|
||||
|
||||
D3D11RenderTargetView::~D3D11RenderTargetView() {
|
||||
ResourceReleasePrivate(m_resource);
|
||||
m_resource = nullptr;
|
||||
|
||||
m_view = nullptr;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -52,13 +52,11 @@ namespace dxvk {
|
|||
}
|
||||
|
||||
VkImageLayout GetRenderLayout() const {
|
||||
return m_view->imageInfo().tiling == VK_IMAGE_TILING_OPTIMAL
|
||||
? VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL
|
||||
: VK_IMAGE_LAYOUT_GENERAL;
|
||||
return VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
|
||||
}
|
||||
|
||||
UINT GetSampleCount() const {
|
||||
return UINT(m_view->imageInfo().sampleCount);
|
||||
return UINT(m_view->image()->info().sampleCount);
|
||||
}
|
||||
|
||||
D3D10RenderTargetView* GetD3D10Iface() {
|
||||
|
|
|
@ -42,123 +42,123 @@ namespace dxvk {
|
|||
}
|
||||
|
||||
// Fill in buffer view info
|
||||
DxvkBufferViewCreateInfo viewInfo;
|
||||
DxvkBufferViewKey viewInfo;
|
||||
viewInfo.usage = VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT;
|
||||
|
||||
if (bufInfo.Flags & D3D11_BUFFEREX_SRV_FLAG_RAW) {
|
||||
// Raw buffer view. We'll represent this as a
|
||||
// uniform texel buffer with UINT32 elements.
|
||||
viewInfo.format = VK_FORMAT_R32_UINT;
|
||||
viewInfo.rangeOffset = sizeof(uint32_t) * bufInfo.FirstElement;
|
||||
viewInfo.rangeLength = sizeof(uint32_t) * bufInfo.NumElements;
|
||||
viewInfo.offset = sizeof(uint32_t) * bufInfo.FirstElement;
|
||||
viewInfo.size = sizeof(uint32_t) * bufInfo.NumElements;
|
||||
} else if (pDesc->Format == DXGI_FORMAT_UNKNOWN) {
|
||||
// Structured buffer view
|
||||
viewInfo.format = VK_FORMAT_R32_UINT;
|
||||
viewInfo.rangeOffset = buffer->Desc()->StructureByteStride * bufInfo.FirstElement;
|
||||
viewInfo.rangeLength = buffer->Desc()->StructureByteStride * bufInfo.NumElements;
|
||||
viewInfo.offset = buffer->Desc()->StructureByteStride * bufInfo.FirstElement;
|
||||
viewInfo.size = buffer->Desc()->StructureByteStride * bufInfo.NumElements;
|
||||
} else {
|
||||
viewInfo.format = pDevice->LookupFormat(pDesc->Format, DXGI_VK_FORMAT_MODE_COLOR).Format;
|
||||
|
||||
const DxvkFormatInfo* formatInfo = lookupFormatInfo(viewInfo.format);
|
||||
viewInfo.rangeOffset = formatInfo->elementSize * bufInfo.FirstElement;
|
||||
viewInfo.rangeLength = formatInfo->elementSize * bufInfo.NumElements;
|
||||
viewInfo.offset = formatInfo->elementSize * bufInfo.FirstElement;
|
||||
viewInfo.size = formatInfo->elementSize * bufInfo.NumElements;
|
||||
}
|
||||
|
||||
// Populate view info struct
|
||||
m_info.Buffer.Offset = viewInfo.rangeOffset;
|
||||
m_info.Buffer.Length = viewInfo.rangeLength;
|
||||
m_info.Buffer.Offset = viewInfo.offset;
|
||||
m_info.Buffer.Length = viewInfo.size;
|
||||
|
||||
// Create underlying buffer view object
|
||||
m_bufferView = pDevice->GetDXVKDevice()->createBufferView(
|
||||
buffer->GetBuffer(), viewInfo);
|
||||
m_bufferView = buffer->GetBuffer()->createView(viewInfo);
|
||||
} else {
|
||||
auto texture = GetCommonTexture(pResource);
|
||||
auto formatInfo = pDevice->LookupFormat(pDesc->Format, texture->GetFormatMode());
|
||||
|
||||
DxvkImageViewCreateInfo viewInfo;
|
||||
viewInfo.format = formatInfo.Format;
|
||||
viewInfo.aspect = formatInfo.Aspect;
|
||||
viewInfo.swizzle = formatInfo.Swizzle;
|
||||
viewInfo.usage = VK_IMAGE_USAGE_SAMPLED_BIT;
|
||||
DxvkImageViewKey viewInfo;
|
||||
viewInfo.format = formatInfo.Format;
|
||||
viewInfo.aspects = formatInfo.Aspect;
|
||||
viewInfo.usage = VK_IMAGE_USAGE_SAMPLED_BIT;
|
||||
viewInfo.packedSwizzle = DxvkImageViewKey::packSwizzle(formatInfo.Swizzle);
|
||||
|
||||
// Shaders expect the stencil value in the G component
|
||||
if (viewInfo.aspect == VK_IMAGE_ASPECT_STENCIL_BIT) {
|
||||
viewInfo.swizzle = VkComponentMapping {
|
||||
if (viewInfo.aspects == VK_IMAGE_ASPECT_STENCIL_BIT) {
|
||||
viewInfo.packedSwizzle = DxvkImageViewKey::packSwizzle({
|
||||
VK_COMPONENT_SWIZZLE_ZERO, VK_COMPONENT_SWIZZLE_R,
|
||||
VK_COMPONENT_SWIZZLE_ZERO, VK_COMPONENT_SWIZZLE_ZERO };
|
||||
VK_COMPONENT_SWIZZLE_ZERO, VK_COMPONENT_SWIZZLE_ZERO });
|
||||
}
|
||||
|
||||
switch (pDesc->ViewDimension) {
|
||||
case D3D11_SRV_DIMENSION_TEXTURE1D:
|
||||
viewInfo.type = VK_IMAGE_VIEW_TYPE_1D;
|
||||
viewInfo.minLevel = pDesc->Texture1D.MostDetailedMip;
|
||||
viewInfo.numLevels = pDesc->Texture1D.MipLevels;
|
||||
viewInfo.minLayer = 0;
|
||||
viewInfo.numLayers = 1;
|
||||
viewInfo.viewType = VK_IMAGE_VIEW_TYPE_1D;
|
||||
viewInfo.mipIndex = pDesc->Texture1D.MostDetailedMip;
|
||||
viewInfo.mipCount = pDesc->Texture1D.MipLevels;
|
||||
viewInfo.layerIndex = 0;
|
||||
viewInfo.layerCount = 1;
|
||||
break;
|
||||
|
||||
case D3D11_SRV_DIMENSION_TEXTURE1DARRAY:
|
||||
viewInfo.type = VK_IMAGE_VIEW_TYPE_1D_ARRAY;
|
||||
viewInfo.minLevel = pDesc->Texture1DArray.MostDetailedMip;
|
||||
viewInfo.numLevels = pDesc->Texture1DArray.MipLevels;
|
||||
viewInfo.minLayer = pDesc->Texture1DArray.FirstArraySlice;
|
||||
viewInfo.numLayers = pDesc->Texture1DArray.ArraySize;
|
||||
viewInfo.viewType = VK_IMAGE_VIEW_TYPE_1D_ARRAY;
|
||||
viewInfo.mipIndex = pDesc->Texture1DArray.MostDetailedMip;
|
||||
viewInfo.mipCount = pDesc->Texture1DArray.MipLevels;
|
||||
viewInfo.layerIndex = pDesc->Texture1DArray.FirstArraySlice;
|
||||
viewInfo.layerCount = pDesc->Texture1DArray.ArraySize;
|
||||
break;
|
||||
|
||||
case D3D11_SRV_DIMENSION_TEXTURE2D:
|
||||
viewInfo.type = VK_IMAGE_VIEW_TYPE_2D;
|
||||
viewInfo.minLevel = pDesc->Texture2D.MostDetailedMip;
|
||||
viewInfo.numLevels = pDesc->Texture2D.MipLevels;
|
||||
viewInfo.minLayer = 0;
|
||||
viewInfo.numLayers = 1;
|
||||
viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
|
||||
viewInfo.mipIndex = pDesc->Texture2D.MostDetailedMip;
|
||||
viewInfo.mipCount = pDesc->Texture2D.MipLevels;
|
||||
viewInfo.layerIndex = 0;
|
||||
viewInfo.layerCount = 1;
|
||||
break;
|
||||
|
||||
case D3D11_SRV_DIMENSION_TEXTURE2DARRAY:
|
||||
viewInfo.type = VK_IMAGE_VIEW_TYPE_2D_ARRAY;
|
||||
viewInfo.minLevel = pDesc->Texture2DArray.MostDetailedMip;
|
||||
viewInfo.numLevels = pDesc->Texture2DArray.MipLevels;
|
||||
viewInfo.minLayer = pDesc->Texture2DArray.FirstArraySlice;
|
||||
viewInfo.numLayers = pDesc->Texture2DArray.ArraySize;
|
||||
viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D_ARRAY;
|
||||
viewInfo.mipIndex = pDesc->Texture2DArray.MostDetailedMip;
|
||||
viewInfo.mipCount = pDesc->Texture2DArray.MipLevels;
|
||||
viewInfo.layerIndex = pDesc->Texture2DArray.FirstArraySlice;
|
||||
viewInfo.layerCount = pDesc->Texture2DArray.ArraySize;
|
||||
break;
|
||||
|
||||
case D3D11_SRV_DIMENSION_TEXTURE2DMS:
|
||||
viewInfo.type = VK_IMAGE_VIEW_TYPE_2D;
|
||||
viewInfo.minLevel = 0;
|
||||
viewInfo.numLevels = 1;
|
||||
viewInfo.minLayer = 0;
|
||||
viewInfo.numLayers = 1;
|
||||
viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
|
||||
viewInfo.mipIndex = 0;
|
||||
viewInfo.mipCount = 1;
|
||||
viewInfo.layerIndex = 0;
|
||||
viewInfo.layerCount = 1;
|
||||
break;
|
||||
|
||||
case D3D11_SRV_DIMENSION_TEXTURE2DMSARRAY:
|
||||
viewInfo.type = VK_IMAGE_VIEW_TYPE_2D_ARRAY;
|
||||
viewInfo.minLevel = 0;
|
||||
viewInfo.numLevels = 1;
|
||||
viewInfo.minLayer = pDesc->Texture2DMSArray.FirstArraySlice;
|
||||
viewInfo.numLayers = pDesc->Texture2DMSArray.ArraySize;
|
||||
viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D_ARRAY;
|
||||
viewInfo.mipIndex = 0;
|
||||
viewInfo.mipCount = 1;
|
||||
viewInfo.layerIndex = pDesc->Texture2DMSArray.FirstArraySlice;
|
||||
viewInfo.layerCount = pDesc->Texture2DMSArray.ArraySize;
|
||||
break;
|
||||
|
||||
case D3D11_SRV_DIMENSION_TEXTURE3D:
|
||||
viewInfo.type = VK_IMAGE_VIEW_TYPE_3D;
|
||||
viewInfo.minLevel = pDesc->Texture3D.MostDetailedMip;
|
||||
viewInfo.numLevels = pDesc->Texture3D.MipLevels;
|
||||
viewInfo.minLayer = 0;
|
||||
viewInfo.numLayers = 1;
|
||||
viewInfo.viewType = VK_IMAGE_VIEW_TYPE_3D;
|
||||
viewInfo.mipIndex = pDesc->Texture3D.MostDetailedMip;
|
||||
viewInfo.mipCount = pDesc->Texture3D.MipLevels;
|
||||
viewInfo.layerIndex = 0;
|
||||
viewInfo.layerCount = 1;
|
||||
break;
|
||||
|
||||
case D3D11_SRV_DIMENSION_TEXTURECUBE: {
|
||||
const bool cubeArraysEnabled = pDevice->GetDXVKDevice()->features().core.features.imageCubeArray;
|
||||
viewInfo.type = cubeArraysEnabled ? VK_IMAGE_VIEW_TYPE_CUBE_ARRAY : VK_IMAGE_VIEW_TYPE_CUBE;
|
||||
viewInfo.minLevel = pDesc->TextureCube.MostDetailedMip;
|
||||
viewInfo.numLevels = pDesc->TextureCube.MipLevels;
|
||||
viewInfo.minLayer = 0;
|
||||
viewInfo.numLayers = 6;
|
||||
viewInfo.viewType = cubeArraysEnabled ? VK_IMAGE_VIEW_TYPE_CUBE_ARRAY : VK_IMAGE_VIEW_TYPE_CUBE;
|
||||
viewInfo.mipIndex = pDesc->TextureCube.MostDetailedMip;
|
||||
viewInfo.mipCount = pDesc->TextureCube.MipLevels;
|
||||
viewInfo.layerIndex = 0;
|
||||
viewInfo.layerCount = 6;
|
||||
} break;
|
||||
|
||||
case D3D11_SRV_DIMENSION_TEXTURECUBEARRAY:
|
||||
viewInfo.type = VK_IMAGE_VIEW_TYPE_CUBE_ARRAY;
|
||||
viewInfo.minLevel = pDesc->TextureCubeArray.MostDetailedMip;
|
||||
viewInfo.numLevels = pDesc->TextureCubeArray.MipLevels;
|
||||
viewInfo.minLayer = pDesc->TextureCubeArray.First2DArrayFace;
|
||||
viewInfo.numLayers = pDesc->TextureCubeArray.NumCubes * 6;
|
||||
viewInfo.viewType = VK_IMAGE_VIEW_TYPE_CUBE_ARRAY;
|
||||
viewInfo.mipIndex = pDesc->TextureCubeArray.MostDetailedMip;
|
||||
viewInfo.mipCount = pDesc->TextureCubeArray.MipLevels;
|
||||
viewInfo.layerIndex = pDesc->TextureCubeArray.First2DArrayFace;
|
||||
viewInfo.layerCount = pDesc->TextureCubeArray.NumCubes * 6;
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -166,23 +166,27 @@ namespace dxvk {
|
|||
}
|
||||
|
||||
if (texture->GetPlaneCount() > 1)
|
||||
viewInfo.aspect = vk::getPlaneAspect(GetPlaneSlice(pDesc));
|
||||
viewInfo.aspects = vk::getPlaneAspect(GetPlaneSlice(pDesc));
|
||||
|
||||
// Populate view info struct
|
||||
m_info.Image.Aspects = viewInfo.aspect;
|
||||
m_info.Image.MinLevel = viewInfo.minLevel;
|
||||
m_info.Image.MinLayer = viewInfo.minLayer;
|
||||
m_info.Image.NumLevels = viewInfo.numLevels;
|
||||
m_info.Image.NumLayers = viewInfo.numLayers;
|
||||
m_info.Image.Aspects = viewInfo.aspects;
|
||||
m_info.Image.MinLevel = viewInfo.mipIndex;
|
||||
m_info.Image.MinLayer = viewInfo.layerIndex;
|
||||
m_info.Image.NumLevels = viewInfo.mipCount;
|
||||
m_info.Image.NumLayers = viewInfo.layerCount;
|
||||
|
||||
// Create the underlying image view object
|
||||
m_imageView = pDevice->GetDXVKDevice()->createImageView(texture->GetImage(), viewInfo);
|
||||
m_imageView = texture->GetImage()->createView(viewInfo);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
D3D11ShaderResourceView::~D3D11ShaderResourceView() {
|
||||
ResourceReleasePrivate(m_resource);
|
||||
m_resource = nullptr;
|
||||
|
||||
m_imageView = nullptr;
|
||||
m_bufferView = nullptr;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
@ -446,15 +450,17 @@ namespace dxvk {
|
|||
| VK_ACCESS_TRANSFER_READ_BIT
|
||||
| VK_ACCESS_SHADER_WRITE_BIT
|
||||
| VK_ACCESS_SHADER_READ_BIT;
|
||||
info.debugName = "UAV counter";
|
||||
|
||||
Rc<DxvkBuffer> buffer = device->createBuffer(info, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
|
||||
|
||||
DxvkBufferViewCreateInfo viewInfo;
|
||||
DxvkBufferViewKey viewInfo;
|
||||
viewInfo.format = VK_FORMAT_UNDEFINED;
|
||||
viewInfo.rangeOffset = 0;
|
||||
viewInfo.rangeLength = sizeof(uint32_t);
|
||||
viewInfo.offset = 0;
|
||||
viewInfo.size = sizeof(uint32_t);
|
||||
viewInfo.usage = VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT;
|
||||
|
||||
return device->createBufferView(buffer, viewInfo);
|
||||
return buffer->createView(viewInfo);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -43,6 +43,10 @@ namespace dxvk {
|
|||
return m_info.BindFlags & Flags;
|
||||
}
|
||||
|
||||
BOOL HasCounter() const {
|
||||
return m_counterView != nullptr;
|
||||
}
|
||||
|
||||
D3D11_RESOURCE_DIMENSION GetResourceType() const {
|
||||
D3D11_RESOURCE_DIMENSION type;
|
||||
m_resource->GetType(&type);
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
LIBRARY D3D8.DLL
|
||||
EXPORTS
|
||||
ValidatePixelShader @ 2
|
||||
ValidateVertexShader @ 3
|
||||
DebugSetMute @ 4
|
||||
Direct3DCreate8 @ 5
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
{
|
||||
global:
|
||||
ValidatePixelShader;
|
||||
ValidateVertexShader;
|
||||
DebugSetMute;
|
||||
Direct3DCreate8;
|
||||
|
||||
local:
|
||||
|
|
|
@ -6,7 +6,6 @@
|
|||
|
||||
#include <vector>
|
||||
#include <cstdint>
|
||||
#include <climits>
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
|
@ -16,7 +15,9 @@ namespace dxvk {
|
|||
// 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,
|
||||
|
@ -42,12 +43,16 @@ namespace dxvk {
|
|||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -63,11 +68,13 @@ namespace dxvk {
|
|||
}
|
||||
|
||||
private:
|
||||
|
||||
std::vector<BYTE> m_data;
|
||||
DWORD m_fvf;
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
// Main handler for batching D3D8 draw calls.
|
||||
class D3D8Batcher {
|
||||
|
||||
|
@ -75,13 +82,14 @@ namespace dxvk {
|
|||
D3DPRIMITIVETYPE PrimitiveType = D3DPT_INVALID;
|
||||
std::vector<uint16_t> Indices;
|
||||
UINT Offset = 0;
|
||||
UINT MinVertex = UINT_MAX;
|
||||
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)) {
|
||||
|
@ -111,13 +119,13 @@ namespace dxvk {
|
|||
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 = UINT_MAX;
|
||||
draw.MinVertex = std::numeric_limits<uint32_t>::max();
|
||||
draw.MaxVertex = 0;
|
||||
draw.PrimitiveCount = 0;
|
||||
draw.DrawCallCount = 0;
|
||||
|
@ -227,6 +235,7 @@ namespace dxvk {
|
|||
}
|
||||
|
||||
private:
|
||||
|
||||
D3D8Device* m_device8;
|
||||
Com<d3d9::IDirect3DDevice9> m_device;
|
||||
|
||||
|
@ -235,5 +244,7 @@ namespace dxvk {
|
|||
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));
|
||||
}
|
||||
|
||||
}
|
|
@ -1,6 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
#include "d3d8_include.h"
|
||||
#include "d3d8_options.h"
|
||||
#include "d3d8_resource.h"
|
||||
|
||||
namespace dxvk {
|
||||
|
@ -15,9 +16,9 @@ namespace dxvk {
|
|||
Com<D3D9>&& pBuffer,
|
||||
D3DPOOL Pool,
|
||||
DWORD Usage)
|
||||
: D3D8Resource<D3D9, D3D8> (pDevice, std::move(pBuffer))
|
||||
, m_pool (Pool)
|
||||
: D3D8Resource<D3D9, D3D8> (pDevice, Pool, std::move(pBuffer))
|
||||
, m_usage (Usage) {
|
||||
m_options = this->GetParent()->GetOptions();
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE Lock(
|
||||
|
@ -25,6 +26,13 @@ namespace dxvk {
|
|||
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,
|
||||
|
@ -41,10 +49,10 @@ namespace dxvk {
|
|||
}
|
||||
|
||||
protected:
|
||||
// This is the D3D8 pool, not necessarily what's given to D3D9.
|
||||
const D3DPOOL m_pool;
|
||||
// This is the D3D8 usage, not necessarily what's given to D3D9.
|
||||
const DWORD m_usage;
|
||||
|
||||
const D3D8Options* m_options;
|
||||
const DWORD m_usage;
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
@ -54,23 +62,14 @@ namespace dxvk {
|
|||
public:
|
||||
|
||||
D3D8VertexBuffer(
|
||||
D3D8Device* pDevice,
|
||||
Com<d3d9::IDirect3DVertexBuffer9>&& pBuffer,
|
||||
D3DPOOL Pool,
|
||||
DWORD Usage)
|
||||
: D3D8VertexBufferBase(pDevice, std::move(pBuffer), Pool, Usage) {
|
||||
}
|
||||
D3D8Device* pDevice,
|
||||
Com<d3d9::IDirect3DVertexBuffer9>&& pBuffer,
|
||||
D3DPOOL Pool,
|
||||
DWORD Usage);
|
||||
|
||||
D3DRESOURCETYPE STDMETHODCALLTYPE GetType() final { return D3DRTYPE_VERTEXBUFFER; }
|
||||
D3DRESOURCETYPE STDMETHODCALLTYPE GetType() final;
|
||||
|
||||
HRESULT STDMETHODCALLTYPE GetDesc(D3DVERTEXBUFFER_DESC* pDesc) {
|
||||
HRESULT hr = GetD3D9()->GetDesc(reinterpret_cast<d3d9::D3DVERTEXBUFFER_DESC*>(pDesc));
|
||||
if (!FAILED(hr)) {
|
||||
pDesc->Pool = m_pool;
|
||||
pDesc->Usage = m_usage;
|
||||
}
|
||||
return hr;
|
||||
}
|
||||
HRESULT STDMETHODCALLTYPE GetDesc(D3DVERTEXBUFFER_DESC* pDesc);
|
||||
|
||||
};
|
||||
|
||||
|
@ -80,23 +79,15 @@ namespace dxvk {
|
|||
public:
|
||||
|
||||
D3D8IndexBuffer(
|
||||
D3D8Device* pDevice,
|
||||
Com<d3d9::IDirect3DIndexBuffer9>&& pBuffer,
|
||||
D3DPOOL Pool,
|
||||
DWORD Usage)
|
||||
: D3D8IndexBufferBase(pDevice, std::move(pBuffer), Pool, Usage) {
|
||||
}
|
||||
D3D8Device* pDevice,
|
||||
Com<d3d9::IDirect3DIndexBuffer9>&& pBuffer,
|
||||
D3DPOOL Pool,
|
||||
DWORD Usage);
|
||||
|
||||
D3DRESOURCETYPE STDMETHODCALLTYPE GetType() final { return D3DRTYPE_INDEXBUFFER; }
|
||||
D3DRESOURCETYPE STDMETHODCALLTYPE GetType() final;
|
||||
|
||||
HRESULT STDMETHODCALLTYPE GetDesc(D3DINDEXBUFFER_DESC* pDesc) final {
|
||||
HRESULT hr = GetD3D9()->GetDesc(reinterpret_cast<d3d9::D3DINDEXBUFFER_DESC*>(pDesc));
|
||||
if (!FAILED(hr)) {
|
||||
pDesc->Pool = m_pool;
|
||||
pDesc->Usage = m_usage;
|
||||
}
|
||||
return hr;
|
||||
}
|
||||
HRESULT STDMETHODCALLTYPE GetDesc(D3DINDEXBUFFER_DESC* pDesc) final;
|
||||
|
||||
};
|
||||
|
||||
}
|
|
@ -1,8 +1,8 @@
|
|||
#pragma once
|
||||
|
||||
namespace dxvk::d8caps {
|
||||
|
||||
inline constexpr uint32_t MAX_TEXTURE_STAGES = 8;
|
||||
inline constexpr uint32_t MAX_STREAMS = 16;
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace dxvk::d8caps {
|
||||
|
||||
inline constexpr uint32_t MAX_TEXTURE_STAGES = 8;
|
||||
inline constexpr uint32_t MAX_STREAMS = 16;
|
||||
|
||||
}
|
|
@ -1,164 +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);
|
||||
pCaps8->PixelShaderVersion = D3DPS_VERSION(1, 4);
|
||||
|
||||
// This was removed by D3D9. We can probably render windowed.
|
||||
pCaps8->Caps2 |= D3DCAPS2_CANRENDERWINDOWED;
|
||||
|
||||
// Replaced by D3DPRASTERCAPS_DEPTHBIAS in D3D9
|
||||
pCaps8->RasterCaps |= D3DPRASTERCAPS_ZBIAS;
|
||||
|
||||
|
||||
// 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_INVSRCCOLOR2
|
||||
& ~D3DPBLENDCAPS_SRCCOLOR2;
|
||||
|
||||
pCaps8->LineCaps &= ~D3DLINECAPS_ANTIALIAS;
|
||||
|
||||
pCaps8->StencilCaps &= ~D3DSTENCILCAPS_TWOSIDED;
|
||||
}
|
||||
|
||||
// (9<-8) D3DD3DPRESENT_PARAMETERS: Returns D3D9's params given an input for D3D8
|
||||
inline d3d9::D3DPRESENT_PARAMETERS ConvertPresentParameters9(const D3DPRESENT_PARAMETERS* pParams) {
|
||||
|
||||
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);
|
||||
params.MultiSampleQuality = 0; // (D3D8: no MultiSampleQuality), TODO: get a value for this
|
||||
|
||||
|
||||
UINT PresentationInterval = pParams->FullScreen_PresentationInterval;
|
||||
|
||||
if (pParams->Windowed) {
|
||||
|
||||
if (unlikely(PresentationInterval != D3DPRESENT_INTERVAL_DEFAULT)) {
|
||||
// TODO: what does dx8 do if windowed app sets FullScreen_PresentationInterval?
|
||||
Logger::warn(str::format(
|
||||
"D3D8 Application is windowed yet requested FullScreen_PresentationInterval ", PresentationInterval,
|
||||
" (should be D3DPRESENT_INTERVAL_DEFAULT). This will be ignored."));
|
||||
}
|
||||
|
||||
// D3D8: For windowed swap chain, the back buffer is copied to the window immediately.
|
||||
PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
|
||||
}
|
||||
|
||||
D3DSWAPEFFECT SwapEffect = pParams->SwapEffect;
|
||||
|
||||
// D3DSWAPEFFECT_COPY_VSYNC has been removed
|
||||
if (SwapEffect == D3DSWAPEFFECT_COPY_VSYNC) {
|
||||
|
||||
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) != 0) {
|
||||
PresentationInterval = D3DPRESENT_INTERVAL_ONE;
|
||||
// TODO: what does dx8 do if multiple D3DPRESENT_INTERVAL flags are set?
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
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 -1
|
||||
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_MIPFILTER;
|
||||
case D3DTSS_MAXANISOTROPY: return d3d9::D3DSAMP_MAXANISOTROPY;
|
||||
// 25:
|
||||
case D3DTSS_ADDRESSW: return d3d9::D3DSAMP_ADDRESSW;
|
||||
default: return d3d9::D3DSAMPLERSTATETYPE(-1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,6 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
#include "d3d8_include.h"
|
||||
#include "d3d8_multithread.h"
|
||||
#include "d3d8_texture.h"
|
||||
#include "d3d8_buffer.h"
|
||||
#include "d3d8_swapchain.h"
|
||||
|
@ -26,18 +27,19 @@ namespace dxvk {
|
|||
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);
|
||||
D3D8Interface* pParent,
|
||||
Com<d3d9::IDirect3DDevice9>&& pDevice,
|
||||
D3DDEVTYPE DeviceType,
|
||||
HWND hFocusWindow,
|
||||
DWORD BehaviorFlags,
|
||||
D3DPRESENT_PARAMETERS* pParams);
|
||||
|
||||
~D3D8Device();
|
||||
|
||||
|
||||
HRESULT STDMETHODCALLTYPE TestCooperativeLevel();
|
||||
|
||||
UINT STDMETHODCALLTYPE GetAvailableTextureMem();
|
||||
|
@ -205,7 +207,7 @@ namespace dxvk {
|
|||
HRESULT STDMETHODCALLTYPE SetRenderState(D3DRENDERSTATETYPE State, DWORD Value);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE GetRenderState(D3DRENDERSTATETYPE State, DWORD* pValue);
|
||||
|
||||
|
||||
HRESULT STDMETHODCALLTYPE CreateStateBlock(
|
||||
D3DSTATEBLOCKTYPE Type,
|
||||
DWORD* pToken);
|
||||
|
@ -305,7 +307,7 @@ namespace dxvk {
|
|||
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(
|
||||
|
@ -325,7 +327,7 @@ namespace dxvk {
|
|||
UINT* pBaseVertexIndex);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE CreatePixelShader(
|
||||
const DWORD* pFunction,
|
||||
const DWORD* pFunction,
|
||||
DWORD* pHandle);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE SetPixelShader(DWORD Handle);
|
||||
|
@ -355,11 +357,17 @@ namespace dxvk {
|
|||
|
||||
HRESULT STDMETHODCALLTYPE DeletePatch(UINT Handle);
|
||||
|
||||
public: // Internal Methods //
|
||||
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
|
||||
|
@ -375,8 +383,6 @@ namespace dxvk {
|
|||
m_presentParams.BackBufferCount = std::max(m_presentParams.BackBufferCount, 1u);
|
||||
|
||||
// Purge cached objects
|
||||
// TODO: Some functions may need to be called here (e.g. SetTexture, etc.)
|
||||
// in case Reset can be recorded by state blocks and other things.
|
||||
m_textures.fill(nullptr);
|
||||
m_streams.fill(D3D8VBO());
|
||||
m_indices = nullptr;
|
||||
|
@ -385,20 +391,24 @@ namespace dxvk {
|
|||
|
||||
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, std::move(pSurface9));
|
||||
m_backBuffers[i] = new D3D8Surface(this, D3DPOOL_DEFAULT, std::move(pSurface9));
|
||||
}
|
||||
|
||||
Com<d3d9::IDirect3DSurface9> pStencil9 = nullptr;
|
||||
GetD3D9()->GetDepthStencilSurface(&pStencil9);
|
||||
m_autoDepthStencil = new D3D8Surface(this, std::move(pStencil9));
|
||||
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;
|
||||
|
@ -415,6 +425,18 @@ namespace dxvk {
|
|||
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;
|
||||
|
@ -426,31 +448,31 @@ namespace dxvk {
|
|||
Com<D3D8VertexBuffer, false> buffer = nullptr;
|
||||
UINT stride = 0;
|
||||
};
|
||||
|
||||
// Remember to fill() these in the constructor!
|
||||
|
||||
std::array<Com<D3D8Texture2D, false>, d8caps::MAX_TEXTURE_STAGES> m_textures;
|
||||
std::array<D3D8VBO, d8caps::MAX_STREAMS> m_streams;
|
||||
|
||||
Com<D3D8IndexBuffer, false> m_indices;
|
||||
INT m_baseVertexIndex = 0;
|
||||
UINT m_baseVertexIndex = 0;
|
||||
|
||||
// TODO: Which of these should be a private ref
|
||||
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<d3d9::IDirect3DPixelShader9*> m_pixelShaders;
|
||||
DWORD m_currentVertexShader = 0; // can be FVF or vs index (marked by D3DFVF_RESERVED0)
|
||||
DWORD m_currentPixelShader = 0;
|
||||
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;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -1,71 +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() {
|
||||
// ignore Release calls on objects with 0 refCount
|
||||
if(unlikely(!this->m_refCount))
|
||||
return this->m_refCount;
|
||||
|
||||
uint32_t refCount = --this->m_refCount;
|
||||
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;
|
||||
|
||||
};
|
||||
|
||||
#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;
|
||||
|
||||
};
|
||||
|
||||
}
|
|
@ -3,6 +3,7 @@
|
|||
#include "d3d8_include.h"
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
constexpr bool isDXT(D3DFORMAT fmt) {
|
||||
return fmt == D3DFMT_DXT1
|
||||
|| fmt == D3DFMT_DXT2
|
||||
|
@ -208,7 +209,6 @@ namespace dxvk {
|
|||
return size;
|
||||
}
|
||||
|
||||
|
||||
constexpr UINT getSurfaceSize(D3DFORMAT Format, UINT Width, UINT Height) {
|
||||
if (isDXT(Format)) {
|
||||
Width = ((Width + 3) >> 2);
|
||||
|
|
|
@ -63,21 +63,21 @@ interface DECLSPEC_UUID("4B8AAAFA-140F-42BA-9131-597EAFAA2EAD") IDirect3DVolumeT
|
|||
#endif
|
||||
|
||||
#ifdef __MINGW32__
|
||||
#define __CRT_UUID_DECL(type,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8) \
|
||||
} \
|
||||
#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>(); } } \
|
||||
#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
|
||||
|
||||
|
@ -86,7 +86,7 @@ namespace d3d9 {
|
|||
|
||||
/**
|
||||
* \brief Direct3D 9
|
||||
*
|
||||
*
|
||||
* All D3D9 interfaces are included within
|
||||
* a namespace, so as not to collide with
|
||||
* D3D8 interfaces.
|
||||
|
@ -117,6 +117,8 @@ namespace d3d9 {
|
|||
#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"
|
||||
|
@ -124,27 +126,27 @@ namespace d3d9 {
|
|||
// Missed definitions in Wine/MinGW.
|
||||
|
||||
#ifndef D3DPRESENT_BACK_BUFFERS_MAX_EX
|
||||
#define D3DPRESENT_BACK_BUFFERS_MAX_EX 30
|
||||
#define D3DPRESENT_BACK_BUFFERS_MAX_EX 30
|
||||
#endif
|
||||
|
||||
#ifndef D3DSI_OPCODE_MASK
|
||||
#define D3DSI_OPCODE_MASK 0x0000FFFF
|
||||
#define D3DSI_OPCODE_MASK 0x0000FFFF
|
||||
#endif
|
||||
|
||||
#ifndef D3DSP_TEXTURETYPE_MASK
|
||||
#define D3DSP_TEXTURETYPE_MASK 0x78000000
|
||||
#define D3DSP_TEXTURETYPE_MASK 0x78000000
|
||||
#endif
|
||||
|
||||
#ifndef D3DUSAGE_AUTOGENMIPMAP
|
||||
#define D3DUSAGE_AUTOGENMIPMAP 0x00000400L
|
||||
#define D3DUSAGE_AUTOGENMIPMAP 0x00000400L
|
||||
#endif
|
||||
|
||||
#ifndef D3DSP_DCL_USAGE_MASK
|
||||
#define D3DSP_DCL_USAGE_MASK 0x0000000f
|
||||
#define D3DSP_DCL_USAGE_MASK 0x0000000f
|
||||
#endif
|
||||
|
||||
#ifndef D3DSP_OPCODESPECIFICCONTROL_MASK
|
||||
#define D3DSP_OPCODESPECIFICCONTROL_MASK 0x00ff0000
|
||||
#define D3DSP_OPCODESPECIFICCONTROL_MASK 0x00ff0000
|
||||
#endif
|
||||
|
||||
#ifndef D3DSP_OPCODESPECIFICCONTROL_SHIFT
|
||||
|
@ -152,31 +154,31 @@ namespace d3d9 {
|
|||
#endif
|
||||
|
||||
#ifndef D3DCURSOR_IMMEDIATE_UPDATE
|
||||
#define D3DCURSOR_IMMEDIATE_UPDATE 0x00000001L
|
||||
#define D3DCURSOR_IMMEDIATE_UPDATE 0x00000001L
|
||||
#endif
|
||||
|
||||
#ifndef D3DPRESENT_FORCEIMMEDIATE
|
||||
#define D3DPRESENT_FORCEIMMEDIATE 0x00000100L
|
||||
#define D3DPRESENT_FORCEIMMEDIATE 0x00000100L
|
||||
#endif
|
||||
|
||||
// From d3dtypes.h
|
||||
|
||||
#ifndef D3DDEVINFOID_TEXTUREMANAGER
|
||||
#define D3DDEVINFOID_TEXTUREMANAGER 1
|
||||
#define D3DDEVINFOID_TEXTUREMANAGER 1
|
||||
#endif
|
||||
|
||||
#ifndef D3DDEVINFOID_D3DTEXTUREMANAGER
|
||||
#define D3DDEVINFOID_D3DTEXTUREMANAGER 2
|
||||
#define D3DDEVINFOID_D3DTEXTUREMANAGER 2
|
||||
#endif
|
||||
|
||||
#ifndef D3DDEVINFOID_TEXTURING
|
||||
#define D3DDEVINFOID_TEXTURING 3
|
||||
#define D3DDEVINFOID_TEXTURING 3
|
||||
#endif
|
||||
|
||||
// From d3dhal.h
|
||||
|
||||
#ifndef D3DDEVINFOID_VCACHE
|
||||
#define D3DDEVINFOID_VCACHE 4
|
||||
#define D3DDEVINFOID_VCACHE 4
|
||||
#endif
|
||||
|
||||
// MinGW headers are broken. Who'dve guessed?
|
||||
|
@ -184,17 +186,21 @@ namespace d3d9 {
|
|||
|
||||
// Missing from d3d8types.h
|
||||
#ifndef D3DDEVINFOID_RESOURCEMANAGER
|
||||
#define D3DDEVINFOID_RESOURCEMANAGER 5
|
||||
#define D3DDEVINFOID_RESOURCEMANAGER 5
|
||||
#endif
|
||||
|
||||
#ifndef D3DDEVINFOID_VERTEXSTATS
|
||||
#define D3DDEVINFOID_VERTEXSTATS 6 // Aka D3DDEVINFOID_D3DVERTEXSTATS
|
||||
#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
|
||||
#define D3DVSDT_TYPE DWORD
|
||||
#define D3DVSDE_REGISTER DWORD
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,136 +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("D3D8Device: ERROR! Failed to get D3D9 Bridge. d3d9.dll might not be DXVK!");
|
||||
}
|
||||
|
||||
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) {
|
||||
// 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);
|
||||
|
||||
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) {
|
||||
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 (FAILED(res)) {
|
||||
return res;
|
||||
}
|
||||
|
||||
*ppReturnedDeviceInterface = ref(new D3D8Device(
|
||||
this, std::move(pDevice9),
|
||||
DeviceType, hFocusWindow, BehaviorFlags,
|
||||
pPresentationParameters
|
||||
));
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
#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;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,163 +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) {
|
||||
return m_d3d9->CheckDeviceType(
|
||||
Adapter,
|
||||
(d3d9::D3DDEVTYPE)DevType,
|
||||
(d3d9::D3DFORMAT)AdapterFormat,
|
||||
(d3d9::D3DFORMAT)BackBufferFormat,
|
||||
bWindowed
|
||||
);
|
||||
}
|
||||
|
||||
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) {
|
||||
d3d9::D3DCAPS9 caps9;
|
||||
HRESULT res = m_d3d9->GetDeviceCaps(Adapter, (d3d9::D3DDEVTYPE)DeviceType, &caps9);
|
||||
dxvk::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;
|
||||
|
||||
d3d9::IDirect3D9* m_d3d9;
|
||||
Com<IDxvkD3D8InterfaceBridge> m_bridge;
|
||||
D3D8Options m_d3d8Options;
|
||||
};
|
||||
|
||||
#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;
|
||||
};
|
||||
|
||||
}
|
|
@ -1,24 +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 IDirect3D8* __stdcall Direct3DCreate8(UINT nSDKVersion) {
|
||||
dxvk::Logger::trace("Direct3DCreate8 called");
|
||||
|
||||
IDirect3D8* pDirect3D = nullptr;
|
||||
dxvk::CreateD3D8(&pDirect3D);
|
||||
|
||||
return pDirect3D;
|
||||
}
|
||||
}
|
||||
#include "d3d8_interface.h"
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
Logger Logger::s_instance("d3d8.log");
|
||||
|
||||
HRESULT CreateD3D8(IDirect3D8** ppDirect3D8) {
|
||||
if (!ppDirect3D8)
|
||||
return D3DERR_INVALIDCALL;
|
||||
|
||||
*ppDirect3D8 = ref(new D3D8Interface());
|
||||
return D3D_OK;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
|
||||
DLLEXPORT HRESULT __stdcall ValidatePixelShader(
|
||||
const DWORD* pPixelShader,
|
||||
const D3DCAPS8* pCaps,
|
||||
BOOL ErrorReturn,
|
||||
char** pErrorString) {
|
||||
HRESULT res = S_OK;
|
||||
std::string errorMessage = "";
|
||||
|
||||
// ValidatePixelShader returns immediately in case of a NULL pPixelShader
|
||||
if (unlikely(pPixelShader == nullptr)) {
|
||||
dxvk::Logger::warn("D3D8: ValidatePixelShader: Null pPixelShader");
|
||||
return E_FAIL;
|
||||
} else {
|
||||
const uint32_t majorVersion = D3DSHADER_VERSION_MAJOR(pPixelShader[0]);
|
||||
const uint32_t minorVersion = D3DSHADER_VERSION_MINOR(pPixelShader[0]);
|
||||
|
||||
if (unlikely(majorVersion != 1 || minorVersion > 4)) {
|
||||
errorMessage = dxvk::str::format("D3D8: ValidatePixelShader: Unsupported PS version ",
|
||||
majorVersion, ".", minorVersion);
|
||||
res = E_FAIL;
|
||||
} else if (unlikely(pCaps && pPixelShader[0] > pCaps->PixelShaderVersion)) {
|
||||
errorMessage = dxvk::str::format("D3D8: ValidatePixelShader: Caps: Unsupported PS version ",
|
||||
majorVersion, ".", minorVersion);
|
||||
res = E_FAIL;
|
||||
}
|
||||
}
|
||||
|
||||
if (unlikely(res != S_OK)) {
|
||||
dxvk::Logger::warn(errorMessage);
|
||||
|
||||
if (!ErrorReturn)
|
||||
errorMessage = "";
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
if (pErrorString != nullptr) {
|
||||
const size_t errorMessageSize = errorMessage.size() + 1;
|
||||
// Wine tests call HeapFree() on the returned error string,
|
||||
// so the expectation is for it to be allocated on the heap.
|
||||
*pErrorString = (char*) HeapAlloc(GetProcessHeap(), 0, errorMessageSize);
|
||||
if (*pErrorString)
|
||||
memcpy(*pErrorString, errorMessage.c_str(), errorMessageSize);
|
||||
}
|
||||
#endif
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
DLLEXPORT HRESULT __stdcall ValidateVertexShader(
|
||||
const DWORD* pVertexShader,
|
||||
const DWORD* pVertexDecl,
|
||||
const D3DCAPS8* pCaps,
|
||||
BOOL ErrorReturn,
|
||||
char** pErrorString) {
|
||||
HRESULT res = S_OK;
|
||||
std::string errorMessage = "";
|
||||
|
||||
if (unlikely(pVertexShader == nullptr)) {
|
||||
errorMessage = "D3D8: ValidateVertexShader: Null pVertexShader";
|
||||
res = E_FAIL;
|
||||
} else {
|
||||
const uint32_t majorVersion = D3DSHADER_VERSION_MAJOR(pVertexShader[0]);
|
||||
const uint32_t minorVersion = D3DSHADER_VERSION_MINOR(pVertexShader[0]);
|
||||
|
||||
if (unlikely(majorVersion != 1 || minorVersion > 1)) {
|
||||
errorMessage = dxvk::str::format("D3D8: ValidateVertexShader: Unsupported VS version ",
|
||||
majorVersion, ".", minorVersion);
|
||||
res = E_FAIL;
|
||||
} else if (unlikely(pCaps && pVertexShader[0] > pCaps->VertexShaderVersion)) {
|
||||
errorMessage = dxvk::str::format("D3D8: ValidateVertexShader: Caps: Unsupported VS version ",
|
||||
majorVersion, ".", minorVersion);
|
||||
res = E_FAIL;
|
||||
}
|
||||
}
|
||||
|
||||
if (unlikely(res != S_OK)) {
|
||||
dxvk::Logger::warn(errorMessage);
|
||||
|
||||
if (!ErrorReturn)
|
||||
errorMessage = "";
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
if (pErrorString != nullptr) {
|
||||
const size_t errorMessageSize = errorMessage.size() + 1;
|
||||
// Wine tests call HeapFree() on the returned error string,
|
||||
// so the expectation is for it to be allocated on the heap.
|
||||
*pErrorString = (char*) HeapAlloc(GetProcessHeap(), 0, errorMessageSize);
|
||||
if (*pErrorString)
|
||||
memcpy(*pErrorString, errorMessage.c_str(), errorMessageSize);
|
||||
}
|
||||
#endif
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
DLLEXPORT void __stdcall DebugSetMute() {}
|
||||
|
||||
DLLEXPORT IDirect3D8* __stdcall Direct3DCreate8(UINT nSDKVersion) {
|
||||
IDirect3D8* pDirect3D = nullptr;
|
||||
dxvk::CreateD3D8(&pDirect3D);
|
||||
|
||||
return pDirect3D;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
9
src/d3d8/d3d8_multithread.cpp
Normal file
9
src/d3d8/d3d8_multithread.cpp
Normal file
|
@ -0,0 +1,9 @@
|
|||
#include "d3d8_device.h"
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
D3D8Multithread::D3D8Multithread(
|
||||
BOOL Protected)
|
||||
: m_protected( Protected ) { }
|
||||
|
||||
}
|
77
src/d3d8/d3d8_multithread.h
Normal file
77
src/d3d8/d3d8_multithread.h
Normal file
|
@ -0,0 +1,77 @@
|
|||
#pragma once
|
||||
|
||||
#include "d3d8_include.h"
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
/**
|
||||
* \brief Device lock
|
||||
*
|
||||
* Lightweight RAII wrapper that implements
|
||||
* a subset of the functionality provided by
|
||||
* \c std::unique_lock, with the goal of being
|
||||
* cheaper to construct and destroy.
|
||||
*/
|
||||
class D3D8DeviceLock {
|
||||
|
||||
public:
|
||||
|
||||
D3D8DeviceLock()
|
||||
: m_mutex(nullptr) { }
|
||||
|
||||
D3D8DeviceLock(sync::RecursiveSpinlock& mutex)
|
||||
: m_mutex(&mutex) {
|
||||
mutex.lock();
|
||||
}
|
||||
|
||||
D3D8DeviceLock(D3D8DeviceLock&& other)
|
||||
: m_mutex(other.m_mutex) {
|
||||
other.m_mutex = nullptr;
|
||||
}
|
||||
|
||||
D3D8DeviceLock& operator = (D3D8DeviceLock&& other) {
|
||||
if (m_mutex)
|
||||
m_mutex->unlock();
|
||||
|
||||
m_mutex = other.m_mutex;
|
||||
other.m_mutex = nullptr;
|
||||
return *this;
|
||||
}
|
||||
|
||||
~D3D8DeviceLock() {
|
||||
if (m_mutex != nullptr)
|
||||
m_mutex->unlock();
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
sync::RecursiveSpinlock* m_mutex;
|
||||
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* \brief D3D8 context lock
|
||||
*/
|
||||
class D3D8Multithread {
|
||||
|
||||
public:
|
||||
|
||||
D3D8Multithread(
|
||||
BOOL Protected);
|
||||
|
||||
D3D8DeviceLock AcquireLock() {
|
||||
return m_protected
|
||||
? D3D8DeviceLock(m_mutex)
|
||||
: D3D8DeviceLock();
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
BOOL m_protected;
|
||||
|
||||
sync::RecursiveSpinlock m_mutex;
|
||||
|
||||
};
|
||||
|
||||
}
|
|
@ -1,4 +1,5 @@
|
|||
#include "d3d8_options.h"
|
||||
|
||||
#include "../d3d9/d3d9_bridge.h"
|
||||
#include "../util/config/config.h"
|
||||
#include "../util/util_string.h"
|
||||
|
@ -6,8 +7,9 @@
|
|||
#include <charconv>
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
static inline uint32_t parseDword(std::string_view str) {
|
||||
uint32_t value = UINT32_MAX;
|
||||
uint32_t value = std::numeric_limits<uint32_t>::max();
|
||||
std::from_chars(str.data(), str.data() + str.size(), value);
|
||||
return value;
|
||||
}
|
||||
|
@ -50,6 +52,6 @@ namespace dxvk {
|
|||
|
||||
forceVsDecl.emplace_back(D3DVSDE_REGISTER(reg), D3DVSDT_TYPE(type));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,48 +1,65 @@
|
|||
#pragma once
|
||||
|
||||
#include "d3d8_include.h"
|
||||
#include "../d3d9/d3d9_bridge.h"
|
||||
#include "../util/config/config.h"
|
||||
|
||||
namespace dxvk {
|
||||
struct D3D8Options {
|
||||
|
||||
/// Some games rely on undefined behavior by using undeclared vertex shader inputs.
|
||||
/// The simplest way to fix them is to simply modify their vertex shader decl.
|
||||
///
|
||||
/// This option takes a comma-separated list of colon-separated number pairs, where
|
||||
/// the first number is a D3DVSDE_REGISTER value, the second is a D3DVSDT_TYPE value.
|
||||
/// e.g. "0:2,3:2,7:1" for float3 position : v0, float3 normal : v3, float2 uv : v7
|
||||
std::vector<std::pair<D3DVSDE_REGISTER, D3DVSDT_TYPE>> forceVsDecl;
|
||||
|
||||
/// Specialized drawcall batcher, typically for games that draw a lot of similar
|
||||
/// geometry in separate drawcalls (sometimes even one triangle at a time).
|
||||
///
|
||||
/// May hurt performance outside of specifc games that benefit from it.
|
||||
bool batching = false;
|
||||
|
||||
/// The Lord of the Rings: The Fellowship of the Ring tries to create a P8 texture
|
||||
/// in D3DPOOL_MANAGED on Nvidia and Intel, which fails, but has a separate code
|
||||
/// path for ATI/AMD that creates it in D3DPOOL_SCRATCH instead, which works.
|
||||
///
|
||||
/// The internal logic determining this path doesn't seem to be d3d-related, but
|
||||
/// the game works universally if we mimic its own ATI/AMD workaround during P8
|
||||
/// texture creation.
|
||||
///
|
||||
/// Early Nvidia GPUs, such as the GeForce 4 generation cards, included and exposed
|
||||
/// P8 texture support. However, it was no longer advertised with cards in the FX series
|
||||
/// and above. Most likely ATI/AMD drivers never supported P8 in the first place.
|
||||
bool placeP8InScratch = false;
|
||||
|
||||
D3D8Options() {}
|
||||
D3D8Options(const Config& config) {
|
||||
auto forceVsDeclStr = config.getOption<std::string>("d3d8.forceVsDecl", "");
|
||||
batching = config.getOption<bool> ("d3d8.batching", batching);
|
||||
placeP8InScratch = config.getOption<bool> ("d3d8.placeP8InScratch", placeP8InScratch);
|
||||
|
||||
parseVsDecl(forceVsDeclStr);
|
||||
}
|
||||
|
||||
void parseVsDecl(const std::string& decl);
|
||||
};
|
||||
}
|
||||
#pragma once
|
||||
|
||||
#include "d3d8_include.h"
|
||||
#include "../d3d9/d3d9_bridge.h"
|
||||
#include "../util/config/config.h"
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
struct D3D8Options {
|
||||
|
||||
/// Some games rely on undefined behavior by using undeclared vertex shader inputs.
|
||||
/// The simplest way to fix them is to simply modify their vertex shader decl.
|
||||
///
|
||||
/// This option takes a comma-separated list of colon-separated number pairs, where
|
||||
/// the first number is a D3DVSDE_REGISTER value, the second is a D3DVSDT_TYPE value.
|
||||
/// e.g. "0:2,3:2,7:1" for float3 position : v0, float3 normal : v3, float2 uv : v7
|
||||
std::vector<std::pair<D3DVSDE_REGISTER, D3DVSDT_TYPE>> forceVsDecl;
|
||||
|
||||
/// Specialized drawcall batcher, typically for games that draw a lot of similar
|
||||
/// geometry in separate drawcalls (sometimes even one triangle at a time).
|
||||
///
|
||||
/// May hurt performance outside of specifc games that benefit from it.
|
||||
bool batching = false;
|
||||
|
||||
/// The Lord of the Rings: The Fellowship of the Ring tries to create a P8 texture
|
||||
/// in D3DPOOL_MANAGED on Nvidia and Intel, which fails, but has a separate code
|
||||
/// path for ATI/AMD that creates it in D3DPOOL_SCRATCH instead, which works.
|
||||
///
|
||||
/// The internal logic determining this path doesn't seem to be d3d-related, but
|
||||
/// the game works universally if we mimic its own ATI/AMD workaround during P8
|
||||
/// texture creation.
|
||||
///
|
||||
/// Early Nvidia GPUs, such as the GeForce 4 generation cards, included and exposed
|
||||
/// P8 texture support. However, it was no longer advertised with cards in the FX series
|
||||
/// and above. Most likely ATI/AMD drivers never supported P8 in the first place.
|
||||
bool placeP8InScratch = false;
|
||||
|
||||
/// Rayman 3 relies on D3DLOCK_DISCARD being ignored for everything except D3DUSAGE_DYNAMIC +
|
||||
/// D3DUSAGE_WRITEONLY buffers, however this approach incurs a performance penalty.
|
||||
///
|
||||
/// Some titles might abuse this early D3D8 quirk, however at some point in its history
|
||||
/// it was brought in line with standard D3D9 behavior.
|
||||
bool forceLegacyDiscard = false;
|
||||
|
||||
/// Splinter Cell expects shadow map texture coordinates to be perspective divided
|
||||
/// even though D3DTTFF_PROJECTED is never set for any texture coordinates. This flag
|
||||
/// forces that flag for the necessary stages when a depth texture is bound to slot 0
|
||||
bool shadowPerspectiveDivide = false;
|
||||
|
||||
D3D8Options() {}
|
||||
|
||||
D3D8Options(const Config& config) {
|
||||
auto forceVsDeclStr = config.getOption<std::string>("d3d8.forceVsDecl", "");
|
||||
batching = config.getOption<bool> ("d3d8.batching", batching);
|
||||
placeP8InScratch = config.getOption<bool> ("d3d8.placeP8InScratch", placeP8InScratch);
|
||||
forceLegacyDiscard = config.getOption<bool> ("d3d8.forceLegacyDiscard", forceLegacyDiscard);
|
||||
shadowPerspectiveDivide = config.getOption<bool> ("d3d8.shadowPerspectiveDivide", shadowPerspectiveDivide);
|
||||
|
||||
parseVsDecl(forceVsDeclStr);
|
||||
}
|
||||
|
||||
void parseVsDecl(const std::string& decl);
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -1,100 +1,117 @@
|
|||
#pragma once
|
||||
|
||||
/** Implements IDirect3DResource8
|
||||
*
|
||||
* - SetPrivateData, GetPrivateData, FreePrivateData
|
||||
* - SetPriority, GetPriority
|
||||
*
|
||||
* - Subclasses provide: PreLoad, GetType
|
||||
*/
|
||||
|
||||
#include "d3d8_device_child.h"
|
||||
#include "../util/com/com_private_data.h"
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
template <typename D3D9, typename D3D8>
|
||||
class D3D8Resource : public D3D8DeviceChild<D3D9, D3D8> {
|
||||
|
||||
public:
|
||||
|
||||
D3D8Resource(D3D8Device* pDevice, Com<D3D9>&& Object)
|
||||
: D3D8DeviceChild<D3D9, D3D8>(pDevice, std::move(Object))
|
||||
, m_priority ( 0 ) { }
|
||||
|
||||
HRESULT STDMETHODCALLTYPE SetPrivateData(
|
||||
REFGUID refguid,
|
||||
const void* pData,
|
||||
DWORD SizeOfData,
|
||||
DWORD Flags) final {
|
||||
HRESULT hr;
|
||||
if (Flags & D3DSPD_IUNKNOWN) {
|
||||
IUnknown* unknown =
|
||||
const_cast<IUnknown*>(
|
||||
reinterpret_cast<const IUnknown*>(pData));
|
||||
hr = m_privateData.setInterface(
|
||||
refguid, unknown);
|
||||
}
|
||||
else
|
||||
hr = m_privateData.setData(
|
||||
refguid, SizeOfData, pData);
|
||||
|
||||
if (FAILED(hr))
|
||||
return D3DERR_INVALIDCALL;
|
||||
|
||||
return D3D_OK;
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE GetPrivateData(
|
||||
REFGUID refguid,
|
||||
void* pData,
|
||||
DWORD* pSizeOfData) final {
|
||||
HRESULT hr = m_privateData.getData(
|
||||
refguid, reinterpret_cast<UINT*>(pSizeOfData), pData);
|
||||
|
||||
if (FAILED(hr))
|
||||
return D3DERR_INVALIDCALL;
|
||||
|
||||
return D3D_OK;
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE FreePrivateData(REFGUID refguid) final {
|
||||
HRESULT hr = m_privateData.setData(refguid, 0, nullptr);
|
||||
|
||||
if (FAILED(hr))
|
||||
return D3DERR_INVALIDCALL;
|
||||
|
||||
return D3D_OK;
|
||||
}
|
||||
|
||||
DWORD STDMETHODCALLTYPE SetPriority(DWORD PriorityNew) {
|
||||
DWORD oldPriority = m_priority;
|
||||
m_priority = PriorityNew;
|
||||
return oldPriority;
|
||||
}
|
||||
|
||||
DWORD STDMETHODCALLTYPE GetPriority() {
|
||||
return m_priority;
|
||||
}
|
||||
|
||||
virtual IUnknown* GetInterface(REFIID riid) override try {
|
||||
return D3D8DeviceChild<D3D9, D3D8>::GetInterface(riid);
|
||||
} catch (HRESULT err) {
|
||||
if (riid == __uuidof(IDirect3DResource8))
|
||||
return this;
|
||||
|
||||
throw err;
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
DWORD m_priority;
|
||||
|
||||
private:
|
||||
|
||||
ComPrivateData m_privateData;
|
||||
|
||||
};
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
/** Implements IDirect3DResource8
|
||||
*
|
||||
* - SetPrivateData, GetPrivateData, FreePrivateData
|
||||
* - SetPriority, GetPriority
|
||||
*
|
||||
* - Subclasses provide: PreLoad, GetType
|
||||
*/
|
||||
|
||||
#include "d3d8_device_child.h"
|
||||
#include "../util/com/com_private_data.h"
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
template <typename D3D9, typename D3D8>
|
||||
class D3D8Resource : public D3D8DeviceChild<D3D9, D3D8> {
|
||||
|
||||
public:
|
||||
|
||||
D3D8Resource(D3D8Device* pDevice, D3DPOOL Pool, Com<D3D9>&& Object)
|
||||
: D3D8DeviceChild<D3D9, D3D8>(pDevice, std::move(Object))
|
||||
, m_pool ( Pool )
|
||||
, m_priority ( 0 ) { }
|
||||
|
||||
HRESULT STDMETHODCALLTYPE SetPrivateData(
|
||||
REFGUID refguid,
|
||||
const void* pData,
|
||||
DWORD SizeOfData,
|
||||
DWORD Flags) final {
|
||||
HRESULT hr;
|
||||
if (Flags & D3DSPD_IUNKNOWN) {
|
||||
if(unlikely(SizeOfData != sizeof(IUnknown*)))
|
||||
return D3DERR_INVALIDCALL;
|
||||
IUnknown* unknown =
|
||||
const_cast<IUnknown*>(
|
||||
reinterpret_cast<const IUnknown*>(pData));
|
||||
hr = m_privateData.setInterface(
|
||||
refguid, unknown);
|
||||
}
|
||||
else
|
||||
hr = m_privateData.setData(
|
||||
refguid, SizeOfData, pData);
|
||||
|
||||
if (unlikely(FAILED(hr)))
|
||||
return D3DERR_INVALIDCALL;
|
||||
|
||||
return D3D_OK;
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE GetPrivateData(
|
||||
REFGUID refguid,
|
||||
void* pData,
|
||||
DWORD* pSizeOfData) final {
|
||||
if (unlikely(pData == nullptr && pSizeOfData == nullptr))
|
||||
return D3DERR_NOTFOUND;
|
||||
|
||||
HRESULT hr = m_privateData.getData(
|
||||
refguid, reinterpret_cast<UINT*>(pSizeOfData), pData);
|
||||
|
||||
if (unlikely(FAILED(hr))) {
|
||||
if(hr == DXGI_ERROR_MORE_DATA)
|
||||
return D3DERR_MOREDATA;
|
||||
else if (hr == DXGI_ERROR_NOT_FOUND)
|
||||
return D3DERR_NOTFOUND;
|
||||
else
|
||||
return D3DERR_INVALIDCALL;
|
||||
}
|
||||
|
||||
return D3D_OK;
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE FreePrivateData(REFGUID refguid) final {
|
||||
HRESULT hr = m_privateData.setData(refguid, 0, nullptr);
|
||||
|
||||
if (unlikely(FAILED(hr)))
|
||||
return D3DERR_INVALIDCALL;
|
||||
|
||||
return D3D_OK;
|
||||
}
|
||||
|
||||
DWORD STDMETHODCALLTYPE SetPriority(DWORD PriorityNew) {
|
||||
// Priority can only be set for D3DPOOL_MANAGED resources
|
||||
if (likely(m_pool == D3DPOOL_MANAGED)) {
|
||||
DWORD oldPriority = m_priority;
|
||||
m_priority = PriorityNew;
|
||||
return oldPriority;
|
||||
}
|
||||
|
||||
return m_priority;
|
||||
}
|
||||
|
||||
DWORD STDMETHODCALLTYPE GetPriority() {
|
||||
return m_priority;
|
||||
}
|
||||
|
||||
virtual IUnknown* GetInterface(REFIID riid) override try {
|
||||
return D3D8DeviceChild<D3D9, D3D8>::GetInterface(riid);
|
||||
} catch (HRESULT err) {
|
||||
if (riid == __uuidof(IDirect3DResource8))
|
||||
return this;
|
||||
|
||||
throw err;
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
const D3DPOOL m_pool;
|
||||
DWORD m_priority;
|
||||
|
||||
private:
|
||||
|
||||
ComPrivateData m_privateData;
|
||||
|
||||
};
|
||||
|
||||
}
|
|
@ -1,4 +1,3 @@
|
|||
|
||||
#include "d3d8_shader.h"
|
||||
|
||||
#define VSD_SHIFT_MASK(token, field) ((token & field ## MASK) >> field ## SHIFT)
|
||||
|
@ -138,7 +137,7 @@ namespace dxvk {
|
|||
DWORD token;
|
||||
|
||||
std::stringstream dbg;
|
||||
dbg << "Vertex Declaration Tokens:\n\t";
|
||||
dbg << "D3D8: Vertex Declaration Tokens:\n\t";
|
||||
|
||||
WORD currentStream = 0;
|
||||
WORD currentOffset = 0;
|
||||
|
@ -313,8 +312,10 @@ namespace dxvk {
|
|||
// Instructions
|
||||
if ((token & VS_BIT_PARAM) == 0) {
|
||||
|
||||
// RSQ swizzle fixup
|
||||
if (opcode == D3DSIO_RSQ) {
|
||||
// Swizzle fixup for opcodes that require explicit use of a replicate swizzle.
|
||||
if (opcode == D3DSIO_RSQ || opcode == D3DSIO_RCP
|
||||
|| opcode == D3DSIO_EXP || opcode == D3DSIO_LOG
|
||||
|| opcode == D3DSIO_EXPP || opcode == D3DSIO_LOGP) {
|
||||
tokens.push_back(token); // instr
|
||||
tokens.push_back(token = pFunction[i++]); // dest
|
||||
token = pFunction[i++]; // src0
|
||||
|
@ -333,4 +334,5 @@ namespace dxvk {
|
|||
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,49 +1,109 @@
|
|||
#include "d3d8_device.h"
|
||||
#include "d3d8_state_block.h"
|
||||
|
||||
HRESULT dxvk::D3D8StateBlock::Capture() {
|
||||
if (unlikely(m_stateBlock == nullptr))
|
||||
return D3DERR_INVALIDCALL;
|
||||
namespace dxvk {
|
||||
|
||||
if (m_capture.vs) m_device->GetVertexShader(&m_vertexShader);
|
||||
if (m_capture.ps) m_device->GetPixelShader(&m_pixelShader);
|
||||
D3D8StateBlock::D3D8StateBlock(
|
||||
D3D8Device* pDevice,
|
||||
D3DSTATEBLOCKTYPE Type,
|
||||
Com<d3d9::IDirect3DStateBlock9>&& pStateBlock)
|
||||
: m_device(pDevice)
|
||||
, m_stateBlock(std::move(pStateBlock))
|
||||
, m_type(Type)
|
||||
, m_isSWVP(pDevice->GetD3D9()->GetSoftwareVertexProcessing()) {
|
||||
if (Type == D3DSBT_VERTEXSTATE || Type == D3DSBT_ALL) {
|
||||
// Lights, D3DTSS_TEXCOORDINDEX and D3DTSS_TEXTURETRANSFORMFLAGS,
|
||||
// vertex shader, VS constants, and various render states.
|
||||
m_capture.vs = true;
|
||||
}
|
||||
|
||||
for (DWORD stage = 0; stage < m_textures.size(); stage++) {
|
||||
if (m_capture.textures.get(stage))
|
||||
m_textures[stage] = m_device->m_textures[stage].ptr();
|
||||
if (Type == D3DSBT_PIXELSTATE || Type == D3DSBT_ALL) {
|
||||
// Pixel shader, PS constants, and various RS/TSS states.
|
||||
m_capture.ps = true;
|
||||
}
|
||||
|
||||
if (Type == D3DSBT_ALL) {
|
||||
m_capture.indices = true;
|
||||
m_capture.swvp = true;
|
||||
m_capture.textures.setAll();
|
||||
m_capture.streams.setAll();
|
||||
}
|
||||
|
||||
m_textures.fill(nullptr);
|
||||
m_streams.fill(D3D8VBOP());
|
||||
}
|
||||
|
||||
if (m_capture.indices) {
|
||||
m_baseVertexIndex = m_device->m_baseVertexIndex;
|
||||
m_indices = m_device->m_indices.ptr();
|
||||
// Construct a state block without a D3D9 object
|
||||
D3D8StateBlock::D3D8StateBlock(D3D8Device* pDevice)
|
||||
: D3D8StateBlock(pDevice, D3DSTATEBLOCKTYPE(0), nullptr) {
|
||||
}
|
||||
|
||||
if (m_capture.swvp)
|
||||
m_device->GetRenderState(D3DRS_SOFTWAREVERTEXPROCESSING, (DWORD*)&m_isSWVP);
|
||||
// Attach a D3D9 object to a state block that doesn't have one yet
|
||||
void D3D8StateBlock::SetD3D9(Com<d3d9::IDirect3DStateBlock9>&& pStateBlock) {
|
||||
if (likely(m_stateBlock == nullptr)) {
|
||||
m_stateBlock = std::move(pStateBlock);
|
||||
} else {
|
||||
Logger::err("D3D8StateBlock::SetD3D9: m_stateBlock has already been initialized");
|
||||
}
|
||||
}
|
||||
|
||||
HRESULT D3D8StateBlock::Capture() {
|
||||
if (unlikely(m_stateBlock == nullptr))
|
||||
return D3DERR_INVALIDCALL;
|
||||
|
||||
if (m_capture.vs) m_device->GetVertexShader(&m_vertexShader);
|
||||
if (m_capture.ps) m_device->GetPixelShader(&m_pixelShader);
|
||||
|
||||
for (DWORD stage = 0; stage < m_textures.size(); stage++) {
|
||||
if (m_capture.textures.get(stage))
|
||||
m_textures[stage] = m_device->m_textures[stage].ptr();
|
||||
}
|
||||
|
||||
for (DWORD stream = 0; stream < m_streams.size(); stream++) {
|
||||
if (m_capture.streams.get(stream)) {
|
||||
m_streams[stream].buffer = m_device->m_streams[stream].buffer.ptr();
|
||||
m_streams[stream].stride = m_device->m_streams[stream].stride;
|
||||
}
|
||||
}
|
||||
|
||||
if (m_capture.indices) {
|
||||
m_baseVertexIndex = m_device->m_baseVertexIndex;
|
||||
m_indices = m_device->m_indices.ptr();
|
||||
}
|
||||
|
||||
if (m_capture.swvp)
|
||||
m_device->GetRenderState(D3DRS_SOFTWAREVERTEXPROCESSING, (DWORD*)&m_isSWVP);
|
||||
|
||||
return m_stateBlock->Capture();
|
||||
}
|
||||
|
||||
HRESULT D3D8StateBlock::Apply() {
|
||||
if (unlikely(m_stateBlock == nullptr))
|
||||
return D3DERR_INVALIDCALL;
|
||||
|
||||
HRESULT res = m_stateBlock->Apply();
|
||||
|
||||
if (m_capture.vs) m_device->SetVertexShader(m_vertexShader);
|
||||
if (m_capture.ps) m_device->SetPixelShader(m_pixelShader);
|
||||
|
||||
for (DWORD stage = 0; stage < m_textures.size(); stage++) {
|
||||
if (m_capture.textures.get(stage))
|
||||
m_device->SetTexture(stage, m_textures[stage]);
|
||||
}
|
||||
|
||||
for (DWORD stream = 0; stream < m_streams.size(); stream++) {
|
||||
if (m_capture.streams.get(stream))
|
||||
m_device->SetStreamSource(stream, m_streams[stream].buffer, m_streams[stream].stride);
|
||||
}
|
||||
|
||||
if (m_capture.indices)
|
||||
m_device->SetIndices(m_indices, m_baseVertexIndex);
|
||||
|
||||
// This was a very easy footgun for D3D8 applications.
|
||||
if (m_capture.swvp)
|
||||
m_device->SetRenderState(D3DRS_SOFTWAREVERTEXPROCESSING, m_isSWVP);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
return m_stateBlock->Capture();
|
||||
}
|
||||
|
||||
HRESULT dxvk::D3D8StateBlock::Apply() {
|
||||
if (unlikely(m_stateBlock == nullptr))
|
||||
return D3DERR_INVALIDCALL;
|
||||
|
||||
HRESULT res = m_stateBlock->Apply();
|
||||
|
||||
if (m_capture.vs) m_device->SetVertexShader(m_vertexShader);
|
||||
if (m_capture.ps) m_device->SetPixelShader(m_pixelShader);
|
||||
|
||||
for (DWORD stage = 0; stage < m_textures.size(); stage++) {
|
||||
if (m_capture.textures.get(stage))
|
||||
m_device->SetTexture(stage, m_textures[stage]);
|
||||
}
|
||||
|
||||
if (m_capture.indices)
|
||||
m_device->SetIndices(m_indices, m_baseVertexIndex);
|
||||
|
||||
// This was a very easy footgun for D3D8 applications.
|
||||
if (m_capture.swvp)
|
||||
m_device->SetRenderState(D3DRS_SOFTWAREVERTEXPROCESSING, m_isSWVP);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
|
|
@ -1,134 +1,120 @@
|
|||
#pragma once
|
||||
|
||||
#include "d3d8_caps.h"
|
||||
#include "d3d8_include.h"
|
||||
#include "d3d8_device.h"
|
||||
#include "d3d8_device_child.h"
|
||||
|
||||
#include <array>
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
struct D3D8StateCapture {
|
||||
bool vs : 1;
|
||||
bool ps : 1;
|
||||
bool indices : 1;
|
||||
bool swvp : 1;
|
||||
|
||||
bit::bitset<d8caps::MAX_TEXTURE_STAGES> textures;
|
||||
|
||||
D3D8StateCapture()
|
||||
: vs(false)
|
||||
, ps(false)
|
||||
, indices(false)
|
||||
, swvp(false) {
|
||||
// Ensure all bits are initialized to false
|
||||
textures.clearAll();
|
||||
}
|
||||
};
|
||||
|
||||
// Wrapper class for D3D9 state blocks. Captures D3D8-specific state.
|
||||
class D3D8StateBlock {
|
||||
|
||||
public:
|
||||
|
||||
D3D8StateBlock(
|
||||
D3D8Device* pDevice,
|
||||
D3DSTATEBLOCKTYPE Type,
|
||||
Com<d3d9::IDirect3DStateBlock9>&& pStateBlock)
|
||||
: m_device(pDevice)
|
||||
, m_stateBlock(std::move(pStateBlock))
|
||||
, m_type(Type) {
|
||||
if (Type == D3DSBT_VERTEXSTATE || Type == D3DSBT_ALL) {
|
||||
// Lights, D3DTSS_TEXCOORDINDEX and D3DTSS_TEXTURETRANSFORMFLAGS,
|
||||
// vertex shader, VS constants, and various render states.
|
||||
m_capture.vs = true;
|
||||
}
|
||||
|
||||
if (Type == D3DSBT_PIXELSTATE || Type == D3DSBT_ALL) {
|
||||
// Pixel shader, PS constants, and various RS/TSS states.
|
||||
m_capture.ps = true;
|
||||
}
|
||||
|
||||
if (Type == D3DSBT_ALL) {
|
||||
m_capture.indices = true;
|
||||
m_capture.swvp = true;
|
||||
m_capture.textures.setAll();
|
||||
}
|
||||
|
||||
m_textures.fill(nullptr);
|
||||
}
|
||||
|
||||
~D3D8StateBlock() {}
|
||||
|
||||
// Construct a state block without a D3D9 object
|
||||
D3D8StateBlock(D3D8Device* pDevice)
|
||||
: D3D8StateBlock(pDevice, D3DSTATEBLOCKTYPE(0), nullptr) {
|
||||
}
|
||||
|
||||
// Attach a D3D9 object to a state block that doesn't have one yet
|
||||
void SetD3D9(Com<d3d9::IDirect3DStateBlock9>&& pStateBlock) {
|
||||
if (likely(m_stateBlock == nullptr)) {
|
||||
m_stateBlock = std::move(pStateBlock);
|
||||
} else {
|
||||
Logger::err("D3D8StateBlock::SetD3D9 called when m_stateBlock has already been initialized");
|
||||
}
|
||||
}
|
||||
|
||||
HRESULT Capture();
|
||||
|
||||
HRESULT Apply();
|
||||
|
||||
inline HRESULT SetVertexShader(DWORD Handle) {
|
||||
m_vertexShader = Handle;
|
||||
m_capture.vs = true;
|
||||
return D3D_OK;
|
||||
}
|
||||
|
||||
inline HRESULT SetPixelShader(DWORD Handle) {
|
||||
m_pixelShader = Handle;
|
||||
m_capture.ps = true;
|
||||
return D3D_OK;
|
||||
}
|
||||
|
||||
inline HRESULT SetTexture(DWORD Stage, IDirect3DBaseTexture8* pTexture) {
|
||||
m_textures[Stage] = pTexture;
|
||||
m_capture.textures.set(Stage, true);
|
||||
return D3D_OK;
|
||||
}
|
||||
|
||||
inline HRESULT SetIndices(IDirect3DIndexBuffer8* pIndexData, UINT BaseVertexIndex) {
|
||||
m_indices = pIndexData;
|
||||
m_baseVertexIndex = BaseVertexIndex;
|
||||
m_capture.indices = true;
|
||||
return D3D_OK;
|
||||
}
|
||||
|
||||
inline HRESULT SetSoftwareVertexProcessing(bool value) {
|
||||
m_isSWVP = value;
|
||||
m_capture.swvp = true;
|
||||
return D3D_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
D3D8Device* m_device;
|
||||
Com<d3d9::IDirect3DStateBlock9> m_stateBlock;
|
||||
D3DSTATEBLOCKTYPE m_type;
|
||||
|
||||
private: // State Data //
|
||||
|
||||
D3D8StateCapture m_capture;
|
||||
|
||||
DWORD m_vertexShader; // vs
|
||||
DWORD m_pixelShader; // ps
|
||||
|
||||
std::array<IDirect3DBaseTexture8*, d8caps::MAX_TEXTURE_STAGES> m_textures; // textures
|
||||
|
||||
IDirect3DIndexBuffer8* m_indices = nullptr; // indices
|
||||
UINT m_baseVertexIndex; // indices
|
||||
|
||||
bool m_isSWVP; // D3DRS_SOFTWAREVERTEXPROCESSING
|
||||
};
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "d3d8_caps.h"
|
||||
#include "d3d8_include.h"
|
||||
#include "d3d8_device.h"
|
||||
#include "d3d8_device_child.h"
|
||||
|
||||
#include "../util/util_bit.h"
|
||||
|
||||
#include <array>
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
struct D3D8StateCapture {
|
||||
bool vs : 1;
|
||||
bool ps : 1;
|
||||
bool indices : 1;
|
||||
bool swvp : 1;
|
||||
|
||||
bit::bitset<d8caps::MAX_TEXTURE_STAGES> textures;
|
||||
bit::bitset<d8caps::MAX_STREAMS> streams;
|
||||
|
||||
D3D8StateCapture()
|
||||
: vs(false)
|
||||
, ps(false)
|
||||
, indices(false)
|
||||
, swvp(false) {
|
||||
// Ensure all bits are initialized to false
|
||||
textures.clearAll();
|
||||
streams.clearAll();
|
||||
}
|
||||
};
|
||||
|
||||
// Wrapper class for D3D9 state blocks. Captures D3D8-specific state.
|
||||
class D3D8StateBlock {
|
||||
|
||||
public:
|
||||
|
||||
D3D8StateBlock(
|
||||
D3D8Device* pDevice,
|
||||
D3DSTATEBLOCKTYPE Type,
|
||||
Com<d3d9::IDirect3DStateBlock9>&& pStateBlock);
|
||||
|
||||
D3D8StateBlock(D3D8Device* pDevice);
|
||||
|
||||
void SetD3D9(Com<d3d9::IDirect3DStateBlock9>&& pStateBlock);
|
||||
|
||||
HRESULT Capture();
|
||||
|
||||
HRESULT Apply();
|
||||
|
||||
inline HRESULT SetVertexShader(DWORD Handle) {
|
||||
m_vertexShader = Handle;
|
||||
m_capture.vs = true;
|
||||
return D3D_OK;
|
||||
}
|
||||
|
||||
inline HRESULT SetPixelShader(DWORD Handle) {
|
||||
m_pixelShader = Handle;
|
||||
m_capture.ps = true;
|
||||
return D3D_OK;
|
||||
}
|
||||
|
||||
inline HRESULT SetTexture(DWORD Stage, IDirect3DBaseTexture8* pTexture) {
|
||||
m_textures[Stage] = pTexture;
|
||||
m_capture.textures.set(Stage, true);
|
||||
return D3D_OK;
|
||||
}
|
||||
|
||||
inline HRESULT SetStreamSource(UINT StreamNumber, IDirect3DVertexBuffer8* pStreamData, UINT Stride) {
|
||||
m_streams[StreamNumber].buffer = pStreamData;
|
||||
// The previous stride is preserved if pStreamData is NULL
|
||||
if (likely(pStreamData != nullptr))
|
||||
m_streams[StreamNumber].stride = Stride;
|
||||
m_capture.streams.set(StreamNumber, true);
|
||||
return D3D_OK;
|
||||
}
|
||||
|
||||
inline HRESULT SetIndices(IDirect3DIndexBuffer8* pIndexData, UINT BaseVertexIndex) {
|
||||
m_indices = pIndexData;
|
||||
m_baseVertexIndex = BaseVertexIndex;
|
||||
m_capture.indices = true;
|
||||
return D3D_OK;
|
||||
}
|
||||
|
||||
inline HRESULT SetSoftwareVertexProcessing(bool value) {
|
||||
m_isSWVP = value;
|
||||
m_capture.swvp = true;
|
||||
return D3D_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
D3D8Device* m_device;
|
||||
Com<d3d9::IDirect3DStateBlock9> m_stateBlock;
|
||||
D3DSTATEBLOCKTYPE m_type;
|
||||
|
||||
struct D3D8VBOP {
|
||||
IDirect3DVertexBuffer8* buffer = nullptr;
|
||||
UINT stride = 0;
|
||||
};
|
||||
|
||||
// State Data //
|
||||
|
||||
D3D8StateCapture m_capture;
|
||||
|
||||
DWORD m_vertexShader = 0;
|
||||
DWORD m_pixelShader = 0;
|
||||
|
||||
std::array<IDirect3DBaseTexture8*, d8caps::MAX_TEXTURE_STAGES> m_textures;
|
||||
std::array<D3D8VBOP, d8caps::MAX_STREAMS> m_streams;
|
||||
|
||||
IDirect3DIndexBuffer8* m_indices = nullptr;
|
||||
UINT m_baseVertexIndex = 0;
|
||||
|
||||
bool m_isSWVP; // D3DRS_SOFTWAREVERTEXPROCESSING
|
||||
|
||||
};
|
||||
|
||||
}
|
|
@ -16,15 +16,13 @@ namespace dxvk {
|
|||
|
||||
D3D8Subresource(
|
||||
D3D8Device* pDevice,
|
||||
const D3DPOOL Pool,
|
||||
Com<D3D9>&& Object,
|
||||
IDirect3DBaseTexture8* pBaseTexture)
|
||||
: Resource(pDevice, std::move(Object)),
|
||||
: Resource(pDevice, Pool, std::move(Object)),
|
||||
m_container(pBaseTexture) {
|
||||
}
|
||||
|
||||
~D3D8Subresource() {
|
||||
}
|
||||
|
||||
// Refing subresources implicitly refs the container texture,
|
||||
ULONG STDMETHODCALLTYPE AddRef() final {
|
||||
if (m_container != nullptr)
|
||||
|
@ -56,6 +54,7 @@ namespace dxvk {
|
|||
protected:
|
||||
|
||||
IDirect3DBaseTexture8* m_container;
|
||||
|
||||
};
|
||||
|
||||
}
|
|
@ -1,26 +1,78 @@
|
|||
|
||||
#include "d3d8_surface.h"
|
||||
#include "d3d8_device.h"
|
||||
|
||||
#include "d3d8_d3d9_util.h"
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
Com<d3d9::IDirect3DSurface9> D3D8Surface::CreateBlitImage() {
|
||||
d3d9::D3DSURFACE_DESC desc;
|
||||
GetD3D9()->GetDesc(&desc);
|
||||
D3D8Surface::D3D8Surface(
|
||||
D3D8Device* pDevice,
|
||||
const D3DPOOL Pool,
|
||||
IDirect3DBaseTexture8* pTexture,
|
||||
Com<d3d9::IDirect3DSurface9>&& pSurface)
|
||||
: D3D8SurfaceBase (pDevice, Pool, std::move(pSurface), pTexture) {
|
||||
}
|
||||
|
||||
// NOTE: This adds a D3DPOOL_DEFAULT resource to the
|
||||
// device, which counts as losable during device reset
|
||||
Com<d3d9::IDirect3DSurface9> image = nullptr;
|
||||
HRESULT res = GetParent()->GetD3D9()->CreateRenderTarget(
|
||||
desc.Width, desc.Height, desc.Format,
|
||||
d3d9::D3DMULTISAMPLE_NONE, 0,
|
||||
FALSE,
|
||||
&image,
|
||||
NULL);
|
||||
|
||||
if (FAILED(res))
|
||||
throw new DxvkError("D3D8: Failed to create blit image");
|
||||
|
||||
return image;
|
||||
// A surface does not need to be attached to a texture
|
||||
D3D8Surface::D3D8Surface(
|
||||
D3D8Device* pDevice,
|
||||
const D3DPOOL Pool,
|
||||
Com<d3d9::IDirect3DSurface9>&& pSurface)
|
||||
: D3D8Surface (pDevice, Pool, nullptr, std::move(pSurface)) {
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE D3D8Surface::GetDesc(D3DSURFACE_DESC* pDesc) {
|
||||
if (unlikely(pDesc == nullptr))
|
||||
return D3DERR_INVALIDCALL;
|
||||
|
||||
d3d9::D3DSURFACE_DESC desc;
|
||||
HRESULT res = GetD3D9()->GetDesc(&desc);
|
||||
|
||||
if (likely(SUCCEEDED(res)))
|
||||
ConvertSurfaceDesc8(&desc, pDesc);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE D3D8Surface::LockRect(
|
||||
D3DLOCKED_RECT* pLockedRect,
|
||||
CONST RECT* pRect,
|
||||
DWORD Flags) {
|
||||
return GetD3D9()->LockRect((d3d9::D3DLOCKED_RECT*)pLockedRect, pRect, Flags);
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE D3D8Surface::UnlockRect() {
|
||||
return GetD3D9()->UnlockRect();
|
||||
}
|
||||
|
||||
// TODO: Consider creating only one texture to
|
||||
// encompass all surface levels of a texture.
|
||||
Com<d3d9::IDirect3DSurface9> D3D8Surface::GetBlitImage() {
|
||||
if (unlikely(m_blitImage == nullptr)) {
|
||||
m_blitImage = CreateBlitImage();
|
||||
}
|
||||
|
||||
return m_blitImage;
|
||||
}
|
||||
|
||||
Com<d3d9::IDirect3DSurface9> D3D8Surface::CreateBlitImage() {
|
||||
d3d9::D3DSURFACE_DESC desc;
|
||||
GetD3D9()->GetDesc(&desc);
|
||||
|
||||
// NOTE: This adds a D3DPOOL_DEFAULT resource to the
|
||||
// device, which counts as losable during device reset
|
||||
Com<d3d9::IDirect3DSurface9> image = nullptr;
|
||||
HRESULT res = GetParent()->GetD3D9()->CreateRenderTarget(
|
||||
desc.Width, desc.Height, desc.Format,
|
||||
d3d9::D3DMULTISAMPLE_NONE, 0,
|
||||
FALSE,
|
||||
&image,
|
||||
NULL);
|
||||
|
||||
if (FAILED(res))
|
||||
throw new DxvkError("D3D8: Failed to create blit image");
|
||||
|
||||
return image;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,81 +1,50 @@
|
|||
#pragma once
|
||||
|
||||
#include "d3d8_include.h"
|
||||
#include "d3d8_subresource.h"
|
||||
#include "d3d8_d3d9_util.h"
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
// TODO: all inherited methods in D3D8Surface should be final like in d9vk
|
||||
|
||||
using D3D8SurfaceBase = D3D8Subresource<d3d9::IDirect3DSurface9, IDirect3DSurface8>;
|
||||
class D3D8Surface final : public D3D8SurfaceBase {
|
||||
|
||||
public:
|
||||
|
||||
D3D8Surface(
|
||||
D3D8Device* pDevice,
|
||||
IDirect3DBaseTexture8* pTexture,
|
||||
Com<d3d9::IDirect3DSurface9>&& pSurface)
|
||||
: D3D8SurfaceBase (pDevice, std::move(pSurface), pTexture) {
|
||||
}
|
||||
|
||||
// A surface does not need to be attached to a texture
|
||||
D3D8Surface(
|
||||
D3D8Device* pDevice,
|
||||
Com<d3d9::IDirect3DSurface9>&& pSurface)
|
||||
: D3D8Surface (pDevice, nullptr, std::move(pSurface)) {
|
||||
}
|
||||
|
||||
D3DRESOURCETYPE STDMETHODCALLTYPE GetType() {
|
||||
return D3DRESOURCETYPE(GetD3D9()->GetType());
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE GetDesc(D3DSURFACE_DESC* pDesc) {
|
||||
d3d9::D3DSURFACE_DESC desc;
|
||||
HRESULT res = GetD3D9()->GetDesc(&desc);
|
||||
ConvertSurfaceDesc8(&desc, pDesc);
|
||||
return res;
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE LockRect(D3DLOCKED_RECT* pLockedRect, CONST RECT* pRect, DWORD Flags) {
|
||||
return GetD3D9()->LockRect((d3d9::D3DLOCKED_RECT*)pLockedRect, pRect, Flags);
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE UnlockRect() {
|
||||
return GetD3D9()->UnlockRect();
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE GetDC(HDC* phDC) {
|
||||
return GetD3D9()->GetDC(phDC);
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE ReleaseDC(HDC hDC) {
|
||||
return GetD3D9()->ReleaseDC(hDC);
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* \brief Allocate or reuse an image of the same size
|
||||
* as this texture for performing blit into system mem.
|
||||
*
|
||||
* TODO: Consider creating only one texture to
|
||||
* encompass all surface levels of a texture.
|
||||
*/
|
||||
Com<d3d9::IDirect3DSurface9> GetBlitImage() {
|
||||
if (unlikely(m_blitImage == nullptr)) {
|
||||
m_blitImage = CreateBlitImage();
|
||||
}
|
||||
|
||||
return m_blitImage;
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
Com<d3d9::IDirect3DSurface9> CreateBlitImage();
|
||||
|
||||
Com<d3d9::IDirect3DSurface9> m_blitImage = nullptr;
|
||||
|
||||
};
|
||||
#pragma once
|
||||
|
||||
#include "d3d8_include.h"
|
||||
#include "d3d8_subresource.h"
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
// Note: IDirect3DSurface8 does not actually inherit from IDirect3DResource8,
|
||||
// however it does expose serveral of the methods typically found part of
|
||||
// IDirect3DResource8, such as Set/Get/FreePrivateData, so model it as such.
|
||||
using D3D8SurfaceBase = D3D8Subresource<d3d9::IDirect3DSurface9, IDirect3DSurface8>;
|
||||
class D3D8Surface final : public D3D8SurfaceBase {
|
||||
|
||||
public:
|
||||
|
||||
D3D8Surface(
|
||||
D3D8Device* pDevice,
|
||||
const D3DPOOL Pool,
|
||||
IDirect3DBaseTexture8* pTexture,
|
||||
Com<d3d9::IDirect3DSurface9>&& pSurface);
|
||||
|
||||
D3D8Surface(
|
||||
D3D8Device* pDevice,
|
||||
const D3DPOOL Pool,
|
||||
Com<d3d9::IDirect3DSurface9>&& pSurface);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE GetDesc(D3DSURFACE_DESC* pDesc) final;
|
||||
|
||||
HRESULT STDMETHODCALLTYPE LockRect(
|
||||
D3DLOCKED_RECT* pLockedRect,
|
||||
CONST RECT* pRect,
|
||||
DWORD Flags) final;
|
||||
|
||||
HRESULT STDMETHODCALLTYPE UnlockRect() final;
|
||||
|
||||
/**
|
||||
* \brief Allocate or reuse an image of the same size
|
||||
* as this texture for performing blit into system mem.
|
||||
*/
|
||||
Com<d3d9::IDirect3DSurface9> GetBlitImage();
|
||||
|
||||
private:
|
||||
|
||||
Com<d3d9::IDirect3DSurface9> CreateBlitImage();
|
||||
|
||||
Com<d3d9::IDirect3DSurface9> m_blitImage;
|
||||
|
||||
};
|
||||
|
||||
}
|
41
src/d3d8/d3d8_swapchain.cpp
Normal file
41
src/d3d8/d3d8_swapchain.cpp
Normal file
|
@ -0,0 +1,41 @@
|
|||
#include "d3d8_swapchain.h"
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
D3D8SwapChain::D3D8SwapChain(
|
||||
D3D8Device* pDevice,
|
||||
D3DPRESENT_PARAMETERS* pPresentationParameters,
|
||||
Com<d3d9::IDirect3DSwapChain9>&& pSwapChain)
|
||||
: D3D8SwapChainBase(pDevice, std::move(pSwapChain)) {
|
||||
m_backBuffers.resize(pPresentationParameters->BackBufferCount);
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE D3D8SwapChain::Present(const RECT *src, const RECT *dst, HWND hWnd, const RGNDATA *dirtyRegion) {
|
||||
return GetD3D9()->Present(src, dst, hWnd, dirtyRegion, 0);
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE D3D8SwapChain::GetBackBuffer(
|
||||
UINT BackBuffer,
|
||||
D3DBACKBUFFER_TYPE Type,
|
||||
IDirect3DSurface8** ppBackBuffer) {
|
||||
if (unlikely(ppBackBuffer == nullptr))
|
||||
return D3DERR_INVALIDCALL;
|
||||
|
||||
// Same logic as in D3D8Device::GetBackBuffer
|
||||
if (BackBuffer >= m_backBuffers.size() || m_backBuffers[BackBuffer] == nullptr) {
|
||||
Com<d3d9::IDirect3DSurface9> pSurface9;
|
||||
HRESULT res = GetD3D9()->GetBackBuffer(BackBuffer, (d3d9::D3DBACKBUFFER_TYPE)Type, &pSurface9);
|
||||
|
||||
if (likely(SUCCEEDED(res))) {
|
||||
m_backBuffers[BackBuffer] = new D3D8Surface(GetParent(), D3DPOOL_DEFAULT, std::move(pSurface9));
|
||||
*ppBackBuffer = m_backBuffers[BackBuffer].ref();
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
*ppBackBuffer = m_backBuffers[BackBuffer].ref();
|
||||
return D3D_OK;
|
||||
}
|
||||
|
||||
}
|
|
@ -2,40 +2,29 @@
|
|||
|
||||
#include "d3d8_device_child.h"
|
||||
#include "d3d8_surface.h"
|
||||
#include "d3d8_d3d9_util.h"
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
|
||||
using D3D8SwapChainBase = D3D8DeviceChild<d3d9::IDirect3DSwapChain9, IDirect3DSwapChain8>;
|
||||
class D3D8SwapChain final : public D3D8SwapChainBase {
|
||||
|
||||
public:
|
||||
|
||||
D3D8SwapChain(
|
||||
D3D8Device* pDevice,
|
||||
Com<d3d9::IDirect3DSwapChain9>&& pSwapChain)
|
||||
: D3D8SwapChainBase(pDevice, std::move(pSwapChain)) {}
|
||||
D3D8Device* pDevice,
|
||||
D3DPRESENT_PARAMETERS* pPresentationParameters,
|
||||
Com<d3d9::IDirect3DSwapChain9>&& pSwapChain);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE Present(const RECT *src, const RECT *dst, HWND hWnd, const RGNDATA *dirtyRegion) final {
|
||||
return GetD3D9()->Present(src, dst, hWnd, dirtyRegion, 0);
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE GetBackBuffer(UINT BackBuffer, D3DBACKBUFFER_TYPE Type, IDirect3DSurface8** ppBackBuffer) final {
|
||||
// Same logic as in D3D8Device::GetBackBuffer
|
||||
if (unlikely(m_backBuffer == nullptr)) {
|
||||
Com<d3d9::IDirect3DSurface9> pSurface9;
|
||||
HRESULT res = GetD3D9()->GetBackBuffer(BackBuffer, (d3d9::D3DBACKBUFFER_TYPE)Type, &pSurface9);
|
||||
HRESULT STDMETHODCALLTYPE Present(const RECT *src, const RECT *dst, HWND hWnd, const RGNDATA *dirtyRegion) final;
|
||||
|
||||
m_backBuffer = new D3D8Surface(GetParent(), std::move(pSurface9));
|
||||
*ppBackBuffer = m_backBuffer.ref();
|
||||
return res;
|
||||
}
|
||||
HRESULT STDMETHODCALLTYPE GetBackBuffer(
|
||||
UINT BackBuffer,
|
||||
D3DBACKBUFFER_TYPE Type,
|
||||
IDirect3DSurface8** ppBackBuffer) final;
|
||||
|
||||
*ppBackBuffer = m_backBuffer.ref();
|
||||
return D3D_OK;
|
||||
}
|
||||
private:
|
||||
Com<D3D8Surface> m_backBuffer = nullptr;
|
||||
|
||||
std::vector<Com<D3D8Surface, false>> m_backBuffers;
|
||||
|
||||
};
|
||||
|
||||
|
|
152
src/d3d8/d3d8_texture.cpp
Normal file
152
src/d3d8/d3d8_texture.cpp
Normal file
|
@ -0,0 +1,152 @@
|
|||
#include "d3d8_texture.h"
|
||||
|
||||
#include "d3d8_d3d9_util.h"
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
// D3D8Texture2D
|
||||
|
||||
D3D8Texture2D::D3D8Texture2D(
|
||||
D3D8Device* pDevice,
|
||||
const D3DPOOL Pool,
|
||||
Com<d3d9::IDirect3DTexture9>&& pTexture)
|
||||
: D3D8Texture2DBase(pDevice, Pool, std::move(pTexture), pTexture->GetLevelCount()) {
|
||||
}
|
||||
|
||||
D3DRESOURCETYPE STDMETHODCALLTYPE D3D8Texture2D::GetType() { return D3DRTYPE_TEXTURE; }
|
||||
|
||||
HRESULT STDMETHODCALLTYPE D3D8Texture2D::GetLevelDesc(UINT Level, D3DSURFACE_DESC* pDesc) {
|
||||
if (unlikely(pDesc == nullptr))
|
||||
return D3DERR_INVALIDCALL;
|
||||
|
||||
d3d9::D3DSURFACE_DESC surf;
|
||||
HRESULT res = GetD3D9()->GetLevelDesc(Level, &surf);
|
||||
|
||||
if (likely(SUCCEEDED(res)))
|
||||
ConvertSurfaceDesc8(&surf, pDesc);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE D3D8Texture2D::GetSurfaceLevel(UINT Level, IDirect3DSurface8** ppSurfaceLevel) {
|
||||
return GetSubresource(Level, ppSurfaceLevel);
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE D3D8Texture2D::LockRect(
|
||||
UINT Level,
|
||||
D3DLOCKED_RECT* pLockedRect,
|
||||
CONST RECT* pRect,
|
||||
DWORD Flags) {
|
||||
return GetD3D9()->LockRect(Level, reinterpret_cast<d3d9::D3DLOCKED_RECT*>(pLockedRect), pRect, Flags);
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE D3D8Texture2D::UnlockRect(UINT Level) {
|
||||
return GetD3D9()->UnlockRect(Level);
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE D3D8Texture2D::AddDirtyRect(CONST RECT* pDirtyRect) {
|
||||
return GetD3D9()->AddDirtyRect(pDirtyRect);
|
||||
}
|
||||
|
||||
// D3D8Texture3D
|
||||
|
||||
D3D8Texture3D::D3D8Texture3D(
|
||||
D3D8Device* pDevice,
|
||||
const D3DPOOL Pool,
|
||||
Com<d3d9::IDirect3DVolumeTexture9>&& pVolumeTexture)
|
||||
: D3D8Texture3DBase(pDevice, Pool, std::move(pVolumeTexture), pVolumeTexture->GetLevelCount()) {}
|
||||
|
||||
D3DRESOURCETYPE STDMETHODCALLTYPE D3D8Texture3D::GetType() { return D3DRTYPE_VOLUMETEXTURE; }
|
||||
|
||||
HRESULT STDMETHODCALLTYPE D3D8Texture3D::GetLevelDesc(UINT Level, D3DVOLUME_DESC *pDesc) {
|
||||
if (unlikely(pDesc == nullptr))
|
||||
return D3DERR_INVALIDCALL;
|
||||
|
||||
d3d9::D3DVOLUME_DESC vol;
|
||||
HRESULT res = GetD3D9()->GetLevelDesc(Level, &vol);
|
||||
|
||||
if (likely(SUCCEEDED(res)))
|
||||
ConvertVolumeDesc8(&vol, pDesc);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE D3D8Texture3D::GetVolumeLevel(UINT Level, IDirect3DVolume8** ppVolumeLevel) {
|
||||
return GetSubresource(Level, ppVolumeLevel);
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE D3D8Texture3D::LockBox(
|
||||
UINT Level,
|
||||
D3DLOCKED_BOX* pLockedBox,
|
||||
CONST D3DBOX* pBox,
|
||||
DWORD Flags) {
|
||||
return GetD3D9()->LockBox(
|
||||
Level,
|
||||
reinterpret_cast<d3d9::D3DLOCKED_BOX*>(pLockedBox),
|
||||
reinterpret_cast<const d3d9::D3DBOX*>(pBox),
|
||||
Flags
|
||||
);
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE D3D8Texture3D::UnlockBox(UINT Level) {
|
||||
return GetD3D9()->UnlockBox(Level);
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE D3D8Texture3D::AddDirtyBox(CONST D3DBOX* pDirtyBox) {
|
||||
return GetD3D9()->AddDirtyBox(reinterpret_cast<const d3d9::D3DBOX*>(pDirtyBox));
|
||||
}
|
||||
|
||||
// D3D8TextureCube
|
||||
|
||||
D3D8TextureCube::D3D8TextureCube(
|
||||
D3D8Device* pDevice,
|
||||
const D3DPOOL Pool,
|
||||
Com<d3d9::IDirect3DCubeTexture9>&& pTexture)
|
||||
: D3D8TextureCubeBase(pDevice, Pool, std::move(pTexture), pTexture->GetLevelCount() * CUBE_FACES) {
|
||||
}
|
||||
|
||||
D3DRESOURCETYPE STDMETHODCALLTYPE D3D8TextureCube::GetType() { return D3DRTYPE_CUBETEXTURE; }
|
||||
|
||||
HRESULT STDMETHODCALLTYPE D3D8TextureCube::GetLevelDesc(UINT Level, D3DSURFACE_DESC* pDesc) {
|
||||
if (unlikely(pDesc == nullptr))
|
||||
return D3DERR_INVALIDCALL;
|
||||
|
||||
d3d9::D3DSURFACE_DESC surf;
|
||||
HRESULT res = GetD3D9()->GetLevelDesc(Level, &surf);
|
||||
|
||||
if (likely(SUCCEEDED(res)))
|
||||
ConvertSurfaceDesc8(&surf, pDesc);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE D3D8TextureCube::GetCubeMapSurface(
|
||||
D3DCUBEMAP_FACES Face,
|
||||
UINT Level,
|
||||
IDirect3DSurface8** ppSurfaceLevel) {
|
||||
return GetSubresource((Level * CUBE_FACES) + Face, ppSurfaceLevel);
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE D3D8TextureCube::LockRect(
|
||||
D3DCUBEMAP_FACES Face,
|
||||
UINT Level,
|
||||
D3DLOCKED_RECT* pLockedRect,
|
||||
const RECT* pRect,
|
||||
DWORD Flags) {
|
||||
return GetD3D9()->LockRect(
|
||||
d3d9::D3DCUBEMAP_FACES(Face),
|
||||
Level,
|
||||
reinterpret_cast<d3d9::D3DLOCKED_RECT*>(pLockedRect),
|
||||
pRect,
|
||||
Flags);
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE D3D8TextureCube::UnlockRect(D3DCUBEMAP_FACES Face, UINT Level) {
|
||||
return GetD3D9()->UnlockRect(d3d9::D3DCUBEMAP_FACES(Face), Level);
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE D3D8TextureCube::AddDirtyRect(D3DCUBEMAP_FACES Face, const RECT* pDirtyRect) {
|
||||
return GetD3D9()->AddDirtyRect(d3d9::D3DCUBEMAP_FACES(Face), pDirtyRect);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,233 +1,197 @@
|
|||
#pragma once
|
||||
|
||||
#include "d3d8_resource.h"
|
||||
#include "d3d8_surface.h"
|
||||
#include "d3d8_volume.h"
|
||||
|
||||
#include "d3d8_d3d9_util.h"
|
||||
|
||||
#include <vector>
|
||||
#include <new>
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
template <typename SubresourceType, typename D3D9, typename D3D8>
|
||||
class D3D8BaseTexture : public D3D8Resource<D3D9, D3D8> {
|
||||
|
||||
public:
|
||||
|
||||
constexpr static UINT CUBE_FACES = 6;
|
||||
|
||||
using SubresourceType8 = typename SubresourceType::D3D8;
|
||||
using SubresourceType9 = typename SubresourceType::D3D9;
|
||||
|
||||
D3D8BaseTexture(
|
||||
D3D8Device* pDevice,
|
||||
Com<D3D9>&& pBaseTexture,
|
||||
UINT SubresourceCount)
|
||||
: D3D8Resource<D3D9, D3D8> ( pDevice, std::move(pBaseTexture) ) {
|
||||
m_subresources.resize(SubresourceCount, nullptr);
|
||||
}
|
||||
|
||||
~D3D8BaseTexture() {
|
||||
for (size_t i = 0; i < m_subresources.size(); i++)
|
||||
if (m_subresources[i] != nullptr)
|
||||
m_subresources[i] = nullptr;
|
||||
}
|
||||
|
||||
virtual IUnknown* GetInterface(REFIID riid) final override try {
|
||||
return D3D8Resource<D3D9, D3D8>::GetInterface(riid);
|
||||
} catch (HRESULT err) {
|
||||
if (riid == __uuidof(IDirect3DBaseTexture8))
|
||||
return this;
|
||||
|
||||
throw err;
|
||||
}
|
||||
|
||||
void STDMETHODCALLTYPE PreLoad() final {
|
||||
this->GetD3D9()->PreLoad();
|
||||
}
|
||||
|
||||
DWORD STDMETHODCALLTYPE SetLOD(DWORD LODNew) final {
|
||||
return this->GetD3D9()->SetLOD(LODNew);
|
||||
}
|
||||
|
||||
DWORD STDMETHODCALLTYPE GetLOD() final {
|
||||
return this->GetD3D9()->GetLOD();
|
||||
}
|
||||
|
||||
DWORD STDMETHODCALLTYPE GetLevelCount() final {
|
||||
return this->GetD3D9()->GetLevelCount();
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
HRESULT STDMETHODCALLTYPE GetSubresource(UINT Index, SubresourceType8** ppSubresource) {
|
||||
InitReturnPtr(ppSubresource);
|
||||
|
||||
if (unlikely(Index >= m_subresources.size()))
|
||||
return D3DERR_INVALIDCALL;
|
||||
|
||||
if (m_subresources[Index] == nullptr) {
|
||||
try {
|
||||
Com<SubresourceType9> subresource = LookupSubresource(Index);
|
||||
|
||||
// Cache the subresource
|
||||
m_subresources[Index] = new SubresourceType(this->m_parent, this, std::move(subresource));
|
||||
} catch (HRESULT res) {
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
*ppSubresource = m_subresources[Index].ref();
|
||||
return D3D_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
Com<SubresourceType9> LookupSubresource(UINT Index) {
|
||||
Com<SubresourceType9> ptr = nullptr;
|
||||
HRESULT res = D3DERR_INVALIDCALL;
|
||||
if constexpr (std::is_same_v<D3D8, IDirect3DTexture8>) {
|
||||
res = this->GetD3D9()->GetSurfaceLevel(Index, &ptr);
|
||||
} else if constexpr (std::is_same_v<D3D8, IDirect3DVolume8>) {
|
||||
res = this->GetD3D9()->GetVolumeLevel(Index, &ptr);
|
||||
} else if constexpr (std::is_same_v<D3D8, IDirect3DCubeTexture8>) {
|
||||
res = this->GetD3D9()->GetCubeMapSurface(d3d9::D3DCUBEMAP_FACES(Index % CUBE_FACES), Index / CUBE_FACES, &ptr);
|
||||
}
|
||||
if (FAILED(res))
|
||||
throw res;
|
||||
return ptr;
|
||||
}
|
||||
|
||||
std::vector<Com<SubresourceType, false>> m_subresources;
|
||||
|
||||
};
|
||||
|
||||
using D3D8Texture2DBase = D3D8BaseTexture<D3D8Surface, d3d9::IDirect3DTexture9, IDirect3DTexture8>;
|
||||
class D3D8Texture2D final : public D3D8Texture2DBase {
|
||||
|
||||
public:
|
||||
|
||||
D3D8Texture2D(
|
||||
D3D8Device* pDevice,
|
||||
Com<d3d9::IDirect3DTexture9>&& pTexture)
|
||||
: D3D8Texture2DBase(pDevice, std::move(pTexture), pTexture->GetLevelCount()) {
|
||||
}
|
||||
|
||||
D3DRESOURCETYPE STDMETHODCALLTYPE GetType() final { return D3DRTYPE_TEXTURE; }
|
||||
|
||||
HRESULT STDMETHODCALLTYPE GetLevelDesc(UINT Level, D3DSURFACE_DESC* pDesc) {
|
||||
d3d9::D3DSURFACE_DESC surf;
|
||||
HRESULT res = GetD3D9()->GetLevelDesc(Level, &surf);
|
||||
ConvertSurfaceDesc8(&surf, pDesc);
|
||||
return res;
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE GetSurfaceLevel(UINT Level, IDirect3DSurface8** ppSurfaceLevel) {
|
||||
return GetSubresource(Level, ppSurfaceLevel);
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE LockRect(UINT Level, D3DLOCKED_RECT* pLockedRect, CONST RECT* pRect, DWORD Flags) {
|
||||
return GetD3D9()->LockRect(Level, reinterpret_cast<d3d9::D3DLOCKED_RECT*>(pLockedRect), pRect, Flags);
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE UnlockRect(UINT Level) {
|
||||
return GetD3D9()->UnlockRect(Level);
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE AddDirtyRect(CONST RECT* pDirtyRect) {
|
||||
return GetD3D9()->AddDirtyRect(pDirtyRect);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
using D3D8Texture3DBase = D3D8BaseTexture<D3D8Volume, d3d9::IDirect3DVolumeTexture9, IDirect3DVolumeTexture8>;
|
||||
class D3D8Texture3D final : public D3D8Texture3DBase {
|
||||
|
||||
public:
|
||||
|
||||
D3D8Texture3D(
|
||||
D3D8Device* pDevice,
|
||||
Com<d3d9::IDirect3DVolumeTexture9>&& pVolumeTexture)
|
||||
: D3D8Texture3DBase(pDevice, std::move(pVolumeTexture), pVolumeTexture->GetLevelCount()) {}
|
||||
|
||||
D3DRESOURCETYPE STDMETHODCALLTYPE GetType() final { return D3DRTYPE_VOLUMETEXTURE; }
|
||||
|
||||
HRESULT STDMETHODCALLTYPE GetLevelDesc(UINT Level, D3DVOLUME_DESC *pDesc) {
|
||||
d3d9::D3DVOLUME_DESC vol;
|
||||
HRESULT res = GetD3D9()->GetLevelDesc(Level, &vol);
|
||||
ConvertVolumeDesc8(&vol, pDesc);
|
||||
return res;
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE GetVolumeLevel(UINT Level, IDirect3DVolume8** ppVolumeLevel) {
|
||||
return GetSubresource(Level, ppVolumeLevel);
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE LockBox(UINT Level, D3DLOCKED_BOX* pLockedBox, CONST D3DBOX* pBox, DWORD Flags) {
|
||||
return GetD3D9()->LockBox(
|
||||
Level,
|
||||
reinterpret_cast<d3d9::D3DLOCKED_BOX*>(pLockedBox),
|
||||
reinterpret_cast<const d3d9::D3DBOX*>(pBox),
|
||||
Flags
|
||||
);
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE UnlockBox(UINT Level) {
|
||||
return GetD3D9()->UnlockBox(Level);
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE AddDirtyBox(CONST D3DBOX* pDirtyBox) {
|
||||
return GetD3D9()->AddDirtyBox(reinterpret_cast<const d3d9::D3DBOX*>(pDirtyBox));
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
using D3D8TextureCubeBase = D3D8BaseTexture<D3D8Surface, d3d9::IDirect3DCubeTexture9, IDirect3DCubeTexture8>;
|
||||
class D3D8TextureCube final : public D3D8TextureCubeBase {
|
||||
|
||||
public:
|
||||
|
||||
D3D8TextureCube(
|
||||
D3D8Device* pDevice,
|
||||
Com<d3d9::IDirect3DCubeTexture9>&& pTexture)
|
||||
: D3D8TextureCubeBase(pDevice, std::move(pTexture), pTexture->GetLevelCount() * CUBE_FACES) {
|
||||
}
|
||||
|
||||
D3DRESOURCETYPE STDMETHODCALLTYPE GetType() final { return D3DRTYPE_CUBETEXTURE; }
|
||||
|
||||
HRESULT STDMETHODCALLTYPE GetLevelDesc(UINT Level, D3DSURFACE_DESC* pDesc) {
|
||||
d3d9::D3DSURFACE_DESC surf;
|
||||
HRESULT res = GetD3D9()->GetLevelDesc(Level, &surf);
|
||||
ConvertSurfaceDesc8(&surf, pDesc);
|
||||
return res;
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE GetCubeMapSurface(D3DCUBEMAP_FACES Face, UINT Level, IDirect3DSurface8** ppSurfaceLevel) {
|
||||
return GetSubresource((Level * CUBE_FACES) + Face, ppSurfaceLevel);
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE LockRect(
|
||||
D3DCUBEMAP_FACES Face,
|
||||
UINT Level,
|
||||
D3DLOCKED_RECT* pLockedRect,
|
||||
const RECT* pRect,
|
||||
DWORD Flags) {
|
||||
return GetD3D9()->LockRect(
|
||||
d3d9::D3DCUBEMAP_FACES(Face),
|
||||
Level,
|
||||
reinterpret_cast<d3d9::D3DLOCKED_RECT*>(pLockedRect),
|
||||
pRect,
|
||||
Flags);
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE UnlockRect(D3DCUBEMAP_FACES Face, UINT Level) {
|
||||
return GetD3D9()->UnlockRect(d3d9::D3DCUBEMAP_FACES(Face), Level);
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE AddDirtyRect(D3DCUBEMAP_FACES Face, const RECT* pDirtyRect) {
|
||||
return GetD3D9()->AddDirtyRect(d3d9::D3DCUBEMAP_FACES(Face), pDirtyRect);
|
||||
}
|
||||
};
|
||||
#pragma once
|
||||
|
||||
#include "d3d8_resource.h"
|
||||
#include "d3d8_surface.h"
|
||||
#include "d3d8_volume.h"
|
||||
|
||||
#include <vector>
|
||||
#include <new>
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
template <typename SubresourceType, typename D3D9, typename D3D8>
|
||||
class D3D8BaseTexture : public D3D8Resource<D3D9, D3D8> {
|
||||
|
||||
public:
|
||||
|
||||
constexpr static UINT CUBE_FACES = 6;
|
||||
|
||||
using SubresourceType8 = typename SubresourceType::D3D8;
|
||||
using SubresourceType9 = typename SubresourceType::D3D9;
|
||||
|
||||
D3D8BaseTexture(
|
||||
D3D8Device* pDevice,
|
||||
const D3DPOOL Pool,
|
||||
Com<D3D9>&& pBaseTexture,
|
||||
UINT SubresourceCount)
|
||||
: D3D8Resource<D3D9, D3D8> ( pDevice, Pool, std::move(pBaseTexture) ) {
|
||||
m_subresources.resize(SubresourceCount, nullptr);
|
||||
}
|
||||
|
||||
~D3D8BaseTexture() {
|
||||
for (size_t i = 0; i < m_subresources.size(); i++)
|
||||
if (m_subresources[i] != nullptr)
|
||||
m_subresources[i] = nullptr;
|
||||
}
|
||||
|
||||
virtual IUnknown* GetInterface(REFIID riid) final override try {
|
||||
return D3D8Resource<D3D9, D3D8>::GetInterface(riid);
|
||||
} catch (HRESULT err) {
|
||||
if (riid == __uuidof(IDirect3DBaseTexture8))
|
||||
return this;
|
||||
|
||||
throw err;
|
||||
}
|
||||
|
||||
void STDMETHODCALLTYPE PreLoad() final {
|
||||
this->GetD3D9()->PreLoad();
|
||||
}
|
||||
|
||||
DWORD STDMETHODCALLTYPE SetLOD(DWORD LODNew) final {
|
||||
return this->GetD3D9()->SetLOD(LODNew);
|
||||
}
|
||||
|
||||
DWORD STDMETHODCALLTYPE GetLOD() final {
|
||||
return this->GetD3D9()->GetLOD();
|
||||
}
|
||||
|
||||
DWORD STDMETHODCALLTYPE GetLevelCount() final {
|
||||
return this->GetD3D9()->GetLevelCount();
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
HRESULT STDMETHODCALLTYPE GetSubresource(UINT Index, SubresourceType8** ppSubresource) {
|
||||
InitReturnPtr(ppSubresource);
|
||||
|
||||
if (unlikely(ppSubresource == nullptr))
|
||||
return D3DERR_INVALIDCALL;
|
||||
|
||||
if (unlikely(Index >= m_subresources.size()))
|
||||
return D3DERR_INVALIDCALL;
|
||||
|
||||
if (m_subresources[Index] == nullptr) {
|
||||
try {
|
||||
Com<SubresourceType9> subresource = LookupSubresource(Index);
|
||||
|
||||
// Cache the subresource
|
||||
m_subresources[Index] = new SubresourceType(this->m_parent, this->m_pool, this, std::move(subresource));
|
||||
} catch (HRESULT res) {
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
*ppSubresource = m_subresources[Index].ref();
|
||||
return D3D_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
Com<SubresourceType9> LookupSubresource(UINT Index) {
|
||||
Com<SubresourceType9> ptr = nullptr;
|
||||
HRESULT res = D3DERR_INVALIDCALL;
|
||||
if constexpr (std::is_same_v<D3D8, IDirect3DTexture8>) {
|
||||
res = this->GetD3D9()->GetSurfaceLevel(Index, &ptr);
|
||||
} else if constexpr (std::is_same_v<D3D8, IDirect3DVolumeTexture8>) {
|
||||
res = this->GetD3D9()->GetVolumeLevel(Index, &ptr);
|
||||
} else if constexpr (std::is_same_v<D3D8, IDirect3DCubeTexture8>) {
|
||||
res = this->GetD3D9()->GetCubeMapSurface(d3d9::D3DCUBEMAP_FACES(Index % CUBE_FACES), Index / CUBE_FACES, &ptr);
|
||||
}
|
||||
if (FAILED(res))
|
||||
throw res;
|
||||
return ptr;
|
||||
}
|
||||
|
||||
std::vector<Com<SubresourceType, false>> m_subresources;
|
||||
|
||||
};
|
||||
|
||||
using D3D8Texture2DBase = D3D8BaseTexture<D3D8Surface, d3d9::IDirect3DTexture9, IDirect3DTexture8>;
|
||||
class D3D8Texture2D final : public D3D8Texture2DBase {
|
||||
|
||||
public:
|
||||
|
||||
D3D8Texture2D(
|
||||
D3D8Device* pDevice,
|
||||
const D3DPOOL Pool,
|
||||
Com<d3d9::IDirect3DTexture9>&& pTexture);
|
||||
|
||||
D3DRESOURCETYPE STDMETHODCALLTYPE GetType() final;
|
||||
|
||||
HRESULT STDMETHODCALLTYPE GetLevelDesc(UINT Level, D3DSURFACE_DESC* pDesc);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE GetSurfaceLevel(UINT Level, IDirect3DSurface8** ppSurfaceLevel);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE LockRect(
|
||||
UINT Level,
|
||||
D3DLOCKED_RECT* pLockedRect,
|
||||
CONST RECT* pRect,
|
||||
DWORD Flags);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE UnlockRect(UINT Level);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE AddDirtyRect(CONST RECT* pDirtyRect);
|
||||
|
||||
};
|
||||
|
||||
using D3D8Texture3DBase = D3D8BaseTexture<D3D8Volume, d3d9::IDirect3DVolumeTexture9, IDirect3DVolumeTexture8>;
|
||||
class D3D8Texture3D final : public D3D8Texture3DBase {
|
||||
|
||||
public:
|
||||
|
||||
D3D8Texture3D(
|
||||
D3D8Device* pDevice,
|
||||
const D3DPOOL Pool,
|
||||
Com<d3d9::IDirect3DVolumeTexture9>&& pVolumeTexture);
|
||||
|
||||
D3DRESOURCETYPE STDMETHODCALLTYPE GetType() final;
|
||||
|
||||
HRESULT STDMETHODCALLTYPE GetLevelDesc(UINT Level, D3DVOLUME_DESC *pDesc);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE GetVolumeLevel(UINT Level, IDirect3DVolume8** ppVolumeLevel);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE LockBox(
|
||||
UINT Level,
|
||||
D3DLOCKED_BOX* pLockedBox,
|
||||
CONST D3DBOX* pBox,
|
||||
DWORD Flags);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE UnlockBox(UINT Level);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE AddDirtyBox(CONST D3DBOX* pDirtyBox);
|
||||
|
||||
};
|
||||
|
||||
using D3D8TextureCubeBase = D3D8BaseTexture<D3D8Surface, d3d9::IDirect3DCubeTexture9, IDirect3DCubeTexture8>;
|
||||
class D3D8TextureCube final : public D3D8TextureCubeBase {
|
||||
|
||||
public:
|
||||
|
||||
D3D8TextureCube(
|
||||
D3D8Device* pDevice,
|
||||
const D3DPOOL Pool,
|
||||
Com<d3d9::IDirect3DCubeTexture9>&& pTexture);
|
||||
|
||||
D3DRESOURCETYPE STDMETHODCALLTYPE GetType() final;
|
||||
|
||||
HRESULT STDMETHODCALLTYPE GetLevelDesc(UINT Level, D3DSURFACE_DESC* pDesc);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE GetCubeMapSurface(
|
||||
D3DCUBEMAP_FACES Face,
|
||||
UINT Level,
|
||||
IDirect3DSurface8** ppSurfaceLevel);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE LockRect(
|
||||
D3DCUBEMAP_FACES Face,
|
||||
UINT Level,
|
||||
D3DLOCKED_RECT* pLockedRect,
|
||||
const RECT* pRect,
|
||||
DWORD Flags);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE UnlockRect(D3DCUBEMAP_FACES Face, UINT Level);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE AddDirtyRect(D3DCUBEMAP_FACES Face, const RECT* pDirtyRect);
|
||||
|
||||
};
|
||||
|
||||
}
|
40
src/d3d8/d3d8_volume.cpp
Normal file
40
src/d3d8/d3d8_volume.cpp
Normal file
|
@ -0,0 +1,40 @@
|
|||
#include "d3d8_volume.h"
|
||||
|
||||
#include "d3d8_d3d9_util.h"
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
D3D8Volume::D3D8Volume(
|
||||
D3D8Device* pDevice,
|
||||
const D3DPOOL Pool,
|
||||
IDirect3DVolumeTexture8* pTexture,
|
||||
Com<d3d9::IDirect3DVolume9>&& pVolume)
|
||||
: D3D8VolumeBase(pDevice, Pool, std::move(pVolume), pTexture) {
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE D3D8Volume::GetDesc(D3DVOLUME_DESC* pDesc) {
|
||||
if (unlikely(pDesc == nullptr))
|
||||
return D3DERR_INVALIDCALL;
|
||||
|
||||
d3d9::D3DVOLUME_DESC desc;
|
||||
HRESULT res = GetD3D9()->GetDesc(&desc);
|
||||
|
||||
if (likely(SUCCEEDED(res)))
|
||||
ConvertVolumeDesc8(&desc, pDesc);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE D3D8Volume::LockBox(D3DLOCKED_BOX* pLockedBox, CONST D3DBOX* pBox, DWORD Flags) {
|
||||
return GetD3D9()->LockBox(
|
||||
reinterpret_cast<d3d9::D3DLOCKED_BOX*>(pLockedBox),
|
||||
reinterpret_cast<const d3d9::D3DBOX*>(pBox),
|
||||
Flags
|
||||
);
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE D3D8Volume::UnlockBox() {
|
||||
return GetD3D9()->UnlockBox();
|
||||
}
|
||||
|
||||
}
|
|
@ -1,40 +1,26 @@
|
|||
#pragma once
|
||||
|
||||
#include "d3d8_subresource.h"
|
||||
#include "d3d8_d3d9_util.h"
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
using D3D8VolumeBase = D3D8Subresource<d3d9::IDirect3DVolume9, IDirect3DVolume8>;
|
||||
class D3D8Volume final : public D3D8VolumeBase {
|
||||
|
||||
public:
|
||||
|
||||
D3D8Volume(
|
||||
D3D8Device* pDevice,
|
||||
IDirect3DVolumeTexture8* pTexture,
|
||||
Com<d3d9::IDirect3DVolume9>&& pVolume)
|
||||
: D3D8VolumeBase(pDevice, std::move(pVolume), pTexture) {}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE GetDesc(D3DVOLUME_DESC* pDesc) {
|
||||
d3d9::D3DVOLUME_DESC desc;
|
||||
HRESULT res = GetD3D9()->GetDesc(&desc);
|
||||
ConvertVolumeDesc8(&desc, pDesc);
|
||||
return res;
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE LockBox(D3DLOCKED_BOX* pLockedBox, CONST D3DBOX* pBox, DWORD Flags) final {
|
||||
return GetD3D9()->LockBox(
|
||||
reinterpret_cast<d3d9::D3DLOCKED_BOX*>(pLockedBox),
|
||||
reinterpret_cast<const d3d9::D3DBOX*>(pBox),
|
||||
Flags
|
||||
);
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE UnlockBox() final {
|
||||
return GetD3D9()->UnlockBox();
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "d3d8_subresource.h"
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
using D3D8VolumeBase = D3D8Subresource<d3d9::IDirect3DVolume9, IDirect3DVolume8>;
|
||||
class D3D8Volume final : public D3D8VolumeBase {
|
||||
|
||||
public:
|
||||
|
||||
D3D8Volume(
|
||||
D3D8Device* pDevice,
|
||||
const D3DPOOL Pool,
|
||||
IDirect3DVolumeTexture8* pTexture,
|
||||
Com<d3d9::IDirect3DVolume9>&& pVolume);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE GetDesc(D3DVOLUME_DESC* pDesc);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE LockBox(D3DLOCKED_BOX* pLockedBox, CONST D3DBOX* pBox, DWORD Flags) final;
|
||||
|
||||
HRESULT STDMETHODCALLTYPE UnlockBox() final;
|
||||
|
||||
};
|
||||
|
||||
}
|
|
@ -38,7 +38,7 @@ namespace dxvk {
|
|||
return this;
|
||||
if (riid == __uuidof(D3D8))
|
||||
return this;
|
||||
|
||||
|
||||
throw E_NOINTERFACE;
|
||||
}
|
||||
|
||||
|
@ -58,7 +58,6 @@ namespace dxvk {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
|
||||
Com<D3D9> m_d3d9;
|
||||
|
|
|
@ -1,13 +1,18 @@
|
|||
d3d8_res = wrc_generator.process('version.rc')
|
||||
|
||||
d3d8_src = [
|
||||
'd3d8_main.cpp',
|
||||
'd3d8_interface.cpp',
|
||||
'd3d8_buffer.cpp',
|
||||
'd3d8_device.cpp',
|
||||
'd3d8_interface.cpp',
|
||||
'd3d8_main.cpp',
|
||||
'd3d8_multithread.cpp',
|
||||
'd3d8_options.cpp',
|
||||
'd3d8_surface.cpp',
|
||||
'd3d8_shader.cpp',
|
||||
'd3d8_state_block.cpp',
|
||||
'd3d8_shader.cpp'
|
||||
'd3d8_surface.cpp',
|
||||
'd3d8_swapchain.cpp',
|
||||
'd3d8_texture.cpp',
|
||||
'd3d8_volume.cpp'
|
||||
]
|
||||
|
||||
d3d8_ld_args = []
|
||||
|
|
|
@ -114,6 +114,9 @@ namespace dxvk {
|
|||
DWORD Usage,
|
||||
D3DRESOURCETYPE RType,
|
||||
D3D9Format CheckFormat) {
|
||||
if(unlikely(AdapterFormat == D3D9Format::Unknown))
|
||||
return D3DERR_INVALIDCALL;
|
||||
|
||||
if (!IsSupportedAdapterFormat(AdapterFormat))
|
||||
return D3DERR_NOTAVAILABLE;
|
||||
|
||||
|
@ -134,7 +137,7 @@ namespace dxvk {
|
|||
if (rt && CheckFormat == D3D9Format::A8 && m_parent->GetOptions().disableA8RT)
|
||||
return D3DERR_NOTAVAILABLE;
|
||||
|
||||
if (ds && !IsDepthFormat(CheckFormat))
|
||||
if (ds && !IsDepthStencilFormat(CheckFormat))
|
||||
return D3DERR_NOTAVAILABLE;
|
||||
|
||||
if (rt && CheckFormat == D3D9Format::NULL_FORMAT && twoDimensional)
|
||||
|
@ -169,7 +172,11 @@ namespace dxvk {
|
|||
return D3D_OK;
|
||||
|
||||
// Let's actually ask Vulkan now that we got some quirks out the way!
|
||||
return CheckDeviceVkFormat(mapping.FormatColor, Usage, RType);
|
||||
VkFormat format = mapping.FormatColor;
|
||||
if (unlikely(mapping.ConversionFormatInfo.FormatColor != VK_FORMAT_UNDEFINED)) {
|
||||
format = mapping.ConversionFormatInfo.FormatColor;
|
||||
}
|
||||
return CheckDeviceVkFormat(format, Usage, RType);
|
||||
}
|
||||
|
||||
|
||||
|
@ -182,6 +189,12 @@ namespace dxvk {
|
|||
if (pQualityLevels != nullptr)
|
||||
*pQualityLevels = 1;
|
||||
|
||||
if (unlikely(MultiSampleType > D3DMULTISAMPLE_16_SAMPLES))
|
||||
return D3DERR_INVALIDCALL;
|
||||
|
||||
if (unlikely(SurfaceFormat == D3D9Format::Unknown))
|
||||
return D3DERR_INVALIDCALL;
|
||||
|
||||
auto dst = ConvertFormatUnfixed(SurfaceFormat);
|
||||
if (dst.FormatColor == VK_FORMAT_UNDEFINED)
|
||||
return D3DERR_NOTAVAILABLE;
|
||||
|
@ -190,7 +203,12 @@ namespace dxvk {
|
|||
&& (SurfaceFormat == D3D9Format::D32_LOCKABLE
|
||||
|| SurfaceFormat == D3D9Format::D32F_LOCKABLE
|
||||
|| SurfaceFormat == D3D9Format::D16_LOCKABLE
|
||||
|| SurfaceFormat == D3D9Format::INTZ))
|
||||
|| SurfaceFormat == D3D9Format::INTZ
|
||||
|| SurfaceFormat == D3D9Format::DXT1
|
||||
|| SurfaceFormat == D3D9Format::DXT2
|
||||
|| SurfaceFormat == D3D9Format::DXT3
|
||||
|| SurfaceFormat == D3D9Format::DXT4
|
||||
|| SurfaceFormat == D3D9Format::DXT5))
|
||||
return D3DERR_NOTAVAILABLE;
|
||||
|
||||
uint32_t sampleCount = std::max<uint32_t>(MultiSampleType, 1u);
|
||||
|
@ -224,7 +242,7 @@ namespace dxvk {
|
|||
D3D9Format AdapterFormat,
|
||||
D3D9Format RenderTargetFormat,
|
||||
D3D9Format DepthStencilFormat) {
|
||||
if (!IsDepthFormat(DepthStencilFormat))
|
||||
if (!IsDepthStencilFormat(DepthStencilFormat))
|
||||
return D3DERR_NOTAVAILABLE;
|
||||
|
||||
auto dsfMapping = GetFormatMapping(DepthStencilFormat);
|
||||
|
@ -247,7 +265,8 @@ namespace dxvk {
|
|||
D3D9Format SourceFormat,
|
||||
D3D9Format TargetFormat) {
|
||||
bool sourceSupported = SourceFormat != D3D9Format::Unknown
|
||||
&& IsSupportedBackBufferFormat(SourceFormat);
|
||||
&& (IsSupportedBackBufferFormat(SourceFormat)
|
||||
|| (IsFourCCFormat(SourceFormat) && !IsVendorFormat(SourceFormat)));
|
||||
bool targetSupported = TargetFormat == D3D9Format::X1R5G5B5
|
||||
|| TargetFormat == D3D9Format::A1R5G5B5
|
||||
|| TargetFormat == D3D9Format::R5G6B5
|
||||
|
@ -393,9 +412,13 @@ namespace dxvk {
|
|||
| D3DPBLENDCAPS_SRCALPHASAT
|
||||
| D3DPBLENDCAPS_BOTHSRCALPHA
|
||||
| D3DPBLENDCAPS_BOTHINVSRCALPHA
|
||||
| D3DPBLENDCAPS_BLENDFACTOR
|
||||
| D3DPBLENDCAPS_INVSRCCOLOR2
|
||||
| D3DPBLENDCAPS_SRCCOLOR2;
|
||||
| D3DPBLENDCAPS_BLENDFACTOR;
|
||||
|
||||
// Only 9Ex devices advertise D3DPBLENDCAPS_SRCCOLOR2 and D3DPBLENDCAPS_INVSRCCOLOR2
|
||||
if (m_parent->IsExtended())
|
||||
pCaps->SrcBlendCaps |= D3DPBLENDCAPS_SRCCOLOR2
|
||||
| D3DPBLENDCAPS_INVSRCCOLOR2;
|
||||
|
||||
// Destination Blend Caps
|
||||
pCaps->DestBlendCaps = pCaps->SrcBlendCaps;
|
||||
// Alpha Comparison Caps
|
||||
|
@ -550,17 +573,22 @@ namespace dxvk {
|
|||
// Max Stream Stride
|
||||
pCaps->MaxStreamStride = 508; // bytes
|
||||
|
||||
const uint32_t majorVersion = options.shaderModel;
|
||||
const uint32_t minorVersion = options.shaderModel != 1 ? 0 : 4;
|
||||
// Late fixed-function capable cards, such as the GeForce 4 MX series,
|
||||
// expose support for VS 1.1, while not advertising any PS support
|
||||
const uint32_t majorVersionVS = options.shaderModel == 0 ? 1 : options.shaderModel;
|
||||
const uint32_t majorVersionPS = options.shaderModel;
|
||||
// Max supported SM1 is VS 1.1 and PS 1.4
|
||||
const uint32_t minorVersionVS = majorVersionVS != 1 ? 0 : 1;
|
||||
const uint32_t minorVersionPS = majorVersionPS != 1 ? 0 : 4;
|
||||
|
||||
// Shader Versions
|
||||
pCaps->VertexShaderVersion = D3DVS_VERSION(majorVersion, minorVersion);
|
||||
pCaps->PixelShaderVersion = D3DPS_VERSION(majorVersion, minorVersion);
|
||||
pCaps->VertexShaderVersion = D3DVS_VERSION(majorVersionVS, minorVersionVS);
|
||||
pCaps->PixelShaderVersion = D3DPS_VERSION(majorVersionPS, minorVersionPS);
|
||||
|
||||
// Max Vertex Shader Const
|
||||
pCaps->MaxVertexShaderConst = MaxFloatConstantsVS;
|
||||
// Max PS1 Value
|
||||
pCaps->PixelShader1xMaxValue = FLT_MAX;
|
||||
pCaps->PixelShader1xMaxValue = options.shaderModel > 0 ? std::numeric_limits<float>::max() : 0.0f;
|
||||
// Dev Caps 2
|
||||
pCaps->DevCaps2 = D3DDEVCAPS2_STREAMOFFSET
|
||||
/* | D3DDEVCAPS2_DMAPNPATCH */
|
||||
|
@ -607,24 +635,38 @@ namespace dxvk {
|
|||
/* | D3DPTFILTERCAPS_MAGFPYRAMIDALQUAD */
|
||||
/* | D3DPTFILTERCAPS_MAGFGAUSSIANQUAD */;
|
||||
|
||||
// Not too bothered about doing these longhand
|
||||
// We should match whatever my AMD hardware reports here
|
||||
// methinks for the best chance of stuff working.
|
||||
pCaps->VS20Caps.Caps = 1;
|
||||
pCaps->VS20Caps.DynamicFlowControlDepth = 24;
|
||||
pCaps->VS20Caps.NumTemps = 32;
|
||||
pCaps->VS20Caps.StaticFlowControlDepth = 4;
|
||||
pCaps->VS20Caps.Caps = options.shaderModel >= 2 ? D3DVS20CAPS_PREDICATION : 0;
|
||||
pCaps->VS20Caps.DynamicFlowControlDepth = options.shaderModel >= 2 ? D3DVS20_MAX_DYNAMICFLOWCONTROLDEPTH : 0;
|
||||
pCaps->VS20Caps.NumTemps = options.shaderModel >= 2 ? D3DVS20_MAX_NUMTEMPS : 0;
|
||||
pCaps->VS20Caps.StaticFlowControlDepth = options.shaderModel >= 2 ? D3DVS20_MAX_STATICFLOWCONTROLDEPTH : 0;
|
||||
|
||||
pCaps->PS20Caps.Caps = 31;
|
||||
pCaps->PS20Caps.DynamicFlowControlDepth = 24;
|
||||
pCaps->PS20Caps.NumTemps = 32;
|
||||
pCaps->PS20Caps.StaticFlowControlDepth = 4;
|
||||
pCaps->PS20Caps.Caps = options.shaderModel >= 2 ? D3DPS20CAPS_ARBITRARYSWIZZLE
|
||||
| D3DPS20CAPS_GRADIENTINSTRUCTIONS
|
||||
| D3DPS20CAPS_PREDICATION
|
||||
| D3DPS20CAPS_NODEPENDENTREADLIMIT
|
||||
| D3DPS20CAPS_NOTEXINSTRUCTIONLIMIT : 0;
|
||||
pCaps->PS20Caps.DynamicFlowControlDepth = options.shaderModel >= 2 ? D3DPS20_MAX_DYNAMICFLOWCONTROLDEPTH : 0;
|
||||
pCaps->PS20Caps.NumTemps = options.shaderModel >= 2 ? D3DPS20_MAX_NUMTEMPS : 0;
|
||||
pCaps->PS20Caps.StaticFlowControlDepth = options.shaderModel >= 2 ? D3DPS20_MAX_STATICFLOWCONTROLDEPTH : 0;
|
||||
pCaps->PS20Caps.NumInstructionSlots = options.shaderModel >= 2 ? D3DPS20_MAX_NUMINSTRUCTIONSLOTS : 0;
|
||||
|
||||
pCaps->PS20Caps.NumInstructionSlots = options.shaderModel >= 2 ? 512 : 256;
|
||||
// Vertex texture samplers are only available as part of SM3, the caps are 0 otherwise.
|
||||
pCaps->VertexTextureFilterCaps = options.shaderModel == 3 ? D3DPTFILTERCAPS_MINFPOINT
|
||||
| D3DPTFILTERCAPS_MINFLINEAR
|
||||
/* | D3DPTFILTERCAPS_MINFANISOTROPIC */
|
||||
/* | D3DPTFILTERCAPS_MINFPYRAMIDALQUAD */
|
||||
/* | D3DPTFILTERCAPS_MINFGAUSSIANQUAD */
|
||||
/* | D3DPTFILTERCAPS_MIPFPOINT */
|
||||
/* | D3DPTFILTERCAPS_MIPFLINEAR */
|
||||
/* | D3DPTFILTERCAPS_CONVOLUTIONMONO */
|
||||
| D3DPTFILTERCAPS_MAGFPOINT
|
||||
| D3DPTFILTERCAPS_MAGFLINEAR
|
||||
/* | D3DPTFILTERCAPS_MAGFANISOTROPIC */
|
||||
/* | D3DPTFILTERCAPS_MAGFPYRAMIDALQUAD */
|
||||
/* | D3DPTFILTERCAPS_MAGFGAUSSIANQUAD */ : 0;
|
||||
|
||||
pCaps->VertexTextureFilterCaps = 50332416;
|
||||
pCaps->MaxVShaderInstructionsExecuted = 4294967295;
|
||||
pCaps->MaxPShaderInstructionsExecuted = 4294967295;
|
||||
pCaps->MaxVShaderInstructionsExecuted = options.shaderModel >= 2 ? 4294967295 : 0;
|
||||
pCaps->MaxPShaderInstructionsExecuted = options.shaderModel >= 2 ? 4294967295 : 0;
|
||||
|
||||
pCaps->MaxVertexShader30InstructionSlots = options.shaderModel == 3 ? 32768 : 0;
|
||||
pCaps->MaxPixelShader30InstructionSlots = options.shaderModel == 3 ? 32768 : 0;
|
||||
|
@ -801,8 +843,9 @@ namespace dxvk {
|
|||
m_modes.push_back(mode);
|
||||
}
|
||||
|
||||
// Sort display modes by width, height and refresh rate,
|
||||
// in that order. Some games rely on correct ordering.
|
||||
// Sort display modes by width, height and refresh rate (descending), in that order.
|
||||
// Some games rely on correct ordering, e.g. Prince of Persia (2008) expects the highest
|
||||
// refresh rate to be listed first for a particular resolution.
|
||||
std::sort(m_modes.begin(), m_modes.end(),
|
||||
[](const D3DDISPLAYMODEEX& a, const D3DDISPLAYMODEEX& b) {
|
||||
if (a.Width < b.Width) return true;
|
||||
|
@ -811,7 +854,7 @@ namespace dxvk {
|
|||
if (a.Height < b.Height) return true;
|
||||
if (a.Height > b.Height) return false;
|
||||
|
||||
return a.RefreshRate < b.RefreshRate;
|
||||
return b.RefreshRate < a.RefreshRate;
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -127,6 +127,7 @@ namespace dxvk {
|
|||
INT STDMETHODCALLTYPE D3D9UserDefinedAnnotation::BeginEvent(
|
||||
D3DCOLOR Color,
|
||||
LPCWSTR Name) {
|
||||
D3D9DeviceLock lock = m_container->LockDevice();
|
||||
m_container->EmitCs([color = Color, labelName = dxvk::str::fromws(Name)](DxvkContext *ctx) {
|
||||
VkDebugUtilsLabelEXT label;
|
||||
label.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT;
|
||||
|
@ -134,7 +135,7 @@ namespace dxvk {
|
|||
label.pLabelName = labelName.c_str();
|
||||
DecodeD3DCOLOR(color, label.color);
|
||||
|
||||
ctx->beginDebugLabel(&label);
|
||||
ctx->beginDebugLabel(label);
|
||||
});
|
||||
|
||||
// Handled by the global list.
|
||||
|
@ -143,6 +144,7 @@ namespace dxvk {
|
|||
|
||||
|
||||
INT STDMETHODCALLTYPE D3D9UserDefinedAnnotation::EndEvent() {
|
||||
D3D9DeviceLock lock = m_container->LockDevice();
|
||||
m_container->EmitCs([](DxvkContext *ctx) {
|
||||
ctx->endDebugLabel();
|
||||
});
|
||||
|
@ -155,6 +157,7 @@ namespace dxvk {
|
|||
void STDMETHODCALLTYPE D3D9UserDefinedAnnotation::SetMarker(
|
||||
D3DCOLOR Color,
|
||||
LPCWSTR Name) {
|
||||
D3D9DeviceLock lock = m_container->LockDevice();
|
||||
m_container->EmitCs([color = Color, labelName = dxvk::str::fromws(Name)](DxvkContext *ctx) {
|
||||
VkDebugUtilsLabelEXT label;
|
||||
label.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT;
|
||||
|
@ -162,7 +165,7 @@ namespace dxvk {
|
|||
label.pLabelName = labelName.c_str();
|
||||
DecodeD3DCOLOR(color, label.color);
|
||||
|
||||
ctx->insertDebugLabel(&label);
|
||||
ctx->insertDebugLabel(label);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -1,111 +1,125 @@
|
|||
|
||||
#include "d3d9_device.h"
|
||||
#include "d3d9_interface.h"
|
||||
#include "d3d9_bridge.h"
|
||||
#include "d3d9_swapchain.h"
|
||||
#include "d3d9_surface.h"
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
DxvkD3D8Bridge::DxvkD3D8Bridge(D3D9DeviceEx* pDevice)
|
||||
: m_device(pDevice) {
|
||||
}
|
||||
|
||||
DxvkD3D8Bridge::~DxvkD3D8Bridge() {
|
||||
}
|
||||
|
||||
ULONG STDMETHODCALLTYPE DxvkD3D8Bridge::AddRef() {
|
||||
return m_device->AddRef();
|
||||
}
|
||||
|
||||
ULONG STDMETHODCALLTYPE DxvkD3D8Bridge::Release() {
|
||||
return m_device->Release();
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE DxvkD3D8Bridge::QueryInterface(
|
||||
REFIID riid,
|
||||
void** ppvObject) {
|
||||
return m_device->QueryInterface(riid, ppvObject);
|
||||
}
|
||||
|
||||
void DxvkD3D8Bridge::SetAPIName(const char* name) {
|
||||
m_device->m_implicitSwapchain->SetApiName(name);
|
||||
}
|
||||
|
||||
void DxvkD3D8Bridge::SetD3D8CompatibilityMode(const bool compatMode) {
|
||||
m_device->SetD3D8CompatibilityMode(compatMode);
|
||||
}
|
||||
|
||||
HRESULT DxvkD3D8Bridge::UpdateTextureFromBuffer(
|
||||
IDirect3DSurface9* pDestSurface,
|
||||
IDirect3DSurface9* pSrcSurface,
|
||||
const RECT* pSrcRect,
|
||||
const POINT* pDestPoint) {
|
||||
auto lock = m_device->LockDevice();
|
||||
|
||||
D3D9Surface* dst = static_cast<D3D9Surface*>(pDestSurface);
|
||||
D3D9Surface* src = static_cast<D3D9Surface*>(pSrcSurface);
|
||||
|
||||
if (unlikely(dst == nullptr || src == nullptr))
|
||||
return D3DERR_INVALIDCALL;
|
||||
|
||||
D3D9CommonTexture* srcTextureInfo = src->GetCommonTexture();
|
||||
D3D9CommonTexture* dstTextureInfo = dst->GetCommonTexture();
|
||||
|
||||
VkOffset3D srcOffset = { 0u, 0u, 0u };
|
||||
VkOffset3D dstOffset = { 0u, 0u, 0u };
|
||||
VkExtent3D texLevelExtent = srcTextureInfo->GetExtentMip(src->GetSubresource());
|
||||
VkExtent3D extent = texLevelExtent;
|
||||
|
||||
srcOffset = { pSrcRect->left,
|
||||
pSrcRect->top,
|
||||
0u };
|
||||
|
||||
extent = { uint32_t(pSrcRect->right - pSrcRect->left), uint32_t(pSrcRect->bottom - pSrcRect->top), 1 };
|
||||
|
||||
// TODO: Validate extents like in D3D9DeviceEx::UpdateSurface
|
||||
|
||||
dstOffset = { pDestPoint->x,
|
||||
pDestPoint->y,
|
||||
0u };
|
||||
|
||||
|
||||
m_device->UpdateTextureFromBuffer(
|
||||
srcTextureInfo, dstTextureInfo,
|
||||
src->GetSubresource(), dst->GetSubresource(),
|
||||
srcOffset, extent, dstOffset
|
||||
);
|
||||
|
||||
dstTextureInfo->SetNeedsReadback(dst->GetSubresource(), true);
|
||||
|
||||
if (dstTextureInfo->IsAutomaticMip())
|
||||
m_device->MarkTextureMipsDirty(dstTextureInfo);
|
||||
|
||||
return D3D_OK;
|
||||
}
|
||||
|
||||
DxvkD3D8InterfaceBridge::DxvkD3D8InterfaceBridge(D3D9InterfaceEx* pObject)
|
||||
: m_interface(pObject) {
|
||||
}
|
||||
|
||||
DxvkD3D8InterfaceBridge::~DxvkD3D8InterfaceBridge() {
|
||||
}
|
||||
|
||||
ULONG STDMETHODCALLTYPE DxvkD3D8InterfaceBridge::AddRef() {
|
||||
return m_interface->AddRef();
|
||||
}
|
||||
|
||||
ULONG STDMETHODCALLTYPE DxvkD3D8InterfaceBridge::Release() {
|
||||
return m_interface->Release();
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE DxvkD3D8InterfaceBridge::QueryInterface(
|
||||
REFIID riid,
|
||||
void** ppvObject) {
|
||||
return m_interface->QueryInterface(riid, ppvObject);
|
||||
}
|
||||
|
||||
const Config* DxvkD3D8InterfaceBridge::GetConfig() const {
|
||||
return &m_interface->GetInstance()->config();
|
||||
}
|
||||
}
|
||||
|
||||
#include "d3d9_device.h"
|
||||
#include "d3d9_interface.h"
|
||||
#include "d3d9_bridge.h"
|
||||
#include "d3d9_swapchain.h"
|
||||
#include "d3d9_surface.h"
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
DxvkD3D8Bridge::DxvkD3D8Bridge(D3D9DeviceEx* pDevice)
|
||||
: m_device(pDevice) {
|
||||
}
|
||||
|
||||
DxvkD3D8Bridge::~DxvkD3D8Bridge() {
|
||||
}
|
||||
|
||||
ULONG STDMETHODCALLTYPE DxvkD3D8Bridge::AddRef() {
|
||||
return m_device->AddRef();
|
||||
}
|
||||
|
||||
ULONG STDMETHODCALLTYPE DxvkD3D8Bridge::Release() {
|
||||
return m_device->Release();
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE DxvkD3D8Bridge::QueryInterface(
|
||||
REFIID riid,
|
||||
void** ppvObject) {
|
||||
return m_device->QueryInterface(riid, ppvObject);
|
||||
}
|
||||
|
||||
HRESULT DxvkD3D8Bridge::UpdateTextureFromBuffer(
|
||||
IDirect3DSurface9* pDestSurface,
|
||||
IDirect3DSurface9* pSrcSurface,
|
||||
const RECT* pSrcRect,
|
||||
const POINT* pDestPoint) {
|
||||
auto lock = m_device->LockDevice();
|
||||
|
||||
D3D9Surface* dst = static_cast<D3D9Surface*>(pDestSurface);
|
||||
D3D9Surface* src = static_cast<D3D9Surface*>(pSrcSurface);
|
||||
|
||||
if (unlikely(dst == nullptr || src == nullptr))
|
||||
return D3DERR_INVALIDCALL;
|
||||
|
||||
// CopyRects will not pass a null pSrcRect, but check anyway
|
||||
if (unlikely(pSrcRect == nullptr))
|
||||
return D3DERR_INVALIDCALL;
|
||||
|
||||
// validate dimensions to ensure we calculate a meaningful srcOffset & extent
|
||||
if (unlikely(pSrcRect->left < 0
|
||||
|| pSrcRect->top < 0
|
||||
|| pSrcRect->right <= pSrcRect->left
|
||||
|| pSrcRect->bottom <= pSrcRect->top))
|
||||
return D3DERR_INVALIDCALL;
|
||||
|
||||
// CopyRects will not pass a null pDestPoint, but check anyway
|
||||
if (unlikely(pDestPoint == nullptr))
|
||||
return D3DERR_INVALIDCALL;
|
||||
|
||||
// validate dimensions to ensure we caculate a meaningful dstOffset
|
||||
if (unlikely(pDestPoint->x < 0
|
||||
|| pDestPoint->y < 0))
|
||||
return D3DERR_INVALIDCALL;
|
||||
|
||||
D3D9CommonTexture* srcTextureInfo = src->GetCommonTexture();
|
||||
D3D9CommonTexture* dstTextureInfo = dst->GetCommonTexture();
|
||||
|
||||
VkOffset3D srcOffset = { 0u, 0u, 0u };
|
||||
VkOffset3D dstOffset = { 0u, 0u, 0u };
|
||||
VkExtent3D texLevelExtent = srcTextureInfo->GetExtentMip(src->GetSubresource());
|
||||
VkExtent3D extent = texLevelExtent;
|
||||
|
||||
srcOffset = { pSrcRect->left,
|
||||
pSrcRect->top,
|
||||
0u };
|
||||
|
||||
extent = { uint32_t(pSrcRect->right - pSrcRect->left), uint32_t(pSrcRect->bottom - pSrcRect->top), 1 };
|
||||
|
||||
dstOffset = { pDestPoint->x,
|
||||
pDestPoint->y,
|
||||
0u };
|
||||
|
||||
m_device->UpdateTextureFromBuffer(
|
||||
srcTextureInfo, dstTextureInfo,
|
||||
src->GetSubresource(), dst->GetSubresource(),
|
||||
srcOffset, extent, dstOffset
|
||||
);
|
||||
|
||||
dstTextureInfo->SetNeedsReadback(dst->GetSubresource(), true);
|
||||
|
||||
if (dstTextureInfo->IsAutomaticMip())
|
||||
m_device->MarkTextureMipsDirty(dstTextureInfo);
|
||||
|
||||
return D3D_OK;
|
||||
}
|
||||
|
||||
DxvkD3D8InterfaceBridge::DxvkD3D8InterfaceBridge(D3D9InterfaceEx* pObject)
|
||||
: m_interface(pObject) {
|
||||
}
|
||||
|
||||
DxvkD3D8InterfaceBridge::~DxvkD3D8InterfaceBridge() {
|
||||
}
|
||||
|
||||
ULONG STDMETHODCALLTYPE DxvkD3D8InterfaceBridge::AddRef() {
|
||||
return m_interface->AddRef();
|
||||
}
|
||||
|
||||
ULONG STDMETHODCALLTYPE DxvkD3D8InterfaceBridge::Release() {
|
||||
return m_interface->Release();
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE DxvkD3D8InterfaceBridge::QueryInterface(
|
||||
REFIID riid,
|
||||
void** ppvObject) {
|
||||
return m_interface->QueryInterface(riid, ppvObject);
|
||||
}
|
||||
|
||||
void DxvkD3D8InterfaceBridge::SetD3D8CompatibilityMode(const bool compatMode) {
|
||||
m_interface->SetD3D8CompatibilityMode(compatMode);
|
||||
}
|
||||
|
||||
const Config* DxvkD3D8InterfaceBridge::GetConfig() const {
|
||||
return &m_interface->GetInstance()->config();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,116 +1,119 @@
|
|||
#pragma once
|
||||
|
||||
#include <windows.h>
|
||||
#include "../util/config/config.h"
|
||||
|
||||
/**
|
||||
* The D3D9 bridge allows D3D8 to access DXVK internals.
|
||||
* For Vulkan interop without needing DXVK internals, see d3d9_interop.h.
|
||||
*
|
||||
* NOTE: You must include "d3d9_include.h" or "d3d8_include.h" before this header.
|
||||
*/
|
||||
|
||||
/**
|
||||
* \brief D3D9 device interface for D3D8 interop
|
||||
*/
|
||||
MIDL_INTERFACE("D3D9D3D8-42A9-4C1E-AA97-BEEFCAFE2000")
|
||||
IDxvkD3D8Bridge : public IUnknown {
|
||||
|
||||
// D3D8 keeps D3D9 objects contained in a namespace.
|
||||
#ifdef DXVK_D3D9_NAMESPACE
|
||||
using IDirect3DSurface9 = d3d9::IDirect3DSurface9;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* \brief Changes the API name displayed on the HUD
|
||||
*
|
||||
* \param [in] name The new API name
|
||||
*/
|
||||
virtual void SetAPIName(const char* name) = 0;
|
||||
|
||||
/**
|
||||
* \brief Enables or disables D3D9-specific device features and validations
|
||||
*
|
||||
* \param [in] compatibility state
|
||||
*/
|
||||
virtual void SetD3D8CompatibilityMode(const bool compatMode) = 0;
|
||||
|
||||
/**
|
||||
* \brief Updates a D3D9 surface from a D3D9 buffer
|
||||
*
|
||||
* \param [in] pDestSurface Destination surface (typically in VRAM)
|
||||
* \param [in] pSrcSurface Source surface (typically in system memory)
|
||||
* \param [in] pSrcRect Source rectangle
|
||||
* \param [in] pDestPoint Destination (top-left) point
|
||||
*/
|
||||
virtual HRESULT UpdateTextureFromBuffer(
|
||||
IDirect3DSurface9* pDestSurface,
|
||||
IDirect3DSurface9* pSrcSurface,
|
||||
const RECT* pSrcRect,
|
||||
const POINT* pDestPoint) = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief D3D9 instance interface for D3D8 interop
|
||||
*/
|
||||
MIDL_INTERFACE("D3D9D3D8-A407-773E-18E9-CAFEBEEF3000")
|
||||
IDxvkD3D8InterfaceBridge : public IUnknown {
|
||||
/**
|
||||
* \brief Retrieves the DXVK configuration
|
||||
*
|
||||
* \returns The DXVK Config object
|
||||
*/
|
||||
virtual const dxvk::Config* GetConfig() const = 0;
|
||||
};
|
||||
|
||||
#ifndef _MSC_VER
|
||||
__CRT_UUID_DECL(IDxvkD3D8Bridge, 0xD3D9D3D8, 0x42A9, 0x4C1E, 0xAA, 0x97, 0xBE, 0xEF, 0xCA, 0xFE, 0x20, 0x00);
|
||||
__CRT_UUID_DECL(IDxvkD3D8InterfaceBridge, 0xD3D9D3D8, 0xA407, 0x773E, 0x18, 0xE9, 0xCA, 0xFE, 0xBE, 0xEF, 0x30, 0x00);
|
||||
#endif
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
class D3D9DeviceEx;
|
||||
class D3D9InterfaceEx;
|
||||
|
||||
class DxvkD3D8Bridge : public IDxvkD3D8Bridge {
|
||||
public:
|
||||
DxvkD3D8Bridge(D3D9DeviceEx* pDevice);
|
||||
~DxvkD3D8Bridge();
|
||||
|
||||
ULONG STDMETHODCALLTYPE AddRef();
|
||||
ULONG STDMETHODCALLTYPE Release();
|
||||
HRESULT STDMETHODCALLTYPE QueryInterface(
|
||||
REFIID riid,
|
||||
void** ppvObject);
|
||||
|
||||
void SetAPIName(const char* name);
|
||||
void SetD3D8CompatibilityMode(const bool compatMode);
|
||||
|
||||
HRESULT UpdateTextureFromBuffer(
|
||||
IDirect3DSurface9* pDestSurface,
|
||||
IDirect3DSurface9* pSrcSurface,
|
||||
const RECT* pSrcRect,
|
||||
const POINT* pDestPoint);
|
||||
|
||||
private:
|
||||
D3D9DeviceEx* m_device;
|
||||
};
|
||||
|
||||
class DxvkD3D8InterfaceBridge : public IDxvkD3D8InterfaceBridge {
|
||||
public:
|
||||
DxvkD3D8InterfaceBridge(D3D9InterfaceEx* pObject);
|
||||
~DxvkD3D8InterfaceBridge();
|
||||
|
||||
ULONG STDMETHODCALLTYPE AddRef();
|
||||
ULONG STDMETHODCALLTYPE Release();
|
||||
HRESULT STDMETHODCALLTYPE QueryInterface(
|
||||
REFIID riid,
|
||||
void** ppvObject);
|
||||
|
||||
const Config* GetConfig() const;
|
||||
|
||||
protected:
|
||||
D3D9InterfaceEx* m_interface;
|
||||
};
|
||||
}
|
||||
#pragma once
|
||||
|
||||
#include <windows.h>
|
||||
#include "../util/config/config.h"
|
||||
|
||||
/**
|
||||
* The D3D9 bridge allows D3D8 to access DXVK internals.
|
||||
* For Vulkan interop without needing DXVK internals, see d3d9_interop.h.
|
||||
*
|
||||
* NOTE: You must include "d3d9_include.h" or "d3d8_include.h" before this header.
|
||||
*/
|
||||
|
||||
/**
|
||||
* \brief D3D9 device interface for D3D8 interop
|
||||
*/
|
||||
MIDL_INTERFACE("D3D9D3D8-42A9-4C1E-AA97-BEEFCAFE2000")
|
||||
IDxvkD3D8Bridge : public IUnknown {
|
||||
|
||||
// D3D8 keeps D3D9 objects contained in a namespace.
|
||||
#ifdef DXVK_D3D9_NAMESPACE
|
||||
using IDirect3DSurface9 = d3d9::IDirect3DSurface9;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* \brief Updates a D3D9 surface from a D3D9 buffer
|
||||
*
|
||||
* \param [in] pDestSurface Destination surface (typically in VRAM)
|
||||
* \param [in] pSrcSurface Source surface (typically in system memory)
|
||||
* \param [in] pSrcRect Source rectangle
|
||||
* \param [in] pDestPoint Destination (top-left) point
|
||||
*/
|
||||
virtual HRESULT UpdateTextureFromBuffer(
|
||||
IDirect3DSurface9* pDestSurface,
|
||||
IDirect3DSurface9* pSrcSurface,
|
||||
const RECT* pSrcRect,
|
||||
const POINT* pDestPoint) = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief D3D9 instance interface for D3D8 interop
|
||||
*/
|
||||
MIDL_INTERFACE("D3D9D3D8-A407-773E-18E9-CAFEBEEF3000")
|
||||
IDxvkD3D8InterfaceBridge : public IUnknown {
|
||||
/**
|
||||
* \brief Enables or disables D3D9-specific features and validations
|
||||
*
|
||||
* \param [in] compatMode Compatibility state
|
||||
*/
|
||||
virtual void SetD3D8CompatibilityMode(const bool compatMode) = 0;
|
||||
|
||||
/**
|
||||
* \brief Retrieves the DXVK configuration
|
||||
*
|
||||
* \returns The DXVK Config object
|
||||
*/
|
||||
virtual const dxvk::Config* GetConfig() const = 0;
|
||||
};
|
||||
|
||||
#ifndef _MSC_VER
|
||||
__CRT_UUID_DECL(IDxvkD3D8Bridge, 0xD3D9D3D8, 0x42A9, 0x4C1E, 0xAA, 0x97, 0xBE, 0xEF, 0xCA, 0xFE, 0x20, 0x00);
|
||||
__CRT_UUID_DECL(IDxvkD3D8InterfaceBridge, 0xD3D9D3D8, 0xA407, 0x773E, 0x18, 0xE9, 0xCA, 0xFE, 0xBE, 0xEF, 0x30, 0x00);
|
||||
#endif
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
class D3D9DeviceEx;
|
||||
class D3D9InterfaceEx;
|
||||
|
||||
class DxvkD3D8Bridge : public IDxvkD3D8Bridge {
|
||||
|
||||
public:
|
||||
|
||||
DxvkD3D8Bridge(D3D9DeviceEx* pDevice);
|
||||
|
||||
~DxvkD3D8Bridge();
|
||||
|
||||
ULONG STDMETHODCALLTYPE AddRef();
|
||||
ULONG STDMETHODCALLTYPE Release();
|
||||
HRESULT STDMETHODCALLTYPE QueryInterface(
|
||||
REFIID riid,
|
||||
void** ppvObject);
|
||||
|
||||
HRESULT UpdateTextureFromBuffer(
|
||||
IDirect3DSurface9* pDestSurface,
|
||||
IDirect3DSurface9* pSrcSurface,
|
||||
const RECT* pSrcRect,
|
||||
const POINT* pDestPoint);
|
||||
|
||||
private:
|
||||
|
||||
D3D9DeviceEx* m_device;
|
||||
|
||||
};
|
||||
|
||||
class DxvkD3D8InterfaceBridge : public IDxvkD3D8InterfaceBridge {
|
||||
|
||||
public:
|
||||
|
||||
DxvkD3D8InterfaceBridge(D3D9InterfaceEx* pObject);
|
||||
|
||||
~DxvkD3D8InterfaceBridge();
|
||||
|
||||
ULONG STDMETHODCALLTYPE AddRef();
|
||||
ULONG STDMETHODCALLTYPE Release();
|
||||
HRESULT STDMETHODCALLTYPE QueryInterface(
|
||||
REFIID riid,
|
||||
void** ppvObject);
|
||||
|
||||
void SetD3D8CompatibilityMode(const bool compatMode);
|
||||
|
||||
const Config* GetConfig() const;
|
||||
|
||||
protected:
|
||||
|
||||
D3D9InterfaceEx* m_interface;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -8,8 +8,9 @@ namespace dxvk {
|
|||
|
||||
D3D9VertexBuffer::D3D9VertexBuffer(
|
||||
D3D9DeviceEx* pDevice,
|
||||
const D3D9_BUFFER_DESC* pDesc)
|
||||
: D3D9VertexBufferBase(pDevice, pDesc) {
|
||||
const D3D9_BUFFER_DESC* pDesc,
|
||||
const bool Extended)
|
||||
: D3D9VertexBufferBase(pDevice, pDesc, Extended) {
|
||||
|
||||
}
|
||||
|
||||
|
@ -68,8 +69,9 @@ namespace dxvk {
|
|||
|
||||
D3D9IndexBuffer::D3D9IndexBuffer(
|
||||
D3D9DeviceEx* pDevice,
|
||||
const D3D9_BUFFER_DESC* pDesc)
|
||||
: D3D9IndexBufferBase(pDevice, pDesc) {
|
||||
const D3D9_BUFFER_DESC* pDesc,
|
||||
const bool Extended)
|
||||
: D3D9IndexBufferBase(pDevice, pDesc, Extended) {
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -13,8 +13,9 @@ namespace dxvk {
|
|||
|
||||
D3D9Buffer(
|
||||
D3D9DeviceEx* pDevice,
|
||||
const D3D9_BUFFER_DESC* pDesc)
|
||||
: D3D9Resource<Type...> (pDevice),
|
||||
const D3D9_BUFFER_DESC* pDesc,
|
||||
const bool Extended)
|
||||
: D3D9Resource<Type...> (pDevice, pDesc->Pool, Extended ),
|
||||
m_buffer (pDevice, pDesc) {
|
||||
|
||||
}
|
||||
|
@ -57,7 +58,8 @@ namespace dxvk {
|
|||
|
||||
D3D9VertexBuffer(
|
||||
D3D9DeviceEx* pDevice,
|
||||
const D3D9_BUFFER_DESC* pDesc);
|
||||
const D3D9_BUFFER_DESC* pDesc,
|
||||
const bool Extended);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE QueryInterface(
|
||||
REFIID riid,
|
||||
|
@ -76,7 +78,8 @@ namespace dxvk {
|
|||
|
||||
D3D9IndexBuffer(
|
||||
D3D9DeviceEx* pDevice,
|
||||
const D3D9_BUFFER_DESC* pDesc);
|
||||
const D3D9_BUFFER_DESC* pDesc,
|
||||
const bool Extended);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE QueryInterface(
|
||||
REFIID riid,
|
||||
|
|
|
@ -14,7 +14,7 @@ namespace dxvk {
|
|||
if (m_mapMode == D3D9_COMMON_BUFFER_MAP_MODE_BUFFER)
|
||||
m_stagingBuffer = CreateStagingBuffer();
|
||||
|
||||
m_sliceHandle = GetMapBuffer()->getSliceHandle();
|
||||
m_allocation = GetMapBuffer()->storage();
|
||||
|
||||
if (m_desc.Pool != D3DPOOL_DEFAULT)
|
||||
m_dirtyRange = D3D9Range(0, m_desc.Size);
|
||||
|
@ -46,7 +46,20 @@ namespace dxvk {
|
|||
|
||||
|
||||
HRESULT D3D9CommonBuffer::ValidateBufferProperties(const D3D9_BUFFER_DESC* pDesc) {
|
||||
if (pDesc->Size == 0)
|
||||
if (unlikely(pDesc->Size == 0))
|
||||
return D3DERR_INVALIDCALL;
|
||||
|
||||
// Neither vertex nor index buffers can be created in D3DPOOL_SCRATCH
|
||||
// or in D3DPOOL_MANAGED with D3DUSAGE_DYNAMIC.
|
||||
if (unlikely(pDesc->Pool == D3DPOOL_SCRATCH
|
||||
|| (pDesc->Pool == D3DPOOL_MANAGED && (pDesc->Usage & D3DUSAGE_DYNAMIC))))
|
||||
return D3DERR_INVALIDCALL;
|
||||
|
||||
// D3DUSAGE_AUTOGENMIPMAP, D3DUSAGE_DEPTHSTENCIL and D3DUSAGE_RENDERTARGET
|
||||
// are not permitted on index or vertex buffers.
|
||||
if (unlikely((pDesc->Usage & D3DUSAGE_AUTOGENMIPMAP)
|
||||
|| (pDesc->Usage & D3DUSAGE_DEPTHSTENCIL)
|
||||
|| (pDesc->Usage & D3DUSAGE_RENDERTARGET)))
|
||||
return D3DERR_INVALIDCALL;
|
||||
|
||||
return D3D_OK;
|
||||
|
@ -74,14 +87,6 @@ namespace dxvk {
|
|||
if (!(m_desc.Usage & (D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY)))
|
||||
return D3D9_COMMON_BUFFER_MAP_MODE_BUFFER;
|
||||
|
||||
// Tests show that DISCARD does not work for pure SWVP devices.
|
||||
// So force staging buffer path to avoid stalls.
|
||||
// Dark Romance: Vampire in Love also expects draws to be synchronous
|
||||
// and breaks if we respect NOOVERWRITE.
|
||||
// D&D Temple of Elemental Evil breaks if we respect DISCARD.
|
||||
if (m_parent->CanOnlySWVP())
|
||||
return D3D9_COMMON_BUFFER_MAP_MODE_BUFFER;
|
||||
|
||||
if (!options->allowDirectBufferMapping)
|
||||
return D3D9_COMMON_BUFFER_MAP_MODE_BUFFER;
|
||||
|
||||
|
@ -119,12 +124,20 @@ namespace dxvk {
|
|||
info.stages |= VK_PIPELINE_STAGE_HOST_BIT;
|
||||
info.access |= VK_ACCESS_HOST_WRITE_BIT;
|
||||
|
||||
if (!(m_desc.Usage & D3DUSAGE_WRITEONLY))
|
||||
info.access |= VK_ACCESS_HOST_READ_BIT;
|
||||
|
||||
memoryFlags |= VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT
|
||||
| VK_MEMORY_PROPERTY_HOST_COHERENT_BIT
|
||||
| VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
|
||||
| VK_MEMORY_PROPERTY_HOST_COHERENT_BIT;
|
||||
|
||||
if ((m_desc.Usage & (D3DUSAGE_WRITEONLY | D3DUSAGE_DYNAMIC)) == 0
|
||||
|| DoPerDrawUpload()
|
||||
|| m_parent->CanOnlySWVP()
|
||||
|| m_parent->GetOptions()->cachedDynamicBuffers) {
|
||||
// Never use uncached memory on devices that support SWVP because we might end up reading from it.
|
||||
|
||||
info.access |= VK_ACCESS_HOST_READ_BIT;
|
||||
memoryFlags |= VK_MEMORY_PROPERTY_HOST_CACHED_BIT;
|
||||
} else {
|
||||
memoryFlags |= VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
|
||||
}
|
||||
}
|
||||
else {
|
||||
info.stages |= VK_PIPELINE_STAGE_TRANSFER_BIT;
|
||||
|
@ -134,12 +147,6 @@ namespace dxvk {
|
|||
memoryFlags |= VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
|
||||
}
|
||||
|
||||
if ((memoryFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) && m_parent->GetOptions()->cachedDynamicBuffers) {
|
||||
memoryFlags &= ~VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
|
||||
memoryFlags |= VK_MEMORY_PROPERTY_HOST_COHERENT_BIT
|
||||
| VK_MEMORY_PROPERTY_HOST_CACHED_BIT;
|
||||
}
|
||||
|
||||
return m_parent->GetDXVKDevice()->createBuffer(info, memoryFlags);
|
||||
}
|
||||
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue