Compare commits

...

170 Commits
v2.3 ... master

Author SHA1 Message Date
Robin Kertels 60cfafe027 [d3d9] Fix strange type in dynamic vertex upload 2024-05-26 04:58:47 +00:00
Robin Kertels 889802887f [d3d9] Rework uploading dynamic sysmem buffers at draw time
... and handle mismatching vertex sizes and vertex strides.
2024-05-23 16:44:49 +02:00
WinterSnowfall a1ce690c5c [d3d9] Determine DF format support in the options parser 2024-05-23 16:37:09 +02:00
WinterSnowfall 07d007c642 [d3d9] Use customVendorId to determine the options vendorId 2024-05-23 16:37:09 +02:00
Danylo Piliaiev 58d8ea2d31 [d3d11,d3d9,util] Add a config option for reproducible VK output
It ensures that for the same D3D commands the output VK commands
don't change between runs.

Useful for comparative benchmarking, can negatively affect performance.

Signed-off-by: Danylo Piliaiev <dpiliaiev@igalia.com>
2024-05-23 15:20:28 +02:00
Philip Rebohle 61bd62c327 [dxvk] Allow descriptor pool overallocation if supported 2024-05-23 14:27:28 +02:00
Philip Rebohle 7bc77b597e [dxvk] Enable VK_NV_descriptor_pool_overallocation if available 2024-05-23 14:27:28 +02:00
Simon McVittie 2ff2c826a5 [build] Generate pkg-config metadata to link to DXVK libraries
This allows dependent projects to query the version and location of DXVK
via the pkg-config interface.

The include directories aren't yet set, because the headers aren't
installed; that will follow in a subsequent commit.

The naming of these pkg-config files is based on proposed Fedora packages
for DXVK 2.0, and is not compatible with older Fedora packages for DXVK
1.x (which used the naming convention dxvk-native-d3d9 and so on).
Packagers can create symlinks such as dxvk-native-d3d9.pc -> dxvk-d3d9.pc
if they want to retain compatibility with older names.

Signed-off-by: Simon McVittie <smcv@collabora.com>
2024-05-21 19:18:12 +00:00
Simon McVittie f9b4046223 [build] Install headers for native builds
When building a game that has been ported to Linux using DXVK Native,
these headers are necessary to provide the Direct3D and DXVK APIs.

Signed-off-by: Simon McVittie <smcv@collabora.com>
2024-05-21 19:18:12 +00:00
Simon McVittie 83436a97f2 [meson] Set the stem of library names instead of the name_prefix
This is necessary for compatibility with Meson's pkg module, which
generates pkg-config metadata containing "-lNAME" where NAME is the
first argument to shared_library(). Changing the name_prefix parameter
would break that.

Conversely, including .dll or .so in the first parameter would also
break that, so remove the `+dll_ext` part (in practice this is not a
functional change, because `dll_ext` is always set to an empty string).

Signed-off-by: Simon McVittie <smcv@collabora.com>
2024-05-21 19:18:12 +00:00
Ethan Lee e991bfa604 [ci] Use a tarball for the steamrt-sniper artifact.
Zips can't preserve the symlink, so make the .tar.gz package with package_native.sh and zip that up instead.
2024-05-21 19:18:12 +00:00
Ethan Lee f33453afbb [build] Add soversion to dxvk-native binaries 2024-05-21 19:18:12 +00:00
Robin Kertels 65dd3c7df3 [d3d9] Always enable STORAGE_BUFFER usage
Fixes a validation error. Drivers don't care about buffer usage bits anyway.
2024-05-21 20:32:13 +02:00
Robin Kertels dfc3776b24 [d3d9] FF: Fix a bunch of wine tests with FF texture coordinates 2024-05-21 20:32:13 +02:00
Philip Rebohle 3420cd78ac [dxvk] Use new Version helper to deal with driver version numbers 2024-05-20 18:30:36 +02:00
Philip Rebohle 4225f35034 [util] Add version helper class
Useful to decode, store and compare human-readable driver versions.
2024-05-20 18:30:36 +02:00
Philip Rebohle 2cb2f8694e [dxvk] Use VK_MAKE_API_VERSION instead of VK_MAKE_VERSION.
The old macro is deprecated.
2024-05-20 18:30:36 +02:00
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
156 changed files with 3459 additions and 1578 deletions

View File

@ -54,7 +54,7 @@ jobs:
shell: bash
run: |
export VERSION_NAME="${GITHUB_REF##*/}-${GITHUB_SHA##*/}"
./package-native.sh ${VERSION_NAME} build --no-package
./package-native.sh ${VERSION_NAME} build
echo "VERSION_NAME=${VERSION_NAME}" >> $GITHUB_ENV
- name: Upload artifacts
@ -62,5 +62,5 @@ jobs:
uses: actions/upload-artifact@v3
with:
name: dxvk-${{ env.VERSION_NAME }}
path: build/dxvk-native-${{ env.VERSION_NAME }}
path: build/dxvk-native-${{ env.VERSION_NAME }}.tar.gz
if-no-files-found: error

View File

@ -163,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.3
2.3.1

View File

@ -62,7 +62,7 @@
# Report Nvidia GPUs as AMD GPUs. Unless NVAPI support is explicitly
# enabled through proton, this is done by default in order to work
# 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.
#
@ -71,6 +71,13 @@
# 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.
#
@ -90,6 +97,7 @@
# 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.
@ -292,6 +300,32 @@
# d3d11.enableContextLock = False
# Exposes or hides support for driver command lists
#
# Some games use the feature flag to decide whether to use deferred
# contexts or not. We enable this by default, but in some situations
# this can lead to issues if games detect an AMD GPU where command
# lists are not natively supported on Windows.
#
# Supported values: True, False
# d3d11.exposeDriverCommandLists = True
# Reproducible Command Stream
#
# Ensure that for the same D3D commands the output VK commands
# don't change between runs. Useful for comparative benchmarking,
# can negatively affect performance and can break some games
# that don't use queries correctly.
#
# Supported values:
# - True/False
# d3d11.reproducibleCommandStream = False
# d3d9.reproducibleCommandStream = False
# Sets number of pipeline compiler threads.
#
# If the graphics pipeline library feature is enabled, the given
@ -479,6 +513,7 @@
# Supported values:
# - True/False
# d3d11.longMad = False
# d3d9.longMad = False
# Device Local Constant Buffers
@ -494,7 +529,9 @@
# 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
@ -623,3 +660,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

@ -0,0 +1,19 @@
install_subdir(
'directx',
install_dir: get_option('includedir') / 'dxvk',
strip_directory: true,
exclude_files: '.git'
)
install_subdir(
'windows',
install_dir: get_option('includedir') / 'dxvk',
strip_directory: true,
)
install_headers(
'wsi/native_wsi.h',
'wsi/native_sdl2.h',
'wsi/native_glfw.h',
subdir: 'dxvk/wsi',
)

View File

@ -48,7 +48,6 @@ typedef const void* LPCVOID;
typedef size_t SIZE_T;
typedef int8_t INT8;
typedef uint8_t UINT8;
typedef uint8_t BYTE;
@ -56,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;
@ -330,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 85c2334e92e215cce34e8e0ed8b2dce4700f4a50
Subproject commit 46dc0f6e514f5730784bb2cac2a7c731636839e8

View File

@ -1,11 +1,13 @@
project('dxvk', ['c', 'cpp'], version : 'v2.3', 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' ])
pkg = import('pkgconfig')
cpu_family = target_machine.cpu_family()
platform = target_machine.system()
fs = import('fs')
cpp = meson.get_compiler('cpp')
cc = meson.get_compiler('c')
dxvk_is_msvc = cpp.get_id() == 'msvc'
dxvk_is_msvc = cpp.get_argument_syntax() == 'msvc'
compiler_args = [
'-msse',
@ -33,42 +35,60 @@ if get_option('build_id')
]
endif
dxvk_include_dirs = [
'./include',
'./include/vulkan/include',
'./include/spirv/include'
]
dxvk_include_dirs = ['./include']
if fs.is_dir('./include/vulkan/include')
dxvk_include_dirs += ['./include/vulkan/include']
elif not cpp.check_header('vulkan/vulkan.h')
error('Missing Vulkan-Headers')
endif
if fs.is_dir('./include/spirv/include')
dxvk_include_dirs += ['./include/spirv/include']
elif not cpp.check_header('spirv/unified1/spirv.hpp')
error('Missing SPIRV-Headers')
endif
proj_displayinfo = subproject('libdisplay-info')
dep_displayinfo = proj_displayinfo.get_variable('di_dep')
dep_displayinfo = dependency(
'libdisplay-info',
version: ['>= 0.0.0', '< 0.2.0'],
fallback: ['libdisplay-info', 'di_dep'],
default_options: ['default_library=static'],
)
if platform == 'windows'
dxvk_so_version = {'name_prefix': ''}
compiler_args += [
'-DNOMINMAX',
'-D_WIN32_WINNT=0xa00',
]
link_args += [
'-static',
'-static-libgcc',
'-static-libstdc++',
# We need to set the section alignment for debug symbols to
# work properly as well as avoiding a memcpy from the Wine loader.
'-Wl,--file-alignment=4096',
]
# Wine's built-in back traces only work with dwarf4 symbols
if get_option('debug')
compiler_args += [
'-gdwarf-4',
]
endif
# Enable stdcall fixup on 32-bit
if cpu_family == 'x86'
if not dxvk_is_msvc
link_args += [
'-Wl,--enable-stdcall-fixup',
'-Wl,--kill-at',
'-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
@ -98,10 +118,13 @@ if platform == 'windows'
)
endif
dxvk_wsi = 'win32'
dxvk_name_prefix = ''
compiler_args += ['-DDXVK_WSI_WIN32']
else
dxvk_abi_version = '0'
dxvk_version = meson.project_version().strip('v').split('.')
dxvk_so_version = {'version': dxvk_abi_version + '.' + dxvk_version[0] + dxvk_version[1] + dxvk_version[2]}
wrc = find_program('touch')
wrc_generator = generator(wrc, output : [ '@BASENAME@_ignored.h' ], arguments : [ '@OUTPUT@' ] )
@ -111,17 +134,20 @@ 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_'
dxvk_name_prefix = 'dxvk_'
dxvk_pkg_prefix = 'dxvk-'
link_args += [
'-static-libgcc',
@ -137,13 +163,12 @@ add_project_link_arguments(cpp.get_supported_link_arguments(link_args), language
add_project_link_arguments(cc.get_supported_link_arguments(link_args), language: 'c')
exe_ext = ''
dll_ext = ''
def_spec_ext = '.def'
glsl_compiler = find_program('glslang', 'glslangValidator')
glsl_args = [
'--quiet',
'--target-env', 'vulkan1.2',
'--target-env', 'vulkan1.3',
'--vn', '@BASENAME@',
'--depfile', '@DEPFILE@',
'@INPUT@',
@ -162,4 +187,8 @@ dxvk_version = vcs_tag(
output: 'version.h',
)
if platform != 'windows'
subdir('include/native')
endif
subdir('src')

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

@ -15,16 +15,23 @@ else
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,
d3d10_core_dll = shared_library(dxvk_name_prefix+'d3d10core', d3d10_core_src, d3d10_core_res,
dependencies : [ d3d10_d3d11_dep ],
include_directories : dxvk_include_path,
install : true,
vs_module_defs : 'd3d10core'+def_spec_ext,
link_args : d3d10_core_ld_args,
link_depends : [ d3d10_core_link_depends ],
kwargs : dxvk_so_version,
)
d3d10_core_dep = declare_dependency(
link_with : [ d3d10_core_dll ],
)
if platform != 'windows'
pkg.generate(d3d10_core_dll,
filebase: dxvk_pkg_prefix + 'd3d10core',
subdirs: 'dxvk',
)
endif

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;

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

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

@ -19,6 +19,7 @@ namespace dxvk {
m_csThread(Device, Device->createContext(DxvkContextType::Primary)),
m_maxImplicitDiscardSize(pParent->GetOptions()->maxImplicitDiscardSize),
m_submissionFence(new sync::CallbackFence()),
m_flushTracker(pParent->GetOptions()->reproducibleCommandStream),
m_multithread(this, false, pParent->GetOptions()->enableContextLock),
m_videoContext(this, Device) {
EmitCs([

View File

@ -89,6 +89,10 @@ namespace dxvk {
void SynchronizeCsThread(
uint64_t SequenceNumber);
D3D10Multithread& GetMultithread() {
return m_multithread;
}
D3D10DeviceLock LockContext() {
return m_multithread.AcquireLock();
}

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

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

@ -38,7 +38,7 @@ extern "C" {
DXGI_ADAPTER_DESC desc;
pAdapter->GetDesc(&desc);
dxvkInstance = new DxvkInstance();
dxvkInstance = new DxvkInstance(0);
dxvkAdapter = dxvkInstance->findAdapterByLuid(&desc.AdapterLuid);
if (dxvkAdapter == nullptr)
@ -376,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);
@ -31,7 +31,9 @@ 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->exposeDriverCommandLists = config.getOption<bool>("d3d11.exposeDriverCommandLists", true);
this->longMad = config.getOption<bool>("d3d11.longMad", false);
this->reproducibleCommandStream = config.getOption<bool>("d3d11.reproducibleCommandStream", false);
// Clamp LOD bias so that people don't abuse this in unintended ways
this->samplerLodBias = dxvk::fclamp(this->samplerLodBias, -2.0f, 1.0f);

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
///
@ -76,10 +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;
/// Override maximum frame latency if the app specifies
/// a higher value. May help with frame timing issues.
int32_t maxFrameLatency;
@ -117,8 +113,21 @@ 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;
/// Ensure that for the same D3D commands the output VK commands
/// don't change between runs. Useful for comparative benchmarking,
/// can negatively affect performance.
bool reproducibleCommandStream;
};
}

View File

@ -9,11 +9,10 @@
namespace dxvk {
D3D11DXGIKeyedMutex::D3D11DXGIKeyedMutex(
ID3D11Resource* pResource)
: m_resource(pResource) {
Com<ID3D11Device> device;
m_resource->GetDevice(&device);
m_device = static_cast<D3D11Device*>(device.ptr());
ID3D11Resource* pResource,
D3D11Device* pDevice)
: m_resource(pResource),
m_device(pDevice) {
m_supported = m_device->GetDXVKDevice()->features().khrWin32KeyedMutex
&& m_device->GetDXVKDevice()->vkd()->wine_vkAcquireKeyedMutex != nullptr
@ -112,7 +111,17 @@ namespace dxvk {
D3D11CommonTexture* texture = GetCommonTexture(m_resource);
Rc<DxvkDevice> dxvkDevice = m_device->GetDXVKDevice();
m_device->GetContext()->WaitForResource(texture->GetImage(), DxvkCsThread::SynchronizeAll, D3D11_MAP_READ_WRITE, 0);
{
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
@ -120,9 +129,10 @@ namespace dxvk {
}
D3D11DXGIResource::D3D11DXGIResource(
ID3D11Resource* pResource)
ID3D11Resource* pResource,
D3D11Device* pDevice)
: m_resource(pResource),
m_keyedMutex(pResource) {
m_keyedMutex(pResource, pDevice) {
}

View File

@ -30,7 +30,8 @@ namespace dxvk {
public:
D3D11DXGIKeyedMutex(
ID3D11Resource* pResource);
ID3D11Resource* pResource,
D3D11Device* pDevice);
~D3D11DXGIKeyedMutex();
@ -88,7 +89,8 @@ namespace dxvk {
public:
D3D11DXGIResource(
ID3D11Resource* pResource);
ID3D11Resource* pResource,
D3D11Device* pDevice);
~D3D11DXGIResource();

View File

@ -254,11 +254,6 @@ 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))
m_dirty |= m_presenter->setSyncInterval(SyncInterval) != VK_SUCCESS;

View File

@ -58,9 +58,6 @@ namespace dxvk {
"\n MiscFlags: ", m_desc.MiscFlags,
"\n FeatureLevel: ", pDevice->GetFeatureLevel()));
if (m_desc.MiscFlags & D3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX)
Logger::warn("D3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX: not supported.");
imageInfo.shared = true;
imageInfo.sharing.mode = hSharedHandle == INVALID_HANDLE_VALUE ? DxvkSharedHandleMode::Export : DxvkSharedHandleMode::Import;
imageInfo.sharing.type = (m_desc.MiscFlags & D3D11_RESOURCE_MISC_SHARED_NTHANDLE)
@ -214,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(
@ -1099,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) {
}
@ -1205,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) {
}
@ -1220,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) {
@ -1236,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) {
@ -1384,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) {
}

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

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

@ -77,18 +77,25 @@ else
d3d11_dxgi_dep = dxgi_dep
endif
d3d11_dll = shared_library('d3d11'+dll_ext, dxgi_common_src + d3d11_src + d3d10_src,
d3d11_dll = shared_library(dxvk_name_prefix+'d3d11', dxgi_common_src + d3d11_src + d3d10_src,
glsl_generator.process(d3d11_shaders), d3d11_res,
name_prefix : dxvk_name_prefix,
dependencies : [ d3d11_dxgi_dep, dxbc_dep, dxvk_dep ],
include_directories : dxvk_include_path,
install : true,
vs_module_defs : 'd3d11'+def_spec_ext,
link_args : d3d11_ld_args,
link_depends : [ d3d11_link_depends ],
kwargs : dxvk_so_version,
)
d3d11_dep = declare_dependency(
link_with : [ d3d11_dll ],
include_directories : [ dxvk_include_path ],
)
if platform != 'windows'
pkg.generate(d3d11_dll,
filebase: dxvk_pkg_prefix + 'd3d11',
subdirs: 'dxvk',
)
endif

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

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

View File

@ -32,6 +32,10 @@ namespace dxvk {
m_device->m_implicitSwapchain->SetApiName(name);
}
void DxvkD3D8Bridge::SetD3D8CompatibilityMode(const bool compatMode) {
m_device->SetD3D8CompatibilityMode(compatMode);
}
HRESULT DxvkD3D8Bridge::UpdateTextureFromBuffer(
IDirect3DSurface9* pDestSurface,
IDirect3DSurface9* pSrcSurface,
@ -104,4 +108,4 @@ namespace dxvk {
const Config* DxvkD3D8InterfaceBridge::GetConfig() const {
return &m_interface->GetInstance()->config();
}
}
}

View File

@ -30,6 +30,13 @@ IDxvkD3D8Bridge : public IUnknown {
*/
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
*
@ -58,10 +65,7 @@ IDxvkD3D8InterfaceBridge : public IUnknown {
virtual const dxvk::Config* GetConfig() const = 0;
};
#if defined(_MSC_VER)
struct DECLSPEC_UUID("D3D9D3D8-42A9-4C1E-AA97-BEEFCAFE2000") IDxvkD3D8Bridge;
struct DECLSPEC_UUID("D3D9D3D8-A407-773E-18E9-CAFEBEEF3000") IDxvkD3D8InterfaceBridge;
#else
#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
@ -83,6 +87,7 @@ namespace dxvk {
void** ppvObject);
void SetAPIName(const char* name);
void SetD3D8CompatibilityMode(const bool compatMode);
HRESULT UpdateTextureFromBuffer(
IDirect3DSurface9* pDestSurface,

View File

@ -125,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() {
@ -206,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;

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);
@ -117,6 +118,7 @@ namespace dxvk {
HRESULT D3D9CommonTexture::NormalizeTextureProperties(
D3D9DeviceEx* pDevice,
D3DRESOURCETYPE ResourceType,
D3D9_COMMON_TEXTURE_DESC* pDesc) {
auto* options = pDevice->GetOptions();
@ -130,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

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);
/**

View File

@ -13,7 +13,7 @@ namespace dxvk {
DxsoProgramType ShaderStage,
DxsoConstantBuffers BufferType,
VkDeviceSize Size)
: D3D9ConstantBuffer(pDevice, getBufferUsage(pDevice, ShaderStage, BufferType), GetShaderStage(ShaderStage),
: D3D9ConstantBuffer(pDevice, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, GetShaderStage(ShaderStage),
computeResourceSlotId(ShaderStage, DxsoBindingType::ConstantBuffer, BufferType),
Size) {
@ -135,21 +135,4 @@ namespace dxvk {
device->properties().extRobustness2.robustUniformBufferAccessSizeAlignment);
}
VkBufferUsageFlags D3D9ConstantBuffer::getBufferUsage(
D3D9DeviceEx* pDevice,
DxsoProgramType ShaderStage,
DxsoConstantBuffers BufferType) {
VkBufferUsageFlags result = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT;
// We won't always need this, but the only buffer that
// this applies to is so large that it will not matter.
if (pDevice->CanSWVP()
&& ShaderStage == DxsoProgramType::VertexShader
&& BufferType == DxsoConstantBuffers::VSConstantBuffer)
result |= VK_BUFFER_USAGE_STORAGE_BUFFER_BIT;
return result;
}
}

View File

@ -80,11 +80,6 @@ namespace dxvk {
VkDeviceSize getAlignment(const Rc<DxvkDevice>& device) const;
static VkBufferUsageFlags getBufferUsage(
D3D9DeviceEx* pDevice,
DxsoProgramType ShaderStage,
DxsoConstantBuffers BufferType);
};
}

View File

@ -56,6 +56,7 @@ namespace dxvk {
, m_csThread ( dxvkDevice, dxvkDevice->createContext(DxvkContextType::Primary) )
, m_csChunk ( AllocCsChunk() )
, m_submissionFence (new sync::Fence())
, m_flushTracker (m_d3d9Options.reproducibleCommandStream)
, m_d3d9Interop ( this )
, m_d3d9On12 ( this )
, m_d3d8Bridge ( this ) {
@ -455,6 +456,8 @@ namespace dxvk {
SetDepthStencilSurface(nullptr);
}
m_flags.clr(D3D9DeviceFlag::InScene);
/*
* Before calling the IDirect3DDevice9::Reset method for a device,
* an application should release any explicit render targets,
@ -464,7 +467,7 @@ namespace dxvk {
* We have to check after ResetState clears the references held by SetTexture, etc.
* This matches what Windows D3D9 does.
*/
if (unlikely(m_losableResourceCounter.load() != 0 && !IsExtended())) {
if (unlikely(m_losableResourceCounter.load() != 0 && !IsExtended() && m_d3d9Options.countLosableResources)) {
Logger::warn(str::format("Device reset failed because device still has alive losable resources: Device not reset. Remaining resources: ", m_losableResourceCounter.load()));
m_deviceLostState = D3D9DeviceLostState::NotReset;
return D3DERR_INVALIDCALL;
@ -479,9 +482,20 @@ namespace dxvk {
return hr;
}
// Unbind all buffers that were still bound to the backend to avoid leaks.
EmitCs([](DxvkContext* ctx) {
ctx->bindIndexBuffer(DxvkBufferSlice(), VK_INDEX_TYPE_UINT32);
for (uint32_t i = 0; i < caps::MaxStreams; i++) {
ctx->bindVertexBuffer(i, DxvkBufferSlice(), 0);
}
});
Flush();
SynchronizeCsThread(DxvkCsThread::SynchronizeAll);
if (m_d3d9Options.deferSurfaceCreation)
m_deviceHasBeenReset = true;
return D3D_OK;
}
@ -581,7 +595,7 @@ namespace dxvk {
|| (Usage & D3DUSAGE_DYNAMIC)
|| IsVendorFormat(EnumerateFormat(Format));
if (FAILED(D3D9CommonTexture::NormalizeTextureProperties(this, &desc)))
if (FAILED(D3D9CommonTexture::NormalizeTextureProperties(this, D3DRTYPE_TEXTURE, &desc)))
return D3DERR_INVALIDCALL;
try {
@ -651,7 +665,7 @@ namespace dxvk {
|| (Usage & D3DUSAGE_DYNAMIC)
|| IsVendorFormat(EnumerateFormat(Format));
if (FAILED(D3D9CommonTexture::NormalizeTextureProperties(this, &desc)))
if (FAILED(D3D9CommonTexture::NormalizeTextureProperties(this, D3DRTYPE_VOLUMETEXTURE, &desc)))
return D3DERR_INVALIDCALL;
try {
@ -708,7 +722,7 @@ namespace dxvk {
|| (Usage & D3DUSAGE_DYNAMIC)
|| IsVendorFormat(EnumerateFormat(Format));
if (FAILED(D3D9CommonTexture::NormalizeTextureProperties(this, &desc)))
if (FAILED(D3D9CommonTexture::NormalizeTextureProperties(this, D3DRTYPE_CUBETEXTURE, &desc)))
return D3DERR_INVALIDCALL;
try {
@ -1034,6 +1048,9 @@ namespace dxvk {
if (srcTexInfo->Desc()->Format != dstTexInfo->Desc()->Format)
return D3DERR_INVALIDCALL;
if (src->GetSurfaceExtent() != dst->GetSurfaceExtent())
return D3DERR_INVALIDCALL;
if (dstTexInfo->Desc()->Pool == D3DPOOL_DEFAULT)
return this->StretchRect(pRenderTarget, nullptr, pDestSurface, nullptr, D3DTEXF_NONE);
@ -1077,7 +1094,12 @@ namespace dxvk {
if (unlikely(iSwapChain != 0))
return D3DERR_INVALIDCALL;
return m_implicitSwapchain->GetFrontBufferData(pDestSurface);
D3D9DeviceLock lock = LockDevice();
// In windowed mode, GetFrontBufferData takes a screenshot of the entire screen.
// We use the last used swapchain as a workaround.
// Total War: Medieval 2 relies on this.
return m_mostRecentlyUsedSwapchain->GetFrontBufferData(pDestSurface);
}
@ -1595,6 +1617,23 @@ namespace dxvk {
m_flags.clr(D3D9DeviceFlag::InScene);
// D3D9 resets the internally bound vertex buffers and index buffer in EndScene if they were unbound in the meantime.
// We have to ignore unbinding those buffers because of Operation Flashpoint Red River,
// so we should also clear the bindings here, to avoid leaks.
if (m_state.indices == nullptr) {
EmitCs([](DxvkContext* ctx) {
ctx->bindIndexBuffer(DxvkBufferSlice(), VK_INDEX_TYPE_UINT32);
});
}
for (uint32_t i = 0; i < caps::MaxStreams; i++) {
if (m_state.vertexBuffers[i].vertexBuffer == nullptr) {
EmitCs([cIndex = i](DxvkContext* ctx) {
ctx->bindVertexBuffer(cIndex, DxvkBufferSlice(), 0);
});
}
}
return D3D_OK;
}
@ -2360,7 +2399,8 @@ namespace dxvk {
try {
const Com<D3D9StateBlock> sb = new D3D9StateBlock(this, ConvertStateBlockType(Type));
*ppSB = sb.ref();
m_losableResourceCounter++;
if (!m_isD3D8Compatible)
m_losableResourceCounter++;
return D3D_OK;
}
@ -2392,7 +2432,8 @@ namespace dxvk {
return D3DERR_INVALIDCALL;
*ppSB = m_recorder.ref();
m_losableResourceCounter++;
if (!m_isD3D8Compatible)
m_losableResourceCounter++;
m_recorder = nullptr;
return D3D_OK;
@ -2610,7 +2651,21 @@ namespace dxvk {
if (unlikely(!PrimitiveCount))
return S_OK;
PrepareDraw(PrimitiveType);
bool dynamicSysmemVBOs;
uint32_t firstIndex = 0;
int32_t baseVertexIndex = 0;
uint32_t vertexCount = GetVertexCount(PrimitiveType, PrimitiveCount);
UploadDynamicSysmemBuffers(
StartVertex,
vertexCount,
firstIndex,
0,
baseVertexIndex,
&dynamicSysmemVBOs,
nullptr
);
PrepareDraw(PrimitiveType, !dynamicSysmemVBOs, false);
EmitCs([this,
cPrimType = PrimitiveType,
@ -2631,7 +2686,6 @@ namespace dxvk {
return D3D_OK;
}
HRESULT STDMETHODCALLTYPE D3D9DeviceEx::DrawIndexedPrimitive(
D3DPRIMITIVETYPE PrimitiveType,
INT BaseVertexIndex,
@ -2647,7 +2701,20 @@ namespace dxvk {
if (unlikely(!PrimitiveCount))
return S_OK;
PrepareDraw(PrimitiveType);
bool dynamicSysmemVBOs;
bool dynamicSysmemIBO;
uint32_t indexCount = GetVertexCount(PrimitiveType, PrimitiveCount);
UploadDynamicSysmemBuffers(
MinVertexIndex,
NumVertices,
StartIndex,
indexCount,
BaseVertexIndex,
&dynamicSysmemVBOs,
&dynamicSysmemIBO
);
PrepareDraw(PrimitiveType, !dynamicSysmemVBOs, !dynamicSysmemIBO);
EmitCs([this,
cPrimType = PrimitiveType,
@ -2683,7 +2750,7 @@ namespace dxvk {
if (unlikely(!PrimitiveCount))
return S_OK;
PrepareDraw(PrimitiveType);
PrepareDraw(PrimitiveType, false, false);
uint32_t vertexCount = GetVertexCount(PrimitiveType, PrimitiveCount);
@ -2735,7 +2802,7 @@ namespace dxvk {
if (unlikely(!PrimitiveCount))
return S_OK;
PrepareDraw(PrimitiveType);
PrepareDraw(PrimitiveType, false, false);
uint32_t vertexCount = GetVertexCount(PrimitiveType, PrimitiveCount);
@ -2822,7 +2889,7 @@ namespace dxvk {
D3D9CommonBuffer* dst = static_cast<D3D9VertexBuffer*>(pDestBuffer)->GetCommonBuffer();
D3D9VertexDecl* decl = static_cast<D3D9VertexDecl*> (pVertexDecl);
PrepareDraw(D3DPT_FORCE_DWORD);
PrepareDraw(D3DPT_FORCE_DWORD, true, true);
if (decl == nullptr) {
DWORD FVF = dst->Desc()->FVF;
@ -2837,7 +2904,7 @@ namespace dxvk {
decl = iter->second.ptr();
}
uint32_t offset = DestIndex * decl->GetSize();
uint32_t offset = DestIndex * decl->GetSize(0);
auto slice = dst->GetBufferSlice<D3D9_COMMON_BUFFER_TYPE_REAL>();
slice = slice.subSlice(offset, slice.length() - offset);
@ -2884,7 +2951,7 @@ namespace dxvk {
}
if (dst->GetMapMode() == D3D9_COMMON_BUFFER_MAP_MODE_BUFFER) {
uint32_t copySize = VertexCount * decl->GetSize();
uint32_t copySize = VertexCount * decl->GetSize(0);
EmitCs([
cSrcBuffer = dst->GetBuffer<D3D9_COMMON_BUFFER_TYPE_REAL>(),
@ -3220,6 +3287,11 @@ namespace dxvk {
vbo.offset = OffsetInBytes;
vbo.stride = Stride;
} else {
// D3D9 doesn't actually unbind any vertex buffer when passing null.
// Operation Flashpoint: Red River relies on this behavior.
needsUpdate = false;
vbo.offset = 0;
}
if (needsUpdate)
@ -3325,7 +3397,8 @@ namespace dxvk {
m_state.indices = buffer;
BindIndices();
if (buffer != nullptr)
BindIndices();
return D3D_OK;
}
@ -3726,7 +3799,7 @@ namespace dxvk {
desc.IsAttachmentOnly = TRUE;
desc.IsLockable = Lockable;
if (FAILED(D3D9CommonTexture::NormalizeTextureProperties(this, &desc)))
if (FAILED(D3D9CommonTexture::NormalizeTextureProperties(this, D3DRTYPE_TEXTURE, &desc)))
return D3DERR_INVALIDCALL;
try {
@ -3774,7 +3847,7 @@ namespace dxvk {
// Docs: Off-screen plain surfaces are always lockable, regardless of their pool types.
desc.IsLockable = TRUE;
if (FAILED(D3D9CommonTexture::NormalizeTextureProperties(this, &desc)))
if (FAILED(D3D9CommonTexture::NormalizeTextureProperties(this, D3DRTYPE_TEXTURE, &desc)))
return D3DERR_INVALIDCALL;
if (pSharedHandle != nullptr && Pool != D3DPOOL_DEFAULT)
@ -3829,7 +3902,7 @@ namespace dxvk {
// Docs don't say anything, so just assume it's lockable.
desc.IsLockable = TRUE;
if (FAILED(D3D9CommonTexture::NormalizeTextureProperties(this, &desc)))
if (FAILED(D3D9CommonTexture::NormalizeTextureProperties(this, D3DRTYPE_TEXTURE, &desc)))
return D3DERR_INVALIDCALL;
try {
@ -5087,6 +5160,191 @@ namespace dxvk {
}
void D3D9DeviceEx::UploadDynamicSysmemBuffers(
UINT& FirstVertexIndex,
UINT NumVertices,
UINT& FirstIndex,
UINT NumIndices,
INT& BaseVertexIndex,
bool* pDynamicVBOs,
bool* pDynamicIBO
) {
bool dynamicSysmemVBOs = true;
for (uint32_t i = 0; i < caps::MaxStreams && dynamicSysmemVBOs; i++) {
auto* vbo = GetCommonBuffer(m_state.vertexBuffers[i].vertexBuffer);
dynamicSysmemVBOs &= vbo == nullptr || vbo->IsSysmemDynamic();
}
D3D9CommonBuffer* ibo = GetCommonBuffer(m_state.indices);
bool dynamicSysmemIBO = NumIndices != 0 && ibo != nullptr && ibo->IsSysmemDynamic();
*pDynamicVBOs = dynamicSysmemVBOs;
if (pDynamicIBO)
*pDynamicIBO = dynamicSysmemIBO;
if (likely(!dynamicSysmemVBOs && !dynamicSysmemIBO))
return;
// The UP buffer allocator will invalidate,
// so we can only use 1 UP buffer slice per draw.
// First we calculate the size of that UP buffer slice
// and store all sizes and offsets into it.
struct VBOCopy {
uint32_t srcOffset;
uint32_t dstOffset;
uint32_t copyBufferLength;
uint32_t copyElementCount;
uint32_t copyElementSize;
uint32_t copyElementStride;
};
uint32_t totalUpBufferSize = 0;
std::array<VBOCopy, caps::MaxStreams> vboCopies = {};
for (uint32_t i = 0; i < caps::MaxStreams && dynamicSysmemVBOs; i++) {
auto* vbo = GetCommonBuffer(m_state.vertexBuffers[i].vertexBuffer);
if (likely(vbo == nullptr)) {
continue;
}
const uint32_t vertexSize = m_state.vertexDecl->GetSize(i);
const uint32_t vertexStride = m_state.vertexBuffers[i].stride;
const uint32_t srcStride = vertexStride;
const uint32_t dstStride = std::min(vertexStride, vertexSize);
uint32_t elementCount = NumVertices;
if (m_state.streamFreq[i] & D3DSTREAMSOURCE_INSTANCEDATA) {
elementCount = GetInstanceCount();
}
const uint32_t vboOffset = m_state.vertexBuffers[i].offset;
const uint32_t vertexOffset = (FirstVertexIndex + BaseVertexIndex) * srcStride;
const uint32_t vertexBufferSize = vbo->Desc()->Size;
const uint32_t srcOffset = vboOffset + vertexOffset;
if (unlikely(srcOffset > vertexBufferSize)) {
// All vertices are out of bounds
vboCopies[i].copyBufferLength = 0;
} else if (unlikely(srcOffset + elementCount * srcStride > vertexBufferSize)) {
// Some vertices are (partially) out of bounds
uint32_t boundVertexBufferRange = vertexBufferSize - vboOffset;
elementCount = boundVertexBufferRange / srcStride;
// Copy all complete vertices
vboCopies[i].copyBufferLength = elementCount * dstStride;
// Copy the remaining partial vertex
vboCopies[i].copyBufferLength += std::min(dstStride, boundVertexBufferRange % srcStride);
} else {
// No vertices are out of bounds
vboCopies[i].copyBufferLength = elementCount * dstStride;
}
vboCopies[i].copyElementCount = elementCount;
vboCopies[i].copyElementStride = srcStride;
vboCopies[i].copyElementSize = dstStride;
vboCopies[i].srcOffset = srcOffset;
vboCopies[i].dstOffset = totalUpBufferSize;
totalUpBufferSize += vboCopies[i].copyBufferLength;
}
uint32_t iboUPBufferSize = 0;
uint32_t iboUPBufferOffset = 0;
if (dynamicSysmemIBO) {
auto* ibo = GetCommonBuffer(m_state.indices);
if (likely(ibo != nullptr)) {
uint32_t indexStride = ibo->Desc()->Format == D3D9Format::INDEX16 ? 2 : 4;
uint32_t offset = indexStride * FirstIndex;
uint32_t indexBufferSize = ibo->Desc()->Size;
if (offset < indexBufferSize) {
iboUPBufferSize = std::min(NumIndices * indexStride, indexBufferSize - offset);
iboUPBufferOffset = totalUpBufferSize;
totalUpBufferSize += iboUPBufferSize;
}
}
}
if (unlikely(totalUpBufferSize == 0)) {
*pDynamicVBOs = false;
if (pDynamicIBO)
*pDynamicIBO = false;
return;
}
auto upSlice = AllocUPBuffer(totalUpBufferSize);
// Now copy the actual data and bind it.
for (uint32_t i = 0; i < caps::MaxStreams && dynamicSysmemVBOs; i++) {
const VBOCopy& copy = vboCopies[i];
if (likely(copy.copyBufferLength != 0)) {
const auto* vbo = GetCommonBuffer(m_state.vertexBuffers[i].vertexBuffer);
uint8_t* data = reinterpret_cast<uint8_t*>(upSlice.mapPtr) + copy.dstOffset;
const uint8_t* src = reinterpret_cast<uint8_t*>(vbo->GetMappedSlice().mapPtr) + copy.srcOffset;
if (likely(copy.copyElementStride == copy.copyElementSize)) {
std::memcpy(data, src, copy.copyBufferLength);
} else {
for (uint32_t j = 0; j < copy.copyElementCount; j++) {
std::memcpy(data + j * copy.copyElementSize, src + j * copy.copyElementStride, copy.copyElementSize);
}
if (unlikely(copy.copyBufferLength > copy.copyElementCount * copy.copyElementSize)) {
// Partial vertex at the end
std::memcpy(
data + copy.copyElementCount * copy.copyElementSize,
src + copy.copyElementCount * copy.copyElementStride,
copy.copyBufferLength - copy.copyElementCount * copy.copyElementSize);
}
}
}
auto vboSlice = upSlice.slice.subSlice(copy.dstOffset, copy.copyBufferLength);
EmitCs([
cStream = i,
cBufferSlice = std::move(vboSlice),
cStride = copy.copyElementSize
](DxvkContext* ctx) mutable {
ctx->bindVertexBuffer(cStream, std::move(cBufferSlice), cStride);
});
m_flags.set(D3D9DeviceFlag::DirtyVertexBuffers);
}
// Change the draw call parameters to reflect the changed vertex buffers
if (NumIndices != 0) {
BaseVertexIndex = -FirstVertexIndex;
} else {
FirstVertexIndex = 0;
}
if (dynamicSysmemIBO) {
if (unlikely(iboUPBufferSize == 0)) {
EmitCs([](DxvkContext* ctx) {
ctx->bindIndexBuffer(DxvkBufferSlice(), VK_INDEX_TYPE_UINT32);
});
m_flags.set(D3D9DeviceFlag::DirtyIndexBuffer);
} else {
auto* ibo = GetCommonBuffer(m_state.indices);
uint32_t indexStride = ibo->Desc()->Format == D3D9Format::INDEX16 ? 2 : 4;
VkIndexType indexType = DecodeIndexType(ibo->Desc()->Format);
uint32_t offset = indexStride * FirstIndex;
uint8_t* data = reinterpret_cast<uint8_t*>(upSlice.mapPtr) + iboUPBufferOffset;
uint8_t* src = reinterpret_cast<uint8_t*>(ibo->GetMappedSlice().mapPtr) + offset;
std::memcpy(data, src, iboUPBufferSize);
auto iboSlice = upSlice.slice.subSlice(iboUPBufferOffset, iboUPBufferSize);
EmitCs([
cBufferSlice = std::move(iboSlice),
cIndexType = indexType
](DxvkContext* ctx) mutable {
ctx->bindIndexBuffer(std::move(cBufferSlice), cIndexType);
});
m_flags.set(D3D9DeviceFlag::DirtyIndexBuffer);
}
// Change the draw call parameters to reflect the changed index buffer
FirstIndex = 0;
}
}
void D3D9DeviceEx::EmitCsChunk(DxvkCsChunkRef&& chunk) {
m_csSeqNum = m_csThread.dispatchChunk(std::move(chunk));
}
@ -5133,7 +5391,7 @@ namespace dxvk {
// Round to nearest
_controlfp(_RC_NEAR, _MCW_RC);
#elif (defined(__GNUC__) || defined(__MINGW32__)) && (defined(__i386__) || defined(__x86_64__) || defined(__ia64))
#elif (defined(__GNUC__) || defined(__MINGW32__)) && (defined(__i386__) || (defined(__x86_64__) && !defined(__arm64ec__)) || defined(__ia64))
// For GCC/MinGW we can use inline asm to set it.
// This only works for x86 and x64 processors however.
@ -5255,7 +5513,7 @@ namespace dxvk {
uint32_t floatCount = m_vsFloatConstsCount;
if (constSet.meta.needsConstantCopies) {
auto shader = GetCommonShader(m_state.vertexShader);
floatCount = std::max(floatCount, shader->GetMaxDefinedConstant());
floatCount = std::max(floatCount, shader->GetMaxDefinedConstant() + 1);
}
floatCount = std::min(floatCount, constSet.meta.maxConstIndexF);
@ -5317,7 +5575,7 @@ namespace dxvk {
uint32_t floatCount = ShaderStage == DxsoProgramType::VertexShader ? m_vsFloatConstsCount : m_psFloatConstsCount;
if (constSet.meta.needsConstantCopies) {
auto shader = GetCommonShader(Shader);
floatCount = std::max(floatCount, shader->GetMaxDefinedConstant());
floatCount = std::max(floatCount, shader->GetMaxDefinedConstant() + 1);
}
floatCount = std::min(constSet.meta.maxConstIndexF, floatCount);
@ -5450,10 +5708,13 @@ namespace dxvk {
}
void D3D9DeviceEx::Flush() {
template <bool Synchronize9On12>
void D3D9DeviceEx::ExecuteFlush() {
D3D9DeviceLock lock = LockDevice();
if constexpr (Synchronize9On12)
m_submitStatus.result = VK_NOT_READY;
m_initializer->Flush();
m_converter->Flush();
@ -5465,16 +5726,32 @@ namespace dxvk {
EmitCs<false>([
cSubmissionFence = m_submissionFence,
cSubmissionId = submissionId
cSubmissionId = submissionId,
cSubmissionStatus = Synchronize9On12 ? &m_submitStatus : nullptr
] (DxvkContext* ctx) {
ctx->signal(cSubmissionFence, cSubmissionId);
ctx->flushCommandList(nullptr);
ctx->flushCommandList(cSubmissionStatus);
});
FlushCsChunk();
m_flushSeqNum = m_csSeqNum;
m_flushTracker.notifyFlush(m_flushSeqNum, submissionId);
// If necessary, block calling thread until the
// Vulkan queue submission is performed.
if constexpr (Synchronize9On12)
m_dxvkDevice->waitForSubmission(&m_submitStatus);
}
void D3D9DeviceEx::Flush() {
ExecuteFlush<false>();
}
void D3D9DeviceEx::FlushAndSync9On12() {
ExecuteFlush<true>();
}
@ -6449,7 +6726,7 @@ namespace dxvk {
}
void D3D9DeviceEx::PrepareDraw(D3DPRIMITIVETYPE PrimitiveType) {
void D3D9DeviceEx::PrepareDraw(D3DPRIMITIVETYPE PrimitiveType, bool UploadVBOs, bool UploadIBO) {
if (unlikely(m_activeHazardsRT != 0 || m_activeHazardsDS != 0))
MarkRenderHazards();
@ -6462,7 +6739,7 @@ namespace dxvk {
for (uint32_t i = 0; i < caps::MaxStreams; i++) {
auto* vbo = GetCommonBuffer(m_state.vertexBuffers[i].vertexBuffer);
if (vbo != nullptr && vbo->NeedsUpload())
if (vbo != nullptr && vbo->NeedsUpload() && UploadVBOs)
FlushBuffer(vbo);
}
@ -6478,7 +6755,7 @@ namespace dxvk {
GenerateTextureMips(texturesToGen);
auto* ibo = GetCommonBuffer(m_state.indices);
if (ibo != nullptr && ibo->NeedsUpload())
if (ibo != nullptr && ibo->NeedsUpload() && UploadIBO)
FlushBuffer(ibo);
UpdateFog();
@ -6611,6 +6888,19 @@ namespace dxvk {
}
BindSpecConstants();
if (unlikely(m_flags.test(D3D9DeviceFlag::DirtyVertexBuffers) && UploadVBOs)) {
for (uint32_t i = 0; i < caps::MaxStreams; i++) {
const D3D9VBO& vbo = m_state.vertexBuffers[i];
BindVertexBuffer(i, vbo.vertexBuffer.ptr(), vbo.offset, vbo.stride);
}
m_flags.clr(D3D9DeviceFlag::DirtyVertexBuffers);
}
if (unlikely(m_flags.test(D3D9DeviceFlag::DirtyIndexBuffer) && UploadIBO)) {
BindIndices();
m_flags.clr(D3D9DeviceFlag::DirtyIndexBuffer);
}
}
@ -7614,8 +7904,10 @@ namespace dxvk {
if (FAILED(hr))
return hr;
}
else
else {
m_implicitSwapchain = new D3D9SwapChainEx(this, pPresentationParameters, pFullscreenDisplayMode);
m_mostRecentlyUsedSwapchain = m_implicitSwapchain.ptr();
}
if (pPresentationParameters->EnableAutoDepthStencil) {
D3D9_COMMON_TEXTURE_DESC desc;
@ -7635,7 +7927,7 @@ namespace dxvk {
// Docs: Also note that - unlike textures - swap chain back buffers, render targets [..] can be locked
desc.IsLockable = TRUE;
if (FAILED(D3D9CommonTexture::NormalizeTextureProperties(this, &desc)))
if (FAILED(D3D9CommonTexture::NormalizeTextureProperties(this, D3DRTYPE_TEXTURE, &desc)))
return D3DERR_NOTAVAILABLE;
m_autoDepthStencil = new D3D9Surface(this, &desc, nullptr, nullptr);

View File

@ -66,6 +66,8 @@ namespace dxvk {
DirtyInputLayout,
DirtyViewportScissor,
DirtyMultiSampleState,
DirtyVertexBuffers,
DirtyIndexBuffer,
DirtyFogState,
DirtyFogColor,
@ -764,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();
@ -773,6 +793,7 @@ namespace dxvk {
void SynchronizeCsThread(uint64_t SequenceNumber);
void Flush();
void FlushAndSync9On12();
void EndFrame();
@ -816,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() {
@ -895,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(
@ -970,6 +991,17 @@ 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;
@ -1022,6 +1054,15 @@ namespace dxvk {
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);
@ -1046,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) {
@ -1204,6 +1245,34 @@ 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;
@ -1318,13 +1387,15 @@ 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;
@ -1354,6 +1425,8 @@ namespace dxvk {
Rc<sync::Fence> m_submissionFence;
uint64_t m_submissionId = 0ull;
DxvkSubmitStatus m_submitStatus;
uint64_t m_flushSeqNum = 0ull;
GpuFlushTracker m_flushTracker;
@ -1364,6 +1437,8 @@ namespace dxvk {
HWND m_fullscreenWindow = NULL;
std::atomic<uint32_t> m_losableResourceCounter = { 0 };
D3D9SwapChainEx* m_mostRecentlyUsedSwapchain = nullptr;
#ifdef D3D9_ALLOW_UNMAPPING
lru_list<D3D9CommonTexture*> m_mappedTextures;
#endif

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());
}
@ -1111,6 +1106,17 @@ namespace dxvk {
const uint32_t wIndex = 3;
uint32_t flags = (m_vsKey.Data.Contents.TransformFlags >> (i * 3)) & 0b111;
if (flags == D3DTTFF_COUNT1) {
// D3DTTFF_COUNT1 behaves like D3DTTFF_DISABLE on NV and like D3DTTFF_COUNT2 on AMD.
// The Nvidia behavior is easier to implement.
flags = D3DTTFF_DISABLE;
}
// Passing 0xffffffff results in it getting clamped to the dimensions of the texture coords and getting treated as PROJECTED
// but D3D9 does not apply the transformation matrix.
bool applyTransform = flags >= D3DTTFF_COUNT1 && flags <= D3DTTFF_COUNT4;
uint32_t count;
switch (inputFlags) {
default:
@ -1121,11 +1127,14 @@ namespace dxvk {
count = flags;
if (texcoordCount) {
// Clamp by the number of elements in the texcoord input.
if (!count || count > texcoordCount)
if (!count || count > texcoordCount) {
count = texcoordCount;
}
else
}
} else {
count = 0;
flags = D3DTTFF_DISABLE;
applyTransform = false;
}
break;
case (DXVK_TSS_TCI_CAMERASPACENORMAL >> TCIOffset):
@ -1141,7 +1150,7 @@ namespace dxvk {
case (DXVK_TSS_TCI_CAMERASPACEREFLECTIONVECTOR >> TCIOffset): {
uint32_t vtx3 = m_module.opVectorShuffle(m_vec3Type, vtx, vtx, 3, indices.data());
vtx3 = m_module.opNormalize(m_vec3Type, vtx3);
uint32_t reflection = m_module.opReflect(m_vec3Type, vtx3, normal);
std::array<uint32_t, 4> transformIndices;
@ -1179,9 +1188,8 @@ namespace dxvk {
}
}
uint32_t type = flags;
if (type != D3DTTFF_DISABLE) {
if (!m_vsKey.Data.Contents.HasPositionT) {
if (applyTransform || (count != 4 && count != 0)) {
if (applyTransform && !m_vsKey.Data.Contents.HasPositionT) {
for (uint32_t j = count; j < 4; j++) {
// If we're outside the component count of the vertex decl for this texcoord then we pad with zeroes.
// Otherwise, pad with ones.
@ -1198,8 +1206,8 @@ namespace dxvk {
}
// Pad the unused section of it with the value for projection.
uint32_t lastIdx = count - 1;
uint32_t projValue = m_module.opCompositeExtract(m_floatType, transformed, 1, &lastIdx);
uint32_t projIdx = std::max(2u, count - 1);
uint32_t projValue = m_module.opCompositeExtract(m_floatType, transformed, 1, &projIdx);
for (uint32_t j = count; j < 4; j++)
transformed = m_module.opCompositeInsert(m_vec4Type, projValue, transformed, 1, &j);
@ -1384,20 +1392,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);
}
@ -1808,22 +1803,17 @@ namespace dxvk {
texcoord = m_module.opVectorShuffle(texcoord_t,
texcoord, texcoord, texcoordCnt, indices.data());
uint32_t projIdx = m_fsKey.Stages[i].Contents.ProjectedCount;
if (projIdx == 0 || projIdx > texcoordCnt) {
projIdx = 4; // Always use w if ProjectedCount is 0.
}
--projIdx;
bool shouldProject = m_fsKey.Stages[i].Contents.Projected;
uint32_t projValue = 0;
if (m_fsKey.Stages[i].Contents.Projected) {
if (shouldProject) {
// Always use w, the vertex shader puts the correct value there.
const uint32_t projIdx = 3;
projValue = m_module.opCompositeExtract(m_floatType, m_ps.in.TEXCOORD[i], 1, &projIdx);
uint32_t insertIdx = texcoordCnt - 1;
texcoord = m_module.opCompositeInsert(texcoord_t, projValue, texcoord, 1, &insertIdx);
}
bool shouldProject = m_fsKey.Stages[i].Contents.Projected;
if (i != 0 && (
m_fsKey.Stages[i - 1].Contents.ColorOp == D3DTOP_BUMPENVMAP ||
m_fsKey.Stages[i - 1].Contents.ColorOp == D3DTOP_BUMPENVMAPLUMINANCE)) {

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

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

@ -101,9 +101,7 @@ IDirect3DDevice9On12 : public IUnknown {
virtual HRESULT STDMETHODCALLTYPE ReturnUnderlyingResource(IDirect3DResource9* resource, UINT num_sync, UINT64* signal_values, ID3D12Fence** fences) = 0;
};
#ifdef _MSC_VER
struct __declspec(uuid("e7fda234-b589-4049-940d-8878977531c8")) IDirect3DDevice9On12;
#else
#ifndef _MSC_VER
__CRT_UUID_DECL(IDirect3DDevice9On12, 0xe7fda234,0xb589,0x4049,0x94,0x0d,0x88,0x78,0x97,0x75,0x31,0xc8);
#endif

View File

@ -14,7 +14,7 @@ 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() )

View File

@ -229,12 +229,7 @@ ID3D9VkExtSwapchain : public IUnknown {
virtual void STDMETHODCALLTYPE UnlockAdditionalFormats() = 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;
struct __declspec(uuid("13776e93-4aa9-430a-a4ec-fe9e281181d5")) ID3D9VkExtSwapchain;
#else
#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);

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

View File

@ -30,8 +30,11 @@ namespace dxvk {
return E_NOINTERFACE;
}
HRESULT STDMETHODCALLTYPE D3D9On12::ReturnUnderlyingResource(IDirect3DResource9* resource, UINT num_sync, UINT64* signal_values, ID3D12Fence** fences) {
Logger::err("D3D9On12::GetD3D12Device: ReturnUnderlyingResource: Stub");
return E_NOINTERFACE;
if (num_sync)
Logger::err("D3D9On12::GetD3D12Device: ReturnUnderlyingResource: Stub");
m_device->FlushAndSync9On12();
return S_OK;
}
}

View File

@ -37,8 +37,8 @@ namespace dxvk {
this->customDeviceId = parsePciId(config.getOption<std::string>("d3d9.customDeviceId"));
this->customDeviceDesc = config.getOption<std::string>("d3d9.customDeviceDesc");
const int32_t vendorId = this->customDeviceId != -1
? this->customDeviceId
const uint32_t vendorId = this->customVendorId != -1
? this->customVendorId
: (adapter != nullptr ? adapter->deviceProperties().vendorID : 0);
this->maxFrameLatency = config.getOption<int32_t> ("d3d9.maxFrameLatency", 0);
@ -53,14 +53,14 @@ namespace dxvk {
this->deferSurfaceCreation = config.getOption<bool> ("d3d9.deferSurfaceCreation", false);
this->samplerAnisotropy = config.getOption<int32_t> ("d3d9.samplerAnisotropy", -1);
this->maxAvailableMemory = config.getOption<int32_t> ("d3d9.maxAvailableMemory", 4096);
this->supportDFFormats = config.getOption<bool> ("d3d9.supportDFFormats", true);
this->supportDFFormats = config.getOption<bool> ("d3d9.supportDFFormats", vendorId != uint32_t(DxvkGpuVendor::Nvidia));
this->supportX4R4G4B4 = config.getOption<bool> ("d3d9.supportX4R4G4B4", true);
this->supportD32 = config.getOption<bool> ("d3d9.supportD32", true);
this->useD32forD24 = config.getOption<bool> ("d3d9.useD32forD24", false);
this->disableA8RT = config.getOption<bool> ("d3d9.disableA8RT", false);
this->invariantPosition = config.getOption<bool> ("d3d9.invariantPosition", true);
this->memoryTrackTest = config.getOption<bool> ("d3d9.memoryTrackTest", false);
this->supportVCache = config.getOption<bool> ("d3d9.supportVCache", vendorId == 0x10de);
this->supportVCache = config.getOption<bool> ("d3d9.supportVCache", vendorId == uint32_t(DxvkGpuVendor::Nvidia));
this->enableDialogMode = config.getOption<bool> ("d3d9.enableDialogMode", false);
this->forceSamplerTypeSpecConstants = config.getOption<bool> ("d3d9.forceSamplerTypeSpecConstants", false);
this->forceSwapchainMSAA = config.getOption<int32_t> ("d3d9.forceSwapchainMSAA", -1);
@ -76,6 +76,8 @@ namespace dxvk {
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);
this->reproducibleCommandStream = config.getOption<bool> ("d3d9.reproducibleCommandStream", false);
// Clamp LOD bias so that people don't abuse this in unintended ways
this->samplerLodBias = dxvk::fclamp(this->samplerLodBias, -2.0f, 1.0f);
@ -89,8 +91,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_NVK, 0, 0));
&& (adapter->matchesDriver(VK_DRIVER_ID_MESA_RADV)
|| adapter->matchesDriver(VK_DRIVER_ID_MESA_NVK));
d3d9FloatEmulation = hasMulz ? D3D9FloatEmulation::Strict : D3D9FloatEmulation::Enabled;
}

View File

@ -152,6 +152,14 @@ namespace dxvk {
/// Enable emulation of device loss when a fullscreen app loses focus
bool deviceLossOnFocusLoss;
/// Disable counting losable resources and rejecting calls to Reset() if any are still alive
bool countLosableResources;
/// Ensure that for the same D3D commands the output VK commands
/// don't change between runs. Useful for comparative benchmarking,
/// can negatively affect performance.
bool reproducibleCommandStream;
};
}

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

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

@ -18,7 +18,8 @@ namespace dxvk {
}
D3D9StateBlock::~D3D9StateBlock() {
m_parent->DecrementLosableCounter();
if (!m_parent->IsD3D8Compatible())
m_parent->DecrementLosableCounter();
}
HRESULT STDMETHODCALLTYPE D3D9StateBlock::QueryInterface(
@ -575,4 +576,4 @@ namespace dxvk {
this->Capture();
}
}
}

View File

@ -65,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);
@ -112,6 +122,8 @@ namespace dxvk {
DWORD dwFlags) {
D3D9DeviceLock lock = m_parent->LockDevice();
m_parent->SetMostRecentlyUsedSwapchain(this);
if (unlikely(m_parent->IsDeviceLost()))
return D3DERR_DEVICELOST;
@ -147,6 +159,8 @@ namespace dxvk {
bool recreate = false;
recreate |= m_wctx->presenter == nullptr;
recreate |= m_dialog != m_lastDialog;
if (options->deferSurfaceCreation)
recreate |= m_parent->IsDeviceReset();
if (m_wctx->presenter != nullptr) {
m_dirty |= m_wctx->presenter->setSyncInterval(presentInterval) != VK_SUCCESS;
@ -380,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,

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

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

@ -57,17 +57,24 @@ if platform != 'windows'
d3d9_link_depends += files('d3d9.sym')
endif
d3d9_dll = shared_library('d3d9'+dll_ext, d3d9_src, glsl_generator.process(d3d9_shaders), d3d9_res,
name_prefix : dxvk_name_prefix,
d3d9_dll = shared_library(dxvk_name_prefix+'d3d9', d3d9_src, glsl_generator.process(d3d9_shaders), d3d9_res,
dependencies : [ dxso_dep, dxvk_dep ],
include_directories : dxvk_include_path,
install : true,
vs_module_defs : 'd3d9'+def_spec_ext,
link_args : d3d9_ld_args,
link_depends : [ d3d9_link_depends ],
kwargs : dxvk_so_version,
)
d3d9_dep = declare_dependency(
link_with : [ d3d9_dll ],
include_directories : [ dxvk_include_path ],
)
if platform != 'windows'
pkg.generate(d3d9_dll,
filebase: dxvk_pkg_prefix + 'd3d9',
subdirs: 'dxvk',
)
endif

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
@ -944,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(
@ -1233,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;
@ -298,7 +299,10 @@ namespace dxvk {
fallbackDevice = 0x2487;
}
bool hideGpu = (deviceProp.vendorID == uint16_t(DxvkGpuVendor::Nvidia) && options->hideNvidiaGpu)
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);

View File

@ -79,7 +79,7 @@ namespace dxvk {
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),
@ -230,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);
@ -244,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) {

View File

@ -200,6 +200,14 @@ namespace dxvk {
UINT m_flags;
BOOL m_monitorFallback;
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

@ -318,10 +318,12 @@ namespace dxvk {
VK_FORMAT_R8_UINT,
VK_IMAGE_ASPECT_COLOR_BIT },
// DXGI_FORMAT_A8_UNORM
{ VK_FORMAT_A8_UNORM_KHR,
{ VK_FORMAT_R8_UNORM,
VK_FORMAT_UNDEFINED,
VK_FORMAT_R8_UINT,
VK_IMAGE_ASPECT_COLOR_BIT, 0 },
VK_FORMAT_UNDEFINED,
VK_IMAGE_ASPECT_COLOR_BIT, 0,
{ VK_COMPONENT_SWIZZLE_ZERO, VK_COMPONENT_SWIZZLE_ZERO,
VK_COMPONENT_SWIZZLE_ZERO, VK_COMPONENT_SWIZZLE_R }},
// DXGI_FORMAT_R1_UNORM
{ }, // Unsupported
// DXGI_FORMAT_R9G9B9E5_SHAREDEXP
@ -858,16 +860,6 @@ namespace dxvk {
RemapDepthFormat(DXGI_FORMAT_X24_TYPELESS_G8_UINT, VK_FORMAT_D32_SFLOAT_S8_UINT);
RemapDepthFormat(DXGI_FORMAT_D24_UNORM_S8_UINT, VK_FORMAT_D32_SFLOAT_S8_UINT);
}
// Map A8_UNORM to R8_UNORM with appropriate swizzles if necessary
if (!CheckImageFormatSupport(device, VK_FORMAT_A8_UNORM_KHR,
VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_BIT |
VK_FORMAT_FEATURE_2_COLOR_ATTACHMENT_BIT |
VK_FORMAT_FEATURE_2_STORAGE_IMAGE_BIT)) {
RemapColorFormat(DXGI_FORMAT_A8_UNORM, VK_FORMAT_R8_UNORM,
{ VK_COMPONENT_SWIZZLE_ZERO, VK_COMPONENT_SWIZZLE_ZERO,
VK_COMPONENT_SWIZZLE_ZERO, VK_COMPONENT_SWIZZLE_R });
}
}

View File

@ -458,21 +458,7 @@ IDXGIVkInteropFactory1 : public IDXGIVkInteropFactory {
};
#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("2a289dbd-2d0a-4a51-89f7-f2adce465cd6")) IDXGIVkInteropFactory1;
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("785326d4-b77b-4826-ae70-8d08308ee6d1")) IDXGIVkSwapChain1;
struct __declspec(uuid("e7d6c3ca-23a0-4e08-9f2f-ea5231df6633")) IDXGIVkSwapChainFactory;
#else
#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);

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,21 @@ 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";
@ -78,17 +93,16 @@ namespace dxvk {
this->maxDeviceMemory = VkDeviceSize(config.getOption<int32_t>("dxgi.maxDeviceMemory", 0)) << 20;
this->maxSharedMemory = VkDeviceSize(config.getOption<int32_t>("dxgi.maxSharedMemory", 0)) << 20;
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));
Tristate hideNvidiaGpuOption = config.getOption<Tristate>("dxgi.hideNvidiaGpu", Tristate::Auto);
if (hideNvidiaGpuOption == Tristate::Auto && !config.getOption<bool>("dxgi.nvapiHack", true)) {
Logger::warn("dxgi.nvapiHack is deprecated, please set dxgi.hideNvidiaGpu instead.");
hideNvidiaGpuOption = Tristate::False;
}
applyTristate(this->hideNvidiaGpu, hideNvidiaGpuOption);
// 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
@ -96,6 +110,12 @@ namespace dxvk {
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()) {
Logger::info("HDR was configured to be enabled, but has been force disabled as a UE4 DX11 game was detected.");

View File

@ -33,9 +33,13 @@ namespace dxvk {
/// Emulate UMA
bool emulateUMA;
/// Reports Nvidia GPUs as a different vendor (usually AMD)
/// 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;
@ -44,6 +48,10 @@ namespace dxvk {
/// Enable HDR
bool enableHDR;
/// Sync interval. Overrides the value
/// passed to IDXGISwapChain::Present.
int32_t syncInterval;
};
}

View File

@ -32,6 +32,9 @@ namespace dxvk {
// 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);
}
@ -300,18 +303,30 @@ 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) {
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);
@ -393,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;
}
@ -567,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;
}
@ -864,6 +880,7 @@ namespace dxvk {
m_monitorInfo->ReleaseMonitorData();
}
void DxgiSwapChain::UpdateGlobalHDRState() {
// Update the global HDR state if called from the legacy NVAPI
// interfaces, etc.
@ -888,4 +905,51 @@ namespace dxvk {
}
}
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

@ -193,6 +193,8 @@ namespace dxvk {
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(
@ -223,6 +225,18 @@ namespace dxvk {
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);
};
}

View File

@ -21,17 +21,24 @@ if platform != 'windows'
dxgi_link_depends += files('dxgi.sym')
endif
dxgi_dll = shared_library('dxgi'+dll_ext, dxgi_src, dxgi_res,
name_prefix : dxvk_name_prefix,
dxgi_dll = shared_library(dxvk_name_prefix+'dxgi', dxgi_src, dxgi_res,
dependencies : [ dxvk_dep ],
include_directories : dxvk_include_path,
install : true,
vs_module_defs : 'dxgi'+def_spec_ext,
link_args : dxgi_ld_args,
link_depends : [ dxgi_link_depends ],
kwargs : dxvk_so_version,
)
dxgi_dep = declare_dependency(
link_with : [ dxgi_dll ],
include_directories : [ dxvk_include_path ],
)
if platform != 'windows'
pkg.generate(dxgi_dll,
filebase: dxvk_pkg_prefix + 'dxgi',
subdirs: 'dxvk',
)
endif

View File

@ -228,8 +228,8 @@ namespace dxvk {
info.bindings = m_bindings.data();
info.inputMask = m_inputMask;
info.outputMask = m_outputMask;
info.pushConstOffset = m_pushConstOffset;
info.pushConstSize = m_pushConstSize;
info.pushConstStages = VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT;
info.pushConstSize = sizeof(D3D9RenderStateInfo);
if (m_programInfo.type() == DxsoProgramTypes::PixelShader)
info.flatShadingInputs = m_ps.flatShadingMask;
@ -2029,12 +2029,22 @@ namespace dxvk {
result.id = resultIndices[0];
else
result.id = m_module.opCompositeConstruct(typeId, result.type.ccount, resultIndices.data());
if (m_moduleInfo.options.d3d9FloatEmulation == D3D9FloatEmulation::Enabled) {
result.id = m_module.opNMin(typeId, result.id,
m_module.constfReplicant(FLT_MAX, result.type.ccount));
}
break;
}
[[fallthrough]];
case DxsoOpcode::Exp:
result.id = m_module.opExp2(typeId,
emitRegisterLoad(src[0], mask).id);
if (m_moduleInfo.options.d3d9FloatEmulation == D3D9FloatEmulation::Enabled) {
result.id = m_module.opNMin(typeId, result.id,
m_module.constfReplicant(FLT_MAX, result.type.ccount));
}
break;
case DxsoOpcode::Pow: {
uint32_t base = emitRegisterLoad(src[0], mask).id;
@ -3551,30 +3561,7 @@ void DxsoCompiler::emitControlFlowGenericLoop(
void DxsoCompiler::setupRenderStateInfo() {
uint32_t count;
// Only need alpha ref for PS 3.
// No FF fog component.
if (m_programInfo.type() == DxsoProgramType::PixelShader) {
if (m_programInfo.majorVersion() == 3) {
m_pushConstOffset = offsetof(D3D9RenderStateInfo, alphaRef);
m_pushConstSize = sizeof(float);
}
else {
m_pushConstOffset = 0;
m_pushConstSize = offsetof(D3D9RenderStateInfo, pointSize);
}
count = 5;
}
else {
m_pushConstOffset = offsetof(D3D9RenderStateInfo, pointSize);
// Point scale never triggers on programmable
m_pushConstSize = sizeof(float) * 3;
count = 8;
}
m_rsBlock = SetupRenderStateBlock(m_module, count);
m_rsBlock = SetupRenderStateBlock(m_module);
}

View File

@ -344,8 +344,6 @@ namespace dxvk {
// covers vertex input and fragment output.
uint32_t m_inputMask = 0u;
uint32_t m_outputMask = 0u;
uint32_t m_pushConstOffset = 0u;
uint32_t m_pushConstSize = 0u;
///////////////////////////////////
// Shader-specific data structures

View File

@ -346,6 +346,11 @@ namespace dxvk {
enabledFeatures.vk13.synchronization2 = VK_TRUE;
enabledFeatures.vk13.dynamicRendering = VK_TRUE;
// Maintenance4 may cause performance problems on amdvlk in some cases
if (m_deviceInfo.vk12.driverID != VK_DRIVER_ID_AMD_OPEN_SOURCE
&& m_deviceInfo.vk12.driverID != VK_DRIVER_ID_AMD_PROPRIETARY)
enabledFeatures.vk13.maintenance4 = VK_TRUE;
// We expose depth clip rather than depth clamp to client APIs
enabledFeatures.extDepthClipEnable.depthClipEnable =
m_deviceFeatures.extDepthClipEnable.depthClipEnable;
@ -410,21 +415,26 @@ namespace dxvk {
m_deviceFeatures.khrPresentWait.presentWait;
// Unless we're on an Nvidia driver where these extensions are known to be broken
if (matchesDriver(VK_DRIVER_ID_NVIDIA_PROPRIETARY, 0, VK_MAKE_VERSION(535, 0, 0))) {
if (matchesDriver(VK_DRIVER_ID_NVIDIA_PROPRIETARY, Version(), Version(535, 0, 0))) {
enabledFeatures.khrPresentId.presentId = VK_FALSE;
enabledFeatures.khrPresentWait.presentWait = VK_FALSE;
}
// Enable descriptor pool overallocation if supported
enabledFeatures.nvDescriptorPoolOverallocation.descriptorPoolOverallocation =
m_deviceFeatures.nvDescriptorPoolOverallocation.descriptorPoolOverallocation;
// Enable raw access chains for shader backends
enabledFeatures.nvRawAccessChains.shaderRawAccessChains =
m_deviceFeatures.nvRawAccessChains.shaderRawAccessChains;
// Create pNext chain for additional device features
initFeatureChain(enabledFeatures, devExtensions, instance->extensions());
// Log feature support info an extension list
Logger::info(str::format("Device properties:"
"\n Device : ", m_deviceInfo.core.properties.deviceName,
"\n Driver : ", m_deviceInfo.vk12.driverName, " ",
VK_VERSION_MAJOR(m_deviceInfo.core.properties.driverVersion), ".",
VK_VERSION_MINOR(m_deviceInfo.core.properties.driverVersion), ".",
VK_VERSION_PATCH(m_deviceInfo.core.properties.driverVersion)));
"\n Driver : ", m_deviceInfo.vk12.driverName, " ", m_deviceInfo.driverVersion.toString()));
Logger::info("Enabled device extensions:");
this->logNameList(extensionNameList);
@ -606,6 +616,14 @@ namespace dxvk {
enabledFeatures.khrPresentWait = *reinterpret_cast<const VkPhysicalDevicePresentWaitFeaturesKHR*>(f);
break;
case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_POOL_OVERALLOCATION_FEATURES_NV:
enabledFeatures.nvDescriptorPoolOverallocation = *reinterpret_cast<const VkPhysicalDeviceDescriptorPoolOverallocationFeaturesNV*>(f);
break;
case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAW_ACCESS_CHAINS_FEATURES_NV:
enabledFeatures.nvRawAccessChains = *reinterpret_cast<const VkPhysicalDeviceRawAccessChainsFeaturesNV*>(f);
break;
default:
// Ignore any unknown feature structs
break;
@ -618,9 +636,7 @@ namespace dxvk {
Logger::info(str::format("Device properties:"
"\n Device name: ", m_deviceInfo.core.properties.deviceName,
"\n Driver: ", m_deviceInfo.vk12.driverName, " ",
VK_VERSION_MAJOR(m_deviceInfo.core.properties.driverVersion), ".",
VK_VERSION_MINOR(m_deviceInfo.core.properties.driverVersion), ".",
VK_VERSION_PATCH(m_deviceInfo.core.properties.driverVersion)));
m_deviceInfo.driverVersion.toString()));
Logger::info("Enabled device extensions:");
this->logNameList(extensionNameList);
@ -656,26 +672,29 @@ namespace dxvk {
bool DxvkAdapter::matchesDriver(
VkDriverIdKHR driver,
uint32_t minVer,
uint32_t maxVer) const {
Version minVer,
Version maxVer) const {
bool driverMatches = driver == m_deviceInfo.vk12.driverID;
if (minVer) driverMatches &= m_deviceInfo.core.properties.driverVersion >= minVer;
if (maxVer) driverMatches &= m_deviceInfo.core.properties.driverVersion < maxVer;
if (minVer) driverMatches &= m_deviceInfo.driverVersion >= minVer;
if (maxVer) driverMatches &= m_deviceInfo.driverVersion < maxVer;
return driverMatches;
}
bool DxvkAdapter::matchesDriver(
VkDriverIdKHR driver) const {
return driver == m_deviceInfo.vk12.driverID;
}
void DxvkAdapter::logAdapterInfo() const {
const auto deviceInfo = this->devicePropertiesExt();
const auto memoryInfo = this->memoryProperties();
Logger::info(str::format(deviceInfo.core.properties.deviceName, ":",
"\n Driver : ", deviceInfo.vk12.driverName, " ",
VK_VERSION_MAJOR(deviceInfo.core.properties.driverVersion), ".",
VK_VERSION_MINOR(deviceInfo.core.properties.driverVersion), ".",
VK_VERSION_PATCH(deviceInfo.core.properties.driverVersion)));
"\n Driver : ", deviceInfo.vk12.driverName, " ", deviceInfo.driverVersion.toString()));
for (uint32_t i = 0; i < memoryInfo.memoryHeapCount; i++) {
constexpr VkDeviceSize mib = 1024 * 1024;
@ -777,22 +796,8 @@ namespace dxvk {
m_vki->vkGetPhysicalDeviceProperties2(m_handle, &m_deviceInfo.core);
// Some drivers reports the driver version in a slightly different format
switch (m_deviceInfo.vk12.driverID) {
case VK_DRIVER_ID_NVIDIA_PROPRIETARY:
m_deviceInfo.core.properties.driverVersion = VK_MAKE_VERSION(
(m_deviceInfo.core.properties.driverVersion >> 22) & 0x3ff,
(m_deviceInfo.core.properties.driverVersion >> 14) & 0x0ff,
(m_deviceInfo.core.properties.driverVersion >> 6) & 0x0ff);
break;
case VK_DRIVER_ID_INTEL_PROPRIETARY_WINDOWS:
m_deviceInfo.core.properties.driverVersion = VK_MAKE_VERSION(
m_deviceInfo.core.properties.driverVersion >> 14,
m_deviceInfo.core.properties.driverVersion & 0x3fff, 0);
break;
default:;
}
m_deviceInfo.driverVersion = decodeDriverVersion(
m_deviceInfo.vk12.driverID, m_deviceInfo.core.properties.driverVersion);
}
@ -927,6 +932,16 @@ namespace dxvk {
m_deviceFeatures.khrPresentWait.pNext = std::exchange(m_deviceFeatures.core.pNext, &m_deviceFeatures.khrPresentWait);
}
if (m_deviceExtensions.supports(VK_NV_DESCRIPTOR_POOL_OVERALLOCATION_EXTENSION_NAME)) {
m_deviceFeatures.nvDescriptorPoolOverallocation.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_POOL_OVERALLOCATION_FEATURES_NV;
m_deviceFeatures.nvDescriptorPoolOverallocation.pNext = std::exchange(m_deviceFeatures.core.pNext, &m_deviceFeatures.nvDescriptorPoolOverallocation);
}
if (m_deviceExtensions.supports(VK_NV_RAW_ACCESS_CHAINS_EXTENSION_NAME)) {
m_deviceFeatures.nvRawAccessChains.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAW_ACCESS_CHAINS_FEATURES_NV;
m_deviceFeatures.nvRawAccessChains.pNext = std::exchange(m_deviceFeatures.core.pNext, &m_deviceFeatures.nvRawAccessChains);
}
if (m_deviceExtensions.supports(VK_NVX_BINARY_IMPORT_EXTENSION_NAME))
m_deviceFeatures.nvxBinaryImport = VK_TRUE;
@ -994,6 +1009,8 @@ namespace dxvk {
&devExtensions.khrPresentWait,
&devExtensions.khrSwapchain,
&devExtensions.khrWin32KeyedMutex,
&devExtensions.nvDescriptorPoolOverallocation,
&devExtensions.nvRawAccessChains,
&devExtensions.nvxBinaryImport,
&devExtensions.nvxImageViewHandle,
}};
@ -1133,6 +1150,16 @@ namespace dxvk {
enabledFeatures.khrPresentWait.pNext = std::exchange(enabledFeatures.core.pNext, &enabledFeatures.khrPresentWait);
}
if (devExtensions.nvDescriptorPoolOverallocation) {
enabledFeatures.nvDescriptorPoolOverallocation.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_POOL_OVERALLOCATION_FEATURES_NV;
enabledFeatures.nvDescriptorPoolOverallocation.pNext = std::exchange(enabledFeatures.core.pNext, &enabledFeatures.nvDescriptorPoolOverallocation);
}
if (devExtensions.nvRawAccessChains) {
enabledFeatures.nvRawAccessChains.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAW_ACCESS_CHAINS_FEATURES_NV;
enabledFeatures.nvRawAccessChains.pNext = std::exchange(enabledFeatures.core.pNext, &enabledFeatures.nvRawAccessChains);
}
if (devExtensions.nvxBinaryImport)
enabledFeatures.nvxBinaryImport = VK_TRUE;
@ -1279,6 +1306,10 @@ namespace dxvk {
"\n presentId : ", features.khrPresentId.presentId ? "1" : "0",
"\n", VK_KHR_PRESENT_WAIT_EXTENSION_NAME,
"\n presentWait : ", features.khrPresentWait.presentWait ? "1" : "0",
"\n", VK_NV_DESCRIPTOR_POOL_OVERALLOCATION_EXTENSION_NAME,
"\n descriptorPoolOverallocation : ", features.nvDescriptorPoolOverallocation.descriptorPoolOverallocation ? "1" : "0",
"\n", VK_NV_RAW_ACCESS_CHAINS_EXTENSION_NAME,
"\n shaderRawAccessChains : ", features.nvRawAccessChains.shaderRawAccessChains ? "1" : "0",
"\n", VK_NVX_BINARY_IMPORT_EXTENSION_NAME,
"\n extension supported : ", features.nvxBinaryImport ? "1" : "0",
"\n", VK_NVX_IMAGE_VIEW_HANDLE_EXTENSION_NAME,
@ -1295,4 +1326,25 @@ namespace dxvk {
"\n Sparse : ", queues.sparse != VK_QUEUE_FAMILY_IGNORED ? str::format(queues.sparse) : "n/a"));
}
Version DxvkAdapter::decodeDriverVersion(VkDriverId driverId, uint32_t version) {
switch (driverId) {
case VK_DRIVER_ID_NVIDIA_PROPRIETARY:
return Version(
(version >> 22) & 0x3ff,
(version >> 14) & 0x0ff,
(version >> 6) & 0x0ff);
break;
case VK_DRIVER_ID_INTEL_PROPRIETARY_WINDOWS:
return Version(version >> 14, version & 0x3fff, 0);
default:
return Version(
VK_API_VERSION_MAJOR(version),
VK_API_VERSION_MINOR(version),
VK_API_VERSION_PATCH(version));
}
}
}

View File

@ -255,8 +255,17 @@ namespace dxvk {
*/
bool matchesDriver(
VkDriverIdKHR driver,
uint32_t minVer,
uint32_t maxVer) const;
Version minVer,
Version maxVer) const;
/**
* \brief Tests if the driver matches certain criteria
*
* \param [in] driver Driver ID
* \returns \c True if the driver matches these criteria
*/
bool matchesDriver(
VkDriverIdKHR driver) const;
/**
* \brief Logs DXVK adapter info
@ -343,6 +352,8 @@ namespace dxvk {
static void logFeatures(const DxvkDeviceFeatures& features);
static void logQueueFamilies(const DxvkAdapterQueueIndices& queues);
static Version decodeDriverVersion(VkDriverId driverId, uint32_t version);
};
}

View File

@ -28,8 +28,6 @@ public:
};
#ifdef _MSC_VER
struct __declspec(uuid("7f2c2f72-1cc8-4979-8d9c-7e3faeddecde")) IDXVKUserDefinedAnnotation;
#else
#ifndef _MSC_VER
__CRT_UUID_DECL(IDXVKUserDefinedAnnotation, 0x7f2c2f72,0x1cc8,0x4979,0x8d,0x9c,0x7e,0x3f,0xae,0xdd,0xec,0xde);
#endif

View File

@ -671,7 +671,7 @@ namespace dxvk {
uint32_t indexCount,
uint32_t instanceCount,
uint32_t firstIndex,
uint32_t vertexOffset,
int32_t vertexOffset,
uint32_t firstInstance) {
m_vkd->vkCmdDrawIndexed(m_cmd.execBuffer,
indexCount, instanceCount,

View File

@ -48,9 +48,7 @@ namespace dxvk {
// Retrieve actual pipeline handle on first use. This
// may wait for an ongoing compile job to finish, or
// compile the pipeline immediately on the calling thread.
m_libraryHandle = m_library->acquirePipelineHandle(
DxvkShaderPipelineLibraryCompileArgs());
m_libraryHandle = m_library->acquirePipelineHandle().handle;
return m_libraryHandle;
} else {
// Slow path for compute shaders that do use spec constants

View File

@ -1354,7 +1354,7 @@ namespace dxvk {
uint32_t indexCount,
uint32_t instanceCount,
uint32_t firstIndex,
uint32_t vertexOffset,
int32_t vertexOffset,
uint32_t firstInstance) {
if (this->commitGraphicsState<true, false>()) {
m_cmd->cmdDrawIndexed(
@ -1997,7 +1997,7 @@ namespace dxvk {
depthOp.loadOpS = VK_ATTACHMENT_LOAD_OP_LOAD;
depthOp.loadLayout = imageView->imageInfo().layout;
depthOp.storeLayout = imageView->imageInfo().layout;
if (clearAspects & VK_IMAGE_ASPECT_COLOR_BIT)
colorOp.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
else if (discardAspects & VK_IMAGE_ASPECT_COLOR_BIT)
@ -2010,7 +2010,7 @@ namespace dxvk {
if (clearAspects & VK_IMAGE_ASPECT_STENCIL_BIT)
depthOp.loadOpS = VK_ATTACHMENT_LOAD_OP_CLEAR;
else if (discardAspects & VK_IMAGE_ASPECT_DEPTH_BIT)
else if (discardAspects & VK_IMAGE_ASPECT_STENCIL_BIT)
depthOp.loadOpS = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
if (attachmentIndex >= 0 && !m_state.om.framebufferInfo.isWritable(attachmentIndex, clearAspects | discardAspects)) {
@ -2041,6 +2041,8 @@ namespace dxvk {
}
if (attachmentIndex < 0) {
bool hasViewFormatMismatch = imageView->info().format != imageView->imageInfo().format;
if (m_execBarriers.isImageDirty(imageView->image(), imageView->imageSubresources(), DxvkAccess::Write))
m_execBarriers.recordCommands(m_cmd);
@ -2075,6 +2077,11 @@ namespace dxvk {
attachmentInfo.loadOp = colorOp.loadOp;
// We can't use LOAD_OP_CLEAR if the view format does not match the
// underlying image format, so just discard here and use clear later.
if (hasViewFormatMismatch && attachmentInfo.loadOp == VK_ATTACHMENT_LOAD_OP_CLEAR)
attachmentInfo.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
renderingInfo.colorAttachmentCount = 1;
renderingInfo.pColorAttachments = &attachmentInfo;
@ -2110,6 +2117,20 @@ namespace dxvk {
}
m_cmd->cmdBeginRendering(&renderingInfo);
if (hasViewFormatMismatch) {
VkClearAttachment clearInfo = { };
clearInfo.aspectMask = imageView->info().aspect;
clearInfo.clearValue = clearValue;
VkClearRect clearRect = { };
clearRect.rect.extent.width = extent.width;
clearRect.rect.extent.height = extent.height;
clearRect.layerCount = imageView->info().numLayers;
m_cmd->cmdClearAttachments(1, &clearInfo, 1, &clearRect);
}
m_cmd->cmdEndRendering();
m_execBarriers.accessImage(
@ -3563,69 +3584,90 @@ namespace dxvk {
VkImageSubresourceLayers srcSubresource,
VkOffset3D srcOffset,
VkExtent3D extent) {
VkFormat viewFormat = m_common->metaCopy().getCopyDestinationFormat(
dstSubresource.aspectMask,
srcSubresource.aspectMask,
srcImage->info().format);
DxvkMetaCopyFormats viewFormats = m_common->metaCopy().getFormats(
dstImage->info().format, dstSubresource.aspectMask,
srcImage->info().format, srcSubresource.aspectMask);
if (!viewFormat) {
Logger::err("DxvkContext: copyImageFb: Unsupported format");
return;
}
// Usually we should be able to draw directly to the destination image,
// but in some cases this might not be possible, e.g. if when copying
// from something like D32_SFLOAT to RGBA8_UNORM. In those situations,
// create a temporary image to draw to, and then copy to the actual
// destination image using a regular Vulkan transfer function.
bool useDirectCopy = (dstImage->info().usage & (VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT))
&& (dstImage->isViewCompatible(viewFormat));
bool dstIsCompatible = (dstImage->info().usage & (VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT))
&& (dstImage->isViewCompatible(viewFormats.dstFormat));
bool srcIsCompatible = (srcImage->info().usage & (VK_IMAGE_USAGE_SAMPLED_BIT))
&& (srcImage->isViewCompatible(viewFormats.srcFormat));
if (useDirectCopy) {
if (dstIsCompatible && srcIsCompatible) {
this->copyImageFbDirect(
dstImage, dstSubresource, dstOffset, viewFormat,
srcImage, srcSubresource, srcOffset, extent);
} else {
dstImage, dstSubresource, dstOffset, viewFormats.dstFormat,
srcImage, srcSubresource, srcOffset, viewFormats.srcFormat, extent);
} else if (dstIsCompatible || srcIsCompatible) {
DxvkImageCreateInfo imageInfo = dstImage->info();
imageInfo.format = viewFormat;
imageInfo.flags = 0;
imageInfo.usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
imageInfo.extent = extent;
imageInfo.numLayers = dstSubresource.layerCount;
imageInfo.mipLevels = 1;
imageInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
imageInfo.layout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
imageInfo.stages = VK_PIPELINE_STAGE_TRANSFER_BIT;
imageInfo.access = VK_ACCESS_TRANSFER_READ_BIT;
imageInfo.viewFormatCount = 0;
if (dstImage->formatInfo()->aspectMask & VK_IMAGE_ASPECT_COLOR_BIT) {
imageInfo.usage |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
imageInfo.stages |= VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
imageInfo.access |= VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
} else {
imageInfo.usage |= VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
imageInfo.stages |= VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT
| VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
imageInfo.access |= VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
if (!dstIsCompatible) {
imageInfo.format = viewFormats.dstFormat;
imageInfo.numLayers = dstSubresource.layerCount;
imageInfo.usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
imageInfo.layout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
imageInfo.stages = VK_PIPELINE_STAGE_TRANSFER_BIT;
imageInfo.access = VK_ACCESS_TRANSFER_READ_BIT;
if (dstImage->formatInfo()->aspectMask & VK_IMAGE_ASPECT_COLOR_BIT) {
imageInfo.usage |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
imageInfo.stages |= VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
imageInfo.access |= VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
} else {
imageInfo.usage |= VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
imageInfo.stages |= VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT
| VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
imageInfo.access |= VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
}
} else /* if (!srcIsCompatible) */ {
imageInfo.format = viewFormats.srcFormat;
imageInfo.numLayers = srcSubresource.layerCount;
imageInfo.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT;
imageInfo.layout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
imageInfo.stages = VK_PIPELINE_STAGE_TRANSFER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
imageInfo.access = VK_ACCESS_TRANSFER_WRITE_BIT | VK_ACCESS_SHADER_READ_BIT;
}
Rc<DxvkImage> tmpImage = m_device->createImage(imageInfo,
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
Rc<DxvkImage> tmpImage = m_device->createImage(imageInfo, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
VkImageSubresourceLayers tmpSubresource = dstSubresource;
VkImageSubresourceLayers tmpSubresource = { };
tmpSubresource.aspectMask = tmpImage->formatInfo()->aspectMask;
tmpSubresource.mipLevel = 0;
tmpSubresource.baseArrayLayer = 0;
tmpSubresource.layerCount = imageInfo.numLayers;
VkOffset3D tmpOffset = { 0, 0, 0 };
this->copyImageFbDirect(
tmpImage, tmpSubresource, tmpOffset, viewFormat,
srcImage, srcSubresource, srcOffset, extent);
if (!dstIsCompatible) {
this->copyImageFbDirect(
tmpImage, tmpSubresource, tmpOffset, viewFormats.dstFormat,
srcImage, srcSubresource, srcOffset, viewFormats.srcFormat, extent);
this->copyImageHw(
dstImage, dstSubresource, dstOffset,
tmpImage, tmpSubresource, tmpOffset, extent);
this->copyImageHw(
dstImage, dstSubresource, dstOffset,
tmpImage, tmpSubresource, tmpOffset, extent);
} else /* if (!srcIsCompatible) */ {
this->copyImageHw(
tmpImage, tmpSubresource, tmpOffset,
srcImage, srcSubresource, srcOffset, extent);
this->copyImageFbDirect(
dstImage, dstSubresource, dstOffset, viewFormats.dstFormat,
tmpImage, tmpSubresource, tmpOffset, viewFormats.srcFormat, extent);
}
} else {
Logger::err(str::format("DxvkContext: copyImageFb: Unsupported operation:\n"
" srcFormat = ", srcImage->info().format, " (aspect ", srcSubresource.aspectMask, ")\n",
" dstFormat = ", dstImage->info().format, " (aspect ", dstSubresource.aspectMask, ")"));
}
}
@ -3638,6 +3680,7 @@ namespace dxvk {
const Rc<DxvkImage>& srcImage,
VkImageSubresourceLayers srcSubresource,
VkOffset3D srcOffset,
VkFormat srcFormat,
VkExtent3D extent) {
this->invalidateState();
@ -3701,8 +3744,6 @@ namespace dxvk {
m_execAcquires.recordCommands(m_cmd);
// Create source and destination image views
VkFormat srcFormat = srcImage->info().format;
Rc<DxvkMetaCopyViews> views = new DxvkMetaCopyViews(m_device->vkd(),
dstImage, dstSubresource, dstFormat,
srcImage, srcSubresource, srcFormat);
@ -4721,8 +4762,10 @@ namespace dxvk {
this->renderPassEmitPostBarriers(framebufferInfo, ops);
uint32_t colorInfoCount = 0;
uint32_t lateClearCount = 0;
std::array<VkRenderingAttachmentInfo, MaxNumRenderTargets> colorInfos;
std::array<VkClearAttachment, MaxNumRenderTargets> lateClears;
for (uint32_t i = 0; i < MaxNumRenderTargets; i++) {
const auto& colorTarget = framebufferInfo.getColorTarget(i);
@ -4734,9 +4777,21 @@ namespace dxvk {
colorInfos[i].loadOp = ops.colorOps[i].loadOp;
colorInfos[i].storeOp = VK_ATTACHMENT_STORE_OP_STORE;
if (ops.colorOps[i].loadOp == VK_ATTACHMENT_LOAD_OP_CLEAR)
if (ops.colorOps[i].loadOp == VK_ATTACHMENT_LOAD_OP_CLEAR) {
colorInfos[i].clearValue.color = ops.colorOps[i].clearValue;
// We can't use LOAD_OP_CLEAR if the view format does not match the
// underlying image format, so just discard here and use clear later.
if (colorTarget.view->info().format != colorTarget.view->imageInfo().format) {
colorInfos[i].loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
auto& clear = lateClears[lateClearCount++];
clear.colorAttachment = i;
clear.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
clear.clearValue.color = ops.colorOps[i].clearValue;
}
}
colorInfoCount = i + 1;
}
}
@ -4784,6 +4839,15 @@ namespace dxvk {
m_cmd->cmdBeginRendering(&renderingInfo);
if (lateClearCount) {
VkClearRect clearRect = { };
clearRect.rect.extent.width = fbSize.width;
clearRect.rect.extent.height = fbSize.height;
clearRect.layerCount = fbSize.layers;
m_cmd->cmdClearAttachments(lateClearCount, lateClears.data(), 1, &clearRect);
}
for (uint32_t i = 0; i < framebufferInfo.numAttachments(); i++) {
m_cmd->trackResource<DxvkAccess::None> (framebufferInfo.getAttachment(i).view);
m_cmd->trackResource<DxvkAccess::Write>(framebufferInfo.getAttachment(i).view->image());
@ -4920,7 +4984,7 @@ namespace dxvk {
// Mark compute resources and push constants as dirty
m_descriptorState.dirtyStages(VK_SHADER_STAGE_COMPUTE_BIT);
if (newPipeline->getBindings()->layout().getPushConstantRange().size)
if (newPipeline->getBindings()->layout().getPushConstantRange(true).size)
m_flags.set(DxvkContextFlag::DirtyPushConstants);
m_flags.clr(DxvkContextFlag::CpDirtyPipelineState);
@ -4994,7 +5058,7 @@ namespace dxvk {
m_descriptorState.dirtyStages(VK_SHADER_STAGE_ALL_GRAPHICS);
if (newPipeline->getBindings()->layout().getPushConstantRange().size)
if (newPipeline->getBindings()->layout().getPushConstantRange(true).size)
m_flags.set(DxvkContextFlag::DirtyPushConstants);
m_flags.clr(DxvkContextFlag::GpDirtyPipeline);
@ -5594,11 +5658,13 @@ namespace dxvk {
auto bufferInfo = m_state.vi.indexBuffer.getDescriptor();
if (m_features.test(DxvkContextFeature::IndexBufferRobustness)) {
VkDeviceSize align = m_state.vi.indexType == VK_INDEX_TYPE_UINT16 ? 2 : 4;
VkDeviceSize range = bufferInfo.buffer.range & ~(align - 1);
m_cmd->cmdBindIndexBuffer2(
bufferInfo.buffer.buffer,
bufferInfo.buffer.offset,
bufferInfo.buffer.range,
m_state.vi.indexType);
range, m_state.vi.indexType);
} else {
m_cmd->cmdBindIndexBuffer(
bufferInfo.buffer.buffer,
@ -5859,16 +5925,19 @@ namespace dxvk {
auto bindings = BindPoint == VK_PIPELINE_BIND_POINT_GRAPHICS
? m_state.gp.pipeline->getBindings()
: m_state.cp.pipeline->getBindings();
VkPushConstantRange pushConstRange = bindings->layout().getPushConstantRange();
// Optimized pipelines may have push constants trimmed, so look up
// the exact layout used for the currently bound pipeline.
bool independentSets = BindPoint == VK_PIPELINE_BIND_POINT_GRAPHICS
&& m_flags.test(DxvkContextFlag::GpIndependentSets);
VkPushConstantRange pushConstRange = bindings->layout().getPushConstantRange(independentSets);
if (!pushConstRange.size)
return;
// Push constants should be compatible between complete and
// independent layouts, so always ask for the complete one
m_cmd->cmdPushConstants(
bindings->getPipelineLayout(false),
bindings->getPipelineLayout(independentSets),
pushConstRange.stageFlags,
pushConstRange.offset,
pushConstRange.size,

View File

@ -810,7 +810,7 @@ namespace dxvk {
uint32_t indexCount,
uint32_t instanceCount,
uint32_t firstIndex,
uint32_t vertexOffset,
int32_t vertexOffset,
uint32_t firstInstance);
/**
@ -1506,6 +1506,7 @@ namespace dxvk {
const Rc<DxvkImage>& srcImage,
VkImageSubresourceLayers srcSubresource,
VkOffset3D srcOffset,
VkFormat srcFormat,
VkExtent3D extent);
bool copyImageClear(

View File

@ -350,7 +350,7 @@ namespace dxvk {
return m_chunk;
}
operator bool () const {
explicit operator bool () const {
return m_chunk != nullptr;
}

View File

@ -72,7 +72,7 @@ namespace dxvk {
// memory bloat. This may be necessary for off-screen
// rendering applications, or in situations where games
// pre-render a lot of images without presenting in between.
return m_descriptorPools.size() >= 8;
return m_descriptorPools.size() > MaxDesiredPoolCount;
}
@ -100,29 +100,25 @@ namespace dxvk {
void DxvkDescriptorPool::reset() {
// As a heuristic to save memory, check how many descriptors
// have actively been used in the past couple of submissions.
bool isLowUsageFrame = false;
// As a heuristic to save memory, check how many descriptor
// sets were actually being used in past submissions.
size_t poolCount = m_descriptorPools.size();
bool needsReset = poolCount > MaxDesiredPoolCount;
if (poolCount > 1 || m_setsAllocated > m_manager->getMaxSetCount() / 2) {
double factor = std::max(11.0 / 3.0 - double(poolCount) / 3.0, 1.0);
isLowUsageFrame = double(m_setsUsed) * factor < double(m_setsAllocated);
needsReset = double(m_setsUsed) * factor < double(m_setsAllocated);
}
m_lowUsageFrames = isLowUsageFrame
? m_lowUsageFrames + 1
: 0;
m_setsUsed = 0;
if (m_lowUsageFrames < 16) {
if (!needsReset) {
for (auto& entry : m_setLists)
entry.second.reset();
} else {
// If most sets are no longer being used, reset and destroy
// descriptor pools and reset all lookup tables in order to
// accomodate more descriptors of different layouts.
// If most sets are no longer needed, reset and destroy
// descriptor pools and reset all lookup tables in order
// to accomodate more descriptors of different layouts.
for (auto pool : m_descriptorPools)
m_manager->recycleVulkanDescriptorPool(pool);
@ -131,7 +127,6 @@ namespace dxvk {
m_setMaps.clear();
m_setsAllocated = 0;
m_lowUsageFrames = 0;
}
m_cachedEntry = { nullptr, nullptr };
@ -311,7 +306,12 @@ namespace dxvk {
info.maxSets = m_maxSets;
info.poolSizeCount = pools.size();
info.pPoolSizes = pools.data();
if (m_device->features().nvDescriptorPoolOverallocation.descriptorPoolOverallocation) {
info.flags |= VK_DESCRIPTOR_POOL_CREATE_ALLOW_OVERALLOCATION_POOLS_BIT_NV
| VK_DESCRIPTOR_POOL_CREATE_ALLOW_OVERALLOCATION_SETS_BIT_NV;
}
VkDescriptorPool pool = VK_NULL_HANDLE;
if (vk->vkCreateDescriptorPool(vk->device(), &info, nullptr, &pool) != VK_SUCCESS)

View File

@ -80,7 +80,7 @@ namespace dxvk {
* to be updated.
*/
class DxvkDescriptorPool : public RcObject {
constexpr static uint32_t MaxDesiredPoolCount = 2;
public:
DxvkDescriptorPool(
@ -155,8 +155,6 @@ namespace dxvk {
uint32_t m_prevSetsAllocated = 0;
uint32_t m_lowUsageFrames = 0;
DxvkDescriptorSetMap* getSetMapCached(
const DxvkBindingLayoutObjects* layout);

View File

@ -82,7 +82,7 @@ namespace dxvk {
// Disable lifetime tracking for drivers that do not have any
// significant issues with 32-bit address space to begin with
if (m_adapter->matchesDriver(VK_DRIVER_ID_MESA_RADV_KHR, 0, 0))
if (m_adapter->matchesDriver(VK_DRIVER_ID_MESA_RADV_KHR))
return false;
return true;
@ -325,12 +325,12 @@ namespace dxvk {
DxvkDevicePerfHints DxvkDevice::getPerfHints() {
DxvkDevicePerfHints hints;
hints.preferFbDepthStencilCopy = m_features.extShaderStencilExport
&& (m_adapter->matchesDriver(VK_DRIVER_ID_MESA_RADV_KHR, 0, 0)
|| m_adapter->matchesDriver(VK_DRIVER_ID_AMD_OPEN_SOURCE_KHR, 0, 0)
|| m_adapter->matchesDriver(VK_DRIVER_ID_AMD_PROPRIETARY_KHR, 0, 0));
&& (m_adapter->matchesDriver(VK_DRIVER_ID_MESA_RADV_KHR)
|| m_adapter->matchesDriver(VK_DRIVER_ID_AMD_OPEN_SOURCE_KHR)
|| m_adapter->matchesDriver(VK_DRIVER_ID_AMD_PROPRIETARY_KHR));
hints.preferFbResolve = m_features.amdShaderFragmentMask
&& (m_adapter->matchesDriver(VK_DRIVER_ID_AMD_OPEN_SOURCE_KHR, 0, 0)
|| m_adapter->matchesDriver(VK_DRIVER_ID_AMD_PROPRIETARY_KHR, 0, 0));
&& (m_adapter->matchesDriver(VK_DRIVER_ID_AMD_OPEN_SOURCE_KHR)
|| m_adapter->matchesDriver(VK_DRIVER_ID_AMD_PROPRIETARY_KHR));
return hints;
}

View File

@ -17,10 +17,10 @@ namespace dxvk {
bool DxvkDeviceFilter::testAdapter(const VkPhysicalDeviceProperties& properties) const {
if (properties.apiVersion < VK_MAKE_VERSION(1, 3, 0)) {
if (properties.apiVersion < VK_MAKE_API_VERSION(0, 1, 3, 0)) {
Logger::warn(str::format("Skipping Vulkan ",
VK_VERSION_MAJOR(properties.apiVersion), ".",
VK_VERSION_MINOR(properties.apiVersion), " adapter: ",
VK_API_VERSION_MAJOR(properties.apiVersion), ".",
VK_API_VERSION_MINOR(properties.apiVersion), " adapter: ",
properties.deviceName));
return false;
}

View File

@ -2,6 +2,8 @@
#include "dxvk_include.h"
#include "../util/util_version.h"
namespace dxvk {
/**
@ -13,6 +15,7 @@ namespace dxvk {
* so before using them, check whether they are supported.
*/
struct DxvkDeviceInfo {
Version driverVersion;
VkPhysicalDeviceProperties2 core;
VkPhysicalDeviceVulkan11Properties vk11;
VkPhysicalDeviceVulkan12Properties vk12;
@ -68,6 +71,8 @@ namespace dxvk {
VkPhysicalDeviceMaintenance5FeaturesKHR khrMaintenance5;
VkPhysicalDevicePresentIdFeaturesKHR khrPresentId;
VkPhysicalDevicePresentWaitFeaturesKHR khrPresentWait;
VkPhysicalDeviceDescriptorPoolOverallocationFeaturesNV nvDescriptorPoolOverallocation;
VkPhysicalDeviceRawAccessChainsFeaturesNV nvRawAccessChains;
VkBool32 nvxBinaryImport;
VkBool32 nvxImageViewHandle;
VkBool32 khrWin32KeyedMutex;

View File

@ -61,7 +61,7 @@ namespace dxvk {
* provided by the extension can be used.
* \returns \c true if the extension is enabled
*/
operator bool () const {
explicit operator bool () const {
return m_revision != 0;
}
@ -325,6 +325,8 @@ namespace dxvk {
DxvkExt khrPresentWait = { VK_KHR_PRESENT_WAIT_EXTENSION_NAME, DxvkExtMode::Optional };
DxvkExt khrSwapchain = { VK_KHR_SWAPCHAIN_EXTENSION_NAME, DxvkExtMode::Required };
DxvkExt khrWin32KeyedMutex = { VK_KHR_WIN32_KEYED_MUTEX_EXTENSION_NAME, DxvkExtMode::Optional };
DxvkExt nvDescriptorPoolOverallocation = { VK_NV_DESCRIPTOR_POOL_OVERALLOCATION_EXTENSION_NAME, DxvkExtMode::Optional };
DxvkExt nvRawAccessChains = { VK_NV_RAW_ACCESS_CHAINS_EXTENSION_NAME, DxvkExtMode::Optional };
DxvkExt nvxBinaryImport = { VK_NVX_BINARY_IMPORT_EXTENSION_NAME, DxvkExtMode::Disabled };
DxvkExt nvxImageViewHandle = { VK_NVX_IMAGE_VIEW_HANDLE_EXTENSION_NAME, DxvkExtMode::Disabled };
};

View File

@ -1111,7 +1111,9 @@ namespace dxvk {
if (doCreateBasePipeline)
baseHandle = this->getBasePipeline(state);
else
// Fast-linking may fail in some situations
if (!baseHandle)
fastHandle = this->getOptimizedPipeline(state);
// Log pipeline state if requested, or on failure
@ -1148,6 +1150,13 @@ namespace dxvk {
|| (state.rs.lineMode() != VK_LINE_RASTERIZATION_MODE_DEFAULT_EXT && isLineRendering))
return false;
// Depth clip is assumed to be enabled. If the driver does not
// support dynamic depth clip, we'd have to late-compile anyway
// unless the pipeline is used multiple times.
if (!m_device->features().extExtendedDynamicState3.extendedDynamicState3DepthClipEnable
&& !state.rs.depthClipEnable())
return false;
if (m_shaders.tcs != nullptr) {
// If tessellation shaders are present, the input patch
// vertex count must match the shader's definition.
@ -1219,9 +1228,6 @@ namespace dxvk {
key.viLibrary = m_manager->createVertexInputLibrary(viState);
key.foLibrary = m_manager->createFragmentOutputLibrary(foState);
if (!m_device->features().extExtendedDynamicState3.extendedDynamicState3DepthClipEnable)
key.args.depthClipEnable = state.rs.depthClipEnable();
auto entry = m_basePipelines.find(key);
if (entry != m_basePipelines.end())
return entry->second;
@ -1236,10 +1242,11 @@ namespace dxvk {
const DxvkGraphicsPipelineBaseInstanceKey& key) const {
auto vk = m_device->vkd();
DxvkShaderPipelineLibraryHandle vs = m_vsLibrary->acquirePipelineHandle();
DxvkShaderPipelineLibraryHandle fs = m_fsLibrary->acquirePipelineHandle();
std::array<VkPipeline, 4> libraries = {{
key.viLibrary->getHandle(),
m_vsLibrary->acquirePipelineHandle(key.args),
m_fsLibrary->acquirePipelineHandle(key.args),
key.viLibrary->getHandle(), vs.handle, fs.handle,
key.foLibrary->getHandle(),
}};
@ -1248,13 +1255,14 @@ namespace dxvk {
libInfo.pLibraries = libraries.data();
VkGraphicsPipelineCreateInfo info = { VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, &libInfo };
info.flags = vs.linkFlags | fs.linkFlags;
info.layout = m_bindings->getPipelineLayout(true);
info.basePipelineIndex = -1;
VkPipeline pipeline = VK_NULL_HANDLE;
VkResult vr = vk->vkCreateGraphicsPipelines(vk->device(), VK_NULL_HANDLE, 1, &info, nullptr, &pipeline);
if (vr != VK_SUCCESS)
if (vr && vr != VK_PIPELINE_COMPILE_REQUIRED_EXT)
Logger::err(str::format("DxvkGraphicsPipeline: Failed to create base pipeline: ", vr));
return pipeline;

Some files were not shown because too many files have changed in this diff Show More