Compare commits

...

346 Commits
v2.2 ... master

Author SHA1 Message Date
Blisto91 c1f665f92b [util] Disable supportDFFormats for Prototype
Incorrect shadows on AMD & Intel
2024-05-18 19:31:07 +02:00
WinterSnowfall 20185a5309 [d3d9] Do not enable support for DF formats on Nvidia 2024-05-18 16:16:34 +00:00
Blisto91 0c2efda804 [meta] Add DXVK Native section to the readme 2024-05-16 10:57:35 +00:00
Blisto91 c7d61b2fc0 [native] Change DXVK_WSIDRIVER to DXVK_WSI_DRIVER 2024-05-16 10:57:35 +00:00
Ethan Lee 6259e86392 [meson] Use dependency() instead of find_library() for SDL2/GLFW detection.
Since we're not linking to the libraries anymore, it doesn't make much sense to
use find_library, and in fact we need to use dependency() in order to get the
right CFLAGS for includes, defines, etc, so use that instead.

As a result, we can remove the 'SDL2/' folders from the includes, making the SDL
includes more correct.
2024-05-13 13:18:03 +00:00
Ethan Lee d5d236a1e2 [wsi] Refactor platform system to support multiple WSI implementations 2024-05-13 13:18:03 +00:00
Ethan Lee 10b83d184b [native] Dynamically load SDL2/GLFW at runtime.
Removing these link-time dependencies is important for making a single binary that is compatible with either backend, regardless of whether or not each one is currently available to the program.
2024-05-13 13:18:03 +00:00
Ethan Lee 0f7c1f753a [wsi] Refactor the WSI backends to be implementations of a WsiDriver interface.
Rather than directly calling functions, the API now calls shared functions that call into a WsiDriver instance, which is allocated and implemented by the backend. Functionally this should be the same, it just has the extra allocation for the function table.

This prepares the WSI library for supporting multiple implementations in a single binary.
2024-05-13 13:18:03 +00:00
Ethan Lee 529129c332 [dxvk] Move getInstanceExtensions platform logic to wsi.
This ensures that all of the WSI backend logic is in one place rather than two.
2024-05-13 13:18:03 +00:00
Ethan Lee 4055a92856 [wsi] Add init/quit functions, integrate them into DxvkInstance.
This is preparation for loading/unloading WSI backends at runtime, which will be in an upcoming commit.
2024-05-13 13:18:03 +00:00
Blisto91 7bad17c1d1 [util] Set deviceLossOnFocusLoss for The Sims 3
Prevents the game black screening on alt-tab
2024-05-11 14:38:43 +02:00
Blisto91 6b76d70d9d [util] Enable d3d11.longMad for Guild Wars 2
Fixes invisibility effect flicker when invariantPosition is enabled
2024-05-09 00:47:13 +02:00
Philip Rebohle 611dc60018 [d3d9] Do not support cube textures with depth formats 2024-05-08 17:05:48 +00:00
WinterSnowfall b2789ab894 [d3d9] Validate DS format support during CheckDepthStencilMatch 2024-05-06 20:26:09 +00:00
Philip Rebohle ab715a8876 [d3d11] Implement better filtering when blitting video content
Unlike linear filtering this guarantees that we never read outside the source
region, and this also lets us perform color space conversion prior to filtering.
2024-05-03 16:23:17 +02:00
talkingerbil 1fb35b6d19
[dxgi] Initialize UMD version quad to a max signed int64 (#3985) 2024-05-03 16:22:58 +02:00
Rémi Bernon 4333ee872d [d3d11] Use nearest filter for ID3D11VideoContext scaling 2024-05-02 18:17:54 +02:00
Rémi Bernon b99d42c688 [d3d11] Implement VideoProcessorSetStreamSourceRect scaling 2024-05-02 18:17:54 +02:00
Blisto91 dacb8b434b [util] Add configs for Delta Force Xtreme 1 & 2
Prevents the games from black screening on Alt-Tab and helps big performance dips.
2024-05-01 14:08:03 +02:00
Philip Rebohle ea4cb84d8a [dxvk] Remove workaround for non-dynamic depth clip
Kind of pointless and everyone supports the required EDS3 subset anyway.
2024-04-29 17:43:40 +02:00
Philip Rebohle 65373792d2 [dxvk] Forward link flags when using shader identifiers
Fixes a long-standing bug that now causes validation errors.
2024-04-29 17:43:40 +02:00
Lierrmm 29253da356 feat: add H2M-Mod to config 2024-04-29 16:19:42 +02:00
Robin Kertels 79398b468d [util] Enable longMad for Red Faction Guerrila Remastered 2024-04-29 13:17:21 +02:00
Robin Kertels e7d14e97de [dxbc] Implement option to split up fma 2024-04-29 13:17:21 +02:00
Philip Rebohle c613078ba8 [dxvk] Bump internal version number
Potentially useful for drivers and tools to deal with the new pipeline
layout changes.
2024-04-26 19:54:52 +02:00
Philip Rebohle 2970645f33 [dxvk] Fix push constant compatibility for pipeline libraries
When linking pipelines, all pipeline libraries are required to declare
the exact same set of push constants, even for stages not part of the
respective libraries.

This invalidates all fossilize databases.
2024-04-26 19:54:52 +02:00
Philip Rebohle 462165da19 [util] Add Deck profile for Fallout 4
Should fix the FPS problem on Deck OLED.
2024-04-26 14:34:08 +02:00
Philip Rebohle 3f27a0ee58 [util] Add a way to define app profiles exclusive to Steam Deck 2024-04-26 14:34:08 +02:00
Katharine Chui aac3396671 [dxgi] unchain DxgiFactory::CreateSwapChain and CreateSwapChainForHwnd
similar to https://github.com/doitsujin/dxvk/pull/3966, avoid
chaining so that dxgi tools attempting to wrap swapchains don't
end up double wrapping

ref: https://github.com/SpecialKO/SpecialK/issues/168
2024-04-25 12:07:50 +02:00
Katharine Chui 92a43ebf65 [dxgi] unchain DxgiSwapChain::Present1 and Present
dxgi hooking tools might hook both, eg. https://github.com/SpecialKO/SpecialK/issues/167
2024-04-22 14:04:43 +02:00
Blisto91 8ba5256dc7 [util] Set deferSurfaceCreation for 9th Dawn II
OpenGL game that also spins up d3d9. Will black screen without deferSurfaceCreation when using dxvk
2024-04-22 04:48:56 +02:00
Philip Rebohle 2b70ba8f77 [dxbc] Do not emit OpImageQueryLevels for multisampled images 2024-04-19 13:55:31 +02:00
Philip Rebohle 9c66c4bf1d [build] Target SPIR-V 1.6 for built-in GLSL shaders
Silences a Mesa warning when the HUD is enabled.
2024-04-19 13:36:32 +02:00
Philip Rebohle 00872e9e4f [dxvk] Fix render target clears with format reinterpretation
With LOAD_OP_CLEAR, we cannot rely on the clear actually being performed
with the view format in mind. Use a vkCmdClearAttachment path instead.
2024-04-19 13:08:36 +02:00
Philip Rebohle 35157357dd [dxvk] Fix stencil discard being broken 2024-04-19 01:43:23 +02:00
Philip Rebohle 617ebf4e05 [dxbc] Take used components into account for PS inputs 2024-04-19 01:01:52 +02:00
Philip Rebohle c2489d5a45 [dxbc] Fix array register anaylsis with multiple dst operands 2024-04-19 01:01:52 +02:00
Philip Rebohle 6ef98c613f [dxvk] Re-enable maintenance4 feature
Sileces some validation errors.
2024-04-19 01:01:52 +02:00
Philip Rebohle 7441137a33 [dxbc] Ignore system value components when declaring inputs 2024-04-19 01:01:52 +02:00
WinterSnowfall 571948cfc0 [d3d9] Remove support for VERTEXSTATS queries 2024-04-13 19:11:00 +01:00
Martino Fontana 133f0794bc [util] Remove framerate limiter for Nier Replicant
Without mods, Nier Replicant runs faster when going above 60 FPS.
The game had an official patch that implemented a framerate limiter to prevent this. This limiter is terrible, because it's not a stable 60 FPS, but a weird 57-58 FPS. There's no way to disable this in-game, it has to be done by editing a config file or through a mod.

So, why remove the default frame limiter from DXVK?
- In the default case (a user plays the game as it is), it does nothing, since 57-58 is lower than 60.
- If a user is going out of their way to edit the config file, why would they assume that DXVK already provides a frame limiter? They are going to follow [a guide](https://www.pcgamingwiki.com/wiki/NieR_Replicant#Framerate_limited_to_57.7E58_FPS) that says to set up a frame limiter, it doesn't say "set up a frame limiter, unless you are using DXVK, in that case it's already there".
- They are using [Special K in order to use a mod to play at high refresh rates at normal speed](https://wiki.special-k.info/SpecialK/Custom/Replicant). In this case, DXVK's default limiter is harmful, since it is not documented that it's there by default.

Since this default limiter is useless in the first two cases and harmful in the third, I think it should be removed.
The alternative would be to document this (e.g. in PCGamingWiki), but the instructions wouldn't look pretty... "After following the instructions to use Special K in order to play at higher framerates at normal speed, if are using DXVK/Proton, also do these things to disable its default 60 FPS cap: [...]"

Especially because that the game isn't broken in the default case, I don't think DXVK should tamper with these things in a way that requires documentation to revert.

Tested Special K's mod to play at higher refresh rates on Linux.
2024-04-08 21:48:47 +02:00
Philip Rebohle 44695f9311 [dxvk] Adjust desciptor pool reset heuristic
Drastically limits the amount of descriptor memory we allocate in situations
where an application renders without presenting anything to a swap chain.

The new limit is a bit tight for some real-world use cases (e.g. Ashes of the Singularity),
but at worst we will start calling vkAllocateDescriptorSets once per set and draw.
2024-04-08 15:40:25 +02:00
Casey Bowman 49e9ea5f5a [dxgi] Force vendor ID change when XeSS is detected on an Intel GPU
Games using libxess.dll or wrapper modules will crash.
To work around this, we hide the Intel GPU's vendor ID to avoid using the
XeSS module.
2024-04-03 20:32:04 +02:00
Blisto91 198bd3a4b8 [d3d11] Remove missed Shared Keyedmutex warning
D3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX is implemented.
2024-04-03 20:31:52 +02:00
Philip Rebohle f06c646315 [dxbc] Remove broken atomic counter subgroup optimization
This is not a legal optimization inside non-uniform control flow due
to Vulkan's extremely permissive convergence rules, and apparently
breaks on Nvidia as a result.

Mesa drivers already do the same thing internally anyway.
2024-04-03 14:55:43 +02:00
Philip Rebohle 855b2746b6 [util] Remove TRAHA Global config
This game apparently no longer exists.
2024-03-26 13:42:55 +01:00
Blisto91 28c7c09bf5 [dxgi] Remove useMonitorFallback option
QueryDisplayConfig optimization is now in Proton 9 Wine
2024-03-21 17:23:38 +01:00
Philip Rebohle 2742486540 [dxvk] Don't query color space support for null surfaces
Fixes a crash in games with the dxgi.deferSurfaceCreation workaround set.
Note that this potentially breaks HDR.
2024-03-21 15:32:48 +01:00
Philip Rebohle 037d0fa1ad [meta] Release 2.3.1 2024-03-20 13:48:30 +01:00
Philip Rebohle cbf51a7a25 [d3d11] Enable copy usage for typeless images as necessary 2024-03-20 13:30:31 +01:00
Philip Rebohle 70e34dc31c [dxvk] Support arbitrary source formats for color<->depth copies
Fixes rendering bugs in War Thunder.
2024-03-20 13:29:59 +01:00
Philip Rebohle c5aeb0f87a [dxvk] Get rid of separate depth shaders for shader-based copies
We can export both depth and color in a single shader instead.
2024-03-19 19:32:12 +01:00
Philip Rebohle a163082770 [dxvk] Align index buffer size to index size
Fixes validation errors in FFXIV.
2024-03-19 19:32:12 +01:00
Blisto91 2e1a19c7fd [util] Cap Dark Void to 60fps
Game crashes in certain places like specific cutscenes unless capped at 60fps.
2024-03-18 12:56:27 +01:00
Joshua Ashton 0beb18ef73 [d3d9] Wait for submission when calling ReturnUnderlyingResource 2024-03-16 19:11:11 +00:00
Joshua Ashton ef4428ab8c [d3d9] Improve ReturnUnderlyingResource stub for 9on12 2024-03-16 18:59:03 +00:00
Philip Rebohle 1085ba713e [dxgi] Implicitly set HDR color space for RGBA16_FLOAT swap chains 2024-03-16 18:56:41 +00:00
Philip Rebohle e857b09432 [dxgi] Change default behaviour of hideNvkGpu option 2024-03-15 22:48:57 +01:00
Kaitlyn 538f1d13d4 Fix UAV as well 2024-03-15 15:22:13 +01:00
Kaitlyn 783c9d4591 Fix MiscFlags check in GetDescFromResource 2024-03-15 15:22:13 +01:00
Kaitlyn 1a685b1c67 Implement D3D11DXGIDevice::EnqueueSetEvent 2024-03-15 13:47:28 +01:00
Robin Kertels 8b8be7c2bf [d3d9] Fix stream count in Reset 2024-03-10 17:12:22 +01:00
Billy Laws 0776d764a4
build: Support building for ARM64EC
When targeting ARM64EC, both __x86_64__ and _M_X86_64 are defined but
not all x86 intrinsics are present, treat EC as regular ARM64 so the
native intrinsics are used instead.
2024-03-09 05:43:46 +00:00
Robin Kertels 15ddadc4de [d3d9] Fix number of streams 2024-03-08 18:42:15 +01:00
Philip Rebohle 69a52b3da0 [dxbc] Do not emit depth compare for unsupported image types
Fixes invalid SPIR-V.
2024-03-07 16:11:23 +01:00
Philip Rebohle 707ad6f328 [spirv] Add OpConstantNull 2024-03-07 16:11:23 +01:00
Philip Rebohle 3a6992ea97 [dxbc] Enable depth compare types for 1D images
Used by Renderdoc internal shaders.
2024-03-07 16:11:23 +01:00
Robin Kertels 72c86b8229 [d3d9] Only unbind in EndScene if the game cleared the binding 2024-03-06 22:58:48 +01:00
Robin Kertels 85215b10d6 [d3d9] Respect vertex buffer offset when dynamically uploading geometry 2024-03-06 18:13:26 +01:00
Philip Rebohle fd3fbf6607 [dxvk] Remove old memory budget code
Obsolete since we removed the Nvidia HVV workaround for old drivers.

Closes #3877.
2024-03-06 15:48:34 +01:00
Minelelol 0a699fddb6 Update config.cpp
Insane Performance increase
2024-03-06 15:25:16 +01:00
Blisto91 afec5cce88 [util] Remove some unneeded built in configs
Dirt 5 does not crash without working ags anymore and Ethan Carter Redux also starts fine without a spoof.
This allows the built in AMD ags in Proton 9 to be used for these games.

The Hitman 3 config is redundant as it doesn't allow RT to be enabled without Nvapi anyway.
2024-03-06 15:24:54 +01:00
Ethan Lee 4b0e3111d1 meson: Check for bundled Vulkan/SPIR-V headers before adding them to the include list.
This feature requires Meson 0.58 or newer.
2024-03-06 15:21:15 +01:00
Philip Rebohle 0414bbe2d5 [dxgi] Add separate option to override vendor IDs for NVK 2024-03-06 14:46:21 +01:00
Robin Kertels 20490b678f [d3d9] Fix missing else brackets in ResetSwapchain 2024-03-06 12:08:45 +01:00
Blisto91 428c98bc63 [util] Disable countLosableResources for all d3d9 Supreme Ruler games
All the d3d9 Supreme ruler games have this issue.
2024-03-05 15:28:11 +01:00
Robin Kertels a0e39e94fa [d3d9] Use most recently used swapchain for GetFrontBufferData 2024-03-05 13:54:15 +00:00
Robin Kertels eaa732d0b3 [d3d9] Place GetFrontBufferData screenshot at window position 2024-03-05 13:54:15 +00:00
Robin Kertels 49b18f03fe [d3d9] Unbind buffers in EndScene & Reset 2024-03-05 13:52:51 +00:00
Philip Rebohle c9cea93b7b [dxbc] Use raw access chains for buffer loads and stores
Maps more or less perfectly to D3D raw and structured buffers.
2024-03-05 14:41:18 +01:00
Philip Rebohle 69d74a46a0 [dxbc] Remove emitRawBuffer{Load,Store}
And factor these into the callers. We need to preserve the raw
index and offset parameters to use raw access chains.
2024-03-05 14:41:18 +01:00
Philip Rebohle 94098aa97d [dxbc] Enable SPV_NV_raw_access_chains 2024-03-05 14:41:18 +01:00
Philip Rebohle c677ba9b3e [dxvk] Enable VK_NV_raw_access_chains if available 2024-03-05 14:41:18 +01:00
Philip Rebohle 77c7396ee1 [spirv] Add support for OpRawAccessChainNV 2024-03-05 14:41:18 +01:00
Philip Rebohle f07e5f9eaa [include] Update SPIR-V headers 2024-03-05 14:41:18 +01:00
Philip Rebohle d5c3011f54 [include] Update Vulkan headers 2024-03-05 14:41:18 +01:00
Blisto91 6b3b934471 [util] Clarify maxDeviceMemory and maxSharedMemory
This config often leads to confusion as people expect applications to honor the limit.
2024-03-02 20:41:19 +01:00
Philip Rebohle 9004c132ed [dxbc] Declare dynamically indexed UBOs with the maximum possible size
Fixes #3861.
2024-02-23 13:39:29 +01:00
Philip Rebohle 24d4c9c938 [util] Disable command lists for Granblue Fantasy Relink
The uses deferred contexts for rendering if driver command lists are enabled,
but when AMDAGS is loaded, it will also unconditionally use MultiDrawIndirect
functions. Since the AGS version in use does not support deferred contexts,
this breaks rendering, so we will have to force it into the immediate context
path.

Testing also shows slightly higher performance (~3-5%) with this path in
CPU-bound scenarios.
2024-02-22 16:07:24 +01:00
Philip Rebohle 5ded7d67f0 [d3d11] Implement UpdateSubresource bug if native command lists are disabled 2024-02-22 16:07:24 +01:00
Philip Rebohle 234f3ea071 [d3d11] Add option to hide native command list support 2024-02-22 16:07:24 +01:00
Robin Kertels c5a37d443a [d3d9] Handle null IBO when uploading data for draw 2024-02-20 13:04:01 -08:00
Robin Kertels f254afb4fb [util] Enable strict float emulation for Red River 2024-02-20 12:58:03 -08:00
Robin Kertels 39c19e9299 [d3d9] End scene on reset 2024-02-20 12:58:03 -08:00
Robin Kertels 738fd4f895 [d3d9] Don't actually unbind buffers 2024-02-20 12:58:03 -08:00
Philip Rebohle 9491b56beb util: Enable d3d11.ignoreGraphicsBarriers for Granblue Relink
Improves GPU-bound performance due to the game using PS UAVs.
2024-02-15 20:33:55 +01:00
Robin Kertels ab3593185f [d3d9] Fail GetRTData if src and dst have mismatching sizes
MySims tries to do this and needs this to fail,
otherwise mouse picking is off.
2024-02-06 11:02:43 +01:00
Robin Kertels e9a0fec5b3 [dxso] Clamp Exp when fast float emulation is enabled 2024-02-06 11:02:20 +01:00
Echo J fae78407a2 d3d9: Remove an unused variable
This fixes a gcc warning (originally reported by Saancreed)
2024-02-06 10:19:28 +01:00
Robin Kertels 5312ef1cf9 [d3d9] Upload DYNAMIC+SYSMEM vertex and index data for each draw 2024-02-05 13:13:18 +00:00
Robin Kertels 62d64bd63a [d3d9] Don't upload buffers before Up draws 2024-02-05 13:13:18 +00:00
Robin Kertels f83ba898af [dxvk] Use signed int for vertexOffset
BaseVertexIndex is signed in Vulkan, D3D11 & D3D9.
2024-02-05 13:13:18 +00:00
Ethan Lee 30f2b2df31 package-native.sh should force libdisplay-info subproject
This ensures that the script produces a build similar to the default steamrt build, even if libdisplay-info is available on the build system root.
2024-02-05 13:08:30 +01:00
Philip Rebohle 05cb963e22 [util] Set sync interval override for P3R 2024-02-02 17:30:13 +01:00
Philip Rebohle eb339bc7e4 [dxgi,d3d11] Move syncInterval override to DXGI swap chain
This way it also applies to D3D12 games.
2024-02-02 17:30:13 +01:00
Ethan Lee c423819e90 [meson] Only use the libdisplay-info subproject as a fallback 2024-01-30 20:48:40 +01:00
Tatsuyuki Ishi e2a46a347d [meta] Declare bool conversion operators as explicit
Non-explicit conversion operators in general can participate in very
surprising conversion chains. Explicit bool operator is a good place to
start with, because even with explicit they do get automatic contextual
conversion in a lot of places, e.g., if conditions.
2024-01-27 11:44:51 +01:00
Tatsuyuki Ishi afc6aa70fb [d3d11] Explicitly convert DxvkExt to bool in D3D11DeviceFeatures
When assigning to a BOOL (which is an uint in disguise) and using explicit
bool conversion operators (introduced in a latter commit) an explicit cast
is required.
2024-01-27 11:44:51 +01:00
Tatsuyuki Ishi 799aeff560 [dxvk] Fix incorrect comparison in DxvkSparsePageTable::updateMapping
m_mappings[page] was getting implicitly converted to bool.
2024-01-27 11:44:51 +01:00
Robin Kertels 2ca8fdf890 [util] Disable counting losable resources for Supreme Ruler Ultimate
The game is broken and leaks a state block.
2024-01-26 18:11:25 +00:00
Robin Kertels 0841f5faf4 [d3d9] Implement config option to disable rejecting reset 2024-01-26 18:11:25 +00:00
Ethan Lee 2334bbccb0 [native] Add a DECLARE_INTERFACE define for !CONST_VTABLE.
This helps avoid some compiler warnings on GCC in particular.
2024-01-26 17:48:44 +00:00
Robin Kertels 7d9864c077 [d3d9] Only enable ATOC when rendering to MS RT 2024-01-26 17:48:21 +00:00
Dean Beeler d4c5fc74e7
d3d11: Fix crash when srv is submitted to ClearUnorderedAccessViewUint
* The Settlers submits (possibly incorrectly) an SRV to ClearUnorderedAccessViewUint. The static_cast in the function does not translate correctly and crashes.

Native D3D11 behavior is to ignore the bad parameter entirely. It does not clear the SRV nor does it fault or even error with the DEBUG validator.
2024-01-23 16:01:12 +01:00
Tatsuyuki Ishi 6199776869 [build] Set filealign for MSVC builds
Useful if you want to run a MSVC build on Wine.
2024-01-23 15:45:42 +01:00
Tatsuyuki Ishi 6faf3c1acd [build] Don't pass unix compiler and link args to MSVC
clang-cl accepts both style of options but these will be generally meaningless:
- Static CRT is unnecessary.
- File alignment will be introduced in another commit.
- Wine has partial support for PDB backtrace so there is probably no need to
  insist on DWARF (which is unsupported by real MSVC anyway).
- MSVC doesn't have the weird stdcall ordinal naming convention that
  necessiates fixup and kill-at.
2024-01-23 15:45:42 +01:00
Tatsuyuki Ishi ab6bd8b17f [build] Recognize more MSVC-like compilers as MSVC
clang-cl has its own compiler id but supports MSVC argument conventions.
Use get_argument_syntax to recognize MSVC-like compilers generally.
2024-01-23 15:45:42 +01:00
Tatsuyuki Ishi 89267b62ad [build] Remove declspec UUID annotations
MIDL_INTERFACE already implies struct DECLSPEC_UUID.
2024-01-23 15:44:47 +01:00
Blisto91 34d8e65fd7 [util] cachedDynamicBuffers for Codename Panzers Phase One/Two
Helps CPU bound performance
2024-01-23 15:44:28 +01:00
Joshua Ashton 1568c263fb [d3d9] Only add unique modes to mode list 2024-01-19 16:28:22 +00:00
Joshua Ashton 0cd4165658 [d3d9] Add D3DDISPLAYMODEEX operator 2024-01-19 16:28:22 +00:00
Joshua Ashton 4b8e8bed6e [d3d9] Move operators out of dxvk namespace 2024-01-19 16:28:22 +00:00
r-a-sattarov ac78048c23 [util] Fix e2k build 2024-01-16 22:03:31 +01:00
Richard Yao 14560600a9 Micro-optimize locking in fences
When a fence has been missed, we can avoid locking *most* of the time
via the double-checked locking pattern. We still lock before a second
check in case the scheduler caused us to miss the fence. If the
scheduler did cause us to miss the fence, we can drop the lock prior to
executing the callback function, as a second micro-optimization.

Signed-off-by: Richard Yao <richard.yao@alumni.stonybrook.edu>
2024-01-15 12:42:19 +01:00
Blisto91 854e06d3f0 [util] Enable deviceLossOnFocusLoss for BF2 and BF2142
The ingame spawn and gear selection GUI can disappear from view unless this is set.
2024-01-14 22:25:43 +01:00
Blisto91 eb806952d8
[util] Set deviceLossOnFocusLoss for Assassin's Creed 2 (#3763)
Makes it not crash on alt tab using at least Proton. 
Windows will still have issues with alt tab.
2024-01-09 10:43:48 +01:00
Blisto91 a44dfabe26 [util] Set float emulation to Strict for UK Truck Simulator 1
Fixes black foliage
2024-01-09 10:42:52 +01:00
spiffeeroo 5e06cf9573 [util] Limit Sonic CD to 60 fps
Game engine physics/speed for Sonic CD is tied to frame rate so limit max frame rate to 60 fps. Otherwise, the game runs too quickly for high refresh rate monitors.
2024-01-02 19:05:44 +01:00
Blisto91 2cf590f636 [util] Enable cached vertex buffers for Kenshi
Improves the games performance when CPU bound.
2023-12-30 22:47:24 +01:00
Robin Kertels a7a63b37c3 [util] Fix incorrect config option name 2023-12-27 03:06:49 +01:00
Robin Kertels 9cde0b5798 [d3d9] Fix off-by-one when copying shader defined constants 2023-12-25 14:51:02 +00:00
Blisto91 adb33d3af1 [util] Hide Intel in Far Cry 3, 4 and Primal
Also unhides Nvidia in Primal as it has the same clear value rounding assumptions as Far Cry 3 and 4
2023-12-23 09:23:27 +01:00
Philip Rebohle 1b31aa5dbc [util] Enable hideIntegratedGraphics for Metro Exodus EE 2023-12-01 14:14:36 +01:00
Philip Rebohle 03c09ce15f [dxvk] Add option to skip integrated GPU adapters 2023-12-01 14:14:13 +01:00
Blisto91 91f7f43c35 [util] Don't spoof Nvidia on AMD GPUs in Hitman 3
Spoofing to Nvidia prevents ray tracing enablement on AMD and the game does not crash without ags anymore
2023-11-18 12:18:08 +01:00
Robin Kertels d998dee46e [d3d11] Lock context in KeyedMutex::ReleaseSync
Co-authored-by: Yuxuan Shui <yshuiv7@gmail.com>
2023-11-16 15:43:07 +01:00
Philip Rebohle ea3149801f [d3d9] Return empty buffer slice for out-of-bounds offsets
Fixes #3715.
2023-11-14 10:54:54 -08:00
xpander69 1cb58b0732 [Util] two more executables to workaround Warhammer Online
Test server executables need the same VendorID to work around the rendering issues.
2023-11-14 12:23:50 +01:00
Philip Rebohle 2ed1778df9 [d3d11] Handle potential integer overflow when validating draw offsets
Apparently some games use -1 as an argument offset, which is nonsensical
and leads to issues.
2023-11-02 17:49:38 +01:00
Philip Rebohle a427d22cde [dxvk] Add Vulkan instance flag for D3D9 apps 2023-10-31 16:05:58 +01:00
Joshua Ashton 22c2abb9b7 [dxgi] Treat R16G16B16A16_FLOAT as 32bpp for display
HDR in Control (a patch released by a developer post-launch, not
actually in the game sadly) tries to set a video mode with
DXGI_FORMAT_R16G16B16A16_FLOAT.

This seemingly works on Windows, and based on FindClosestMode etc
documentaton, this seems required to work for any format that scanout
it supported for.

It's really not like the bpp is meaningful on Windows with the
distinction of 8bit and 10bit not working in GDI modes at all.
Nor does it end up actually setting anything on Linux/Deck where
modesets are emulated.

So, treat DXGI_FORMAT_R16G16B16A16_FLOAT as 32bpp so the
FindClosestMatchingMode and EnterFullscreenMode calls succeed.
2023-10-29 10:09:34 +01:00
Blisto91 f45911a28f [util] Disable allowDirectBufferMapping for SkyDrift
Works around a alt tab OOM crash
2023-10-23 14:52:44 +02:00
Blisto91 e00db24557 [util] Enable useMonitorFallback for Holocure
Temporary performance drop workaround until QueryDisplayConfig optimization is in Proton Wine.
2023-10-10 19:32:23 +02:00
Paul Gofman 552d2f0a6d [dxgi] Add useMonitorFallback option
And enable it for CP2077.
It is supposed to be dropped once QueryDisplayConfig optimization
is in Proton Wine.
2023-10-10 12:01:51 +02:00
WinterSnowfall 4d974685c9 [d3d9] Mark presenter for recreation on device reset with deferSurfaceCreation 2023-10-06 14:05:39 +02:00
Blisto91 f0ff0007dc [util] Enable cachedDynamicBuffers for Battlestations Midway
Helps performance dips that can happen in some areas
2023-10-06 14:05:04 +02:00
Robin Kertels 494f7fd38d [d3d9] Only set initial NeedsUpload for D3DPOOL_MANAGED textures 2023-09-19 13:25:12 -07:00
WinterSnowfall 0632da1935 [d3d9] Add a device compatibility mode for d3d8 2023-09-19 09:19:55 -07:00
Philip Rebohle 83dc4678df [util] Set maximum frame latency to 1 for Age of Empires 2 (2013)
Game seems to be doing something horrible on its own, literally impossible
to make it run smoothly. This at least seems to limit excursions to ±10ms
and fix the camera flinging back and forth when running the game through
Gamescope.
2023-09-14 16:50:30 +02:00
Paul Gofman f93cfbc26a [d3d11] Pass device directly to D3D11DXGIKeyedMutex 2023-09-13 14:29:25 -07:00
Philip Rebohle c113b791a1 [util] Enable 60 FPS lock for Aviary Attorney
This game (or nw.js) comes with a hard-coded frame rate limit that
behaves more like a random number generator which happens to average
out at around 16ms on a good day.

Fix this complete mess by enabling ours on top of that.
2023-09-08 03:04:02 +02:00
Ellie Hermaszewska 41191af3b1 A few more WinDef types in windows_base.h
These specific ones are used in MS's d3dx12 headers
2023-09-07 16:31:32 +02:00
Philip Rebohle 5828f0e2b9 Revert "[dxgi] Use VK_FORMAT_A8_UNORM if available"
This reverts commit 6a5ed02db3.

Native A8 breaks Crysis 2/3 Remastered for unknown reasons.
2023-09-07 03:58:39 +02:00
Philip Rebohle 80e075406b [meta] Release 2.3 2023-09-04 17:59:12 +02:00
Margen67 a53f0e8168 [util] Remove whitespace 2023-09-04 03:10:49 +02:00
Margen67 4705de5725 [util] Escape . 2023-09-04 03:10:49 +02:00
Robin Kertels 9e26964a96 [d3d9] Divide projected textures by w if ProjectedCount is 0 2023-09-03 18:08:47 -07:00
Blisto91 ce2f9f35ce [util] Hide AMD in Riders Republic
Works around crashing because of statically linked amd ags
2023-09-01 00:21:16 +02:00
Philip Rebohle a3fa9c26dc Revert "[d3d11] Implement DXGI_SWAP_EFFECT_SEQUENTIAL and FLIP_SEQUENTIAL"
This reverts commit 79f6239df3.

Some engines use SEQUENTIAL presentation despite not making use of it, and
sparse binding is much slower than expected on Nvidia drivers, which leads
to massive performance regressions across the board.
2023-09-01 00:15:09 +02:00
Joshua Ashton ff5507769a [wsi] Add proper values for SDR metadata fallbacks 2023-08-31 22:54:02 +01:00
WinterSnowfall 5c56fa0df4 [util] Enable deferSurfaceCreation for Drakensang 2023-08-30 18:02:02 +02:00
Tatsuyuki Ishi 7e10021eac Remove unused DxvkResource::waitIdle
Spinning-based wait idle is no longer used.
2023-08-29 11:05:42 +02:00
Joshua Ashton bbd1d84cd0 [dxgi] Set BitsPerColor to 10
For two reasons:
1) Some apps will only enable or attempt to enable HDR if BitsPerColor is >= 10.

2) Encouraging apps to create 10-bit swapchains for use in hardware dithering on Gamescope/Steam Deck and to have more precision thru scanout color transforms
2023-08-26 01:43:42 -07:00
Jens Peters 02db89ac30 [dxgi] Allow HDR on UE4/D3D11 when NVAPI is enabled 2023-08-24 21:21:29 -07:00
Philip Rebohle 92dc61f161 [d3d11] Fix up UAV clears for A8_UNORM 2023-08-24 13:12:07 +02:00
Philip Rebohle 6a5ed02db3 [dxgi] Use VK_FORMAT_A8_UNORM if available 2023-08-24 13:12:07 +02:00
Philip Rebohle 64828e2c6c [dxvk] Use vkCmdBindIndexBuffer2 if supported 2023-08-24 13:12:07 +02:00
Philip Rebohle a4f2a49a02 [dxvk] Add description for new image formats 2023-08-24 13:12:07 +02:00
Philip Rebohle aa41a7a351 [dxvk] Enable VK_KHR_maintenance5 if available. 2023-08-24 13:12:07 +02:00
Philip Rebohle fb71c08d8c [include] Update Vulkan headers. 2023-08-24 13:12:07 +02:00
Philip Rebohle 79f6239df3 [d3d11] Implement DXGI_SWAP_EFFECT_SEQUENTIAL and FLIP_SEQUENTIAL
Requires sparse since we have no other means to swap the backing image.
2023-08-24 13:00:35 +02:00
Philip Rebohle 53a68635b2 [dxvk] Optimize page table updates for images
Dramatically reduces overhead when binding full subresources.
2023-08-24 13:00:35 +02:00
Philip Rebohle 179c5ec998 [dxvk] Sort allocated memory pages for sparse allocator
This way, memory regions bound to consecutive pages are more likely
to end up in consecutive memory regions, which allows batching page
table updates more efficiently.
2023-08-24 13:00:35 +02:00
Philip Rebohle d6e0107e23 [dxvk] Ensure to submit sparse binding commands 2023-08-24 13:00:35 +02:00
Joshua Ashton 428ca9416d [d3d11] Implement synchronization on keyed mutexes
Co-authored-by: Paul Gofman <pgofman@codeweavers.com>
2023-08-23 16:50:52 +02:00
Joshua Ashton c26f40229a [vulkan] Query wine_vk{Acquire,Release}KeyedMutex
Non-standard functions, but exposed by winevulkan to support keyed mutexes.

Co-authored-by: Paul Gofman <pgofman@codeweavers.com>
2023-08-23 16:50:52 +02:00
Joshua Ashton 8226690298 [dxvk] Enable VK_KHR_win32_keyed_mutex
Co-authored-by: Paul Gofman <pgofman@codeweavers.com>
2023-08-23 16:50:52 +02:00
Joshua Ashton 138f727fbb [native] Add WAIT_* defines 2023-08-23 16:50:52 +02:00
Philip Rebohle c2cd129b89 [dxvk] Fix xfb counter buffer draw tracking 2023-08-23 13:44:35 +02:00
Philip Rebohle 915244c00c [d3d11] Fix various D3D10 interface queries 2023-08-23 01:06:04 +02:00
Blisto91 6fce094942 [util] Limit fps in Project: Snowblind
Player movement and animation can bug out at high fps like issues moving around objects and the players head detaching slightly when moving backwards.
Seems like it also helps some crash issues.
2023-08-21 01:43:24 +02:00
Robin Kertels 740ebec7ee [d3d9+dxso] Consider DMAP sampler in bit masks 2023-08-20 10:21:16 -07:00
Robin Kertels bcaaac4ad7 [d3d9] Handle sampling from DS_READONLY properly 2023-08-18 18:59:53 -07:00
Joshua Ashton 1130512db5 [dxgi] Add global HDR interop interface for NVAPI/AGS 2023-08-18 22:57:06 +01:00
Blisto91 143eb8c710 [meta] Document DXVK_CONFIG in readme 2023-08-16 12:57:42 +02:00
Philip Rebohle 4ae542e875 [util] Do not hide Nvidia GPUs from Ratchet & Clank
NVAPI is disabled now due to crashing issues in a wine-specific code
path within the game, but we still want it to detect the correct GPU
so that it doesn't complain about drivers and also allows users to
enable Raytracing.
2023-08-15 00:23:19 +02:00
Philip Rebohle 952c66fe2a [dxgi] Add options to hide Intel or AMD GPUs. 2023-08-14 20:12:02 +02:00
Philip Rebohle b6a7714e67 [dxgi,util] Rename dxgi.nvapiHack option to dxgi.hideNvidiaGpu 2023-08-14 19:21:16 +02:00
Etaash Mathamsetty 037669f715 [dxso] Don't assume 32 registers. 2023-08-13 20:34:38 +01:00
Robin Kertels 295a58afdf [d3d9] Check depth bounds test when deciding to bind DSV 2023-08-13 20:32:20 +01:00
Robin Kertels 0746a3b91a [d3d9] Don't resolve an image with 1 sample 2023-08-10 13:45:40 +02:00
Etaash Mathamsetty 429555a540 [dxgi] Fix behavior of GetWindowAssociation 2023-08-09 12:18:24 +02:00
Blisto91 dfcd7aedd8
[util] Limit Conflict Vietnam to 60fps (#3606)
Physics can bug out at higher fps making the character fly or get stuck when running up or down slopes.
2023-08-09 12:18:10 +02:00
gofman cbda22a040
[d3d11] Add stub IDXGIKeyedMutex interface. (#3601)
Partially based on a patch by Derek Lesho.

Co-authored-by: Paul Gofman <pgofman@codeweavers.com>
2023-08-07 17:23:32 +02:00
Georg Lehmann 549bd86f03 [d3d9] use strict float emulation for nvk
nvk supports nir_op_fmulz/ffmaz
2023-08-06 11:01:03 +01:00
WinterSnowfall b0b46fd075 [d3d9] Don't show/hide a software cursor 2023-08-02 01:51:19 +01:00
Joshua Ashton a62117cd13 build: Disable stdcall alias-ing and use kill-at
Disable stdcall aliasing and enable kill-at to ensure our exported
functions don't have the @8, @40, etc suffixes.

This still keeps `--enable-stdcall-fixup` as otherwise the linker can
get confused trying to find exports from the .def. This does not result
in aliases being added, just for them to be found to add to the export
table.

This also switches d3d11 to use the MinGW provided dxgi.lib for linking
and d3d10 to use the MinGW provided d3d11.lib for linking.
Unfortunately the .a's we output seem to still have the @blah that we
killed so we cannot use them for internal linkage since using kill-at.

Tested that what we get out of MinGW now is what we want with dllexp.

Supercedes: #3590

Exports

```
➜  build git:(master) ✗ winedump -j export src/dxgi/dxgi.dll
Contents of src/dxgi/dxgi.dll: 129505860 bytes

  Name:            DXGI.DLL
  Characteristics: 00000000
  TimeDateStamp:   64C97A2D Tue Aug  1 22:33:33 2023
  Version:         0.00
  Ordinal base:    9
  # of functions:  9
  # of Names:      5
Addresses of functions: 00423028
Addresses of name ordinals: 00423060
Addresses of names: 0042304C

  Entry Pt  Ordn  Name
  00007C17     9 CreateDXGIFactory
  00007BF3    10 CreateDXGIFactory1
  00007B62    11 CreateDXGIFactory2
  00007C3B    16 DXGIDeclareAdapterRemovalSupport
  00007CD8    17 DXGIGetDebugInterface1

Done dumping src/dxgi/dxgi.dll
```

```
➜  build git:(fix-stdcall-32-bit) winedump -j export src/d3d11/d3d11.dll
Contents of src/d3d11/d3d11.dll: 263021637 bytes

  Name:            D3D11.DLL
  Characteristics: 00000000
  TimeDateStamp:   64C97A2E Tue Aug  1 22:33:34 2023
  Version:         0.00
  Ordinal base:    18
  # of functions:  7
  # of Names:      4
Addresses of functions: 005E3028
Addresses of name ordinals: 005E3054
Addresses of names: 005E3044

  Entry Pt  Ordn  Name
  00020045    18 D3D11CoreCreateDevice
  000200AA    22 D3D11CreateDevice
  0002010E    23 D3D11CreateDeviceAndSwapChain
  0002025F    24 D3D11On12CreateDevice

Done dumping src/d3d11/d3d11.dll
```

Import of DXGI in D3D11

```
  offset 005e1014 dxgi.dll
  Hint/Name Table: 005E408C
  TimeDateStamp:   00000000 (Thu Jan  1 01:00:00 1970)
  ForwarderChain:  00000000
  First thunk RVA: 005E4300
   Thunk    Ordn  Name
  005e4300     4  CreateDXGIFactory1
```
2023-08-01 23:35:09 +01:00
pchome e598dcd77e
[util] Add DXVK_CONFIG to define additional options 2023-08-01 22:09:29 +02:00
Philip Rebohle 09857dcaa9 [dxvk] Dirty multisample state if sample mask export changes.
This affects Alpha-to-Coverage.
2023-08-01 18:07:47 +02:00
Philip Rebohle d66f8385c3 [dxvk] Disable alpha to coverage if sample mask is written
Matches D3D11 behaviour and fixes tree rendering in A Total War Saga: TROY.
2023-08-01 16:58:46 +02:00
Philip Rebohle 007e9f4c89 [dxvk] Check whether fragment shader exports sample mask 2023-08-01 16:27:23 +02:00
Philip Rebohle 9b019d26ac [dxgi] Forward IDXGIOutput::GetFrameStatistics to full-screen swap chain
Testing on Windows reveals that this function does not work with windowed
mode swap chains even in flip model.
2023-07-31 21:47:44 +02:00
Philip Rebohle 228615b639 [d3d11] Rework D3D11CoreCreateDevice
FiveM calls this directly and apparently our signature wasn't quite
what they expect it to be.
2023-07-31 13:13:48 +02:00
Ellie Hermaszewska dfbebba6b5
[native] Add CHAR and PCSTR to windows_base.h 2023-07-29 18:01:01 +01:00
Blisto91 4ed04268fd [build] Use new glslang name with fallback 2023-07-29 14:54:32 +02:00
Blisto91 4ed1474030 [meta] Move up Vulkan driver section in readme 2023-07-23 19:59:31 +02:00
Blisto91 13440a5d89 [dxvk] Clarify Vulkan 1.3 driver requirement in log 2023-07-23 19:59:31 +02:00
Blisto91 1daae75048 [util] Set Cached Dynamic Resources for d3d11 Vindictus
Co-authored-by: NorbertHarangozo <maszek.solutions@gmail.com>
2023-07-23 19:12:12 +02:00
Philip Rebohle b4d87eaac0 [dxbc] Fix constant texture offsets with 1D textures
Fixes #3572.
2023-07-22 17:37:37 +02:00
Philip Rebohle 1e11db98d0 [dxvk] Use separate mutex for completed chunk counter
Fixes a possible deadlock.
2023-07-21 21:45:50 +02:00
Philip Rebohle f689ddd838 [dxvk] Use dual queues for CS thread
Reduces lock contention since we can just swap out the entire queue
any time the worker thread runs out of stuff to do.
2023-07-21 21:21:34 +02:00
Philip Rebohle eed43c8524 [dxgi] Fix QPC time in frame statistics 2023-07-21 10:22:56 +02:00
Philip Rebohle d066fbbaed [d3d11] Set up line rasterization mode appropriately 2023-07-20 23:43:03 +02:00
Philip Rebohle a67c99943a [dxbc] Set output topology for GS and TES correctly 2023-07-20 23:43:03 +02:00
Philip Rebohle 5ece97f769 [dxvk] Add line rasterization mode to rasterization state 2023-07-20 23:43:03 +02:00
Philip Rebohle 228cd4c331 [dxvk] Enable VK_EXT_line_rasterization if supported. 2023-07-20 23:43:03 +02:00
Blisto91 98f3887680 [util] Cleanup a couple of example config options 2023-07-17 15:38:13 +02:00
Blisto91 3a9a70b5f0 [meta] Add Graphics Pipeline Library section to readme 2023-07-17 15:38:13 +02:00
Philip Rebohle 878da4984b [util] Disable single-use command lists for Ghost Recon Wildlands 2023-07-17 15:00:55 +02:00
Philip Rebohle c599f95e5d [d3d11] Do not cache GetCurrentProcess result
This is just a constant.
2023-07-16 21:16:16 +02:00
Paul Gofman 4893788d9b [d3d11] Fixup incorrect MiscFlags in D3D11Device::OpenSharedResourceGeneric()
So texture sharing works with vkd3d-proton before correcting flags
there.
2023-07-16 15:34:39 +02:00
Paul Gofman fc952a3ca3 [d3d11] Validate texture sharing parameters at texture creation 2023-07-16 15:34:39 +02:00
Paul Gofman 01ad79278b [d3d11] Support just one handle type in D3D11DXGIResource::{Get|Create}SharedHandle 2023-07-16 15:34:39 +02:00
Paul Gofman 48557886de [d3d11] Determine shared texture handle type through D3D11_RESOURCE_MISC_SHARED_NTHANDLE 2023-07-16 15:34:39 +02:00
Paul Gofman 8319793a98 [d3d11] Always close handle in D3D11CommonTexture::ExportImageInfo()
For KMT handle openKmtHandle() creates new handle, for NT handle
m_image->sharedHandle() gets duplicated handle from
vkGetMemoryWin32HandleKHR().
2023-07-16 15:34:39 +02:00
Blisto91 886268fcf9 [util] Remove Secret World Legends config 2023-07-16 15:26:46 +02:00
Hans-Kristian Arntzen 84e59fc9e5 [ci] Download glslangValidator.exe directly rather than using choco.
The choco package is extremely outdated and breaks now.
2023-07-16 15:25:21 +02:00
Blisto91 6be1f6d7bd [util] Limit fps in The Incredibles 2023-07-05 20:48:19 +02:00
Joshua Ashton 2f72115f91 [d3d9] Keep 1 presenter per swapchain window
Some apps such as level editors such as Hammer World Editor, some GUI apps/launchers etc use window overrides in presentation.

Previously we'd remake a new surface every time, which was incredibly slow making these apps basically unusable.

Now we keep one surface + swapchain + image views around per window/window override we have, along with the frame latency objs + frame counter.
(Obviously an app may present to multiple windows in a frame, so for frame latency purposes we track that per-window.
2023-07-04 16:44:31 +02:00
Alpyne 026aa49ef8 [util] replaceNaN: Align result
Otherwise _mm_store_ps can fail
2023-07-03 15:36:21 +02:00
Trevonn 3a368f4780 Bladestorm Nightmare - Game speed increases when above 60 FPS outside of missions
The game has 3 v-sync options but doesn't explain what they do.
0 = 60 FPS
1 = Monitor Refresh Rate
2 = 30 FPS

Framerate is capped at 60 in missions and then up to monitor refresh in the main menu and tavern area

This PR would provide a better default experience for people using option 1 with high refresh displays
2023-07-01 17:12:36 +02:00
Tatsuyuki Ishi 2ef41bdbf6 build: Switch symbols to DWARF 4
Since [1], Wine's supports and uses DWARF 4 as default. Make use of it, which
should fix inlined stacks and some other small details.

[1]: https://www.winehq.org/pipermail/wine-devel/2021-November/201333.html
2023-07-01 17:12:18 +02:00
Philip Rebohle 0f4458e173 [dxvk] Remove pending submission counter 2023-06-26 01:37:46 +01:00
Philip Rebohle ccb87d5ea9 [d3d9] Port flush heuristic from D3D11 2023-06-26 01:37:46 +01:00
Alpyne 022bf1d134 [d3d9] Allow changing API name for d3d8 2023-06-24 18:18:38 +01:00
Alpyne d6e7e3e780 [d3d9] Add DxvkD3D8Bridge for d3d8 interop 2023-06-24 17:58:49 +01:00
Blisto91 b77928b6fe [util] Fix Modern Warfare 2 Campaign Remastered config 2023-06-24 13:28:49 +02:00
Philip Rebohle 987df8a487 [util] Filter out internal private ref on object destruction
Closes #3531 for real this time.
2023-06-24 12:45:38 +02:00
Philip Rebohle a7278cdab1 [dxgi] Do not interact with other DXGI objects during swapchain destruction
This trips up Stalker Anomaly for some reason, but initializing an output
is not meaningful anyway in this situation since we either know the output
in question already, or we don't and it cannot be in a non-default state.

Closes #3531.
2023-06-24 12:38:10 +02:00
Joshua Ashton 3b3ebc9350 [d3d9] Rename some members to be clearer 2023-06-24 04:09:04 +01:00
Joshua Ashton 00ae118655 [d3d9] Don't use m_activeRTs in SetPixelShader
These are just textures, not surfaces.
2023-06-24 04:07:19 +01:00
Joshua Ashton 55be12daa5 Revert "[d3d9] Use m_activeRTs in BindFramebuffer"
This is only textures. Oops.

This reverts commit ff65599dba.
2023-06-24 04:06:24 +01:00
Joshua Ashton 0e36a07a93 [d3d9] Don't mark DS as hazardous if depth write is disabled 2023-06-24 03:55:16 +01:00
Joshua Ashton ff65599dba [d3d9] Use m_activeRTs in BindFramebuffer
Can roll in the anyColorWrites this way.
2023-06-24 03:42:54 +01:00
Joshua Ashton 6b60de2d31 [d3d9] Fix unbinding RTs
Fixes a regression with 8560efa3c7 in ND1.

Also more optimized.
2023-06-24 03:41:31 +01:00
Joshua Ashton 362743c1d6 [d3d9] Update DS hazards when PS shader masks change 2023-06-24 02:55:38 +01:00
Joshua Ashton 7f302fc350 [d3d9] Don't mark DS hazards if not used by shader 2023-06-24 02:53:14 +01:00
Philip Rebohle 8704ed7af6 [dxvk] Ignore some pipeline flags when ending render pass 2023-06-22 23:41:24 +02:00
Philip Rebohle 0895858901 [dxvk] Only decrement pending submission count for command submissions
Otherwise we'll underflow the integer and break the D3D9 flush heuristic.
2023-06-22 20:15:42 +02:00
Joshua Ashton 80b27f95bc [d3d9] Fix active hazards RT only being 4 bits 2023-06-22 16:37:09 +01:00
Joshua Ashton a791493d14 [d3d9] Don't rebind AlphaTest when changing RT if not necessary 2023-06-22 16:37:09 +01:00
Joshua Ashton c768196251 [d3d9] Compress hazard state going into CS
This can potentially happen per-draw so make it as small as possible.
2023-06-22 16:37:09 +01:00
Joshua Ashton 3625c5d481 [d3d9] Optimize DS active hazard check
There can only be one DS, so no need to loop over.
2023-06-22 16:37:09 +01:00
Philip Rebohle b3cbe36c08 [dxvk] Apply frame rate limit on presentation timeline
This may reduce latency as we no longer end up stalling subsequent
GPU submissions.
2023-06-22 16:17:03 +02:00
Philip Rebohle 166d90b04c [d3d11] Fix frame latency based on buffer count
We need to ignore the front buffer here since we synchronize after
presentation.
2023-06-22 16:16:30 +02:00
Robin Kertels 60b6e98529 [d3d9] Transition DS too if there's a feedback loop 2023-06-21 15:16:43 +01:00
Robin Kertels a20869fb93 [d3d9] Track textures in m_activeHazardsRT instead of RT
There's 21 textures and only 4 RTs.
Tracking the textures allows us to mask off the active texture bitfield
instead of the active render target one, potentially resulting in fewer iterations.
2023-06-21 15:16:43 +01:00
Philip Rebohle a287566c65 [dxgi] Implement frame statistics based on IDXGIVkSwapChain1 2023-06-21 15:16:37 +02:00
Philip Rebohle 28f48f9fdc [dxgi] Initialize output refresh counts with non-zero values
Matches Windows behaviour.
2023-06-21 15:16:37 +02:00
Philip Rebohle e02a800c33 [d3d11] Implement IDXGIVkSwapChain1 interface for D3D11 swap chain 2023-06-21 15:16:37 +02:00
Philip Rebohle d7fa39c4eb [util] Be more robust against timing weirdness when computing vblank count 2023-06-21 15:16:37 +02:00
Philip Rebohle d1e39be7e7 [dxgi] Add IDXGIVkSwapChain1 interface definition 2023-06-21 15:16:37 +02:00
Philip Rebohle 438c535fe7 [d3d11] Always release frame latency semaphore in Present 2023-06-21 15:16:37 +02:00
Philip Rebohle 7dbe4abb48 [d3d9] Use new presenter signal mechanism for frame pacing 2023-06-21 15:16:37 +02:00
Philip Rebohle e99bc591df [d3d11] Use new presenter signal mechanism for frame latency event 2023-06-21 15:16:37 +02:00
Philip Rebohle 08363edb05 [dxvk] Only synchronize with presents with FIFO present modes 2023-06-21 15:16:37 +02:00
Philip Rebohle 5d1196733b [dxvk] Implement waiting for specific present requests 2023-06-21 15:16:37 +02:00
Philip Rebohle ca3492570c [dxvk] Add functionality to wait for a given present operation 2023-06-21 15:16:37 +02:00
Philip Rebohle 215c4f8f6f [dxvk] Enable VK_KHR_present_id and VK_KHR_present_wait if supported 2023-06-21 15:16:37 +02:00
Robin Kertels 5a1ebfa4ee Revert "[d3d9] Only use direct buffer mapping for DYNAMIC buffers"
This reverts commit 1850819483.
2023-06-20 23:08:52 +01:00
Joshua Ashton 6f87ccdafc [d3d11] Use FORCE_UNORM depth bias representation for UNORM formats 2023-06-20 13:31:48 +01:00
Joshua Ashton b30a4f0cc7 [d3d9] Use FLOAT or FORCE_UNORM depth bias representation 2023-06-20 13:31:48 +01:00
Joshua Ashton 4e9853f608 [dxvk] Expose depth bias representation/exact controls 2023-06-20 13:31:48 +01:00
Joshua Ashton 5fbb0dd4ba [dxvk] Enable EXT_depth_bias_control 2023-06-20 13:31:48 +01:00
Joshua Ashton 77f6f2a84b [include] Bump Vulkan headers to v1.3.254 2023-06-20 13:31:48 +01:00
Alpyne 0b9acf3a25 [util] Add str::split
Used by d3d8
2023-06-20 13:31:17 +01:00
Timo Gurr 211d095ee4 [util] Limit STEINS;GATE ELITE to 60 fps
Intros, menu and ui animations are playing way too fast, also causing
input issues.
2023-06-20 13:27:52 +02:00
Trevonn 77e7e8bfba [util] Report NVIDIA for Star Wars Battlefront as it errors out on AMD 2023-06-20 13:23:52 +02:00
Alpyne 42a0264e69 [build] Fix libdisplay-info
See https://gitlab.freedesktop.org/JoshuaAshton/libdisplay-info/-/merge_requests/4
2023-06-19 21:14:03 +01:00
Alpyne 5d29140f74 [util] replaceNaN: Use unaligned SIMD _mm_loadu_ps
There is no good reason to expect games will have aligned the data they're passing in.
2023-06-19 21:13:37 +01:00
Alpyne 0236e780a7 [d3d9] Fix std::hex in D3D9CommonTexture 2023-06-19 21:02:10 +01:00
Alpyne 24dbcf8fd8 [dxso] Shared code for texbem and bem 2023-06-19 20:59:18 +01:00
Alpyne 404c984f9c [dxso] Implement bem instruction 2023-06-19 20:59:18 +01:00
Alpyne a79772322b [d3d9] Initialize m_mapFlags to 0
Can sometimes get weird default values in there.
2023-06-19 19:52:03 +01:00
Trevonn 36e6a7c2e5 [util] Set maxChunkSize to 1 for GOG and fix EA App exe name
Similar to the other launchers the VRAM goes 600MB+ to 100MB+
2023-06-16 16:28:31 +01:00
Trevonn c5ab5be48d [util] Set maxChunkSize to 1 for EA App
Reduces GPU VRAM usage of EADesktop.exe from 162MB to 6MB
2023-06-15 19:39:28 +01:00
Paul Gofman af9bd16b8d [dxvk] Always reference library in VR extension providers 2023-06-15 19:07:26 +02:00
Winter Snowfall 2c014fdb34 [util] Match on the GOG version of KoF XIII as well 2023-06-15 19:06:45 +02:00
Timo Gurr 6478c10a18 [util] Set maxChunkSize to 1 for Battle.net
Currently when Diablo 4 is running the Battle.net launcher it uses around
600MB of VRAM. Reducing the max chunk size to 1MB reduces the memory usage
to around 150MB.
2023-06-15 19:06:26 +02:00
Philip Rebohle 7388c243d2 [dxvk] Fix incorrect fullScreenExclusive feature check 2023-06-15 17:32:05 +02:00
Lilium bd575a4a46 [d3d11] implement 'clampNegativeLodBias' as a conf option 2023-06-14 20:22:27 +01:00
Lilium 3fce9886f5 [d3d9] implement 'clampNegativeLodBias' as a conf option 2023-06-14 20:22:27 +01:00
Lilium 5d134b877a [d3d9] implement 'samplerLodBias' as a conf option 2023-06-14 20:22:27 +01:00
Robin Kertels c75ed86909 [d3d9] Reset vertex & index buffer in Reset 2023-06-13 22:47:55 +01:00
Robin Kertels d1707026f9 [d3d9] Remove uninitialized device present params 2023-06-13 22:47:55 +01:00
Robin Kertels b8d36eeacc [d3d9] Fix losing auto depth stencil surface 2023-06-13 22:47:55 +01:00
Robin Kertels 8f740c53b4 [d3d9] Remove IsLosable
Redundant.
2023-06-13 22:47:55 +01:00
Robin Kertels 52ac271acb [d3d9] Reject Reset if there's any remaining DEFAULT resources 2023-06-13 14:15:18 +01:00
Robin Kertels a1a91dd766 [d3d9] Fix potential race when discarding systemmem textures 2023-06-11 16:57:17 +01:00
Robin Kertels 22f6246fd6 [util] Fix app profile grouping 2023-06-11 16:57:17 +01:00
Robin Kertels 9d6804e40a [util] Disable direct buffer mapping for Injustice 2023-06-11 16:57:17 +01:00
Robin Kertels 5fd025c513 [d3d9] Rename apitraceMode
It's not just used for apitrace and the new name
is more consistent with the D3D11 equivalent option.
2023-06-11 16:57:17 +01:00
Robin Kertels d9d6316609 [d3d9] Remove allowDiscard hack 2023-06-11 16:57:17 +01:00
Robin Kertels 9b877cf623 [util] Remove D&D - The Temple of Evil workaround
The game uses SWVP, so we don't need an app hack here.
2023-06-11 16:57:17 +01:00
Robin Kertels 2c3f2b9ad1 [d3d9] Ignore DISCARD after device loss 2023-06-11 16:57:17 +01:00
Robin Kertels 1850819483 [d3d9] Only use direct buffer mapping for DYNAMIC buffers
Tests show that buffers with just D3DUSAGE_WRITEONLY are uploaded on Unlock.
2023-06-11 16:57:17 +01:00
Robin Kertels 1db2e3a6ec [util] Re-enable direct buffer mapping for Dark Romance
The game uses SWVP, so we don't need the hack anymore.
2023-06-11 16:57:17 +01:00
Robin Kertels 2efd3f3698 [util] Re-enable direct buffer mapping for RE games
I cannot reproduce the stalls anymore.
2023-06-11 16:57:17 +01:00
Robin Kertels bbaf01d9e6 [d3d9] Force staging buffer mapping for pure SWVP devices 2023-06-11 16:57:17 +01:00
Robin Kertels 4a55047dde [d3d9] Forbid disabling SWVP on a pure SWVP device 2023-06-11 16:57:17 +01:00
Joshua Ashton 3fddc364ee [util] Fix UTF8 encodeTypedChar for 4 byte chars
Some flipped logic here...
2023-06-10 13:58:33 +02:00
Blisto91 f3fb5ba320 [util] Example config wording changes 2023-06-06 13:47:00 -07:00
Philip Rebohle 4d254b13be [dxgi] Unlock presenter lock early during presentation
If SetGammaControl and Present are called at the same time, we'll
otherwise have a deadlock due to reversed lock order.

Fixes #3458.
2023-06-05 17:02:15 +02:00
Joshua Ashton d241daa0b1 [util] Add app profile for Fallout 76 2023-06-05 03:00:53 +02:00
Eric Sullivan 2e70a2b07d [util] Set maxChunkSize to 1 for the Rockstar launcher and social club
Currently when Red Dead Redemption 2 is running the Rockstar launcher,
and social club each use over 600MB of VRAM. The root cause of this is
DXVK creating two memory pools of 256MB for read, and read/write resources.
Reducing the max chunk size to 1MB reduces the memory usage of each to
around 40MB.
2023-06-05 02:17:26 +02:00
Robin Kertels 52f04ca3d4 [d3d9] FF: Fix using wrong texCoord mask 2023-06-04 17:52:18 +01:00
Joshua Ashton c585ea251e [dxso] Respect all PS input elements for registers
Fixes shadows in Test Drive Unlimited 2.

Closes: #3469
2023-06-02 23:12:22 +02:00
Philip Rebohle ab00591297 [dxvk] Introduce dxvk.tearFree option
And replace the old frontend-specific options.
2023-06-01 17:48:51 +02:00
Philip Rebohle 85d52ccb88 [dxvk] Implement dynamic present mode switching
This way, we don't need to recreate the swap chain when the app switches
between vsync enabled and disabled. Currently only works when running
bleeding-edge Gamescope with ENABLE_GAMESCOPE_WSI=1.
2023-06-01 17:48:51 +02:00
Philip Rebohle e6be0cf996 [dxvk] Rework present mode selection for swap chains 2023-06-01 17:48:51 +02:00
Philip Rebohle 1728d9e89d [dxvk] Rework presenter creation to take a DxvkDevice
This way we can easily query available Vulkan features.
2023-06-01 17:48:51 +02:00
Philip Rebohle b1b0abdbbf [dxvk] Move presenter implementation to DXVK module 2023-06-01 17:48:51 +02:00
Philip Rebohle be875cd7e6 [dxvk] Enable VK_EXT_swapchain_maintenance1 and surface_maintenance1 2023-06-01 17:48:51 +02:00
Philip Rebohle 0543956ea0 [meta] Update Vulkan headers 2023-06-01 17:48:51 +02:00
Blisto91 e9e0949717 [meta] Clarify readme setup instructions 2023-05-31 12:58:28 +02:00
WinterSnowfall 8b6cbda6de [d3d9] Properly expose the MaxVertexBlendMatrixIndex capability 2023-05-30 23:56:26 +01:00
Robin Kertels 4b10846008 [dxso] Fix RT mask for SM1 2023-05-26 04:28:49 +01:00
Joshua Ashton e0654977c9 [d3d9] Stub out D3D9On12 interfaces
Closes: #3445
2023-05-24 14:36:45 +01:00
Joshua Ashton b5c18a02ae [d3d9] Optimize UpdateAnyColorWrites for 0th case
This is the most common
2023-05-24 14:21:30 +01:00
Joshua Ashton cafd104783 [d3d9] Pack RT bitmasks tightly
No need to waste a whole 32-bits for each entry here when we only have 4 possible RTs at a time.
2023-05-24 14:10:41 +01:00
Joshua Ashton 269bab2c34 [d3d9] Track if any color writes are enabled for an RT
Use this for determining whether to rebind FB and in checks, otherwise we can miss stuff for pure surface RTs
2023-05-24 14:05:13 +01:00
Joshua Ashton 075c0bf203 [d3d9] Use m_boundRTs for COLORWRITEENABLE checks
Also allows us to check for NULL RTs with this too and avoid extra work!
2023-05-24 13:42:42 +01:00
Joshua Ashton 8560efa3c7 [d3d9] Unbind RTs which are unwritten by a PS
Otherwise we can end up with feedback loops on RTs with a 0 color mask.

Closes: #3447
2023-05-24 13:40:17 +01:00
Blisto91 b9b2db510e [util] Limit fps for some Tomb Raider games 2023-05-24 14:31:38 +02:00
Lilium d5c6ae2e4d [dxvk] dxvk_adapter: implement macro to check for feature need in checkFeatureSupport 2023-05-24 11:53:34 +01:00
Lilium 633f6663a4 [dxvk] fix copy mistake in dxvk_adapter 2023-05-24 11:53:34 +01:00
Robin Kertels d2759c20ba [d3d9+d3d11] Remove DEVICE_LOCAL flag when forcing cached memory
Otherwise DXVK removes both flags at once
and we may end up with uncached memory.
2023-05-22 23:53:01 +02:00
Robin Kertels 1a2e724c16 [util] Enable apitrace mode for Tomb Raider Anniversary
... and Underworld.
2023-05-22 12:24:49 +02:00
Blisto91 6449f583f8 [util] Set dcSingleUseMode to false for SnowRunner 2023-05-21 16:05:41 +02:00
Joshua Ashton f2bb1d4b69 [d3d9] Add extended swapchain interfaces
Allows for controling colorspace, etc.
2023-05-19 19:26:27 +01:00
Joshua Ashton 495dc75ab2 [wsi] Pull out NormalizeDisplayMetadata 2023-05-19 19:26:27 +01:00
Paul Gofman 550e04c579 [dxgi] Preserve system monitor sort order in enumMonitors() 2023-05-19 18:17:40 +02:00
WinterSnowfall d4a7346198 [dxvk] Add configurable HUD opacity 2023-05-19 18:11:25 +02:00
Blisto91 99b367cdd6 [util] Set floatEmulation to Strict for Halo Online 2023-05-18 17:40:01 +01:00
Blisto91 65520fa18e [util] Fix BlazBlue Centralfiction config 2023-05-16 18:56:23 +02:00
Joshua Ashton f30376a1e4 [d3d11] Fix min luminance of HDR Metadata
This should be a multiply instead of a divide. Values are 1/10000th of a nit (0.0001 nit).
2023-05-13 21:16:29 +00:00
197 changed files with 6754 additions and 2728 deletions

View File

@ -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

View File

@ -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.

View File

@ -1 +1 @@
2.2
2.3.1

131
dxvk.conf
View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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@',

View File

@ -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"

View File

@ -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;

View File

@ -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,

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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:

View File

@ -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();
}

View File

@ -37,7 +37,7 @@ namespace dxvk {
if (riid == __uuidof(ID3D10DeviceChild)
|| riid == __uuidof(ID3D10DepthStencilState)) {
*ppvObject = ref(this);
*ppvObject = ref(&m_d3d10);
return S_OK;
}

View File

@ -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;
}

View File

@ -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();
}

View File

@ -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();

View File

@ -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);
}
}

View File

@ -71,6 +71,8 @@ namespace dxvk {
void FlushImplicit();
void FlushInternal();
void SyncKeyedMutex(ID3D11Resource *pResource);
};
}

View File

@ -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);

View File

@ -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;

View File

@ -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

View File

@ -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);

View File

@ -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;
};
}

View File

@ -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;
}
}

View File

@ -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) {

View File

@ -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 {
};
}
}

View File

@ -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;

View File

@ -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;

View File

@ -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);

View File

@ -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;

View File

@ -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();
}

View File

@ -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();

View File

@ -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;
}

View File

@ -77,6 +77,10 @@ namespace dxvk {
return mask;
}
DXGI_FORMAT GetViewFormat() const {
return m_desc.Format;
}
D3D10DepthStencilView* GetD3D10Iface() {
return &m_d3d10;
}

View File

@ -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;
}

View File

@ -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;

View File

@ -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;

View File

@ -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,

View File

@ -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;
}

View File

@ -25,3 +25,6 @@ EXPORTS
DXVK_UnRegisterAnnotation @28258 NONAME
Direct3D9ForceHybridEnumeration @16 NONAME PRIVATE
Direct3DCreate9On12 @20
Direct3DCreate9On12Ex @21

View File

@ -18,6 +18,8 @@
DXVK_RegisterAnnotation;
DXVK_UnRegisterAnnotation;
Direct3D9ForceHybridEnumeration;
Direct3DCreate9On12;
Direct3DCreate9On12Ex;
local:
*;

View File

@ -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,

111
src/d3d9/d3d9_bridge.cpp Normal file
View File

@ -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();
}
}

118
src/d3d9/d3d9_bridge.h Normal file
View File

@ -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;
};
}

View File

@ -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;
}

View File

@ -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;

View File

@ -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);

View File

@ -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;

View File

@ -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

View File

@ -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;
};
}

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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));

View File

@ -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

View File

@ -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;

View File

@ -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;

View File

@ -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

View File

@ -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);
}
}

View File

@ -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() {}

40
src/d3d9/d3d9_on_12.cpp Normal file
View File

@ -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;
}
}

29
src/d3d9/d3d9_on_12.h Normal file
View File

@ -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;
};
}

View File

@ -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;
}

View File

@ -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;
};
}

View File

@ -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:

View File

@ -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

View File

@ -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; }

View File

@ -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();
}
}
}

View File

@ -89,6 +89,8 @@ namespace dxvk {
D3D9StateBlock(D3D9DeviceEx* pDevice, D3D9StateBlockType Type);
~D3D9StateBlock();
HRESULT STDMETHODCALLTYPE QueryInterface(
REFIID riid,
void** ppvObject) final;

View File

@ -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;
}
}

View File

@ -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);

View File

@ -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);

View File

@ -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;
}

View File

@ -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);

View File

@ -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 = {};
};

View File

@ -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 = []

View File

@ -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;
}
}
}

View File

@ -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();

View File

@ -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

View File

@ -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

View File

@ -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;
}

View File

@ -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) {

View File

@ -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;
};
}

View File

@ -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

View File

@ -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;
}
}

View File

@ -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);
};
}

View File

@ -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"

View File

@ -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

View File

@ -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(

View File

@ -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()) {

View File

@ -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;
};
}

View File

@ -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);

View File

@ -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;
}
}

View File

@ -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