mirror of
https://github.com/doitsujin/dxvk.git
synced 2025-03-06 20:58:37 +01:00
Compare commits
817 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 |
346 changed files with 35285 additions and 16517 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\*
|
||||
|
|
|
@ -56,6 +56,7 @@ The `DXVK_HUD` environment variable controls a HUD which can display the framera
|
|||
- `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.
|
||||
|
@ -121,7 +122,7 @@ 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
|
||||
|
||||
|
@ -185,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.1
|
||||
2.5.3
|
||||
|
|
6
buildenv.h.in
Normal file
6
buildenv.h.in
Normal file
|
@ -0,0 +1,6 @@
|
|||
#pragma once
|
||||
|
||||
#define DXVK_TARGET "@BUILD_TARGET@"
|
||||
#define DXVK_COMPILER "@BUILD_COMPILER@"
|
||||
#define DXVK_COMPILER_VERSION "@BUILD_COMPILER_VERSION@"
|
||||
|
174
dxvk.conf
174
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,15 +191,6 @@
|
|||
# dxgi.maxSharedMemory = 0
|
||||
|
||||
|
||||
# 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
|
||||
|
@ -138,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,
|
||||
|
@ -154,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
|
||||
|
@ -181,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
|
||||
|
@ -265,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
|
||||
|
@ -386,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
|
||||
|
@ -401,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
|
||||
|
@ -480,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)
|
||||
|
|
|
@ -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.1', 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;
|
||||
|
||||
|
@ -94,32 +97,25 @@ namespace dxvk {
|
|||
if (m_desc.CPUAccessFlags)
|
||||
m_11on12.Resource->Map(0, nullptr, &importInfo.mapPtr);
|
||||
|
||||
// D3D12 will always have BDA enabled
|
||||
info.usage |= VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT;
|
||||
|
||||
m_buffer = m_parent->GetDXVKDevice()->importBuffer(info, importInfo, GetMemoryFlags());
|
||||
m_mapped = m_buffer->getSliceHandle();
|
||||
|
||||
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);
|
||||
|
||||
// Prevent buffer renaming for buffers that are not mappable, so
|
||||
// that interop interfaces can safely query the GPU address.
|
||||
if (m_mapMode == D3D11_COMMON_BUFFER_MAP_MODE_NONE
|
||||
&& m_parent->GetDXVKDevice()->features().vk12.bufferDeviceAddress)
|
||||
info.usage |= VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT;
|
||||
|
||||
// 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, memoryFlags);
|
||||
m_mapped = m_buffer->getSliceHandle();
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -216,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))
|
||||
|
@ -375,6 +383,8 @@ 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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
@ -146,11 +158,10 @@ namespace dxvk {
|
|||
D3D11Device* parent = static_cast<D3D11Device*>(m_ctx->GetParentInterface());
|
||||
DxvkBarrierControlFlags flags = parent->GetOptionsBarrierControlFlags();
|
||||
|
||||
if (ControlFlags & D3D11_VK_BARRIER_CONTROL_IGNORE_WRITE_AFTER_WRITE)
|
||||
flags.set(DxvkBarrierControl::IgnoreWriteAfterWrite);
|
||||
|
||||
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,10 +16,10 @@ 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([
|
||||
|
@ -30,6 +30,10 @@ namespace dxvk {
|
|||
|
||||
ctx->setBarrierControl(cBarrierControlFlags);
|
||||
});
|
||||
|
||||
// Stall here so that external submissions to the
|
||||
// CS thread can actually access the command list
|
||||
SynchronizeCsThread(DxvkCsThread::SynchronizeAll);
|
||||
|
||||
ClearState();
|
||||
}
|
||||
|
@ -93,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);
|
||||
}
|
||||
|
||||
|
@ -152,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);
|
||||
}
|
||||
|
||||
|
@ -161,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);
|
||||
}
|
||||
|
||||
|
@ -181,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;
|
||||
}
|
||||
|
@ -195,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([
|
||||
|
@ -214,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
|
||||
|
@ -275,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;
|
||||
}
|
||||
|
||||
|
||||
|
@ -323,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;
|
||||
}
|
||||
|
||||
|
@ -332,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;
|
||||
|
@ -364,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);
|
||||
|
@ -377,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;
|
||||
|
@ -412,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
|
||||
|
@ -441,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);
|
||||
|
@ -495,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;
|
||||
|
@ -522,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
|
||||
|
@ -544,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;
|
||||
}
|
||||
|
@ -570,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);
|
||||
}
|
||||
|
||||
|
||||
|
@ -610,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())
|
||||
|
@ -668,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);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -696,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);
|
||||
}
|
||||
|
||||
|
||||
|
@ -723,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);
|
||||
|
@ -830,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) {
|
||||
|
@ -852,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));
|
||||
}
|
||||
|
||||
|
@ -919,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();
|
||||
|
||||
|
@ -938,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;
|
||||
|
||||
|
@ -959,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();
|
||||
|
@ -975,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();
|
||||
}
|
||||
|
@ -436,13 +479,13 @@ namespace dxvk {
|
|||
const Rc<DxvkAdapter>& Adapter);
|
||||
|
||||
DxvkBarrierControlFlags GetOptionsBarrierControlFlags() {
|
||||
DxvkBarrierControlFlags barrierControl;
|
||||
DxvkBarrierControlFlags barrierControl = 0u;
|
||||
|
||||
if (m_d3d11Options.relaxedBarriers)
|
||||
barrierControl.set(DxvkBarrierControl::IgnoreWriteAfterWrite);
|
||||
barrierControl.set(DxvkBarrierControl::ComputeAllowWriteOnlyOverlap);
|
||||
|
||||
if (m_d3d11Options.ignoreGraphicsBarriers)
|
||||
barrierControl.set(DxvkBarrierControl::IgnoreGraphicsBarriers);
|
||||
if (m_d3d11Options.relaxedBarriers || m_d3d11Options.relaxedGraphicsBarriers)
|
||||
barrierControl.set(DxvkBarrierControl::GraphicsAllowReadWriteOverlap);
|
||||
|
||||
return barrierControl;
|
||||
}
|
||||
|
@ -592,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;
|
||||
|
@ -709,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
|
||||
*/
|
||||
|
@ -872,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) {
|
||||
|
@ -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,36 +302,74 @@ 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::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();
|
||||
}
|
||||
|
||||
|
||||
|
@ -294,13 +380,10 @@ namespace dxvk {
|
|||
// 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.
|
||||
auto mapMode = pResource->GetMapMode();
|
||||
if (pResource->HasImage()) {
|
||||
ExecuteFlush();
|
||||
|
||||
if (mapMode == D3D11_COMMON_TEXTURE_MAP_MODE_NONE
|
||||
|| mapMode == D3D11_COMMON_TEXTURE_MAP_MODE_BUFFER) {
|
||||
FlushInternal();
|
||||
|
||||
m_device->waitForResource(pResource->GetImage(), DxvkAccess::Write);
|
||||
m_device->waitForResource(*pResource->GetImage(), DxvkAccess::Write);
|
||||
}
|
||||
|
||||
// If a keyed mutex is used, initialize that to the correct state as well.
|
||||
|
@ -313,4 +396,16 @@ namespace dxvk {
|
|||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
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,12 +98,30 @@ namespace dxvk {
|
|||
void InitTiledTexture(
|
||||
D3D11CommonTexture* pTexture);
|
||||
|
||||
void FlushImplicit();
|
||||
void FlushInternal();
|
||||
void ThrottleAllocationLocked();
|
||||
|
||||
void ExecuteFlush();
|
||||
|
||||
void ExecuteFlushLocked();
|
||||
|
||||
void SyncSharedTexture(
|
||||
D3D11CommonTexture* pResource);
|
||||
|
||||
void FlushCsChunkLocked();
|
||||
|
||||
void NotifyContextFlushLocked();
|
||||
|
||||
template<typename Cmd>
|
||||
void EmitCs(Cmd&& command) {
|
||||
std::lock_guard<dxvk::mutex> lock(m_csMutex);
|
||||
|
||||
if (unlikely(!m_csChunk->push(command))) {
|
||||
FlushCsChunkLocked();
|
||||
|
||||
m_csChunk->push(command);
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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,7 +28,6 @@ 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->reproducibleCommandStream = config.getOption<bool>("d3d11.reproducibleCommandStream", false);
|
||||
|
@ -36,16 +35,6 @@ namespace dxvk {
|
|||
// Clamp LOD bias so that people don't abuse this in unintended ways
|
||||
this->samplerLodBias = dxvk::fclamp(this->samplerLodBias, -2.0f, 1.0f);
|
||||
|
||||
int32_t maxImplicitDiscardSize = config.getOption<int32_t>("d3d11.maxImplicitDiscardSize", 256);
|
||||
this->maxImplicitDiscardSize = maxImplicitDiscardSize >= 0
|
||||
? VkDeviceSize(maxImplicitDiscardSize) << 10
|
||||
: VkDeviceSize(~0ull);
|
||||
|
||||
int32_t maxDynamicImageBufferSize = config.getOption<int32_t>("d3d11.maxDynamicImageBufferSize", -1);
|
||||
this->maxDynamicImageBufferSize = maxDynamicImageBufferSize >= 0
|
||||
? VkDeviceSize(maxDynamicImageBufferSize) << 10
|
||||
: VkDeviceSize(~0ull);
|
||||
|
||||
auto cachedDynamicResources = config.getOption<std::string>("d3d11.cachedDynamicResources", std::string());
|
||||
|
||||
if (IsAPITracingDXGI()) {
|
||||
|
@ -72,4 +61,4 @@ namespace dxvk {
|
|||
this->shaderDumpPath = env::getEnvVar("DXVK_SHADER_DUMP_PATH");
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,115 +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;
|
||||
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;
|
||||
}
|
||||
|
@ -357,139 +357,137 @@ namespace dxvk {
|
|||
}
|
||||
|
||||
|
||||
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) {
|
||||
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_SUBOPTIMAL_KHR)
|
||||
break;
|
||||
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();
|
||||
}
|
||||
|
||||
|
||||
|
@ -502,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 = 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;
|
||||
|
@ -602,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));
|
||||
}
|
||||
|
||||
|
||||
|
@ -661,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());
|
||||
|
@ -696,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,14 +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,33 +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,124 +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:
|
||||
|
@ -167,17 +166,17 @@ 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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -185,6 +184,9 @@ namespace dxvk {
|
|||
D3D11ShaderResourceView::~D3D11ShaderResourceView() {
|
||||
ResourceReleasePrivate(m_resource);
|
||||
m_resource = nullptr;
|
||||
|
||||
m_imageView = nullptr;
|
||||
m_bufferView = nullptr;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -25,87 +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:
|
||||
|
@ -113,17 +112,16 @@ 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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -131,6 +129,10 @@ namespace dxvk {
|
|||
D3D11UnorderedAccessView::~D3D11UnorderedAccessView() {
|
||||
ResourceReleasePrivate(m_resource);
|
||||
m_resource = nullptr;
|
||||
|
||||
m_bufferView = nullptr;
|
||||
m_counterView = nullptr;
|
||||
m_imageView = nullptr;
|
||||
}
|
||||
|
||||
|
||||
|
@ -448,16 +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,
|
||||
|
@ -67,11 +68,13 @@ namespace dxvk {
|
|||
}
|
||||
|
||||
private:
|
||||
|
||||
std::vector<BYTE> m_data;
|
||||
DWORD m_fvf;
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
// Main handler for batching D3D8 draw calls.
|
||||
class D3D8Batcher {
|
||||
|
||||
|
@ -79,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)) {
|
||||
|
@ -115,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;
|
||||
|
@ -231,6 +235,7 @@ namespace dxvk {
|
|||
}
|
||||
|
||||
private:
|
||||
|
||||
D3D8Device* m_device8;
|
||||
Com<d3d9::IDirect3DDevice9> m_device;
|
||||
|
||||
|
@ -239,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,8 +16,7 @@ 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();
|
||||
}
|
||||
|
@ -49,9 +49,10 @@ namespace dxvk {
|
|||
}
|
||||
|
||||
protected:
|
||||
|
||||
const D3D8Options* m_options;
|
||||
const D3DPOOL m_pool;
|
||||
const DWORD m_usage;
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
@ -61,18 +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) {
|
||||
return GetD3D9()->GetDesc(reinterpret_cast<d3d9::D3DVERTEXBUFFER_DESC*>(pDesc));
|
||||
}
|
||||
HRESULT STDMETHODCALLTYPE GetDesc(D3DVERTEXBUFFER_DESC* pDesc);
|
||||
|
||||
};
|
||||
|
||||
|
@ -82,18 +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 {
|
||||
return GetD3D9()->GetDesc(reinterpret_cast<d3d9::D3DINDEXBUFFER_DESC*>(pDesc));
|
||||
}
|
||||
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,169 +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;
|
||||
|
||||
// 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 -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
|
@ -27,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();
|
||||
|
@ -206,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);
|
||||
|
@ -306,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(
|
||||
|
@ -326,7 +327,7 @@ namespace dxvk {
|
|||
UINT* pBaseVertexIndex);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE CreatePixelShader(
|
||||
const DWORD* pFunction,
|
||||
const DWORD* pFunction,
|
||||
DWORD* pHandle);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE SetPixelShader(DWORD Handle);
|
||||
|
@ -356,8 +357,6 @@ namespace dxvk {
|
|||
|
||||
HRESULT STDMETHODCALLTYPE DeletePatch(UINT Handle);
|
||||
|
||||
public: // Internal Methods //
|
||||
|
||||
const D3D8Options* GetOptions() const {
|
||||
return &m_d3d8Options;
|
||||
}
|
||||
|
@ -384,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;
|
||||
|
@ -394,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;
|
||||
|
@ -424,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;
|
||||
|
@ -435,15 +448,13 @@ 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;
|
||||
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;
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
@ -126,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
|
||||
|
@ -154,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?
|
||||
|
@ -186,21 +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
|
||||
#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,144 +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) {
|
||||
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;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
#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,169 +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) {
|
||||
if (unlikely(pCaps == nullptr))
|
||||
return D3DERR_INVALIDCALL;
|
||||
|
||||
d3d9::D3DCAPS9 caps9;
|
||||
HRESULT res = m_d3d9->GetDeviceCaps(Adapter, (d3d9::D3DDEVTYPE)DeviceType, &caps9);
|
||||
|
||||
if (likely(SUCCEEDED(res)))
|
||||
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;
|
||||
|
||||
Com<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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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,56 +1,65 @@
|
|||
#pragma once
|
||||
|
||||
#include "d3d8_include.h"
|
||||
#include "../d3d9/d3d9_bridge.h"
|
||||
#include "../util/config/config.h"
|
||||
|
||||
namespace dxvk {
|
||||
struct D3D8Options {
|
||||
|
||||
/// Some games rely on undefined behavior by using undeclared vertex shader inputs.
|
||||
/// The simplest way to fix them is to simply modify their vertex shader decl.
|
||||
///
|
||||
/// This option takes a comma-separated list of colon-separated number pairs, where
|
||||
/// the first number is a D3DVSDE_REGISTER value, the second is a D3DVSDT_TYPE value.
|
||||
/// e.g. "0:2,3:2,7:1" for float3 position : v0, float3 normal : v3, float2 uv : v7
|
||||
std::vector<std::pair<D3DVSDE_REGISTER, D3DVSDT_TYPE>> forceVsDecl;
|
||||
|
||||
/// Specialized drawcall batcher, typically for games that draw a lot of similar
|
||||
/// geometry in separate drawcalls (sometimes even one triangle at a time).
|
||||
///
|
||||
/// May hurt performance outside of specifc games that benefit from it.
|
||||
bool batching = false;
|
||||
|
||||
/// The Lord of the Rings: The Fellowship of the Ring tries to create a P8 texture
|
||||
/// in D3DPOOL_MANAGED on Nvidia and Intel, which fails, but has a separate code
|
||||
/// path for ATI/AMD that creates it in D3DPOOL_SCRATCH instead, which works.
|
||||
///
|
||||
/// The internal logic determining this path doesn't seem to be d3d-related, but
|
||||
/// the game works universally if we mimic its own ATI/AMD workaround during P8
|
||||
/// texture creation.
|
||||
///
|
||||
/// Early Nvidia GPUs, such as the GeForce 4 generation cards, included and exposed
|
||||
/// P8 texture support. However, it was no longer advertised with cards in the FX series
|
||||
/// and above. Most likely ATI/AMD drivers never supported P8 in the first place.
|
||||
bool placeP8InScratch = false;
|
||||
|
||||
/// Rayman 3 relies on D3DLOCK_DISCARD being ignored for everything except D3DUSAGE_DYNAMIC +
|
||||
/// D3DUSAGE_WRITEONLY buffers, however this approach incurs a performance penalty.
|
||||
///
|
||||
/// Some titles might abuse this early D3D8 quirk, however at some point in its history
|
||||
/// it was brought in line with standard D3D9 behavior.
|
||||
bool forceLegacyDiscard = false;
|
||||
|
||||
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);
|
||||
|
||||
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,87 +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) {
|
||||
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 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,49 +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 {
|
||||
InitReturnPtr(ppBackBuffer);
|
||||
HRESULT STDMETHODCALLTYPE Present(const RECT *src, const RECT *dst, HWND hWnd, const RGNDATA *dirtyRegion) final;
|
||||
|
||||
if (unlikely(ppBackBuffer == nullptr))
|
||||
return D3DERR_INVALIDCALL;
|
||||
|
||||
// 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);
|
||||
|
||||
if (likely(SUCCEEDED(res))) {
|
||||
m_backBuffer = new D3D8Surface(GetParent(), std::move(pSurface9));
|
||||
*ppBackBuffer = m_backBuffer.ref();
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
*ppBackBuffer = m_backBuffer.ref();
|
||||
return D3D_OK;
|
||||
}
|
||||
HRESULT STDMETHODCALLTYPE GetBackBuffer(
|
||||
UINT BackBuffer,
|
||||
D3DBACKBUFFER_TYPE Type,
|
||||
IDirect3DSurface8** ppBackBuffer) final;
|
||||
|
||||
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,254 +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(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, 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) {
|
||||
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 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) {
|
||||
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 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) {
|
||||
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 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,46 +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) {
|
||||
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 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,14 +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;
|
||||
|
||||
|
@ -186,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;
|
||||
|
@ -194,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);
|
||||
|
@ -398,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
|
||||
|
@ -555,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 */
|
||||
|
@ -612,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;
|
||||
|
@ -806,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;
|
||||
|
@ -816,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] compatMode 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;
|
||||
|
|
|
@ -133,17 +133,13 @@ namespace dxvk {
|
|||
return DxvkBufferSlice();
|
||||
}
|
||||
|
||||
inline DxvkBufferSliceHandle AllocMapSlice() {
|
||||
return GetMapBuffer()->allocSlice();
|
||||
inline Rc<DxvkResourceAllocation> DiscardMapSlice() {
|
||||
m_allocation = GetMapBuffer()->allocateStorage();
|
||||
return m_allocation;
|
||||
}
|
||||
|
||||
inline DxvkBufferSliceHandle DiscardMapSlice() {
|
||||
m_sliceHandle = GetMapBuffer()->allocSlice();
|
||||
return m_sliceHandle;
|
||||
}
|
||||
|
||||
inline DxvkBufferSliceHandle GetMappedSlice() const {
|
||||
return m_sliceHandle;
|
||||
inline Rc<DxvkResourceAllocation> GetMappedSlice() const {
|
||||
return m_allocation;
|
||||
}
|
||||
|
||||
inline DWORD GetMapFlags() const { return m_mapFlags; }
|
||||
|
@ -240,7 +236,7 @@ namespace dxvk {
|
|||
Rc<DxvkBuffer> m_buffer;
|
||||
Rc<DxvkBuffer> m_stagingBuffer;
|
||||
|
||||
DxvkBufferSliceHandle m_sliceHandle;
|
||||
Rc<DxvkResourceAllocation> m_allocation;
|
||||
|
||||
D3D9Range m_dirtyRange;
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@ namespace dxvk {
|
|||
: m_device(pDevice), m_desc(*pDesc), m_type(ResourceType), m_d3d9Interop(pInterface, this) {
|
||||
if (m_desc.Format == D3D9Format::Unknown)
|
||||
m_desc.Format = (m_desc.Usage & D3DUSAGE_DEPTHSTENCIL)
|
||||
? D3D9Format::D32
|
||||
? D3D9Format::D24X8
|
||||
: D3D9Format::X8R8G8B8;
|
||||
|
||||
m_exposedMipLevels = m_desc.MipLevels;
|
||||
|
@ -76,7 +76,7 @@ namespace dxvk {
|
|||
CreateSampleView(0);
|
||||
|
||||
if (!IsManaged()) {
|
||||
m_size = m_image->memory().length();
|
||||
m_size = m_image->getMemoryInfo().size;
|
||||
if (!m_device->ChangeReportedMemory(-m_size))
|
||||
throw DxvkError("D3D9: Reporting out of memory from tracking.");
|
||||
}
|
||||
|
@ -156,6 +156,16 @@ namespace dxvk {
|
|||
|
||||
if (pDesc->Width == 0 || pDesc->Height == 0 || pDesc->Depth == 0)
|
||||
return D3DERR_INVALIDCALL;
|
||||
|
||||
// Native drivers won't allow the creation of DXT format
|
||||
// textures that aren't aligned to block dimensions.
|
||||
if (IsDXTFormat(pDesc->Format)) {
|
||||
D3D9_FORMAT_BLOCK_SIZE blockSize = GetFormatAlignedBlockSize(pDesc->Format);
|
||||
|
||||
if ((blockSize.Width && (pDesc->Width & (blockSize.Width - 1)))
|
||||
|| (blockSize.Height && (pDesc->Height & (blockSize.Height - 1))))
|
||||
return D3DERR_INVALIDCALL;
|
||||
}
|
||||
|
||||
if (FAILED(DecodeMultiSampleType(pDevice->GetDXVKDevice(), pDesc->MultiSample, pDesc->MultisampleQuality, nullptr)))
|
||||
return D3DERR_INVALIDCALL;
|
||||
|
@ -168,11 +178,46 @@ namespace dxvk {
|
|||
if (pDesc->Usage & D3DUSAGE_WRITEONLY)
|
||||
return D3DERR_INVALIDCALL;
|
||||
|
||||
constexpr DWORD usageRTOrDS = D3DUSAGE_RENDERTARGET | D3DUSAGE_DEPTHSTENCIL;
|
||||
|
||||
// RENDERTARGET and DEPTHSTENCIL must be default pool
|
||||
constexpr DWORD incompatibleUsages = D3DUSAGE_RENDERTARGET | D3DUSAGE_DEPTHSTENCIL;
|
||||
if (pDesc->Pool != D3DPOOL_DEFAULT && (pDesc->Usage & incompatibleUsages))
|
||||
if (pDesc->Pool != D3DPOOL_DEFAULT && (pDesc->Usage & usageRTOrDS))
|
||||
return D3DERR_INVALIDCALL;
|
||||
|
||||
|
||||
// RENDERTARGET and DEPTHSTENCIL in D3DPOOL_DEFAULT
|
||||
// can not also have DYNAMIC usage
|
||||
if (pDesc->Pool == D3DPOOL_DEFAULT &&
|
||||
(pDesc->Usage & usageRTOrDS) &&
|
||||
(pDesc->Usage & D3DUSAGE_DYNAMIC))
|
||||
return D3DERR_INVALIDCALL;
|
||||
|
||||
const bool isPlainSurface = ResourceType == D3DRTYPE_SURFACE && !(pDesc->Usage & usageRTOrDS);
|
||||
const bool isDepthStencilFormat = IsDepthStencilFormat(pDesc->Format);
|
||||
|
||||
// With the exception of image surfaces (d3d8)
|
||||
// or plain offscreen surfaces (d3d9), depth stencil
|
||||
// formats can only be used in D3DPOOL_DEFAULT
|
||||
if (!isPlainSurface && pDesc->Pool != D3DPOOL_DEFAULT && isDepthStencilFormat)
|
||||
return D3DERR_INVALIDCALL;
|
||||
|
||||
// Depth stencil formats can not have RENDERTARGET
|
||||
// usage, and nothing except depth stencil formats
|
||||
// can have DEPTHSTENCIL usage
|
||||
if (( isDepthStencilFormat && (pDesc->Usage & D3DUSAGE_RENDERTARGET)) ||
|
||||
(!isDepthStencilFormat && (pDesc->Usage & D3DUSAGE_DEPTHSTENCIL)))
|
||||
return D3DERR_INVALIDCALL;
|
||||
|
||||
// Volume textures can not be used as render targets
|
||||
if (ResourceType == D3DRTYPE_VOLUMETEXTURE &&
|
||||
(pDesc->Usage & D3DUSAGE_RENDERTARGET))
|
||||
return D3DERR_INVALIDCALL;
|
||||
|
||||
// Volume textures in D3DPOOL_SCRATCH must not have DYNAMIC usage
|
||||
if (ResourceType == D3DRTYPE_VOLUMETEXTURE
|
||||
&& pDesc->Pool == D3DPOOL_SCRATCH
|
||||
&& (pDesc->Usage & D3DUSAGE_DYNAMIC))
|
||||
return D3DERR_INVALIDCALL;
|
||||
|
||||
// Use the maximum possible mip level count if the supplied
|
||||
// mip level count is either unspecified (0) or invalid
|
||||
const uint32_t maxMipLevelCount = pDesc->MultiSample <= D3DMULTISAMPLE_NONMASKABLE
|
||||
|
@ -186,13 +231,13 @@ namespace dxvk {
|
|||
pDesc->MipLevels = maxMipLevelCount;
|
||||
|
||||
if (unlikely(pDesc->Discard)) {
|
||||
if (!IsDepthStencilFormat(pDesc->Format))
|
||||
if (!isDepthStencilFormat)
|
||||
return D3DERR_INVALIDCALL;
|
||||
|
||||
if (pDesc->Format == D3D9Format::D32_LOCKABLE
|
||||
|| pDesc->Format == D3D9Format::D32F_LOCKABLE
|
||||
|| pDesc->Format == D3D9Format::D16_LOCKABLE
|
||||
|| pDesc->Format == D3D9Format::S8_LOCKABLE)
|
||||
|| pDesc->Format == D3D9Format::D32F_LOCKABLE
|
||||
|| pDesc->Format == D3D9Format::D16_LOCKABLE
|
||||
|| pDesc->Format == D3D9Format::S8_LOCKABLE)
|
||||
return D3DERR_INVALIDCALL;
|
||||
}
|
||||
|
||||
|
@ -296,7 +341,8 @@ namespace dxvk {
|
|||
imageInfo.numLayers = m_desc.ArraySize;
|
||||
imageInfo.mipLevels = m_desc.MipLevels;
|
||||
imageInfo.usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT
|
||||
| VK_IMAGE_USAGE_TRANSFER_DST_BIT;
|
||||
| VK_IMAGE_USAGE_TRANSFER_DST_BIT
|
||||
| m_desc.ImageUsage;
|
||||
imageInfo.stages = VK_PIPELINE_STAGE_TRANSFER_BIT
|
||||
| m_device->GetEnabledShaderStages();
|
||||
imageInfo.access = VK_ACCESS_TRANSFER_READ_BIT
|
||||
|
@ -320,6 +366,7 @@ namespace dxvk {
|
|||
if (m_mapping.ConversionFormatInfo.FormatType != D3D9ConversionFormat_None) {
|
||||
imageInfo.usage |= VK_IMAGE_USAGE_STORAGE_BIT;
|
||||
imageInfo.stages |= VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
|
||||
imageInfo.shared = true;
|
||||
}
|
||||
|
||||
DecodeMultiSampleType(m_device->GetDXVKDevice(), m_desc.MultiSample, m_desc.MultisampleQuality, &imageInfo.sampleCount);
|
||||
|
@ -381,11 +428,6 @@ namespace dxvk {
|
|||
if (imageInfo.tiling == VK_IMAGE_TILING_OPTIMAL && imageInfo.sharing.mode == DxvkSharedHandleMode::None)
|
||||
imageInfo.layout = OptimizeLayout(imageInfo.usage);
|
||||
|
||||
// For some formats, we need to enable render target
|
||||
// capabilities if available, but these should
|
||||
// in no way affect the default image layout
|
||||
imageInfo.usage |= EnableMetaCopyUsage(imageInfo.format, imageInfo.tiling, imageInfo.sampleCount);
|
||||
|
||||
// Check if we can actually create the image
|
||||
if (!CheckImageSupport(&imageInfo, imageInfo.tiling)) {
|
||||
throw DxvkError(str::format(
|
||||
|
@ -459,49 +501,6 @@ namespace dxvk {
|
|||
}
|
||||
|
||||
|
||||
VkImageUsageFlags D3D9CommonTexture::EnableMetaCopyUsage(
|
||||
VkFormat Format,
|
||||
VkImageTiling Tiling,
|
||||
VkSampleCountFlags SampleCount) const {
|
||||
VkFormatFeatureFlags2 requestedFeatures = 0;
|
||||
|
||||
if (Format == VK_FORMAT_D16_UNORM || Format == VK_FORMAT_D32_SFLOAT)
|
||||
requestedFeatures |= VK_FORMAT_FEATURE_2_DEPTH_STENCIL_ATTACHMENT_BIT;
|
||||
|
||||
if (Format == VK_FORMAT_R16_UNORM || Format == VK_FORMAT_R32_SFLOAT)
|
||||
requestedFeatures |= VK_FORMAT_FEATURE_2_COLOR_ATTACHMENT_BIT;
|
||||
|
||||
// We need SAMPLED_BIT for StretchRect.
|
||||
// However, StretchRect does not allow stretching for DS formats,
|
||||
// so unless we need to resolve, it should always hit code paths that only need TRANSFER_BIT.
|
||||
if (!IsDepthStencilFormat(m_desc.Format) || SampleCount != VK_SAMPLE_COUNT_1_BIT)
|
||||
requestedFeatures |= VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_BIT;
|
||||
|
||||
if (!requestedFeatures)
|
||||
return 0;
|
||||
|
||||
// Enable usage flags for all supported and requested features
|
||||
DxvkFormatFeatures properties = m_device->GetDXVKDevice()->getFormatFeatures(Format);
|
||||
|
||||
requestedFeatures &= Tiling == VK_IMAGE_TILING_OPTIMAL
|
||||
? properties.optimal
|
||||
: properties.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;
|
||||
}
|
||||
|
||||
|
||||
VkImageType D3D9CommonTexture::GetImageTypeFromResourceType(D3DRESOURCETYPE Type) {
|
||||
switch (Type) {
|
||||
case D3DRTYPE_SURFACE:
|
||||
|
@ -529,8 +528,6 @@ namespace dxvk {
|
|||
|
||||
|
||||
VkImageLayout D3D9CommonTexture::OptimizeLayout(VkImageUsageFlags Usage) const {
|
||||
const VkImageUsageFlags usageFlags = Usage;
|
||||
|
||||
// Filter out unnecessary flags. Transfer operations
|
||||
// are handled by the backend in a transparent manner.
|
||||
// Feedback loops are handled by hazard tracking.
|
||||
|
@ -538,27 +535,30 @@ namespace dxvk {
|
|||
| VK_IMAGE_USAGE_TRANSFER_SRC_BIT
|
||||
| VK_IMAGE_USAGE_ATTACHMENT_FEEDBACK_LOOP_BIT_EXT);
|
||||
|
||||
// Storage images require GENERAL.
|
||||
if (Usage & VK_IMAGE_USAGE_STORAGE_BIT)
|
||||
return VK_IMAGE_LAYOUT_GENERAL;
|
||||
|
||||
// Use GENERAL for non-renderable images to avoid layout transitions.
|
||||
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;
|
||||
|
||||
// Fall back to GENERAL if the image is not shader-readable
|
||||
if (!(Usage & VK_IMAGE_USAGE_SAMPLED_BIT))
|
||||
return VK_IMAGE_LAYOUT_GENERAL;
|
||||
|
||||
// Otherwise, pick a layout that can be used for reading.
|
||||
return Usage & VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT
|
||||
? VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL
|
||||
: VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
|
||||
}
|
||||
|
||||
D3D9_COMMON_TEXTURE_MAP_MODE D3D9CommonTexture::DetermineMapMode() const {
|
||||
|
@ -635,35 +635,34 @@ namespace dxvk {
|
|||
UINT Lod,
|
||||
VkImageUsageFlags UsageFlags,
|
||||
bool Srgb) {
|
||||
DxvkImageViewCreateInfo viewInfo;
|
||||
DxvkImageViewKey viewInfo;
|
||||
viewInfo.format = m_mapping.ConversionFormatInfo.FormatColor != VK_FORMAT_UNDEFINED
|
||||
? PickSRGB(m_mapping.ConversionFormatInfo.FormatColor, m_mapping.ConversionFormatInfo.FormatSrgb, Srgb)
|
||||
: PickSRGB(m_mapping.FormatColor, m_mapping.FormatSrgb, Srgb);
|
||||
viewInfo.aspect = lookupFormatInfo(viewInfo.format)->aspectMask;
|
||||
viewInfo.swizzle = m_mapping.Swizzle;
|
||||
viewInfo.aspects = lookupFormatInfo(viewInfo.format)->aspectMask;
|
||||
viewInfo.usage = UsageFlags;
|
||||
viewInfo.type = GetImageViewTypeFromResourceType(m_type, Layer);
|
||||
viewInfo.minLevel = Lod;
|
||||
viewInfo.numLevels = m_desc.MipLevels - Lod;
|
||||
viewInfo.minLayer = Layer == AllLayers ? 0 : Layer;
|
||||
viewInfo.numLayers = Layer == AllLayers ? m_desc.ArraySize : 1;
|
||||
viewInfo.viewType = GetImageViewTypeFromResourceType(m_type, Layer);
|
||||
viewInfo.mipIndex = Lod;
|
||||
viewInfo.mipCount = m_desc.MipLevels - Lod;
|
||||
viewInfo.layerIndex = Layer == AllLayers ? 0 : Layer;
|
||||
viewInfo.layerCount = Layer == AllLayers ? m_desc.ArraySize : 1;
|
||||
viewInfo.packedSwizzle = DxvkImageViewKey::packSwizzle(m_mapping.Swizzle);
|
||||
|
||||
// Remove the stencil aspect if we are trying to create a regular image
|
||||
// view of a depth stencil format
|
||||
if (UsageFlags != VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT)
|
||||
viewInfo.aspect &= ~VK_IMAGE_ASPECT_STENCIL_BIT;
|
||||
viewInfo.aspects &= ~VK_IMAGE_ASPECT_STENCIL_BIT;
|
||||
|
||||
if (UsageFlags == VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT ||
|
||||
UsageFlags == VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT)
|
||||
viewInfo.numLevels = 1;
|
||||
viewInfo.mipCount = 1;
|
||||
|
||||
// Remove swizzle on depth views.
|
||||
if (UsageFlags == VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT)
|
||||
viewInfo.swizzle = { VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY,
|
||||
VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY };
|
||||
viewInfo.packedSwizzle = 0u;
|
||||
|
||||
// Create the underlying image view object
|
||||
return m_device->GetDXVKDevice()->createImageView(GetImage(), viewInfo);
|
||||
return GetImage()->createView(viewInfo);
|
||||
}
|
||||
|
||||
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue