mirror of https://github.com/doitsujin/dxvk
Compare commits
346 Commits
Author | SHA1 | Date |
---|---|---|
Blisto91 | c1f665f92b | |
WinterSnowfall | 20185a5309 | |
Blisto91 | 0c2efda804 | |
Blisto91 | c7d61b2fc0 | |
Ethan Lee | 6259e86392 | |
Ethan Lee | d5d236a1e2 | |
Ethan Lee | 10b83d184b | |
Ethan Lee | 0f7c1f753a | |
Ethan Lee | 529129c332 | |
Ethan Lee | 4055a92856 | |
Blisto91 | 7bad17c1d1 | |
Blisto91 | 6b76d70d9d | |
Philip Rebohle | 611dc60018 | |
WinterSnowfall | b2789ab894 | |
Philip Rebohle | ab715a8876 | |
talkingerbil | 1fb35b6d19 | |
Rémi Bernon | 4333ee872d | |
Rémi Bernon | b99d42c688 | |
Blisto91 | dacb8b434b | |
Philip Rebohle | ea4cb84d8a | |
Philip Rebohle | 65373792d2 | |
Lierrmm | 29253da356 | |
Robin Kertels | 79398b468d | |
Robin Kertels | e7d14e97de | |
Philip Rebohle | c613078ba8 | |
Philip Rebohle | 2970645f33 | |
Philip Rebohle | 462165da19 | |
Philip Rebohle | 3f27a0ee58 | |
Katharine Chui | aac3396671 | |
Katharine Chui | 92a43ebf65 | |
Blisto91 | 8ba5256dc7 | |
Philip Rebohle | 2b70ba8f77 | |
Philip Rebohle | 9c66c4bf1d | |
Philip Rebohle | 00872e9e4f | |
Philip Rebohle | 35157357dd | |
Philip Rebohle | 617ebf4e05 | |
Philip Rebohle | c2489d5a45 | |
Philip Rebohle | 6ef98c613f | |
Philip Rebohle | 7441137a33 | |
WinterSnowfall | 571948cfc0 | |
Martino Fontana | 133f0794bc | |
Philip Rebohle | 44695f9311 | |
Casey Bowman | 49e9ea5f5a | |
Blisto91 | 198bd3a4b8 | |
Philip Rebohle | f06c646315 | |
Philip Rebohle | 855b2746b6 | |
Blisto91 | 28c7c09bf5 | |
Philip Rebohle | 2742486540 | |
Philip Rebohle | 037d0fa1ad | |
Philip Rebohle | cbf51a7a25 | |
Philip Rebohle | 70e34dc31c | |
Philip Rebohle | c5aeb0f87a | |
Philip Rebohle | a163082770 | |
Blisto91 | 2e1a19c7fd | |
Joshua Ashton | 0beb18ef73 | |
Joshua Ashton | ef4428ab8c | |
Philip Rebohle | 1085ba713e | |
Philip Rebohle | e857b09432 | |
Kaitlyn | 538f1d13d4 | |
Kaitlyn | 783c9d4591 | |
Kaitlyn | 1a685b1c67 | |
Robin Kertels | 8b8be7c2bf | |
Billy Laws | 0776d764a4 | |
Robin Kertels | 15ddadc4de | |
Philip Rebohle | 69a52b3da0 | |
Philip Rebohle | 707ad6f328 | |
Philip Rebohle | 3a6992ea97 | |
Robin Kertels | 72c86b8229 | |
Robin Kertels | 85215b10d6 | |
Philip Rebohle | fd3fbf6607 | |
Minelelol | 0a699fddb6 | |
Blisto91 | afec5cce88 | |
Ethan Lee | 4b0e3111d1 | |
Philip Rebohle | 0414bbe2d5 | |
Robin Kertels | 20490b678f | |
Blisto91 | 428c98bc63 | |
Robin Kertels | a0e39e94fa | |
Robin Kertels | eaa732d0b3 | |
Robin Kertels | 49b18f03fe | |
Philip Rebohle | c9cea93b7b | |
Philip Rebohle | 69d74a46a0 | |
Philip Rebohle | 94098aa97d | |
Philip Rebohle | c677ba9b3e | |
Philip Rebohle | 77c7396ee1 | |
Philip Rebohle | f07e5f9eaa | |
Philip Rebohle | d5c3011f54 | |
Blisto91 | 6b3b934471 | |
Philip Rebohle | 9004c132ed | |
Philip Rebohle | 24d4c9c938 | |
Philip Rebohle | 5ded7d67f0 | |
Philip Rebohle | 234f3ea071 | |
Robin Kertels | c5a37d443a | |
Robin Kertels | f254afb4fb | |
Robin Kertels | 39c19e9299 | |
Robin Kertels | 738fd4f895 | |
Philip Rebohle | 9491b56beb | |
Robin Kertels | ab3593185f | |
Robin Kertels | e9a0fec5b3 | |
Echo J | fae78407a2 | |
Robin Kertels | 5312ef1cf9 | |
Robin Kertels | 62d64bd63a | |
Robin Kertels | f83ba898af | |
Ethan Lee | 30f2b2df31 | |
Philip Rebohle | 05cb963e22 | |
Philip Rebohle | eb339bc7e4 | |
Ethan Lee | c423819e90 | |
Tatsuyuki Ishi | e2a46a347d | |
Tatsuyuki Ishi | afc6aa70fb | |
Tatsuyuki Ishi | 799aeff560 | |
Robin Kertels | 2ca8fdf890 | |
Robin Kertels | 0841f5faf4 | |
Ethan Lee | 2334bbccb0 | |
Robin Kertels | 7d9864c077 | |
Dean Beeler | d4c5fc74e7 | |
Tatsuyuki Ishi | 6199776869 | |
Tatsuyuki Ishi | 6faf3c1acd | |
Tatsuyuki Ishi | ab6bd8b17f | |
Tatsuyuki Ishi | 89267b62ad | |
Blisto91 | 34d8e65fd7 | |
Joshua Ashton | 1568c263fb | |
Joshua Ashton | 0cd4165658 | |
Joshua Ashton | 4b8e8bed6e | |
r-a-sattarov | ac78048c23 | |
Richard Yao | 14560600a9 | |
Blisto91 | 854e06d3f0 | |
Blisto91 | eb806952d8 | |
Blisto91 | a44dfabe26 | |
spiffeeroo | 5e06cf9573 | |
Blisto91 | 2cf590f636 | |
Robin Kertels | a7a63b37c3 | |
Robin Kertels | 9cde0b5798 | |
Blisto91 | adb33d3af1 | |
Philip Rebohle | 1b31aa5dbc | |
Philip Rebohle | 03c09ce15f | |
Blisto91 | 91f7f43c35 | |
Robin Kertels | d998dee46e | |
Philip Rebohle | ea3149801f | |
xpander69 | 1cb58b0732 | |
Philip Rebohle | 2ed1778df9 | |
Philip Rebohle | a427d22cde | |
Joshua Ashton | 22c2abb9b7 | |
Blisto91 | f45911a28f | |
Blisto91 | e00db24557 | |
Paul Gofman | 552d2f0a6d | |
WinterSnowfall | 4d974685c9 | |
Blisto91 | f0ff0007dc | |
Robin Kertels | 494f7fd38d | |
WinterSnowfall | 0632da1935 | |
Philip Rebohle | 83dc4678df | |
Paul Gofman | f93cfbc26a | |
Philip Rebohle | c113b791a1 | |
Ellie Hermaszewska | 41191af3b1 | |
Philip Rebohle | 5828f0e2b9 | |
Philip Rebohle | 80e075406b | |
Margen67 | a53f0e8168 | |
Margen67 | 4705de5725 | |
Robin Kertels | 9e26964a96 | |
Blisto91 | ce2f9f35ce | |
Philip Rebohle | a3fa9c26dc | |
Joshua Ashton | ff5507769a | |
WinterSnowfall | 5c56fa0df4 | |
Tatsuyuki Ishi | 7e10021eac | |
Joshua Ashton | bbd1d84cd0 | |
Jens Peters | 02db89ac30 | |
Philip Rebohle | 92dc61f161 | |
Philip Rebohle | 6a5ed02db3 | |
Philip Rebohle | 64828e2c6c | |
Philip Rebohle | a4f2a49a02 | |
Philip Rebohle | aa41a7a351 | |
Philip Rebohle | fb71c08d8c | |
Philip Rebohle | 79f6239df3 | |
Philip Rebohle | 53a68635b2 | |
Philip Rebohle | 179c5ec998 | |
Philip Rebohle | d6e0107e23 | |
Joshua Ashton | 428ca9416d | |
Joshua Ashton | c26f40229a | |
Joshua Ashton | 8226690298 | |
Joshua Ashton | 138f727fbb | |
Philip Rebohle | c2cd129b89 | |
Philip Rebohle | 915244c00c | |
Blisto91 | 6fce094942 | |
Robin Kertels | 740ebec7ee | |
Robin Kertels | bcaaac4ad7 | |
Joshua Ashton | 1130512db5 | |
Blisto91 | 143eb8c710 | |
Philip Rebohle | 4ae542e875 | |
Philip Rebohle | 952c66fe2a | |
Philip Rebohle | b6a7714e67 | |
Etaash Mathamsetty | 037669f715 | |
Robin Kertels | 295a58afdf | |
Robin Kertels | 0746a3b91a | |
Etaash Mathamsetty | 429555a540 | |
Blisto91 | dfcd7aedd8 | |
gofman | cbda22a040 | |
Georg Lehmann | 549bd86f03 | |
WinterSnowfall | b0b46fd075 | |
Joshua Ashton | a62117cd13 | |
pchome | e598dcd77e | |
Philip Rebohle | 09857dcaa9 | |
Philip Rebohle | d66f8385c3 | |
Philip Rebohle | 007e9f4c89 | |
Philip Rebohle | 9b019d26ac | |
Philip Rebohle | 228615b639 | |
Ellie Hermaszewska | dfbebba6b5 | |
Blisto91 | 4ed04268fd | |
Blisto91 | 4ed1474030 | |
Blisto91 | 13440a5d89 | |
Blisto91 | 1daae75048 | |
Philip Rebohle | b4d87eaac0 | |
Philip Rebohle | 1e11db98d0 | |
Philip Rebohle | f689ddd838 | |
Philip Rebohle | eed43c8524 | |
Philip Rebohle | d066fbbaed | |
Philip Rebohle | a67c99943a | |
Philip Rebohle | 5ece97f769 | |
Philip Rebohle | 228cd4c331 | |
Blisto91 | 98f3887680 | |
Blisto91 | 3a9a70b5f0 | |
Philip Rebohle | 878da4984b | |
Philip Rebohle | c599f95e5d | |
Paul Gofman | 4893788d9b | |
Paul Gofman | fc952a3ca3 | |
Paul Gofman | 01ad79278b | |
Paul Gofman | 48557886de | |
Paul Gofman | 8319793a98 | |
Blisto91 | 886268fcf9 | |
Hans-Kristian Arntzen | 84e59fc9e5 | |
Blisto91 | 6be1f6d7bd | |
Joshua Ashton | 2f72115f91 | |
Alpyne | 026aa49ef8 | |
Trevonn | 3a368f4780 | |
Tatsuyuki Ishi | 2ef41bdbf6 | |
Philip Rebohle | 0f4458e173 | |
Philip Rebohle | ccb87d5ea9 | |
Alpyne | 022bf1d134 | |
Alpyne | d6e7e3e780 | |
Blisto91 | b77928b6fe | |
Philip Rebohle | 987df8a487 | |
Philip Rebohle | a7278cdab1 | |
Joshua Ashton | 3b3ebc9350 | |
Joshua Ashton | 00ae118655 | |
Joshua Ashton | 55be12daa5 | |
Joshua Ashton | 0e36a07a93 | |
Joshua Ashton | ff65599dba | |
Joshua Ashton | 6b60de2d31 | |
Joshua Ashton | 362743c1d6 | |
Joshua Ashton | 7f302fc350 | |
Philip Rebohle | 8704ed7af6 | |
Philip Rebohle | 0895858901 | |
Joshua Ashton | 80b27f95bc | |
Joshua Ashton | a791493d14 | |
Joshua Ashton | c768196251 | |
Joshua Ashton | 3625c5d481 | |
Philip Rebohle | b3cbe36c08 | |
Philip Rebohle | 166d90b04c | |
Robin Kertels | 60b6e98529 | |
Robin Kertels | a20869fb93 | |
Philip Rebohle | a287566c65 | |
Philip Rebohle | 28f48f9fdc | |
Philip Rebohle | e02a800c33 | |
Philip Rebohle | d7fa39c4eb | |
Philip Rebohle | d1e39be7e7 | |
Philip Rebohle | 438c535fe7 | |
Philip Rebohle | 7dbe4abb48 | |
Philip Rebohle | e99bc591df | |
Philip Rebohle | 08363edb05 | |
Philip Rebohle | 5d1196733b | |
Philip Rebohle | ca3492570c | |
Philip Rebohle | 215c4f8f6f | |
Robin Kertels | 5a1ebfa4ee | |
Joshua Ashton | 6f87ccdafc | |
Joshua Ashton | b30a4f0cc7 | |
Joshua Ashton | 4e9853f608 | |
Joshua Ashton | 5fbb0dd4ba | |
Joshua Ashton | 77f6f2a84b | |
Alpyne | 0b9acf3a25 | |
Timo Gurr | 211d095ee4 | |
Trevonn | 77e7e8bfba | |
Alpyne | 42a0264e69 | |
Alpyne | 5d29140f74 | |
Alpyne | 0236e780a7 | |
Alpyne | 24dbcf8fd8 | |
Alpyne | 404c984f9c | |
Alpyne | a79772322b | |
Trevonn | 36e6a7c2e5 | |
Trevonn | c5ab5be48d | |
Paul Gofman | af9bd16b8d | |
Winter Snowfall | 2c014fdb34 | |
Timo Gurr | 6478c10a18 | |
Philip Rebohle | 7388c243d2 | |
Lilium | bd575a4a46 | |
Lilium | 3fce9886f5 | |
Lilium | 5d134b877a | |
Robin Kertels | c75ed86909 | |
Robin Kertels | d1707026f9 | |
Robin Kertels | b8d36eeacc | |
Robin Kertels | 8f740c53b4 | |
Robin Kertels | 52ac271acb | |
Robin Kertels | a1a91dd766 | |
Robin Kertels | 22f6246fd6 | |
Robin Kertels | 9d6804e40a | |
Robin Kertels | 5fd025c513 | |
Robin Kertels | d9d6316609 | |
Robin Kertels | 9b877cf623 | |
Robin Kertels | 2c3f2b9ad1 | |
Robin Kertels | 1850819483 | |
Robin Kertels | 1db2e3a6ec | |
Robin Kertels | 2efd3f3698 | |
Robin Kertels | bbaf01d9e6 | |
Robin Kertels | 4a55047dde | |
Joshua Ashton | 3fddc364ee | |
Blisto91 | f3fb5ba320 | |
Philip Rebohle | 4d254b13be | |
Joshua Ashton | d241daa0b1 | |
Eric Sullivan | 2e70a2b07d | |
Robin Kertels | 52f04ca3d4 | |
Joshua Ashton | c585ea251e | |
Philip Rebohle | ab00591297 | |
Philip Rebohle | 85d52ccb88 | |
Philip Rebohle | e6be0cf996 | |
Philip Rebohle | 1728d9e89d | |
Philip Rebohle | b1b0abdbbf | |
Philip Rebohle | be875cd7e6 | |
Philip Rebohle | 0543956ea0 | |
Blisto91 | e9e0949717 | |
WinterSnowfall | 8b6cbda6de | |
Robin Kertels | 4b10846008 | |
Joshua Ashton | e0654977c9 | |
Joshua Ashton | b5c18a02ae | |
Joshua Ashton | cafd104783 | |
Joshua Ashton | 269bab2c34 | |
Joshua Ashton | 075c0bf203 | |
Joshua Ashton | 8560efa3c7 | |
Blisto91 | b9b2db510e | |
Lilium | d5c6ae2e4d | |
Lilium | 633f6663a4 | |
Robin Kertels | d2759c20ba | |
Robin Kertels | 1a2e724c16 | |
Blisto91 | 6449f583f8 | |
Joshua Ashton | f2bb1d4b69 | |
Joshua Ashton | 495dc75ab2 | |
Paul Gofman | 550e04c579 | |
WinterSnowfall | d4a7346198 | |
Blisto91 | 99b367cdd6 | |
Blisto91 | 65520fa18e | |
Joshua Ashton | f30376a1e4 |
|
@ -16,9 +16,8 @@ jobs:
|
|||
- name: Setup glslangValidator
|
||||
shell: pwsh
|
||||
run: |
|
||||
choco install vulkan-sdk -y
|
||||
Write-Output "$([System.Environment]::GetEnvironmentVariable('VULKAN_SDK', 'Machine'))\Bin" `
|
||||
| Out-File -FilePath "${Env:GITHUB_PATH}" -Append
|
||||
Invoke-WebRequest -Uri "https://raw.githubusercontent.com/HansKristian-Work/vkd3d-proton-ci/main/glslangValidator.exe" -OutFile "glslangValidator.exe"
|
||||
Write-Output "$pwd" | Out-File -FilePath "${Env:GITHUB_PATH}" -Append
|
||||
|
||||
- name: Setup Meson
|
||||
shell: pwsh
|
||||
|
|
57
README.md
57
README.md
|
@ -9,20 +9,32 @@ The most recent development builds can be found [here](https://github.com/doitsu
|
|||
Release builds can be found [here](https://github.com/doitsujin/dxvk/releases).
|
||||
|
||||
## How to use
|
||||
In order to install a DXVK package obtained from the [release](https://github.com/doitsujin/dxvk/releases) page into a given wine prefix, copy or symlink the DLLs into the following directories as follows, then open `winecfg` and manually add DLL overrides for `d3d11`, `d3d10core`, `dxgi`, and `d3d9`:
|
||||
In order to install a DXVK package obtained from the [release](https://github.com/doitsujin/dxvk/releases) page into a given wine prefix, copy or symlink the DLLs into the following directories as follows, then open `winecfg` and manually add DLL overrides for `d3d11`, `d3d10core`, `dxgi`, and `d3d9`.
|
||||
|
||||
In a default Wine prefix that would be as follows:
|
||||
```
|
||||
WINEPREFIX=/path/to/wineprefix
|
||||
export WINEPREFIX=/path/to/wineprefix
|
||||
cp x64/*.dll $WINEPREFIX/drive_c/windows/system32
|
||||
cp x32/*.dll $WINEPREFIX/drive_c/windows/syswow64
|
||||
winecfg
|
||||
```
|
||||
|
||||
Note that this is **not** an error, 64-bit DLLs are indeed supposed to go to the `system32` directory. Please refrain from opening issues or pull requests to change that, the instructions are correct as they are.
|
||||
For a pure 32-bit Wine prefix (non default) the 32-bit DLLs instead go to the `system32` directory:
|
||||
```
|
||||
export WINEPREFIX=/path/to/wineprefix
|
||||
cp x32/*.dll $WINEPREFIX/drive_c/windows/system32
|
||||
winecfg
|
||||
```
|
||||
|
||||
Verify that your application uses DXVK instead of wined3d by by enabling the HUD (see notes below).
|
||||
Verify that your application uses DXVK instead of wined3d by enabling the HUD (see notes below).
|
||||
|
||||
In order to remove DXVK from a prefix, remove the DLLs and DLL overrides, and run `wineboot -u` to restore the original DLL files.
|
||||
|
||||
Tools such as Steam Play, Lutris, Bottles, Heroic Launcher, etc will automatically handle setup of dxvk on their own when enabled.
|
||||
|
||||
### Notes on Vulkan drivers
|
||||
Before reporting an issue, please check the [Wiki](https://github.com/doitsujin/dxvk/wiki/Driver-support) page on the current driver status and make sure you run a recent enough driver version for your hardware.
|
||||
|
||||
## Build instructions
|
||||
|
||||
In order to pull in all submodules that are needed for building, clone the repository using the following command:
|
||||
|
@ -66,9 +78,6 @@ ninja install
|
|||
|
||||
The D3D9, D3D10, D3D11 and DXGI DLLs will be located in `/your/dxvk/directory/bin`. Setup has to be done manually in this case.
|
||||
|
||||
### Notes on Vulkan drivers
|
||||
Before reporting an issue, please check the [Wiki](https://github.com/doitsujin/dxvk/wiki/Driver-support) page on the current driver status and make sure you run a recent enough driver version for your hardware.
|
||||
|
||||
### Online multi-player games
|
||||
Manipulation of Direct3D libraries in multi-player games may be considered cheating and can get your account **banned**. This may also apply to single-player games with an embedded or dedicated multiplayer portion. **Use at your own risk.**
|
||||
|
||||
|
@ -94,6 +103,7 @@ The `DXVK_HUD` environment variable controls a HUD which can display the framera
|
|||
- `compiler`: Shows shader compiler activity
|
||||
- `samplers`: Shows the current number of sampler pairs used *[D3D9 Only]*
|
||||
- `scale=x`: Scales the HUD by a factor of `x` (e.g. `1.5`)
|
||||
- `opacity=y`: Adjusts the HUD opacity by a factor of `y` (e.g. `0.5`, `1.0` being fully opaque).
|
||||
|
||||
Additionally, `DXVK_HUD=1` has the same effect as `DXVK_HUD=devinfo,fps`, and `DXVK_HUD=full` enables all available HUD elements.
|
||||
|
||||
|
@ -106,6 +116,15 @@ Some applications do not provide a method to select a different GPU. In that cas
|
|||
|
||||
**Note:** If the device filter is configured incorrectly, it may filter out all devices and applications will be unable to create a D3D device.
|
||||
|
||||
### Graphics Pipeline Library
|
||||
On drivers which support `VK_EXT_graphics_pipeline_library` Vulkan shaders will be compiled at the time the game loads its D3D shaders, rather than at draw time. This reduces or eliminates shader compile stutter in many games when compared to the previous system.
|
||||
|
||||
In games that load their shaders during loading screens or in the menu, this can lead to prolonged periods of very high CPU utilization, especially on weaker CPUs. For affected games it is recommended to wait for shader compilation to finish before starting the game to avoid stutter and low performance. Shader compiler activity can be monitored with `DXVK_HUD=compiler`.
|
||||
|
||||
This feature largely replaces the state cache.
|
||||
|
||||
**Note:** Games which only load their D3D shaders at draw time (e.g. most Unreal Engine games) will still exhibit some stutter, although it should still be less severe than without this feature.
|
||||
|
||||
### State cache
|
||||
DXVK caches pipeline state by default, so that shaders can be recompiled ahead of time on subsequent runs of an application, even if the driver's own shader cache got invalidated in the meantime. This cache is enabled by default, and generally reduces stuttering.
|
||||
|
||||
|
@ -115,13 +134,16 @@ The following environment variables can be used to control the cache:
|
|||
- `reset`: Clears the cache file.
|
||||
- `DXVK_STATE_CACHE_PATH=/some/directory` Specifies a directory where to put the cache files. Defaults to the current working directory of the application.
|
||||
|
||||
This feature is mostly only relevant on systems without support for `VK_EXT_graphics_pipeline_library`
|
||||
|
||||
### Debugging
|
||||
The following environment variables can be used for **debugging** purposes.
|
||||
- `VK_INSTANCE_LAYERS=VK_LAYER_KHRONOS_validation` Enables Vulkan debug layers. Highly recommended for troubleshooting rendering issues and driver crashes. Requires the Vulkan SDK to be installed on the host system.
|
||||
- `DXVK_LOG_LEVEL=none|error|warn|info|debug` Controls message logging.
|
||||
- `DXVK_LOG_PATH=/some/directory` Changes path where log files are stored. Set to `none` to disable log file creation entirely, without disabling logging.
|
||||
- `DXVK_CONFIG_FILE=/xxx/dxvk.conf` Sets path to the configuration file.
|
||||
- `DXVK_DEBUG=markers|validation` Enables use of the `VK_EXT_debug_utils` extension for translating performance event markers, or to enable Vulkan validation, respecticely.
|
||||
- `DXVK_CONFIG_FILE=/xxx/dxvk.conf` Sets path to the configuration file.
|
||||
- `DXVK_CONFIG="dxgi.hideAmdGpu = True; dxgi.syncInterval = 0"` Can be used to set config variables through the environment instead of a configuration file using the same syntax. `;` is used as a seperator.
|
||||
|
||||
## Troubleshooting
|
||||
DXVK requires threading support from your mingw-w64 build environment. If you
|
||||
|
@ -141,3 +163,22 @@ For non debian based distros, make sure that your mingw-w64-gcc cross compiler
|
|||
does have `--enable-threads=posix` enabled during configure. If your distro does
|
||||
ship its mingw-w64-gcc binary with `--enable-threads=win32` you might have to
|
||||
recompile locally or open a bug at your distro's bugtracker to ask for it.
|
||||
|
||||
# DXVK Native
|
||||
|
||||
DXVK Native is a version of DXVK which allows it to be used natively without Wine.
|
||||
|
||||
This is primarily useful for game and application ports to either avoid having to write another rendering backend, or to help with port bringup during development.
|
||||
|
||||
[Release builds](https://github.com/doitsujin/dxvk/releases) are built using the Steam Runtime.
|
||||
|
||||
### How does it work?
|
||||
|
||||
DXVK Native replaces certain Windows-isms with a platform and framework-agnostic replacement, for example, `HWND`s can become `SDL_Window*`s, etc.
|
||||
All it takes to do that is to add another WSI backend.
|
||||
|
||||
**Note:** DXVK Native requires a backend to be explicitly set via the `DXVK_WSI_DRIVER` environment variable. The current built-in options are `SDL2` and `GLFW`.
|
||||
|
||||
DXVK Native comes with a slim set of Windows header definitions required for D3D9/11 and the MinGW headers for D3D9/11.
|
||||
In most cases, it will end up being plug and play with your renderer, but there may be certain teething issues such as:
|
||||
- `__uuidof(type)` is supported, but `__uuidof(variable)` is not supported. Use `__uuidof_var(variable)` instead.
|
||||
|
|
131
dxvk.conf
131
dxvk.conf
|
@ -61,18 +61,43 @@
|
|||
# d3d9.customDeviceDesc = ""
|
||||
|
||||
|
||||
# Report Nvidia GPUs as AMD GPUs by default. This is enabled by default
|
||||
# to work around issues with NVAPI, but may cause issues in some games.
|
||||
# Report Nvidia GPUs as AMD GPUs. Unless NVAPI support is explicitly
|
||||
# enabled through Proton, this is done by default in order to work
|
||||
# around crashes or low performance with Nvidia-speciic code paths
|
||||
# in games, especially Unreal Engine.
|
||||
#
|
||||
# Supported values: True, False
|
||||
# Supported values: Auto, True, False
|
||||
|
||||
# dxgi.nvapiHack = True
|
||||
# dxgi.hideNvidiaGpu = Auto
|
||||
|
||||
|
||||
# Report Nvidia GPUs running on NVK as AMD GPUs.
|
||||
#
|
||||
# Supported values: Auto, True, False
|
||||
|
||||
# dxgi.hideNvkGpu = Auto
|
||||
|
||||
|
||||
# Report AMD GPUs as Nvidia GPUs. This is only done for games that are
|
||||
# known to have issues with AMDAGS or other AMD-specific code paths.
|
||||
#
|
||||
# Supported values: Auto, True, False
|
||||
|
||||
# dxgi.hideAmdGpu = Auto
|
||||
|
||||
|
||||
# Report Intel GPUs as AMD GPUs. This is only done for games that are
|
||||
# known to have issues with Intel-specific libraries such as XESS.
|
||||
#
|
||||
# Supported values: Auto, True, False
|
||||
|
||||
# dxgi.hideIntelGpu = Auto
|
||||
|
||||
|
||||
# Override maximum amount of device memory and shared system memory
|
||||
# reported to the application. This may fix texture streaming issues
|
||||
# in games that do not support cards with large amounts of VRAM.
|
||||
# This is not a hard cap and applications can choose to ignore it.
|
||||
#
|
||||
# Supported values: Any number in Megabytes.
|
||||
|
||||
|
@ -122,8 +147,7 @@
|
|||
#
|
||||
# Supported values: Auto, True, False
|
||||
|
||||
# dxgi.tearFree = Auto
|
||||
# d3d9.tearFree = Auto
|
||||
# dxvk.tearFree = Auto
|
||||
|
||||
|
||||
# Assume single-use mode for command lists created on deferred contexts.
|
||||
|
@ -190,6 +214,16 @@
|
|||
# Supported values: Any number between -2.0 and 1.0
|
||||
|
||||
# d3d11.samplerLodBias = 0.0
|
||||
# d3d9.samplerLodBias = 0.0
|
||||
|
||||
|
||||
# Clamps any negative LOD bias to 0. Applies after samplerLodBias has been
|
||||
# applied. May help with games that use a high negative LOD bias by default.
|
||||
#
|
||||
# Supported values: True, False
|
||||
|
||||
# d3d11.clampNegativeLodBias = False
|
||||
# d3d9.clampNegativeLodBias = False
|
||||
|
||||
|
||||
# Declares vertex positions as invariant in order to solve
|
||||
|
@ -266,6 +300,18 @@
|
|||
# d3d11.enableContextLock = False
|
||||
|
||||
|
||||
# Exposes or hides support for driver command lists
|
||||
#
|
||||
# Some games use the feature flag to decide whether to use deferred
|
||||
# contexts or not. We enable this by default, but in some situations
|
||||
# this can lead to issues if games detect an AMD GPU where command
|
||||
# lists are not natively supported on Windows.
|
||||
#
|
||||
# Supported values: True, False
|
||||
|
||||
# d3d11.exposeDriverCommandLists = True
|
||||
|
||||
|
||||
# Sets number of pipeline compiler threads.
|
||||
#
|
||||
# If the graphics pipeline library feature is enabled, the given
|
||||
|
@ -453,6 +499,7 @@
|
|||
# Supported values:
|
||||
# - True/False
|
||||
|
||||
# d3d11.longMad = False
|
||||
# d3d9.longMad = False
|
||||
|
||||
# Device Local Constant Buffers
|
||||
|
@ -466,18 +513,11 @@
|
|||
|
||||
# d3d9.deviceLocalConstantBuffers = False
|
||||
|
||||
# No Explicit Front Buffer
|
||||
#
|
||||
# Disables the front buffer
|
||||
#
|
||||
# Supported values:
|
||||
# - True/False
|
||||
|
||||
# d3d9.noExplicitFrontBuffer = False
|
||||
|
||||
# Support DF formats
|
||||
#
|
||||
# Support the vendor extension DF floating point depth formats
|
||||
# Support the vendor extension DF floating point depth formats on AMD and Intel.
|
||||
# Note that this config is ignored and disabled by default on Nvidia, or when
|
||||
# spoofing a Nvidia GPU, as it does not support these formats natively.
|
||||
#
|
||||
# Supported values:
|
||||
# - True/False
|
||||
|
@ -496,7 +536,7 @@
|
|||
# Support X4R4G4B4
|
||||
#
|
||||
# Support the X4R4G4B4 format.
|
||||
# The Sims 2 is a horrible game made by complete morons.
|
||||
# The Sims 2 is a very broken game.
|
||||
#
|
||||
# Supported values:
|
||||
# - True/False
|
||||
|
@ -515,7 +555,7 @@
|
|||
# Disable A8 as a Render Target
|
||||
#
|
||||
# Disable support for A8 format render targets
|
||||
# Once again, The Sims 2 is a horrible game made by complete morons.
|
||||
# Once again, The Sims 2 is a very broken game.
|
||||
#
|
||||
# Supported values:
|
||||
# - True/False
|
||||
|
@ -555,16 +595,6 @@
|
|||
|
||||
# d3d9.forceAspectRatio = ""
|
||||
|
||||
# Allow Discard
|
||||
#
|
||||
# Allow the discard lock flag to be used
|
||||
# Useful if some apps use this incorrectly.
|
||||
#
|
||||
# Supported values:
|
||||
# - True/False
|
||||
|
||||
# d3d9.allowDiscard = True
|
||||
|
||||
# Enumerate by Displays
|
||||
#
|
||||
# Whether we should enumerate D3D9 adapters by display (windows behaviour)
|
||||
|
@ -576,16 +606,17 @@
|
|||
|
||||
# d3d9.enumerateByDisplays = True
|
||||
|
||||
# APITrace Mode
|
||||
# Cached Dynamic Buffers
|
||||
#
|
||||
# Makes all host visible buffers cached and coherent
|
||||
# Improves performance when apitracing, but also can impact
|
||||
# some dumb games.
|
||||
# Allocates dynamic resources in D3DPOOL_DEFAULT in
|
||||
# cached system memory rather than uncached memory or host-visible
|
||||
# VRAM, in order to allow fast readback from the CPU. This is only
|
||||
# useful for buggy applications, and may reduce GPU-bound performance.
|
||||
#
|
||||
# Supported values:
|
||||
# - True/False
|
||||
|
||||
# d3d9.apitraceMode = False
|
||||
# d3d9.cachedDynamicBuffers = False
|
||||
|
||||
# Seamless Cubes
|
||||
#
|
||||
|
@ -615,3 +646,37 @@
|
|||
# DO NOT CHANGE THIS UNLESS YOU HAVE A VERY GOOD REASON.
|
||||
|
||||
# d3d9.textureMemory = 100
|
||||
|
||||
# Hide integrated graphics from applications
|
||||
#
|
||||
# Only has an effect when dedicated GPUs are present on the system. It is
|
||||
# not recommended to use this option at all unless absolutely necessary for
|
||||
# a game to work; prefer using DXVK_FILTER_DEVICE_NAME whenever possible.
|
||||
#
|
||||
# Supported values:
|
||||
# - True/False
|
||||
|
||||
# dxvk.hideIntegratedGraphics = False
|
||||
|
||||
# Trigger DEVICELOST when losing focus
|
||||
#
|
||||
# D3D9 requires the application to call Device::Reset after
|
||||
# it loses focus in fullscreen.
|
||||
# Some games rely on observing a D3DERR_DEVICELOST or D3DERR_NOTRESET.
|
||||
# Others don't handle it correctly.
|
||||
#
|
||||
# Supported values:
|
||||
# - True/False
|
||||
|
||||
# d3d9.deviceLossOnFocusLoss = False
|
||||
|
||||
# Reject Device::Reset if any losable resource is still alive
|
||||
#
|
||||
# D3D9 rejects Device::Reset if there's still any alive resources of specific types.
|
||||
# (State blocks, additional swapchains, D3DPOOL_DEFAULT resources)
|
||||
# Some games leak resources leading to a hang.
|
||||
#
|
||||
# Supported values:
|
||||
# - True/False
|
||||
|
||||
# d3d9.countLosableResources = True
|
||||
|
|
|
@ -31,6 +31,9 @@ typedef wchar_t WCHAR;
|
|||
typedef WCHAR *NWPSTR, *LPWSTR, *PWSTR;
|
||||
typedef unsigned char UCHAR, *PUCHAR;
|
||||
|
||||
typedef char CHAR;
|
||||
typedef const CHAR *LPCSTR, *PCSTR;
|
||||
|
||||
typedef INT BOOL;
|
||||
typedef BOOL WINBOOL;
|
||||
|
||||
|
@ -45,7 +48,6 @@ typedef const void* LPCVOID;
|
|||
typedef size_t SIZE_T;
|
||||
|
||||
typedef int8_t INT8;
|
||||
|
||||
typedef uint8_t UINT8;
|
||||
typedef uint8_t BYTE;
|
||||
|
||||
|
@ -53,9 +55,13 @@ typedef int16_t SHORT;
|
|||
typedef uint16_t USHORT;
|
||||
|
||||
typedef int64_t LONGLONG;
|
||||
typedef int64_t INT64;
|
||||
|
||||
typedef uint64_t ULONGLONG;
|
||||
typedef uint64_t UINT64;
|
||||
|
||||
typedef intptr_t LONG_PTR;
|
||||
typedef uintptr_t ULONG_PTR;
|
||||
|
||||
typedef float FLOAT;
|
||||
|
||||
|
@ -208,6 +214,11 @@ typedef struct RGNDATA {
|
|||
#define TRUE 1
|
||||
#define FALSE 0
|
||||
|
||||
#define WAIT_TIMEOUT 0x00000102
|
||||
#define WAIT_FAILED 0xffffffff
|
||||
#define WAIT_OBJECT_0 0
|
||||
#define WAIT_ABANDONED 0x00000080
|
||||
|
||||
#define interface struct
|
||||
#define MIDL_INTERFACE(x) struct
|
||||
|
||||
|
@ -322,12 +333,21 @@ typedef struct RGNDATA {
|
|||
#define DECLARE_INTERFACE(x) struct x
|
||||
#define DECLARE_INTERFACE_(x, y) struct x : public y
|
||||
#else
|
||||
#ifdef CONST_VTABLE
|
||||
#define DECLARE_INTERFACE(x) \
|
||||
typedef interface x { \
|
||||
const struct x##Vtbl *lpVtbl; \
|
||||
} x; \
|
||||
typedef const struct x##Vtbl x##Vtbl; \
|
||||
const struct x##Vtbl
|
||||
#else
|
||||
#define DECLARE_INTERFACE(x) \
|
||||
typedef interface x { \
|
||||
struct x##Vtbl *lpVtbl; \
|
||||
} x; \
|
||||
typedef struct x##Vtbl x##Vtbl; \
|
||||
struct x##Vtbl
|
||||
#endif // CONST_VTABLE
|
||||
#define DECLARE_INTERFACE_(x, y) DECLARE_INTERFACE(x)
|
||||
#endif // __cplusplus
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#include <windows.h>
|
||||
|
||||
#include <SDL2/SDL.h>
|
||||
#include <SDL.h>
|
||||
|
||||
namespace dxvk::wsi {
|
||||
|
||||
|
@ -22,4 +22,4 @@ namespace dxvk::wsi {
|
|||
return reinterpret_cast<HMONITOR>(static_cast<intptr_t>(displayId + 1));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit 0bcc624926a25a2a273d07877fd25a6ff5ba1cfb
|
||||
Subproject commit 8b246ff75c6615ba4532fe4fde20f1be090c3764
|
|
@ -1 +1 @@
|
|||
Subproject commit 98f440ce6868c94f5ec6e198cc1adda4760e8849
|
||||
Subproject commit 46dc0f6e514f5730784bb2cac2a7c731636839e8
|
97
meson.build
97
meson.build
|
@ -1,11 +1,12 @@
|
|||
project('dxvk', ['c', 'cpp'], version : 'v2.2', meson_version : '>= 0.49', default_options : [ 'cpp_std=c++17', 'warning_level=2' ])
|
||||
project('dxvk', ['c', 'cpp'], version : 'v2.3.1', meson_version : '>= 0.58', default_options : [ 'cpp_std=c++17', 'warning_level=2' ])
|
||||
|
||||
cpu_family = target_machine.cpu_family()
|
||||
platform = target_machine.system()
|
||||
fs = import('fs')
|
||||
|
||||
cpp = meson.get_compiler('cpp')
|
||||
cc = meson.get_compiler('c')
|
||||
dxvk_is_msvc = cpp.get_id() == 'msvc'
|
||||
dxvk_is_msvc = cpp.get_argument_syntax() == 'msvc'
|
||||
|
||||
compiler_args = [
|
||||
'-msse',
|
||||
|
@ -33,14 +34,24 @@ if get_option('build_id')
|
|||
]
|
||||
endif
|
||||
|
||||
dxvk_include_dirs = [
|
||||
'./include',
|
||||
'./include/vulkan/include',
|
||||
'./include/spirv/include'
|
||||
]
|
||||
dxvk_include_dirs = ['./include']
|
||||
if fs.is_dir('./include/vulkan/include')
|
||||
dxvk_include_dirs += ['./include/vulkan/include']
|
||||
elif not cpp.check_header('vulkan/vulkan.h')
|
||||
error('Missing Vulkan-Headers')
|
||||
endif
|
||||
if fs.is_dir('./include/spirv/include')
|
||||
dxvk_include_dirs += ['./include/spirv/include']
|
||||
elif not cpp.check_header('spirv/unified1/spirv.hpp')
|
||||
error('Missing SPIRV-Headers')
|
||||
endif
|
||||
|
||||
proj_displayinfo = subproject('libdisplay-info')
|
||||
dep_displayinfo = proj_displayinfo.get_variable('di_dep')
|
||||
dep_displayinfo = dependency(
|
||||
'libdisplay-info',
|
||||
version: ['>= 0.0.0', '< 0.2.0'],
|
||||
fallback: ['libdisplay-info', 'di_dep'],
|
||||
default_options: ['default_library=static'],
|
||||
)
|
||||
|
||||
if platform == 'windows'
|
||||
compiler_args += [
|
||||
|
@ -48,29 +59,34 @@ if platform == 'windows'
|
|||
'-D_WIN32_WINNT=0xa00',
|
||||
]
|
||||
|
||||
link_args += [
|
||||
'-static',
|
||||
'-static-libgcc',
|
||||
'-static-libstdc++',
|
||||
# We need to set the section alignment for debug symbols to
|
||||
# work properly as well as avoiding a memcpy from the Wine loader.
|
||||
'-Wl,--file-alignment=4096',
|
||||
]
|
||||
|
||||
# Wine's built-in back traces only work with dwarf2 symbols
|
||||
if get_option('debug')
|
||||
compiler_args += [
|
||||
'-gstrict-dwarf',
|
||||
'-gdwarf-2',
|
||||
]
|
||||
endif
|
||||
|
||||
# Enable stdcall fixup on 32-bit
|
||||
if cpu_family == 'x86'
|
||||
if not dxvk_is_msvc
|
||||
link_args += [
|
||||
'-Wl,--enable-stdcall-fixup',
|
||||
'-Wl,--add-stdcall-alias',
|
||||
]
|
||||
'-static',
|
||||
'-static-libgcc',
|
||||
'-static-libstdc++',
|
||||
# We need to set the section alignment for debug symbols to
|
||||
# work properly as well as avoiding a memcpy from the Wine loader.
|
||||
'-Wl,--file-alignment=4096',
|
||||
]
|
||||
|
||||
# Wine's built-in back traces only work with dwarf4 symbols
|
||||
if get_option('debug')
|
||||
compiler_args += [
|
||||
'-gdwarf-4',
|
||||
]
|
||||
endif
|
||||
|
||||
# Enable stdcall fixup on 32-bit
|
||||
if cpu_family == 'x86'
|
||||
link_args += [
|
||||
'-Wl,--enable-stdcall-fixup',
|
||||
'-Wl,--kill-at',
|
||||
]
|
||||
endif
|
||||
else
|
||||
link_args += [
|
||||
'/FILEALIGN:4096',
|
||||
]
|
||||
endif
|
||||
|
||||
lib_d3d9 = cpp.find_library('d3d9')
|
||||
|
@ -99,7 +115,6 @@ if platform == 'windows'
|
|||
)
|
||||
endif
|
||||
|
||||
dxvk_wsi = 'win32'
|
||||
dxvk_name_prefix = ''
|
||||
compiler_args += ['-DDXVK_WSI_WIN32']
|
||||
else
|
||||
|
@ -112,15 +127,17 @@ else
|
|||
'./include/native/directx'
|
||||
]
|
||||
|
||||
dxvk_wsi = get_option('dxvk_native_wsi')
|
||||
|
||||
if dxvk_wsi == 'sdl2'
|
||||
lib_sdl2 = cpp.find_library('SDL2')
|
||||
lib_sdl2 = dependency('SDL2', required: false)
|
||||
lib_glfw = dependency('glfw', required: false)
|
||||
if lib_sdl2.found()
|
||||
compiler_args += ['-DDXVK_WSI_SDL2']
|
||||
elif dxvk_wsi == 'glfw'
|
||||
lib_glfw = cpp.find_library('glfw')
|
||||
endif
|
||||
if lib_glfw.found()
|
||||
compiler_args += ['-DDXVK_WSI_GLFW']
|
||||
endif
|
||||
if (not lib_sdl2.found() and not lib_glfw.found())
|
||||
error('SDL2 or GLFW are required to build dxvk-native')
|
||||
endif
|
||||
|
||||
dxvk_name_prefix = 'libdxvk_'
|
||||
|
||||
|
@ -141,10 +158,10 @@ exe_ext = ''
|
|||
dll_ext = ''
|
||||
def_spec_ext = '.def'
|
||||
|
||||
glsl_compiler = find_program('glslangValidator')
|
||||
glsl_compiler = find_program('glslang', 'glslangValidator')
|
||||
glsl_args = [
|
||||
'--quiet',
|
||||
'--target-env', 'vulkan1.2',
|
||||
'--target-env', 'vulkan1.3',
|
||||
'--vn', '@BASENAME@',
|
||||
'--depfile', '@DEPFILE@',
|
||||
'@INPUT@',
|
||||
|
|
|
@ -56,13 +56,14 @@ function build_arch {
|
|||
opt_strip=--strip
|
||||
fi
|
||||
|
||||
CC="$CC -m$1" CXX="$CXX -m$1" meson setup \
|
||||
--buildtype "release" \
|
||||
--prefix "$DXVK_BUILD_DIR/usr" \
|
||||
$opt_strip \
|
||||
--bindir "$2" \
|
||||
--libdir "$2" \
|
||||
-Dbuild_id=$opt_buildid \
|
||||
CC="$CC -m$1" CXX="$CXX -m$1" meson setup \
|
||||
--buildtype "release" \
|
||||
--prefix "$DXVK_BUILD_DIR/usr" \
|
||||
$opt_strip \
|
||||
--bindir "$2" \
|
||||
--libdir "$2" \
|
||||
-Dbuild_id=$opt_buildid \
|
||||
--force-fallback-for=libdisplay-info \
|
||||
"$DXVK_BUILD_DIR/build.$1"
|
||||
|
||||
cd "$DXVK_BUILD_DIR/build.$1"
|
||||
|
|
|
@ -9,10 +9,14 @@ extern "C" {
|
|||
HRESULT __stdcall D3D11CoreCreateDevice(
|
||||
IDXGIFactory* pFactory,
|
||||
IDXGIAdapter* pAdapter,
|
||||
D3D_DRIVER_TYPE DriverType,
|
||||
HMODULE Software,
|
||||
UINT Flags,
|
||||
const D3D_FEATURE_LEVEL* pFeatureLevels,
|
||||
UINT FeatureLevels,
|
||||
ID3D11Device** ppDevice);
|
||||
UINT SDKVersion,
|
||||
ID3D11Device** ppDevice,
|
||||
D3D_FEATURE_LEVEL* pFeatureLevel);
|
||||
|
||||
|
||||
DLLEXPORT HRESULT __stdcall D3D10CoreCreateDevice(
|
||||
|
@ -31,8 +35,8 @@ extern "C" {
|
|||
if (FAILED(hr))
|
||||
return hr;
|
||||
|
||||
hr = D3D11CoreCreateDevice(pFactory, pAdapter,
|
||||
Flags, &FeatureLevel, 1, &d3d11Device);
|
||||
hr = D3D11CoreCreateDevice(pFactory, pAdapter, D3D_DRIVER_TYPE_UNKNOWN,
|
||||
nullptr, Flags, &FeatureLevel, 1, D3D11_SDK_VERSION, &d3d11Device, nullptr);
|
||||
|
||||
if (FAILED(hr))
|
||||
return hr;
|
||||
|
|
|
@ -7,14 +7,17 @@ d3d10_core_src = [
|
|||
d3d10_core_ld_args = []
|
||||
d3d10_core_link_depends = []
|
||||
|
||||
if platform != 'windows'
|
||||
if platform == 'windows'
|
||||
d3d10_d3d11_dep = lib_d3d11
|
||||
else
|
||||
d3d10_core_ld_args += [ '-Wl,--version-script', join_paths(meson.current_source_dir(), 'd3d10core.sym') ]
|
||||
d3d10_core_link_depends += files('d3d10core.sym')
|
||||
d3d10_d3d11_dep = d3d11_dep
|
||||
endif
|
||||
|
||||
d3d10_core_dll = shared_library('d3d10core'+dll_ext, d3d10_core_src, d3d10_core_res,
|
||||
name_prefix : dxvk_name_prefix,
|
||||
dependencies : [ d3d11_dep ],
|
||||
dependencies : [ d3d10_d3d11_dep ],
|
||||
include_directories : dxvk_include_path,
|
||||
install : true,
|
||||
vs_module_defs : 'd3d10core'+def_spec_ext,
|
||||
|
|
|
@ -12,7 +12,7 @@ namespace dxvk {
|
|||
const D3D11_ON_12_RESOURCE_INFO* p11on12Info)
|
||||
: D3D11DeviceChild<ID3D11Buffer>(pDevice),
|
||||
m_desc (*pDesc),
|
||||
m_resource (this),
|
||||
m_resource (this, pDevice),
|
||||
m_d3d10 (this) {
|
||||
DxvkBufferCreateInfo info;
|
||||
info.flags = 0;
|
||||
|
@ -339,6 +339,7 @@ namespace dxvk {
|
|||
|| (m_parent->GetOptions()->cachedDynamicResources & m_desc.BindFlags);
|
||||
|
||||
if ((memoryFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) && useCached) {
|
||||
memoryFlags &= ~VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
|
||||
memoryFlags |= VK_MEMORY_PROPERTY_HOST_COHERENT_BIT
|
||||
| VK_MEMORY_PROPERTY_HOST_CACHED_BIT;
|
||||
}
|
||||
|
|
|
@ -386,11 +386,16 @@ namespace dxvk {
|
|||
const UINT Values[4]) {
|
||||
D3D10DeviceLock lock = LockContext();
|
||||
|
||||
auto uav = static_cast<D3D11UnorderedAccessView*>(pUnorderedAccessView);
|
||||
|
||||
if (!uav)
|
||||
if (!pUnorderedAccessView)
|
||||
return;
|
||||
|
||||
Com<ID3D11UnorderedAccessView> qiUav;
|
||||
|
||||
if (FAILED(pUnorderedAccessView->QueryInterface(IID_PPV_ARGS(&qiUav))))
|
||||
return;
|
||||
|
||||
auto uav = static_cast<D3D11UnorderedAccessView*>(qiUav.ptr());
|
||||
|
||||
// Gather UAV format info. We'll use this to determine
|
||||
// whether we need to create a temporary view or not.
|
||||
D3D11_UNORDERED_ACCESS_VIEW_DESC uavDesc;
|
||||
|
@ -406,15 +411,22 @@ namespace dxvk {
|
|||
|
||||
VkClearValue clearValue;
|
||||
|
||||
// R11G11B10 is a special case since there's no corresponding
|
||||
// integer format with the same bit layout. Use R32 instead.
|
||||
if (uavFormat == VK_FORMAT_B10G11R11_UFLOAT_PACK32) {
|
||||
if (uavDesc.Format == DXGI_FORMAT_R11G11B10_FLOAT) {
|
||||
// R11G11B10 is a special case since there's no corresponding
|
||||
// integer format with the same bit layout. Use R32 instead.
|
||||
clearValue.color.uint32[0] = ((Values[0] & 0x7FF) << 0)
|
||||
| ((Values[1] & 0x7FF) << 11)
|
||||
| ((Values[2] & 0x3FF) << 22);
|
||||
clearValue.color.uint32[1] = 0;
|
||||
clearValue.color.uint32[2] = 0;
|
||||
clearValue.color.uint32[3] = 0;
|
||||
} else if (uavDesc.Format == DXGI_FORMAT_A8_UNORM) {
|
||||
// We need to use R8_UINT to clear A8_UNORM images,
|
||||
// so remap the alpha component to the red channel.
|
||||
clearValue.color.uint32[0] = Values[3];
|
||||
clearValue.color.uint32[1] = 0;
|
||||
clearValue.color.uint32[2] = 0;
|
||||
clearValue.color.uint32[3] = 0;
|
||||
} else {
|
||||
clearValue.color.uint32[0] = Values[0];
|
||||
clearValue.color.uint32[1] = Values[1];
|
||||
|
@ -916,6 +928,34 @@ namespace dxvk {
|
|||
const void* pSrcData,
|
||||
UINT SrcRowPitch,
|
||||
UINT SrcDepthPitch) {
|
||||
if (IsDeferred && unlikely(pDstBox != nullptr) && unlikely(!m_parent->GetOptions()->exposeDriverCommandLists)) {
|
||||
// If called from a deferred context and native command list support is not
|
||||
// exposed, we need to apply the destination box to the source pointer. This
|
||||
// only applies to UpdateSubresource, not to UpdateSubresource1. See MSDN:
|
||||
// https://msdn.microsoft.com/en-us/library/windows/desktop/ff476486(v=vs.85).aspx)
|
||||
size_t srcOffset = pDstBox->left;
|
||||
|
||||
// For textures, the offset logic needs to take the format into account.
|
||||
// Ignore that multi-planar images exist, this is hairy enough already.
|
||||
D3D11CommonTexture* dstTexture = GetCommonTexture(pDstResource);
|
||||
|
||||
if (dstTexture) {
|
||||
auto dstFormat = dstTexture->GetPackedFormat();
|
||||
auto dstFormatInfo = lookupFormatInfo(dstFormat);
|
||||
|
||||
size_t blockSize = dstFormatInfo->elementSize;
|
||||
|
||||
VkOffset3D offset;
|
||||
offset.x = pDstBox->left / dstFormatInfo->blockSize.width;
|
||||
offset.y = pDstBox->top / dstFormatInfo->blockSize.height;
|
||||
offset.z = pDstBox->front / dstFormatInfo->blockSize.depth;
|
||||
|
||||
srcOffset = offset.x * blockSize + offset.y * SrcRowPitch + offset.z * SrcDepthPitch;
|
||||
}
|
||||
|
||||
pSrcData = reinterpret_cast<const char*>(pSrcData) + srcOffset;
|
||||
}
|
||||
|
||||
UpdateResource(pDstResource, DstSubresource, pDstBox,
|
||||
pSrcData, SrcRowPitch, SrcDepthPitch, 0);
|
||||
}
|
||||
|
@ -3389,8 +3429,24 @@ namespace dxvk {
|
|||
}
|
||||
|
||||
|
||||
static VkDepthBiasRepresentationEXT FormatToDepthBiasRepresentation(DXGI_FORMAT format) {
|
||||
switch (format) {
|
||||
default:
|
||||
case DXGI_FORMAT_D32_FLOAT_S8X24_UINT:
|
||||
case DXGI_FORMAT_D32_FLOAT:
|
||||
return VK_DEPTH_BIAS_REPRESENTATION_LEAST_REPRESENTABLE_VALUE_FORMAT_EXT;
|
||||
|
||||
case DXGI_FORMAT_D24_UNORM_S8_UINT:
|
||||
case DXGI_FORMAT_D16_UNORM:
|
||||
return VK_DEPTH_BIAS_REPRESENTATION_LEAST_REPRESENTABLE_VALUE_FORCE_UNORM_EXT;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename ContextType>
|
||||
void D3D11CommonContext<ContextType>::BindFramebuffer() {
|
||||
DxvkDepthBiasRepresentation depthBiasRepresentation =
|
||||
{ VK_DEPTH_BIAS_REPRESENTATION_LEAST_REPRESENTABLE_VALUE_FORMAT_EXT,
|
||||
m_device->features().extDepthBiasControl.depthBiasExact };
|
||||
DxvkRenderTargets attachments;
|
||||
uint32_t sampleCount = 0;
|
||||
|
||||
|
@ -3411,12 +3467,17 @@ namespace dxvk {
|
|||
m_state.om.dsv->GetImageView(),
|
||||
m_state.om.dsv->GetRenderLayout() };
|
||||
sampleCount = m_state.om.dsv->GetSampleCount();
|
||||
|
||||
if (m_device->features().extDepthBiasControl.leastRepresentableValueForceUnormRepresentation)
|
||||
depthBiasRepresentation.depthBiasRepresentation = FormatToDepthBiasRepresentation(m_state.om.dsv->GetViewFormat());
|
||||
}
|
||||
|
||||
// Create and bind the framebuffer object to the context
|
||||
EmitCs([
|
||||
cAttachments = std::move(attachments)
|
||||
cAttachments = std::move(attachments),
|
||||
cRepresentation = depthBiasRepresentation
|
||||
] (DxvkContext* ctx) mutable {
|
||||
ctx->setDepthBiasRepresentation(cRepresentation);
|
||||
ctx->bindRenderTargets(Forwarder::move(cAttachments), 0u);
|
||||
});
|
||||
|
||||
|
@ -5380,6 +5441,7 @@ namespace dxvk {
|
|||
pRsState->conservativeMode = VK_CONSERVATIVE_RASTERIZATION_MODE_DISABLED_EXT;
|
||||
pRsState->sampleCount = 0;
|
||||
pRsState->flatShading = VK_FALSE;
|
||||
pRsState->lineMode = VK_LINE_RASTERIZATION_MODE_DEFAULT_EXT;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -1130,7 +1130,7 @@ namespace dxvk {
|
|||
if (likely(pBuffer != nullptr))
|
||||
bufferSize = static_cast<D3D11Buffer*>(pBuffer)->Desc()->ByteWidth;
|
||||
|
||||
return bufferSize >= Offset + Size;
|
||||
return uint64_t(bufferSize) >= uint64_t(Offset) + uint64_t(Size);
|
||||
}
|
||||
|
||||
private:
|
||||
|
|
|
@ -17,6 +17,7 @@ namespace dxvk {
|
|||
friend class D3D11CommonContext<D3D11ImmediateContext>;
|
||||
friend class D3D11SwapChain;
|
||||
friend class D3D11VideoContext;
|
||||
friend class D3D11DXGIKeyedMutex;
|
||||
public:
|
||||
|
||||
D3D11ImmediateContext(
|
||||
|
@ -88,6 +89,10 @@ namespace dxvk {
|
|||
void SynchronizeCsThread(
|
||||
uint64_t SequenceNumber);
|
||||
|
||||
D3D10Multithread& GetMultithread() {
|
||||
return m_multithread;
|
||||
}
|
||||
|
||||
D3D10DeviceLock LockContext() {
|
||||
return m_multithread.AcquireLock();
|
||||
}
|
||||
|
|
|
@ -37,7 +37,7 @@ namespace dxvk {
|
|||
|
||||
if (riid == __uuidof(ID3D10DeviceChild)
|
||||
|| riid == __uuidof(ID3D10DepthStencilState)) {
|
||||
*ppvObject = ref(this);
|
||||
*ppvObject = ref(&m_d3d10);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -45,10 +45,10 @@ namespace dxvk {
|
|||
m_dxvkDevice (pContainer->GetDXVKDevice()),
|
||||
m_dxvkAdapter (m_dxvkDevice->adapter()),
|
||||
m_d3d11Formats (m_dxvkDevice),
|
||||
m_d3d11Options (m_dxvkDevice->instance()->config(), m_dxvkDevice),
|
||||
m_d3d11Options (m_dxvkDevice->instance()->config()),
|
||||
m_dxbcOptions (m_dxvkDevice, m_d3d11Options),
|
||||
m_maxFeatureLevel (GetMaxFeatureLevel(m_dxvkDevice->instance(), m_dxvkDevice->adapter())),
|
||||
m_deviceFeatures (m_dxvkDevice->instance(), m_dxvkDevice->adapter(), m_featureLevel) {
|
||||
m_deviceFeatures (m_dxvkDevice->instance(), m_dxvkDevice->adapter(), m_d3d11Options, m_featureLevel) {
|
||||
m_initializer = new D3D11Initializer(this);
|
||||
m_context = new D3D11ImmediateContext(this, m_dxvkDevice);
|
||||
m_d3d10Device = new D3D10Device(this, m_context.ptr());
|
||||
|
@ -1348,7 +1348,7 @@ namespace dxvk {
|
|||
m_deviceFeatures = D3D11DeviceFeatures(
|
||||
m_dxvkDevice->instance(),
|
||||
m_dxvkDevice->adapter(),
|
||||
m_featureLevel);
|
||||
m_d3d11Options, m_featureLevel);
|
||||
}
|
||||
|
||||
if (pChosenFeatureLevel)
|
||||
|
@ -1953,6 +1953,11 @@ namespace dxvk {
|
|||
enabled.core.features.shaderFloat64 = supported.core.features.shaderFloat64;
|
||||
enabled.core.features.shaderInt64 = supported.core.features.shaderInt64;
|
||||
|
||||
// Depth bias control
|
||||
enabled.extDepthBiasControl.depthBiasControl = supported.extDepthBiasControl.depthBiasControl;
|
||||
enabled.extDepthBiasControl.depthBiasExact = supported.extDepthBiasControl.depthBiasExact;
|
||||
enabled.extDepthBiasControl.leastRepresentableValueForceUnormRepresentation = supported.extDepthBiasControl.leastRepresentableValueForceUnormRepresentation;
|
||||
|
||||
return enabled;
|
||||
}
|
||||
|
||||
|
@ -2304,6 +2309,10 @@ namespace dxvk {
|
|||
d3d11Desc.CPUAccessFlags = metadata.CPUAccessFlags;
|
||||
d3d11Desc.MiscFlags = metadata.MiscFlags;
|
||||
d3d11Desc.TextureLayout = metadata.TextureLayout;
|
||||
if ((d3d11Desc.MiscFlags & D3D11_RESOURCE_MISC_SHARED_NTHANDLE) && !(d3d11Desc.MiscFlags & (D3D11_RESOURCE_MISC_SHARED | D3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX))) {
|
||||
Logger::warn("Fixing up wrong MiscFlags");
|
||||
d3d11Desc.MiscFlags |= D3D11_RESOURCE_MISC_SHARED;
|
||||
}
|
||||
|
||||
// Only 2D textures may be shared
|
||||
try {
|
||||
|
@ -3402,8 +3411,9 @@ namespace dxvk {
|
|||
|
||||
|
||||
HRESULT STDMETHODCALLTYPE D3D11DXGIDevice::EnqueueSetEvent(HANDLE hEvent) {
|
||||
Logger::err("D3D11DXGIDevice::EnqueueSetEvent: Not implemented");
|
||||
return DXGI_ERROR_UNSUPPORTED;
|
||||
auto immediateContext = m_d3d11Device.GetContext();
|
||||
immediateContext->Flush1(D3D11_CONTEXT_TYPE_ALL, hEvent);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -12,6 +12,7 @@ namespace dxvk {
|
|||
D3D11DeviceFeatures::D3D11DeviceFeatures(
|
||||
const Rc<DxvkInstance>& Instance,
|
||||
const Rc<DxvkAdapter>& Adapter,
|
||||
const D3D11Options& Options,
|
||||
D3D_FEATURE_LEVEL FeatureLevel)
|
||||
: m_features (Adapter->features()),
|
||||
m_properties (Adapter->devicePropertiesExt()) {
|
||||
|
@ -107,7 +108,7 @@ namespace dxvk {
|
|||
m_gpuVirtualAddress.MaxGPUVirtualAddressBitsPerProcess = 40;
|
||||
|
||||
// Marker support only depends on the debug utils extension
|
||||
m_marker.Profile = Instance->extensions().extDebugUtils;
|
||||
m_marker.Profile = static_cast<bool>(Instance->extensions().extDebugUtils);
|
||||
|
||||
// DXVK will keep all shaders in memory once created, and all Vulkan
|
||||
// drivers that we know of that can run DXVK have an on-disk cache.
|
||||
|
@ -118,11 +119,11 @@ namespace dxvk {
|
|||
m_shaderMinPrecision.PixelShaderMinPrecision = 0;
|
||||
m_shaderMinPrecision.AllOtherShaderStagesMinPrecision = 0;
|
||||
|
||||
// Report native support for command lists here so that we do not actually have
|
||||
// to re-implement the UpdateSubresource bug from the D3D11 runtime, see MSDN:
|
||||
// https://msdn.microsoft.com/en-us/library/windows/desktop/ff476486(v=vs.85).aspx)
|
||||
// Report native support for command lists by default. Deferred context
|
||||
// usage can be beneficial for us as ExecuteCommandList has low overhead,
|
||||
// and we avoid having to deal with known UpdateSubresource bugs this way.
|
||||
m_threading.DriverConcurrentCreates = TRUE;
|
||||
m_threading.DriverCommandLists = TRUE;
|
||||
m_threading.DriverCommandLists = Options.exposeDriverCommandLists;
|
||||
}
|
||||
|
||||
|
||||
|
@ -182,7 +183,8 @@ namespace dxvk {
|
|||
D3D_FEATURE_LEVEL D3D11DeviceFeatures::GetMaxFeatureLevel(
|
||||
const Rc<DxvkInstance>& Instance,
|
||||
const Rc<DxvkAdapter>& Adapter) {
|
||||
D3D11DeviceFeatures features(Instance, Adapter, D3D_FEATURE_LEVEL_12_1);
|
||||
D3D11Options options(Instance->config());
|
||||
D3D11DeviceFeatures features(Instance, Adapter, options, D3D_FEATURE_LEVEL_12_1);
|
||||
return features.GetMaxFeatureLevel();
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
#include "d3d11_include.h"
|
||||
#include "d3d11_options.h"
|
||||
|
||||
#include "../dxvk/dxvk_adapter.h"
|
||||
#include "../dxvk/dxvk_instance.h"
|
||||
|
@ -21,6 +22,7 @@ namespace dxvk {
|
|||
D3D11DeviceFeatures(
|
||||
const Rc<DxvkInstance>& Instance,
|
||||
const Rc<DxvkAdapter>& Adapter,
|
||||
const D3D11Options& Options,
|
||||
D3D_FEATURE_LEVEL FeatureLevel);
|
||||
|
||||
~D3D11DeviceFeatures();
|
||||
|
|
|
@ -49,6 +49,8 @@ namespace dxvk {
|
|||
InitHostVisibleTexture(pTexture, pInitialData);
|
||||
else
|
||||
InitDeviceLocalTexture(pTexture, pInitialData);
|
||||
|
||||
SyncKeyedMutex(pTexture->GetInterface());
|
||||
}
|
||||
|
||||
|
||||
|
@ -284,4 +286,14 @@ namespace dxvk {
|
|||
m_transferMemory = 0;
|
||||
}
|
||||
|
||||
|
||||
void D3D11Initializer::SyncKeyedMutex(ID3D11Resource *pResource) {
|
||||
Com<IDXGIKeyedMutex> keyedMutex;
|
||||
if (pResource->QueryInterface(__uuidof(IDXGIKeyedMutex), reinterpret_cast<void**>(&keyedMutex)) != S_OK)
|
||||
return;
|
||||
|
||||
keyedMutex->AcquireSync(0, 0);
|
||||
keyedMutex->ReleaseSync(0);
|
||||
}
|
||||
|
||||
}
|
|
@ -71,6 +71,8 @@ namespace dxvk {
|
|||
void FlushImplicit();
|
||||
void FlushInternal();
|
||||
|
||||
void SyncKeyedMutex(ID3D11Resource *pResource);
|
||||
|
||||
};
|
||||
|
||||
}
|
|
@ -183,13 +183,7 @@ ID3D11VkExtContext1 : public ID3D11VkExtContext {
|
|||
};
|
||||
|
||||
|
||||
#ifdef _MSC_VER
|
||||
struct __declspec(uuid("bb8a4fb9-3935-4762-b44b-35189a26414a")) ID3D11VkExtShader;
|
||||
struct __declspec(uuid("8a6e3c42-f74c-45b7-8265-a231b677ca17")) ID3D11VkExtDevice;
|
||||
struct __declspec(uuid("cfcf64ef-9586-46d0-bca4-97cf2ca61b06")) ID3D11VkExtDevice1;
|
||||
struct __declspec(uuid("fd0bca13-5cb6-4c3a-987e-4750de2ca791")) ID3D11VkExtContext;
|
||||
struct __declspec(uuid("874b09b2-ae0b-41d8-8476-5f3b7a0e879d")) ID3D11VkExtContext1;
|
||||
#else
|
||||
#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);
|
||||
|
|
|
@ -15,7 +15,7 @@ namespace dxvk {
|
|||
extern "C" {
|
||||
using namespace dxvk;
|
||||
|
||||
DLLEXPORT HRESULT __stdcall D3D11CoreCreateDevice(
|
||||
HRESULT D3D11InternalCreateDevice(
|
||||
IDXGIFactory* pFactory,
|
||||
IDXGIAdapter* pAdapter,
|
||||
UINT Flags,
|
||||
|
@ -34,11 +34,11 @@ extern "C" {
|
|||
dxvkAdapter = dxgiVkAdapter->GetDXVKAdapter();
|
||||
dxvkInstance = dxgiVkAdapter->GetDXVKInstance();
|
||||
} else {
|
||||
Logger::warn("D3D11CoreCreateDevice: Adapter is not a DXVK adapter");
|
||||
Logger::warn("D3D11InternalCreateDevice: Adapter is not a DXVK adapter");
|
||||
DXGI_ADAPTER_DESC desc;
|
||||
pAdapter->GetDesc(&desc);
|
||||
|
||||
dxvkInstance = new DxvkInstance();
|
||||
dxvkInstance = new DxvkInstance(0);
|
||||
dxvkAdapter = dxvkInstance->findAdapterByLuid(&desc.AdapterLuid);
|
||||
|
||||
if (dxvkAdapter == nullptr)
|
||||
|
@ -70,7 +70,7 @@ extern "C" {
|
|||
D3D_FEATURE_LEVEL minFeatureLevel = D3D_FEATURE_LEVEL();
|
||||
D3D_FEATURE_LEVEL devFeatureLevel = D3D_FEATURE_LEVEL();
|
||||
|
||||
Logger::info(str::format("D3D11CoreCreateDevice: Maximum supported feature level: ", maxFeatureLevel));
|
||||
Logger::info(str::format("D3D11InternalCreateDevice: Maximum supported feature level: ", maxFeatureLevel));
|
||||
|
||||
for (uint32_t flId = 0 ; flId < FeatureLevels; flId++) {
|
||||
minFeatureLevel = pFeatureLevels[flId];
|
||||
|
@ -82,12 +82,12 @@ extern "C" {
|
|||
}
|
||||
|
||||
if (!devFeatureLevel) {
|
||||
Logger::err(str::format("D3D11CoreCreateDevice: Minimum required feature level ", minFeatureLevel, " not supported"));
|
||||
Logger::err(str::format("D3D11InternalCreateDevice: Minimum required feature level ", minFeatureLevel, " not supported"));
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
|
||||
try {
|
||||
Logger::info(str::format("D3D11CoreCreateDevice: Using feature level ", devFeatureLevel));
|
||||
Logger::info(str::format("D3D11InternalCreateDevice: Using feature level ", devFeatureLevel));
|
||||
|
||||
DxvkDeviceFeatures deviceFeatures = D3D11Device::GetDeviceFeatures(dxvkAdapter);
|
||||
Rc<DxvkDevice> dxvkDevice = dxvkAdapter->createDevice(dxvkInstance, deviceFeatures);
|
||||
|
@ -101,7 +101,7 @@ extern "C" {
|
|||
__uuidof(ID3D11Device),
|
||||
reinterpret_cast<void**>(ppDevice));
|
||||
} catch (const DxvkError& e) {
|
||||
Logger::err("D3D11CoreCreateDevice: Failed to create D3D11 device");
|
||||
Logger::err("D3D11InternalCreateDevice: Failed to create D3D11 device");
|
||||
return E_FAIL;
|
||||
}
|
||||
}
|
||||
|
@ -173,7 +173,7 @@ extern "C" {
|
|||
}
|
||||
|
||||
// Create the actual device
|
||||
hr = D3D11CoreCreateDevice(
|
||||
hr = D3D11InternalCreateDevice(
|
||||
dxgiFactory.ptr(), dxgiAdapter.ptr(),
|
||||
Flags, pFeatureLevels, FeatureLevels,
|
||||
&device);
|
||||
|
@ -212,6 +212,25 @@ extern "C" {
|
|||
}
|
||||
|
||||
|
||||
DLLEXPORT HRESULT __stdcall D3D11CoreCreateDevice(
|
||||
IDXGIFactory* pFactory,
|
||||
IDXGIAdapter* pAdapter,
|
||||
D3D_DRIVER_TYPE DriverType,
|
||||
HMODULE Software,
|
||||
UINT Flags,
|
||||
const D3D_FEATURE_LEVEL* pFeatureLevels,
|
||||
UINT FeatureLevels,
|
||||
UINT SDKVersion,
|
||||
ID3D11Device** ppDevice,
|
||||
D3D_FEATURE_LEVEL* pFeatureLevel) {
|
||||
return D3D11InternalCreateDeviceAndSwapChain(
|
||||
pAdapter, DriverType, Software, Flags,
|
||||
pFeatureLevels, FeatureLevels, SDKVersion,
|
||||
nullptr, nullptr,
|
||||
ppDevice, pFeatureLevel, nullptr);
|
||||
}
|
||||
|
||||
|
||||
DLLEXPORT HRESULT __stdcall D3D11CreateDevice(
|
||||
IDXGIAdapter* pAdapter,
|
||||
D3D_DRIVER_TYPE DriverType,
|
||||
|
@ -357,7 +376,7 @@ extern "C" {
|
|||
instanceInfo.extensionCount = instanceExtensions.size();
|
||||
instanceInfo.extensionNames = instanceExtensions.data();
|
||||
|
||||
Rc<DxvkInstance> dxvkInstance = new DxvkInstance(instanceInfo);
|
||||
Rc<DxvkInstance> dxvkInstance = new DxvkInstance(instanceInfo, 0);
|
||||
|
||||
// Find adapter by physical device handle
|
||||
Rc<DxvkAdapter> dxvkAdapter;
|
||||
|
|
|
@ -49,8 +49,6 @@ ID3D12DXVKInteropDevice : public IUnknown {
|
|||
|
||||
};
|
||||
|
||||
#ifdef _MSC_VER
|
||||
struct __declspec(uuid("39da4e09-bd1c-4198-9fae-86bbe3be41fd")) ID3D12DXVKInteropDevice;
|
||||
#else
|
||||
#ifndef _MSC_VER
|
||||
__CRT_UUID_DECL(ID3D12DXVKInteropDevice, 0x39da4e09, 0xbd1c, 0x4198, 0x9f,0xae, 0x86,0xbb,0xe3,0xbe,0x41,0xfd)
|
||||
#endif
|
||||
|
|
|
@ -12,7 +12,7 @@ namespace dxvk {
|
|||
#endif
|
||||
}
|
||||
|
||||
D3D11Options::D3D11Options(const Config& config, const Rc<DxvkDevice>& device) {
|
||||
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);
|
||||
|
@ -21,6 +21,7 @@ namespace dxvk {
|
|||
this->maxTessFactor = config.getOption<int32_t>("d3d11.maxTessFactor", 0);
|
||||
this->samplerAnisotropy = config.getOption<int32_t>("d3d11.samplerAnisotropy", -1);
|
||||
this->samplerLodBias = config.getOption<float>("d3d11.samplerLodBias", 0.0f);
|
||||
this->clampNegativeLodBias = config.getOption<bool>("d3d11.clampNegativeLodBias", false);
|
||||
this->invariantPosition = config.getOption<bool>("d3d11.invariantPosition", true);
|
||||
this->floatControls = config.getOption<bool>("d3d11.floatControls", true);
|
||||
this->forceSampleRateShading = config.getOption<bool>("d3d11.forceSampleRateShading", false);
|
||||
|
@ -30,8 +31,8 @@ namespace dxvk {
|
|||
this->numBackBuffers = config.getOption<int32_t>("dxgi.numBackBuffers", 0);
|
||||
this->maxFrameLatency = config.getOption<int32_t>("dxgi.maxFrameLatency", 0);
|
||||
this->maxFrameRate = config.getOption<int32_t>("dxgi.maxFrameRate", 0);
|
||||
this->syncInterval = config.getOption<int32_t>("dxgi.syncInterval", -1);
|
||||
this->tearFree = config.getOption<Tristate>("dxgi.tearFree", Tristate::Auto);
|
||||
this->exposeDriverCommandLists = config.getOption<bool>("d3d11.exposeDriverCommandLists", true);
|
||||
this->longMad = config.getOption<bool>("d3d11.longMad", false);
|
||||
|
||||
// Clamp LOD bias so that people don't abuse this in unintended ways
|
||||
this->samplerLodBias = dxvk::fclamp(this->samplerLodBias, -2.0f, 1.0f);
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
namespace dxvk {
|
||||
|
||||
struct D3D11Options {
|
||||
D3D11Options(const Config& config, const Rc<DxvkDevice>& device);
|
||||
D3D11Options(const Config& config);
|
||||
|
||||
/// Enables speed hack for mapping on deferred contexts
|
||||
///
|
||||
|
@ -63,6 +63,9 @@ namespace dxvk {
|
|||
/// Enforces the given LOD bias for all samplers.
|
||||
float samplerLodBias;
|
||||
|
||||
/// Clamps negative LOD bias
|
||||
bool clampNegativeLodBias;
|
||||
|
||||
/// Declare vertex positions in shaders as invariant
|
||||
bool invariantPosition;
|
||||
|
||||
|
@ -73,14 +76,6 @@ namespace dxvk {
|
|||
/// Overrides DXGI_SWAP_CHAIN_DESC::BufferCount.
|
||||
int32_t numBackBuffers;
|
||||
|
||||
/// Sync interval. Overrides the value
|
||||
/// passed to IDXGISwapChain::Present.
|
||||
int32_t syncInterval;
|
||||
|
||||
/// Tear-free mode if vsync is disabled
|
||||
/// Tearing mode if vsync is enabled
|
||||
Tristate tearFree;
|
||||
|
||||
/// Override maximum frame latency if the app specifies
|
||||
/// a higher value. May help with frame timing issues.
|
||||
int32_t maxFrameLatency;
|
||||
|
@ -118,8 +113,16 @@ namespace dxvk {
|
|||
/// race conditions.
|
||||
bool enableContextLock;
|
||||
|
||||
/// Whether to expose the driver command list feature. Enabled by
|
||||
/// default and generally beneficial, but some games may assume that
|
||||
/// this is not supported when running on an AMD GPU.
|
||||
bool exposeDriverCommandLists;
|
||||
|
||||
/// Shader dump path
|
||||
std::string shaderDumpPath;
|
||||
|
||||
/// Should we make our Mads a FFma or do it the long way with an FMul and an FAdd?
|
||||
bool longMad;
|
||||
};
|
||||
|
||||
}
|
|
@ -38,13 +38,22 @@ namespace dxvk {
|
|||
m_state.conservativeMode = DecodeConservativeRasterizationMode(desc.ConservativeRaster);
|
||||
m_state.sampleCount = VkSampleCountFlags(desc.ForcedSampleCount);
|
||||
m_state.flatShading = VK_FALSE;
|
||||
m_state.lineMode = VK_LINE_RASTERIZATION_MODE_DEFAULT_EXT;
|
||||
|
||||
m_depthBias.depthBiasConstant = float(desc.DepthBias);
|
||||
m_depthBias.depthBiasSlope = desc.SlopeScaledDepthBias;
|
||||
m_depthBias.depthBiasClamp = desc.DepthBiasClamp;
|
||||
|
||||
if (desc.AntialiasedLineEnable)
|
||||
Logger::err("D3D11RasterizerState: Antialiased lines not supported");
|
||||
// Set up line rasterization mode
|
||||
const auto& features = device->GetDXVKDevice()->features();
|
||||
|
||||
if (desc.MultisampleEnable) {
|
||||
if (features.extLineRasterization.rectangularLines)
|
||||
m_state.lineMode = VK_LINE_RASTERIZATION_MODE_RECTANGULAR_EXT;
|
||||
} else if (desc.AntialiasedLineEnable) {
|
||||
if (features.extLineRasterization.smoothLines)
|
||||
m_state.lineMode = VK_LINE_RASTERIZATION_MODE_RECTANGULAR_SMOOTH_EXT;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -1,14 +1,138 @@
|
|||
#include "d3d11_buffer.h"
|
||||
#include "d3d11_texture.h"
|
||||
#include "d3d11_resource.h"
|
||||
#include "d3d11_context_imm.h"
|
||||
#include "d3d11_device.h"
|
||||
|
||||
#include "../util/util_shared_res.h"
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
D3D11DXGIKeyedMutex::D3D11DXGIKeyedMutex(
|
||||
ID3D11Resource* pResource,
|
||||
D3D11Device* pDevice)
|
||||
: m_resource(pResource),
|
||||
m_device(pDevice) {
|
||||
|
||||
m_supported = m_device->GetDXVKDevice()->features().khrWin32KeyedMutex
|
||||
&& m_device->GetDXVKDevice()->vkd()->wine_vkAcquireKeyedMutex != nullptr
|
||||
&& m_device->GetDXVKDevice()->vkd()->wine_vkReleaseKeyedMutex != nullptr;
|
||||
}
|
||||
|
||||
|
||||
D3D11DXGIKeyedMutex::~D3D11DXGIKeyedMutex() {
|
||||
|
||||
}
|
||||
|
||||
|
||||
ULONG STDMETHODCALLTYPE D3D11DXGIKeyedMutex::AddRef() {
|
||||
return m_resource->AddRef();
|
||||
}
|
||||
|
||||
|
||||
ULONG STDMETHODCALLTYPE D3D11DXGIKeyedMutex::Release() {
|
||||
return m_resource->Release();
|
||||
}
|
||||
|
||||
|
||||
HRESULT STDMETHODCALLTYPE D3D11DXGIKeyedMutex::QueryInterface(
|
||||
REFIID riid,
|
||||
void** ppvObject) {
|
||||
return m_resource->QueryInterface(riid, ppvObject);
|
||||
}
|
||||
|
||||
|
||||
HRESULT STDMETHODCALLTYPE D3D11DXGIKeyedMutex::GetPrivateData(
|
||||
REFGUID Name,
|
||||
UINT* pDataSize,
|
||||
void* pData) {
|
||||
return m_resource->GetPrivateData(Name, pDataSize, pData);
|
||||
}
|
||||
|
||||
|
||||
HRESULT STDMETHODCALLTYPE D3D11DXGIKeyedMutex::SetPrivateData(
|
||||
REFGUID Name,
|
||||
UINT DataSize,
|
||||
const void* pData) {
|
||||
return m_resource->SetPrivateData(Name, DataSize, pData);
|
||||
}
|
||||
|
||||
|
||||
HRESULT STDMETHODCALLTYPE D3D11DXGIKeyedMutex::SetPrivateDataInterface(
|
||||
REFGUID Name,
|
||||
const IUnknown* pUnknown) {
|
||||
return m_resource->SetPrivateDataInterface(Name, pUnknown);
|
||||
}
|
||||
|
||||
|
||||
HRESULT STDMETHODCALLTYPE D3D11DXGIKeyedMutex::GetParent(
|
||||
REFIID riid,
|
||||
void** ppParent) {
|
||||
return GetDevice(riid, ppParent);
|
||||
}
|
||||
|
||||
|
||||
HRESULT STDMETHODCALLTYPE D3D11DXGIKeyedMutex::GetDevice(
|
||||
REFIID riid,
|
||||
void** ppDevice) {
|
||||
Com<ID3D11Device> device;
|
||||
m_resource->GetDevice(&device);
|
||||
return device->QueryInterface(riid, ppDevice);
|
||||
}
|
||||
|
||||
|
||||
HRESULT STDMETHODCALLTYPE D3D11DXGIKeyedMutex::AcquireSync(
|
||||
UINT64 Key,
|
||||
DWORD dwMilliseconds) {
|
||||
if (!m_supported) {
|
||||
if (!m_warned) {
|
||||
m_warned = true;
|
||||
Logger::err("D3D11DXGIKeyedMutex::AcquireSync: Not supported");
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
D3D11CommonTexture* texture = GetCommonTexture(m_resource);
|
||||
Rc<DxvkDevice> dxvkDevice = m_device->GetDXVKDevice();
|
||||
|
||||
VkResult vr = dxvkDevice->vkd()->wine_vkAcquireKeyedMutex(dxvkDevice->handle(), texture->GetImage()->memory().memory(), Key, dwMilliseconds);
|
||||
switch (vr) {
|
||||
case VK_SUCCESS: return S_OK;
|
||||
case VK_TIMEOUT: return WAIT_TIMEOUT;
|
||||
default: return DXGI_ERROR_INVALID_CALL;
|
||||
}
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE D3D11DXGIKeyedMutex::ReleaseSync(
|
||||
UINT64 Key) {
|
||||
if (!m_supported)
|
||||
return S_OK;
|
||||
|
||||
D3D11CommonTexture* texture = GetCommonTexture(m_resource);
|
||||
Rc<DxvkDevice> dxvkDevice = m_device->GetDXVKDevice();
|
||||
|
||||
{
|
||||
D3D11ImmediateContext* context = m_device->GetContext();
|
||||
D3D10Multithread& multithread = context->GetMultithread();
|
||||
static bool s_errorShown = false;
|
||||
|
||||
if (!multithread.GetMultithreadProtected() && !std::exchange(s_errorShown, true))
|
||||
Logger::warn("D3D11DXGIKeyedMutex::ReleaseSync: Called without context locking enabled.");
|
||||
|
||||
D3D10DeviceLock lock = context->LockContext();
|
||||
context->WaitForResource(texture->GetImage(), DxvkCsThread::SynchronizeAll, D3D11_MAP_READ_WRITE, 0);
|
||||
}
|
||||
|
||||
return dxvkDevice->vkd()->wine_vkReleaseKeyedMutex(dxvkDevice->handle(), texture->GetImage()->memory().memory(), Key) == VK_SUCCESS
|
||||
? S_OK
|
||||
: DXGI_ERROR_INVALID_CALL;
|
||||
}
|
||||
|
||||
D3D11DXGIResource::D3D11DXGIResource(
|
||||
ID3D11Resource* pResource)
|
||||
: m_resource(pResource) {
|
||||
ID3D11Resource* pResource,
|
||||
D3D11Device* pDevice)
|
||||
: m_resource(pResource),
|
||||
m_keyedMutex(pResource, pDevice) {
|
||||
|
||||
}
|
||||
|
||||
|
@ -84,9 +208,15 @@ namespace dxvk {
|
|||
HRESULT STDMETHODCALLTYPE D3D11DXGIResource::GetSharedHandle(
|
||||
HANDLE* pSharedHandle) {
|
||||
auto texture = GetCommonTexture(m_resource);
|
||||
if (texture == nullptr || pSharedHandle == nullptr || !(texture->Desc()->MiscFlags & D3D11_RESOURCE_MISC_SHARED))
|
||||
if (texture == nullptr || pSharedHandle == nullptr ||
|
||||
(texture->Desc()->MiscFlags & D3D11_RESOURCE_MISC_SHARED_NTHANDLE))
|
||||
return E_INVALIDARG;
|
||||
|
||||
if (!(texture->Desc()->MiscFlags & (D3D11_RESOURCE_MISC_SHARED | D3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX))) {
|
||||
*pSharedHandle = NULL;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HANDLE kmtHandle = texture->GetImage()->sharedHandle();
|
||||
|
||||
if (kmtHandle == INVALID_HANDLE_VALUE)
|
||||
|
@ -143,8 +273,9 @@ namespace dxvk {
|
|||
LPCWSTR lpName,
|
||||
HANDLE* pHandle) {
|
||||
auto texture = GetCommonTexture(m_resource);
|
||||
if (pHandle) *pHandle = nullptr;
|
||||
if (texture == nullptr || pHandle == nullptr ||
|
||||
!(texture->Desc()->MiscFlags & (D3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX | D3D11_RESOURCE_MISC_SHARED_NTHANDLE)))
|
||||
!(texture->Desc()->MiscFlags & D3D11_RESOURCE_MISC_SHARED_NTHANDLE))
|
||||
return E_INVALIDARG;
|
||||
|
||||
if (lpName)
|
||||
|
@ -155,9 +286,6 @@ namespace dxvk {
|
|||
if (handle == INVALID_HANDLE_VALUE)
|
||||
return E_INVALIDARG;
|
||||
|
||||
if (texture->Desc()->MiscFlags & D3D11_RESOURCE_MISC_SHARED)
|
||||
handle = openKmtHandle( handle );
|
||||
|
||||
*pHandle = handle;
|
||||
return S_OK;
|
||||
}
|
||||
|
@ -172,6 +300,16 @@ namespace dxvk {
|
|||
}
|
||||
|
||||
|
||||
HRESULT D3D11DXGIResource::GetKeyedMutex(
|
||||
void **ppvObject) {
|
||||
auto texture = GetCommonTexture(m_resource);
|
||||
if (texture == nullptr || !(texture->Desc()->MiscFlags & D3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX))
|
||||
return E_NOINTERFACE;
|
||||
*ppvObject = ref(&m_keyedMutex);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
HRESULT GetResource11on12Info(
|
||||
ID3D11Resource* pResource,
|
||||
D3D11_ON_12_RESOURCE_INFO* p11on12Info) {
|
||||
|
|
|
@ -22,6 +22,65 @@ namespace dxvk {
|
|||
};
|
||||
|
||||
|
||||
/**
|
||||
* \brief IDXGIKeyedMutex implementation
|
||||
*/
|
||||
class D3D11DXGIKeyedMutex : public IDXGIKeyedMutex {
|
||||
|
||||
public:
|
||||
|
||||
D3D11DXGIKeyedMutex(
|
||||
ID3D11Resource* pResource,
|
||||
D3D11Device* pDevice);
|
||||
|
||||
~D3D11DXGIKeyedMutex();
|
||||
|
||||
ULONG STDMETHODCALLTYPE AddRef();
|
||||
|
||||
ULONG STDMETHODCALLTYPE Release();
|
||||
|
||||
HRESULT STDMETHODCALLTYPE QueryInterface(
|
||||
REFIID riid,
|
||||
void** ppvObject);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE GetPrivateData(
|
||||
REFGUID Name,
|
||||
UINT* pDataSize,
|
||||
void* pData);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE SetPrivateData(
|
||||
REFGUID Name,
|
||||
UINT DataSize,
|
||||
const void* pData);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE SetPrivateDataInterface(
|
||||
REFGUID Name,
|
||||
const IUnknown* pUnknown);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE GetParent(
|
||||
REFIID riid,
|
||||
void** ppParent);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE GetDevice(
|
||||
REFIID riid,
|
||||
void** ppDevice);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE AcquireSync(
|
||||
UINT64 Key,
|
||||
DWORD dwMilliseconds);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE ReleaseSync(
|
||||
UINT64 Key);
|
||||
|
||||
private:
|
||||
|
||||
ID3D11Resource* m_resource;
|
||||
D3D11Device* m_device;
|
||||
bool m_warned = false;
|
||||
bool m_supported = false;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* \brief IDXGIResource implementation for D3D11 resources
|
||||
*/
|
||||
|
@ -30,7 +89,8 @@ namespace dxvk {
|
|||
public:
|
||||
|
||||
D3D11DXGIResource(
|
||||
ID3D11Resource* pResource);
|
||||
ID3D11Resource* pResource,
|
||||
D3D11Device* pDevice);
|
||||
|
||||
~D3D11DXGIResource();
|
||||
|
||||
|
@ -86,9 +146,12 @@ namespace dxvk {
|
|||
UINT index,
|
||||
IDXGISurface2** ppSurface);
|
||||
|
||||
HRESULT GetKeyedMutex(void **ppvObject);
|
||||
|
||||
private:
|
||||
|
||||
ID3D11Resource* m_resource;
|
||||
D3D11DXGIKeyedMutex m_keyedMutex;
|
||||
|
||||
};
|
||||
|
||||
|
@ -272,4 +335,4 @@ namespace dxvk {
|
|||
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -47,9 +47,13 @@ namespace dxvk {
|
|||
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)
|
||||
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;
|
||||
|
||||
|
|
|
@ -32,7 +32,7 @@ namespace dxvk {
|
|||
}
|
||||
|
||||
static float ConvertMinLuminance(UINT dxgiLuminance) {
|
||||
return float(dxgiLuminance) / 0.0001f;
|
||||
return float(dxgiLuminance) * 0.0001f;
|
||||
}
|
||||
|
||||
static float ConvertLevel(UINT16 dxgiLevel) {
|
||||
|
@ -72,7 +72,7 @@ namespace dxvk {
|
|||
CreateHud();
|
||||
|
||||
if (!pDevice->GetOptions()->deferSurfaceCreation)
|
||||
RecreateSwapChain(false);
|
||||
RecreateSwapChain();
|
||||
}
|
||||
|
||||
|
||||
|
@ -98,7 +98,8 @@ namespace dxvk {
|
|||
InitReturnPtr(ppvObject);
|
||||
|
||||
if (riid == __uuidof(IUnknown)
|
||||
|| riid == __uuidof(IDXGIVkSwapChain)) {
|
||||
|| riid == __uuidof(IDXGIVkSwapChain)
|
||||
|| riid == __uuidof(IDXGIVkSwapChain1)) {
|
||||
*ppvObject = ref(this);
|
||||
return S_OK;
|
||||
}
|
||||
|
@ -160,12 +161,10 @@ namespace dxvk {
|
|||
|
||||
HANDLE STDMETHODCALLTYPE D3D11SwapChain::GetFrameLatencyEvent() {
|
||||
HANDLE result = nullptr;
|
||||
HANDLE processHandle = GetCurrentProcess();
|
||||
|
||||
if (!m_processHandle)
|
||||
m_processHandle = GetCurrentProcess();
|
||||
|
||||
if (!DuplicateHandle(m_processHandle, m_frameLatencyEvent,
|
||||
m_processHandle, &result, 0, FALSE, DUPLICATE_SAME_ACCESS)) {
|
||||
if (!DuplicateHandle(processHandle, m_frameLatencyEvent,
|
||||
processHandle, &result, 0, FALSE, DUPLICATE_SAME_ACCESS)) {
|
||||
Logger::err("DxgiSwapChain::GetFrameLatencyWaitableObject: DuplicateHandle failed");
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -255,22 +254,13 @@ namespace dxvk {
|
|||
UINT SyncInterval,
|
||||
UINT PresentFlags,
|
||||
const DXGI_PRESENT_PARAMETERS* pPresentParameters) {
|
||||
auto options = m_parent->GetOptions();
|
||||
|
||||
if (options->syncInterval >= 0)
|
||||
SyncInterval = options->syncInterval;
|
||||
|
||||
if (!(PresentFlags & DXGI_PRESENT_TEST)) {
|
||||
bool vsync = SyncInterval != 0;
|
||||
|
||||
m_dirty |= vsync != m_vsync;
|
||||
m_vsync = vsync;
|
||||
}
|
||||
if (!(PresentFlags & DXGI_PRESENT_TEST))
|
||||
m_dirty |= m_presenter->setSyncInterval(SyncInterval) != VK_SUCCESS;
|
||||
|
||||
HRESULT hr = S_OK;
|
||||
|
||||
if (!m_presenter->hasSwapChain()) {
|
||||
RecreateSwapChain(m_vsync);
|
||||
RecreateSwapChain();
|
||||
m_dirty = false;
|
||||
}
|
||||
|
||||
|
@ -280,19 +270,29 @@ namespace dxvk {
|
|||
if (m_device->getDeviceStatus() != VK_SUCCESS)
|
||||
hr = DXGI_ERROR_DEVICE_RESET;
|
||||
|
||||
if ((PresentFlags & DXGI_PRESENT_TEST) || hr != S_OK)
|
||||
if (PresentFlags & DXGI_PRESENT_TEST)
|
||||
return hr;
|
||||
|
||||
if (hr != S_OK) {
|
||||
SyncFrameLatency();
|
||||
return hr;
|
||||
}
|
||||
|
||||
if (std::exchange(m_dirty, false))
|
||||
RecreateSwapChain(m_vsync);
|
||||
|
||||
RecreateSwapChain();
|
||||
|
||||
try {
|
||||
PresentImage(SyncInterval);
|
||||
hr = PresentImage(SyncInterval);
|
||||
} catch (const DxvkError& e) {
|
||||
Logger::err(e.message());
|
||||
hr = E_FAIL;
|
||||
}
|
||||
|
||||
// Ensure to synchronize and release the frame latency semaphore
|
||||
// even if presentation failed with STATUS_OCCLUDED, or otherwise
|
||||
// applications using the semaphore may deadlock. This works because
|
||||
// we do not increment the frame ID in those situations.
|
||||
SyncFrameLatency();
|
||||
return hr;
|
||||
}
|
||||
|
||||
|
@ -334,34 +334,44 @@ namespace dxvk {
|
|||
}
|
||||
|
||||
|
||||
void STDMETHODCALLTYPE D3D11SwapChain::GetLastPresentCount(
|
||||
UINT64* pLastPresentCount) {
|
||||
*pLastPresentCount = UINT64(m_frameId - DXGI_MAX_SWAP_CHAIN_BUFFERS);
|
||||
}
|
||||
|
||||
|
||||
void STDMETHODCALLTYPE D3D11SwapChain::GetFrameStatistics(
|
||||
DXGI_VK_FRAME_STATISTICS* pFrameStatistics) {
|
||||
std::lock_guard<dxvk::mutex> lock(m_frameStatisticsLock);
|
||||
*pFrameStatistics = m_frameStatistics;
|
||||
}
|
||||
|
||||
|
||||
HRESULT D3D11SwapChain::PresentImage(UINT SyncInterval) {
|
||||
// Flush pending rendering commands before
|
||||
auto immediateContext = m_parent->GetContext();
|
||||
immediateContext->EndFrame();
|
||||
immediateContext->Flush();
|
||||
|
||||
// Bump our frame id.
|
||||
++m_frameId;
|
||||
|
||||
for (uint32_t i = 0; i < SyncInterval || i < 1; i++) {
|
||||
SynchronizePresent();
|
||||
|
||||
if (!m_presenter->hasSwapChain())
|
||||
return DXGI_STATUS_OCCLUDED;
|
||||
return i ? S_OK : DXGI_STATUS_OCCLUDED;
|
||||
|
||||
// Presentation semaphores and WSI swap chain image
|
||||
vk::PresenterInfo info = m_presenter->info();
|
||||
vk::PresenterSync sync;
|
||||
PresenterInfo info = m_presenter->info();
|
||||
PresenterSync sync;
|
||||
|
||||
uint32_t imageIndex = 0;
|
||||
|
||||
VkResult status = m_presenter->acquireNextImage(sync, imageIndex);
|
||||
|
||||
while (status != VK_SUCCESS && status != VK_SUBOPTIMAL_KHR) {
|
||||
RecreateSwapChain(m_vsync);
|
||||
RecreateSwapChain();
|
||||
|
||||
if (!m_presenter->hasSwapChain())
|
||||
return DXGI_STATUS_OCCLUDED;
|
||||
return i ? S_OK : DXGI_STATUS_OCCLUDED;
|
||||
|
||||
info = m_presenter->info();
|
||||
status = m_presenter->acquireNextImage(sync, imageIndex);
|
||||
|
@ -372,8 +382,6 @@ namespace dxvk {
|
|||
m_dirtyHdrMetadata = false;
|
||||
}
|
||||
|
||||
// Resolve back buffer if it is multisampled. We
|
||||
// only have to do it only for the first frame.
|
||||
m_context->beginRecording(
|
||||
m_device->createCommandList());
|
||||
|
||||
|
@ -384,40 +392,45 @@ namespace dxvk {
|
|||
if (m_hud != nullptr)
|
||||
m_hud->render(m_context, info.format, info.imageExtent);
|
||||
|
||||
if (i + 1 >= SyncInterval)
|
||||
m_context->signal(m_frameLatencySignal, m_frameId);
|
||||
|
||||
SubmitPresent(immediateContext, sync, i);
|
||||
}
|
||||
|
||||
SyncFrameLatency();
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
void D3D11SwapChain::SubmitPresent(
|
||||
D3D11ImmediateContext* pContext,
|
||||
const vk::PresenterSync& Sync,
|
||||
uint32_t FrameId) {
|
||||
const PresenterSync& Sync,
|
||||
uint32_t Repeat) {
|
||||
auto lock = pContext->LockContext();
|
||||
|
||||
// Bump frame ID as necessary
|
||||
if (!Repeat)
|
||||
m_frameId += 1;
|
||||
|
||||
// Present from CS thread so that we don't
|
||||
// have to synchronize with it first.
|
||||
m_presentStatus.result = VK_NOT_READY;
|
||||
|
||||
pContext->EmitCs([this,
|
||||
cFrameId = FrameId,
|
||||
cRepeat = Repeat,
|
||||
cSync = Sync,
|
||||
cHud = m_hud,
|
||||
cPresentMode = m_presenter->info().presentMode,
|
||||
cFrameId = m_frameId,
|
||||
cCommandList = m_context->endRecording()
|
||||
] (DxvkContext* ctx) {
|
||||
cCommandList->setWsiSemaphores(cSync);
|
||||
m_device->submitCommandList(cCommandList, nullptr);
|
||||
|
||||
if (cHud != nullptr && !cFrameId)
|
||||
if (cHud != nullptr && !cRepeat)
|
||||
cHud->update();
|
||||
|
||||
m_device->presentImage(m_presenter, &m_presentStatus);
|
||||
uint64_t frameId = cRepeat ? 0 : cFrameId;
|
||||
|
||||
m_device->presentImage(m_presenter,
|
||||
cPresentMode, frameId, &m_presentStatus);
|
||||
});
|
||||
|
||||
pContext->FlushCsChunk();
|
||||
|
@ -429,11 +442,11 @@ namespace dxvk {
|
|||
VkResult status = m_device->waitForSubmission(&m_presentStatus);
|
||||
|
||||
if (status != VK_SUCCESS)
|
||||
RecreateSwapChain(m_vsync);
|
||||
RecreateSwapChain();
|
||||
}
|
||||
|
||||
|
||||
void D3D11SwapChain::RecreateSwapChain(BOOL Vsync) {
|
||||
void D3D11SwapChain::RecreateSwapChain() {
|
||||
// Ensure that we can safely destroy the swap chain
|
||||
m_device->waitForSubmission(&m_presentStatus);
|
||||
m_device->waitForIdle();
|
||||
|
@ -441,11 +454,10 @@ namespace dxvk {
|
|||
m_presentStatus.result = VK_SUCCESS;
|
||||
m_dirtyHdrMetadata = true;
|
||||
|
||||
vk::PresenterDesc presenterDesc;
|
||||
PresenterDesc presenterDesc;
|
||||
presenterDesc.imageExtent = { m_desc.Width, m_desc.Height };
|
||||
presenterDesc.imageCount = PickImageCount(m_desc.BufferCount + 1);
|
||||
presenterDesc.numFormats = PickFormats(m_desc.Format, presenterDesc.formats);
|
||||
presenterDesc.numPresentModes = PickPresentModes(Vsync, presenterDesc.presentModes);
|
||||
presenterDesc.fullScreenExclusive = PickFullscreenMode();
|
||||
|
||||
VkResult vr = m_presenter->recreateSwapChain(presenterDesc);
|
||||
|
@ -477,28 +489,13 @@ namespace dxvk {
|
|||
|
||||
|
||||
void D3D11SwapChain::CreatePresenter() {
|
||||
DxvkDeviceQueue graphicsQueue = m_device->queues().graphics;
|
||||
|
||||
vk::PresenterDevice presenterDevice;
|
||||
presenterDevice.queueFamily = graphicsQueue.queueFamily;
|
||||
presenterDevice.queue = graphicsQueue.queueHandle;
|
||||
presenterDevice.adapter = m_device->adapter()->handle();
|
||||
presenterDevice.features.fullScreenExclusive = m_device->features().extFullScreenExclusive;
|
||||
presenterDevice.features.hdrMetadata = m_device->features().extHdrMetadata;
|
||||
|
||||
vk::PresenterDesc presenterDesc;
|
||||
PresenterDesc presenterDesc;
|
||||
presenterDesc.imageExtent = { m_desc.Width, m_desc.Height };
|
||||
presenterDesc.imageCount = PickImageCount(m_desc.BufferCount + 1);
|
||||
presenterDesc.numFormats = PickFormats(m_desc.Format, presenterDesc.formats);
|
||||
presenterDesc.numPresentModes = PickPresentModes(false, presenterDesc.presentModes);
|
||||
presenterDesc.fullScreenExclusive = PickFullscreenMode();
|
||||
|
||||
m_presenter = new vk::Presenter(
|
||||
m_device->adapter()->vki(),
|
||||
m_device->vkd(),
|
||||
presenterDevice,
|
||||
presenterDesc);
|
||||
|
||||
m_presenter = new Presenter(m_device, m_frameLatencySignal, presenterDesc);
|
||||
m_presenter->setFrameRateLimit(m_parent->GetOptions()->maxFrameRate);
|
||||
}
|
||||
|
||||
|
@ -513,7 +510,7 @@ namespace dxvk {
|
|||
|
||||
|
||||
void D3D11SwapChain::CreateRenderTargetViews() {
|
||||
vk::PresenterInfo info = m_presenter->info();
|
||||
PresenterInfo info = m_presenter->info();
|
||||
|
||||
m_imageViews.clear();
|
||||
m_imageViews.resize(info.imageCount);
|
||||
|
@ -655,11 +652,17 @@ namespace dxvk {
|
|||
// Wait for the sync event so that we respect the maximum frame latency
|
||||
m_frameLatencySignal->wait(m_frameId - GetActualFrameLatency());
|
||||
|
||||
if (m_frameLatencyEvent) {
|
||||
m_frameLatencySignal->setCallback(m_frameId, [cFrameLatencyEvent = m_frameLatencyEvent] () {
|
||||
m_frameLatencySignal->setCallback(m_frameId, [this,
|
||||
cFrameId = m_frameId,
|
||||
cFrameLatencyEvent = m_frameLatencyEvent
|
||||
] () {
|
||||
if (cFrameLatencyEvent)
|
||||
ReleaseSemaphore(cFrameLatencyEvent, 1, nullptr);
|
||||
});
|
||||
}
|
||||
|
||||
std::lock_guard<dxvk::mutex> lock(m_frameStatisticsLock);
|
||||
m_frameStatistics.PresentCount = cFrameId - DXGI_MAX_SWAP_CHAIN_BUFFERS;
|
||||
m_frameStatistics.PresentQPCTime = dxvk::high_resolution_clock::get_counter();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
@ -675,7 +678,7 @@ namespace dxvk {
|
|||
if (m_frameLatencyCap)
|
||||
maxFrameLatency = std::min(maxFrameLatency, m_frameLatencyCap);
|
||||
|
||||
maxFrameLatency = std::min(maxFrameLatency, m_desc.BufferCount + 1);
|
||||
maxFrameLatency = std::min(maxFrameLatency, m_desc.BufferCount);
|
||||
return maxFrameLatency;
|
||||
}
|
||||
|
||||
|
@ -716,25 +719,6 @@ namespace dxvk {
|
|||
}
|
||||
|
||||
|
||||
uint32_t D3D11SwapChain::PickPresentModes(
|
||||
BOOL Vsync,
|
||||
VkPresentModeKHR* pDstModes) {
|
||||
uint32_t n = 0;
|
||||
|
||||
if (Vsync) {
|
||||
if (m_parent->GetOptions()->tearFree == Tristate::False)
|
||||
pDstModes[n++] = VK_PRESENT_MODE_FIFO_RELAXED_KHR;
|
||||
pDstModes[n++] = VK_PRESENT_MODE_FIFO_KHR;
|
||||
} else {
|
||||
if (m_parent->GetOptions()->tearFree != Tristate::True)
|
||||
pDstModes[n++] = VK_PRESENT_MODE_IMMEDIATE_KHR;
|
||||
pDstModes[n++] = VK_PRESENT_MODE_MAILBOX_KHR;
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
|
||||
uint32_t D3D11SwapChain::PickImageCount(
|
||||
UINT Preferred) {
|
||||
int32_t option = m_parent->GetOptions()->numBackBuffers;
|
||||
|
|
|
@ -13,7 +13,7 @@ namespace dxvk {
|
|||
class D3D11Device;
|
||||
class D3D11DXGIDevice;
|
||||
|
||||
class D3D11SwapChain : public ComObject<IDXGIVkSwapChain> {
|
||||
class D3D11SwapChain : public ComObject<IDXGIVkSwapChain1> {
|
||||
constexpr static uint32_t DefaultFrameLatency = 1;
|
||||
public:
|
||||
|
||||
|
@ -80,6 +80,12 @@ namespace dxvk {
|
|||
HRESULT STDMETHODCALLTYPE SetHDRMetaData(
|
||||
const DXGI_VK_HDR_METADATA* pMetaData);
|
||||
|
||||
void STDMETHODCALLTYPE GetLastPresentCount(
|
||||
UINT64* pLastPresentCount);
|
||||
|
||||
void STDMETHODCALLTYPE GetFrameStatistics(
|
||||
DXGI_VK_FRAME_STATISTICS* pFrameStatistics);
|
||||
|
||||
private:
|
||||
|
||||
enum BindingIds : uint32_t {
|
||||
|
@ -97,7 +103,7 @@ namespace dxvk {
|
|||
Rc<DxvkDevice> m_device;
|
||||
Rc<DxvkContext> m_context;
|
||||
|
||||
Rc<vk::Presenter> m_presenter;
|
||||
Rc<Presenter> m_presenter;
|
||||
|
||||
Rc<DxvkImage> m_swapImage;
|
||||
Rc<DxvkImageView> m_swapImageView;
|
||||
|
@ -116,27 +122,26 @@ namespace dxvk {
|
|||
HANDLE m_frameLatencyEvent = nullptr;
|
||||
Rc<sync::CallbackFence> m_frameLatencySignal;
|
||||
|
||||
HANDLE m_processHandle = nullptr;
|
||||
|
||||
bool m_dirty = true;
|
||||
bool m_vsync = true;
|
||||
|
||||
VkColorSpaceKHR m_colorspace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR;
|
||||
|
||||
std::optional<VkHdrMetadataEXT> m_hdrMetadata;
|
||||
bool m_dirtyHdrMetadata = true;
|
||||
|
||||
dxvk::mutex m_frameStatisticsLock;
|
||||
DXGI_VK_FRAME_STATISTICS m_frameStatistics = { };
|
||||
|
||||
HRESULT PresentImage(UINT SyncInterval);
|
||||
|
||||
void SubmitPresent(
|
||||
D3D11ImmediateContext* pContext,
|
||||
const vk::PresenterSync& Sync,
|
||||
uint32_t FrameId);
|
||||
const PresenterSync& Sync,
|
||||
uint32_t Repeat);
|
||||
|
||||
void SynchronizePresent();
|
||||
|
||||
void RecreateSwapChain(
|
||||
BOOL Vsync);
|
||||
void RecreateSwapChain();
|
||||
|
||||
void CreateFrameLatencyEvent();
|
||||
|
||||
|
@ -162,10 +167,6 @@ namespace dxvk {
|
|||
DXGI_FORMAT Format,
|
||||
VkSurfaceFormatKHR* pDstFormats);
|
||||
|
||||
uint32_t PickPresentModes(
|
||||
BOOL Vsync,
|
||||
VkPresentModeKHR* pDstModes);
|
||||
|
||||
uint32_t PickImageCount(
|
||||
UINT Preferred);
|
||||
|
||||
|
|
|
@ -48,15 +48,21 @@ namespace dxvk {
|
|||
if (hSharedHandle == nullptr)
|
||||
hSharedHandle = INVALID_HANDLE_VALUE;
|
||||
|
||||
if (m_desc.MiscFlags & (D3D11_RESOURCE_MISC_SHARED|D3D11_RESOURCE_MISC_SHARED_NTHANDLE)) {
|
||||
if (m_desc.MiscFlags & D3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX)
|
||||
Logger::warn("D3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX: not supported.");
|
||||
const auto sharingFlags = D3D11_RESOURCE_MISC_SHARED|D3D11_RESOURCE_MISC_SHARED_NTHANDLE|D3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX;
|
||||
|
||||
if (m_desc.MiscFlags & sharingFlags) {
|
||||
if (pDevice->GetFeatureLevel() < D3D_FEATURE_LEVEL_10_0 ||
|
||||
(m_desc.MiscFlags & (D3D11_RESOURCE_MISC_SHARED|D3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX)) == (D3D11_RESOURCE_MISC_SHARED|D3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX) ||
|
||||
(m_desc.MiscFlags & sharingFlags) == D3D11_RESOURCE_MISC_SHARED_NTHANDLE)
|
||||
throw DxvkError(str::format("D3D11: Cannot create shared texture:",
|
||||
"\n MiscFlags: ", m_desc.MiscFlags,
|
||||
"\n FeatureLevel: ", pDevice->GetFeatureLevel()));
|
||||
|
||||
imageInfo.shared = true;
|
||||
imageInfo.sharing.mode = hSharedHandle == INVALID_HANDLE_VALUE ? DxvkSharedHandleMode::Export : DxvkSharedHandleMode::Import;
|
||||
imageInfo.sharing.type = (m_desc.MiscFlags & D3D11_RESOURCE_MISC_SHARED)
|
||||
? VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT
|
||||
: VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT;
|
||||
imageInfo.sharing.type = (m_desc.MiscFlags & D3D11_RESOURCE_MISC_SHARED_NTHANDLE)
|
||||
? VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT
|
||||
: VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT;
|
||||
imageInfo.sharing.handle = hSharedHandle;
|
||||
}
|
||||
|
||||
|
@ -205,9 +211,12 @@ namespace dxvk {
|
|||
// For some formats, we need to enable sampled and/or
|
||||
// render target capabilities if available, but these
|
||||
// should in no way affect the default image layout
|
||||
imageInfo.usage |= EnableMetaCopyUsage(imageInfo.format, imageInfo.tiling);
|
||||
imageInfo.usage |= EnableMetaPackUsage(imageInfo.format, m_desc.CPUAccessFlags);
|
||||
|
||||
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(
|
||||
|
@ -696,10 +705,10 @@ namespace dxvk {
|
|||
void D3D11CommonTexture::ExportImageInfo() {
|
||||
HANDLE hSharedHandle;
|
||||
|
||||
if (m_desc.MiscFlags & D3D11_RESOURCE_MISC_SHARED)
|
||||
hSharedHandle = openKmtHandle( m_image->sharedHandle() );
|
||||
else
|
||||
if (m_desc.MiscFlags & D3D11_RESOURCE_MISC_SHARED_NTHANDLE)
|
||||
hSharedHandle = m_image->sharedHandle();
|
||||
else
|
||||
hSharedHandle = openKmtHandle( m_image->sharedHandle() );
|
||||
|
||||
DxvkSharedTextureMetadata metadata;
|
||||
|
||||
|
@ -719,7 +728,7 @@ namespace dxvk {
|
|||
Logger::warn("D3D11: Failed to write shared resource info for a texture");
|
||||
}
|
||||
|
||||
if ((m_desc.MiscFlags & D3D11_RESOURCE_MISC_SHARED) && hSharedHandle != INVALID_HANDLE_VALUE)
|
||||
if (hSharedHandle != INVALID_HANDLE_VALUE)
|
||||
CloseHandle(hSharedHandle);
|
||||
}
|
||||
|
||||
|
@ -1090,7 +1099,7 @@ namespace dxvk {
|
|||
m_texture (this, pDevice, pDesc, p11on12Info, D3D11_RESOURCE_DIMENSION_TEXTURE1D, 0, VK_NULL_HANDLE, nullptr),
|
||||
m_interop (this, &m_texture),
|
||||
m_surface (this, &m_texture),
|
||||
m_resource(this),
|
||||
m_resource(this, pDevice),
|
||||
m_d3d10 (this) {
|
||||
|
||||
}
|
||||
|
@ -1137,7 +1146,10 @@ namespace dxvk {
|
|||
*ppvObject = ref(&m_resource);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
if (riid == __uuidof(IDXGIKeyedMutex))
|
||||
return m_resource.GetKeyedMutex(ppvObject);
|
||||
|
||||
if (riid == __uuidof(IDXGIVkInteropSurface)) {
|
||||
*ppvObject = ref(&m_interop);
|
||||
return S_OK;
|
||||
|
@ -1193,7 +1205,7 @@ namespace dxvk {
|
|||
m_texture (this, pDevice, pDesc, p11on12Info, D3D11_RESOURCE_DIMENSION_TEXTURE2D, 0, VK_NULL_HANDLE, hSharedHandle),
|
||||
m_interop (this, &m_texture),
|
||||
m_surface (this, &m_texture),
|
||||
m_resource (this),
|
||||
m_resource (this, pDevice),
|
||||
m_d3d10 (this),
|
||||
m_swapChain (nullptr) {
|
||||
}
|
||||
|
@ -1208,7 +1220,7 @@ namespace dxvk {
|
|||
m_texture (this, pDevice, pDesc, nullptr, D3D11_RESOURCE_DIMENSION_TEXTURE2D, DxgiUsage, vkImage, nullptr),
|
||||
m_interop (this, &m_texture),
|
||||
m_surface (this, &m_texture),
|
||||
m_resource (this),
|
||||
m_resource (this, pDevice),
|
||||
m_d3d10 (this),
|
||||
m_swapChain (nullptr) {
|
||||
|
||||
|
@ -1224,7 +1236,7 @@ namespace dxvk {
|
|||
m_texture (this, pDevice, pDesc, nullptr, D3D11_RESOURCE_DIMENSION_TEXTURE2D, DxgiUsage, VK_NULL_HANDLE, nullptr),
|
||||
m_interop (this, &m_texture),
|
||||
m_surface (this, &m_texture),
|
||||
m_resource (this),
|
||||
m_resource (this, pDevice),
|
||||
m_d3d10 (this),
|
||||
m_swapChain (pSwapChain) {
|
||||
|
||||
|
@ -1298,6 +1310,9 @@ namespace dxvk {
|
|||
*ppvObject = ref(&m_resource);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
if (riid == __uuidof(IDXGIKeyedMutex))
|
||||
return m_resource.GetKeyedMutex(ppvObject);
|
||||
|
||||
if (riid == __uuidof(IDXGIVkInteropSurface)) {
|
||||
*ppvObject = ref(&m_interop);
|
||||
|
@ -1369,7 +1384,7 @@ namespace dxvk {
|
|||
: D3D11DeviceChild<ID3D11Texture3D1>(pDevice),
|
||||
m_texture (this, pDevice, pDesc, p11on12Info, D3D11_RESOURCE_DIMENSION_TEXTURE3D, 0, VK_NULL_HANDLE, nullptr),
|
||||
m_interop (this, &m_texture),
|
||||
m_resource(this),
|
||||
m_resource(this, pDevice),
|
||||
m_d3d10 (this) {
|
||||
|
||||
}
|
||||
|
@ -1409,7 +1424,10 @@ namespace dxvk {
|
|||
*ppvObject = ref(&m_resource);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
if (riid == __uuidof(IDXGIKeyedMutex))
|
||||
return m_resource.GetKeyedMutex(ppvObject);
|
||||
|
||||
if (riid == __uuidof(IDXGIVkInteropSurface)) {
|
||||
*ppvObject = ref(&m_interop);
|
||||
return S_OK;
|
||||
|
|
|
@ -1262,12 +1262,28 @@ namespace dxvk {
|
|||
viewport.height = float(cStreamState.dstRect.bottom) - viewport.y;
|
||||
}
|
||||
|
||||
VkExtent3D viewExtent = cViews[0]->mipLevelExtent(0);
|
||||
|
||||
VkRect2D srcRect;
|
||||
srcRect.offset = { 0, 0 };
|
||||
srcRect.extent = { viewExtent.width, viewExtent.height };
|
||||
|
||||
if (cStreamState.srcRectEnabled) {
|
||||
srcRect.offset.x = cStreamState.srcRect.left;
|
||||
srcRect.offset.y = cStreamState.srcRect.top;
|
||||
srcRect.extent.width = cStreamState.srcRect.right - srcRect.offset.x;
|
||||
srcRect.extent.height = cStreamState.srcRect.bottom - srcRect.offset.y;
|
||||
}
|
||||
|
||||
UboData uboData = { };
|
||||
uboData.colorMatrix[0][0] = 1.0f;
|
||||
uboData.colorMatrix[1][1] = 1.0f;
|
||||
uboData.colorMatrix[2][2] = 1.0f;
|
||||
uboData.coordMatrix[0][0] = 1.0f;
|
||||
uboData.coordMatrix[1][1] = 1.0f;
|
||||
uboData.coordMatrix[0][0] = float(srcRect.extent.width) / float(viewExtent.width);
|
||||
uboData.coordMatrix[1][1] = float(srcRect.extent.height) / float(viewExtent.height);
|
||||
uboData.coordMatrix[2][0] = float(srcRect.offset.x) / float(viewExtent.width);
|
||||
uboData.coordMatrix[2][1] = float(srcRect.offset.y) / float(viewExtent.height);
|
||||
uboData.srcRect = srcRect;
|
||||
uboData.yMin = 0.0f;
|
||||
uboData.yMax = 1.0f;
|
||||
uboData.isPlanar = cViews[1] != nullptr;
|
||||
|
@ -1290,17 +1306,14 @@ namespace dxvk {
|
|||
ctx->bindShader<VK_SHADER_STAGE_FRAGMENT_BIT>(Rc<DxvkShader>(m_fs));
|
||||
|
||||
ctx->bindUniformBuffer(VK_SHADER_STAGE_FRAGMENT_BIT, 0, DxvkBufferSlice(m_ubo));
|
||||
ctx->bindResourceSampler(VK_SHADER_STAGE_FRAGMENT_BIT, 1, Rc<DxvkSampler>(m_sampler));
|
||||
|
||||
for (uint32_t i = 0; i < cViews.size(); i++)
|
||||
ctx->bindResourceImageView(VK_SHADER_STAGE_FRAGMENT_BIT, 2 + i, Rc<DxvkImageView>(cViews[i]));
|
||||
ctx->bindResourceImageView(VK_SHADER_STAGE_FRAGMENT_BIT, 1 + i, Rc<DxvkImageView>(cViews[i]));
|
||||
|
||||
ctx->draw(3, 1, 0, 0);
|
||||
|
||||
ctx->bindResourceSampler(VK_SHADER_STAGE_FRAGMENT_BIT, 1, nullptr);
|
||||
|
||||
for (uint32_t i = 0; i < cViews.size(); i++)
|
||||
ctx->bindResourceImageView(VK_SHADER_STAGE_FRAGMENT_BIT, 2 + i, nullptr);
|
||||
ctx->bindResourceImageView(VK_SHADER_STAGE_FRAGMENT_BIT, 1 + i, nullptr);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -1315,38 +1328,14 @@ namespace dxvk {
|
|||
}
|
||||
|
||||
|
||||
void D3D11VideoContext::CreateSampler() {
|
||||
DxvkSamplerCreateInfo samplerInfo;
|
||||
samplerInfo.magFilter = VK_FILTER_LINEAR;
|
||||
samplerInfo.minFilter = VK_FILTER_LINEAR;
|
||||
samplerInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_NEAREST;
|
||||
samplerInfo.mipmapLodBias = 0.0f;
|
||||
samplerInfo.mipmapLodMin = 0.0f;
|
||||
samplerInfo.mipmapLodMax = 0.0f;
|
||||
samplerInfo.useAnisotropy = VK_FALSE;
|
||||
samplerInfo.maxAnisotropy = 1.0f;
|
||||
samplerInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
|
||||
samplerInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
|
||||
samplerInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
|
||||
samplerInfo.compareToDepth = VK_FALSE;
|
||||
samplerInfo.compareOp = VK_COMPARE_OP_ALWAYS;
|
||||
samplerInfo.reductionMode = VK_SAMPLER_REDUCTION_MODE_WEIGHTED_AVERAGE;
|
||||
samplerInfo.borderColor = VkClearColorValue();
|
||||
samplerInfo.usePixelCoord = VK_FALSE;
|
||||
samplerInfo.nonSeamless = VK_FALSE;
|
||||
m_sampler = m_device->createSampler(samplerInfo);
|
||||
}
|
||||
|
||||
|
||||
void D3D11VideoContext::CreateShaders() {
|
||||
SpirvCodeBuffer vsCode(d3d11_video_blit_vert);
|
||||
SpirvCodeBuffer fsCode(d3d11_video_blit_frag);
|
||||
|
||||
const std::array<DxvkBindingInfo, 4> fsBindings = {{
|
||||
const std::array<DxvkBindingInfo, 3> fsBindings = {{
|
||||
{ VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 0, VK_IMAGE_VIEW_TYPE_MAX_ENUM, VK_SHADER_STAGE_FRAGMENT_BIT, VK_ACCESS_UNIFORM_READ_BIT, VK_TRUE },
|
||||
{ VK_DESCRIPTOR_TYPE_SAMPLER, 1, VK_IMAGE_VIEW_TYPE_MAX_ENUM, VK_SHADER_STAGE_FRAGMENT_BIT, 0 },
|
||||
{ VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, 1, VK_IMAGE_VIEW_TYPE_2D, VK_SHADER_STAGE_FRAGMENT_BIT, VK_ACCESS_SHADER_READ_BIT },
|
||||
{ VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, 2, VK_IMAGE_VIEW_TYPE_2D, VK_SHADER_STAGE_FRAGMENT_BIT, VK_ACCESS_SHADER_READ_BIT },
|
||||
{ VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, 3, VK_IMAGE_VIEW_TYPE_2D, VK_SHADER_STAGE_FRAGMENT_BIT, VK_ACCESS_SHADER_READ_BIT },
|
||||
}};
|
||||
|
||||
DxvkShaderCreateInfo vsInfo;
|
||||
|
@ -1368,7 +1357,6 @@ namespace dxvk {
|
|||
if (std::exchange(m_resourcesCreated, true))
|
||||
return;
|
||||
|
||||
CreateSampler();
|
||||
CreateUniformBuffer();
|
||||
CreateShaders();
|
||||
}
|
||||
|
|
|
@ -584,6 +584,7 @@ namespace dxvk {
|
|||
struct alignas(16) UboData {
|
||||
float colorMatrix[3][4];
|
||||
float coordMatrix[3][2];
|
||||
VkRect2D srcRect;
|
||||
float yMin, yMax;
|
||||
VkBool32 isPlanar;
|
||||
};
|
||||
|
@ -593,7 +594,6 @@ namespace dxvk {
|
|||
Rc<DxvkDevice> m_device;
|
||||
Rc<DxvkShader> m_vs;
|
||||
Rc<DxvkShader> m_fs;
|
||||
Rc<DxvkSampler> m_sampler;
|
||||
Rc<DxvkBuffer> m_ubo;
|
||||
|
||||
VkExtent2D m_dstExtent = { 0u, 0u };
|
||||
|
@ -613,8 +613,6 @@ namespace dxvk {
|
|||
|
||||
void CreateUniformBuffer();
|
||||
|
||||
void CreateSampler();
|
||||
|
||||
void CreateShaders();
|
||||
|
||||
void CreateResources();
|
||||
|
|
|
@ -126,7 +126,7 @@ namespace dxvk {
|
|||
if (riid == __uuidof(ID3D10DeviceChild)
|
||||
|| riid == __uuidof(ID3D10View)
|
||||
|| riid == __uuidof(ID3D10DepthStencilView)) {
|
||||
*ppvObject = ref(this);
|
||||
*ppvObject = ref(&m_d3d10);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -77,6 +77,10 @@ namespace dxvk {
|
|||
return mask;
|
||||
}
|
||||
|
||||
DXGI_FORMAT GetViewFormat() const {
|
||||
return m_desc.Format;
|
||||
}
|
||||
|
||||
D3D10DepthStencilView* GetD3D10Iface() {
|
||||
return &m_d3d10;
|
||||
}
|
||||
|
|
|
@ -137,7 +137,7 @@ namespace dxvk {
|
|||
if (riid == __uuidof(ID3D10DeviceChild)
|
||||
|| riid == __uuidof(ID3D10View)
|
||||
|| riid == __uuidof(ID3D10RenderTargetView)) {
|
||||
*ppvObject = ref(this);
|
||||
*ppvObject = ref(&m_d3d10);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -205,7 +205,7 @@ namespace dxvk {
|
|||
|| riid == __uuidof(ID3D10View)
|
||||
|| riid == __uuidof(ID3D10ShaderResourceView)
|
||||
|| riid == __uuidof(ID3D10ShaderResourceView1)) {
|
||||
*ppvObject = ref(this);
|
||||
*ppvObject = ref(&m_d3d10);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
@ -298,7 +298,7 @@ namespace dxvk {
|
|||
D3D11_BUFFER_DESC bufferDesc;
|
||||
static_cast<D3D11Buffer*>(pResource)->GetDesc(&bufferDesc);
|
||||
|
||||
if (bufferDesc.MiscFlags == D3D11_RESOURCE_MISC_BUFFER_STRUCTURED) {
|
||||
if (bufferDesc.MiscFlags & D3D11_RESOURCE_MISC_BUFFER_STRUCTURED) {
|
||||
pDesc->Format = DXGI_FORMAT_UNKNOWN;
|
||||
pDesc->ViewDimension = D3D11_SRV_DIMENSION_BUFFER;
|
||||
pDesc->Buffer.FirstElement = 0;
|
||||
|
|
|
@ -214,7 +214,7 @@ namespace dxvk {
|
|||
D3D11_BUFFER_DESC bufferDesc;
|
||||
static_cast<D3D11Buffer*>(pResource)->GetDesc(&bufferDesc);
|
||||
|
||||
if (bufferDesc.MiscFlags == D3D11_RESOURCE_MISC_BUFFER_STRUCTURED) {
|
||||
if (bufferDesc.MiscFlags & D3D11_RESOURCE_MISC_BUFFER_STRUCTURED) {
|
||||
pDesc->Format = DXGI_FORMAT_UNKNOWN;
|
||||
pDesc->ViewDimension = D3D11_UAV_DIMENSION_BUFFER;
|
||||
pDesc->Buffer.FirstElement = 0;
|
||||
|
|
|
@ -69,15 +69,18 @@ d3d11_shaders = files([
|
|||
d3d11_ld_args = []
|
||||
d3d11_link_depends = []
|
||||
|
||||
if platform != 'windows'
|
||||
if platform == 'windows'
|
||||
d3d11_dxgi_dep = lib_dxgi
|
||||
else
|
||||
d3d11_ld_args += [ '-Wl,--version-script', join_paths(meson.current_source_dir(), 'd3d11.sym') ]
|
||||
d3d11_link_depends += files('d3d11.sym')
|
||||
d3d11_dxgi_dep = dxgi_dep
|
||||
endif
|
||||
|
||||
d3d11_dll = shared_library('d3d11'+dll_ext, dxgi_common_src + d3d11_src + d3d10_src,
|
||||
glsl_generator.process(d3d11_shaders), d3d11_res,
|
||||
name_prefix : dxvk_name_prefix,
|
||||
dependencies : [ dxgi_dep, dxbc_dep, dxvk_dep ],
|
||||
dependencies : [ d3d11_dxgi_dep, dxbc_dep, dxvk_dep ],
|
||||
include_directories : dxvk_include_path,
|
||||
install : true,
|
||||
vs_module_defs : 'd3d11'+def_spec_ext,
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
#version 450
|
||||
|
||||
#extension GL_EXT_samplerless_texture_functions : require
|
||||
|
||||
// Can't use matrix types here since even a two-row
|
||||
// matrix will be padded to 16 bytes per column for
|
||||
// absolutely no reason
|
||||
|
@ -11,6 +13,8 @@ uniform ubo_t {
|
|||
vec2 coord_matrix_c1;
|
||||
vec2 coord_matrix_c2;
|
||||
vec2 coord_matrix_c3;
|
||||
uvec2 src_offset;
|
||||
uvec2 src_extent;
|
||||
float y_min;
|
||||
float y_max;
|
||||
bool is_planar;
|
||||
|
@ -19,9 +23,8 @@ uniform ubo_t {
|
|||
layout(location = 0) in vec2 i_texcoord;
|
||||
layout(location = 0) out vec4 o_color;
|
||||
|
||||
layout(set = 0, binding = 1) uniform sampler s_sampler;
|
||||
layout(set = 0, binding = 2) uniform texture2D s_inputY;
|
||||
layout(set = 0, binding = 3) uniform texture2D s_inputCbCr;
|
||||
layout(set = 0, binding = 1) uniform texture2D s_inputY;
|
||||
layout(set = 0, binding = 2) uniform texture2D s_inputCbCr;
|
||||
|
||||
void main() {
|
||||
// Transform input texture coordinates to
|
||||
|
@ -31,25 +34,61 @@ void main() {
|
|||
coord_matrix_c2,
|
||||
coord_matrix_c3);
|
||||
|
||||
vec2 coord = coord_matrix * vec3(i_texcoord, 1.0f);
|
||||
|
||||
// Fetch source image color
|
||||
vec4 color = vec4(0.0f, 0.0f, 0.0f, 1.0f);
|
||||
|
||||
if (is_planar) {
|
||||
color.g = texture(sampler2D(s_inputY, s_sampler), coord).r;
|
||||
color.rb = texture(sampler2D(s_inputCbCr, s_sampler), coord).gr;
|
||||
color.g = clamp((color.g - y_min) / (y_max - y_min), 0.0f, 1.0f);
|
||||
} else {
|
||||
color = texture(sampler2D(s_inputY, s_sampler), coord);
|
||||
}
|
||||
|
||||
// Color space transformation
|
||||
// Load color space transform
|
||||
mat3x4 color_matrix = mat3x4(
|
||||
color_matrix_r1,
|
||||
color_matrix_r2,
|
||||
color_matrix_r3);
|
||||
|
||||
o_color.rgb = vec4(color.rgb, 1.0f) * color_matrix;
|
||||
o_color.a = color.a;
|
||||
// Compute actual pixel coordinates to sample. We filter
|
||||
// manually in order to avoid bleeding from pixels outside
|
||||
// the source rectangle.
|
||||
vec2 abs_size_y = vec2(textureSize(s_inputY, 0));
|
||||
vec2 abs_size_c = vec2(textureSize(s_inputCbCr, 0));
|
||||
|
||||
vec2 coord = coord_matrix * vec3(i_texcoord, 1.0f);
|
||||
coord -= 0.5f / abs_size_y;
|
||||
|
||||
vec2 size_factor = abs_size_c / abs_size_y;
|
||||
|
||||
vec2 src_lo = vec2(src_offset);
|
||||
vec2 src_hi = vec2(src_offset + src_extent - 1u);
|
||||
|
||||
vec2 abs_coord = coord * abs_size_y;
|
||||
vec2 fract_coord = fract(clamp(abs_coord, src_lo, src_hi));
|
||||
|
||||
vec4 accum = vec4(0.0f, 0.0f, 0.0f, 0.0f);
|
||||
|
||||
for (int i = 0; i < 4; i++) {
|
||||
ivec2 offset = ivec2(i & 1, i >> 1);
|
||||
|
||||
// Compute exact pixel coordinates for the current
|
||||
// iteration and clamp it to the source rectangle.
|
||||
vec2 fetch_coord = clamp(abs_coord + vec2(offset), src_lo, src_hi);
|
||||
|
||||
// Fetch actual pixel color in source color space
|
||||
vec4 color;
|
||||
|
||||
if (is_planar) {
|
||||
color.g = texelFetch(s_inputY, ivec2(fetch_coord), 0).r;
|
||||
color.rb = texelFetch(s_inputCbCr, ivec2(fetch_coord * size_factor), 0).gr;
|
||||
color.g = clamp((color.g - y_min) / (y_max - y_min), 0.0f, 1.0f);
|
||||
color.a = 1.0f;
|
||||
} else {
|
||||
color = texelFetch(s_inputY, ivec2(fetch_coord), 0);
|
||||
}
|
||||
|
||||
// Transform color space before accumulation
|
||||
color.rgb = vec4(color.rgb, 1.0f) * color_matrix;
|
||||
|
||||
// Filter and accumulate final pixel color
|
||||
vec2 factor = fract_coord;
|
||||
|
||||
if (offset.x == 0) factor.x = 1.0f - factor.x;
|
||||
if (offset.y == 0) factor.y = 1.0f - factor.y;
|
||||
|
||||
accum += factor.x * factor.y * color;
|
||||
}
|
||||
|
||||
o_color = accum;
|
||||
}
|
||||
|
|
|
@ -25,3 +25,6 @@ EXPORTS
|
|||
DXVK_UnRegisterAnnotation @28258 NONAME
|
||||
|
||||
Direct3D9ForceHybridEnumeration @16 NONAME PRIVATE
|
||||
|
||||
Direct3DCreate9On12 @20
|
||||
Direct3DCreate9On12Ex @21
|
||||
|
|
|
@ -18,6 +18,8 @@
|
|||
DXVK_RegisterAnnotation;
|
||||
DXVK_UnRegisterAnnotation;
|
||||
Direct3D9ForceHybridEnumeration;
|
||||
Direct3DCreate9On12;
|
||||
Direct3DCreate9On12Ex;
|
||||
|
||||
local:
|
||||
*;
|
||||
|
|
|
@ -162,6 +162,9 @@ namespace dxvk {
|
|||
if (mapping.FormatSrgb == VK_FORMAT_UNDEFINED && srgb)
|
||||
return D3DERR_NOTAVAILABLE;
|
||||
|
||||
if (RType == D3DRTYPE_CUBETEXTURE && mapping.Aspect != VK_IMAGE_ASPECT_COLOR_BIT)
|
||||
return D3DERR_NOTAVAILABLE;
|
||||
|
||||
if (RType == D3DRTYPE_VERTEXBUFFER || RType == D3DRTYPE_INDEXBUFFER)
|
||||
return D3D_OK;
|
||||
|
||||
|
@ -224,11 +227,15 @@ namespace dxvk {
|
|||
if (!IsDepthFormat(DepthStencilFormat))
|
||||
return D3DERR_NOTAVAILABLE;
|
||||
|
||||
auto dsfMapping = ConvertFormatUnfixed(DepthStencilFormat);
|
||||
if (dsfMapping.FormatColor == VK_FORMAT_UNDEFINED)
|
||||
return D3DERR_NOTAVAILABLE;
|
||||
|
||||
if (RenderTargetFormat == dxvk::D3D9Format::NULL_FORMAT)
|
||||
return D3D_OK;
|
||||
|
||||
auto mapping = ConvertFormatUnfixed(RenderTargetFormat);
|
||||
if (mapping.FormatColor == VK_FORMAT_UNDEFINED)
|
||||
auto rtfMapping = ConvertFormatUnfixed(RenderTargetFormat);
|
||||
if (rtfMapping.FormatColor == VK_FORMAT_UNDEFINED)
|
||||
return D3DERR_NOTAVAILABLE;
|
||||
|
||||
return D3D_OK;
|
||||
|
@ -529,7 +536,7 @@ namespace dxvk {
|
|||
// Max Vertex Blend Matrices
|
||||
pCaps->MaxVertexBlendMatrices = 4;
|
||||
// Max Vertex Blend Matrix Index
|
||||
pCaps->MaxVertexBlendMatrixIndex = 8;
|
||||
pCaps->MaxVertexBlendMatrixIndex = 0;
|
||||
// Max Point Size
|
||||
pCaps->MaxPointSize = 256.0f;
|
||||
// Max Primitive Count
|
||||
|
@ -788,7 +795,8 @@ namespace dxvk {
|
|||
// Fix up the D3DFORMAT to match what we are enumerating
|
||||
mode.Format = static_cast<D3DFORMAT>(Format);
|
||||
|
||||
m_modes.push_back(mode);
|
||||
if (std::count(m_modes.begin(), m_modes.end(), mode) == 0)
|
||||
m_modes.push_back(mode);
|
||||
}
|
||||
|
||||
// Sort display modes by width, height and refresh rate,
|
||||
|
|
|
@ -0,0 +1,111 @@
|
|||
|
||||
#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();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,118 @@
|
|||
#pragma once
|
||||
|
||||
#include <windows.h>
|
||||
#include "../util/config/config.h"
|
||||
|
||||
#include "../vulkan/vulkan_loader.h"
|
||||
|
||||
/**
|
||||
* The D3D9 bridge allows D3D8 to access DXVK internals.
|
||||
* For Vulkan interop without needing DXVK internals, see d3d9_interop.h.
|
||||
*
|
||||
* NOTE: You must include "d3d9_include.h" or "d3d8_include.h" before this header.
|
||||
*/
|
||||
|
||||
/**
|
||||
* \brief D3D9 device interface for D3D8 interop
|
||||
*/
|
||||
MIDL_INTERFACE("D3D9D3D8-42A9-4C1E-AA97-BEEFCAFE2000")
|
||||
IDxvkD3D8Bridge : public IUnknown {
|
||||
|
||||
// D3D8 keeps D3D9 objects contained in a namespace.
|
||||
#ifdef DXVK_D3D9_NAMESPACE
|
||||
using IDirect3DSurface9 = d3d9::IDirect3DSurface9;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* \brief Changes the API name displayed on the HUD
|
||||
*
|
||||
* \param [in] name The new API name
|
||||
*/
|
||||
virtual void SetAPIName(const char* name) = 0;
|
||||
|
||||
/**
|
||||
* \brief Enables or disables D3D9-specific device features and validations
|
||||
*
|
||||
* \param [in] compatibility state
|
||||
*/
|
||||
virtual void SetD3D8CompatibilityMode(const bool compatMode) = 0;
|
||||
|
||||
/**
|
||||
* \brief Updates a D3D9 surface from a D3D9 buffer
|
||||
*
|
||||
* \param [in] pDestSurface Destination surface (typically in VRAM)
|
||||
* \param [in] pSrcSurface Source surface (typically in system memory)
|
||||
* \param [in] pSrcRect Source rectangle
|
||||
* \param [in] pDestPoint Destination (top-left) point
|
||||
*/
|
||||
virtual HRESULT UpdateTextureFromBuffer(
|
||||
IDirect3DSurface9* pDestSurface,
|
||||
IDirect3DSurface9* pSrcSurface,
|
||||
const RECT* pSrcRect,
|
||||
const POINT* pDestPoint) = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief D3D9 instance interface for D3D8 interop
|
||||
*/
|
||||
MIDL_INTERFACE("D3D9D3D8-A407-773E-18E9-CAFEBEEF3000")
|
||||
IDxvkD3D8InterfaceBridge : public IUnknown {
|
||||
/**
|
||||
* \brief Retrieves the DXVK configuration
|
||||
*
|
||||
* \returns The DXVK Config object
|
||||
*/
|
||||
virtual const dxvk::Config* GetConfig() const = 0;
|
||||
};
|
||||
|
||||
#ifndef _MSC_VER
|
||||
__CRT_UUID_DECL(IDxvkD3D8Bridge, 0xD3D9D3D8, 0x42A9, 0x4C1E, 0xAA, 0x97, 0xBE, 0xEF, 0xCA, 0xFE, 0x20, 0x00);
|
||||
__CRT_UUID_DECL(IDxvkD3D8InterfaceBridge, 0xD3D9D3D8, 0xA407, 0x773E, 0x18, 0xE9, 0xCA, 0xFE, 0xBE, 0xEF, 0x30, 0x00);
|
||||
#endif
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
class D3D9DeviceEx;
|
||||
class D3D9InterfaceEx;
|
||||
|
||||
class DxvkD3D8Bridge : public IDxvkD3D8Bridge {
|
||||
public:
|
||||
DxvkD3D8Bridge(D3D9DeviceEx* pDevice);
|
||||
~DxvkD3D8Bridge();
|
||||
|
||||
ULONG STDMETHODCALLTYPE AddRef();
|
||||
ULONG STDMETHODCALLTYPE Release();
|
||||
HRESULT STDMETHODCALLTYPE QueryInterface(
|
||||
REFIID riid,
|
||||
void** ppvObject);
|
||||
|
||||
void SetAPIName(const char* name);
|
||||
void SetD3D8CompatibilityMode(const bool compatMode);
|
||||
|
||||
HRESULT UpdateTextureFromBuffer(
|
||||
IDirect3DSurface9* pDestSurface,
|
||||
IDirect3DSurface9* pSrcSurface,
|
||||
const RECT* pSrcRect,
|
||||
const POINT* pDestPoint);
|
||||
|
||||
private:
|
||||
D3D9DeviceEx* m_device;
|
||||
};
|
||||
|
||||
class DxvkD3D8InterfaceBridge : public IDxvkD3D8InterfaceBridge {
|
||||
public:
|
||||
DxvkD3D8InterfaceBridge(D3D9InterfaceEx* pObject);
|
||||
~DxvkD3D8InterfaceBridge();
|
||||
|
||||
ULONG STDMETHODCALLTYPE AddRef();
|
||||
ULONG STDMETHODCALLTYPE Release();
|
||||
HRESULT STDMETHODCALLTYPE QueryInterface(
|
||||
REFIID riid,
|
||||
void** ppvObject);
|
||||
|
||||
const Config* GetConfig() const;
|
||||
|
||||
protected:
|
||||
D3D9InterfaceEx* m_interface;
|
||||
};
|
||||
}
|
|
@ -20,6 +20,11 @@ namespace dxvk {
|
|||
m_dirtyRange = D3D9Range(0, m_desc.Size);
|
||||
}
|
||||
|
||||
D3D9CommonBuffer::~D3D9CommonBuffer() {
|
||||
if (m_desc.Pool == D3DPOOL_DEFAULT)
|
||||
m_parent->DecrementLosableCounter();
|
||||
}
|
||||
|
||||
|
||||
HRESULT D3D9CommonBuffer::Lock(
|
||||
UINT OffsetToLock,
|
||||
|
@ -57,6 +62,32 @@ namespace dxvk {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
D3D9_COMMON_BUFFER_MAP_MODE D3D9CommonBuffer::DetermineMapMode(const D3D9Options* options) const {
|
||||
if (m_desc.Pool != D3DPOOL_DEFAULT)
|
||||
return D3D9_COMMON_BUFFER_MAP_MODE_BUFFER;
|
||||
|
||||
// CSGO keeps vertex buffers locked across multiple frames and writes to it. It uses them for drawing without unlocking first.
|
||||
// Tests show that D3D9 DEFAULT + USAGE_DYNAMIC behaves like a directly mapped buffer even when unlocked.
|
||||
// DEFAULT + WRITEONLY does not behave like a directly mapped buffer EXCEPT if its locked at the moment.
|
||||
// That's annoying to implement so we just always directly map DEFAULT + WRITEONLY.
|
||||
if (!(m_desc.Usage & (D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY)))
|
||||
return D3D9_COMMON_BUFFER_MAP_MODE_BUFFER;
|
||||
|
||||
// Tests show that DISCARD does not work for pure SWVP devices.
|
||||
// So force staging buffer path to avoid stalls.
|
||||
// Dark Romance: Vampire in Love also expects draws to be synchronous
|
||||
// and breaks if we respect NOOVERWRITE.
|
||||
// D&D Temple of Elemental Evil breaks if we respect DISCARD.
|
||||
if (m_parent->CanOnlySWVP())
|
||||
return D3D9_COMMON_BUFFER_MAP_MODE_BUFFER;
|
||||
|
||||
if (!options->allowDirectBufferMapping)
|
||||
return D3D9_COMMON_BUFFER_MAP_MODE_BUFFER;
|
||||
|
||||
return D3D9_COMMON_BUFFER_MAP_MODE_DIRECT;
|
||||
}
|
||||
|
||||
|
||||
Rc<DxvkBuffer> D3D9CommonBuffer::CreateBuffer() const {
|
||||
DxvkBufferCreateInfo info;
|
||||
|
@ -103,7 +134,8 @@ namespace dxvk {
|
|||
memoryFlags |= VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
|
||||
}
|
||||
|
||||
if (memoryFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT && m_parent->GetOptions()->apitraceMode) {
|
||||
if ((memoryFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) && m_parent->GetOptions()->cachedDynamicBuffers) {
|
||||
memoryFlags &= ~VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
|
||||
memoryFlags |= VK_MEMORY_PROPERTY_HOST_COHERENT_BIT
|
||||
| VK_MEMORY_PROPERTY_HOST_CACHED_BIT;
|
||||
}
|
||||
|
|
|
@ -78,6 +78,8 @@ namespace dxvk {
|
|||
D3D9DeviceEx* pDevice,
|
||||
const D3D9_BUFFER_DESC* pDesc);
|
||||
|
||||
~D3D9CommonBuffer();
|
||||
|
||||
HRESULT Lock(
|
||||
UINT OffsetToLock,
|
||||
UINT SizeToLock,
|
||||
|
@ -89,11 +91,7 @@ namespace dxvk {
|
|||
/**
|
||||
* \brief Determine the mapping mode of the buffer, (ie. direct mapping or backed)
|
||||
*/
|
||||
inline D3D9_COMMON_BUFFER_MAP_MODE DetermineMapMode(const D3D9Options* options) const {
|
||||
return (m_desc.Pool == D3DPOOL_DEFAULT && (m_desc.Usage & (D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY)) && options->allowDirectBufferMapping)
|
||||
? D3D9_COMMON_BUFFER_MAP_MODE_DIRECT
|
||||
: D3D9_COMMON_BUFFER_MAP_MODE_BUFFER;
|
||||
}
|
||||
D3D9_COMMON_BUFFER_MAP_MODE DetermineMapMode(const D3D9Options* options) const;
|
||||
|
||||
/**
|
||||
* \brief Get the mapping mode of the buffer, (ie. direct mapping or backed)
|
||||
|
@ -127,7 +125,12 @@ namespace dxvk {
|
|||
|
||||
template <D3D9_COMMON_BUFFER_TYPE Type>
|
||||
inline DxvkBufferSlice GetBufferSlice(VkDeviceSize offset, VkDeviceSize length) const {
|
||||
return DxvkBufferSlice(GetBuffer<Type>(), offset, length);
|
||||
if (likely(length && offset < m_desc.Size)) {
|
||||
return DxvkBufferSlice(GetBuffer<Type>(), offset,
|
||||
std::min<VkDeviceSize>(m_desc.Size - offset, length));
|
||||
}
|
||||
|
||||
return DxvkBufferSlice();
|
||||
}
|
||||
|
||||
inline DxvkBufferSliceHandle AllocMapSlice() {
|
||||
|
@ -208,6 +211,10 @@ namespace dxvk {
|
|||
: DxvkCsThread::SynchronizeAll;
|
||||
}
|
||||
|
||||
bool IsSysmemDynamic() const {
|
||||
return m_desc.Pool == D3DPOOL_SYSTEMMEM && (m_desc.Usage & D3DUSAGE_DYNAMIC) != 0;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
Rc<DxvkBuffer> CreateBuffer() const;
|
||||
|
@ -227,7 +234,7 @@ namespace dxvk {
|
|||
|
||||
D3D9DeviceEx* m_parent;
|
||||
const D3D9_BUFFER_DESC m_desc;
|
||||
DWORD m_mapFlags;
|
||||
DWORD m_mapFlags = 0;
|
||||
bool m_needsReadback = false;
|
||||
D3D9_COMMON_BUFFER_MAP_MODE m_mapMode;
|
||||
|
||||
|
|
|
@ -31,11 +31,12 @@ namespace dxvk {
|
|||
AddDirtyBox(nullptr, i);
|
||||
}
|
||||
|
||||
if (m_desc.Pool != D3DPOOL_DEFAULT) {
|
||||
if (m_desc.Pool != D3DPOOL_DEFAULT && pSharedHandle) {
|
||||
throw DxvkError("D3D9: Incompatible pool type for texture sharing.");
|
||||
}
|
||||
|
||||
if (IsPoolManaged(m_desc.Pool)) {
|
||||
SetAllNeedUpload();
|
||||
if (pSharedHandle) {
|
||||
throw DxvkError("D3D9: Incompatible pool type for texture sharing.");
|
||||
}
|
||||
}
|
||||
|
||||
m_mapping = pDevice->LookupFormat(m_desc.Format);
|
||||
|
@ -98,6 +99,9 @@ namespace dxvk {
|
|||
m_device->ChangeReportedMemory(m_size);
|
||||
|
||||
m_device->RemoveMappedTexture(this);
|
||||
|
||||
if (m_desc.Pool == D3DPOOL_DEFAULT)
|
||||
m_device->DecrementLosableCounter();
|
||||
}
|
||||
|
||||
|
||||
|
@ -114,6 +118,7 @@ namespace dxvk {
|
|||
|
||||
HRESULT D3D9CommonTexture::NormalizeTextureProperties(
|
||||
D3D9DeviceEx* pDevice,
|
||||
D3DRESOURCETYPE ResourceType,
|
||||
D3D9_COMMON_TEXTURE_DESC* pDesc) {
|
||||
auto* options = pDevice->GetOptions();
|
||||
|
||||
|
@ -127,6 +132,11 @@ namespace dxvk {
|
|||
options->disableA8RT)
|
||||
return D3DERR_INVALIDCALL;
|
||||
|
||||
// Cube textures with depth formats are not supported on any native
|
||||
// driver, and allowing them triggers a broken code path in Gothic 3.
|
||||
if (ResourceType == D3DRTYPE_CUBETEXTURE && mapping.Aspect != VK_IMAGE_ASPECT_COLOR_BIT)
|
||||
return D3DERR_INVALIDCALL;
|
||||
|
||||
// If the mapping is invalid then lets return invalid
|
||||
// Some edge cases:
|
||||
// NULL format does not map to anything, but should succeed
|
||||
|
@ -364,7 +374,7 @@ namespace dxvk {
|
|||
if (!CheckImageSupport(&imageInfo, imageInfo.tiling)) {
|
||||
throw DxvkError(str::format(
|
||||
"D3D9: Cannot create texture:",
|
||||
"\n Type: ", std::hex, ResourceType,
|
||||
"\n Type: 0x", std::hex, ResourceType, std::dec,
|
||||
"\n Format: ", m_desc.Format,
|
||||
"\n Extent: ", m_desc.Width,
|
||||
"x", m_desc.Height,
|
||||
|
@ -372,8 +382,8 @@ namespace dxvk {
|
|||
"\n Samples: ", m_desc.MultiSample,
|
||||
"\n Layers: ", m_desc.ArraySize,
|
||||
"\n Levels: ", m_desc.MipLevels,
|
||||
"\n Usage: ", std::hex, m_desc.Usage,
|
||||
"\n Pool: ", std::hex, m_desc.Pool));
|
||||
"\n Usage: 0x", std::hex, m_desc.Usage, std::dec,
|
||||
"\n Pool: 0x", std::hex, m_desc.Pool, std::dec));
|
||||
}
|
||||
|
||||
return m_device->GetDXVKDevice()->createImage(imageInfo, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
|
||||
|
|
|
@ -179,11 +179,14 @@ namespace dxvk {
|
|||
* Fills in undefined values and validates the texture
|
||||
* parameters. Any error returned by this method should
|
||||
* be forwarded to the application.
|
||||
* \param [in] pDevice D3D9 device
|
||||
* \param [in] ResourceType Resource type
|
||||
* \param [in,out] pDesc Texture description
|
||||
* \returns \c S_OK if the parameters are valid
|
||||
*/
|
||||
static HRESULT NormalizeTextureProperties(
|
||||
D3D9DeviceEx* pDevice,
|
||||
D3DRESOURCETYPE ResourceType,
|
||||
D3D9_COMMON_TEXTURE_DESC* pDesc);
|
||||
|
||||
/**
|
||||
|
@ -307,8 +310,8 @@ namespace dxvk {
|
|||
return util::computeMipLevelExtent(GetExtent(), MipLevel);
|
||||
}
|
||||
|
||||
bool MarkHazardous() {
|
||||
return std::exchange(m_hazardous, true);
|
||||
bool MarkTransitionedToHazardLayout() {
|
||||
return std::exchange(m_transitionedToHazardLayout, true);
|
||||
}
|
||||
|
||||
D3DRESOURCETYPE GetType() {
|
||||
|
@ -340,7 +343,7 @@ namespace dxvk {
|
|||
}
|
||||
|
||||
VkImageLayout DetermineRenderTargetLayout(VkImageLayout hazardLayout) const {
|
||||
if (unlikely(m_hazardous))
|
||||
if (unlikely(m_transitionedToHazardLayout))
|
||||
return hazardLayout;
|
||||
|
||||
return m_image != nullptr &&
|
||||
|
@ -350,18 +353,16 @@ namespace dxvk {
|
|||
}
|
||||
|
||||
VkImageLayout DetermineDepthStencilLayout(bool write, bool hazardous, VkImageLayout hazardLayout) const {
|
||||
VkImageLayout layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
|
||||
|
||||
if (unlikely(hazardous)) {
|
||||
layout = write
|
||||
? hazardLayout
|
||||
: VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL;
|
||||
}
|
||||
if (unlikely(m_transitionedToHazardLayout))
|
||||
return hazardLayout;
|
||||
|
||||
if (unlikely(m_image->info().tiling != VK_IMAGE_TILING_OPTIMAL))
|
||||
layout = VK_IMAGE_LAYOUT_GENERAL;
|
||||
return VK_IMAGE_LAYOUT_GENERAL;
|
||||
|
||||
return layout;
|
||||
if (unlikely(hazardous && !write))
|
||||
return VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL;
|
||||
|
||||
return VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
|
||||
}
|
||||
|
||||
Rc<DxvkImageView> CreateView(
|
||||
|
@ -512,7 +513,7 @@ namespace dxvk {
|
|||
|
||||
int64_t m_size = 0;
|
||||
|
||||
bool m_hazardous = false;
|
||||
bool m_transitionedToHazardLayout = false;
|
||||
|
||||
D3D9ColorView m_sampleView;
|
||||
|
||||
|
|
|
@ -16,7 +16,11 @@ namespace dxvk {
|
|||
|
||||
|
||||
BOOL D3D9Cursor::ShowCursor(BOOL bShow) {
|
||||
::SetCursor(bShow ? m_hCursor : nullptr);
|
||||
if (likely(m_hCursor != nullptr))
|
||||
::SetCursor(bShow ? m_hCursor : nullptr);
|
||||
else
|
||||
Logger::debug("D3D9Cursor::ShowCursor: Software cursor not implemented.");
|
||||
|
||||
return std::exchange(m_visible, bShow);
|
||||
}
|
||||
|
||||
|
@ -63,4 +67,4 @@ namespace dxvk {
|
|||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -28,12 +28,17 @@
|
|||
|
||||
#include "d3d9_spec_constants.h"
|
||||
#include "d3d9_interop.h"
|
||||
#include "d3d9_on_12.h"
|
||||
|
||||
#include <cstdint>
|
||||
#include <unordered_set>
|
||||
#include "d3d9_bridge.h"
|
||||
|
||||
#include <vector>
|
||||
#include <type_traits>
|
||||
#include <unordered_map>
|
||||
|
||||
#include "../util/util_flush.h"
|
||||
#include "../util/util_lru.h"
|
||||
|
||||
namespace dxvk {
|
||||
|
@ -61,6 +66,8 @@ namespace dxvk {
|
|||
DirtyInputLayout,
|
||||
DirtyViewportScissor,
|
||||
DirtyMultiSampleState,
|
||||
DirtyVertexBuffers,
|
||||
DirtyIndexBuffer,
|
||||
|
||||
DirtyFogState,
|
||||
DirtyFogColor,
|
||||
|
@ -123,8 +130,10 @@ namespace dxvk {
|
|||
constexpr static VkDeviceSize StagingBufferSize = 4ull << 20;
|
||||
|
||||
friend class D3D9SwapChainEx;
|
||||
friend struct D3D9WindowContext;
|
||||
friend class D3D9ConstantBuffer;
|
||||
friend class D3D9UserDefinedAnnotation;
|
||||
friend class DxvkD3D8Bridge;
|
||||
friend D3D9VkInteropDevice;
|
||||
public:
|
||||
|
||||
|
@ -757,6 +766,24 @@ namespace dxvk {
|
|||
HRESULT UnlockBuffer(
|
||||
D3D9CommonBuffer* pResource);
|
||||
|
||||
/**
|
||||
* @brief Uploads data from D3DPOOL_SYSMEM + D3DUSAGE_DYNAMIC buffers and binds the temporary buffers.
|
||||
*
|
||||
* @param FirstVertexIndex The first vertex
|
||||
* @param NumVertices The number of vertices that are accessed. If this is 0, the vertex buffer binding will not be modified.
|
||||
* @param FirstIndex The first index
|
||||
* @param NumIndices The number of indices that will be drawn. If this is 0, the index buffer binding will not be modified.
|
||||
*/
|
||||
void UploadDynamicSysmemBuffers(
|
||||
UINT& FirstVertexIndex,
|
||||
UINT NumVertices,
|
||||
UINT& FirstIndex,
|
||||
UINT NumIndices,
|
||||
INT& BaseVertexIndex,
|
||||
bool* pDynamicVBOs,
|
||||
bool* pDynamicIBO);
|
||||
|
||||
|
||||
void SetupFPU();
|
||||
|
||||
int64_t DetermineInitialTextureMemory();
|
||||
|
@ -766,6 +793,7 @@ namespace dxvk {
|
|||
void SynchronizeCsThread(uint64_t SequenceNumber);
|
||||
|
||||
void Flush();
|
||||
void FlushAndSync9On12();
|
||||
|
||||
void EndFrame();
|
||||
|
||||
|
@ -773,6 +801,9 @@ namespace dxvk {
|
|||
|
||||
void UpdateActiveRTs(uint32_t index);
|
||||
|
||||
template <uint32_t Index>
|
||||
void UpdateAnyColorWrites(bool has);
|
||||
|
||||
void UpdateActiveTextures(uint32_t index, DWORD combinedUsage);
|
||||
|
||||
void UpdateActiveHazardsRT(uint32_t rtMask);
|
||||
|
@ -806,7 +837,7 @@ namespace dxvk {
|
|||
inline bool IsAlphaToCoverageEnabled() {
|
||||
const bool alphaTest = m_state.renderStates[D3DRS_ALPHATESTENABLE] != 0;
|
||||
|
||||
return m_amdATOC || (m_nvATOC && alphaTest);
|
||||
return (m_amdATOC || (m_nvATOC && alphaTest)) && m_flags.test(D3D9DeviceFlag::ValidSampleMask);
|
||||
}
|
||||
|
||||
inline bool IsDepthBiasEnabled() {
|
||||
|
@ -874,6 +905,10 @@ namespace dxvk {
|
|||
|
||||
void MarkTextureBindingDirty(IDirect3DBaseTexture9* texture);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE SetRenderTargetInternal(
|
||||
DWORD RenderTargetIndex,
|
||||
IDirect3DSurface9* pRenderTarget);
|
||||
|
||||
D3D9DrawInfo GenerateDrawInfo(
|
||||
D3DPRIMITIVETYPE PrimitiveType,
|
||||
UINT PrimitiveCount,
|
||||
|
@ -881,7 +916,7 @@ namespace dxvk {
|
|||
|
||||
uint32_t GetInstanceCount() const;
|
||||
|
||||
void PrepareDraw(D3DPRIMITIVETYPE PrimitiveType);
|
||||
void PrepareDraw(D3DPRIMITIVETYPE PrimitiveType, bool UploadVBOs, bool UploadIBOs);
|
||||
|
||||
template <DxsoProgramType ShaderStage>
|
||||
void BindShader(
|
||||
|
@ -915,7 +950,7 @@ namespace dxvk {
|
|||
void SetVertexBoolBitfield(uint32_t idx, uint32_t mask, uint32_t bits);
|
||||
void SetPixelBoolBitfield (uint32_t idx, uint32_t mask, uint32_t bits);
|
||||
|
||||
void FlushImplicit(BOOL StrongHint);
|
||||
void ConsiderFlush(GpuFlushType FlushType);
|
||||
|
||||
bool ChangeReportedMemory(int64_t delta) {
|
||||
if (IsExtended())
|
||||
|
@ -956,41 +991,35 @@ namespace dxvk {
|
|||
void TouchMappedTexture(D3D9CommonTexture* pTexture);
|
||||
void RemoveMappedTexture(D3D9CommonTexture* pTexture);
|
||||
|
||||
bool IsD3D8Compatible() const {
|
||||
return m_isD3D8Compatible;
|
||||
}
|
||||
|
||||
void SetD3D8CompatibilityMode(bool compatMode) {
|
||||
if (compatMode)
|
||||
Logger::info("The D3D9 device is now operating in D3D8 compatibility mode.");
|
||||
|
||||
m_isD3D8Compatible = compatMode;
|
||||
}
|
||||
|
||||
// Device Lost
|
||||
bool IsDeviceLost() const {
|
||||
return m_deviceLostState != D3D9DeviceLostState::Ok;
|
||||
}
|
||||
|
||||
void NotifyFullscreen(HWND window, bool fullscreen) {
|
||||
D3D9DeviceLock lock = LockDevice();
|
||||
void NotifyFullscreen(HWND window, bool fullscreen);
|
||||
void NotifyWindowActivated(HWND window, bool activated);
|
||||
|
||||
if (fullscreen) {
|
||||
if (unlikely(window != m_fullscreenWindow && m_fullscreenWindow != NULL)) {
|
||||
Logger::warn("Multiple fullscreen windows detected.");
|
||||
}
|
||||
m_fullscreenWindow = window;
|
||||
} else {
|
||||
if (unlikely(m_fullscreenWindow != window)) {
|
||||
Logger::warn("Window was not fullscreen in the first place.");
|
||||
} else {
|
||||
m_fullscreenWindow = 0;
|
||||
}
|
||||
}
|
||||
void IncrementLosableCounter() {
|
||||
m_losableResourceCounter++;
|
||||
}
|
||||
|
||||
void NotifyWindowActivated(HWND window, bool activated) {
|
||||
D3D9DeviceLock lock = LockDevice();
|
||||
|
||||
if (likely(!m_d3d9Options.deviceLost || IsExtended()))
|
||||
return;
|
||||
void DecrementLosableCounter() {
|
||||
m_losableResourceCounter--;
|
||||
}
|
||||
|
||||
if (activated && m_deviceLostState == D3D9DeviceLostState::Lost) {
|
||||
Logger::info("Device not reset");
|
||||
m_deviceLostState = D3D9DeviceLostState::NotReset;
|
||||
} else if (!activated && m_deviceLostState != D3D9DeviceLostState::Lost && m_fullscreenWindow == window) {
|
||||
Logger::info("Device lost");
|
||||
m_deviceLostState = D3D9DeviceLostState::Lost;
|
||||
m_fullscreenWindow = NULL;
|
||||
}
|
||||
bool CanOnlySWVP() const {
|
||||
return m_behaviorFlags & D3DCREATE_SOFTWARE_VERTEXPROCESSING;
|
||||
}
|
||||
|
||||
private:
|
||||
|
@ -1000,12 +1029,15 @@ namespace dxvk {
|
|||
return DxvkCsChunkRef(chunk, &m_csChunkPool);
|
||||
}
|
||||
|
||||
template<typename Cmd>
|
||||
template<bool AllowFlush = true, typename Cmd>
|
||||
void EmitCs(Cmd&& command) {
|
||||
if (unlikely(!m_csChunk->push(command))) {
|
||||
EmitCsChunk(std::move(m_csChunk));
|
||||
|
||||
m_csChunk = AllocCsChunk();
|
||||
|
||||
if constexpr (AllowFlush)
|
||||
ConsiderFlush(GpuFlushType::ImplicitWeakHint);
|
||||
|
||||
m_csChunk->push(command);
|
||||
}
|
||||
}
|
||||
|
@ -1019,10 +1051,18 @@ namespace dxvk {
|
|||
}
|
||||
}
|
||||
|
||||
bool CanSWVP() {
|
||||
bool CanSWVP() const {
|
||||
return m_behaviorFlags & (D3DCREATE_MIXED_VERTEXPROCESSING | D3DCREATE_SOFTWARE_VERTEXPROCESSING);
|
||||
}
|
||||
|
||||
// Device Reset detection for D3D9SwapChainEx::Present
|
||||
bool IsDeviceReset() {
|
||||
return std::exchange(m_deviceHasBeenReset, false);
|
||||
}
|
||||
|
||||
template <bool Synchronize9On12>
|
||||
void ExecuteFlush();
|
||||
|
||||
void DetermineConstantLayouts(bool canSWVP);
|
||||
|
||||
D3D9BufferSlice AllocUPBuffer(VkDeviceSize size);
|
||||
|
@ -1047,7 +1087,7 @@ namespace dxvk {
|
|||
}
|
||||
|
||||
inline uint32_t GetUPBufferSize(uint32_t vertexCount, uint32_t stride) {
|
||||
return (vertexCount - 1) * stride + std::max(m_state.vertexDecl->GetSize(), stride);
|
||||
return (vertexCount - 1) * stride + std::max(m_state.vertexDecl->GetSize(0), stride);
|
||||
}
|
||||
|
||||
inline void FillUPVertexBuffer(void* buffer, const void* userData, uint32_t dataSize, uint32_t bufferSize) {
|
||||
|
@ -1205,11 +1245,38 @@ namespace dxvk {
|
|||
|
||||
uint64_t GetCurrentSequenceNumber();
|
||||
|
||||
/**
|
||||
* @brief Get the swapchain that was used the most recently for presenting
|
||||
* Has to be externally synchronized.
|
||||
*
|
||||
* @return D3D9SwapChainEx* Swapchain
|
||||
*/
|
||||
D3D9SwapChainEx* GetMostRecentlyUsedSwapchain() {
|
||||
return m_mostRecentlyUsedSwapchain;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set the swapchain that was used the most recently for presenting
|
||||
* Has to be externally synchronized.
|
||||
*
|
||||
* @param swapchain Swapchain
|
||||
*/
|
||||
void SetMostRecentlyUsedSwapchain(D3D9SwapChainEx* swapchain) {
|
||||
m_mostRecentlyUsedSwapchain = swapchain;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Reset the most recently swapchain back to the implicit one
|
||||
* Has to be externally synchronized.
|
||||
*/
|
||||
void ResetMostRecentlyUsedSwapchain() {
|
||||
m_mostRecentlyUsedSwapchain = m_implicitSwapchain.ptr();
|
||||
}
|
||||
|
||||
Com<D3D9InterfaceEx> m_parent;
|
||||
D3DDEVTYPE m_deviceType;
|
||||
HWND m_window;
|
||||
WORD m_behaviorFlags;
|
||||
D3DPRESENT_PARAMETERS m_presentParams;
|
||||
|
||||
D3D9Adapter* m_adapter;
|
||||
Rc<DxvkDevice> m_dxvkDevice;
|
||||
|
@ -1288,14 +1355,16 @@ namespace dxvk {
|
|||
uint32_t m_dirtySamplerStates = 0;
|
||||
uint32_t m_dirtyTextures = 0;
|
||||
|
||||
uint32_t m_boundRTs = 0;
|
||||
uint32_t m_boundRTs : 4;
|
||||
uint32_t m_anyColorWrites : 4;
|
||||
uint32_t m_activeRTsWhichAreTextures : 4;
|
||||
uint32_t m_alphaSwizzleRTs : 4;
|
||||
uint32_t m_lastHazardsRT : 4;
|
||||
|
||||
uint32_t m_activeRTs = 0;
|
||||
uint32_t m_activeRTTextures = 0;
|
||||
uint32_t m_activeDSTextures = 0;
|
||||
uint32_t m_activeTextureRTs = 0;
|
||||
uint32_t m_activeTextureDSs = 0;
|
||||
uint32_t m_activeHazardsRT = 0;
|
||||
uint32_t m_activeHazardsDS = 0;
|
||||
uint32_t m_alphaSwizzleRTs = 0;
|
||||
uint32_t m_activeTextures = 0;
|
||||
uint32_t m_activeTexturesToUpload = 0;
|
||||
uint32_t m_activeTexturesToGen = 0;
|
||||
|
@ -1310,7 +1379,6 @@ namespace dxvk {
|
|||
uint32_t m_fetch4 = 0;
|
||||
|
||||
uint32_t m_lastHazardsDS = 0;
|
||||
uint32_t m_lastHazardsRT = 0;
|
||||
uint32_t m_lastSamplerTypesFF = 0;
|
||||
|
||||
D3D9SpecializationInfo m_specInfo = D3D9SpecializationInfo();
|
||||
|
@ -1319,14 +1387,17 @@ namespace dxvk {
|
|||
D3D9ShaderMasks m_psShaderMasks = FixedFunctionMask;
|
||||
|
||||
bool m_isSWVP;
|
||||
bool m_amdATOC = false;
|
||||
bool m_nvATOC = false;
|
||||
bool m_ffZTest = false;
|
||||
bool m_isD3D8Compatible = false;
|
||||
bool m_amdATOC = false;
|
||||
bool m_nvATOC = false;
|
||||
bool m_ffZTest = false;
|
||||
|
||||
VkImageLayout m_hazardLayout = VK_IMAGE_LAYOUT_GENERAL;
|
||||
|
||||
bool m_usingGraphicsPipelines = false;
|
||||
bool m_deviceHasBeenReset = false;
|
||||
|
||||
DxvkDepthBiasRepresentation m_depthBiasRepresentation = { VK_DEPTH_BIAS_REPRESENTATION_LEAST_REPRESENTABLE_VALUE_FORMAT_EXT, false };
|
||||
float m_depthBiasScale = 0.0f;
|
||||
|
||||
uint32_t m_robustSSBOAlignment = 1;
|
||||
|
@ -1348,18 +1419,25 @@ namespace dxvk {
|
|||
D3D9ViewportInfo m_viewportInfo;
|
||||
|
||||
DxvkCsChunkPool m_csChunkPool;
|
||||
dxvk::high_resolution_clock::time_point m_lastFlush
|
||||
= dxvk::high_resolution_clock::now();
|
||||
DxvkCsThread m_csThread;
|
||||
DxvkCsChunkRef m_csChunk;
|
||||
uint64_t m_csSeqNum = 0ull;
|
||||
bool m_csIsBusy = false;
|
||||
|
||||
Rc<sync::Fence> m_submissionFence;
|
||||
uint64_t m_submissionId = 0ull;
|
||||
DxvkSubmitStatus m_submitStatus;
|
||||
|
||||
uint64_t m_flushSeqNum = 0ull;
|
||||
GpuFlushTracker m_flushTracker;
|
||||
|
||||
std::atomic<int64_t> m_availableMemory = { 0 };
|
||||
std::atomic<int32_t> m_samplerCount = { 0 };
|
||||
|
||||
D3D9DeviceLostState m_deviceLostState = D3D9DeviceLostState::Ok;
|
||||
HWND m_fullscreenWindow = NULL;
|
||||
std::atomic<uint32_t> m_losableResourceCounter = { 0 };
|
||||
|
||||
D3D9SwapChainEx* m_mostRecentlyUsedSwapchain = nullptr;
|
||||
|
||||
#ifdef D3D9_ALLOW_UNMAPPING
|
||||
lru_list<D3D9CommonTexture*> m_mappedTextures;
|
||||
|
@ -1370,6 +1448,8 @@ namespace dxvk {
|
|||
Direct3DState9 m_state;
|
||||
|
||||
D3D9VkInteropDevice m_d3d9Interop;
|
||||
D3D9On12 m_d3d9On12;
|
||||
DxvkD3D8Bridge m_d3d8Bridge;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -336,7 +336,7 @@ namespace dxvk {
|
|||
}
|
||||
|
||||
|
||||
uint32_t SetupRenderStateBlock(SpirvModule& spvModule, uint32_t count) {
|
||||
uint32_t SetupRenderStateBlock(SpirvModule& spvModule) {
|
||||
uint32_t floatType = spvModule.defFloatType(32);
|
||||
uint32_t uintType = spvModule.defIntType(32, 0);
|
||||
uint32_t vec3Type = spvModule.defVectorType(floatType, 3);
|
||||
|
@ -357,7 +357,7 @@ namespace dxvk {
|
|||
floatType,
|
||||
}};
|
||||
|
||||
uint32_t rsStruct = spvModule.defStructTypeUnique(count, rsMembers.data());
|
||||
uint32_t rsStruct = spvModule.defStructTypeUnique(rsMembers.size(), rsMembers.data());
|
||||
uint32_t rsBlock = spvModule.newVar(
|
||||
spvModule.defPointerType(rsStruct, spv::StorageClassPushConstant),
|
||||
spv::StorageClassPushConstant);
|
||||
|
@ -369,9 +369,6 @@ namespace dxvk {
|
|||
|
||||
uint32_t memberIdx = 0;
|
||||
auto SetMemberName = [&](const char* name, uint32_t offset) {
|
||||
if (memberIdx >= count)
|
||||
return;
|
||||
|
||||
spvModule.setDebugMemberName (rsStruct, memberIdx, name);
|
||||
spvModule.memberDecorateOffset (rsStruct, memberIdx, offset);
|
||||
memberIdx++;
|
||||
|
@ -781,8 +778,6 @@ namespace dxvk {
|
|||
uint32_t m_inputMask = 0u;
|
||||
uint32_t m_outputMask = 0u;
|
||||
uint32_t m_flatShadingMask = 0u;
|
||||
uint32_t m_pushConstOffset = 0u;
|
||||
uint32_t m_pushConstSize = 0u;
|
||||
|
||||
DxsoProgramType m_programType;
|
||||
D3D9FFShaderKeyVS m_vsKey;
|
||||
|
@ -892,8 +887,8 @@ namespace dxvk {
|
|||
info.inputMask = m_inputMask;
|
||||
info.outputMask = m_outputMask;
|
||||
info.flatShadingInputs = m_flatShadingMask;
|
||||
info.pushConstOffset = m_pushConstOffset;
|
||||
info.pushConstSize = m_pushConstSize;
|
||||
info.pushConstStages = VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT;
|
||||
info.pushConstSize = sizeof(D3D9RenderStateInfo);
|
||||
|
||||
return new DxvkShader(info, m_module.compile());
|
||||
}
|
||||
|
@ -1104,7 +1099,7 @@ namespace dxvk {
|
|||
for (uint32_t i = 0; i < caps::TextureStageCount; i++) {
|
||||
uint32_t inputIndex = (m_vsKey.Data.Contents.TexcoordIndices >> (i * 3)) & 0b111;
|
||||
uint32_t inputFlags = (m_vsKey.Data.Contents.TexcoordFlags >> (i * 3)) & 0b111;
|
||||
uint32_t texcoordCount = (m_vsKey.Data.Contents.TexcoordDeclMask >> (i * 3)) & 0b111;
|
||||
uint32_t texcoordCount = (m_vsKey.Data.Contents.TexcoordDeclMask >> (inputIndex * 3)) & 0b111;
|
||||
|
||||
uint32_t transformed;
|
||||
|
||||
|
@ -1384,20 +1379,7 @@ namespace dxvk {
|
|||
|
||||
|
||||
void D3D9FFShaderCompiler::setupRenderStateInfo() {
|
||||
uint32_t count;
|
||||
|
||||
if (m_programType == DxsoProgramType::PixelShader) {
|
||||
m_pushConstOffset = 0;
|
||||
m_pushConstSize = offsetof(D3D9RenderStateInfo, pointSize);
|
||||
count = 5;
|
||||
}
|
||||
else {
|
||||
m_pushConstOffset = offsetof(D3D9RenderStateInfo, pointSize);
|
||||
m_pushConstSize = sizeof(float) * 6;
|
||||
count = 11;
|
||||
}
|
||||
|
||||
m_rsBlock = SetupRenderStateBlock(m_module, count);
|
||||
m_rsBlock = SetupRenderStateBlock(m_module);
|
||||
}
|
||||
|
||||
|
||||
|
@ -1809,8 +1791,9 @@ namespace dxvk {
|
|||
texcoord, texcoord, texcoordCnt, indices.data());
|
||||
|
||||
uint32_t projIdx = m_fsKey.Stages[i].Contents.ProjectedCount;
|
||||
if (projIdx == 0 || projIdx > texcoordCnt)
|
||||
projIdx = texcoordCnt;
|
||||
if (projIdx == 0 || projIdx > texcoordCnt) {
|
||||
projIdx = 4; // Always use w if ProjectedCount is 0.
|
||||
}
|
||||
--projIdx;
|
||||
|
||||
uint32_t projValue = 0;
|
||||
|
|
|
@ -59,7 +59,7 @@ namespace dxvk {
|
|||
void DoFixedFunctionAlphaTest(SpirvModule& spvModule, const D3D9AlphaTestContext& ctx);
|
||||
|
||||
// Returns a render state block
|
||||
uint32_t SetupRenderStateBlock(SpirvModule& spvModule, uint32_t count);
|
||||
uint32_t SetupRenderStateBlock(SpirvModule& spvModule);
|
||||
|
||||
struct D3D9PointSizeInfoVS {
|
||||
uint32_t defaultValue;
|
||||
|
|
|
@ -438,7 +438,11 @@ namespace dxvk {
|
|||
D3D9VkFormatTable::D3D9VkFormatTable(
|
||||
const Rc<DxvkAdapter>& adapter,
|
||||
const D3D9Options& options) {
|
||||
m_dfSupport = options.supportDFFormats;
|
||||
|
||||
const auto& props = adapter->deviceProperties();
|
||||
uint32_t vendorId = options.customVendorId == -1 ? props.vendorID : uint32_t(options.customVendorId);
|
||||
|
||||
m_dfSupport = options.supportDFFormats && DxvkGpuVendor(vendorId) != DxvkGpuVendor::Nvidia;
|
||||
m_x4r4g4b4Support = options.supportX4R4G4B4;
|
||||
m_d32supportFinal = options.supportD32;
|
||||
|
||||
|
|
|
@ -134,7 +134,7 @@ namespace dxvk {
|
|||
info.stage = VK_SHADER_STAGE_COMPUTE_BIT;
|
||||
info.bindingCount = bindings.size();
|
||||
info.bindings = bindings.data();
|
||||
info.pushConstOffset = 0;
|
||||
info.pushConstStages = VK_SHADER_STAGE_COMPUTE_BIT;
|
||||
info.pushConstSize = sizeof(VkExtent2D);
|
||||
|
||||
return new DxvkShader(info, std::move(code));
|
||||
|
|
|
@ -12,9 +12,9 @@
|
|||
|
||||
//for some reason we need to specify __declspec(dllexport) for MinGW
|
||||
#if defined(__WINE__) || !defined(_WIN32)
|
||||
#define DLLEXPORT __attribute__((visibility("default")))
|
||||
#define DLLEXPORT __attribute__((visibility("default")))
|
||||
#else
|
||||
#define DLLEXPORT
|
||||
#define DLLEXPORT
|
||||
#endif
|
||||
|
||||
|
||||
|
@ -60,3 +60,48 @@ typedef struct _D3DDEVINFO_RESOURCEMANAGER
|
|||
#define D3DPOOL_MANAGED_EX D3DPOOL(6)
|
||||
|
||||
using D3D9VertexElements = std::vector<D3DVERTEXELEMENT9>;
|
||||
|
||||
/////////////////////
|
||||
// D3D9On12 content
|
||||
/////////////////////
|
||||
|
||||
#include <d3d12.h>
|
||||
|
||||
#define MAX_D3D9ON12_QUEUES 2
|
||||
|
||||
struct D3D9ON12_ARGS {
|
||||
BOOL Enable9On12;
|
||||
IUnknown* pD3D12Device;
|
||||
IUnknown* ppD3D12Queues[MAX_D3D9ON12_QUEUES];
|
||||
UINT NumQueues;
|
||||
UINT NodeMask;
|
||||
};
|
||||
|
||||
extern "C" {
|
||||
|
||||
// Ordinal 20
|
||||
typedef IDirect3D9* (WINAPI* PFN_Direct3DCreate9On12)(UINT sdk_version, D3D9ON12_ARGS* override_list, UINT override_entry_count);
|
||||
IDirect3D9* WINAPI Direct3DCreate9On12(UINT sdk_version, D3D9ON12_ARGS* override_list, UINT override_entry_count);
|
||||
|
||||
// Ordinal 21
|
||||
typedef HRESULT(WINAPI* PFN_Direct3DCreate9On12Ex)(UINT sdk_version, D3D9ON12_ARGS* override_list, UINT override_entry_count, IDirect3D9Ex** output);
|
||||
HRESULT WINAPI Direct3DCreate9On12Ex(UINT sdk_version, D3D9ON12_ARGS* override_list, UINT override_entry_count, IDirect3D9Ex** output);
|
||||
|
||||
}
|
||||
|
||||
MIDL_INTERFACE("e7fda234-b589-4049-940d-8878977531c8")
|
||||
IDirect3DDevice9On12 : public IUnknown {
|
||||
|
||||
virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void** object) = 0;
|
||||
virtual ULONG STDMETHODCALLTYPE AddRef() = 0;
|
||||
virtual ULONG STDMETHODCALLTYPE Release() = 0;
|
||||
|
||||
virtual HRESULT STDMETHODCALLTYPE GetD3D12Device(REFIID riid, void** object) = 0;
|
||||
virtual HRESULT STDMETHODCALLTYPE UnwrapUnderlyingResource(IDirect3DResource9* resource, ID3D12CommandQueue* command_queue, REFIID riid, void** object) = 0;
|
||||
virtual HRESULT STDMETHODCALLTYPE ReturnUnderlyingResource(IDirect3DResource9* resource, UINT num_sync, UINT64* signal_values, ID3D12Fence** fences) = 0;
|
||||
};
|
||||
|
||||
#ifndef _MSC_VER
|
||||
__CRT_UUID_DECL(IDirect3DDevice9On12, 0xe7fda234,0xb589,0x4049,0x94,0x0d,0x88,0x78,0x97,0x75,0x31,0xc8);
|
||||
#endif
|
||||
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
#include "d3d9_monitor.h"
|
||||
#include "d3d9_caps.h"
|
||||
#include "d3d9_device.h"
|
||||
#include "d3d9_bridge.h"
|
||||
|
||||
#include "../util/util_singleton.h"
|
||||
|
||||
|
@ -13,7 +14,8 @@ namespace dxvk {
|
|||
Singleton<DxvkInstance> g_dxvkInstance;
|
||||
|
||||
D3D9InterfaceEx::D3D9InterfaceEx(bool bExtended)
|
||||
: m_instance ( g_dxvkInstance.acquire() )
|
||||
: m_instance ( g_dxvkInstance.acquire(DxvkInstanceFlag::ClientApiIsD3D9) )
|
||||
, m_d3d8Bridge ( this )
|
||||
, m_extended ( bExtended )
|
||||
, m_d3d9Options ( nullptr, m_instance->config() )
|
||||
, m_d3d9Interop ( this ) {
|
||||
|
@ -86,6 +88,11 @@ namespace dxvk {
|
|||
return S_OK;
|
||||
}
|
||||
|
||||
if (riid == __uuidof(IDxvkD3D8InterfaceBridge)) {
|
||||
*ppvObject = ref(&m_d3d8Bridge);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
if (riid == __uuidof(ID3D9VkInteropInterface)) {
|
||||
*ppvObject = ref(&m_d3d9Interop);
|
||||
return S_OK;
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
#include "d3d9_adapter.h"
|
||||
#include "d3d9_bridge.h"
|
||||
#include "d3d9_interop.h"
|
||||
|
||||
#include "../dxvk/dxvk_instance.h"
|
||||
|
@ -140,6 +141,8 @@ namespace dxvk {
|
|||
|
||||
Rc<DxvkInstance> m_instance;
|
||||
|
||||
DxvkD3D8InterfaceBridge m_d3d8Bridge;
|
||||
|
||||
bool m_extended;
|
||||
|
||||
D3D9Options m_d3d9Options;
|
||||
|
|
|
@ -196,12 +196,42 @@ ID3D9VkInteropDevice : public IUnknown {
|
|||
DWORD MapFlags) = 0;
|
||||
};
|
||||
|
||||
#ifdef _MSC_VER
|
||||
struct __declspec(uuid("3461a81b-ce41-485b-b6b5-fcf08ba6a6bd")) ID3D9VkInteropInterface;
|
||||
struct __declspec(uuid("d56344f5-8d35-46fd-806d-94c351b472c1")) ID3D9VkInteropTexture;
|
||||
struct __declspec(uuid("2eaa4b89-0107-4bdb-87f7-0f541c493ce0")) ID3D9VkInteropDevice;
|
||||
#else
|
||||
/**
|
||||
* \brief D3D9 current output metadata
|
||||
*/
|
||||
struct D3D9VkExtOutputMetadata {
|
||||
float RedPrimary[2];
|
||||
float GreenPrimary[2];
|
||||
float BluePrimary[2];
|
||||
float WhitePoint[2];
|
||||
float MinLuminance;
|
||||
float MaxLuminance;
|
||||
float MaxFullFrameLuminance;
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief D3D9 extended swapchain
|
||||
*/
|
||||
MIDL_INTERFACE("13776e93-4aa9-430a-a4ec-fe9e281181d5")
|
||||
ID3D9VkExtSwapchain : public IUnknown {
|
||||
virtual BOOL STDMETHODCALLTYPE CheckColorSpaceSupport(
|
||||
VkColorSpaceKHR ColorSpace) = 0;
|
||||
|
||||
virtual HRESULT STDMETHODCALLTYPE SetColorSpace(
|
||||
VkColorSpaceKHR ColorSpace) = 0;
|
||||
|
||||
virtual HRESULT STDMETHODCALLTYPE SetHDRMetaData(
|
||||
const VkHdrMetadataEXT *pHDRMetadata) = 0;
|
||||
|
||||
virtual HRESULT STDMETHODCALLTYPE GetCurrentOutputDesc(
|
||||
D3D9VkExtOutputMetadata *pOutputDesc) = 0;
|
||||
|
||||
virtual void STDMETHODCALLTYPE UnlockAdditionalFormats() = 0;
|
||||
};
|
||||
|
||||
#ifndef _MSC_VER
|
||||
__CRT_UUID_DECL(ID3D9VkInteropInterface, 0x3461a81b,0xce41,0x485b,0xb6,0xb5,0xfc,0xf0,0x8b,0xa6,0xa6,0xbd);
|
||||
__CRT_UUID_DECL(ID3D9VkInteropTexture, 0xd56344f5,0x8d35,0x46fd,0x80,0x6d,0x94,0xc3,0x51,0xb4,0x72,0xc1);
|
||||
__CRT_UUID_DECL(ID3D9VkInteropDevice, 0x2eaa4b89,0x0107,0x4bdb,0x87,0xf7,0x0f,0x54,0x1c,0x49,0x3c,0xe0);
|
||||
__CRT_UUID_DECL(ID3D9VkExtSwapchain, 0x13776e93,0x4aa9,0x430a,0xa4,0xec,0xfe,0x9e,0x28,0x11,0x81,0xd5);
|
||||
#endif
|
||||
|
|
|
@ -101,4 +101,14 @@ extern "C" {
|
|||
DLLEXPORT void __stdcall Direct3D9ForceHybridEnumeration(UINT uHybrid) {
|
||||
}
|
||||
|
||||
DLLEXPORT IDirect3D9* __stdcall Direct3DCreate9On12(UINT sdk_version, D3D9ON12_ARGS* override_list, UINT override_entry_count) {
|
||||
dxvk::Logger::warn("Direct3DCreate9On12: 9On12 functionality is unimplemented.");
|
||||
return Direct3DCreate9(sdk_version);
|
||||
}
|
||||
|
||||
DLLEXPORT HRESULT __stdcall Direct3DCreate9On12Ex(UINT sdk_version, D3D9ON12_ARGS* override_list, UINT override_entry_count, IDirect3D9Ex** output) {
|
||||
dxvk::Logger::warn("Direct3DCreate9On12Ex: 9On12 functionality is unimplemented.");
|
||||
return Direct3DCreate9Ex(sdk_version, output);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -81,7 +81,7 @@ namespace dxvk {
|
|||
D3D9Memory (D3D9Memory&& other);
|
||||
D3D9Memory& operator = (D3D9Memory&& other);
|
||||
|
||||
operator bool() const { return m_chunk != nullptr; }
|
||||
explicit operator bool() const { return m_chunk != nullptr; }
|
||||
|
||||
void Map();
|
||||
void Unmap();
|
||||
|
@ -139,7 +139,7 @@ namespace dxvk {
|
|||
D3D9Memory (D3D9Memory&& other);
|
||||
D3D9Memory& operator = (D3D9Memory&& other);
|
||||
|
||||
operator bool() const { return m_ptr != nullptr; }
|
||||
explicit operator bool() const { return m_ptr != nullptr; }
|
||||
|
||||
void Map() {}
|
||||
void Unmap() {}
|
||||
|
|
|
@ -0,0 +1,40 @@
|
|||
#include "d3d9_on_12.h"
|
||||
|
||||
#include "d3d9_device.h"
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
D3D9On12::D3D9On12(D3D9DeviceEx* device)
|
||||
: m_device(device) {
|
||||
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE D3D9On12::QueryInterface(REFIID riid, void** object) {
|
||||
return m_device->QueryInterface(riid, object);
|
||||
}
|
||||
ULONG STDMETHODCALLTYPE D3D9On12::AddRef() {
|
||||
return m_device->AddRef();
|
||||
}
|
||||
ULONG STDMETHODCALLTYPE D3D9On12::Release() {
|
||||
return m_device->Release();
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE D3D9On12::GetD3D12Device(REFIID riid, void** object) {
|
||||
InitReturnPtr(object);
|
||||
|
||||
Logger::err("D3D9On12::GetD3D12Device: Stub");
|
||||
return E_NOINTERFACE;
|
||||
}
|
||||
HRESULT STDMETHODCALLTYPE D3D9On12::UnwrapUnderlyingResource(IDirect3DResource9* resource, ID3D12CommandQueue* command_queue, REFIID riid, void** object) {
|
||||
Logger::err("D3D9On12::GetD3D12Device: UnwrapUnderlyingResource: Stub");
|
||||
return E_NOINTERFACE;
|
||||
}
|
||||
HRESULT STDMETHODCALLTYPE D3D9On12::ReturnUnderlyingResource(IDirect3DResource9* resource, UINT num_sync, UINT64* signal_values, ID3D12Fence** fences) {
|
||||
if (num_sync)
|
||||
Logger::err("D3D9On12::GetD3D12Device: ReturnUnderlyingResource: Stub");
|
||||
|
||||
m_device->FlushAndSync9On12();
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
#pragma once
|
||||
|
||||
#include "d3d9_include.h"
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
class D3D9DeviceEx;
|
||||
|
||||
class D3D9On12 final : public IDirect3DDevice9On12 {
|
||||
|
||||
public:
|
||||
|
||||
D3D9On12(D3D9DeviceEx* device);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void** object);
|
||||
ULONG STDMETHODCALLTYPE AddRef();
|
||||
ULONG STDMETHODCALLTYPE Release();
|
||||
|
||||
HRESULT STDMETHODCALLTYPE GetD3D12Device(REFIID riid, void** object);
|
||||
HRESULT STDMETHODCALLTYPE UnwrapUnderlyingResource(IDirect3DResource9* resource, ID3D12CommandQueue* command_queue, REFIID riid, void** object);
|
||||
HRESULT STDMETHODCALLTYPE ReturnUnderlyingResource(IDirect3DResource9* resource, UINT num_sync, UINT64* signal_values, ID3D12Fence** fences);
|
||||
|
||||
private:
|
||||
|
||||
D3D9DeviceEx* m_device;
|
||||
|
||||
};
|
||||
|
||||
}
|
|
@ -1,3 +1,5 @@
|
|||
#include "../util/util_math.h"
|
||||
|
||||
#include "d3d9_options.h"
|
||||
|
||||
#include "d3d9_caps.h"
|
||||
|
@ -64,16 +66,20 @@ namespace dxvk {
|
|||
this->forceSwapchainMSAA = config.getOption<int32_t> ("d3d9.forceSwapchainMSAA", -1);
|
||||
this->forceSampleRateShading = config.getOption<bool> ("d3d9.forceSampleRateShading", false);
|
||||
this->forceAspectRatio = config.getOption<std::string> ("d3d9.forceAspectRatio", "");
|
||||
this->allowDiscard = config.getOption<bool> ("d3d9.allowDiscard", true);
|
||||
this->enumerateByDisplays = config.getOption<bool> ("d3d9.enumerateByDisplays", true);
|
||||
this->longMad = config.getOption<bool> ("d3d9.longMad", false);
|
||||
this->tearFree = config.getOption<Tristate> ("d3d9.tearFree", Tristate::Auto);
|
||||
this->apitraceMode = config.getOption<bool> ("d3d9.apitraceMode", false);
|
||||
this->cachedDynamicBuffers = config.getOption<bool> ("d3d9.cachedDynamicBuffers", false);
|
||||
this->deviceLocalConstantBuffers = config.getOption<bool> ("d3d9.deviceLocalConstantBuffers", false);
|
||||
this->allowDirectBufferMapping = config.getOption<bool> ("d3d9.allowDirectBufferMapping", true);
|
||||
this->seamlessCubes = config.getOption<bool> ("d3d9.seamlessCubes", false);
|
||||
this->textureMemory = config.getOption<int32_t> ("d3d9.textureMemory", 100) << 20;
|
||||
this->deviceLost = config.getOption<bool> ("d3d9.deviceLost", false);
|
||||
this->textureMemory = config.getOption<int32_t> ("d3d9.textureMemory", 100) << 20;
|
||||
this->deviceLossOnFocusLoss = config.getOption<bool> ("d3d9.deviceLossOnFocusLoss", false);
|
||||
this->samplerLodBias = config.getOption<float> ("d3d9.samplerLodBias", 0.0f);
|
||||
this->clampNegativeLodBias = config.getOption<bool> ("d3d9.clampNegativeLodBias", false);
|
||||
this->countLosableResources = config.getOption<bool> ("d3d9.countLosableResources", true);
|
||||
|
||||
// Clamp LOD bias so that people don't abuse this in unintended ways
|
||||
this->samplerLodBias = dxvk::fclamp(this->samplerLodBias, -2.0f, 1.0f);
|
||||
|
||||
std::string floatEmulation = Config::toLower(config.getOption<std::string>("d3d9.floatEmulation", "auto"));
|
||||
if (floatEmulation == "strict") {
|
||||
|
@ -84,7 +90,8 @@ namespace dxvk {
|
|||
d3d9FloatEmulation = D3D9FloatEmulation::Enabled;
|
||||
} else {
|
||||
bool hasMulz = adapter != nullptr
|
||||
&& adapter->matchesDriver(VK_DRIVER_ID_MESA_RADV, 0, 0);
|
||||
&& (adapter->matchesDriver(VK_DRIVER_ID_MESA_RADV, 0, 0)
|
||||
|| adapter->matchesDriver(VK_DRIVER_ID_MESA_NVK, 0, 0));
|
||||
d3d9FloatEmulation = hasMulz ? D3D9FloatEmulation::Strict : D3D9FloatEmulation::Enabled;
|
||||
}
|
||||
|
||||
|
|
|
@ -116,9 +116,6 @@ namespace dxvk {
|
|||
/// Forces sample rate shading
|
||||
bool forceSampleRateShading;
|
||||
|
||||
/// Allow D3DLOCK_DISCARD
|
||||
bool allowDiscard;
|
||||
|
||||
/// Enumerate adapters by displays
|
||||
bool enumerateByDisplays;
|
||||
|
||||
|
@ -127,12 +124,8 @@ namespace dxvk {
|
|||
/// don't match entirely to the regular vertex shader in this way.
|
||||
bool longMad;
|
||||
|
||||
/// Tear-free mode if vsync is disabled
|
||||
/// Tearing mode if vsync is enabled
|
||||
Tristate tearFree;
|
||||
|
||||
/// Apitrace mode: Maps all buffers in cached memory.
|
||||
bool apitraceMode;
|
||||
/// Cached dynamic buffers: Maps all buffers in cached memory.
|
||||
bool cachedDynamicBuffers;
|
||||
|
||||
/// Use device local memory for constant buffers.
|
||||
bool deviceLocalConstantBuffers;
|
||||
|
@ -143,6 +136,14 @@ namespace dxvk {
|
|||
/// Don't use non seamless cube maps
|
||||
bool seamlessCubes;
|
||||
|
||||
/// Mipmap LOD bias
|
||||
///
|
||||
/// Enforces the given LOD bias for all samplers.
|
||||
float samplerLodBias;
|
||||
|
||||
/// Clamps negative LOD bias
|
||||
bool clampNegativeLodBias;
|
||||
|
||||
/// How much virtual memory will be used for textures (in MB).
|
||||
int32_t textureMemory;
|
||||
|
||||
|
@ -150,7 +151,10 @@ namespace dxvk {
|
|||
std::string shaderDumpPath;
|
||||
|
||||
/// Enable emulation of device loss when a fullscreen app loses focus
|
||||
bool deviceLost;
|
||||
bool deviceLossOnFocusLoss;
|
||||
|
||||
/// Disable counting losable resources and rejecting calls to Reset() if any are still alive
|
||||
bool countLosableResources;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -41,11 +41,6 @@ namespace dxvk {
|
|||
case D3DQUERYTYPE_TIMESTAMPFREQ:
|
||||
break;
|
||||
|
||||
case D3DQUERYTYPE_VERTEXSTATS:
|
||||
m_query[0] = dxvkDevice->createGpuQuery(
|
||||
VK_QUERY_TYPE_PIPELINE_STATISTICS, 0, 0);
|
||||
break;
|
||||
|
||||
default:
|
||||
throw DxvkError(str::format("D3D9Query: Unsupported query type ", m_queryType));
|
||||
}
|
||||
|
@ -160,7 +155,7 @@ namespace dxvk {
|
|||
// they didn't call end, do some flushy stuff...
|
||||
if (flush && hr == S_FALSE && m_state != D3D9_VK_QUERY_BEGUN) {
|
||||
this->NotifyStall();
|
||||
m_parent->FlushImplicit(FALSE);
|
||||
m_parent->ConsiderFlush(GpuFlushType::ImplicitSynchronization);
|
||||
}
|
||||
|
||||
return hr;
|
||||
|
@ -246,11 +241,6 @@ namespace dxvk {
|
|||
m_dataCache.TimestampFreq = GetTimestampQueryFrequency();
|
||||
break;
|
||||
|
||||
case D3DQUERYTYPE_VERTEXSTATS:
|
||||
m_dataCache.VertexStats.NumRenderedTriangles = queryData[0].statistic.iaPrimitives;
|
||||
m_dataCache.VertexStats.NumExtraClippingTriangles = queryData[0].statistic.clipPrimitives;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -276,7 +266,6 @@ namespace dxvk {
|
|||
void D3D9Query::Begin(DxvkContext* ctx) {
|
||||
switch (m_queryType) {
|
||||
case D3DQUERYTYPE_OCCLUSION:
|
||||
case D3DQUERYTYPE_VERTEXSTATS:
|
||||
ctx->beginQuery(m_query[0]);
|
||||
break;
|
||||
|
||||
|
@ -296,7 +285,6 @@ namespace dxvk {
|
|||
ctx->writeTimestamp(m_query[0]);
|
||||
break;
|
||||
|
||||
case D3DQUERYTYPE_VERTEXSTATS:
|
||||
case D3DQUERYTYPE_OCCLUSION:
|
||||
ctx->endQuery(m_query[0]);
|
||||
break;
|
||||
|
@ -314,7 +302,6 @@ namespace dxvk {
|
|||
|
||||
bool D3D9Query::QueryBeginnable(D3DQUERYTYPE QueryType) {
|
||||
return QueryType == D3DQUERYTYPE_OCCLUSION
|
||||
|| QueryType == D3DQUERYTYPE_VERTEXSTATS
|
||||
|| QueryType == D3DQUERYTYPE_TIMESTAMPDISJOINT;
|
||||
}
|
||||
|
||||
|
@ -338,7 +325,6 @@ namespace dxvk {
|
|||
case D3DQUERYTYPE_TIMESTAMP:
|
||||
case D3DQUERYTYPE_TIMESTAMPDISJOINT:
|
||||
case D3DQUERYTYPE_TIMESTAMPFREQ:
|
||||
case D3DQUERYTYPE_VERTEXSTATS:
|
||||
return D3D_OK;
|
||||
|
||||
default:
|
||||
|
|
|
@ -13,14 +13,14 @@ namespace dxvk {
|
|||
enum D3D9SpecConstantId : uint32_t {
|
||||
SpecSamplerType, // 2 bits for 16 PS samplers | Bits: 32
|
||||
|
||||
SpecSamplerDepthMode, // 1 bit for 20 VS + PS samplers | Bits: 20
|
||||
SpecSamplerDepthMode, // 1 bit for 21 VS + PS samplers | Bits: 21
|
||||
SpecAlphaCompareOp, // Range: 0 -> 7 | Bits: 3
|
||||
SpecPointMode, // Range: 0 -> 3 | Bits: 2
|
||||
SpecVertexFogMode, // Range: 0 -> 3 | Bits: 2
|
||||
SpecPixelFogMode, // Range: 0 -> 3 | Bits: 2
|
||||
SpecFogEnabled, // Range: 0 -> 1 | Bits: 1
|
||||
|
||||
SpecSamplerNull, // 1 bit for 20 samplers | Bits: 20
|
||||
SpecSamplerNull, // 1 bit for 21 samplers | Bits: 21
|
||||
SpecProjectionType, // 1 bit for 6 PS 1.x samplers | Bits: 6
|
||||
SpecAlphaPrecisionBits, // Range: 0 -> 8 or 0xF | Bits: 4
|
||||
|
||||
|
@ -49,16 +49,16 @@ namespace dxvk {
|
|||
static constexpr std::array<BitfieldPosition, SpecConstantCount> Layout{{
|
||||
{ 0, 0, 32 }, // SamplerType
|
||||
|
||||
{ 1, 0, 20 }, // SamplerDepthMode
|
||||
{ 1, 20, 3 }, // AlphaCompareOp
|
||||
{ 1, 23, 2 }, // PointMode
|
||||
{ 1, 25, 2 }, // VertexFogMode
|
||||
{ 1, 27, 2 }, // PixelFogMode
|
||||
{ 1, 29, 1 }, // FogEnabled
|
||||
{ 1, 0, 21 }, // SamplerDepthMode
|
||||
{ 1, 21, 3 }, // AlphaCompareOp
|
||||
{ 1, 24, 2 }, // PointMode
|
||||
{ 1, 26, 2 }, // VertexFogMode
|
||||
{ 1, 28, 2 }, // PixelFogMode
|
||||
{ 1, 30, 1 }, // FogEnabled
|
||||
|
||||
{ 2, 0, 20 }, // SamplerNull
|
||||
{ 2, 20, 6 }, // ProjectionType
|
||||
{ 2, 26, 4 }, // AlphaPrecisionBits
|
||||
{ 2, 0, 21 }, // SamplerNull
|
||||
{ 2, 21, 6 }, // ProjectionType
|
||||
{ 2, 27, 4 }, // AlphaPrecisionBits
|
||||
|
||||
{ 3, 0, 16 }, // VertexShaderBools
|
||||
{ 3, 16, 16 }, // PixelShaderBools
|
||||
|
|
|
@ -195,7 +195,7 @@ namespace dxvk {
|
|||
const T* operator & () const { ensure(); return m_data.get(); }
|
||||
T* operator & () { ensure(); return m_data.get(); }
|
||||
|
||||
operator bool() { return m_data != nullptr; }
|
||||
explicit operator bool() const { return m_data != nullptr; }
|
||||
operator T() { ensure(); return *m_data; }
|
||||
|
||||
void ensure() const { if (!m_data) m_data = std::make_unique<T>(); }
|
||||
|
@ -213,7 +213,7 @@ namespace dxvk {
|
|||
|
||||
T& operator=(const T& x) { m_data = x; return m_data; }
|
||||
|
||||
operator bool() { return true; }
|
||||
explicit operator bool() const { return true; }
|
||||
operator T() { return m_data; }
|
||||
|
||||
const T* operator -> () const { return &m_data; }
|
||||
|
|
|
@ -17,6 +17,10 @@ namespace dxvk {
|
|||
CaptureType(Type);
|
||||
}
|
||||
|
||||
D3D9StateBlock::~D3D9StateBlock() {
|
||||
if (!m_parent->IsD3D8Compatible())
|
||||
m_parent->DecrementLosableCounter();
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE D3D9StateBlock::QueryInterface(
|
||||
REFIID riid,
|
||||
|
@ -572,4 +576,4 @@ namespace dxvk {
|
|||
this->Capture();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -89,6 +89,8 @@ namespace dxvk {
|
|||
|
||||
D3D9StateBlock(D3D9DeviceEx* pDevice, D3D9StateBlockType Type);
|
||||
|
||||
~D3D9StateBlock();
|
||||
|
||||
HRESULT STDMETHODCALLTYPE QueryInterface(
|
||||
REFIID riid,
|
||||
void** ppvObject) final;
|
||||
|
|
|
@ -28,19 +28,21 @@ namespace dxvk {
|
|||
, m_device (pDevice->GetDXVKDevice())
|
||||
, m_context (m_device->createContext(DxvkContextType::Supplementary))
|
||||
, m_frameLatencyCap (pDevice->GetOptions()->maxFrameLatency)
|
||||
, m_frameLatencySignal(new sync::Fence(m_frameId))
|
||||
, m_dialog (pDevice->GetOptions()->enableDialogMode) {
|
||||
, m_dialog (pDevice->GetOptions()->enableDialogMode)
|
||||
, m_swapchainExt (this) {
|
||||
this->NormalizePresentParameters(pPresentParams);
|
||||
m_presentParams = *pPresentParams;
|
||||
m_window = m_presentParams.hDeviceWindow;
|
||||
|
||||
UpdateWindowCtx();
|
||||
|
||||
UpdatePresentRegion(nullptr, nullptr);
|
||||
|
||||
if (m_window) {
|
||||
CreatePresenter();
|
||||
|
||||
if (!pDevice->GetOptions()->deferSurfaceCreation)
|
||||
RecreateSwapChain(false);
|
||||
RecreateSwapChain();
|
||||
}
|
||||
|
||||
if (FAILED(CreateBackBuffers(m_presentParams.BackBufferCount)))
|
||||
|
@ -63,6 +65,16 @@ namespace dxvk {
|
|||
if (this_thread::isInModuleDetachment())
|
||||
return;
|
||||
|
||||
{
|
||||
// Locking here and in Device::GetFrontBufferData
|
||||
// ensures that other threads don't accidentally access a stale pointer.
|
||||
D3D9DeviceLock lock = m_parent->LockDevice();
|
||||
|
||||
if (m_parent->GetMostRecentlyUsedSwapchain() == this) {
|
||||
m_parent->ResetMostRecentlyUsedSwapchain();
|
||||
}
|
||||
}
|
||||
|
||||
DestroyBackBuffers();
|
||||
|
||||
ResetWindowProc(m_window);
|
||||
|
@ -70,6 +82,8 @@ namespace dxvk {
|
|||
|
||||
m_device->waitForSubmission(&m_presentStatus);
|
||||
m_device->waitForIdle();
|
||||
|
||||
m_parent->DecrementLosableCounter();
|
||||
}
|
||||
|
||||
|
||||
|
@ -86,6 +100,11 @@ namespace dxvk {
|
|||
return S_OK;
|
||||
}
|
||||
|
||||
if (riid == __uuidof(ID3D9VkExtSwapchain)) {
|
||||
*ppvObject = ref(&m_swapchainExt);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
if (logQueryInterfaceError(__uuidof(IDirect3DSwapChain9), riid)) {
|
||||
Logger::warn("D3D9SwapChainEx::QueryInterface: Unknown interface query");
|
||||
Logger::warn(str::format(riid));
|
||||
|
@ -103,6 +122,8 @@ namespace dxvk {
|
|||
DWORD dwFlags) {
|
||||
D3D9DeviceLock lock = m_parent->LockDevice();
|
||||
|
||||
m_parent->SetMostRecentlyUsedSwapchain(this);
|
||||
|
||||
if (unlikely(m_parent->IsDeviceLost()))
|
||||
return D3DERR_DEVICELOST;
|
||||
|
||||
|
@ -129,33 +150,32 @@ namespace dxvk {
|
|||
if (options->presentInterval >= 0)
|
||||
presentInterval = options->presentInterval;
|
||||
|
||||
bool vsync = presentInterval != 0;
|
||||
|
||||
HWND window = m_presentParams.hDeviceWindow;
|
||||
m_window = m_presentParams.hDeviceWindow;
|
||||
if (hDestWindowOverride != nullptr)
|
||||
window = hDestWindowOverride;
|
||||
m_window = hDestWindowOverride;
|
||||
|
||||
UpdateWindowCtx();
|
||||
|
||||
bool recreate = false;
|
||||
recreate |= m_presenter == nullptr;
|
||||
recreate |= window != m_window;
|
||||
recreate |= m_wctx->presenter == nullptr;
|
||||
recreate |= m_dialog != m_lastDialog;
|
||||
if (options->deferSurfaceCreation)
|
||||
recreate |= m_parent->IsDeviceReset();
|
||||
|
||||
m_window = window;
|
||||
if (m_wctx->presenter != nullptr) {
|
||||
m_dirty |= m_wctx->presenter->setSyncInterval(presentInterval) != VK_SUCCESS;
|
||||
m_dirty |= !m_wctx->presenter->hasSwapChain();
|
||||
}
|
||||
|
||||
m_dirty |= vsync != m_vsync;
|
||||
m_dirty |= UpdatePresentRegion(pSourceRect, pDestRect);
|
||||
m_dirty |= recreate;
|
||||
m_dirty |= m_presenter != nullptr &&
|
||||
!m_presenter->hasSwapChain();
|
||||
|
||||
m_vsync = vsync;
|
||||
|
||||
m_lastDialog = m_dialog;
|
||||
|
||||
#ifdef _WIN32
|
||||
const bool useGDIFallback = m_partialCopy && !HasFrontBuffer();
|
||||
if (useGDIFallback)
|
||||
return PresentImageGDI(window);
|
||||
return PresentImageGDI(m_window);
|
||||
#endif
|
||||
|
||||
try {
|
||||
|
@ -163,12 +183,12 @@ namespace dxvk {
|
|||
CreatePresenter();
|
||||
|
||||
if (std::exchange(m_dirty, false))
|
||||
RecreateSwapChain(vsync);
|
||||
RecreateSwapChain();
|
||||
|
||||
// We aren't going to device loss simply because
|
||||
// 99% of D3D9 games don't handle this properly and
|
||||
// just end up crashing (like with alt-tab loss)
|
||||
if (!m_presenter->hasSwapChain())
|
||||
if (!m_wctx->presenter->hasSwapChain())
|
||||
return D3D_OK;
|
||||
|
||||
PresentImage(presentInterval);
|
||||
|
@ -176,7 +196,7 @@ namespace dxvk {
|
|||
} catch (const DxvkError& e) {
|
||||
Logger::err(e.message());
|
||||
#ifdef _WIN32
|
||||
return PresentImageGDI(window);
|
||||
return PresentImageGDI(m_window);
|
||||
#else
|
||||
return D3DERR_DEVICEREMOVED;
|
||||
#endif
|
||||
|
@ -374,6 +394,20 @@ namespace dxvk {
|
|||
blitInfo.srcOffsets[0] = VkOffset3D{ 0, 0, 0 };
|
||||
blitInfo.srcOffsets[1] = VkOffset3D{ int32_t(srcExtent.width), int32_t(srcExtent.height), 1 };
|
||||
|
||||
#ifdef _WIN32
|
||||
if (m_presentParams.Windowed) {
|
||||
// In windowed mode, GetFrontBufferData takes a screenshot of the entire screen.
|
||||
// So place the copy of the front buffer at the position of the window.
|
||||
POINT point = { 0, 0 };
|
||||
if (ClientToScreen(m_window, &point) != 0) {
|
||||
blitInfo.dstOffsets[0].x = point.x;
|
||||
blitInfo.dstOffsets[0].y = point.y;
|
||||
blitInfo.dstOffsets[1].x += point.x;
|
||||
blitInfo.dstOffsets[1].y += point.y;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
m_parent->EmitCs([
|
||||
cDstImage = blittedSrc,
|
||||
cDstMap = dstTexInfo->GetMapping().Swizzle,
|
||||
|
@ -432,6 +466,13 @@ namespace dxvk {
|
|||
return D3DERR_INVALIDCALL;
|
||||
}
|
||||
|
||||
if (m_backBuffers.empty()) {
|
||||
// The backbuffers were destroyed and not recreated.
|
||||
// This can happen when a call to Reset fails.
|
||||
*ppBackBuffer = nullptr;
|
||||
return D3D_OK;
|
||||
}
|
||||
|
||||
*ppBackBuffer = ref(m_backBuffers[iBackBuffer].ptr());
|
||||
return D3D_OK;
|
||||
}
|
||||
|
@ -671,8 +712,10 @@ namespace dxvk {
|
|||
if (hWindow == nullptr)
|
||||
hWindow = m_parent->GetWindow();
|
||||
|
||||
if (m_presentParams.hDeviceWindow == hWindow) {
|
||||
m_presenter = nullptr;
|
||||
if (m_presenters.count(hWindow)) {
|
||||
if (m_wctx == &m_presenters[hWindow])
|
||||
m_wctx = nullptr;
|
||||
m_presenters.erase(hWindow);
|
||||
|
||||
m_device->waitForSubmission(&m_presentStatus);
|
||||
m_device->waitForIdle();
|
||||
|
@ -741,25 +784,27 @@ namespace dxvk {
|
|||
Rc<DxvkImage> swapImage = m_backBuffers[0]->GetCommonTexture()->GetImage();
|
||||
Rc<DxvkImageView> swapImageView = m_backBuffers[0]->GetImageView(false);
|
||||
|
||||
// Bump our frame id.
|
||||
++m_frameId;
|
||||
|
||||
for (uint32_t i = 0; i < SyncInterval || i < 1; i++) {
|
||||
SynchronizePresent();
|
||||
|
||||
// Presentation semaphores and WSI swap chain image
|
||||
vk::PresenterInfo info = m_presenter->info();
|
||||
vk::PresenterSync sync;
|
||||
PresenterInfo info = m_wctx->presenter->info();
|
||||
PresenterSync sync;
|
||||
|
||||
uint32_t imageIndex = 0;
|
||||
|
||||
VkResult status = m_presenter->acquireNextImage(sync, imageIndex);
|
||||
VkResult status = m_wctx->presenter->acquireNextImage(sync, imageIndex);
|
||||
|
||||
while (status != VK_SUCCESS && status != VK_SUBOPTIMAL_KHR) {
|
||||
RecreateSwapChain(m_vsync);
|
||||
RecreateSwapChain();
|
||||
|
||||
info = m_presenter->info();
|
||||
status = m_presenter->acquireNextImage(sync, imageIndex);
|
||||
info = m_wctx->presenter->info();
|
||||
status = m_wctx->presenter->acquireNextImage(sync, imageIndex);
|
||||
}
|
||||
|
||||
if (m_hdrMetadata && m_dirtyHdrMetadata) {
|
||||
m_wctx->presenter->setHdrMetadata(*m_hdrMetadata);
|
||||
m_dirtyHdrMetadata = false;
|
||||
}
|
||||
|
||||
m_context->beginRecording(
|
||||
|
@ -774,15 +819,12 @@ namespace dxvk {
|
|||
{ uint32_t(m_dstRect.right - m_dstRect.left), uint32_t(m_dstRect.bottom - m_dstRect.top) } };
|
||||
|
||||
m_blitter->presentImage(m_context.ptr(),
|
||||
m_imageViews.at(imageIndex), dstRect,
|
||||
m_wctx->imageViews.at(imageIndex), dstRect,
|
||||
swapImageView, srcRect);
|
||||
|
||||
if (m_hud != nullptr)
|
||||
m_hud->render(m_context, info.format, info.imageExtent);
|
||||
|
||||
if (i + 1 >= SyncInterval)
|
||||
m_context->signal(m_frameLatencySignal, m_frameId);
|
||||
|
||||
SubmitPresent(sync, i);
|
||||
}
|
||||
|
||||
|
@ -797,24 +839,33 @@ namespace dxvk {
|
|||
}
|
||||
|
||||
|
||||
void D3D9SwapChainEx::SubmitPresent(const vk::PresenterSync& Sync, uint32_t FrameId) {
|
||||
void D3D9SwapChainEx::SubmitPresent(const PresenterSync& Sync, uint32_t Repeat) {
|
||||
// Bump frame ID
|
||||
if (!Repeat)
|
||||
m_wctx->frameId += 1;
|
||||
|
||||
// Present from CS thread so that we don't
|
||||
// have to synchronize with it first.
|
||||
m_presentStatus.result = VK_NOT_READY;
|
||||
|
||||
m_parent->EmitCs([this,
|
||||
cFrameId = FrameId,
|
||||
cRepeat = Repeat,
|
||||
cSync = Sync,
|
||||
cHud = m_hud,
|
||||
cPresentMode = m_wctx->presenter->info().presentMode,
|
||||
cFrameId = m_wctx->frameId,
|
||||
cCommandList = m_context->endRecording()
|
||||
] (DxvkContext* ctx) {
|
||||
cCommandList->setWsiSemaphores(cSync);
|
||||
m_device->submitCommandList(cCommandList, nullptr);
|
||||
|
||||
if (cHud != nullptr && !cFrameId)
|
||||
if (cHud != nullptr && !cRepeat)
|
||||
cHud->update();
|
||||
|
||||
m_device->presentImage(m_presenter, &m_presentStatus);
|
||||
uint64_t frameId = cRepeat ? 0 : cFrameId;
|
||||
|
||||
m_device->presentImage(m_wctx->presenter,
|
||||
cPresentMode, frameId, &m_presentStatus);
|
||||
});
|
||||
|
||||
m_parent->FlushCsChunk();
|
||||
|
@ -826,34 +877,33 @@ namespace dxvk {
|
|||
VkResult status = m_device->waitForSubmission(&m_presentStatus);
|
||||
|
||||
if (status != VK_SUCCESS)
|
||||
RecreateSwapChain(m_vsync);
|
||||
RecreateSwapChain();
|
||||
}
|
||||
|
||||
void D3D9SwapChainEx::RecreateSwapChain(BOOL Vsync) {
|
||||
void D3D9SwapChainEx::RecreateSwapChain() {
|
||||
// Ensure that we can safely destroy the swap chain
|
||||
m_device->waitForSubmission(&m_presentStatus);
|
||||
m_device->waitForIdle();
|
||||
|
||||
m_presentStatus.result = VK_SUCCESS;
|
||||
|
||||
vk::PresenterDesc presenterDesc;
|
||||
PresenterDesc presenterDesc;
|
||||
presenterDesc.imageExtent = GetPresentExtent();
|
||||
presenterDesc.imageCount = PickImageCount(m_presentParams.BackBufferCount + 1);
|
||||
presenterDesc.numFormats = PickFormats(EnumerateFormat(m_presentParams.BackBufferFormat), presenterDesc.formats);
|
||||
presenterDesc.numPresentModes = PickPresentModes(Vsync, presenterDesc.presentModes);
|
||||
presenterDesc.fullScreenExclusive = PickFullscreenMode();
|
||||
|
||||
VkResult vr = m_presenter->recreateSwapChain(presenterDesc);
|
||||
VkResult vr = m_wctx->presenter->recreateSwapChain(presenterDesc);
|
||||
|
||||
if (vr == VK_ERROR_SURFACE_LOST_KHR) {
|
||||
vr = m_presenter->recreateSurface([this] (VkSurfaceKHR* surface) {
|
||||
vr = m_wctx->presenter->recreateSurface([this] (VkSurfaceKHR* surface) {
|
||||
return CreateSurface(surface);
|
||||
});
|
||||
|
||||
if (vr)
|
||||
throw DxvkError(str::format("D3D9SwapChainEx: Failed to recreate surface: ", vr));
|
||||
|
||||
vr = m_presenter->recreateSwapChain(presenterDesc);
|
||||
vr = m_wctx->presenter->recreateSwapChain(presenterDesc);
|
||||
}
|
||||
|
||||
if (vr)
|
||||
|
@ -870,27 +920,14 @@ namespace dxvk {
|
|||
|
||||
m_presentStatus.result = VK_SUCCESS;
|
||||
|
||||
DxvkDeviceQueue graphicsQueue = m_device->queues().graphics;
|
||||
|
||||
vk::PresenterDevice presenterDevice;
|
||||
presenterDevice.queueFamily = graphicsQueue.queueFamily;
|
||||
presenterDevice.queue = graphicsQueue.queueHandle;
|
||||
presenterDevice.adapter = m_device->adapter()->handle();
|
||||
|
||||
vk::PresenterDesc presenterDesc;
|
||||
PresenterDesc presenterDesc;
|
||||
presenterDesc.imageExtent = GetPresentExtent();
|
||||
presenterDesc.imageCount = PickImageCount(m_presentParams.BackBufferCount + 1);
|
||||
presenterDesc.numFormats = PickFormats(EnumerateFormat(m_presentParams.BackBufferFormat), presenterDesc.formats);
|
||||
presenterDesc.numPresentModes = PickPresentModes(false, presenterDesc.presentModes);
|
||||
presenterDesc.fullScreenExclusive = PickFullscreenMode();
|
||||
|
||||
m_presenter = new vk::Presenter(
|
||||
m_device->adapter()->vki(),
|
||||
m_device->vkd(),
|
||||
presenterDevice,
|
||||
presenterDesc);
|
||||
|
||||
m_presenter->setFrameRateLimit(m_parent->GetOptions()->maxFrameRate);
|
||||
m_wctx->presenter = new Presenter(m_device, m_wctx->frameLatencySignal, presenterDesc);
|
||||
m_wctx->presenter->setFrameRateLimit(m_parent->GetOptions()->maxFrameRate);
|
||||
}
|
||||
|
||||
|
||||
|
@ -905,10 +942,10 @@ namespace dxvk {
|
|||
|
||||
|
||||
void D3D9SwapChainEx::CreateRenderTargetViews() {
|
||||
vk::PresenterInfo info = m_presenter->info();
|
||||
PresenterInfo info = m_wctx->presenter->info();
|
||||
|
||||
m_imageViews.clear();
|
||||
m_imageViews.resize(info.imageCount);
|
||||
m_wctx->imageViews.clear();
|
||||
m_wctx->imageViews.resize(info.imageCount);
|
||||
|
||||
DxvkImageCreateInfo imageInfo;
|
||||
imageInfo.type = VK_IMAGE_TYPE_2D;
|
||||
|
@ -936,13 +973,13 @@ namespace dxvk {
|
|||
viewInfo.numLayers = 1;
|
||||
|
||||
for (uint32_t i = 0; i < info.imageCount; i++) {
|
||||
VkImage imageHandle = m_presenter->getImage(i).image;
|
||||
VkImage imageHandle = m_wctx->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_wctx->imageViews[i] = new DxvkImageView(
|
||||
m_device->vkd(), image, viewInfo);
|
||||
}
|
||||
}
|
||||
|
@ -956,6 +993,20 @@ namespace dxvk {
|
|||
}
|
||||
|
||||
|
||||
void D3D9SwapChainEx::UpdateWindowCtx() {
|
||||
if (!m_presenters.count(m_window)) {
|
||||
auto res = m_presenters.emplace(
|
||||
std::piecewise_construct,
|
||||
std::forward_as_tuple(m_window),
|
||||
std::forward_as_tuple());
|
||||
|
||||
auto& wctx = res.first->second;
|
||||
wctx.frameLatencySignal = new sync::Fence(wctx.frameId);
|
||||
}
|
||||
m_wctx = &m_presenters[m_window];
|
||||
}
|
||||
|
||||
|
||||
HRESULT D3D9SwapChainEx::CreateBackBuffers(uint32_t NumBackBuffers) {
|
||||
// Explicitly destroy current swap image before
|
||||
// creating a new one to free up resources
|
||||
|
@ -988,6 +1039,7 @@ namespace dxvk {
|
|||
D3D9Surface* surface;
|
||||
try {
|
||||
surface = new D3D9Surface(m_parent, &desc, this, nullptr);
|
||||
m_parent->IncrementLosableCounter();
|
||||
} catch (const DxvkError& e) {
|
||||
DestroyBackBuffers();
|
||||
Logger::err(e.message());
|
||||
|
@ -1057,9 +1109,13 @@ namespace dxvk {
|
|||
|
||||
void D3D9SwapChainEx::SyncFrameLatency() {
|
||||
// Wait for the sync event so that we respect the maximum frame latency
|
||||
m_frameLatencySignal->wait(m_frameId - GetActualFrameLatency());
|
||||
m_wctx->frameLatencySignal->wait(m_wctx->frameId - GetActualFrameLatency());
|
||||
}
|
||||
|
||||
void D3D9SwapChainEx::SetApiName(const char* name) {
|
||||
m_apiName = name;
|
||||
CreateHud();
|
||||
}
|
||||
|
||||
uint32_t D3D9SwapChainEx::GetActualFrameLatency() {
|
||||
uint32_t maxFrameLatency = m_parent->GetFrameLatency();
|
||||
|
@ -1086,46 +1142,36 @@ namespace dxvk {
|
|||
case D3D9Format::X8R8G8B8:
|
||||
case D3D9Format::A8B8G8R8:
|
||||
case D3D9Format::X8B8G8R8: {
|
||||
pDstFormats[n++] = { VK_FORMAT_R8G8B8A8_UNORM, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR };
|
||||
pDstFormats[n++] = { VK_FORMAT_B8G8R8A8_UNORM, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR };
|
||||
pDstFormats[n++] = { VK_FORMAT_R8G8B8A8_UNORM, m_colorspace };
|
||||
pDstFormats[n++] = { VK_FORMAT_B8G8R8A8_UNORM, m_colorspace };
|
||||
} break;
|
||||
|
||||
case D3D9Format::A2R10G10B10:
|
||||
case D3D9Format::A2B10G10R10: {
|
||||
pDstFormats[n++] = { VK_FORMAT_A2B10G10R10_UNORM_PACK32, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR };
|
||||
pDstFormats[n++] = { VK_FORMAT_A2R10G10B10_UNORM_PACK32, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR };
|
||||
pDstFormats[n++] = { VK_FORMAT_A2B10G10R10_UNORM_PACK32, m_colorspace };
|
||||
pDstFormats[n++] = { VK_FORMAT_A2R10G10B10_UNORM_PACK32, m_colorspace };
|
||||
} break;
|
||||
|
||||
case D3D9Format::X1R5G5B5:
|
||||
case D3D9Format::A1R5G5B5: {
|
||||
pDstFormats[n++] = { VK_FORMAT_B5G5R5A1_UNORM_PACK16, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR };
|
||||
pDstFormats[n++] = { VK_FORMAT_R5G5B5A1_UNORM_PACK16, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR };
|
||||
pDstFormats[n++] = { VK_FORMAT_A1R5G5B5_UNORM_PACK16, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR };
|
||||
pDstFormats[n++] = { VK_FORMAT_B5G5R5A1_UNORM_PACK16, m_colorspace };
|
||||
pDstFormats[n++] = { VK_FORMAT_R5G5B5A1_UNORM_PACK16, m_colorspace };
|
||||
pDstFormats[n++] = { VK_FORMAT_A1R5G5B5_UNORM_PACK16, m_colorspace };
|
||||
} break;
|
||||
|
||||
case D3D9Format::R5G6B5: {
|
||||
pDstFormats[n++] = { VK_FORMAT_B5G6R5_UNORM_PACK16, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR };
|
||||
pDstFormats[n++] = { VK_FORMAT_R5G6B5_UNORM_PACK16, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR };
|
||||
pDstFormats[n++] = { VK_FORMAT_B5G6R5_UNORM_PACK16, m_colorspace };
|
||||
pDstFormats[n++] = { VK_FORMAT_R5G6B5_UNORM_PACK16, m_colorspace };
|
||||
} break;
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
|
||||
uint32_t D3D9SwapChainEx::PickPresentModes(
|
||||
BOOL Vsync,
|
||||
VkPresentModeKHR* pDstModes) {
|
||||
uint32_t n = 0;
|
||||
|
||||
if (Vsync) {
|
||||
if (m_parent->GetOptions()->tearFree == Tristate::False)
|
||||
pDstModes[n++] = VK_PRESENT_MODE_FIFO_RELAXED_KHR;
|
||||
pDstModes[n++] = VK_PRESENT_MODE_FIFO_KHR;
|
||||
} else {
|
||||
if (m_parent->GetOptions()->tearFree != Tristate::True)
|
||||
pDstModes[n++] = VK_PRESENT_MODE_IMMEDIATE_KHR;
|
||||
pDstModes[n++] = VK_PRESENT_MODE_MAILBOX_KHR;
|
||||
case D3D9Format::A16B16G16R16F: {
|
||||
if (m_unlockAdditionalFormats) {
|
||||
pDstFormats[n++] = { VK_FORMAT_R16G16B16A16_SFLOAT, m_colorspace };
|
||||
} else {
|
||||
Logger::warn(str::format("D3D9SwapChainEx: Unexpected format: ", Format));
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return n;
|
||||
|
@ -1278,8 +1324,9 @@ namespace dxvk {
|
|||
|| dstRect.bottom - dstRect.top != LONG(height);
|
||||
|
||||
bool recreate =
|
||||
m_swapchainExtent.width != width
|
||||
|| m_swapchainExtent.height != height;
|
||||
m_wctx->presenter == nullptr
|
||||
|| m_wctx->presenter->info().imageExtent.width != width
|
||||
|| m_wctx->presenter->info().imageExtent.height != height;
|
||||
|
||||
m_swapchainExtent = { width, height };
|
||||
m_dstRect = dstRect;
|
||||
|
@ -1300,7 +1347,98 @@ namespace dxvk {
|
|||
|
||||
|
||||
std::string D3D9SwapChainEx::GetApiName() {
|
||||
return this->GetParent()->IsExtended() ? "D3D9Ex" : "D3D9";
|
||||
if (m_apiName == nullptr) {
|
||||
return this->GetParent()->IsExtended() ? "D3D9Ex" : "D3D9";
|
||||
} else {
|
||||
return m_apiName;
|
||||
}
|
||||
}
|
||||
|
||||
D3D9VkExtSwapchain::D3D9VkExtSwapchain(D3D9SwapChainEx *pSwapChain)
|
||||
: m_swapchain(pSwapChain) {
|
||||
|
||||
}
|
||||
|
||||
ULONG STDMETHODCALLTYPE D3D9VkExtSwapchain::AddRef() {
|
||||
return m_swapchain->AddRef();
|
||||
}
|
||||
|
||||
ULONG STDMETHODCALLTYPE D3D9VkExtSwapchain::Release() {
|
||||
return m_swapchain->Release();
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE D3D9VkExtSwapchain::QueryInterface(
|
||||
REFIID riid,
|
||||
void** ppvObject) {
|
||||
return m_swapchain->QueryInterface(riid, ppvObject);
|
||||
}
|
||||
|
||||
BOOL STDMETHODCALLTYPE D3D9VkExtSwapchain::CheckColorSpaceSupport(
|
||||
VkColorSpaceKHR ColorSpace) {
|
||||
return m_swapchain->m_wctx->presenter->supportsColorSpace(ColorSpace);
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE D3D9VkExtSwapchain::SetColorSpace(
|
||||
VkColorSpaceKHR ColorSpace) {
|
||||
if (!CheckColorSpaceSupport(ColorSpace))
|
||||
return D3DERR_INVALIDCALL;
|
||||
|
||||
m_swapchain->m_dirty |= ColorSpace != m_swapchain->m_colorspace;
|
||||
m_swapchain->m_colorspace = ColorSpace;
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE D3D9VkExtSwapchain::SetHDRMetaData(
|
||||
const VkHdrMetadataEXT *pHDRMetadata) {
|
||||
if (!pHDRMetadata)
|
||||
return D3DERR_INVALIDCALL;
|
||||
|
||||
m_swapchain->m_hdrMetadata = *pHDRMetadata;
|
||||
m_swapchain->m_dirtyHdrMetadata = true;
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE D3D9VkExtSwapchain::GetCurrentOutputDesc(
|
||||
D3D9VkExtOutputMetadata *pOutputDesc) {
|
||||
HMONITOR monitor = m_swapchain->m_monitor;
|
||||
if (!monitor)
|
||||
monitor = wsi::getDefaultMonitor();
|
||||
// ^ this should be the display we are mostly covering someday.
|
||||
|
||||
wsi::WsiEdidData edidData = wsi::getMonitorEdid(monitor);
|
||||
wsi::WsiDisplayMetadata metadata = {};
|
||||
{
|
||||
std::optional<wsi::WsiDisplayMetadata> r_metadata = std::nullopt;
|
||||
if (!edidData.empty())
|
||||
r_metadata = wsi::parseColorimetryInfo(edidData);
|
||||
|
||||
if (r_metadata)
|
||||
metadata = *r_metadata;
|
||||
else
|
||||
Logger::err("D3D9: Failed to parse display metadata + colorimetry info, using blank.");
|
||||
}
|
||||
|
||||
|
||||
NormalizeDisplayMetadata(CheckColorSpaceSupport(VK_COLOR_SPACE_HDR10_ST2084_EXT), metadata);
|
||||
|
||||
pOutputDesc->RedPrimary[0] = metadata.redPrimary[0];
|
||||
pOutputDesc->RedPrimary[1] = metadata.redPrimary[1];
|
||||
pOutputDesc->GreenPrimary[0] = metadata.greenPrimary[0];
|
||||
pOutputDesc->GreenPrimary[1] = metadata.greenPrimary[1];
|
||||
pOutputDesc->BluePrimary[0] = metadata.bluePrimary[0];
|
||||
pOutputDesc->BluePrimary[1] = metadata.bluePrimary[1];
|
||||
pOutputDesc->WhitePoint[0] = metadata.whitePoint[0];
|
||||
pOutputDesc->WhitePoint[1] = metadata.whitePoint[1];
|
||||
pOutputDesc->MinLuminance = metadata.minLuminance;
|
||||
pOutputDesc->MaxLuminance = metadata.maxLuminance;
|
||||
pOutputDesc->MaxFullFrameLuminance = metadata.maxFullFrameLuminance;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
void STDMETHODCALLTYPE D3D9VkExtSwapchain::UnlockAdditionalFormats() {
|
||||
m_swapchain->m_unlockAdditionalFormats = true;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -18,10 +18,51 @@
|
|||
namespace dxvk {
|
||||
|
||||
class D3D9Surface;
|
||||
class D3D9SwapChainEx;
|
||||
|
||||
class D3D9VkExtSwapchain final : public ID3D9VkExtSwapchain {
|
||||
public:
|
||||
D3D9VkExtSwapchain(D3D9SwapChainEx *pSwapChain);
|
||||
|
||||
ULONG STDMETHODCALLTYPE AddRef();
|
||||
|
||||
ULONG STDMETHODCALLTYPE Release();
|
||||
|
||||
HRESULT STDMETHODCALLTYPE QueryInterface(
|
||||
REFIID riid,
|
||||
void** ppvObject);
|
||||
|
||||
BOOL STDMETHODCALLTYPE CheckColorSpaceSupport(
|
||||
VkColorSpaceKHR ColorSpace);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE SetColorSpace(
|
||||
VkColorSpaceKHR ColorSpace);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE SetHDRMetaData(
|
||||
const VkHdrMetadataEXT *pHDRMetadata);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE GetCurrentOutputDesc(
|
||||
D3D9VkExtOutputMetadata *pOutputDesc);
|
||||
|
||||
void STDMETHODCALLTYPE UnlockAdditionalFormats();
|
||||
|
||||
private:
|
||||
D3D9SwapChainEx *m_swapchain;
|
||||
};
|
||||
|
||||
struct D3D9WindowContext {
|
||||
Rc<Presenter> presenter;
|
||||
std::vector<Rc<DxvkImageView>> imageViews;
|
||||
|
||||
uint64_t frameId = D3D9DeviceEx::MaxFrameLatency;
|
||||
Rc<sync::Fence> frameLatencySignal;
|
||||
};
|
||||
|
||||
using D3D9SwapChainExBase = D3D9DeviceChild<IDirect3DSwapChain9Ex>;
|
||||
class D3D9SwapChainEx final : public D3D9SwapChainExBase {
|
||||
static constexpr uint32_t NumControlPoints = 256;
|
||||
|
||||
friend class D3D9VkExtSwapchain;
|
||||
public:
|
||||
|
||||
D3D9SwapChainEx(
|
||||
|
@ -85,6 +126,14 @@ namespace dxvk {
|
|||
|
||||
void SyncFrameLatency();
|
||||
|
||||
bool HasFormatsUnlocked() const { return m_unlockAdditionalFormats; }
|
||||
|
||||
void DestroyBackBuffers();
|
||||
|
||||
void SetApiName(const char* name);
|
||||
|
||||
void UpdateWindowCtx();
|
||||
|
||||
private:
|
||||
|
||||
enum BindingIds : uint32_t {
|
||||
|
@ -99,7 +148,11 @@ namespace dxvk {
|
|||
Rc<DxvkContext> m_context;
|
||||
Rc<DxvkSwapchainBlitter> m_blitter;
|
||||
|
||||
Rc<vk::Presenter> m_presenter;
|
||||
std::unordered_map<
|
||||
HWND,
|
||||
D3D9WindowContext> m_presenters;
|
||||
|
||||
D3D9WindowContext* m_wctx = nullptr;
|
||||
|
||||
Rc<hud::Hud> m_hud;
|
||||
|
||||
|
@ -112,17 +165,10 @@ namespace dxvk {
|
|||
|
||||
DxvkSubmitStatus m_presentStatus;
|
||||
|
||||
std::vector<Rc<DxvkImageView>> m_imageViews;
|
||||
|
||||
|
||||
uint64_t m_frameId = D3D9DeviceEx::MaxFrameLatency;
|
||||
uint32_t m_frameLatencyCap = 0;
|
||||
Rc<sync::Fence> m_frameLatencySignal;
|
||||
uint32_t m_frameLatencyCap = 0;
|
||||
|
||||
bool m_dirty = true;
|
||||
bool m_vsync = true;
|
||||
|
||||
bool m_dialog;
|
||||
bool m_dialog = false;
|
||||
bool m_lastDialog = false;
|
||||
|
||||
HWND m_window = nullptr;
|
||||
|
@ -132,16 +178,25 @@ namespace dxvk {
|
|||
|
||||
double m_displayRefreshRate = 0.0;
|
||||
|
||||
const char* m_apiName = nullptr;
|
||||
|
||||
bool m_warnedAboutGDIFallback = false;
|
||||
|
||||
VkColorSpaceKHR m_colorspace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR;
|
||||
|
||||
std::optional<VkHdrMetadataEXT> m_hdrMetadata;
|
||||
bool m_dirtyHdrMetadata = true;
|
||||
bool m_unlockAdditionalFormats = false;
|
||||
|
||||
D3D9VkExtSwapchain m_swapchainExt;
|
||||
|
||||
void PresentImage(UINT PresentInterval);
|
||||
|
||||
void SubmitPresent(const vk::PresenterSync& Sync, uint32_t FrameId);
|
||||
void SubmitPresent(const PresenterSync& Sync, uint32_t Repeat);
|
||||
|
||||
void SynchronizePresent();
|
||||
|
||||
void RecreateSwapChain(
|
||||
BOOL Vsync);
|
||||
void RecreateSwapChain();
|
||||
|
||||
void CreatePresenter();
|
||||
|
||||
|
@ -149,8 +204,6 @@ namespace dxvk {
|
|||
|
||||
void CreateRenderTargetViews();
|
||||
|
||||
void DestroyBackBuffers();
|
||||
|
||||
HRESULT CreateBackBuffers(
|
||||
uint32_t NumBackBuffers);
|
||||
|
||||
|
@ -166,10 +219,6 @@ namespace dxvk {
|
|||
D3D9Format Format,
|
||||
VkSurfaceFormatKHR* pDstFormats);
|
||||
|
||||
uint32_t PickPresentModes(
|
||||
BOOL Vsync,
|
||||
VkPresentModeKHR* pDstModes);
|
||||
|
||||
uint32_t PickImageCount(
|
||||
UINT Preferred);
|
||||
|
||||
|
|
|
@ -144,7 +144,7 @@ namespace dxvk {
|
|||
uint32_t primitiveId = m_module.opLoad(uint_t, primitiveIdPtr);
|
||||
|
||||
// The size of any given vertex
|
||||
uint32_t vertexSize = m_module.constu32(pDecl->GetSize() / sizeof(uint32_t));
|
||||
uint32_t vertexSize = m_module.constu32(pDecl->GetSize(0) / sizeof(uint32_t));
|
||||
|
||||
//The offset of this vertex from the beginning of the buffer
|
||||
uint32_t thisVertexOffset = m_module.opIMul(uint_t, vertexSize, primitiveId);
|
||||
|
|
|
@ -176,19 +176,19 @@ namespace dxvk {
|
|||
|
||||
void ConvertRect(RECT rect, VkOffset2D& offset, VkExtent2D& extent);
|
||||
|
||||
inline float GetDepthBufferRValue(VkFormat Format, int32_t vendorId) {
|
||||
inline float GetDepthBufferRValue(VkFormat Format, int32_t vendorId, bool exact, bool forceUnorm) {
|
||||
switch (Format) {
|
||||
case VK_FORMAT_D16_UNORM_S8_UINT:
|
||||
case VK_FORMAT_D16_UNORM:
|
||||
return vendorId == 0x10de ? float(1 << 15) : float(1 << 16);
|
||||
return (vendorId == 0x10de && !exact) ? float(1 << 15) : float(1 << 16);
|
||||
|
||||
case VK_FORMAT_D24_UNORM_S8_UINT:
|
||||
return vendorId == 0x10de ? float(1 << 23) : float(1 << 24);
|
||||
return (vendorId == 0x10de && !exact) ? float(1 << 23) : float(1 << 24);
|
||||
|
||||
default:
|
||||
case VK_FORMAT_D32_SFLOAT_S8_UINT:
|
||||
case VK_FORMAT_D32_SFLOAT:
|
||||
return float(1 << 23);
|
||||
return forceUnorm ? float(1 << 24) : float(1 << 23);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -204,38 +204,6 @@ namespace dxvk {
|
|||
|
||||
bool IsDepthFormat(D3D9Format Format);
|
||||
|
||||
inline bool operator == (const D3DVIEWPORT9& a, const D3DVIEWPORT9& b) {
|
||||
return a.X == b.X &&
|
||||
a.Y == b.Y &&
|
||||
a.Width == b.Width &&
|
||||
a.Height == b.Height &&
|
||||
a.MinZ == b.MinZ &&
|
||||
a.MaxZ == b.MaxZ;
|
||||
}
|
||||
|
||||
inline bool operator != (const D3DVIEWPORT9& a, const D3DVIEWPORT9& b) {
|
||||
return !(a == b);
|
||||
}
|
||||
|
||||
inline bool operator == (const RECT& a, const RECT& b) {
|
||||
return a.left == b.left &&
|
||||
a.right == b.right &&
|
||||
a.top == b.top &&
|
||||
a.bottom == b.bottom;
|
||||
}
|
||||
|
||||
inline bool operator != (const RECT& a, const RECT& b) {
|
||||
return !(a == b);
|
||||
}
|
||||
|
||||
inline bool operator == (const POINT& a, const POINT& b) {
|
||||
return a.x == b.x && a.y == b.y;
|
||||
}
|
||||
|
||||
inline bool operator != (const POINT& a, const POINT& b) {
|
||||
return !(a == b);
|
||||
}
|
||||
|
||||
inline bool IsPoolManaged(D3DPOOL Pool) {
|
||||
return Pool == D3DPOOL_MANAGED || Pool == D3DPOOL_MANAGED_EX;
|
||||
}
|
||||
|
@ -295,4 +263,47 @@ namespace dxvk {
|
|||
return D3D9TextureStageStateTypes(Type - 1);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
inline bool operator == (const D3DVIEWPORT9& a, const D3DVIEWPORT9& b) {
|
||||
return a.X == b.X &&
|
||||
a.Y == b.Y &&
|
||||
a.Width == b.Width &&
|
||||
a.Height == b.Height &&
|
||||
a.MinZ == b.MinZ &&
|
||||
a.MaxZ == b.MaxZ;
|
||||
}
|
||||
|
||||
inline bool operator != (const D3DVIEWPORT9& a, const D3DVIEWPORT9& b) {
|
||||
return !(a == b);
|
||||
}
|
||||
|
||||
inline bool operator == (const RECT& a, const RECT& b) {
|
||||
return a.left == b.left &&
|
||||
a.right == b.right &&
|
||||
a.top == b.top &&
|
||||
a.bottom == b.bottom;
|
||||
}
|
||||
|
||||
inline bool operator != (const RECT& a, const RECT& b) {
|
||||
return !(a == b);
|
||||
}
|
||||
|
||||
inline bool operator == (const POINT& a, const POINT& b) {
|
||||
return a.x == b.x && a.y == b.y;
|
||||
}
|
||||
|
||||
inline bool operator != (const POINT& a, const POINT& b) {
|
||||
return !(a == b);
|
||||
}
|
||||
|
||||
inline bool operator == (const D3DDISPLAYMODEEX& a, const D3DDISPLAYMODEEX& b) {
|
||||
return a.Size == b.Size &&
|
||||
a.Width == b.Width &&
|
||||
a.Height == b.Height &&
|
||||
a.RefreshRate == b.RefreshRate &&
|
||||
a.Format == b.Format &&
|
||||
a.ScanLineOrdering == b.ScanLineOrdering;
|
||||
}
|
||||
|
||||
|
|
|
@ -354,8 +354,8 @@ namespace dxvk {
|
|||
|
||||
void D3D9VertexDecl::Classify() {
|
||||
for (const auto& element : m_elements) {
|
||||
if (element.Stream == 0 && element.Type != D3DDECLTYPE_UNUSED)
|
||||
m_size = std::max(m_size, element.Offset + GetDecltypeSize(D3DDECLTYPE(element.Type)));
|
||||
if (element.Type != D3DDECLTYPE_UNUSED)
|
||||
m_sizes[element.Stream] = std::max(m_sizes[element.Stream], element.Offset + GetDecltypeSize(D3DDECLTYPE(element.Type)));
|
||||
|
||||
if (element.Usage == D3DDECLUSAGE_COLOR && element.UsageIndex == 0)
|
||||
m_flags.set(D3D9VertexDeclFlag::HasColor0);
|
||||
|
|
|
@ -50,8 +50,8 @@ namespace dxvk {
|
|||
return m_elements;
|
||||
}
|
||||
|
||||
UINT GetSize() const {
|
||||
return m_size;
|
||||
UINT GetSize(UINT Stream) const {
|
||||
return m_sizes[Stream];
|
||||
}
|
||||
|
||||
bool TestFlag(D3D9VertexDeclFlag flag) const {
|
||||
|
@ -94,8 +94,7 @@ namespace dxvk {
|
|||
|
||||
uint32_t m_texcoordMask = 0;
|
||||
|
||||
// The size of Stream 0. That's all we care about.
|
||||
uint32_t m_size = 0;
|
||||
std::array<uint32_t, caps::MaxStreams> m_sizes = {};
|
||||
|
||||
};
|
||||
|
||||
|
|
|
@ -44,7 +44,9 @@ d3d9_src = [
|
|||
'd3d9_annotation.cpp',
|
||||
'd3d9_mem.cpp',
|
||||
'd3d9_window.cpp',
|
||||
'd3d9_interop.cpp'
|
||||
'd3d9_interop.cpp',
|
||||
'd3d9_on_12.cpp',
|
||||
'd3d9_bridge.cpp'
|
||||
]
|
||||
|
||||
d3d9_ld_args = []
|
||||
|
|
|
@ -87,9 +87,9 @@ namespace dxvk {
|
|||
}
|
||||
|
||||
for (uint32_t i = 0; i < ins.dstCount; i++) {
|
||||
if (ins.dst[0].type == DxbcOperandType::IndexableTemp) {
|
||||
uint32_t index = ins.dst[0].idx[0].offset;
|
||||
m_analysis->xRegMasks[index] |= ins.dst[0].mask;
|
||||
if (ins.dst[i].type == DxbcOperandType::IndexableTemp) {
|
||||
uint32_t index = ins.dst[i].idx[0].offset;
|
||||
m_analysis->xRegMasks[index] |= ins.dst[i].mask;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,7 +23,11 @@ namespace dxvk {
|
|||
entry.systemValue = static_cast<DxbcSystemValue>(reader.readu32());
|
||||
entry.componentType = componentTypes.at(reader.readu32());
|
||||
entry.registerId = reader.readu32();
|
||||
entry.componentMask = bit::extract(reader.readu32(), 0, 3);
|
||||
|
||||
uint32_t mask = reader.readu32();
|
||||
|
||||
entry.componentMask = bit::extract(mask, 0, 3);
|
||||
entry.componentUsed = bit::extract(mask, 8, 11);
|
||||
|
||||
if (hasPrecision)
|
||||
reader.readu32();
|
||||
|
|
|
@ -20,6 +20,7 @@ namespace dxvk {
|
|||
uint32_t semanticIndex;
|
||||
uint32_t registerId;
|
||||
DxbcRegMask componentMask;
|
||||
DxbcRegMask componentUsed;
|
||||
DxbcScalarType componentType;
|
||||
DxbcSystemValue systemValue;
|
||||
uint32_t streamId;
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -512,6 +512,7 @@ namespace dxvk {
|
|||
// Entry point description - we'll need to declare
|
||||
// the function ID and all input/output variables.
|
||||
uint32_t m_entryPointId = 0;
|
||||
bool m_hasRawAccessChains = false;
|
||||
|
||||
////////////////////////////////////////////
|
||||
// Inter-stage shader interface slots. Also
|
||||
|
@ -535,6 +536,8 @@ namespace dxvk {
|
|||
DxbcOpcode m_lastOp = DxbcOpcode::Nop;
|
||||
DxbcOpcode m_currOp = DxbcOpcode::Nop;
|
||||
|
||||
VkPrimitiveTopology m_outputTopology = VK_PRIMITIVE_TOPOLOGY_MAX_ENUM;
|
||||
|
||||
/////////////////////////////////////////////////////
|
||||
// Shader interface and metadata declaration methods
|
||||
void emitDcl(
|
||||
|
@ -942,19 +945,6 @@ namespace dxvk {
|
|||
const DxbcRegister& operand,
|
||||
const DxbcRegister& address);
|
||||
|
||||
///////////////////////////////
|
||||
// Resource load/store methods
|
||||
DxbcRegisterValue emitRawBufferLoad(
|
||||
const DxbcRegister& operand,
|
||||
DxbcRegisterValue elementIndex,
|
||||
DxbcRegMask writeMask,
|
||||
uint32_t& sparseFeedbackId);
|
||||
|
||||
void emitRawBufferStore(
|
||||
const DxbcRegister& operand,
|
||||
DxbcRegisterValue elementIndex,
|
||||
DxbcRegisterValue value);
|
||||
|
||||
//////////////////////////
|
||||
// Resource query methods
|
||||
DxbcRegisterValue emitQueryBufferSize(
|
||||
|
@ -1231,6 +1221,9 @@ namespace dxvk {
|
|||
uint32_t getUavCoherence(
|
||||
uint32_t registerId,
|
||||
DxbcUavFlags flags);
|
||||
|
||||
bool ignoreInputSystemValue(
|
||||
DxbcSystemValue sv) const;
|
||||
|
||||
///////////////////////////
|
||||
// Type definition methods
|
||||
|
|
|
@ -149,6 +149,10 @@ namespace dxvk {
|
|||
: m_mask((x ? 0x1 : 0) | (y ? 0x2 : 0)
|
||||
| (z ? 0x4 : 0) | (w ? 0x8 : 0)) { }
|
||||
|
||||
uint32_t raw() const {
|
||||
return m_mask;
|
||||
}
|
||||
|
||||
bool operator [] (uint32_t id) const {
|
||||
return (m_mask >> id) & 1;
|
||||
}
|
||||
|
@ -196,7 +200,7 @@ namespace dxvk {
|
|||
return out;
|
||||
}
|
||||
|
||||
operator bool () const {
|
||||
explicit operator bool () const {
|
||||
return m_mask != 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -17,9 +17,6 @@ namespace dxvk {
|
|||
|
||||
useDepthClipWorkaround
|
||||
= !devFeatures.extDepthClipEnable.depthClipEnable;
|
||||
useSubgroupOpsForAtomicCounters
|
||||
= (devInfo.vk11.subgroupSupportedStages & VK_SHADER_STAGE_COMPUTE_BIT)
|
||||
&& (devInfo.vk11.subgroupSupportedOperations & VK_SUBGROUP_FEATURE_BALLOT_BIT);
|
||||
|
||||
VkFormatFeatureFlags2 r32Features
|
||||
= device->getFormatFeatures(VK_FORMAT_R32_SFLOAT).optimal
|
||||
|
@ -27,6 +24,7 @@ namespace dxvk {
|
|||
& device->getFormatFeatures(VK_FORMAT_R32_SINT).optimal;
|
||||
|
||||
supportsTypedUavLoadR32 = (r32Features & VK_FORMAT_FEATURE_2_STORAGE_READ_WITHOUT_FORMAT_BIT);
|
||||
supportsRawAccessChains = device->features().nvRawAccessChains.shaderRawAccessChains;
|
||||
|
||||
switch (device->config().useRawSsbo) {
|
||||
case Tristate::Auto: minSsboAlignment = devInfo.core.properties.limits.minStorageBufferOffsetAlignment; break;
|
||||
|
@ -40,6 +38,7 @@ namespace dxvk {
|
|||
disableMsaa = options.disableMsaa;
|
||||
forceSampleRateShading = options.forceSampleRateShading;
|
||||
enableSampleShadingInterlock = device->features().extFragmentShaderInterlock.fragmentShaderSampleInterlock;
|
||||
longMad = options.longMad;
|
||||
|
||||
// Figure out float control flags to match D3D11 rules
|
||||
if (options.floatControls) {
|
||||
|
|
|
@ -27,9 +27,8 @@ namespace dxvk {
|
|||
/// on typed UAV loads are required
|
||||
bool supportsTypedUavLoadR32 = false;
|
||||
|
||||
/// Use subgroup operations to reduce the number of
|
||||
/// atomic operations for append/consume buffers.
|
||||
bool useSubgroupOpsForAtomicCounters = false;
|
||||
/// Determines whether raw access chains are supported
|
||||
bool supportsRawAccessChains = false;
|
||||
|
||||
/// Clear thread-group shared memory to zero
|
||||
bool zeroInitWorkgroupMemory = false;
|
||||
|
@ -55,6 +54,9 @@ namespace dxvk {
|
|||
|
||||
/// Minimum storage buffer alignment
|
||||
VkDeviceSize minSsboAlignment = 0;
|
||||
|
||||
/// Should we make our Mads a FFma or do it the long way with an FMul and an FAdd?
|
||||
bool longMad;
|
||||
};
|
||||
|
||||
}
|
|
@ -130,7 +130,7 @@ namespace dxvk {
|
|||
// We can't really reconstruct the version numbers
|
||||
// returned by Windows drivers from Vulkan data
|
||||
if (SUCCEEDED(hr) && pUMDVersion)
|
||||
pUMDVersion->QuadPart = ~0ull;
|
||||
pUMDVersion->QuadPart = INT64_MAX;
|
||||
|
||||
if (FAILED(hr)) {
|
||||
Logger::err("DXGI: CheckInterfaceSupport: Unsupported interface");
|
||||
|
@ -272,7 +272,8 @@ namespace dxvk {
|
|||
auto deviceProp = m_adapter->deviceProperties();
|
||||
auto memoryProp = m_adapter->memoryProperties();
|
||||
auto vk11 = m_adapter->devicePropertiesExt().vk11;
|
||||
|
||||
auto vk12 = m_adapter->devicePropertiesExt().vk12;
|
||||
|
||||
// Custom Vendor / Device ID
|
||||
if (options->customVendorId >= 0)
|
||||
deviceProp.vendorID = options->customVendorId;
|
||||
|
@ -283,13 +284,36 @@ namespace dxvk {
|
|||
std::string description = options->customDeviceDesc.empty()
|
||||
? std::string(deviceProp.deviceName)
|
||||
: options->customDeviceDesc;
|
||||
|
||||
// XXX nvapi workaround for a lot of Unreal Engine 4 games
|
||||
if (options->customVendorId < 0 && options->customDeviceId < 0
|
||||
&& options->nvapiHack && deviceProp.vendorID == uint16_t(DxvkGpuVendor::Nvidia)) {
|
||||
Logger::info("DXGI: NvAPI workaround enabled, reporting AMD GPU");
|
||||
deviceProp.vendorID = uint16_t(DxvkGpuVendor::Amd);
|
||||
deviceProp.deviceID = 0x67df; /* RX 480 */
|
||||
|
||||
if (options->customVendorId < 0) {
|
||||
uint16_t fallbackVendor = 0xdead;
|
||||
uint16_t fallbackDevice = 0xbeef;
|
||||
|
||||
if (!options->hideAmdGpu) {
|
||||
// AMD RX 6700XT
|
||||
fallbackVendor = uint16_t(DxvkGpuVendor::Amd);
|
||||
fallbackDevice = 0x73df;
|
||||
} else if (!options->hideNvidiaGpu) {
|
||||
// Nvidia RTX 3060
|
||||
fallbackVendor = uint16_t(DxvkGpuVendor::Nvidia);
|
||||
fallbackDevice = 0x2487;
|
||||
}
|
||||
|
||||
bool hideNvidiaGpu = vk12.driverID == VK_DRIVER_ID_NVIDIA_PROPRIETARY
|
||||
? options->hideNvidiaGpu : options->hideNvkGpu;
|
||||
|
||||
bool hideGpu = (deviceProp.vendorID == uint16_t(DxvkGpuVendor::Nvidia) && hideNvidiaGpu)
|
||||
|| (deviceProp.vendorID == uint16_t(DxvkGpuVendor::Amd) && options->hideAmdGpu)
|
||||
|| (deviceProp.vendorID == uint16_t(DxvkGpuVendor::Intel) && options->hideIntelGpu);
|
||||
|
||||
if (hideGpu) {
|
||||
deviceProp.vendorID = fallbackVendor;
|
||||
|
||||
if (options->customDeviceId < 0)
|
||||
deviceProp.deviceID = fallbackDevice;
|
||||
|
||||
Logger::info(str::format("DXGI: Hiding actual GPU, reporting vendor ID 0x", std::hex, deviceProp.vendorID, ", device ID ", deviceProp.deviceID));
|
||||
}
|
||||
}
|
||||
|
||||
// Convert device name
|
||||
|
|
|
@ -11,6 +11,9 @@ namespace dxvk {
|
|||
|
||||
Singleton<DxvkInstance> g_dxvkInstance;
|
||||
|
||||
std::mutex s_globalHDRStateMutex;
|
||||
DXVK_VK_GLOBAL_HDR_STATE s_globalHDRState{};
|
||||
|
||||
DxgiVkFactory::DxgiVkFactory(DxgiFactory* pFactory)
|
||||
: m_factory(pFactory) {
|
||||
|
||||
|
@ -47,10 +50,36 @@ namespace dxvk {
|
|||
}
|
||||
|
||||
|
||||
HRESULT STDMETHODCALLTYPE DxgiVkFactory::GetGlobalHDRState(
|
||||
DXGI_COLOR_SPACE_TYPE *pOutColorSpace,
|
||||
DXGI_HDR_METADATA_HDR10 *pOutMetadata) {
|
||||
std::unique_lock lock(s_globalHDRStateMutex);
|
||||
if (!s_globalHDRState.Serial)
|
||||
return S_FALSE;
|
||||
|
||||
*pOutColorSpace = s_globalHDRState.ColorSpace;
|
||||
*pOutMetadata = s_globalHDRState.Metadata.HDR10;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
HRESULT STDMETHODCALLTYPE DxgiVkFactory::SetGlobalHDRState(
|
||||
DXGI_COLOR_SPACE_TYPE ColorSpace,
|
||||
const DXGI_HDR_METADATA_HDR10 *pMetadata) {
|
||||
std::unique_lock lock(s_globalHDRStateMutex);
|
||||
static uint32_t s_GlobalHDRStateSerial = 0;
|
||||
|
||||
s_globalHDRState.Serial = ++s_GlobalHDRStateSerial;
|
||||
s_globalHDRState.ColorSpace = ColorSpace;
|
||||
s_globalHDRState.Metadata.Type = DXGI_HDR_METADATA_TYPE_HDR10;
|
||||
s_globalHDRState.Metadata.HDR10 = *pMetadata;
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
DxgiFactory::DxgiFactory(UINT Flags)
|
||||
: m_instance (g_dxvkInstance.acquire()),
|
||||
: m_instance (g_dxvkInstance.acquire(0)),
|
||||
m_interop (this),
|
||||
m_options (m_instance->config()),
|
||||
m_monitorInfo (this, m_options),
|
||||
|
@ -127,7 +156,8 @@ namespace dxvk {
|
|||
return S_OK;
|
||||
}
|
||||
|
||||
if (riid == __uuidof(IDXGIVkInteropFactory)) {
|
||||
if (riid == __uuidof(IDXGIVkInteropFactory)
|
||||
|| riid == __uuidof(IDXGIVkInteropFactory1)) {
|
||||
*ppvObject = ref(&m_interop);
|
||||
return S_OK;
|
||||
}
|
||||
|
@ -200,7 +230,7 @@ namespace dxvk {
|
|||
descFs.Windowed = pDesc->Windowed;
|
||||
|
||||
IDXGISwapChain1* swapChain = nullptr;
|
||||
HRESULT hr = CreateSwapChainForHwnd(
|
||||
HRESULT hr = CreateSwapChainForHwndBase(
|
||||
pDevice, pDesc->OutputWindow,
|
||||
&desc, &descFs, nullptr,
|
||||
&swapChain);
|
||||
|
@ -214,6 +244,19 @@ namespace dxvk {
|
|||
IUnknown* pDevice,
|
||||
HWND hWnd,
|
||||
const DXGI_SWAP_CHAIN_DESC1* pDesc,
|
||||
const DXGI_SWAP_CHAIN_FULLSCREEN_DESC* pFullscreenDesc,
|
||||
IDXGIOutput* pRestrictToOutput,
|
||||
IDXGISwapChain1** ppSwapChain) {
|
||||
return CreateSwapChainForHwndBase(
|
||||
pDevice, hWnd,
|
||||
pDesc, pFullscreenDesc, pRestrictToOutput,
|
||||
ppSwapChain);
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE DxgiFactory::CreateSwapChainForHwndBase(
|
||||
IUnknown* pDevice,
|
||||
HWND hWnd,
|
||||
const DXGI_SWAP_CHAIN_DESC1* pDesc,
|
||||
const DXGI_SWAP_CHAIN_FULLSCREEN_DESC* pFullscreenDesc,
|
||||
IDXGIOutput* pRestrictToOutput,
|
||||
IDXGISwapChain1** ppSwapChain) {
|
||||
|
@ -407,7 +450,8 @@ namespace dxvk {
|
|||
if (pWindowHandle == nullptr)
|
||||
return DXGI_ERROR_INVALID_CALL;
|
||||
|
||||
*pWindowHandle = m_associatedWindow;
|
||||
// Wine tests show that this is always null for whatever reason
|
||||
*pWindowHandle = nullptr;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
@ -422,7 +466,6 @@ namespace dxvk {
|
|||
|
||||
HRESULT STDMETHODCALLTYPE DxgiFactory::MakeWindowAssociation(HWND WindowHandle, UINT Flags) {
|
||||
Logger::warn("DXGI: MakeWindowAssociation: Ignoring flags");
|
||||
m_associatedWindow = WindowHandle;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
@ -519,4 +562,9 @@ namespace dxvk {
|
|||
}
|
||||
|
||||
|
||||
DXVK_VK_GLOBAL_HDR_STATE DxgiFactory::GlobalHDRState() {
|
||||
std::unique_lock lock(s_globalHDRStateMutex);
|
||||
return s_globalHDRState;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include <mutex>
|
||||
|
||||
#include "dxgi_adapter.h"
|
||||
#include "dxgi_monitor.h"
|
||||
|
@ -12,7 +13,13 @@ namespace dxvk {
|
|||
|
||||
class DxgiFactory;
|
||||
|
||||
class DxgiVkFactory : public IDXGIVkInteropFactory {
|
||||
struct DXVK_VK_GLOBAL_HDR_STATE {
|
||||
uint32_t Serial;
|
||||
DXGI_COLOR_SPACE_TYPE ColorSpace;
|
||||
DXGI_VK_HDR_METADATA Metadata;
|
||||
};
|
||||
|
||||
class DxgiVkFactory : public IDXGIVkInteropFactory1 {
|
||||
|
||||
public:
|
||||
|
||||
|
@ -30,6 +37,14 @@ namespace dxvk {
|
|||
VkInstance* pInstance,
|
||||
PFN_vkGetInstanceProcAddr* ppfnVkGetInstanceProcAddr);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE GetGlobalHDRState(
|
||||
DXGI_COLOR_SPACE_TYPE *pOutColorSpace,
|
||||
DXGI_HDR_METADATA_HDR10 *pOutMetadata);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE SetGlobalHDRState(
|
||||
DXGI_COLOR_SPACE_TYPE ColorSpace,
|
||||
const DXGI_HDR_METADATA_HDR10 *pMetadata);
|
||||
|
||||
private:
|
||||
|
||||
DxgiFactory* m_factory;
|
||||
|
@ -173,6 +188,8 @@ namespace dxvk {
|
|||
DxgiMonitorInfo* GetMonitorInfo() {
|
||||
return &m_monitorInfo;
|
||||
}
|
||||
|
||||
DXVK_VK_GLOBAL_HDR_STATE GlobalHDRState();
|
||||
|
||||
private:
|
||||
|
||||
|
@ -182,9 +199,15 @@ namespace dxvk {
|
|||
DxgiMonitorInfo m_monitorInfo;
|
||||
UINT m_flags;
|
||||
BOOL m_monitorFallback;
|
||||
|
||||
HWND m_associatedWindow = nullptr;
|
||||
|
||||
|
||||
|
||||
HRESULT STDMETHODCALLTYPE CreateSwapChainForHwndBase(
|
||||
IUnknown* pDevice,
|
||||
HWND hWnd,
|
||||
const DXGI_SWAP_CHAIN_DESC1* pDesc,
|
||||
const DXGI_SWAP_CHAIN_FULLSCREEN_DESC* pFullscreenDesc,
|
||||
IDXGIOutput* pRestrictToOutput,
|
||||
IDXGISwapChain1** ppSwapChain);
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -3,10 +3,8 @@
|
|||
//for some reason we need to specify __declspec(dllexport) for MinGW
|
||||
#if defined(__WINE__) || !defined(_WIN32)
|
||||
#define DLLEXPORT __attribute__((visibility("default")))
|
||||
#elif defined(_MSC_VER)
|
||||
#define DLLEXPORT
|
||||
#else
|
||||
#define DLLEXPORT __declspec(dllexport)
|
||||
#define DLLEXPORT
|
||||
#endif
|
||||
|
||||
#include "../util/com/com_guid.h"
|
||||
|
|
|
@ -44,6 +44,15 @@ struct DXGI_VK_HDR_METADATA {
|
|||
};
|
||||
|
||||
|
||||
/**
|
||||
* \brief Frame statistics
|
||||
*/
|
||||
struct DXGI_VK_FRAME_STATISTICS {
|
||||
UINT64 PresentCount;
|
||||
UINT64 PresentQPCTime;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* \brief Private DXGI surface factory
|
||||
*/
|
||||
|
@ -118,6 +127,16 @@ IDXGIVkSwapChain : public IUnknown {
|
|||
};
|
||||
|
||||
|
||||
MIDL_INTERFACE("785326d4-b77b-4826-ae70-8d08308ee6d1")
|
||||
IDXGIVkSwapChain1 : public IDXGIVkSwapChain {
|
||||
virtual void STDMETHODCALLTYPE GetLastPresentCount(
|
||||
UINT64* pLastPresentCount) = 0;
|
||||
|
||||
virtual void STDMETHODCALLTYPE GetFrameStatistics(
|
||||
DXGI_VK_FRAME_STATISTICS* pFrameStatistics) = 0;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* \brief Private DXGI presenter factory
|
||||
*/
|
||||
|
@ -424,29 +443,33 @@ IDXGIVkInteropFactory : public IUnknown {
|
|||
PFN_vkGetInstanceProcAddr* ppfnVkGetInstanceProcAddr) = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief DXGI factory interface for Vulkan interop
|
||||
*/
|
||||
MIDL_INTERFACE("2a289dbd-2d0a-4a51-89f7-f2adce465cd6")
|
||||
IDXGIVkInteropFactory1 : public IDXGIVkInteropFactory {
|
||||
virtual HRESULT STDMETHODCALLTYPE GetGlobalHDRState(
|
||||
DXGI_COLOR_SPACE_TYPE *pOutColorSpace,
|
||||
DXGI_HDR_METADATA_HDR10 *ppOutMetadata) = 0;
|
||||
|
||||
#ifdef _MSC_VER
|
||||
struct __declspec(uuid("907bf281-ea3c-43b4-a8e4-9f231107b4ff")) IDXGIDXVKAdapter;
|
||||
struct __declspec(uuid("92a5d77b-b6e1-420a-b260-fdd701272827")) IDXGIDXVKDevice;
|
||||
struct __declspec(uuid("c06a236f-5be3-448a-8943-89c611c0c2c1")) IDXGIVkMonitorInfo;
|
||||
struct __declspec(uuid("4c5e1b0d-b0c8-4131-bfd8-9b2476f7f408")) IDXGIVkInteropFactory;
|
||||
struct __declspec(uuid("3a6d8f2c-b0e8-4ab4-b4dc-4fd24891bfa5")) IDXGIVkInteropAdapter;
|
||||
struct __declspec(uuid("e2ef5fa5-dc21-4af7-90c4-f67ef6a09323")) IDXGIVkInteropDevice;
|
||||
struct __declspec(uuid("e2ef5fa5-dc21-4af7-90c4-f67ef6a09324")) IDXGIVkInteropDevice1;
|
||||
struct __declspec(uuid("5546cf8c-77e7-4341-b05d-8d4d5000e77d")) IDXGIVkInteropSurface;
|
||||
struct __declspec(uuid("1e7895a1-1bc3-4f9c-a670-290a4bc9581a")) IDXGIVkSurfaceFactory;
|
||||
struct __declspec(uuid("e4a9059e-b569-46ab-8de7-501bd2bc7f7a")) IDXGIVkSwapChain;
|
||||
struct __declspec(uuid("e7d6c3ca-23a0-4e08-9f2f-ea5231df6633")) IDXGIVkSwapChainFactory;
|
||||
#else
|
||||
virtual HRESULT STDMETHODCALLTYPE SetGlobalHDRState(
|
||||
DXGI_COLOR_SPACE_TYPE ColorSpace,
|
||||
const DXGI_HDR_METADATA_HDR10 *pMetadata) = 0;
|
||||
};
|
||||
|
||||
|
||||
#ifndef _MSC_VER
|
||||
__CRT_UUID_DECL(IDXGIDXVKAdapter, 0x907bf281,0xea3c,0x43b4,0xa8,0xe4,0x9f,0x23,0x11,0x07,0xb4,0xff);
|
||||
__CRT_UUID_DECL(IDXGIDXVKDevice, 0x92a5d77b,0xb6e1,0x420a,0xb2,0x60,0xfd,0xf7,0x01,0x27,0x28,0x27);
|
||||
__CRT_UUID_DECL(IDXGIVkMonitorInfo, 0xc06a236f,0x5be3,0x448a,0x89,0x43,0x89,0xc6,0x11,0xc0,0xc2,0xc1);
|
||||
__CRT_UUID_DECL(IDXGIVkInteropFactory, 0x4c5e1b0d,0xb0c8,0x4131,0xbf,0xd8,0x9b,0x24,0x76,0xf7,0xf4,0x08);
|
||||
__CRT_UUID_DECL(IDXGIVkInteropFactory1, 0x2a289dbd,0x2d0a,0x4a51,0x89,0xf7,0xf2,0xad,0xce,0x46,0x5c,0xd6);
|
||||
__CRT_UUID_DECL(IDXGIVkInteropAdapter, 0x3a6d8f2c,0xb0e8,0x4ab4,0xb4,0xdc,0x4f,0xd2,0x48,0x91,0xbf,0xa5);
|
||||
__CRT_UUID_DECL(IDXGIVkInteropDevice, 0xe2ef5fa5,0xdc21,0x4af7,0x90,0xc4,0xf6,0x7e,0xf6,0xa0,0x93,0x23);
|
||||
__CRT_UUID_DECL(IDXGIVkInteropDevice1, 0xe2ef5fa5,0xdc21,0x4af7,0x90,0xc4,0xf6,0x7e,0xf6,0xa0,0x93,0x24);
|
||||
__CRT_UUID_DECL(IDXGIVkInteropSurface, 0x5546cf8c,0x77e7,0x4341,0xb0,0x5d,0x8d,0x4d,0x50,0x00,0xe7,0x7d);
|
||||
__CRT_UUID_DECL(IDXGIVkSurfaceFactory, 0x1e7895a1,0x1bc3,0x4f9c,0xa6,0x70,0x29,0x0a,0x4b,0xc9,0x58,0x1a);
|
||||
__CRT_UUID_DECL(IDXGIVkSwapChain, 0xe4a9059e,0xb569,0x46ab,0x8d,0xe7,0x50,0x1b,0xd2,0xbc,0x7f,0x7a);
|
||||
__CRT_UUID_DECL(IDXGIVkSwapChain1, 0x785326d4,0xb77b,0x4826,0xae,0x70,0x8d,0x08,0x30,0x8e,0xe6,0xd1);
|
||||
__CRT_UUID_DECL(IDXGIVkSwapChainFactory, 0xe7d6c3ca,0x23a0,0x4e08,0x9f,0x2f,0xea,0x52,0x31,0xdf,0x66,0x33);
|
||||
#endif
|
||||
|
|
|
@ -107,7 +107,11 @@ namespace dxvk {
|
|||
return 32;
|
||||
|
||||
case DXGI_FORMAT_R16G16B16A16_FLOAT:
|
||||
return 64;
|
||||
// Floating point output doesn't really make sense.
|
||||
// This seemingly works on Windows, and based on FindClosestMode etc documentaton,
|
||||
// this seems required to work for any format that scanout it supported for.
|
||||
// Treat as 10-bit -> 32.
|
||||
return 32;
|
||||
|
||||
default:
|
||||
Logger::warn(str::format(
|
||||
|
|
|
@ -26,6 +26,26 @@ namespace dxvk {
|
|||
return id;
|
||||
}
|
||||
|
||||
/* First generation XeSS causes crash on proton for Intel due to missing
|
||||
* Intel interface. Avoid crash by pretending to be non-Intel if the
|
||||
* libxess.dll module is loaded by an application.
|
||||
*/
|
||||
static bool isXessUsed() {
|
||||
#ifdef _WIN32
|
||||
if (GetModuleHandleA("libxess") != nullptr ||
|
||||
GetModuleHandleA("libxess_dx11") != nullptr)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
static bool isNvapiEnabled() {
|
||||
return env::getEnvVar("DXVK_ENABLE_NVAPI") == "1";
|
||||
}
|
||||
|
||||
|
||||
static bool isHDRDisallowed() {
|
||||
#ifdef _WIN32
|
||||
|
@ -53,7 +73,7 @@ namespace dxvk {
|
|||
bool isUE4 = exeName.find("-Win64-Shipping") != std::string::npos;
|
||||
bool hasD3D12 = GetModuleHandleA("d3d12") != nullptr;
|
||||
|
||||
if (isUE4 && !hasD3D12)
|
||||
if (isUE4 && !hasD3D12 && !isNvapiEnabled())
|
||||
return true;
|
||||
#endif
|
||||
return false;
|
||||
|
@ -73,11 +93,28 @@ namespace dxvk {
|
|||
this->maxDeviceMemory = VkDeviceSize(config.getOption<int32_t>("dxgi.maxDeviceMemory", 0)) << 20;
|
||||
this->maxSharedMemory = VkDeviceSize(config.getOption<int32_t>("dxgi.maxSharedMemory", 0)) << 20;
|
||||
|
||||
// Force nvapiHack to be disabled if NvAPI is enabled in environment
|
||||
if (env::getEnvVar("DXVK_ENABLE_NVAPI") == "1")
|
||||
this->nvapiHack = false;
|
||||
else
|
||||
this->nvapiHack = config.getOption<bool>("dxgi.nvapiHack", true);
|
||||
this->syncInterval = config.getOption<int32_t>("dxgi.syncInterval", -1);
|
||||
|
||||
// Expose Nvidia GPUs properly if NvAPI is enabled in environment
|
||||
this->hideNvidiaGpu = !isNvapiEnabled();
|
||||
applyTristate(this->hideNvidiaGpu, config.getOption<Tristate>("dxgi.hideNvidiaGpu", Tristate::Auto));
|
||||
|
||||
// Treat NVK adapters the same as Nvidia cards on the proprietary by
|
||||
// default, but provide an override in case something isn't working.
|
||||
this->hideNvkGpu = this->hideNvidiaGpu;
|
||||
applyTristate(this->hideNvkGpu, config.getOption<Tristate>("dxgi.hideNvkGpu", Tristate::Auto));
|
||||
|
||||
// Expose AMD and Intel GPU by default, unless a config override is active.
|
||||
// Implement as a tristate so that we have the option to introduce similar
|
||||
// logic to Nvidia later, if necessary.
|
||||
this->hideAmdGpu = config.getOption<Tristate>("dxgi.hideAmdGpu", Tristate::Auto) == Tristate::True;
|
||||
this->hideIntelGpu = config.getOption<Tristate>("dxgi.hideIntelGpu", Tristate::Auto) == Tristate::True;
|
||||
|
||||
/* Force vendor ID to non-Intel ID when XeSS is in use */
|
||||
if (isXessUsed()) {
|
||||
Logger::info(str::format("Detected XeSS usage, hiding Intel GPU Vendor"));
|
||||
this->hideIntelGpu = true;
|
||||
}
|
||||
|
||||
this->enableHDR = config.getOption<bool>("dxgi.enableHDR", env::getEnvVar("DXVK_HDR") == "1");
|
||||
if (this->enableHDR && isHDRDisallowed()) {
|
||||
|
|
|
@ -33,11 +33,25 @@ namespace dxvk {
|
|||
/// Emulate UMA
|
||||
bool emulateUMA;
|
||||
|
||||
/// Enables nvapi workaround
|
||||
bool nvapiHack;
|
||||
/// Reports Nvidia GPUs running on the proprietary driver as a different
|
||||
/// vendor (usually AMD). Proton will generally disable this option.
|
||||
bool hideNvidiaGpu;
|
||||
|
||||
/// Reports Nvidia GPUs running on NVK as a different vendor (usually AMD)
|
||||
bool hideNvkGpu;
|
||||
|
||||
/// Reports AMD GPUs as a different vendor (usually Nvidia)
|
||||
bool hideAmdGpu;
|
||||
|
||||
/// Reports Intel GPUs as a different vendor (usually AMD)
|
||||
bool hideIntelGpu;
|
||||
|
||||
/// Enable HDR
|
||||
bool enableHDR;
|
||||
|
||||
/// Sync interval. Overrides the value
|
||||
/// passed to IDXGISwapChain::Present.
|
||||
int32_t syncInterval;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -20,60 +20,6 @@
|
|||
|
||||
namespace dxvk {
|
||||
|
||||
static void NormalizeDisplayMetadata(const DxgiMonitorInfo *pMonitorInfo, wsi::WsiDisplayMetadata& metadata) {
|
||||
// Use some dummy info when we have no hdr static metadata for the
|
||||
// display or we were unable to obtain an EDID.
|
||||
//
|
||||
// These dummy values are the same as what Windows DXGI will output
|
||||
// for panels with broken EDIDs such as LG OLEDs displays which
|
||||
// have an entirely zeroed out luminance section in the hdr static
|
||||
// metadata block.
|
||||
//
|
||||
// (Spec has 0 as 'undefined', which isn't really useful for an app
|
||||
// to tonemap against.)
|
||||
if (metadata.minLuminance == 0.0f)
|
||||
metadata.minLuminance = 0.01f;
|
||||
|
||||
if (metadata.maxLuminance == 0.0f)
|
||||
metadata.maxLuminance = 1499.0f;
|
||||
|
||||
if (metadata.maxFullFrameLuminance == 0.0f)
|
||||
metadata.maxFullFrameLuminance = 799.0f;
|
||||
|
||||
// If we have no RedPrimary/GreenPrimary/BluePrimary/WhitePoint due to
|
||||
// the lack of a monitor exposing the chroma block or the lack of an EDID,
|
||||
// simply just fall back to Rec.709 or P3 values depending on the default
|
||||
// ColorSpace we started in.
|
||||
// (Don't change based on punting, as this should be static for a display.)
|
||||
if (metadata.redPrimary[0] == 0.0f && metadata.redPrimary[1] == 0.0f
|
||||
&& metadata.greenPrimary[0] == 0.0f && metadata.greenPrimary[1] == 0.0f
|
||||
&& metadata.bluePrimary[0] == 0.0f && metadata.bluePrimary[1] == 0.0f
|
||||
&& metadata.whitePoint[0] == 0.0f && metadata.whitePoint[1] == 0.0f) {
|
||||
if (pMonitorInfo->DefaultColorSpace() == DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709) {
|
||||
// sRGB ColorSpace -> Rec.709 Primaries
|
||||
metadata.redPrimary[0] = 0.640f;
|
||||
metadata.redPrimary[1] = 0.330f;
|
||||
metadata.greenPrimary[0] = 0.300f;
|
||||
metadata.greenPrimary[1] = 0.600f;
|
||||
metadata.bluePrimary[0] = 0.150f;
|
||||
metadata.bluePrimary[1] = 0.060f;
|
||||
metadata.whitePoint[0] = 0.3127f;
|
||||
metadata.whitePoint[1] = 0.3290f;
|
||||
} else {
|
||||
// HDR10 ColorSpace -> P3 Primaries
|
||||
metadata.redPrimary[0] = 0.680f;
|
||||
metadata.redPrimary[1] = 0.320f;
|
||||
metadata.greenPrimary[0] = 0.265f;
|
||||
metadata.greenPrimary[1] = 0.690f;
|
||||
metadata.bluePrimary[0] = 0.150f;
|
||||
metadata.bluePrimary[1] = 0.060f;
|
||||
metadata.whitePoint[0] = 0.3127f;
|
||||
metadata.whitePoint[1] = 0.3290f;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
DxgiOutput::DxgiOutput(
|
||||
const Com<DxgiFactory>& factory,
|
||||
const Com<DxgiAdapter>& adapter,
|
||||
|
@ -275,7 +221,7 @@ namespace dxvk {
|
|||
pDesc->AttachedToDesktop = 1;
|
||||
pDesc->Rotation = DXGI_MODE_ROTATION_UNSPECIFIED;
|
||||
pDesc->Monitor = m_monitor;
|
||||
pDesc->BitsPerColor = 8;
|
||||
pDesc->BitsPerColor = 10;
|
||||
// This should only return DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020
|
||||
// (HDR) if the user has the HDR setting enabled in Windows.
|
||||
// Games can still punt into HDR mode by using CheckColorSpaceSupport
|
||||
|
@ -416,31 +362,18 @@ namespace dxvk {
|
|||
if (FAILED(hr))
|
||||
return hr;
|
||||
|
||||
static bool s_errorShown = false;
|
||||
|
||||
if (!std::exchange(s_errorShown, true))
|
||||
Logger::warn("DxgiOutput::GetFrameStatistics: Frame statistics may be inaccurate");
|
||||
|
||||
// Estimate vblank count based on last known display mode. Querying
|
||||
// the display mode on every call would be prohibitively expensive.
|
||||
auto refreshPeriod = computeRefreshPeriod(
|
||||
monitorInfo->LastMode.RefreshRate.Numerator,
|
||||
monitorInfo->LastMode.RefreshRate.Denominator);
|
||||
|
||||
// We don't really have a way to query time since boot
|
||||
auto t1Counter = dxvk::high_resolution_clock::get_counter();
|
||||
|
||||
auto t0 = dxvk::high_resolution_clock::get_time_from_counter(monitorInfo->FrameStats.SyncQPCTime.QuadPart);
|
||||
auto t1 = dxvk::high_resolution_clock::get_time_from_counter(t1Counter);
|
||||
|
||||
pStats->PresentCount = monitorInfo->FrameStats.PresentCount;
|
||||
pStats->PresentRefreshCount = monitorInfo->FrameStats.PresentRefreshCount;
|
||||
pStats->SyncRefreshCount = monitorInfo->FrameStats.SyncRefreshCount + computeRefreshCount(t0, t1, refreshPeriod);
|
||||
pStats->SyncQPCTime.QuadPart = t1Counter;
|
||||
pStats->SyncGPUTime.QuadPart = 0;
|
||||
|
||||
// Need to acquire swap chain and unlock monitor data, since querying
|
||||
// frame statistics from the swap chain will also access monitor data.
|
||||
Com<IDXGISwapChain> swapChain = monitorInfo->pSwapChain;
|
||||
m_monitorInfo->ReleaseMonitorData();
|
||||
return S_OK;
|
||||
|
||||
// This API only works if there is a full-screen swap chain active.
|
||||
if (swapChain == nullptr) {
|
||||
*pStats = DXGI_FRAME_STATISTICS();
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
return swapChain->GetFrameStatistics(pStats);
|
||||
}
|
||||
|
||||
|
||||
|
@ -724,9 +657,19 @@ namespace dxvk {
|
|||
|
||||
// Normalize either the display metadata we got back, or our
|
||||
// blank one to get something sane here.
|
||||
NormalizeDisplayMetadata(m_monitorInfo, m_metadata);
|
||||
NormalizeDisplayMetadata(m_monitorInfo->DefaultColorSpace() != DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709, m_metadata);
|
||||
|
||||
auto refreshPeriod = computeRefreshPeriod(
|
||||
activeWsiMode.refreshRate.numerator,
|
||||
activeWsiMode.refreshRate.denominator);
|
||||
|
||||
monitorData.FrameStats.SyncQPCTime.QuadPart = dxvk::high_resolution_clock::get_counter();
|
||||
monitorData.FrameStats.SyncRefreshCount = computeRefreshCount(
|
||||
dxvk::high_resolution_clock::time_point(),
|
||||
dxvk::high_resolution_clock::get_time_from_counter(monitorData.FrameStats.SyncQPCTime.QuadPart),
|
||||
refreshPeriod);
|
||||
|
||||
monitorData.FrameStats.PresentRefreshCount = monitorData.FrameStats.SyncRefreshCount;
|
||||
monitorData.GammaCurve.Scale = { 1.0f, 1.0f, 1.0f };
|
||||
monitorData.GammaCurve.Offset = { 0.0f, 0.0f, 0.0f };
|
||||
monitorData.LastMode = ConvertDisplayMode(activeWsiMode);
|
||||
|
|
|
@ -16,18 +16,25 @@ namespace dxvk {
|
|||
m_window (hWnd),
|
||||
m_desc (*pDesc),
|
||||
m_descFs (*pFullscreenDesc),
|
||||
m_presentCount(0u),
|
||||
m_presentId (0u),
|
||||
m_presenter (pPresenter),
|
||||
m_monitor (wsi::getWindowMonitor(m_window)) {
|
||||
if (FAILED(m_presenter->GetAdapter(__uuidof(IDXGIAdapter), reinterpret_cast<void**>(&m_adapter))))
|
||||
throw DxvkError("DXGI: Failed to get adapter for present device");
|
||||
|
||||
|
||||
// Query updated interface versions from presenter, this
|
||||
// may fail e.g. with older vkd3d-proton builds.
|
||||
m_presenter->QueryInterface(__uuidof(IDXGIVkSwapChain1), reinterpret_cast<void**>(&m_presenter1));
|
||||
|
||||
// Query monitor info form DXVK's DXGI factory, if available
|
||||
m_factory->QueryInterface(__uuidof(IDXGIVkMonitorInfo), reinterpret_cast<void**>(&m_monitorInfo));
|
||||
|
||||
// Apply initial window mode and fullscreen state
|
||||
if (!m_descFs.Windowed && FAILED(EnterFullscreenMode(nullptr)))
|
||||
throw DxvkError("DXGI: Failed to set initial fullscreen state");
|
||||
|
||||
// Ensure that RGBA16 swap chains are scRGB if supported
|
||||
UpdateColorSpace(m_desc.Format, m_colorSpace);
|
||||
}
|
||||
|
||||
|
||||
|
@ -183,15 +190,24 @@ namespace dxvk {
|
|||
// Populate frame statistics with local present count and current time
|
||||
auto t1Counter = dxvk::high_resolution_clock::get_counter();
|
||||
|
||||
pStats->PresentCount = m_presentCount;
|
||||
DXGI_VK_FRAME_STATISTICS frameStatistics = { };
|
||||
frameStatistics.PresentCount = m_presentId;
|
||||
frameStatistics.PresentQPCTime = t1Counter;
|
||||
|
||||
if (m_presenter1 != nullptr)
|
||||
m_presenter1->GetFrameStatistics(&frameStatistics);
|
||||
|
||||
// Fill in actual DXGI statistics, using monitor data to help compute
|
||||
// vblank counts if possible. This is not fully accurate, especially on
|
||||
// displays with variable refresh rates, but it's the best we can do.
|
||||
DXGI_VK_MONITOR_DATA* monitorData = nullptr;
|
||||
|
||||
pStats->PresentCount = frameStatistics.PresentCount;
|
||||
pStats->PresentRefreshCount = 0;
|
||||
pStats->SyncRefreshCount = 0;
|
||||
pStats->SyncQPCTime.QuadPart = t1Counter;
|
||||
pStats->SyncQPCTime.QuadPart = frameStatistics.PresentQPCTime;
|
||||
pStats->SyncGPUTime.QuadPart = 0;
|
||||
|
||||
// If possible, use the monitor's frame statistics for vblank stats
|
||||
DXGI_VK_MONITOR_DATA* monitorData = nullptr;
|
||||
|
||||
if (SUCCEEDED(AcquireMonitorData(m_monitor, &monitorData))) {
|
||||
auto refreshPeriod = computeRefreshPeriod(
|
||||
monitorData->LastMode.RefreshRate.Numerator,
|
||||
|
@ -199,14 +215,24 @@ namespace dxvk {
|
|||
|
||||
auto t0 = dxvk::high_resolution_clock::get_time_from_counter(monitorData->FrameStats.SyncQPCTime.QuadPart);
|
||||
auto t1 = dxvk::high_resolution_clock::get_time_from_counter(t1Counter);
|
||||
auto t2 = dxvk::high_resolution_clock::get_time_from_counter(frameStatistics.PresentQPCTime);
|
||||
|
||||
pStats->PresentRefreshCount = monitorData->FrameStats.PresentRefreshCount;
|
||||
pStats->SyncRefreshCount = monitorData->FrameStats.SyncRefreshCount + computeRefreshCount(t0, t1, refreshPeriod);
|
||||
pStats->PresentRefreshCount = m_presenter1 != nullptr
|
||||
? monitorData->FrameStats.SyncRefreshCount + computeRefreshCount(t0, t2, refreshPeriod)
|
||||
: monitorData->FrameStats.PresentRefreshCount;
|
||||
pStats->SyncRefreshCount = monitorData->FrameStats.SyncRefreshCount + computeRefreshCount(t0, t1, refreshPeriod);
|
||||
|
||||
ReleaseMonitorData();
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
// Docs say that DISJOINT is returned on the first call and around
|
||||
// mode changes. Just make this swap chain state for now.
|
||||
HRESULT hr = S_OK;
|
||||
|
||||
if (std::exchange(m_frameStatisticsDisjoint, false))
|
||||
hr = DXGI_ERROR_FRAME_STATISTICS_DISJOINT;
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
|
||||
|
@ -258,8 +284,13 @@ namespace dxvk {
|
|||
HRESULT STDMETHODCALLTYPE DxgiSwapChain::GetLastPresentCount(UINT* pLastPresentCount) {
|
||||
if (pLastPresentCount == nullptr)
|
||||
return E_INVALIDARG;
|
||||
|
||||
*pLastPresentCount = m_presentCount;
|
||||
|
||||
UINT64 presentId = m_presentId;
|
||||
|
||||
if (m_presenter1 != nullptr)
|
||||
m_presenter1->GetLastPresentCount(&presentId);
|
||||
|
||||
*pLastPresentCount = UINT(presentId);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
@ -272,52 +303,67 @@ namespace dxvk {
|
|||
|
||||
|
||||
HRESULT STDMETHODCALLTYPE DxgiSwapChain::Present(UINT SyncInterval, UINT Flags) {
|
||||
return Present1(SyncInterval, Flags, nullptr);
|
||||
return PresentBase(SyncInterval, Flags, nullptr);
|
||||
}
|
||||
|
||||
|
||||
|
||||
HRESULT STDMETHODCALLTYPE DxgiSwapChain::Present1(
|
||||
UINT SyncInterval,
|
||||
UINT PresentFlags,
|
||||
const DXGI_PRESENT_PARAMETERS* pPresentParameters) {
|
||||
|
||||
if (!wsi::isWindow(m_window))
|
||||
return S_OK;
|
||||
|
||||
return PresentBase(SyncInterval, PresentFlags, pPresentParameters);
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE DxgiSwapChain::PresentBase(
|
||||
UINT SyncInterval,
|
||||
UINT PresentFlags,
|
||||
const DXGI_PRESENT_PARAMETERS* pPresentParameters) {
|
||||
|
||||
if (SyncInterval > 4)
|
||||
return DXGI_ERROR_INVALID_CALL;
|
||||
|
||||
auto options = m_factory->GetOptions();
|
||||
|
||||
if (options->syncInterval >= 0)
|
||||
SyncInterval = options->syncInterval;
|
||||
|
||||
UpdateGlobalHDRState();
|
||||
|
||||
std::lock_guard<dxvk::recursive_mutex> lockWin(m_lockWindow);
|
||||
std::lock_guard<dxvk::mutex> lockBuf(m_lockBuffer);
|
||||
HRESULT hr = S_OK;
|
||||
|
||||
try {
|
||||
HRESULT hr = m_presenter->Present(SyncInterval, PresentFlags, nullptr);
|
||||
|
||||
if (hr != S_OK || (PresentFlags & DXGI_PRESENT_TEST))
|
||||
return hr;
|
||||
} catch (const DxvkError& err) {
|
||||
Logger::err(err.message());
|
||||
return DXGI_ERROR_DRIVER_INTERNAL_ERROR;
|
||||
if (wsi::isWindow(m_window)) {
|
||||
std::lock_guard<dxvk::mutex> lockBuf(m_lockBuffer);
|
||||
hr = m_presenter->Present(SyncInterval, PresentFlags, nullptr);
|
||||
}
|
||||
|
||||
// Update frame statistics
|
||||
DXGI_VK_MONITOR_DATA* monitorData = nullptr;
|
||||
if (PresentFlags & DXGI_PRESENT_TEST)
|
||||
return hr;
|
||||
|
||||
if (SUCCEEDED(AcquireMonitorData(m_monitor, &monitorData))) {
|
||||
auto refreshPeriod = computeRefreshPeriod(
|
||||
monitorData->LastMode.RefreshRate.Numerator,
|
||||
monitorData->LastMode.RefreshRate.Denominator);
|
||||
if (hr == S_OK) {
|
||||
|
||||
auto t0 = dxvk::high_resolution_clock::get_time_from_counter(monitorData->FrameStats.SyncQPCTime.QuadPart);
|
||||
auto t1 = dxvk::high_resolution_clock::now();
|
||||
m_presentId += 1;
|
||||
|
||||
monitorData->FrameStats.PresentCount += 1;
|
||||
monitorData->FrameStats.PresentRefreshCount = monitorData->FrameStats.SyncRefreshCount + computeRefreshCount(t0, t1, refreshPeriod);
|
||||
ReleaseMonitorData();
|
||||
// Update monitor frame statistics. This is not consistent with swap chain
|
||||
// frame statistics at all, but we want to ensure that all presents become
|
||||
// visible to the IDXGIOutput in case applications rely on that behaviour.
|
||||
DXGI_VK_MONITOR_DATA* monitorData = nullptr;
|
||||
|
||||
if (SUCCEEDED(AcquireMonitorData(m_monitor, &monitorData))) {
|
||||
auto refreshPeriod = computeRefreshPeriod(
|
||||
monitorData->LastMode.RefreshRate.Numerator,
|
||||
monitorData->LastMode.RefreshRate.Denominator);
|
||||
|
||||
auto t0 = dxvk::high_resolution_clock::get_time_from_counter(monitorData->FrameStats.SyncQPCTime.QuadPart);
|
||||
auto t1 = dxvk::high_resolution_clock::now();
|
||||
|
||||
monitorData->FrameStats.PresentCount += 1;
|
||||
monitorData->FrameStats.PresentRefreshCount = monitorData->FrameStats.SyncRefreshCount + computeRefreshCount(t0, t1, refreshPeriod);
|
||||
ReleaseMonitorData();
|
||||
}
|
||||
}
|
||||
|
||||
m_presentCount += 1;
|
||||
return S_OK;
|
||||
return hr;
|
||||
}
|
||||
|
||||
|
||||
|
@ -362,7 +408,13 @@ namespace dxvk {
|
|||
if (Format != DXGI_FORMAT_UNKNOWN)
|
||||
m_desc.Format = Format;
|
||||
|
||||
return m_presenter->ChangeProperties(&m_desc, pCreationNodeMask, ppPresentQueue);
|
||||
HRESULT hr = m_presenter->ChangeProperties(&m_desc, pCreationNodeMask, ppPresentQueue);
|
||||
|
||||
if (FAILED(hr))
|
||||
return hr;
|
||||
|
||||
UpdateColorSpace(m_desc.Format, m_colorSpace);
|
||||
return hr;
|
||||
}
|
||||
|
||||
|
||||
|
@ -536,36 +588,31 @@ namespace dxvk {
|
|||
if (!pColorSpaceSupport)
|
||||
return E_INVALIDARG;
|
||||
|
||||
// Don't expose any color spaces other than standard
|
||||
// sRGB if the enableHDR option is not set.
|
||||
//
|
||||
// If we ever have a use for the non-SRGB non-HDR colorspaces
|
||||
// some day, we may want to revisit this.
|
||||
if (ColorSpace != DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709
|
||||
&& !m_factory->GetOptions()->enableHDR) {
|
||||
*pColorSpaceSupport = 0;
|
||||
return S_OK;
|
||||
}
|
||||
std::lock_guard<dxvk::mutex> lock(m_lockBuffer);
|
||||
|
||||
if (ValidateColorSpaceSupport(m_desc.Format, ColorSpace))
|
||||
*pColorSpaceSupport = DXGI_SWAP_CHAIN_COLOR_SPACE_SUPPORT_FLAG_PRESENT;
|
||||
else
|
||||
*pColorSpaceSupport = 0;
|
||||
|
||||
UINT support = m_presenter->CheckColorSpaceSupport(ColorSpace);
|
||||
*pColorSpaceSupport = support;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
HRESULT STDMETHODCALLTYPE DxgiSwapChain::SetColorSpace1(DXGI_COLOR_SPACE_TYPE ColorSpace) {
|
||||
UINT support = m_presenter->CheckColorSpaceSupport(ColorSpace);
|
||||
std::lock_guard<dxvk::mutex> lock(m_lockBuffer);
|
||||
|
||||
if (!support)
|
||||
if (!ValidateColorSpaceSupport(m_desc.Format, ColorSpace))
|
||||
return E_INVALIDARG;
|
||||
|
||||
std::lock_guard<dxvk::mutex> lock(m_lockBuffer);
|
||||
HRESULT hr = m_presenter->SetColorSpace(ColorSpace);
|
||||
if (SUCCEEDED(hr)) {
|
||||
// If this was a colorspace other than our current one,
|
||||
// punt us into that one on the DXGI output.
|
||||
m_monitorInfo->PuntColorSpace(ColorSpace);
|
||||
}
|
||||
// Write back color space if setting it up succeeded. This way, we preserve
|
||||
// the current color space even if the swap chain temporarily switches to a
|
||||
// back buffer format which does not support it.
|
||||
HRESULT hr = UpdateColorSpace(m_desc.Format, ColorSpace);
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
m_colorSpace = ColorSpace;
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
|
@ -804,9 +851,27 @@ namespace dxvk {
|
|||
HRESULT DxgiSwapChain::AcquireMonitorData(
|
||||
HMONITOR hMonitor,
|
||||
DXGI_VK_MONITOR_DATA** ppData) {
|
||||
return m_monitorInfo != nullptr
|
||||
? m_monitorInfo->AcquireMonitorData(hMonitor, ppData)
|
||||
: E_NOINTERFACE;
|
||||
if (m_monitorInfo == nullptr || !hMonitor)
|
||||
return E_NOINTERFACE;
|
||||
|
||||
HRESULT hr = m_monitorInfo->AcquireMonitorData(hMonitor, ppData);
|
||||
|
||||
if (FAILED(hr) && HasLiveReferences()) {
|
||||
// We may need to initialize a DXGI output to populate monitor data.
|
||||
// If acquiring monitor data has failed previously, do not try again.
|
||||
if (hMonitor == m_monitor && !m_monitorHasOutput)
|
||||
return E_NOINTERFACE;
|
||||
|
||||
Com<IDXGIOutput1> output;
|
||||
|
||||
if (SUCCEEDED(GetOutputFromMonitor(hMonitor, &output)))
|
||||
hr = m_monitorInfo->AcquireMonitorData(hMonitor, ppData);
|
||||
}
|
||||
|
||||
if (hMonitor == m_monitor)
|
||||
m_monitorHasOutput = SUCCEEDED(hr);
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
|
||||
|
@ -815,4 +880,76 @@ namespace dxvk {
|
|||
m_monitorInfo->ReleaseMonitorData();
|
||||
}
|
||||
|
||||
|
||||
void DxgiSwapChain::UpdateGlobalHDRState() {
|
||||
// Update the global HDR state if called from the legacy NVAPI
|
||||
// interfaces, etc.
|
||||
|
||||
auto state = m_factory->GlobalHDRState();
|
||||
if (m_globalHDRStateSerial != state.Serial) {
|
||||
SetColorSpace1(state.ColorSpace);
|
||||
|
||||
switch (state.Metadata.Type) {
|
||||
case DXGI_HDR_METADATA_TYPE_NONE:
|
||||
SetHDRMetaData(DXGI_HDR_METADATA_TYPE_NONE, 0, nullptr);
|
||||
break;
|
||||
case DXGI_HDR_METADATA_TYPE_HDR10:
|
||||
SetHDRMetaData(DXGI_HDR_METADATA_TYPE_HDR10, sizeof(state.Metadata.HDR10), reinterpret_cast<void*>(&state.Metadata.HDR10));
|
||||
break;
|
||||
default:
|
||||
Logger::err(str::format("DXGI: Unsupported HDR metadata type (global): ", state.Metadata.Type));
|
||||
break;
|
||||
}
|
||||
|
||||
m_globalHDRStateSerial = state.Serial;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool DxgiSwapChain::ValidateColorSpaceSupport(
|
||||
DXGI_FORMAT Format,
|
||||
DXGI_COLOR_SPACE_TYPE ColorSpace) {
|
||||
// RGBA16 swap chains are treated as scRGB even on SDR displays,
|
||||
// and regular sRGB is not exposed when this format is used.
|
||||
if (Format == DXGI_FORMAT_R16G16B16A16_FLOAT)
|
||||
return ColorSpace == DXGI_COLOR_SPACE_RGB_FULL_G10_NONE_P709;
|
||||
|
||||
// For everything else, we will always expose plain sRGB
|
||||
if (ColorSpace == DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709)
|
||||
return true;
|
||||
|
||||
// Only expose HDR10 color space if HDR option is enabled
|
||||
if (ColorSpace == DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020)
|
||||
return m_factory->GetOptions()->enableHDR && m_presenter->CheckColorSpaceSupport(ColorSpace);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
HRESULT DxgiSwapChain::UpdateColorSpace(
|
||||
DXGI_FORMAT Format,
|
||||
DXGI_COLOR_SPACE_TYPE ColorSpace) {
|
||||
// Don't do anything if the explicitly sepected color space
|
||||
// is compatible with the back buffer format already
|
||||
if (!ValidateColorSpaceSupport(Format, ColorSpace)) {
|
||||
ColorSpace = Format == DXGI_FORMAT_R16G16B16A16_FLOAT
|
||||
? DXGI_COLOR_SPACE_RGB_FULL_G10_NONE_P709
|
||||
: DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709;
|
||||
}
|
||||
|
||||
// Ensure that we pick a supported color space. This is relevant for
|
||||
// mapping scRGB to sRGB on SDR setups, matching Windows behaviour.
|
||||
if (!m_presenter->CheckColorSpaceSupport(ColorSpace))
|
||||
ColorSpace = DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709;
|
||||
|
||||
HRESULT hr = m_presenter->SetColorSpace(ColorSpace);
|
||||
|
||||
// If this was a colorspace other than our current one,
|
||||
// punt us into that one on the DXGI output.
|
||||
if (SUCCEEDED(hr))
|
||||
m_monitorInfo->PuntColorSpace(ColorSpace);
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -183,12 +183,19 @@ namespace dxvk {
|
|||
HWND m_window;
|
||||
DXGI_SWAP_CHAIN_DESC1 m_desc;
|
||||
DXGI_SWAP_CHAIN_FULLSCREEN_DESC m_descFs;
|
||||
UINT m_presentCount;
|
||||
UINT m_presentId;
|
||||
|
||||
Com<IDXGIVkSwapChain> m_presenter;
|
||||
Com<IDXGIVkSwapChain1> m_presenter1;
|
||||
|
||||
HMONITOR m_monitor;
|
||||
bool m_monitorHasOutput = true;
|
||||
bool m_frameStatisticsDisjoint = true;
|
||||
wsi::DxvkWindowState m_windowState;
|
||||
|
||||
DXGI_COLOR_SPACE_TYPE m_colorSpace = DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709;
|
||||
|
||||
uint32_t m_globalHDRStateSerial = 0;
|
||||
|
||||
HRESULT EnterFullscreenMode(
|
||||
IDXGIOutput1 *pTarget);
|
||||
|
@ -216,6 +223,20 @@ namespace dxvk {
|
|||
|
||||
void ReleaseMonitorData();
|
||||
|
||||
void UpdateGlobalHDRState();
|
||||
|
||||
bool ValidateColorSpaceSupport(
|
||||
DXGI_FORMAT Format,
|
||||
DXGI_COLOR_SPACE_TYPE ColorSpace);
|
||||
|
||||
HRESULT UpdateColorSpace(
|
||||
DXGI_FORMAT Format,
|
||||
DXGI_COLOR_SPACE_TYPE ColorSpace);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE PresentBase(
|
||||
UINT SyncInterval,
|
||||
UINT PresentFlags,
|
||||
const DXGI_PRESENT_PARAMETERS* pPresentParameters);
|
||||
};
|
||||
|
||||
}
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue