Compare commits

...

1047 commits

Author SHA1 Message Date
Philip Rebohle
a08579e555 [dxvk] Fix clear after late resolve 2025-03-06 09:54:34 +01:00
Philip Rebohle
45ec01a0a1 [d3d11] Add TRANSFER_SRC usage to icb
Needed for defrag.
2025-03-06 09:54:34 +01:00
Philip Rebohle
542e0d2ab0 [dxvk,d3d9,d3d11] Decouple ID3DUserDefinedAnnotation from internal markers
Some games nope out when we expose debug markers, so add a debug mode
that doesn't while still providing internal markers and debug names.
2025-03-06 09:54:34 +01:00
Philip Rebohle
91b48dd31d [d3d11] Make user defined annotation more robust 2025-03-06 09:54:34 +01:00
GranMinigun
d8eb4d0d66 [util] Spoof vendor ID for CivCity: Rome 2025-03-06 01:25:30 +01:00
Philip Rebohle
f161d9bc7b [dxvk] Fix synchronization on swapchain tear-down 2025-03-05 23:16:28 +01:00
Philip Rebohle
634f38b38d [dxvk] Enable sparse binding features if supported 2025-03-05 23:15:47 +01:00
Philip Rebohle
ff8378be19 [dxvk] Fix uploadImage barriers 2025-03-05 23:15:47 +01:00
Philip Rebohle
ad75fb17cd [dxvk] Fix uploadBuffer barriers 2025-03-05 23:15:47 +01:00
Philip Rebohle
76244812fb [dxvk] Move compressed image initialization to transfer queue
This is relatively common.
2025-03-05 23:15:47 +01:00
Philip Rebohle
9c0dec9f58 [dxvk] Move buffer initialization to transfer queue 2025-03-05 23:15:47 +01:00
Philip Rebohle
a4a5bf5d63 [dxvk] Add helpers for transfer queue release barriers 2025-03-05 23:15:47 +01:00
Philip Rebohle
49f0968f57 [dxvk] Use sparse residency for zero buffer
Saves a small amount of memory since reading from an unbound
buffer will return zero anyway.
2025-03-05 23:15:47 +01:00
Philip Rebohle
ec0deb73da [dxvk] Fix missing zero buffer tracking
Scary.
2025-03-05 23:15:47 +01:00
WinterSnowfall
fed51e6c92 [dxso] Fix uninitialized m_maxDefinedConstant variable 2025-03-05 15:02:11 +01:00
Philip Rebohle
196258111c [dxvk] Be more conservative with CS data alignment
Fixes #4734. Apparently, weak alignment hints are an error rather
than getting ignored.
2025-03-05 13:12:23 +01:00
Philip Rebohle
d04fe1cdc0 [meta] Add some missing documentation to dxvk.conf 2025-03-04 21:49:39 +01:00
Philip Rebohle
3cf453160c [d3d11] Ensure required image usage flags for video blits
Fixes some validation errors.
2025-03-04 21:05:59 +01:00
Philip Rebohle
9769df9dd8 [d3d11] Implement ID3D11On12Device1 2025-03-02 19:21:39 +01:00
Philip Rebohle
106032fa65 [dxvk] Use granular image access tracking in copyImageHw 2025-03-02 14:01:09 +01:00
Philip Rebohle
d2b53b76de [dxvk] Use granular image access tracking in copyBufferToImageHw 2025-03-02 14:01:09 +01:00
Philip Rebohle
02dc403074 [dxvk] Use granular image access tracking in copyImageToBufferCs 2025-03-02 14:01:09 +01:00
Philip Rebohle
420d083677 [dxvk] Use granular image access tracking in copyImageToBufferHw 2025-03-02 14:01:09 +01:00
Philip Rebohle
cd29f0feaa [dxvk] Add barrier helpers for granular image access tracking 2025-03-02 14:01:09 +01:00
Philip Rebohle
baaf72a373 [dxvk] Add helpers to compute more granular image address ranges 2025-03-02 14:01:09 +01:00
Philip Rebohle
1f0ad760e1 [dxvk] Refactor address range for barrier tracking
Allows us to bump the size and offset to 64 bits without increasing the
total size of the node.
2025-03-02 14:01:09 +01:00
Philip Rebohle
fe58b393d4 [util] Add helper for 2D and 3D morton codes 2025-03-02 14:01:09 +01:00
Philip Rebohle
c21f4e0190 [util] Add 48-bit integer type 2025-03-02 14:01:09 +01:00
Philip Rebohle
416f9c5a4a [d3d11] Embed UpdateBuffer data in CS chunk
Tiny optimization that gets rid of a copy and also lets us use chunk
memory more efficiently.
2025-03-02 13:29:48 +01:00
Philip Rebohle
5b68884fd9 [d3d11] Fix confusing debug color for GPU synchronization
Purple was already used for various other things.
2025-03-01 16:37:39 +01:00
Robin Kertels
8f84085370 [dxvk] Add CS thread load to the HUD 2025-03-01 14:23:22 +01:00
Philip Rebohle
b35e69b467 [d3d11] Skip empty draws
Watch Dogs 2 likes to do this with graphics UAVs bound, which
introduces quite a bit of unnecessary GPU synchronization.
2025-03-01 11:30:38 +01:00
Philip Rebohle
11dc0e7ce8 [util] Enable compute UAV barriers for Watch Dogs 2 2025-02-28 23:57:26 +01:00
Philip Rebohle
6b5d595b3e [d3d11] Add option to force compute shader UAV synchronization 2025-02-28 23:57:26 +01:00
Philip Rebohle
396a4e0235 [dxbc] Add option to implicitly synchronize UAV accesses 2025-02-28 23:57:26 +01:00
Philip Rebohle
c04410ca00 [dxbc] Increase maximum size of embedded icbs to 256 bytes
Gives drivers more info, while still avoiding duplication of large ICBs
when compiling the same shader into a large number of pipelines.
2025-02-28 12:07:49 +01:00
Philip Rebohle
fcbdff3b72 [d3d9] Set correct input topology for SWVP emulation
Otherwise we'll run the input patch pass, even if it doesn't do anything.
2025-02-26 20:58:47 +01:00
Philip Rebohle
0359a3521d [dxvk] Patch geometry shader if input topology does not match pipeline 2025-02-26 20:53:43 +01:00
Philip Rebohle
b41253e18d [dxvk] Add pass to patch GS input topology if necessary 2025-02-26 20:53:43 +01:00
Philip Rebohle
96a260e94e [dxbc] Write back GS input topology to shader info 2025-02-26 20:53:43 +01:00
Philip Rebohle
2cb9d40f88 [dxvk] Add input topology field to shader info 2025-02-26 20:53:43 +01:00
Philip Rebohle
2cd305e606 [dxvk] Enable uniformBufferStandardLayout feature
Core and required in Vulkan 1.2, but keep it optional anyway for now
since we're not really doing anything critical with it.
2025-02-26 20:52:25 +01:00
Philip Rebohle
ec5bd04378 [dxvk] Remove uniform data from shaders
No longer used
2025-02-26 20:52:25 +01:00
Philip Rebohle
43f360d20c [d3d11] Move immediate constant buffers to non-mapped VRAM
This has the advantage that icbs can be defragmented and don't
take up space in HVV chunks that would potentially go unused.
2025-02-26 20:52:25 +01:00
Philip Rebohle
6f59124e9a [dxbc] Retrieve icb data directly from shader module 2025-02-26 20:52:25 +01:00
Philip Rebohle
d6d13edb7a [dxbc] Use smallest aligned vector type for buffer-backed ubo 2025-02-26 20:52:25 +01:00
Philip Rebohle
31192b6d3f [dxbc] Rework embedded immediate constant buffers
Considerably reduces the size of immediate constant buffer arrays when
not all vector components are used. Also adds bound-checking.
2025-02-26 20:52:25 +01:00
WinterSnowfall
31a4679960 [dxvk] Don't skip CPU devices when a device filter is set 2025-02-25 21:39:22 +01:00
Philip Rebohle
13bd234cea [dxvk] Actually fix multidraw workaround
Otherwise we'll end up using the feature anyway.
2025-02-25 14:18:05 +01:00
Philip Rebohle
dafb71b18e [d3d11] Add debug labels for submissions 2025-02-25 00:17:35 +01:00
Philip Rebohle
a0c8bbaf10 [dxvk] Add method to retrieve resource debug names 2025-02-25 00:17:31 +01:00
Philip Rebohle
9c395fd60d [dxvk] Disable VK_EXT_multi_draw on qcom drivers 2025-02-24 22:16:37 +01:00
Philip Rebohle
866228a37d [dxvk] Fix memory type selection for non-device local property flags
Fixes potential memory allocation issues on unified memory setups
that have unique memory types for different resources.
2025-02-24 22:16:37 +01:00
Philip Rebohle
60bf1f9ec4 [dxvk] Enable tiler mode on proprietary drivers as well
Not like it really hurts anyone.
2025-02-24 16:32:32 +01:00
Philip Rebohle
95e12decf1 [dxbc] Remove spammy debug logging 2025-02-24 15:40:52 +01:00
Philip Rebohle
e3f047a96a [d3d11] Remove d3d11.dcSingleUseMode option 2025-02-24 15:34:30 +01:00
Philip Rebohle
7208d06548 [dxvk] Clean up indirect draw unrolling
Also don't report explicit multidraw as merged draws, to be more
consistent with reporting in games that also use IndirectCount.
2025-02-23 18:58:19 +01:00
Philip Rebohle
fc3cf3e822 [d3d11] Properly initialize minUav counter
And also use it when resetting UAV bindings. Fixes a small oversight
that didn't affect correctness.
2025-02-23 13:34:11 +01:00
Philip Rebohle
c69dbc4490 [dxvk] Move draw and dispatch stat counters back to the context
Otherwise we'll count the HUD by accident. Only keep the barrier counter
since there are so many different places where we issue pipeline barriers,
and they are interesting anyway.
2025-02-23 13:24:28 +01:00
Philip Rebohle
a0ea29a2fa [hud] Display number of merged draws, if any 2025-02-23 13:24:28 +01:00
Philip Rebohle
9b37ba679a [dxvk] Add stat counter for merged draws 2025-02-23 13:24:28 +01:00
Philip Rebohle
016f05a770 [dxvk] Implement draw batching via VK_EXT_multi_draw 2025-02-23 13:24:28 +01:00
Philip Rebohle
7e503fa053 [dxvk] Enable VK_EXT_multi_draw if supported 2025-02-23 13:24:28 +01:00
Philip Rebohle
7815b6942d [d3d11] Implement direct draw batching
Not super useful without backend support though.
2025-02-23 13:24:28 +01:00
Philip Rebohle
fc3d3ae331 [dxvk,d3d11] Refactor CS command data allocation
Allows us to allocate a (potentially growing) array of
arbitrary data structures for a CS command.
2025-02-23 13:24:28 +01:00
Philip Rebohle
20dc389ab7 [d3d11] Skip unnecessary iterations when binding graphics UAVs
Some games will unconditionally use a high index for UAVStartSlot.
2025-02-23 12:06:51 +01:00
Philip Rebohle
9f9d51d52c [d3d11] Lazy-bind pixel shader UAVs
Moderately cursed because PS UAVs are also available to other graphics
stages.
2025-02-23 12:06:51 +01:00
Philip Rebohle
9389456d20 [d3d11] Lazy-bind compute shader UAVs
And factor UAV counter updates out of binding.
2025-02-23 12:06:51 +01:00
Philip Rebohle
69171873fa [d3d11] Add compile-time debug flag for lazy binding 2025-02-23 12:06:51 +01:00
Philip Rebohle
c0983a32be [d3d11] Reset dirty bindings on command submission 2025-02-23 12:06:51 +01:00
Philip Rebohle
3e6dfcfb15 [d3d11] Reset dirty tracking when re-applying context state 2025-02-23 12:06:51 +01:00
Philip Rebohle
9d890c75ac [d3d11] Don't template methods that restore shader bindings
This was only needed because Bind* methods were also templated.
2025-02-23 12:06:51 +01:00
Philip Rebohle
771f14c466 [d3d11] Refactor BindUnorderedAccessView
We won't do lazy bindings for UAVs, but at least bring this function
in line with the rest of the binding functions.
2025-02-23 12:06:51 +01:00
Philip Rebohle
b0d881046f [d3d11] Lazy-bind samplers 2025-02-23 12:06:51 +01:00
Philip Rebohle
f2ab76c8db [d3d11] Lazy-bind shader resources 2025-02-23 12:06:51 +01:00
Philip Rebohle
4fdbfffdcc [d3d11] Lazy-bind constant buffers 2025-02-23 12:06:51 +01:00
Philip Rebohle
a61c114519 [d3d11] Change AllowFlush behaviour
No functional change, just makes it less annoying to use in methods that
can be called from both immediate and deferred contexts-
2025-02-23 12:06:51 +01:00
Philip Rebohle
41ec7b6a02 [d3d11] Track shader stages with dirty bindings as well as used bindings 2025-02-23 12:06:51 +01:00
Philip Rebohle
be61341178 [d3d11] Rework DXBC shader stage to Vulkan shader stage mapping
We're going to have to do this at runtime, so this needs to be fast.
2025-02-23 12:06:51 +01:00
Philip Rebohle
6080e6d24d [d3d11] Store used binding mask inside shader objects 2025-02-23 12:06:51 +01:00
Philip Rebohle
75599780f2 [dxbc] Gather binding info during shader compilation 2025-02-23 12:06:51 +01:00
Philip Rebohle
5f16faaae0 [util] Generalize bit mask iterator 2025-02-23 12:06:51 +01:00
Robin Kertels
94b48c1633 [d3d9] Slightly clean up sampler slot handling 2025-02-21 13:25:23 +01:00
Robin Kertels
f7d56886c5 [d3d9] Fix sampler slot correction not respecting dmap texture 2025-02-21 13:25:23 +01:00
Philip Rebohle
0691a7fc46 [dxvk] De-duplicate drawIndirectCount implementations
No functional change, just some code cleanup.
2025-02-20 13:30:31 +01:00
Philip Rebohle
a135e01f89 [dxvk] Unroll merged indirect draws as necessary 2025-02-20 13:30:31 +01:00
Philip Rebohle
1d8fb818fc [dxvk] Check whether pipeline has potentially hazardous stores 2025-02-20 13:30:31 +01:00
Philip Rebohle
6f7a468174 [dxvk] Fix global render pass barrier
Only need to deal with common write-after-read scenarios, we can
ignore writes since those will add extra barriers anyway. Also
move this work out of the somewhat hot pipeline bind function.
2025-02-20 13:30:31 +01:00
Philip Rebohle
dd1ca4ce59 [dxvk] Track order-invariant access ops in barrier tracker
This elides barriers between draws or dispatches if we can prove
order-invariance through atomic operations.
2025-02-20 13:30:31 +01:00
Philip Rebohle
c475960754 [dxvk] Pass store op around for barrier tracking 2025-02-20 13:30:31 +01:00
Philip Rebohle
e01a6eec3e [dxbc] Track bindings with order-invariant atomic stores 2025-02-20 13:30:31 +01:00
Philip Rebohle
d94e3633dc [dxvk] Introduce concept of order-invariant atomic stores 2025-02-20 13:30:31 +01:00
Philip Rebohle
8c7da07085 [util] Fix enum declaration 2025-02-20 13:30:31 +01:00
WinterSnowfall
22052106d8 [d3d9] Relax logging level on validateGammaRamp 2025-02-20 00:01:10 +01:00
WinterSnowfall
3716d48c89 [d3d8/9] Use numeric_limits globally 2025-02-20 00:01:10 +01:00
WinterSnowfall
317607e192 [d3d8/9] Prevent device child ref underruns on release 2025-02-20 00:01:10 +01:00
Philip Rebohle
19361c962c [dxvk] Add debug region for barrier control 2025-02-19 19:34:52 +01:00
Philip Rebohle
636669e1a5 [dxvk] Improve handling of nested debug regions 2025-02-19 19:34:52 +01:00
Philip Rebohle
b03d457ffb [dxvk,d3d11] Improve explicit UAV overlap behaviour
If the app explicitly enables UAV overlap, don't synchronize
back-to-back read-modify-write operations to the same UAV either.
2025-02-19 19:34:52 +01:00
Philip Rebohle
a2c9c0f740 [d3d11] Use resource cookies for draw buffer tracking
Avoids keeping draw buffers alive when the app stops using indirect
draws. Unlikely to have caused issues in practice, but draw buffers
are not part of the API state to begin with.
2025-02-19 19:34:52 +01:00
Philip Rebohle
07f7ccdc96 [dxvk,d3d11] Fix draw buffer tracking for DrawAuto
Not like anybody uses this feature, but we need to both check for
hazards and make sure the SO counter actually gets tracked. Use
the existing draw buffer mechanism for this.
2025-02-19 19:34:52 +01:00
Philip Rebohle
d37a13847a [dxvk] Rename and repurpose ignoreGraphicsBarriers option
Less nuclear approach that hopefully works just as well in practice.
2025-02-19 19:34:52 +01:00
Philip Rebohle
18e5c12b6d [dxvk] Fix resource hazard checks
Turns out we've had broken write-after-read checks for a while.
2025-02-19 19:34:52 +01:00
Philip Rebohle
48d145fff6 [dxvk] Change debug color for pipelines with side effects 2025-02-19 19:34:52 +01:00
Philip Rebohle
04d2609a91 [dxvk] Clean up shader resource hazard checking 2025-02-19 19:34:52 +01:00
Philip Rebohle
3bbae86ec9 [dxvk] Rework compute barrier tracking 2025-02-19 19:34:52 +01:00
Philip Rebohle
53b076be61 [dxvk] Rework graphics barrier tracking
Avoids having to insert redundant barriers when the app does UAV rendering.
2025-02-19 19:34:52 +01:00
Philip Rebohle
009f8ee356 [dxvk] Emit barriers when updating shader resources 2025-02-19 19:34:52 +01:00
Philip Rebohle
be9391ded5 [dxvk] Track transform feedback buffer access 2025-02-19 19:34:52 +01:00
Philip Rebohle
96337f11d4 [dxvk] Track vertex buffer access 2025-02-19 19:34:52 +01:00
Philip Rebohle
24b58e5858 [dxvk] Track index buffer access 2025-02-19 19:34:52 +01:00
Philip Rebohle
21eb682b39 [dxvk] Track indirect draw buffer access 2025-02-19 19:34:52 +01:00
Philip Rebohle
a7c1e7a2a0 [dxvk] Add resource flag to track graphics pipeline side effects 2025-02-19 19:34:52 +01:00
Philip Rebohle
978d7cb65b [dxvk] Add more convenience methods to track buffer barriers 2025-02-19 19:34:52 +01:00
Philip Rebohle
23067c48c7 [dxvk] Clean up CS chunk allocation
This also makes it more robust w.r.t. alignment.
2025-02-18 15:37:11 +01:00
Philip Rebohle
4c8ee300b5 [util] Add more optimal popcnt implementation 2025-02-18 15:28:41 +01:00
Robin Kertels
4282829f38 [d3d9] Route operations on unmappable memory through allocator
Fixes an extremely race condition that can happen when freeing a chunk.
2025-02-17 19:23:15 +01:00
WinterSnowfall
92523fc0dd [d3d9] Fix x64 crash on SetVertexShaderConstantF index overflow 2025-02-17 15:11:05 +01:00
WinterSnowfall
4a89b75bb7 [d3d8] Fix x64 crash on shader validation 2025-02-17 15:11:05 +01:00
WinterSnowfall
274c590ad6 [d3d9] Set priority only for D3DPOOL_MANAGED/DEFAULT resources 2025-02-17 15:11:05 +01:00
WinterSnowfall
84b2ac3f97 [d3d8] Set priority only for D3DPOOL_MANAGED resources 2025-02-17 15:11:05 +01:00
WinterSnowfall
8efa3ed84a [d3d8] A few minor formatting adjustments 2025-02-17 15:11:05 +01:00
Robin Kertels
3269f92138 [d3d9] Fix mismatching texture type mask updates 2025-02-17 14:32:34 +01:00
Jeff
0aebedae16 [d3d8] Add shadow perspective divide hack for Splinter Cell 2025-02-17 14:10:54 +01:00
Philip Rebohle
f2802dd2ff [dxvk] Fix some potential image layout bugs 2025-02-17 01:26:03 +01:00
Philip Rebohle
9389a0ca96 [dxvk] Don't transition image layout in clearImageViewCs unless necessary 2025-02-17 01:26:03 +01:00
Philip Rebohle
6d9e0baa27 [dxvk] Don't hold queue lock when invoking periodic memory tasks 2025-02-14 14:34:33 +01:00
Philip Rebohle
9573c389de [dxvk] Don't create GPL pipeline if we need to patch the vertex shader
Works around a game bug in Kingdom Come Deliverance and silences a validation
error.
2025-02-13 18:46:49 +01:00
Philip Rebohle
3453732bba [dxvk] Fix clear optimization edge case with multi-planar images 2025-02-12 21:42:27 +01:00
Philip Rebohle
0a84dbb787 [dxvk] Implement resolves with a render target clear if possible
Same idea as for copies, if the last use of the source image was a clear
then we can simply clear the destination image instead of performing a
much more expensive resolve operation.
2025-02-12 21:42:27 +01:00
Philip Rebohle
f5a5ec7c88 [dxvk] Factor out method to find pending deferred clears 2025-02-12 21:42:27 +01:00
Philip Rebohle
1cabbee2bb [dxvk] Rework render pass resolves
In an attempt to also support batching layered resolves.
2025-02-12 21:42:27 +01:00
Philip Rebohle
563129c863 [dxvk] Fix potential resolve attachment invalidation bug 2025-02-12 14:44:54 +01:00
Philip Rebohle
c5a3aa73a0 [util] Enable dummy composition swap chain for an upcoming game 2025-02-12 01:36:10 +01:00
Philip Rebohle
80bfd2ed97 [util] Add functionality to support hashed app profiles 2025-02-12 01:34:40 +01:00
Philip Rebohle
813ae020b6 [d3d11] Flush more around non-multisampled render passes 2025-02-11 16:14:53 +01:00
Philip Rebohle
7e3c6f819a [util] Add new flush type for render pass boundaries 2025-02-11 16:14:53 +01:00
Philip Rebohle
94b5cfc3d8 [dxvk] Don't use secondary command buffers for certain render passes
If we can't use any store/resolve op optimizations on a render pass, there
is no reason to pay for the overhead of secondary command buffers.
2025-02-11 16:14:53 +01:00
Philip Rebohle
beaf6dd2a6 [dxvk] Add context flag for active secondary command buffers
Makes some checks more explicit.
2025-02-11 16:14:53 +01:00
Philip Rebohle
cf9ccf711b [dxvk] Add perf hint to avoid secondary command buffers 2025-02-11 16:14:53 +01:00
Philip Rebohle
94254f556e [dxvk] Fix stencil resolve mode 2025-02-11 15:26:08 +01:00
Philip Rebohle
70492b2954 [dxvk] Avoid locking built-in latency tracker when calling into presenter
Same reason as for the Reflex one.
2025-02-11 15:12:13 +01:00
Philip Rebohle
b1174a1bdf [dxvk] Avoid locking Reflex latency tracker when calling into presenter
There are complex deadlock conditions during swap chain destruction.
2025-02-11 15:12:13 +01:00
Philip Rebohle
efeb15edbd [dxvk] Fix lack of forward progress guarantee in presenter
Turns out that relying on two threads to unblock another was a bad idea.
Fixes a potential deadlock w.r.t. swapchain recreation with Reflex.
2025-02-11 15:12:13 +01:00
Philip Rebohle
ac17d5f9b1 [dxvk] Enable tiler mode for more drivers 2025-02-10 18:36:01 +01:00
Philip Rebohle
11ec65d516 [include] Update Vulkan headers 2025-02-10 17:44:36 +01:00
Neal Gompa
4d3b35ae53 meson: Fix version construct by dropping the "v" prefix
The "v" prefix was causing the version to be incorrectly set for
generated files (such as pc files for pkg-config).

Dropping the prefix fixes the issue.
2025-02-10 16:38:03 +01:00
Philip Rebohle
3aeedb9c98 [d3d11] Forward DiscardResource calls to backend for images 2025-02-10 16:13:31 +01:00
Philip Rebohle
9b5499caf2 [dxvk] Ignore deferred discards that we can't fold into load ops 2025-02-10 16:13:31 +01:00
Philip Rebohle
fcabffc1e5 [dxvk] Add store op optimization for image discards in tiler mode 2025-02-10 16:13:31 +01:00
Philip Rebohle
821386aeff [dxvk] Add config option to toggle tiler optimizations 2025-02-10 16:13:31 +01:00
Philip Rebohle
fa2d791d79 [dxvk] Use resolve attachments if possible 2025-02-10 16:13:31 +01:00
Philip Rebohle
80fb7e2294 [d3d9,d3d11] Adjust flush heuristic on tiling GPUs
Probably needs work, just disable most of the heuristic for the time being.
2025-02-10 16:13:31 +01:00
Philip Rebohle
00299b264b [dxvk] Use secondary command buffers for rendering on tiling GPUs 2025-02-10 16:13:31 +01:00
Philip Rebohle
4a92b92f58 [dxvk] Add perf hint for tiling GPUs 2025-02-10 16:13:31 +01:00
Philip Rebohle
6c1bc35264 [dxvk] Add functionality to use secondary command buffers 2025-02-10 16:13:31 +01:00
Philip Rebohle
7d35afdc37 [dxvk] Add functionality to allocate secondary command buffer 2025-02-10 16:13:31 +01:00
Philip Rebohle
f615594f22 [dxgi] Create dummy window for composition swap chains
Obviously not a valid implementation, but allows composition swap chains
to exist with some basic functionality.
2025-02-10 14:23:12 +01:00
Philip Rebohle
76f9bec7cc [dxgi] Add option to expose composition swapchains 2025-02-10 14:14:38 +01:00
WinterSnowfall
0a19e5b6db [d3d8] Store the value of D3DRS_ZVISIBLE 2025-02-10 11:25:40 +01:00
WinterSnowfall
946419cda2 [d3d8] Fix invalid casting in GetRenderState 2025-02-10 11:25:40 +01:00
WinterSnowfall
13554f18bd [d3d9] Update software cursor position using SetCursorPosition 2025-02-08 22:28:48 +01:00
Blisto91
54a26dde3d [util] Disable dcSingleUseMode for Cardfight!! Vanguard Dear Days 2 2025-02-07 19:53:45 +01:00
Philip Rebohle
357484bd4b [d3d11] Don't call Flush from swap chain code
Use internal function instead.
2025-02-06 23:26:05 +01:00
Philip Rebohle
9664e0b850 [dxvk] Fix potential race conditions w.r.t. swapchain destruction
The signaling thread can queue up a wait while the swapchain is being
destroyed, which blows up. This also fixes a related race condition
where we would queue up a wait using the wrong present mode.

This is somewhat fragile in the sense that the queue worker *must* call
signalFrame for each and every present, or this will fall apart.
2025-02-06 20:25:32 +01:00
Philip Rebohle
e5a81f8c7e [dxvk] Don't probe buffer compatibility on image-only memory types
Silences a validation error.
2025-02-06 15:29:24 +01:00
Philip Rebohle
215cebc019 [dxvk] Remove superfluous function declaration 2025-02-06 14:29:19 +01:00
Philip Rebohle
a413eb0843 [dxvk] Only end render pass in invalidateImage if currently bound
Not really needed otherwise.
2025-02-05 22:49:25 +01:00
Philip Rebohle
0434b23167 [dxvk] Fix initializing buffers with non-dword sizes
Fixes #4641. This should be very rare in general though.
2025-02-05 18:36:01 +01:00
Philip Rebohle
cf946eb981 [dxvk] Add setupapi as a Windows WSI dependency 2025-02-02 21:22:19 +01:00
Philip Rebohle
3a34dae722 [dxvk] Work around locale-dependent regex parsing crash 2025-02-02 21:21:58 +01:00
WinterSnowfall
bd69d1efdc [d3d8/9] Use shader version macros where applicable 2025-02-02 18:17:10 +01:00
WinterSnowfall
e3f1d4c021 [d3d8] Fix up swizzle for all opcodes requiring a replicate swizzle 2025-02-02 18:17:10 +01:00
Philip Rebohle
5569274a97 [d3d9] Do not assume 16-byte alignment in replaceNaN
Stack alignment is 4 bytes on 32-bit, and we cannot align variables
on the stack, so this is technically broken.
2025-02-02 10:50:33 +01:00
WinterSnowfall
dd5b28e557 [d3d8] Use D3D8 compatibilty mode to set HUD API level 2025-02-02 10:47:32 +01:00
HunterCZ122
8860bde34b [util] Fix black screen after alt-tab for Trainz 2025-01-31 22:47:37 +01:00
Blisto91
8776cf2ce6 [util] Cleanup some deviceLossOnFocusLoss configs
These game work fine out of the box now
missed
2025-01-30 18:22:18 +01:00
Autumn Ashton
0cad97d5ec [util] Add scaleDref to SplinterCell2 2025-01-30 02:58:15 +00:00
Jeff
06bdc88eb6 [d3d8] Restore config for Splinter Cell 2025-01-30 01:59:22 +00:00
WinterSnowfall
1d90772eb2 [d3d9] Report vertex texture filtering support only for SM3 2025-01-27 18:53:10 +01:00
VPInventions
3d35925a05 Assign viewInfo.minLayer for D3D11VideoProcessorInputView 2025-01-27 18:48:46 +01:00
WinterSnowfall
5b21286377 [d3d9] Adjust SM2 VS/PS caps 2025-01-26 21:52:18 +01:00
WinterSnowfall
ad0920fe1e [d3d9] Relax SM2 minor version checks on shader creation 2025-01-26 20:02:45 +01:00
WinterSnowfall
c6dc7e0939 [d3d8/9] Proper (and age accurate) handling of d3d9.shaderModel = 0 2025-01-26 13:56:27 +01:00
WinterSnowfall
48d24893d4 [d3d8] Clean up and document D3D8-specific caps 2025-01-26 13:50:41 +01:00
WinterSnowfall
753c11d144 [d3d8] Implement SCRATCH pool copies with CopyRects 2025-01-26 13:50:41 +01:00
WinterSnowfall
7482e45534 [d3d8] Remove several empty explicit destructors 2025-01-26 13:50:41 +01:00
WinterSnowfall
e757170211 [d3d8] Remove superfluous methods from D3D8Surface 2025-01-26 13:50:41 +01:00
WinterSnowfall
e2a078d534 [d3d8] Properly return the value of D3DRS_SOFTWAREVERTEXPROCESSING 2025-01-26 13:50:41 +01:00
WinterSnowfall
d846e89a4b [d3d8] Improve handling of FullScreen_PresentationInterval 2025-01-26 13:50:41 +01:00
WinterSnowfall
e40f03b96a [d3d8] General TODO and comment cleanup 2025-01-26 13:50:41 +01:00
WinterSnowfall
088915e24c [d3d8] Don't forward D3DRS_ZVISIBLE changes to d3d9 2025-01-26 13:50:41 +01:00
WinterSnowfall
470764e24c [d3d8] Don't forward D3DRS_PATCHSEGMENTS changes to d3d9 2025-01-26 13:50:41 +01:00
WinterSnowfall
0983ab1f39 [d3d8] Don't forward D3DRS_LINEPATTERN changes to d3d9 2025-01-26 13:50:41 +01:00
WinterSnowfall
20b047600f [d3d8] Disable z-buffer discarding for depth stencil surfaces 2025-01-26 13:50:41 +01:00
WinterSnowfall
b61ea1db76 [d3d8] Address the MultiSampleQuality usage 2025-01-26 13:50:41 +01:00
WinterSnowfall
4184452f49 [d3d8] Validate srcRect/destPoint dimensions in UpdateTextureFromBuffer 2025-01-26 13:50:41 +01:00
Philip Rebohle
736ee20eb5 [d3d11] Implement ID3DLowLatencyDevice 2025-01-25 18:02:20 +01:00
Philip Rebohle
4f9b106d40 [d3d11] Stub out ID3DLowLatencyDevice for D3D11 2025-01-25 18:02:20 +01:00
Philip Rebohle
86c317fbbc [d3d11] Add ID3DLowLatencyDevice definitions 2025-01-25 18:02:20 +01:00
Philip Rebohle
59e53c1863 [d3d11] Add queue parameter to CS chunk injection 2025-01-25 18:02:20 +01:00
Philip Rebohle
539da5abdf [dxvk] Refactor CS chunk queues
Introduces two queues and allows us to dispatch chunks to the ordered
queue without disrupting the sequence number.
2025-01-25 18:02:20 +01:00
Philip Rebohle
0e9efa5183 [dxvk] Implement Reflex latency tracker 2025-01-25 18:02:20 +01:00
Philip Rebohle
4b009237d7 [dxvk] Add NV_low_latency2 path to latency tracker 2025-01-25 18:02:20 +01:00
Philip Rebohle
66dc0a9383 [dxvk] Pass present IDs to command submissions as necessary 2025-01-25 18:02:20 +01:00
Philip Rebohle
4c2990f199 [dxvk] Implement NV_low_latency2 functionality in presenter 2025-01-25 18:02:20 +01:00
Philip Rebohle
c700d76477 [dxvk] Add option to disable VK_NV_low_latency2 2025-01-25 18:02:20 +01:00
Philip Rebohle
859117797f [dxvk] Enable VK_NV_low_latency2 if supported 2025-01-25 18:02:20 +01:00
Philip Rebohle
4fcbf52752 [d3d9] Always limit to display refresh in low latency mode 2025-01-25 18:02:20 +01:00
Philip Rebohle
0e3ed707ba [d3d9] Implement latency tracking 2025-01-25 18:02:20 +01:00
Philip Rebohle
50375ee1ee [dxgi] Pass display refresh in windowed mode if latency sleep is enabled 2025-01-25 18:02:20 +01:00
Philip Rebohle
21f69eceaa [d3d11] Implement latency tracking 2025-01-25 18:02:20 +01:00
Philip Rebohle
23f08eaedd [hud] Add frame latency item 2025-01-25 18:02:20 +01:00
Philip Rebohle
2ee598b4af [dxvk] Add latency tracker to context 2025-01-25 18:02:20 +01:00
Philip Rebohle
95b8dc59fb [dxvk] Add latency tracker to presenter 2025-01-25 18:02:20 +01:00
Philip Rebohle
273e4abb14 [dxvk] Add latency tracker to queue submissions 2025-01-25 18:02:20 +01:00
Philip Rebohle
552470de63 [dxvk] Add latency tracker
Implements a basic latency sleep solution that is intended to work
without requiring games to support any related vendor features.

This alone is not enough to expose the Reflex API to applications via
dxvk-nvapi, but since that relies on NV_low_latency2 specifics anyway,
we are going to add an implementation based on that extension later
with an extended interface.
2025-01-25 18:02:20 +01:00
Philip Rebohle
55639889c7 [util] Expose frame rate environment variable
We'll need this in more places.
2025-01-25 18:02:20 +01:00
Philip Rebohle
53e5c4875f [util] Add parameter to initialize small_vector with a given size
Matches std::vector.
2025-01-25 18:02:20 +01:00
Blisto91
b73f9d8ecb [util] Extend Battlefield 2/2142 config to Project Reality 2025-01-22 19:56:41 +01:00
Vasiliy Stelmachenok
84ccad3528 [build] Use -mpreferred-stack-boundary=2 on 32-bit x86
Signed-off-by: Vasiliy Stelmachenok <ventureo@cachyos.org>
2025-01-21 21:17:28 +01:00
Blisto91
a3ba8fb4dc [util] Add configs for Star Wars Empire at War
In both the base game and expansion the Water and Shader Detail options are locked at their lowest value when they see Intel.
In the base game (not expansion) the AA option disappears for some reason whenit sees vram at 2075MB and above.
2025-01-20 23:01:25 +01:00
Vasiliy Stelmachenok
685126482d [d3d11] Fix missing argument reference
Signed-off-by: Vasiliy Stelmachenok <ventureo@cachyos.org>
2025-01-20 22:59:54 +01:00
Philip Rebohle
863591275c [dxvk] Error out on surface creation again
Unless it's NATIVE_WINDOW_IN_USE. Should fix a regression where
D3D swapchain creation would succeed on out-of-memory errors.
2025-01-20 18:20:14 +01:00
Philip Rebohle
c52a68a5be [dxvk] Fix typo that breaks HDR metadata 2025-01-16 17:47:56 +01:00
Philip Rebohle
5ed2d990af [d3d9] Fix software cursor texture format
The new code expects texture reads to be in linear space, so we need
to use an sRGB format here.
2025-01-16 12:05:17 +01:00
Philip Rebohle
3dbe8ad43c [d3d9] Rework device reset detection
More robust.
2025-01-16 11:38:39 +01:00
Philip Rebohle
f9c3dd1f5f [d3d9] Remove explicit swapchain synchronization
No longer necessary.
2025-01-16 11:38:39 +01:00
Philip Rebohle
c43cf6895b [d3d9] Refactor presenter management
There's basically no reason to ever recreate a presenter for an already
managed window with the new code.
2025-01-16 11:38:39 +01:00
Philip Rebohle
785649f3b8 [d3d11] Remove explicit swapchain synchronization 2025-01-16 11:38:39 +01:00
Philip Rebohle
42adc4ac11 [dxvk] Perform acquire and present synchronization in the backend
And add method to explicitly destroy relevant Vulkan objects.
2025-01-16 11:38:39 +01:00
Philip Rebohle
b03ff775ce [dxvk] Do not initialize present status from presentImage
Meaningless, this needs to be done elsewhere anyway.
2025-01-16 11:38:39 +01:00
Philip Rebohle
81c3242b6d [dxvk] Dirty swapchain if present returns SUBOPTIMAL
May fix some issues in case the WSI implementation can return SUBOPTIMAL
from present but not acquire. Also ensure to keep state consistent.
2025-01-16 11:38:39 +01:00
Philip Rebohle
816f8e9c87 [dxvk] Improve swapchain debug logging 2025-01-16 11:38:39 +01:00
Philip Rebohle
0f9245ff33 [d3d9,d3d11] Remove numBackBuffers option
Useless.
2025-01-16 11:38:39 +01:00
Philip Rebohle
cb42ea21be [dxvk] Adjust swapchain format preferences in various cases
For sRGB, using a native sRGB format allows the swapchain blitter
to use a more efficient code path for drawing the HUD.

Also allow RGB9E5 for sRGB and HDR10.
2025-01-16 11:38:39 +01:00
Philip Rebohle
d200184306 [dxvk] Rework swapchain composition
Also adds a separate set of shaders for the software cursor, provided it
can be drawn directly with alpha blending.
2025-01-16 11:38:39 +01:00
Philip Rebohle
a09d372caf [dxvk] Prepare swapchain blitter for compositing HUD and cursor
This will be necessary for non-linear color spaces to get proper blending.
2025-01-16 11:38:39 +01:00
Philip Rebohle
8be30d7d5a [hud] Add method to check whether HUD is empty 2025-01-16 11:38:39 +01:00
Philip Rebohle
5134a4b3c5 [dxvk] Move HUD update and rendering into swapchain blitter 2025-01-16 11:38:39 +01:00
Philip Rebohle
c1ed8cd1f3 [hud] Add function to change API name dynamically
Needed for D3D8 due to implicit swapchain shenanigans.
2025-01-16 11:38:39 +01:00
Philip Rebohle
0eeedf9259 [hud] Allow returning HUD item objects to the caller 2025-01-16 11:38:39 +01:00
Philip Rebohle
d5744e5a81 [dxvk] Enable automatic fallbacks for HDR color spaces
The swap chain blitter can deal with the conversion.
2025-01-16 11:38:39 +01:00
Philip Rebohle
d85d07c0ec [dxvk] Infer swap chain color space from image views 2025-01-16 11:38:39 +01:00
Philip Rebohle
1d790970d5 [d3d9] Set color space for swap chain image 2025-01-16 11:38:39 +01:00
Philip Rebohle
b586294e29 [d3d11] Set color space for swap chain image 2025-01-16 11:38:39 +01:00
Philip Rebohle
ed3c02906c [dxvk] Set color space for swap chain back buffers 2025-01-16 11:38:39 +01:00
Philip Rebohle
84317f913a [dxvk] Don't redundantly update image debug names 2025-01-16 11:38:39 +01:00
Philip Rebohle
ff41a5ab12 [dxvk] Add color space property to image description 2025-01-16 11:38:39 +01:00
Philip Rebohle
ad11509e83 [dxvk] Soften error reporting from the presenter 2025-01-16 11:38:39 +01:00
Philip Rebohle
43838d3df8 [dxvk] Move Vulkan swapchain management to backend
Massive cleanup reduce code duplication between D3D11 and D3D9,
and introduce a sane path to pass data around. Implicit swap
chain recreation is now entirely transparent to the frontends.
2025-01-16 11:38:39 +01:00
Philip Rebohle
06b44c6237 [dxvk] Rework HDR metadata updates 2025-01-16 11:38:39 +01:00
Philip Rebohle
63e88debee [dxvk] Move deferSurfaceCreation handling to backend 2025-01-16 11:38:39 +01:00
Philip Rebohle
ab9646551f [dxvk] Import swap chain images from the back-end 2025-01-16 11:38:39 +01:00
Philip Rebohle
073806df7c [dxvk] Move surface creation to the backend 2025-01-16 11:38:39 +01:00
Philip Rebohle
c707d9026f [meta] Release 2.5.3 2025-01-13 16:20:20 +01:00
Blisto91
3d401690cb [util] Enable Strict floatEmulation for Max Payne 3
Visual issues such as white, black or rainbow colored objects and effect on some driver such as ANV (and amdvlk when set to true)
2025-01-13 16:17:36 +01:00
Philip Rebohle
5f5c9a4cdd [d3d9] Improve logging for PS input register indices 2025-01-13 15:38:25 +01:00
Philip Rebohle
af45295a2f [d3d9] Log instruction stream in validator 2025-01-13 15:38:25 +01:00
Jeff
5b7726cf6f [d3d9] Fix invalid strings returned by GetInstanceExtensions 2025-01-13 11:08:45 +01:00
Philip Rebohle
d5832c3075 [dxbc] Improve code gen for zeroing workgroup memory 2025-01-12 14:10:47 +01:00
Philip Rebohle
f17317061c [dxbc] Bound-check dynamically indexed input registers
Halo MCC reads undefined PS inputs otherwise.
2025-01-12 14:10:47 +01:00
Blisto91
7f4e25267c [util] Enable hideIntegratedGraphics for Bright memory
The game will prefer other vendors over Intel even if the latter is the dGPU in the system. It likely assumes that Intel is always a iGPU.
This also happens with the native game on Windows and so isn't a Linux exclusive. Both in d3d11 and d3d12 mode.
2025-01-11 16:55:00 +01:00
Blisto91
07397305f1 [util] Enable zeroInitWorkgroupMemory for Far Cry 5 and New Dawn 2025-01-11 16:45:06 +01:00
Philip Rebohle
efb9d444c1 [dxvk] Introduce config option to enable FSE on Windows 2025-01-10 14:07:55 +01:00
Philip Rebohle
071dec7148 [hud] Add debug label for HUD rendering 2025-01-09 16:25:46 +01:00
Philip Rebohle
279c6f150a [dxvk] Add debug label for swap chain blitter 2025-01-09 16:25:46 +01:00
Philip Rebohle
50f9630250 [dxvk] Add debug regions for internal operations 2025-01-09 16:25:46 +01:00
Philip Rebohle
485090d039 [dxvk] Add debug region for mip generation 2025-01-09 16:25:46 +01:00
Philip Rebohle
498ecca81d [dxvk] Add debug region for memory defragmentation 2025-01-09 16:25:46 +01:00
Philip Rebohle
9bb06baaaa [dxvk] Add debug labels for pipeline binding 2025-01-09 16:25:46 +01:00
Philip Rebohle
ca2afb0b8b [dxvk] Add debug label for render target clears 2025-01-09 16:25:46 +01:00
Philip Rebohle
1b9ea8c6e3 [dxvk] Add debug regions for render passes 2025-01-09 16:25:46 +01:00
Philip Rebohle
d9b5f09239 [dxvk] Add debug region stack
Ensures that we correctly begin and end app-provided regions within
each command buffer.
2025-01-09 16:25:46 +01:00
Philip Rebohle
71bd780340 [dxvk] Add debug regions to command buffers 2025-01-09 16:25:46 +01:00
Philip Rebohle
b62a8c78b4 [dxvk] Add context feature flag for debug utils support 2025-01-09 16:25:46 +01:00
Philip Rebohle
8c3d7a1979 [d3d11] Support debug names for buffers and textures
Co-authored-by: Aaron Leiby <aleiby@gmail.com>
2025-01-09 16:25:46 +01:00
Philip Rebohle
4970dc3358 [d3d11] Set debug names for internal buffers 2025-01-09 16:25:46 +01:00
Philip Rebohle
1721be4973 [d3d9] Set debug names for internal buffers 2025-01-09 16:25:46 +01:00
Philip Rebohle
d2d46be8da [dxvk] Set debug names for memory allocations
Makes it easier to work out what is allocated where.
2025-01-09 16:25:46 +01:00
Philip Rebohle
3339b165cd [dxvk] Set debug names for internal buffers 2025-01-09 16:25:46 +01:00
Philip Rebohle
3e77893ef7 [dxvk] Set debug names for swap chain blitter resources 2025-01-09 16:25:46 +01:00
Philip Rebohle
098d5adca5 [hud] Set debug names for HUD resources 2025-01-09 16:25:46 +01:00
Philip Rebohle
2507820339 [dxvk] Add support for resource debug names 2025-01-09 16:25:46 +01:00
Philip Rebohle
7f4f927980 [dxvk] Add command buffer parameter to debug label functions 2025-01-09 16:25:46 +01:00
Philip Rebohle
5487f8b9a0 [dxvk] Add convenience methods to check for debug utils support 2025-01-09 16:25:46 +01:00
WinterSnowfall
4151d35e8e [d3d8] Alignment and formatting improvements 2025-01-09 15:50:46 +01:00
WinterSnowfall
639f815432 [d3d8] Refactor D3D8Vertex/IndexBuffer implementation 2025-01-09 15:50:46 +01:00
WinterSnowfall
13ec120289 [d3d8] Refactor D3D8Surface implementation 2025-01-09 15:50:46 +01:00
WinterSnowfall
9d37e4abb4 [d3d8] Refactor D3D8Volume implementation 2025-01-09 15:50:46 +01:00
WinterSnowfall
7bb8819fbc [d3d8] Refactor D3D8Texture2D/3D/Cube implementation 2025-01-09 15:50:46 +01:00
WinterSnowfall
8017607fe7 [d3d8] Refactor D3D8SwapChain implementation 2025-01-09 15:50:46 +01:00
WinterSnowfall
84ad2ea261 [d3d8] Properly initialize state block data 2025-01-09 15:50:46 +01:00
WinterSnowfall
8ead28e481 [d3d8] Unify source file endline delimiters 2025-01-09 15:50:46 +01:00
WinterSnowfall
475bf4e9c1 [d3d9] Use cdw to iterate over register tokens in D3D9ShaderValidator 2025-01-07 17:49:18 +01:00
WinterSnowfall
150cb0d4c7 [d3d9] Refactor the D3D9ShaderValidator implementation 2025-01-06 18:55:37 +01:00
WinterSnowfall
28a08cae6d [d3d8/9] Clear pLockedRect/Box contents universally on lock 2025-01-06 15:52:42 +01:00
Philip Rebohle
9a244e8951 [dxbc] Use NClamp for tess factors and depth clamp
This flushes NaN tess factors to 0, which should match D3D behaviour
for both outer and inner tess factors. The legacy code hasn't been
touched in 7 years.
2025-01-04 17:41:50 +01:00
Robin Kertels
24f98c5835 [d3d9] Skip texture type check when forceSpecConst option is active 2025-01-04 02:11:58 +00:00
esullivan
33498eb512 [spirv] Emit the grad and const offset image ops in the correct order
Currently the grad and const offset image operand ids are emitted in the
incorrect order. This causes incorrect code gen if both the grad and const
offset image operands are used.

This fixes the compilation error found when running TopSpin 2k25 through
DXVK using the NVIDIA proprietary Vulkan driver.
2025-01-03 23:30:56 +01:00
Blisto91
8b9b46dfff [util] Cap fps in The hurricane of the Varstray 2025-01-01 23:42:56 +01:00
Blisto91
7425a33dd7 [util] Merge the Arcana Heart 3 entries 2025-01-01 23:42:56 +01:00
spiffeeroo
39f4d804a2 [util] Limit frame rate to 60 fps for Arcana Heart 3 Love Max!!!!! and Arcana Heart 3 Love Max Six Stars!!!!!! Xtend
[Arcana Heart 3 Love Max!!!!!](https://store.steampowered.com/app/370460) runs too fast when frame rate is above 60 fps (like on high refresh rate monitor). Limit frame rate to 60 fps so game runs at correct speed.

[Arcana Heart 3 Love Max Six Stars!!!!!! Xtend](https://store.steampowered.com/app/661990) also suffers from the game speed being too fast while in windowed mode. Limit frame rate to 60 fps to fix game speed.
2025-01-01 19:46:37 +01:00
Robin Kertels
1eb0c687a6 [d3d9] Fix messing up the dirty textures bitmask 2024-12-20 18:26:02 +01:00
Philip Rebohle
b4faf0bb3e [meta] Release 2.5.2 2024-12-20 13:37:07 +01:00
Robin Kertels
acf93aa70a [util] Remove Alpha Protocol config
The texture type check makes this redundant.
2024-12-17 14:49:52 +01:00
Robin Kertels
65843aa016 [d3d9] Don't bind textures if texture type doesnt match 2024-12-17 14:49:52 +01:00
Tiagoquix
67f4ec73aa [util] Adjust "Earth Defense Force 5" position
Game uses D3D11 according to https://www.pcgamingwiki.com/wiki/Earth_Defense_Force_5#API. Currently it's listed in the D3D9 section.
2024-12-16 23:05:33 +01:00
Philip Rebohle
d1789c4d85 [dxvk] Always consider env var configuration as active
Fixes #4529.
2024-12-15 16:51:32 +01:00
Blisto91
fb8f79e4a7 [util] Add Sims 2 Content Manager & HomeCrafter Plus 2024-12-12 14:02:00 +01:00
Blisto91
0997719a73 [util] Set textureMemory to 0 for Dark Sector
Works around some crashes
2024-12-12 14:01:40 +01:00
Philip Rebohle
5868b067e4 [dxgi] Use VK_FORMAT_A8_UNORM if supported 2024-12-10 01:16:44 +01:00
Philip Rebohle
32399461da [dxvk] Properly encode KHR_maintenance5 formats 2024-12-10 01:16:44 +01:00
WinterSnowfall
4dd0afe121 [d3d9] Validate depth and stencil clears 2024-12-10 01:16:24 +01:00
Jeff
d1abce3be2 [d3d9] Add GetInstanceExtensions to interop API 2024-12-09 18:11:46 +01:00
Philip Rebohle
45da7d6678 [d3d11] Fix rectangle check in ClearView
It is legal to pass a potentially invalid pointer if NumRects is 0.
Fixes validation errors in TopSpin 2k25.
2024-12-09 17:43:53 +01:00
WinterSnowfall
b1ad43145b [d3d8] Add missing include to d3d8_state_block.h 2024-12-05 23:43:23 +01:00
Tiagoquix
a78c1bd6dd [util] Separate Borderlands 2 fixes from Borderlands: The Pre-Sequel 2024-12-05 15:00:19 +01:00
WinterSnowfall
d094053018 [d3d9] Implement several IDirect3DShaderValidator9 validations
Co-Authored-By: Joshua Ashton <joshua@froggi.es>
Co-Authored-By: Paul Gofman <gofmanp@gmail.com>
2024-12-05 14:59:56 +01:00
Autumn Ashton
d956b188ed [d3d9] Clip plane compaction
Compact clip planes to the smallest amount that are enabled.

Signed-off-by: Autumn Ashton <misyl@froggi.es>
2024-12-05 06:08:34 +00:00
Autumn Ashton
8c4c814fb7 [d3d9] Spec-constant out writes to clip distances when disabled
Add a new spec constant with a mask of the enabled clip planes such that they can be optimized out to improve performance.

For GPL shaders, override what we return here so it's always true and don't bother putting the mask in the UBO.

Signed-off-by: Autumn Ashton <misyl@froggi.es>
2024-12-05 06:08:34 +00:00
WinterSnowfall
027fe5963a [d3d9] Fixes for state block specific behavior 2024-12-04 13:06:28 +01:00
WinterSnowfall
17b85accfb [d3d9] Adjust device reset failure error codes 2024-12-04 13:06:28 +01:00
WinterSnowfall
f23c74949a [d3d9] Validate supported formats in D3D9Surface::GetDC 2024-12-04 13:06:28 +01:00
WinterSnowfall
fb56668dc0 [d3d9] Adjust out of bounds clip plane index handling 2024-12-04 13:06:28 +01:00
WinterSnowfall
9c012c8e75 [d3d9] Skip recording MultiplyTransform calls in state blocks 2024-12-04 13:06:28 +01:00
WinterSnowfall
640a266158 [d3d9] Only advertise SRCCOLOR2 & INVSRCCOLOR2 with 9Ex 2024-12-04 13:06:28 +01:00
WinterSnowfall
93d2715b7a [build] Suppress gcc misleading indentation warnings 2024-12-04 10:00:15 +01:00
WinterSnowfall
218b67dd0c [d3d9] Use header back buffer limits during validation
Co-authored-by: Blisto91 <47954800+Blisto91@users.noreply.github.com>
2024-11-28 15:44:00 +01:00
Jeff
4e07302cbf [d3d9] Fix race condition in PIX events 2024-11-28 07:24:12 +00:00
WinterSnowfall
b8ce414820 [util] Enable deferSurfaceCreation for the Codename Panzer series 2024-11-27 16:51:54 +01:00
Philip Rebohle
d7bd3cd58e [d3d9] Remove d3d9.enableDialogMode option 2024-11-25 11:54:55 +01:00
Philip Rebohle
15db475edf [dxvk] Always disable exclusive fullscreen 2024-11-25 11:54:55 +01:00
WinterSnowfall
9e1bc1db23 [d3d9] Expand NormalizeTextureProperties validations 2024-11-23 16:58:25 +01:00
WinterSnowfall
97ad37e409 [d3d9] Validate RT parent device during SetRenderTarget 2024-11-23 16:58:25 +01:00
WinterSnowfall
77020760f1 [d3d9] Fix behavior on multiple image unlocks 2024-11-23 16:58:25 +01:00
WinterSnowfall
bb227fa850 [d3d8] Partially implement ValidateVertexShader/ValidatePixelShader 2024-11-23 16:58:25 +01:00
WinterSnowfall
34165f3814 [d3d8] Validate PS/VS version on creation 2024-11-23 16:58:25 +01:00
WinterSnowfall
423c86bf5e [d3d8] Validate DS dimensions on SetRenderTarget 2024-11-23 16:58:25 +01:00
WinterSnowfall
dd183b4a53 [d3d8] Adjust function, declaration and delete behavior for VS/PS 2024-11-23 16:58:25 +01:00
WinterSnowfall
4f98844f47 [d3d9] Skip some validations for D3DDEVTYPE_NULLREF devices 2024-11-23 16:58:25 +01:00
Blisto91
43b79bcb23 [util] Set Borderlands 2 floatEmulation to Strict
Missing lava in Vault of the Warrior
2024-11-23 02:28:03 +01:00
Blisto91
dd15328ccf [build] Remove old d3dcompiler_47 dependency
Leftover from when tests were in the main repository
2024-11-19 10:50:09 +01:00
Blisto91
7f1e52703d [d3d9] Change correctness factor to 0.5f
The original issue that 0.5f - (1.0f / 128.0f) fixed is a game bug that also happens on Windows and the version of the addon used back then didn't fix correctly. With the latest version of the addon it looks correct.
2024-11-18 13:03:58 +01:00
Philip Rebohle
b276c60f49 [meta] Release 2.5.1 2024-11-18 12:32:41 +01:00
Philip Rebohle
7ffd6dae2c [meta] Document dxgi.enableUe4Workarounds option 2024-11-18 12:32:41 +01:00
Blisto91
987c132df2 [util] Don't include original WC3 in Reforged config
Reforged sits in a folder called x86_64 which should filter out the original Warcraft 3
2024-11-17 20:02:04 +01:00
Blisto91
fefa4ee1f6 [util] Hide iGPU for WoW and WC3 Reforged
Currently with Proton/Wine these games will prefer to use the iGPU. On systems usng the Nvidia proprietary driver this can make them bug out so they don't start or show a gray screen.

It has to be figured and fixed why they even want to use the iGPU, but in the meantime we might as well work around the issue.
2024-11-17 16:12:17 +01:00
WinterSnowfall
ce1b06d0c6 [d3d8] Use unsigned values to identify remapped sampler states 2024-11-16 17:56:57 +01:00
Philip Rebohle
482e758aee [dxgi] Introduce dxgi.enableUe4Workarounds option 2024-11-16 17:26:33 +01:00
Philip Rebohle
1dcc9f3b6a [dxvk] Fix struct <-> class warning 2024-11-16 16:58:17 +01:00
Philip Rebohle
4fb6403b8f [d3d11] Store map mode as raw integer
Fixes some annoying error with clang, hopefully.
2024-11-16 16:58:17 +01:00
60IQ
12c2b2f81b add --64-only and --32-only build options from package-native.sh 2024-11-15 21:14:51 +01:00
Philip Rebohle
4c09b006a5 [d3d9] Actually use correct sampler state for anisotropy 2024-11-13 14:35:59 +01:00
Blisto91
2dadad57f0 [util] Hide amd for GTA The Definitive Edition trilogy
Crashes because of static ags on amd systems which report HDR support.
2024-11-13 12:17:43 +01:00
Randy Eckenrode
8dc1fe1262 [build] Fix native GLFW build
Fixes an undefined reference to `glfwGetWindowAttrib` when building with
GLFW support enabled.
2024-11-11 22:33:52 +01:00
Philip Rebohle
e6209d28cd [build] Fix project version for native builds
Derp, wasn't tested.
2024-11-11 19:59:39 +01:00
Philip Rebohle
56b7c8cd41 [meta] Release 2.5 2024-11-11 15:27:07 +01:00
Philip Rebohle
757081a55a [hud] Pre-multiply alpha before color space conversion
Derp.
2024-11-11 12:53:52 +01:00
Philip Rebohle
3756e83ae4 [dxso] Don't emit FOrdNotEqual 2024-11-11 12:33:40 +01:00
Philip Rebohle
6610f4237f [dxso] Remove OpCross path for cross products 2024-11-11 12:33:40 +01:00
Philip Rebohle
bca3e8db5a [dxso] Explicitly emit long dot products
Potentially avoids vertex shader bugs if a game expects dot product and
a chain of mad instructions to return the same result.
2024-11-11 12:33:40 +01:00
Philip Rebohle
a71603a2a4 [dxso] Fix lrp instruction
Games expect this to be equivalent to add -> mad, but since we changed
mad to emit mul + add, this is no longer the case. Also remove OpFMix
path.
2024-11-11 12:33:40 +01:00
Philip Rebohle
f05b104310 [dxvk] Disable defragmentation on ANV 2024-11-11 12:33:20 +01:00
Philip Rebohle
d9d99445bd [hud] Properly pre-multiply graphs and bars with alpha
Oversight, our blend mode relies on pre-multiplied alpha.
2024-11-11 12:01:31 +01:00
WinterSnowfall
664783b290 [build] Use the static version of the run-time library for MSVC builds 2024-11-10 23:11:59 +01:00
Philip Rebohle
125f0acefd [util] Hide integrated graphics for Diablo 4 2024-11-10 21:39:07 +01:00
WinterSnowfall
d13375f4ed [CI] Use latest action runner images 2024-11-10 20:59:43 +01:00
Blisto91
847a581288 [CI] Add fetch-depth: 0 to Windows CI
Fixes the msvc CI builds not including the git commit in the dxvk version because 'git describe --dirty=+'  called though meson fails.
2024-11-10 20:08:35 +01:00
Philip Rebohle
c745136f67 [dxgi] Fix global variable declarations 2024-11-10 18:18:26 +01:00
Blisto91
8bca36460a [dxvk] Log build target and compiler used 2024-11-10 14:33:14 +01:00
Philip Rebohle
9b272fb3f6 [dxvk] Enable and use VK_EXT_pageable_device_local_memory if supported 2024-11-08 17:25:54 +01:00
Philip Rebohle
c5bc4d1bac [dxvk] Order allocations to relocate by offset
Potentially improves the situation where a chunk cannot be relocated
in its entirely by freeing up a larger block of memory at the end of
the chunk, which may be enough to service a subsequent defrag attempt
of a different chunk.
2024-11-08 13:39:47 +01:00
Philip Rebohle
8584fc7722 [d3d11] Simplify mapped resource tracking on deferred context 2024-11-08 11:19:21 +01:00
Philip Rebohle
bdd4956dd3 [d3d11] Properly validate map parameters for images 2024-11-08 11:19:21 +01:00
Philip Rebohle
2db10b0af8 [d3d11] Use D3D11_COMMON_TEXTURE_MAP_MODE_DYNAMIC where possible 2024-11-08 11:19:21 +01:00
Philip Rebohle
da406133f1 [d3d11] Add D3D11_COMMON_TEXTURE_MAP_MODE_DYNAMIC 2024-11-08 11:19:21 +01:00
Philip Rebohle
1d2d05dde0 [d3d11] Clean up some texture map mode checks 2024-11-08 11:19:21 +01:00
Philip Rebohle
43e636cf42 [dxvk] Rearrange DxvkBufferCreateInfo 2024-11-08 11:19:21 +01:00
Philip Rebohle
bd6b7aedc1 [d3d11] Clean up image staging buffer creation 2024-11-08 11:19:21 +01:00
Philip Rebohle
9e316b8c71 [d3d11] Disallow MAP_WRITE_NO_OVERWRITE on dynamic images
D3D11 explicitly bans this, so we shouldn't pretend to support it.
2024-11-08 11:19:21 +01:00
Philip Rebohle
1dfb869df2 [d3d11] Tie mapped image memory type to map mode selection
Allows us to keep video images in system memory in order to avoid
wasting precious HVV.
2024-11-08 11:19:21 +01:00
Philip Rebohle
ae67c026aa [d3d11] Implement image MAP_WRITE_DISCARD on immediate context 2024-11-08 11:19:21 +01:00
Philip Rebohle
789e8db699 [d3d11] Fix MAP_WRITE_DISCARD for mapped images on deferred contexts
The previous implementation was straight-up broken since it would use the
wrong subresource layout. We can discard the image now so let's just do that.
2024-11-08 11:19:21 +01:00
Philip Rebohle
30f2a8c26b [d3d11] Add methods to discard direct-mapped images 2024-11-08 11:19:21 +01:00
Philip Rebohle
64e32d4ee1 [d3d11] Clean up InitHostVisibleTexture
Also fixes a potential crash if pSysMem of any initial data structs is null.
2024-11-08 11:19:21 +01:00
Philip Rebohle
f5241d187c [d3d11] Use GetMapPtr when initializing mapped image buffer 2024-11-08 11:19:21 +01:00
Philip Rebohle
1832332d6d [d3d11] Add GetMapPtr method to D3D11CommonTexture
Fixes a bug in Read/WriteSubresource where discards result in the wrong
pointer being passed to the app.
2024-11-08 11:19:21 +01:00
Philip Rebohle
81bdf191cb [dxvk] Remove old querySubresourceLayout method 2024-11-08 11:19:21 +01:00
Philip Rebohle
c5d776c3b8 [d3d11] Cache subresource layouts for mapped images
Also adjust the way we expose certain direct-mapped images in order
to be as consistent with staging buffer behaviour as possible.
2024-11-08 11:19:21 +01:00
Philip Rebohle
a5e8a42288 [d3d11] Properly initialize optons struct
No bug, but it's good practice either way.
2024-11-08 11:19:21 +01:00
Philip Rebohle
bdf4cb765a [d3d11] Remove d3d11.maxDynamicImageBufferSize option 2024-11-08 11:19:21 +01:00
Philip Rebohle
116d488faa [d3d11] Use direct mapping for images in more situations 2024-11-08 11:19:21 +01:00
Philip Rebohle
35d94ae057 [d3d11] Improve memory type selection for direct-mapped images 2024-11-08 11:19:21 +01:00
Philip Rebohle
0896df7b9a [dxvk] Add back-end function to compute linear image subresource layouts 2024-11-08 11:19:21 +01:00
Robin Kertels
62970d24c3 [d3d9] Enable strict float emulation by default on new Nvidia drivers 2024-11-07 17:34:45 +01:00
WinterSnowfall
eb98047412 [d3d9] Skip some validations when hDeviceWindow is NULL 2024-11-07 01:10:05 +01:00
Blisto91
c466dec207 [CI] Make MSCV artifacts output match the regular artifact CI
Merges the two separate archives in to one and puts the dll and pdb files in a x32 and x64 folder.
Currently the two archives package the output in a folder called src and the files in subfolders of the respective names. E.g. `src/d3d9/d3d9.dll` etc.

This makes the MSCV artifacts archive match the regular artifacts CI output.
2024-11-04 17:56:16 +01:00
Philip Rebohle
c968ba624b [dxvk] Only force late clears on older Nvidia drivers
Disables the workaround introduced in 00872e9e4f
on drivers that were not affected by the bug.
2024-11-03 17:13:16 +01:00
WinterSnowfall
64b35c5c0f [d3d9] Early return D3D_OK on present with a NULL m_window 2024-11-03 13:35:55 +01:00
Philip Rebohle
3c88591326 [d3d9] Fix various other ColorFill edge cases
Fixes all remaining validation in wine's color_fill_test. Some failed
tests remain because apparently we do not validate resource txpes properly.
2024-11-03 12:41:35 +01:00
Philip Rebohle
ccd19ce90b [d3d9] Properly handle block-compressed formats in ColorFill 2024-11-03 12:41:35 +01:00
Philip Rebohle
c4421348cf [d3d9] Fix image layout for transfer-only images 2024-11-03 12:41:35 +01:00
Philip Rebohle
cde8661bc1 [dxvk] Add helper to compute clear values for compressed formats 2024-11-03 12:41:35 +01:00
Philip Rebohle
778b04f39a [d3d9] Properly destroy format conversion set and pipeline layouts 2024-11-03 12:41:35 +01:00
Philip Rebohle
54c45ef3fa [dxvk] Fix when tracking happens in resource relocation
Invalidation now resets tracking, so it is possible that after recreating
an image with different usage we'd use it on the wrong command buffer for
certain functions.
2024-11-03 12:25:53 +01:00
Philip Rebohle
c764dd97a6 [util] Fix __wine_dbg_output crash with very long lines
This sometimes happens with Vulkan validation layers enabled.
2024-11-03 12:02:03 +01:00
Philip Rebohle
f3c320b490 [dxvk] Fix broken sync in injectCsChunk 2024-11-02 20:56:02 +01:00
WinterSnowfall
b38c6b4dc2 [d3d8] Adjust ValidatePixel/VertexShader error return 2024-11-02 18:07:33 +01:00
WinterSnowfall
27ceecfad9 [d3d9] Fix cursor X/YHotSpot coordinate validation 2024-11-02 18:07:33 +01:00
WinterSnowfall
860d038d77 [d3d8] Don't record calls to MultiplyTransform 2024-11-02 18:07:33 +01:00
WinterSnowfall
88be8256e6 [d3d9] Add additional ValidateBufferProperties validations 2024-11-02 18:07:33 +01:00
WinterSnowfall
931796d1c2 [d3d9] Fix CreateQuery error return code 2024-11-02 18:07:33 +01:00
WinterSnowfall
0c117595b1 [d3d8] Strip all d3d9 device caps 2024-11-02 18:07:33 +01:00
WinterSnowfall
1181efd09d [d3d8] Adjust surface and texture clearing with D3DFMT_UNKNOWN 2024-11-02 18:07:33 +01:00
WinterSnowfall
a760f4a8dc [d3d9] Fixed return code on CheckAdapterFormat with D3DFMT_UNKNOWN 2024-11-02 18:07:33 +01:00
WinterSnowfall
a7c2eb140e [d3d9] Add present params validations on device creation and reset 2024-11-02 18:07:33 +01:00
WinterSnowfall
35352b9c52 [d3d8] Set D3D8 compatibility at D3D9 interface level 2024-11-02 18:07:33 +01:00
WinterSnowfall
11d5f9ee36 [d3d8] State block recording validations 2024-11-02 18:07:33 +01:00
WinterSnowfall
0e6be8a48b [d3d8/9] Add several Set/GetPrivateData validations 2024-11-02 18:07:33 +01:00
Robin Kertels
48d8e7c402 [d3d9] Improve code readability with comments 2024-11-02 17:48:13 +01:00
Robin Kertels
19fea8c48d [d3d9] Move remaining texture bitmask updates to function 2024-11-02 17:48:13 +01:00
Robin Kertels
8d10bfecd4 [d3d9] Remove unused readonly bitfield 2024-11-02 17:48:13 +01:00
WinterSnowfall
c606ab03e8 [util] Re-enable direct buffer mapping for Rayman 3 2024-11-02 15:41:34 +01:00
WinterSnowfall
f74b2cd6c6 [d3d9] Order modes descending by refresh rate 2024-10-31 20:37:04 +01:00
WinterSnowfall
6e43bf6d61 [util] Include Prince of Persia main executable 2024-10-31 14:57:32 +01:00
Philip Rebohle
d4f25c81be [d3d11] Remove d3d11.maxImplicitDiscardSize option 2024-10-31 12:13:27 +01:00
Philip Rebohle
f9bb8f0ad5 [d3d11] Consider discards when throttling immediate context 2024-10-31 12:13:26 +01:00
Philip Rebohle
65aa74aa7f [hud] Fix off-by-one error in memory type enumeration 2024-10-31 12:12:31 +01:00
Philip Rebohle
a91afc3a2f [d3d11] Do not touch row/depth pitch on failed map
Fixes a wine test.
2024-10-30 23:37:54 +01:00
Philip Rebohle
f0e9138886 [d3d11] Fix error return on MAP_WRITE_NO_OVERWRITE on deferred context
Fixes a wine test.
2024-10-30 23:37:54 +01:00
Philip Rebohle
67c5ab87f9 [d3d11] Add missing fragment shader stage to mapped image buffers
Relevant when uploading depth-stencil images.
2024-10-30 23:37:54 +01:00
Philip Rebohle
8ee7031742 [d3d11] Simplify InitHostVisibleBuffer 2024-10-30 23:37:54 +01:00
Philip Rebohle
223691b7aa [d3d11] Use device fence wait in ThrottleAllocation 2024-10-30 23:37:54 +01:00
Philip Rebohle
84ce80f931 [d3d9] Use new fence wait function in WaitStagingBuffer 2024-10-30 23:37:54 +01:00
Philip Rebohle
85684109b3 [dxvk] Add method to wait for fence as a GPU sync point 2024-10-30 23:37:54 +01:00
Philip Rebohle
3c389ae06b [dxvk] Adjust chunk size logic for mapped memory types
Total War Warhammer III discards a 48MB image every frame, so hitting
the dedicated allocation path pretty much at random leads to issues.
2024-10-30 23:37:54 +01:00
Philip Rebohle
ff78112271 [include] Add missing D3D11 error definition for native 2024-10-30 10:51:11 +01:00
Philip Rebohle
e41b1a11b2 [dxvk] Also add tracking ID to sampler objects 2024-10-30 09:42:53 +01:00
Philip Rebohle
0e14fff749 [dxvk] Introduce tracking ID for resource tracking
Replaces the existing bit masks, which is possible now because the
CS thread is the only place where submissions happen now.

This way we only count each resource once per submission, or twice
in case a read access is followed by a write.

This also fixes a potential tracking bug with shader-writeable resources.
2024-10-30 09:41:49 +01:00
Philip Rebohle
10fac66007 [dxvk] Don't override tracked write with a read
Fixes a regression in Control.
2024-10-30 03:39:45 +01:00
Jeff
201e1628b0 [d3d9] Add ID3D9VkInteropTexture to volumes 2024-10-30 02:17:35 +01:00
Philip Rebohle
e499f2e081 [d3d11] Fix potential crash when mapping a default image fails
This also marginally shortens common code paths.
2024-10-29 18:05:14 +01:00
Philip Rebohle
c2928ab3e2 [dxvk] Increment stat counters in command list rather than context
Might change some numbers, but it's closer to reality.
2024-10-28 23:03:46 +01:00
Philip Rebohle
7cd8a14673 [dxvk] Initialize additional command buffers on demand
The vast majority of submissions will only use one or two command buffers
rather than all five, and only the main command buffer will almost always
actually be used. This also saves us a bunch of CPU-side tracking.
2024-10-28 23:03:46 +01:00
Philip Rebohle
34b82a2b5b [dxvk] Add dedicated command buffers for initial layout transitions
This helps batch initial layout transitions for image uploads.
2024-10-28 23:03:46 +01:00
Philip Rebohle
d85cabe457 [dxvk] Refactor command buffer allocation 2024-10-28 23:03:46 +01:00
Philip Rebohle
b5e5d7a498 [dxvk] Use out-of-order transfer helper in clearImageViewCs
Covers image-related ClearUAV use cases.
2024-10-28 23:03:46 +01:00
Philip Rebohle
c795415c39 [dxvk] Use out-of-order transfer helper in clearBufferView
Covers some ClearUAV / ClearView use cases involving buffers.
2024-10-28 23:03:46 +01:00
Philip Rebohle
301f06bdfb [dxvk] Use out-of-order transfer helper in copyBufferToImage 2024-10-28 23:03:46 +01:00
Philip Rebohle
e69f09175f [dxvk] Use out-of-order transfer helper in updateBuffer 2024-10-28 23:03:46 +01:00
Philip Rebohle
28a1077c06 [dxvk] Use out-of-order transfer helper in copyBuffer 2024-10-28 23:03:46 +01:00
Philip Rebohle
8269b93f51 [dxvk] Use out-of-order transfer helper in clearBuffer 2024-10-28 23:03:46 +01:00
Philip Rebohle
c8ab88e8f5 [dxvk] Add helper for out-of-order resource transfers 2024-10-28 23:03:46 +01:00
Philip Rebohle
f0054e7e65 [dxvk] Add command list tracking to resource 2024-10-28 23:03:46 +01:00
Philip Rebohle
dd6d82e1ce [dxvk] Fix nonsensical layout check in ensureImageCompatibility
Derp, this fixes some unnecessary barriers.
2024-10-28 23:03:46 +01:00
Philip Rebohle
0fd00087e9 [dxvk] Filter out BDA usage for buffer invalidation early exit 2024-10-28 00:03:26 +01:00
Ethan Lee
469025d234 native: Add SDL3 WSI
Co-authored-by: Philip Rebohle <philip.rebohle@tu-dortmund.de>
2024-10-27 12:58:22 +01:00
Philip Rebohle
0259f55285 wsi: Pass window state to setWindowMode 2024-10-27 12:58:22 +01:00
WinterSnowfall
5ad84563dd [d3d9] Improve the naming of GetFormatBlockSize helper 2024-10-27 12:36:33 +01:00
WinterSnowfall
7ffe77f7c4 [d3d9] Validate pBox dimensions with LockBox 2024-10-27 12:36:33 +01:00
WinterSnowfall
a0d48cd2a2 [d3d9] Adjust pLockedRect/pLockedBox clearing and return behavior 2024-10-27 12:36:33 +01:00
WinterSnowfall
63d9affdcb [d3d9] Add volume texture creation and locking validations 2024-10-27 12:36:33 +01:00
WinterSnowfall
a323abe085 [d3d9] Validate alignment for block aligned formats 2024-10-27 12:36:33 +01:00
WinterSnowfall
678ccc721d [d3d9] Validate pRect dimensions with LockRect 2024-10-27 12:36:33 +01:00
Philip Rebohle
80fbaed291 Revert "[d3d11] Use existing MD5 hash to look up shader objects"
This reverts commit 800f71c4f5.

We can't do this without breaking fossilize DBs because we compile the
SHA1 hash into the shader binary.
2024-10-27 12:53:11 +01:00
Philip Rebohle
4709d429ed [dxbc] Fix EvalSnapped offset interpretation 2024-10-27 12:52:15 +01:00
Philip Rebohle
640758afcf [util] Enable mapped memory clearing for Vindictus 2024-10-27 02:43:58 +02:00
Philip Rebohle
ed83534970 [dxvk] Add option to clear mapped memory regions to zero 2024-10-27 02:43:58 +02:00
Philip Rebohle
e9574a4155 [dxvk] Add utility function to clear large regions of memory 2024-10-27 02:43:58 +02:00
Philip Rebohle
d535e2964f [dxvk] Remove obsolete comments 2024-10-25 19:22:58 +02:00
Philip Rebohle
3268bda4a2 [dxvk] Fix potential issues in invalidateImageWithUsage
Relevant for image recreation in D3D9, not so much for defrag
since we do everything late in the command list anyway.
2024-10-25 19:22:58 +02:00
Philip Rebohle
1a4ac219ed [dxvk] Properly flush everything before recording defrag commands 2024-10-25 19:22:58 +02:00
Philip Rebohle
7df58de815 [dxvk] Do not emit useless image barriers in relocateResources
Instead, fold barriers with no layout transition into a simple memory
barrier to bring this in line with the usual barrier logic.
2024-10-25 19:22:58 +02:00
Philip Rebohle
763780fb4c [dxvk] Remove obsolete fence code from command submissions
Unused since the timeline semaphore rework.
2024-10-25 11:31:01 +02:00
Philip Rebohle
662cfd49f5 [dxvk] Fix nonsensical pipeline stages when relocating resources 2024-10-24 15:19:43 +02:00
Philip Rebohle
640379e54b [dxvk] Remove obsolete DxvkDeviceOptions structure
This hasn't been used since 2.0.
2024-10-24 12:31:18 +02:00
Philip Rebohle
ec62551412 [dxvk] Add option to disable memory defragmentation 2024-10-24 12:31:18 +02:00
Philip Rebohle
9977313c32 [dxvk] Do not defragment chunks with immovable resources 2024-10-24 12:31:18 +02:00
Philip Rebohle
62f266098e [dxvk] Consider driver allocations when computing memory budget 2024-10-24 12:31:18 +02:00
Philip Rebohle
de400ae8a9 [dxvk] Increase memory task tick rate to 0.5s
Makes cleanup a bit quicker in some cases.
2024-10-24 12:31:18 +02:00
Philip Rebohle
7a09ab6c83 [dxvk] Limit amount of memory to relocate per submission
If the resources we're moving around are in slow memory, moving a full
chunk at once can already take several milliseconds. Try to avoid that.
2024-10-24 12:31:18 +02:00
Philip Rebohle
787671ef62 [dxvk] Limit number of allocations to move per submissions 2024-10-24 12:31:18 +02:00
Philip Rebohle
899f48bc43 [dxvk] Periodically defragment VRAM chunks 2024-10-24 12:31:18 +02:00
Philip Rebohle
c4cddebb89 [hud] Visualize inactive chunks 2024-10-24 12:31:18 +02:00
Philip Rebohle
2c8fe59924 [dxvk] Sort chunks by allocation time for statistics 2024-10-24 12:31:18 +02:00
Philip Rebohle
69437c2fea [dxvk] Include chunk status in statistics 2024-10-24 12:31:18 +02:00
Philip Rebohle
7a693ed41a [dxvk] Implement per-submission resource relocation 2024-10-24 12:31:18 +02:00
Philip Rebohle
9cbd45b8cf [dxvk] Add helper class for resource relocation 2024-10-24 12:31:18 +02:00
Philip Rebohle
0723250c12 [dxvk] Introduce flag to synchronize transfer queue
Also, get rid of superfluous binary semaphores since we have
a straight per-submission timeline anyway.
2024-10-24 12:31:18 +02:00
Philip Rebohle
13da763f9b [dxvk] Use small_vector in submission code 2024-10-24 12:31:18 +02:00
Philip Rebohle
800792a67d [dxvk] Add function to safely acquire a resource 2024-10-24 12:31:18 +02:00
Philip Rebohle
c7a9c626f5 [dxvk] Handle dead chunks in pool allocator 2024-10-24 12:31:18 +02:00
Philip Rebohle
a9bcb40655 [dxvk] Add concept of disabled chunks to allocator 2024-10-24 12:31:18 +02:00
Philip Rebohle
bfcfcab60f [dxvk] Add method to allocate backing storage with constraints 2024-10-24 12:31:18 +02:00
Philip Rebohle
a3c8c88222 [dxvk] Fix race condition in relocation check
The storage pointer is not safe to dereference outside the CS thread
for relocatable resources since the storage object may change.
2024-10-24 12:31:18 +02:00
Philip Rebohle
3a1de271cb [dxvk] Introduce allocation modes
Will be useful when relocating resources for defragmentation purposes.
2024-10-24 12:31:18 +02:00
Philip Rebohle
9a8406f28a [dxvk] Add global resource map to memory allocator 2024-10-24 12:31:18 +02:00
Philip Rebohle
8e94a8bcc6 [dxvk] Add per-chunk allocation list 2024-10-24 12:31:18 +02:00
Philip Rebohle
4e40d0b939 [dxvk] Add allocation flag for moveable resources 2024-10-24 12:31:18 +02:00
Philip Rebohle
bb05f123db [dxvk] Pass resource cookie to allocation objects 2024-10-24 12:31:18 +02:00
Philip Rebohle
efebceecbe [dxvk] Introduce DxvkAllocationInfo
Useful when more properties are added in the future.
2024-10-24 12:31:18 +02:00
Philip Rebohle
7ccfb57d57 [dxvk] Reintroduce resource cookies 2024-10-24 12:31:18 +02:00
Philip Rebohle
809257051b [dxvk] Rename unspecific "next" member in DxvkResourceAllocation 2024-10-24 12:31:18 +02:00
Philip Rebohle
3befea6516 [dxvk] Actually count barriers from resource relocation 2024-10-24 12:31:18 +02:00
Philip Rebohle
90f32d76ff [dxvk] Ignore uninitialized image subresources during relocation 2024-10-24 12:31:18 +02:00
Philip Rebohle
77a1164d1b [dxvk] Track initialization of internally managed images
Otherwise, these will not be relocated properly during defragmentation.
2024-10-24 12:31:18 +02:00
Philip Rebohle
1c157d1a63 [util] Properly return reference from small_vector emplace_back 2024-10-24 12:31:18 +02:00
Philip Rebohle
4af31a9d64 [dxvk] Remove context type concept
We only have a single context per device now.
2024-10-24 12:30:54 +02:00
Philip Rebohle
b4ed108105 [d3d9] Remove format conversion context 2024-10-24 12:30:54 +02:00
Philip Rebohle
f9a99e81f4 [dxvk] Bump state cache format to v18
All D3D11 shader keys change, so we should invalidte existing caches.
2024-10-23 16:56:32 +02:00
Philip Rebohle
f3fa2535e8 [d3d11] Validate shader creation parameters 2024-10-23 16:56:32 +02:00
Philip Rebohle
800f71c4f5 [d3d11] Use existing MD5 hash to look up shader objects
Skips the expensive SHA-1 pass.
2024-10-23 16:56:32 +02:00
Philip Rebohle
ae9024492b [d3d11] Devirtualize context method forwarding 2024-10-23 16:56:22 +02:00
Philip Rebohle
d10df6353b [d3d11] Devirtualize resource and view creation method forwarding 2024-10-23 16:56:22 +02:00
Philip Rebohle
565af8c311 [dxvk] Add important assert to object tracker 2024-10-23 11:30:37 +02:00
Blisto91
24e0440043 [util] Remove The Old Republic config
Looks fine without since dxvk 2.0
2024-10-23 11:19:01 +02:00
Philip Rebohle
01300bb884 [dxvk] Improve some descriptor setup code
Help the compiler out since it cannot fully prove that two consecutive
calls to DxvkImageView::handle with the same argument return the same result.
2024-10-23 10:26:24 +02:00
Philip Rebohle
cd4d68244d [dxvk] Use real shader access types for writeable descriptor types
Mostly relevant for storage buffers since those are often read-only.
2024-10-23 10:08:03 +02:00
Blisto91
f813549ced [util] Set forceSamplerTypeSpecConstants for Alpha Protocol
Some objects like metal containers will have unwanted reflection when they shouldn't otherwise.
2024-10-22 11:34:02 +02:00
Philip Rebohle
ce42ce2f3f [dxvk] Remove memory worker thread 2024-10-21 17:29:38 +02:00
Philip Rebohle
a5dc3400bd [dxvk] Use swap chain fences to synchronize WSI semaphores
Requires EXT_swapchain_maintenance1 to work, otherwise we won't use this.
2024-10-21 12:02:44 +02:00
Philip Rebohle
27539fc838 [dxvk] Use timeline semaphores for GPU synchronization
Ditches the old fence and binary semaphore code.
2024-10-21 12:02:44 +02:00
Philip Rebohle
1ee60048c0 [dxvk] Create timeline semaphores in submission queue 2024-10-21 12:02:44 +02:00
Philip Rebohle
4c0cbbef6a [dxvk] Factor DxvkResource code into DxvkPagedResource
And remove the now obsolete code.
2024-10-18 12:42:33 +02:00
Philip Rebohle
6540ab4f3e [dxvk] Use DxvkPagedResource for CPU synchronization 2024-10-18 12:42:33 +02:00
Philip Rebohle
3a587c5116 [dxvk] Remove old lifetime tracking code 2024-10-18 12:42:33 +02:00
Philip Rebohle
cc22ccfc5c [dxvk] Use new lifetime tracking for resources 2024-10-18 12:42:33 +02:00
Philip Rebohle
8389734e9f [dxvk] Use new lifetime tracking for raw allocations 2024-10-18 12:42:33 +02:00
Philip Rebohle
b011e22406 [dxvk] Use new lifetime tracking for samplers 2024-10-18 12:42:33 +02:00
Philip Rebohle
7fef97dae0 [dxvk] Use new lifetime tracking for events 2024-10-18 12:42:33 +02:00
Philip Rebohle
50d8e3933a [dxvk] Use new lifetime tracking for queries 2024-10-18 12:42:33 +02:00
Philip Rebohle
4a00623c40 [dxvk] Introduce DxvkTrackingRef and new tracking functions
The intention here is to clean up the code significantly while also
paving a way to perform more complex operations on resource release.
2024-10-18 12:42:33 +02:00
Philip Rebohle
56e8d55830 [dxvk] Remove direct resource allocation tracking
Track the containing virtual resources instead and only explicitly
keep allocations alive through invalidations.
2024-10-18 12:42:33 +02:00
Philip Rebohle
863ce5f117 [dxvk] Move DxvkAccess{Flags} to separate file 2024-10-18 12:42:33 +02:00
Philip Rebohle
d72346f2cb [dxvk] Rename various storage-related functions 2024-10-18 12:42:33 +02:00
Philip Rebohle
43355ecd73 [dxvk] Optimize small_vector reallocation code 2024-10-18 12:42:33 +02:00
num0005
f56b77942d [CI][Win] Copy version logic from artifacts script. 2024-10-17 22:40:08 +00:00
num0005
f85596ffbf [CI] Upload artifacts for Windows builds. 2024-10-17 22:40:08 +00:00
num0005
01684d36ba [build][msvc] Enable PDB output for all builds.
PDB generation even for release builds takes a little more time, but makes debugging DXVK on Windows easier. As the symbols are not embedded in the DLL it doesn't impact code generation or output binary size.
2024-10-17 22:40:08 +00:00
Philip Rebohle
e2b4060d43 [dxvk] Properly dirty multisample state when binding linked pipelines
Fixes a validation error in GTA V in very specific circumstances.
2024-10-17 19:40:17 +02:00
Philip Rebohle
990c7f562a [dxvk] Rework HUD to use a GPU query directly
Allows us to leverage the global timestamp query pool now that queries
are reference-counted properly.
2024-10-17 14:27:09 +02:00
Philip Rebohle
fb6e0ad6c1 [dxvk] Remove useless DxvkMarker class 2024-10-16 20:57:50 +02:00
Philip Rebohle
500c86c054 [d3d9] Replace staging buffer marker with monotonic fence
Brings this in line with D3D11.
2024-10-16 20:57:50 +02:00
Philip Rebohle
0249193403 [util] Avoid locking fence objects on wait if target value was reached 2024-10-16 20:57:50 +02:00
Philip Rebohle
bdec26b442 [dxvk] Actually flush layout transition in clearImageViewCs
Fixes 2864a5e474.
2024-10-16 20:55:59 +02:00
Philip Rebohle
f8b9efd11e [dxvk] Fix misaligned image uploads on transfer queue 2024-10-16 11:38:42 +02:00
Philip Rebohle
d2155c7f8c [dxvk] End transform feedback when changing the active graphics pipeline 2024-10-16 11:33:40 +02:00
Philip Rebohle
f69dc96c24 [dxvk] Sanitize multisample state for fragment output libraries
Validation complains about MS state being different between fragment shader
pipeline libraries and fragment output libraries on the EDS3 path.
2024-10-16 11:33:29 +02:00
Philip Rebohle
8ab6b8616b [dxvk] Track image initialization 2024-10-16 11:32:55 +02:00
Philip Rebohle
255e7b7d7a [dxvk] Add functions for image subresource initialization tracking 2024-10-16 11:32:55 +02:00
Philip Rebohle
af4ec3c63d [dxvk] Normalize render target layouts when binding framebuffer
No reason to use ATTACHMENT_OPTIMAL when the default layout is GENERAL.
2024-10-16 11:32:55 +02:00
Philip Rebohle
f76fb75956 [d3d9] Prefer GENERAL layout for read-only textures 2024-10-16 11:32:55 +02:00
Philip Rebohle
b2598906ca [d3d11] Prefer GENERAL layout for read-only textures 2024-10-16 11:32:55 +02:00
Philip Rebohle
6301b9d23d [dxvk] Remove old barrier tracking code 2024-10-16 11:32:55 +02:00
Philip Rebohle
708d23ca4b [dxvk] Use new barrier batch and barrier tracker for main command buffer 2024-10-16 11:32:55 +02:00
Philip Rebohle
4d2799f0d4 [dxvk] Add helper to determine pending barriers 2024-10-16 11:32:55 +02:00
Philip Rebohle
56a58095fe [dxvk] Use new barrier helpers for shader execution barriers 2024-10-16 11:32:55 +02:00
Philip Rebohle
4b94b8989d [dxvk] Use new barrier helpers in transition*Attachment 2024-10-16 11:32:55 +02:00
Philip Rebohle
0388f20cd3 [dxvk] Use new barrier helpers in updateGraphicsPipelineState 2024-10-16 11:32:55 +02:00
Philip Rebohle
7c274d0852 [dxvk] Use new barrier helpers in renderPassEmitPostBarriers 2024-10-16 11:32:55 +02:00
Philip Rebohle
3d12c1aea5 [dxvk] Use new barrier helpers in renderPassEmitInitBarriers 2024-10-16 11:32:55 +02:00
Philip Rebohle
d00d0a39ce [dxvk] Use new barrier helpers in spillRenderPass 2024-10-16 11:32:55 +02:00
Philip Rebohle
c2edd0f9bb [dxvk] Use new barrier helpers in resolveImageFb 2024-10-16 11:32:55 +02:00
Philip Rebohle
7b65ee00d9 [dxvk] Use new barrier helpers in resolveImageDs 2024-10-16 11:32:55 +02:00
Philip Rebohle
7b436a63fb [dxvk] Use new barrier helpers in resolveImageHw 2024-10-16 11:32:55 +02:00
Philip Rebohle
63347b5fce [dxvk] Use new barrier helpers in copySparsePages 2024-10-16 11:32:55 +02:00
Philip Rebohle
706d6cbc1c [dxvk] Use new barrier helpers in copyImageFb 2024-10-16 11:32:55 +02:00
Philip Rebohle
42da4348bf [dxvk] Use new barrier helpers in copyImageHw 2024-10-16 11:32:55 +02:00
Philip Rebohle
2864a5e474 [dxvk] Use new barrier helpers in clearImageViewCs
And ensure we're in GENERAL layout. We generally (pun intended) should
be, but there may be a universe where that is not the case.
2024-10-16 11:32:55 +02:00
Philip Rebohle
793f9b3d38 [dxvk] Use new barrier helpers in clearImageViewFb 2024-10-16 11:32:55 +02:00
Philip Rebohle
856a84e6fd [dxvk] Use new barrier helpers in copyImageToBufferCs
And actually rename that function to make sense.
2024-10-16 11:32:55 +02:00
Philip Rebohle
59d37757b0 [dxvk] Use new barrier helpers in copyImageToBufferHw 2024-10-16 11:32:55 +02:00
Philip Rebohle
e21c2977df [dxvk] Use new barrier helpers in copyBufferToImageFb 2024-10-16 11:32:55 +02:00
Philip Rebohle
d7dd80b62f [dxvk] Use new barrier helpers in copyBufferToImageHw 2024-10-16 11:32:55 +02:00
Philip Rebohle
389e40be67 [dxvk] Use new barrier helpers in blitImageHw 2024-10-16 11:32:55 +02:00
Philip Rebohle
82c2f5d5d1 [dxvk] Use new barrier helpers in blitImageFb 2024-10-16 11:32:55 +02:00
Philip Rebohle
a4daa63d2b [dxvk] Use new barrier helpers in launchCuKernelNVX 2024-10-16 11:32:55 +02:00
Philip Rebohle
ab9ade76d7 [dxvk] Use new barrier helpers in emitGraphicsBarrier 2024-10-16 11:32:55 +02:00
Philip Rebohle
e70e72f109 [dxvk] Use new barrier helpers in updateBuffer 2024-10-16 11:32:55 +02:00
Philip Rebohle
ab300dce2f [dxvk] Use new barrier helpers in performClear 2024-10-16 11:32:55 +02:00
Philip Rebohle
a1a9cd5bb6 [dxvk] Use new barrier helpers in transformImage 2024-10-16 11:32:55 +02:00
Philip Rebohle
7edfad763a [dxvk] Use new barrier helpers in ensureImageCompatibility 2024-10-16 11:32:55 +02:00
Philip Rebohle
33b146467a [dxvk] USe new barrier helpers in generateMipmaps 2024-10-16 11:32:55 +02:00
Philip Rebohle
03a716e308 [dxvk] Use new barrier helpers in emit*Barrier 2024-10-16 11:32:55 +02:00
Philip Rebohle
ee9d09c2e2 [dxvk] Use new barrier helpers in dispatchIndirect 2024-10-16 11:32:55 +02:00
Philip Rebohle
826114f612 [dxvk] Use new barrier helpers in copyPackedBufferImage 2024-10-16 11:32:55 +02:00
Philip Rebohle
3ecca3d171 [dxvk] Use new barrier helpers in copyBuffer 2024-10-16 11:32:55 +02:00
Philip Rebohle
6ef6cb3b45 [dxvk] Use new barrier helpers in clearBufferView 2024-10-16 11:32:55 +02:00
Philip Rebohle
5dfc4d6300 [dxvk] Use new barrier helpers in clearBuffer 2024-10-16 11:32:55 +02:00
Philip Rebohle
cc3dd31a5f [dxvk] Use new barrier helpers in changeImageLayout 2024-10-16 11:32:55 +02:00
Philip Rebohle
bbe7767475 [dxvk] Add helpers to flush pending execution barriers if needed 2024-10-16 11:32:55 +02:00
Philip Rebohle
318e79c2ad [dxvk] Use new barrier batch for init and sdma barriers
No tracking needed here.
2024-10-16 11:32:55 +02:00
Philip Rebohle
50b1932aea [dxvk] Use new barrier helper in uploadBuffer 2024-10-16 11:32:55 +02:00
Philip Rebohle
b33f0c3d30 [dxvk] Use new barrier helper in updateBuffer 2024-10-16 11:32:55 +02:00
Philip Rebohle
e6c0903600 [dxvk] Use new barrier helper in initSparseImage 2024-10-16 11:32:55 +02:00
Philip Rebohle
9698653055 [dxvk] Use new barrier helper in initImage 2024-10-16 11:32:55 +02:00
Philip Rebohle
94915fcbe3 [dxvk] Use new barrier helper in initBuffer 2024-10-16 11:32:55 +02:00
Philip Rebohle
6b01203ddf [dxvk] Use new barrier helper in copyBuffer 2024-10-16 11:32:55 +02:00
Philip Rebohle
6e6ee35587 [dxvk] Use new barrier helper in clearBuffer 2024-10-16 11:32:55 +02:00
Philip Rebohle
b771bef837 [dxvk] Add helper functions to record pending barriers 2024-10-16 11:32:55 +02:00
Philip Rebohle
d154a684ad [dxvk] Remove acquire barrier set 2024-10-16 11:32:55 +02:00
Philip Rebohle
3de0f27dd9 [dxvk] Use new layout transition helper in resolveImageFb 2024-10-16 11:32:55 +02:00
Philip Rebohle
801ef39895 [dxvk] Use new layout transition helper in resolveImageDs 2024-10-16 11:32:55 +02:00
Philip Rebohle
154eee96a0 [dxvk] Use new layout transition helper in resolveImageHw 2024-10-16 11:32:55 +02:00
Philip Rebohle
704fc4eaa7 [dxvk] Use new layout transition helper in copySparseImagePages 2024-10-16 11:32:55 +02:00
Philip Rebohle
4d19e58f51 [dxvk] Use new layout transition helper for copyImageFb 2024-10-16 11:32:55 +02:00
Philip Rebohle
7ffde27551 [dxvk] Use new layout transition helper in copyImageHw 2024-10-16 11:32:55 +02:00
Philip Rebohle
bbd041194b [dxvk] Use new layout transition helper in clearImageViewFb 2024-10-16 11:32:55 +02:00
Philip Rebohle
18cdc25773 [dxvk] Use new layout transition helper in copyImageToBufferFb 2024-10-16 11:32:55 +02:00
Philip Rebohle
e8a5583562 [dxvk] Use new layout transition helper in copyImageToBufferHw 2024-10-16 11:32:55 +02:00
Philip Rebohle
088e4024f5 [dxvk] Use new layout transition helper in copyBufferToImageFb 2024-10-16 11:32:55 +02:00
Philip Rebohle
ebd067f098 [dxvk] Use new layout transition helper in copyBufferToImageHw 2024-10-16 11:32:55 +02:00
Philip Rebohle
2353867d54 [dxvk] Use new layout transition helper for blitImageHw 2024-10-16 11:32:55 +02:00
Philip Rebohle
aff6cb744c [dxvk] Use new layout transition helper for blitImageFb 2024-10-16 11:32:55 +02:00
Philip Rebohle
971042b3d3 [dxvk] Use new layout transition helper in performClear 2024-10-16 11:32:55 +02:00
Philip Rebohle
c24be65f2a [dxvk] Use new layout transition helper in generateMipmaps 2024-10-16 11:32:55 +02:00
Philip Rebohle
ef79f8a617 [dxvk] Use new layout transition helper in initImage
Removes another barrier set.
2024-10-16 11:32:55 +02:00
Philip Rebohle
1e8631189c [dxvk] Use new layout transition helper in uploadImageHw
Allows us to get rid of a barrier set.
2024-10-16 11:32:55 +02:00
Philip Rebohle
8955d2a285 [dxvk] Add various helpers to emit image layout transitions 2024-10-16 11:32:55 +02:00
Philip Rebohle
756ff73c8a [dxvk] Add new barrier batch helper
Separates batching from tracking. This is useful because init
and transfer queue barriers do not need any tracking.
2024-10-16 11:32:55 +02:00
Philip Rebohle
c6c85d7532 [dxvk] Add new barrier tracker
Uses a hash table backed by RB trees in order to reduce
worst-case runtime overhead in some edge cases.
2024-10-16 11:32:55 +02:00
Philip Rebohle
af3c46d83c [dxvk] Remove unused buffer barrier array 2024-10-16 11:32:55 +02:00
Robin Kertels
763b82b1e4 [d3d9] Fix render target null pointer deref 2024-10-15 19:29:20 +02:00
Philip Rebohle
35ead85929 [d3d11] Manually free all view objects in view destructor 2024-10-15 11:48:51 +02:00
Philip Rebohle
de65e06831 [dxvk] Do not try to reset pointer in Rc destructor
This gets optimized away in release builds.
2024-10-15 11:48:51 +02:00
Jeff
e4630685e4 [d3d9] Fix mismatched case in MultiSample and MultisampleQuality 2024-10-15 10:09:51 +02:00
Jeff
01a1c8359a [d3d9] Fix spelling nit 2024-10-15 10:09:51 +02:00
Jeff
eafdf0bfd7 [d3d9] Add alternate constructor for D3D9Texture2D 2024-10-15 10:09:51 +02:00
Jeff
25069dbd1d [d3d9] Add alternate constructor for D3D9Surface 2024-10-15 10:09:51 +02:00
Jeff
a044c639f7 [d3d9] Add ID3D9VkInteropDevice::CreateImage to create custom texture/surfaces 2024-10-15 10:09:51 +02:00
Blisto91
98fa338be0 [util] Move Far Cry 2 config to d3d9 section 2024-10-14 18:39:02 +02:00
Blisto91
b707ca1309 [util] Enable memoryTrackTest for Secret World Legends
Otherwise d3d9 mode thinks we only have 512MB vram which will lock the higher graphics presets.
2024-10-14 18:39:02 +02:00
Robin Kertels
f65897be4c [d3d9] Remove a few unnecessary bitmasks 2024-10-13 17:13:31 +02:00
Robin Kertels
421ead5b30 [d3d9] Only dirty frame buffer on render state changes if render area is impacted 2024-10-13 17:13:31 +02:00
WinterSnowfall
b99012d332 [d3d9] Adjust matrix inversion boundary 2024-10-13 11:09:13 +00:00
Blisto91
05d089bee5 [d3d9] Silence unhandled render state D3DRS_ADAPTIVETESS_Y 2024-10-13 12:31:14 +02:00
Philip Rebohle
458b8e3b41 [util] Add missing includes small_vector
Fixes #4357.
2024-10-13 12:29:12 +02:00
Philip Rebohle
693ee7898d [dxvk] Refactor queries to be properly ref-counted
Should fix a long-standing lifetime tracking issue with timestamp
queries as well as invalid Vulkan usage with overlapping scoped
queries.
2024-10-13 12:08:35 +02:00
Philip Rebohle
1b9c59c964 [dxvk] Refactor events to be properly ref-counted
Mostly serves as a proof-of-concept for the pending query rework,
but also cleans up some silly code.
2024-10-13 12:08:35 +02:00
Philip Rebohle
d00669cb52 [dxvk] Rename DxvkGpu{Event,Query} to Dxvk{Event,Query}
The old name only ever existed because DXVK had two separate implementations
of these prior to version 1.1. Let's name them back so that more sensible
names are available for internal use.
2024-10-13 12:08:35 +02:00
Robin Kertels
5890eae32f [d3d9] Don't clear mipGenBit if texture is bound as attachment 2024-10-13 12:07:30 +02:00
Robin Kertels
5ff365b9f1 [d3d9] Remove initializer context 2024-10-12 10:09:17 +02:00
WinterSnowfall
48c57c11e9 [d3d9] Make proper use of X/YHotSpot for software cursors 2024-10-11 12:40:37 +02:00
WinterSnowfall
44b682051b [d3d8] Stub DebugSetMute to fix C&C:Generals performance 2024-10-10 13:06:54 +02:00
WinterSnowfall
c8759418af [d3d9] Fix device reset handling when no cursor is set 2024-10-10 09:31:13 +02:00
Robin Kertels
d39d879838 [d3d9] Add a bunch of missing likely/unlikely to PrepareDraw
PrepareDraw is pretty much the hottest part of the d3d9
frontend, so we take every tiny bit we get.
2024-10-09 21:28:59 +00:00
Robin Kertels
395ac38890 [d3d9] Fix fixed function texture mask
Fixed function supports 8 textures so we need 8 ones.
2024-10-09 21:28:59 +00:00
WinterSnowfall
a1a3800b3f [d3d9] Fix software cursor reset and transitions 2024-10-08 20:20:31 +02:00
Philip Rebohle
a30fdc466b [d3d11] Remove initializer context
This moves all initialization commands to the CS thread and the regular
context in such a way that resource initialization is processed before
any context commands can use the resource.
2024-10-08 17:46:18 +02:00
Philip Rebohle
ac1dfbacb6 [dxvk] Move image initialization to init command buffer 2024-10-08 17:46:18 +02:00
Philip Rebohle
0f6f543583 [dxvk] Silence validation error about invalid shaders
Known validation bug that is already fixed upstream, but this makes
validation layers unusable due to how spammy that is.
2024-10-08 17:46:18 +02:00
Philip Rebohle
df60a061a4 [d3d11] Throttle resource uploads via UpdateSubresource
Otherwise, some games (e.g. Frostpunk, New World) end up allocating over
a gigabyte of staging memory.
2024-10-08 17:46:18 +02:00
Philip Rebohle
ec18dd7846 [d3d11] Throttle resource uploads through staging buffer 2024-10-08 17:46:18 +02:00
Philip Rebohle
d330718353 [dxvk] Implement staging buffer statistics 2024-10-08 17:46:18 +02:00
Philip Rebohle
e137f049ee [dxvk] Make buffer<->image copy format checks more robust
There are situations where the source format may not match
the image format but the copy is valid nonetheless.
2024-10-08 17:46:18 +02:00
Philip Rebohle
e6f90b8003 [dxvk] Remove legacy depth/stencil repacking code 2024-10-08 17:46:18 +02:00
Philip Rebohle
ad1f70beea [dxvk] Support format conversion in copyImageToBuffer 2024-10-08 17:46:18 +02:00
Philip Rebohle
f67c8dd1da [dxvk] Support format conversion in copyBufferToImage 2024-10-08 17:46:18 +02:00
Philip Rebohle
501b0991da [dxvk] Remove per-context staging buffer
No longer used.
2024-10-08 17:46:18 +02:00
Philip Rebohle
725a04b954 [dxvk,d3d11] Refactor uploadImage to consume a staging buffer
And also handle format differences.
2024-10-08 17:46:18 +02:00
Philip Rebohle
34e0f6952b [dxvk] Always enable depth-stencil usage for depth-stencil formats 2024-10-08 17:46:18 +02:00
Philip Rebohle
2fac69b7f9 [dxvk] Add pipelines for buffer-to-image and image-to-buffer copies 2024-10-08 17:46:18 +02:00
Philip Rebohle
15d5b69d2c [dxvk] Add new format conversion shaders
Intended to replace the old pack/unpack shaders.
2024-10-08 17:46:18 +02:00
Philip Rebohle
3c50ac1f12 [dxvk] Rename DxvkCopyBufferImage* stuff
Slightly misleadning name when we're going to introduce copies
between buffers and images.
2024-10-08 17:46:18 +02:00
Philip Rebohle
c92ee8ee07 [dxvk,d3d11] Refactor uploadBuffer to consume a staging buffer 2024-10-08 17:46:18 +02:00
Philip Rebohle
c27cae2f10 [d3d11] Improve per-context staging buffer handling
In D3D11, the staging buffer is only used for UpdateSubresource, which
isn't always used much. Reducing the size and freeing the buffer after
every submission avoids situations where system memory chunks are kept
alive by a single unused 4MB allocation.
2024-10-08 17:46:18 +02:00
Philip Rebohle
c614e537a9 [dxvk] Remove alignment parameter from staging buffers
Just align all suballocations to 256 bytes as usual.
2024-10-08 17:46:18 +02:00
WinterSnowfall
7eec8fb8dc [d3d8] Various logging format adjustments 2024-10-08 00:25:55 +02:00
WinterSnowfall
559398f6a4 [d3d9] Check block alignment on texture creation with DXT formats 2024-10-08 00:25:55 +02:00
WinterSnowfall
1689cacc47 [d3d8] Stub ValidatePixelShader and ValidateVertexShader 2024-10-08 00:25:55 +02:00
WinterSnowfall
66bd9ec4dd [d3d8] Always forward SetRenderTarget calls to D3D9 2024-10-08 00:25:55 +02:00
WinterSnowfall
8c54969552 [d3d8] Skip stride updates for null buffers in SetStreamSource 2024-10-08 00:25:55 +02:00
WinterSnowfall
088cf45439 [d3d9] Validate 0 valued back buffer dimensions for fullscreen mode 2024-10-08 00:25:55 +02:00
WinterSnowfall
6e0c048b88 [d3d9] Return D3DERR_DEVICELOST on reset failure due to losable resources 2024-10-08 00:25:55 +02:00
WinterSnowfall
912a530d1c [d3d9] Enforce various CheckDeviceMultiSampleType validations 2024-10-08 00:25:55 +02:00
WinterSnowfall
eae12e6f23 [d3d8] Cache all back buffers for additional swapchains 2024-10-08 00:25:55 +02:00
WinterSnowfall
bc78fc6ed0 [d3d8] Validate D3D8 present params before conversion 2024-10-08 00:25:55 +02:00
WinterSnowfall
4a8ba388ff [d3d8] Validate CheckDeviceType windowed calls similarly to fullscreen 2024-10-08 00:25:55 +02:00
WinterSnowfall
653559979c [d3d8] Fix LookupSubresource texture type typo 2024-10-08 00:25:55 +02:00
Philip Rebohle
7935f3934f [dxvk] Sanitize sampler LOD range
Silences a validation error in Dishonored 2. At least on AMD,
MinLOD takes precedence over MaxLOD, so let's do the same.
2024-10-07 19:34:02 +02:00
Philip Rebohle
571a2d5811 [dxvk] Tweak staging memory allocation behaviour 2024-10-07 13:32:46 +02:00
Philip Rebohle
813524c146 [d3d11] Remove texel buffer path for ClearUAV
Instead, recreate the image with the given view format as
necessary. Most of the time we will not actually need this.
2024-10-06 08:47:42 +02:00
Philip Rebohle
851f02fa58 [dxvk] Actually apply new create flags when relocating image
Fixes a derp that leads to validation errors when adding view formats.
2024-10-06 08:47:42 +02:00
WinterSnowfall
36907ec01c [d3d8] Adjust shader handles to skip 0x0001 2024-10-05 20:03:05 +02:00
WinterSnowfall
980a8d185c [d3d9] Use D24X8 for D3DFMT_UNKNOWN depth stencils 2024-10-05 20:03:05 +02:00
WinterSnowfall
4f90ad46b9 [d3d8] Validate D3D9 auto depth stencil query 2024-10-05 20:03:05 +02:00
WinterSnowfall
1675aea857 [d3d8] CopyRects validation tweaks 2024-10-05 20:03:05 +02:00
WinterSnowfall
b13b875ca6 [d3d8] Rework D3D8 device GetInfo implementation 2024-10-05 20:03:05 +02:00
WinterSnowfall
bbe82aa534 [d3d9] Fix (most) cursor-related Wine tests 2024-10-05 18:27:19 +02:00
WinterSnowfall
7ff5321910 [d3d9] Implement a software cursor 2024-10-05 18:27:19 +02:00
WinterSnowfall
87a7882812 [d3d8] Automatically capture state on state block creation 2024-10-05 17:58:04 +02:00
WinterSnowfall
050886d08a [d3d8] Capture VB stream state in D3D8 state blocks 2024-10-05 17:58:04 +02:00
WinterSnowfall
9d19fa18a7 [d3d9] Set D3DRS_POINTSIZE_MIN to 0.0f in D3D8 compatibility mode 2024-10-05 17:58:04 +02:00
Philip Rebohle
329d9a0bb2 [dxvk] Add support for drawing a software cursor 2024-10-04 19:10:14 +02:00
Philip Rebohle
4420c39b62 [dxvk] Factor out swapchain blitter texture uploads 2024-10-04 19:10:14 +02:00
Philip Rebohle
dbaa4d8df4 [dxvk] Add blending toggle to swap chain blitter pipelines 2024-10-04 19:10:14 +02:00
Philip Rebohle
836e990dc5 [dxvk] Correctly use VK_SHARING_MODE_CONCURRENT for buffers
Fixes some out-of-spec behaviour introduced with the global buffer rework.
2024-10-04 18:49:23 +02:00
Philip Rebohle
a278d6bf1d [d3d11] Implement sequential swap effects 2024-10-04 12:58:55 +02:00
Philip Rebohle
c9ec2eeab2 [dxvk] Ensure image is in correct layout for invalidation
Otherwise, layout tracking might track a dead image and get confused.
2024-10-04 12:58:55 +02:00
Philip Rebohle
2af3fde5f2 [d3d9] Remove additional swap chain context 2024-10-04 12:58:55 +02:00
Philip Rebohle
172d3450d1 [d3d11] Rename EmitCsChunkExternal for consistency 2024-10-04 12:58:55 +02:00
Philip Rebohle
c678e8c803 [d3d11] Remove additional swap chain context
Do everything on the main context instead. Also only
present once regardless of sync interval.
2024-10-04 12:58:55 +02:00
Philip Rebohle
129efdaba6 [d3d11] Do not use separate context to initialize back buffers 2024-10-04 12:58:55 +02:00
Philip Rebohle
89ebabd8fd [dxgi] Enable frame rate limit for SyncInterval > 1 in windowed mode 2024-10-04 12:58:55 +02:00
Philip Rebohle
bf9dfc77ce [dxvk] Add context method for WSI synchronization
Mostly convenience, but we do want to get rid of Begin/EndRecording
at some point.
2024-10-04 12:58:55 +02:00
Philip Rebohle
63b200f08d [dxvk] Reimplement HUD rendering to use Vulkan directly
And change how rendering works in general so that we emit fewer
draw calls.
2024-10-04 12:58:55 +02:00
Philip Rebohle
b35c0bce4f [dxvk] Always enable multiDrawIndirect and shaderDrawParameters features 2024-10-04 12:58:55 +02:00
Philip Rebohle
46f10c8fd5 [dxvk] Add command list parameter to dispatch-related functions 2024-10-04 12:58:55 +02:00
Philip Rebohle
7d31a7f16f [dxvk] Add command list parameter to some query-related functions
And reintroduce cmdResetQueryPool.
2024-10-04 12:58:55 +02:00
Philip Rebohle
4ce200bcae [dxvk] Add command list parameter to cmdBindDescriptorSet(s) 2024-10-04 12:58:55 +02:00
Philip Rebohle
aa162365ce [dxvk] Add command list parameter to cmdPushConstants
We want to be able to invoke compute shaders during init commands.
2024-10-04 12:58:55 +02:00
Philip Rebohle
207e15eb24 [dxvk] Refactor swap chain blitter to use plain Vulkan
Temporarily disable the HUD until that is refactored too.
2024-10-04 12:58:55 +02:00
Philip Rebohle
1c06431e18 [dxvk] Add method to use a context's command list directly
Also provide the descriptor pool for convenience.
2024-10-04 12:58:55 +02:00
Philip Rebohle
09284988ff [hud] Show memory used percentage relative to budget 2024-10-03 23:47:56 +02:00
Philip Rebohle
0c49e30882 [dxvk] Add memory budget to memory stats 2024-10-03 23:47:56 +02:00
Philip Rebohle
513312885e [dxvk] Use actual memory budget if provided by the implementation
For now, this is only used for the heuristic on when to aggressively
free empty chunks and replaces the 80% heap size heuristic.

Periodically updates the memory budget from the worker thread.
2024-10-03 23:47:56 +02:00
Robin Kertels
7d05a99640 [d3d9] Fix StretchRect fast-path resolve 2024-10-03 00:06:51 +02:00
Robin Kertels
4807af01ad [d3d9] Resolve whole image in StretchRect
Fixes a validation error in Sims 4.
2024-10-02 20:22:37 +02:00
Philip Rebohle
1443e22626 [d3d11] Fix derp with anisotropy option
Fixes #4313.
2024-10-02 11:02:06 +02:00
Philip Rebohle
90b036f550 [dxvk] Fix undefined behaviour move 2024-09-30 17:44:45 +02:00
WinterSnowfall
a5e3f29074 [dxvk] Fix HUD memory chunk colors on UMA 2024-09-30 14:28:44 +02:00
Philip Rebohle
e83446f5c9 [d3d11] Fix remaining synchronization issues with CUDA interop 2024-09-30 10:29:27 +02:00
Philip Rebohle
c26c21edb4 [d3d11] Lock buffers in place when used with CUDA interop 2024-09-30 10:29:27 +02:00
Philip Rebohle
11f8dc0818 [dxvk] Add functions to lock in and query GPU buffer addresses 2024-09-30 10:29:27 +02:00
Philip Rebohle
9f0bd8e17f [d3d11] Lock textures in place when used with CUDA interop
Prevents images from being relocated by the backend.
2024-09-30 10:29:27 +02:00
Philip Rebohle
c59d6bd12c [dxvk] Add flag to ensure stable image GPU addresses 2024-09-30 10:29:27 +02:00
Philip Rebohle
438a08f87c [d3d11] Add functions to emit externally generated CS chunks 2024-09-30 10:29:27 +02:00
Philip Rebohle
abd888a0bb [dxvk] Clean up check whether buffer can be relocated 2024-09-30 10:29:27 +02:00
Philip Rebohle
b164d6e2a7 [d3d9] Do not proactively enable meta copy usage flags
Same as the corresponding D3D11 change, let the backend deal with this
when necessary.
2024-09-30 10:29:27 +02:00
Philip Rebohle
5f3fa9e423 [d3d11] Do not proactively enable meta copy usage flags
Instead, let the backend deal with this and recreate the image as necessary.
2024-09-30 10:29:27 +02:00
Philip Rebohle
2fa773e791 [dxvk] Bump maximum sampler count to 4000
All sampler allocations go through the pool now, so we can do this.
2024-09-30 10:29:27 +02:00
Philip Rebohle
150c40280f [dxvk] Get rid of internal blit samplers 2024-09-30 10:29:27 +02:00
Philip Rebohle
67d1285b08 [dxvk] Refactor meta blits 2024-09-30 10:29:27 +02:00
Philip Rebohle
58dab7e8c6 [dxvk] Refactor mip generation 2024-09-30 10:29:27 +02:00
Philip Rebohle
8c67af680c [dxvk] Refactor meta resolves 2024-09-30 10:29:27 +02:00
Philip Rebohle
2c176f4950 [dxvk] Refactor meta image copies 2024-09-30 10:29:27 +02:00
Philip Rebohle
ae90e74a5a [dxvk] Introduce concept of transfer-only views 2024-09-30 10:29:27 +02:00
Philip Rebohle
fd439c3e54 [dxvk] Ensure image compatibility for packed depth-stencil copies 2024-09-30 10:29:27 +02:00
Philip Rebohle
56a07b5bd0 [dxvk] Add function to recreate image views with guaranteed compatibility 2024-09-30 10:29:27 +02:00
Philip Rebohle
bfbb7987b2 [dxvk] Add functions to recreate images with additional usage info
Useful when we don't know in advance which usage flags are required
and don't want to set them preemptively for performance reasons.
2024-09-30 10:29:27 +02:00
Philip Rebohle
53f14e2914 [dxvk] Add functions to move resources to a different allocation
Basically a batched copy to use when one or more resources are being
recreated for any reason.
2024-09-30 10:29:27 +02:00
Philip Rebohle
ae3a9f595e [dxvk] Allow larger chunks on small heaps
Effectively doubles the size of HVV chunks to 32 MiB on systems that
do not have ReBAR enabled. 16 MiB is too small for some use cases.
2024-09-29 22:07:30 +02:00
Philip Rebohle
e6f89062f5 [d3d9] Ensure that we stay below the maximum sampler count 2024-09-28 20:21:06 +02:00
Philip Rebohle
07dfeeb319 [d3d9] Move building sampler key to CS thread
All this bit twiddling is a bit slow. Introduces another structure
containing a minimal amount of sampler parameters taken from the
raw D3D9 state.
2024-09-28 20:21:06 +02:00
Philip Rebohle
543b5c7af8 [d3d9] Optimize sampler state decoding
This code is rather hot now, so make sure it's fast.
2024-09-28 20:21:06 +02:00
Philip Rebohle
c7dab6a442 [d3d9] Remove internal sampler pool
We have a sampler pool in the backend now, let's use it.
2024-09-28 20:21:06 +02:00
Philip Rebohle
707ddd63a1 [dxvk] Add stat counter for samplers 2024-09-28 20:21:06 +02:00
Philip Rebohle
4635397bb1 [dxvk] Implement sampler pool
Deduplicates redundant sampler objects and makes sampler creation
as well as lifetime tracking a bit more efficient.
2024-09-28 20:21:06 +02:00
Philip Rebohle
5f9f43e658 [util] Add helpers to encode or decode fixed-point numbers 2024-09-28 20:21:06 +02:00
Philip Rebohle
b4e69dce76 [dxvk] Remove DxvkImageViewCreateInfo 2024-09-28 01:50:23 +02:00
Philip Rebohle
8195bea63e [dxvk] Remove DxvkBufferViewCreateInfo
Use the new key struct directly to avoid unnecessary struct conversion.
2024-09-28 01:21:07 +02:00
Philip Rebohle
b0d0959329 [dxvk] Remove DxvkDataBuffer
Unused.
2024-09-28 01:06:57 +02:00
Philip Rebohle
1cefe90ce7 [d3d11] Don't use data buffer for small buffer updates
Embed an array instead and lower the size threshold.
2024-09-28 01:05:40 +02:00
Philip Rebohle
01a7457a6f [dxvk] Remove createImageView function
Use the image's method instead, like we already do for buffers.
2024-09-28 00:03:56 +02:00
Paul Gofman
a172cab34f [dxgi] Delay qualifying foreground loss as occlusion 2024-09-27 18:15:24 +02:00
Philip Rebohle
4ed50ec6be [d3d9] Fix UP buffer allocation 2024-09-27 12:55:59 +02:00
Philip Rebohle
78f5136fde [dxvk] Fix image view swizzling 2024-09-26 17:42:02 +02:00
Philip Rebohle
5e5c283149 [d3d11] Always use fast MAP_WRITE_DISCARD path on deferred contexts
... but keep the SingleUse option as-is anyway because games do not release
their command lists after submission and end up wasting massive amounts of
memory.
2024-09-26 17:37:50 +02:00
Philip Rebohle
39f50999a3 [d3d11] Cache raw mapped pointer rather than allocation object
Reduces ref counting overhead again and matches previous behaviour.

We should probably do something about the possible case of deferred context
execution with MAP_WRITE_DISCARD followed by MAP_WRITE_NO_OVERWRITE on the
immediate context, but we haven't seen a game rely on this yet.
2024-09-26 17:37:50 +02:00
Philip Rebohle
50878f2846 [dxvk] Add function to invalidate images 2024-09-26 17:37:50 +02:00
Philip Rebohle
347925c8b7 [dxvk] Remove legacy DxvkMemory class 2024-09-26 17:37:50 +02:00
Philip Rebohle
25076d9220 [dxvk] Rework image view creation 2024-09-26 17:37:50 +02:00
Philip Rebohle
713b76bea5 [dxvk] Rework image creation
Uses DxvkResourceAllocation to manage image backing storage,
which will allow invalidating images in the future.
2024-09-26 17:37:50 +02:00
Philip Rebohle
d7e1794e29 [dxvk] Add function to import existing Vulkan image 2024-09-26 17:37:50 +02:00
Philip Rebohle
eec4f0fb35 [dxvk] Implement sparse image creation in allocator 2024-09-26 17:37:50 +02:00
Philip Rebohle
bcd12a5b56 [dxvk] Refactor sparse page table initialization for images 2024-09-26 17:37:50 +02:00
Philip Rebohle
0f23a17d8f [dxvk] Refactor sparse page allocation
Uses the new allocator directly.
2024-09-26 17:37:50 +02:00
Philip Rebohle
af4a2f7973 [dxvk] Introduce DxvkResourceMemoryInfo
And replace the old sparse thing.
2024-09-26 17:37:50 +02:00
Philip Rebohle
bbd2461c8f [dxvk] Reimplement sparse buffer support 2024-09-26 17:37:50 +02:00
Philip Rebohle
1ba6b81901 [dxvk] Reimplement imported buffers 2024-09-26 17:37:50 +02:00
Philip Rebohle
5263307c4a [dxvk] Improve lifetime tracking logic
Reduces ref counting overhead on the CS thread a bit.
2024-09-26 17:37:50 +02:00
Philip Rebohle
7ac9918b39 [hud] Add cache statistics to detailed memory item 2024-09-26 17:37:50 +02:00
Philip Rebohle
9cf72b5b19 [dxvk] Implement basic pool balancing for shared allocation cache
This makes the entire cache available to all allocation sizes rather than
having fixed-size pools for every allocation size. Improves hit rate in
games that primarily use one constant buffer size.
2024-09-26 17:37:50 +02:00
Philip Rebohle
428b1087a0 [dxvk] Implement shared cache statistics 2024-09-26 17:37:50 +02:00
Philip Rebohle
2722a41675 [dxvk] Implement shared allocation cache
Allows refilling local caches in constant time.
2024-09-26 17:37:50 +02:00
Philip Rebohle
9a51849920 [d3d11] Use allocation cache for dynamic buffers 2024-09-26 17:37:50 +02:00
Philip Rebohle
4db0007af3 [dxvk] Implement local allocation cache 2024-09-26 17:37:50 +02:00
Philip Rebohle
93547aec8d [dxvk] Do not track buffer view objects
No longer necessary as they have the same lifetime as the
parent buffer now. Only track the buffers themselves.
2024-09-26 17:37:50 +02:00
Philip Rebohle
088ba404a6 [dxvk] Rework buffer view creation 2024-09-26 17:37:50 +02:00
Philip Rebohle
1fd3c8040d [dxvk] Remove DxvkBufferAllocation 2024-09-26 17:37:50 +02:00
Philip Rebohle
14990dbb49 [dxvk] Rework buffer slice allocation
Temporary solution that hits the allocator on every single invalidation,
which isn't great but will do for now.
2024-09-26 17:37:50 +02:00
Philip Rebohle
ec2f43e5e3 [dxvk] Make DxvkResource manage its own destruction
Necessary for actual resource refactors. We want view objects
to use the resource's reference count wehenever possible.
2024-09-26 17:37:50 +02:00
Philip Rebohle
10164fdf4d [dxvk] Store GPU address for allocated chunk memory 2024-09-26 17:37:50 +02:00
Philip Rebohle
51649f6da6 [dxvk] Add function to create image resource 2024-09-26 17:37:50 +02:00
Philip Rebohle
5813e7c031 [dxvk] Add function to create buffer resource 2024-09-26 17:37:50 +02:00
Philip Rebohle
00f7545d15 [dxvk] Add helper to get memory type mask for buffer usage 2024-09-26 17:37:50 +02:00
Philip Rebohle
e80dd6db5f [dxvk] Cache memory type mask with global buffer support 2024-09-26 17:37:50 +02:00
Philip Rebohle
3bee390d91 [dxvk] Don't log memory errors prematurely
Fallback allocations are a thing.
2024-09-26 17:37:50 +02:00
Philip Rebohle
f36a536288 [dxvk] Use DxvkResourceAllocation internally
Changes DxvkMemory to be nothing more than a wrapper.
2024-09-26 17:37:50 +02:00
Philip Rebohle
5dd7a29261 [dxvk] Introduce DxvkResourceAllocation 2024-09-26 17:37:50 +02:00
Philip Rebohle
4064c89e8c [dxvk] Remove legacy buffer renaming interface 2024-09-26 17:37:50 +02:00
Philip Rebohle
6f6e75b4b8 [d3d9] Use DxvkBufferAllocation where appropriate 2024-09-26 17:37:50 +02:00
Philip Rebohle
8e45a60542 [d3d11] Use DxvkBufferAllocation where appropriate 2024-09-26 17:37:50 +02:00
Philip Rebohle
eae66201f6 [dxvk] Use DxvkBufferAllocation for HUD rendering 2024-09-26 17:37:50 +02:00
Philip Rebohle
75dadf2c1c [dxvk] Use DxvkBufferAllocation in swap chain blitter 2024-09-26 17:37:50 +02:00
Philip Rebohle
5c2f56c9cc [dxvk] Introduce DxvkBufferAllocation
For now, this is merely a wrapper around the existing buffer slice
struct in order to allow easier refactoring.
2024-09-26 17:37:50 +02:00
Philip Rebohle
d0832f8431 [vulkan] Move stage and access mask definitions to header 2024-09-26 17:37:50 +02:00
Philip Rebohle
7ec75aaf81 [util] Make likely/unlikely less annoying to use 2024-09-26 17:37:50 +02:00
Philip Rebohle
888906a6da [util] Add some functionality to smart pointer
Basically lets us deal with objects that manage their own destruction,
which ideally shold be all of them at some point.

Also adds some missing comparison operators.
2024-09-26 17:37:50 +02:00
Philip Rebohle
06baa48c2b [dxvk] Align allocation size to create global buffer 2024-09-26 13:13:48 +02:00
Philip Rebohle
401ca41091 [dxvk] Do not always keep an empty chunk around
Outdated thinking, we have a 20 second timer on this which should
be more than enough to ensure we're not spamming device memory
allocations.
2024-09-26 13:13:48 +02:00
Philip Rebohle
3cd7e3efb5 [dxvk] Tweak memory allocation behaviour on mapped memory types 2024-09-26 13:13:48 +02:00
Philip Rebohle
5c8728abd2 [hud] Use different colors to highlight mapped or non-mapped allocations
Useful on UMA systems or when we have to fall back to system memory.
2024-09-26 13:13:48 +02:00
Philip Rebohle
d00ca261af [dxvk] Use worker to update adapter's memory statistics
Takes a bunch of pointer indirections and atomics off the hot path.
2024-09-26 13:13:48 +02:00
Philip Rebohle
27088beea8 [dxvk] Use worker thread to periodically free unused memory
System memory allocations typically peak very high while loading, but
just sit there unused afterwards. This allows us to free them based
on when they have last been used.

Works well in practice since best-fit avoids using empty chunks as much
as possible.
2024-09-26 13:13:48 +02:00
Philip Rebohle
e1fd2bff2c [dxvk] Rewrite memory allocator
Uses a single allocator pair per memory type in order to make memory
allocations on the entire memory pool faster, and further reduce
fragmentation by applying the best fit strategy to the whole memory
pool.
2024-09-26 13:13:48 +02:00
Philip Rebohle
3a4dadb528 [dxvk] Add chunk concept to page allocator
This allows the allocator to operate on the entire allocated memory pool.
2024-09-26 13:13:48 +02:00
Philip Rebohle
266b99ad8d [hud] Add HUD item to visualize memory chunk allocation 2024-09-26 13:13:48 +02:00
Philip Rebohle
f679d7d90f [dxvk] Add detailed allocation statistics 2024-09-26 13:13:48 +02:00
Philip Rebohle
b46ef2ceff [dxvk] Move memory statistics from memory types to heaps 2024-09-26 13:13:48 +02:00
Philip Rebohle
35fea6475d [dxvk] Tune small buffer allocation sizes
The pool allocator works on powers of two, so buffers should too.
2024-09-26 13:13:48 +02:00
Philip Rebohle
3faa1a76da [dxvk] Simplify memory chunk allocation
Reduces overall waste of memory by reusing already allocated
chunks more aggressively.
2024-09-26 13:13:48 +02:00
Philip Rebohle
661385584a [dxvk] Use new allocators for chunk suballocation 2024-09-26 13:13:48 +02:00
Philip Rebohle
5efaa06c61 [dxvk] Add new page allocator implementation 2024-09-26 13:13:48 +02:00
Philip Rebohle
1eec969448 [util] Add 64-bit lzcnt 2024-09-26 13:13:48 +02:00
Philip Rebohle
343af21594 [build] Disable assertions for release builds 2024-09-26 13:13:48 +02:00
Philip Rebohle
0cf05780ab [meta] Release 2.4.1 2024-09-26 12:09:26 +02:00
Philip Rebohle
15365f2d82 [d3d11] Synchronize shared texture initialization 2024-09-26 08:21:43 +02:00
WinterSnowfall
97091aad39 [util] Enable legacy DISCARD for Rayman 3 2024-09-26 06:48:13 +02:00
WinterSnowfall
a7b3b1e3a4 [d3d8] Add an option to respect DISCARD only for dynamic write-only buffers 2024-09-26 06:48:13 +02:00
WinterSnowfall
4fad20d77c [d3d8] Relax viewport validation in windowed mode 2024-09-25 20:46:48 +02:00
琴梨梨OvO
bb6d1b3b4c [util]Add support for Time Leap Paradise 2024-09-25 19:54:24 +02:00
Robin Kertels
f5ca3cf5df [d3d9] ResolveZ: Only copy aspects that both images support 2024-09-25 00:32:13 +01:00
Robin Kertels
d7c2e3ac76 [d3d9] Use correct aspect mask when blitting depth stencil textures
We don't want to blit stencil when the D3D9 format doesn't have
stencil.
2024-09-25 00:32:13 +01:00
Robin Kertels
ca3aa2014b [d3d9] Improve comment about synchronization with ProcessVertices 2024-09-22 22:53:55 +02:00
Robin Kertels
1d49f247ac [d3d9] Remove incorrect early-exit
The same texture could be bound to
multiple slots and if the shader doesn't
use the lower index texture, we'd never
end up uploading it.
2024-09-22 22:53:55 +02:00
Robin Kertels
ef8bad33a5 [d3d9] Optimize late buffer uploads
... similar to what we're doing for textures.
2024-09-22 22:53:55 +02:00
Blisto91
5a08b3c451 [util] Cap fps for F.E.A.R 1 & expansions
Visual glitches can occur at very high fps
2024-09-22 21:07:08 +02:00
Robin Kertels
04ad98690b [d3d9] Add SWVP HUD item 2024-09-22 21:03:23 +02:00
Robin Kertels
033104f335 [d3d9] Cleanup buffer memory flag selection 2024-09-22 21:03:23 +02:00
Robin Kertels
5bb8d09a96 [d3d9] Always use per-draw buffer uploads on pure SWVP devices 2024-09-22 21:03:23 +02:00
WinterSnowfall
97fb6e4f6d [d3d9] Clean up supported formats from GetUnsupportedFormatInfo 2024-09-22 20:51:15 +02:00
WinterSnowfall
7985ac9cdb [d3d9] Add R16 and AL16 as known unsupported formats 2024-09-22 20:51:15 +02:00
Blisto91
e687303197 [util] Cap Prince of Persia (2008) max fps
Game can get stuck when loading at very high fps
2024-09-22 17:47:51 +02:00
Robin Kertels
07e7781c0b [d3d9] Only add meta image usage after determining layout 2024-09-22 15:48:18 +02:00
WinterSnowfall
c7cf0a7368 [d3d8] Respect D3DCREATE_MULTITHREADED and make d3d8 thread safe 2024-09-21 16:05:25 +02:00
Robin Kertels
c8791a6ba5 [d3d9] Don't emit 1-sized vector type in SWVP Emu
Fixes a validation error.
2024-09-20 12:57:11 +02:00
Robin Kertels
900edf55b5 [d3d9] Only create sampling image views if the image supports sampling
Fixes validation error
2024-09-20 12:57:11 +02:00
Robin Kertels
46e8161649 [d3d9] Enable shaderInt8 for ProcessVertices 2024-09-20 12:57:11 +02:00
Robin Kertels
828aaa5cdd [d3d9] Add missing TRANSFER_SRC usage for swapchain helper images 2024-09-20 12:57:11 +02:00
Philip Rebohle
43c27670ef [dxvk] Fix buffer view stuff again
Testing fallback paths that we only ever hit in scenarios without validation
output sure is fun....
2024-09-20 02:00:50 +02:00
Philip Rebohle
dd8af9da78 [dxvk] Fix buffer view derp systems not supporting maintenance5 2024-09-20 01:25:06 +02:00
Robin Kertels
80e950ac32 [util] Fix small_vector move
... again. We can only move over the ptr
if the other small_vector has MORE than N
elements, otherwise it will still use the local array.
2024-09-20 01:20:25 +02:00
Robin Kertels
2f9ce66879 [util] Fix small_vector move constructor 2024-09-19 20:56:09 +02:00
Philip Rebohle
398c198df6 [dxvk] Fix BDA validation error with dedicated allocations 2024-09-19 18:32:40 +02:00
Philip Rebohle
18ecc17e59 [dxvk] Remove unused discardBuffer method
Unused and not safe to use.
2024-09-18 15:55:57 +02:00
Philip Rebohle
c8410e578e [d3d11] Enable device address usage for non-mappable buffers
NVAPI queries the GPU address of certain resources in a way that could
break otherwise.
2024-09-18 15:55:57 +02:00
Philip Rebohle
fb552db65f [dxvk] Do not invalidate buffers that allow querying the device address 2024-09-18 15:55:57 +02:00
Philip Rebohle
ddb59ae394 [dxvk] Add usage property to buffer views
And pass it to the Vulkan driver depending on maintenance5 support.
2024-09-18 15:55:57 +02:00
Philip Rebohle
ab557a2eed [dxvk] Use global buffer whenever possible
Drastically reduces the number of Vulkan buffer objects allocated.
2024-09-18 15:55:57 +02:00
Philip Rebohle
901861c20b [dxvk] Create global buffer for allocated memory chunks 2024-09-18 15:55:57 +02:00
Blisto91
11ec603540 [util] Enable cachedDynamicBuffers for Battle Mages
Helps CPU bound performance
2024-09-18 00:25:05 +02:00
Paul Gofman
ed9ffa6584 [dxgi] Leave fullscreen mode when window looses focus 2024-09-18 00:19:56 +02:00
Paul Gofman
758dc805bb [dxgi] Prevent recursive fullscreen mode change. 2024-09-18 00:19:56 +02:00
WinterSnowfall
5cf0783edb [d3d8] Clean up D3D9 shaders on D3D8 device release 2024-09-17 19:45:18 +02:00
Robin Kertels
010738c107 [d3d9] Add HUD item for FF shaders 2024-09-17 18:30:27 +02:00
WinterSnowfall
89e190b771 [d3d8] Ensure d3d9 interface release 2024-09-17 18:30:00 +02:00
WinterSnowfall
84a8ea9d4a [d3d8] Remove some unneeded explicit ptr use 2024-09-17 18:30:00 +02:00
WinterSnowfall
9f8832dd14 [d3d8] Improve handling of failed d3d9 calls 2024-09-17 18:30:00 +02:00
Blisto91
f3fa4b102a [meta] Note DLLs need native override in readme 2024-09-17 02:08:28 +02:00
WinterSnowfall
0a2f2275da [d3d8] Add a framecap for Chrome: Gold Edition 2024-09-14 23:52:20 +02:00
Philip Rebohle
04cf0008a0 [dxvk] Correctly enable VK_EXT_line_rasterization
Oversight, and fixes a validation error.
2024-09-13 11:58:11 +02:00
WinterSnowfall
8e03b64ca4 [d3d8] Validate viewport dimensions on SetViewport 2024-09-12 16:39:40 +02:00
Robin Kertels
903f1af176 [d3d9] Fix PresentGDI 2024-09-12 15:39:21 +02:00
Kacper Michajłow
26a14c5175
[util] Fix GetEnvironmentVariableW usage 2024-09-12 00:04:49 +02:00
WinterSnowfall
3e26958906 [util] Add a framecap for Pandora Tomorrow 2024-09-12 00:02:34 +02:00
llyyr
1a1c3a4202 [d3d9,d3d11] recreate swapchain on VK_SUBOPTIMAL_KHR
The vulkan wayland wsi returns suboptimal when the window is
fullscreened and not directly scanned out, and there are modifiers
available that would allow the window to be directly scanned out.
Recreate the swapchain if we receive suboptimal result.

This allows us recreate the swapchain to use a modifier that allows
direct scan-out under winewayland on wayland compositors.
2024-09-11 16:38:26 +02:00
Philip Rebohle
c1a25df468 [dxvk] Fix some logic errors around sysmem chunk size 2024-09-11 15:21:03 +02:00
Philip Rebohle
565ec7e0d3 [dxvk] Remove dxvk.maxChunkSize option 2024-09-09 18:45:34 +02:00
Philip Rebohle
619b9b12c2 [dxvk] Implement dynamically growing chunk size
May reduce memory footprint for launchers.
2024-09-09 18:45:34 +02:00
WinterSnowfall
63506ee1ff [util] Enable cachedDynamicBuffers for Steel Soldiers and FIFA 2003 2024-09-08 19:26:46 +02:00
WinterSnowfall
22ff53013a [d3d8] Ignore unsupported D3DPRESENT_RATE_UNLIMITED 2024-09-08 19:25:16 +02:00
Billy Laws
9077e5212d [util] Use cdecl calling convention for __wine_dbg_output
This matches wine's definition, fixes crashes when wine is built with clang.
Since __cdecl isn't defined for non-windows targets ifdef this needs all
dbg callback uses to be ifdefed out.
2024-09-07 19:44:36 +02:00
Robin Kertels
daccde7643 [d3d9] Don't set IMAGE_USAGE_SAMPLED_BIT for non-msaa depth stencil surfaces 2024-09-04 22:17:10 +00:00
Robin Kertels
7f8cfec46f [d3d9] Always set IsAttachmentOnly for CreateOffscreenPlainSurfaceEx
Surfaces cannot be bound as textures.
2024-09-04 22:17:10 +00:00
Robin Kertels
1b172344eb [d3d9] Remove redundant scene check in StretchRect 2024-09-04 22:17:10 +00:00
Robin Kertels
11efd5092e [d3d9] Handle remaining edge cases of Discard & Lockable 2024-09-04 22:17:10 +00:00
WinterSnowfall
2c23e462b3 [d3d8] Clamp BaseVertexIndex to INT_MAX during use 2024-09-04 21:11:08 +02:00
Philip Rebohle
d0ea5a4a87 [spirv] Account for unreachable continue blocks
Fixes code gen in the following pattern encountered in Black Ops 3:

loop
  break
endloop

We cannot eliminate the loop since we have to adhere to structured
control flow rules, which might be broken if the code inside the
loop was non-trivial.
2024-09-04 02:26:35 +02:00
Philip Rebohle
427e706a40 [util,d3d11] Be more robust against use-after-free
Sims 4 binds an SRV after destroying it, so we need to ensure our internal
view pointers are null or we'll create a problem otherwise.
2024-09-02 22:03:26 +02:00
Philip Rebohle
04d558cf2e [util] Make frame rate limiter enablement heuristic more robust
Allow for more buffering to happen in order to not enable the limiter
too eagerly.
2024-09-02 17:50:47 +02:00
ericzlmd
38308d443e [build] added <algorithm> header for failed subcommand fix - remove_if 2024-08-31 13:23:26 +02:00
Tiagoquix
d31b7997c0 [util] Enable cachedDynamicBuffers for APB:Reloaded
Fixes frametime jumps when shooting.
Discussed on the Discord server.
2024-08-30 20:27:05 +02:00
MickAlmighty
8c58bef9cf [util] Hide Intel for Kena: Bridge of Spirits to skip faulty water rendering path. 2024-08-30 17:39:21 +02:00
Robin Kertels
a5fc08d176 [util] Disable direct buffer mapping for Max Payne 1
Improves performance by avoiding stalls.
2024-08-30 00:37:58 +02:00
Robin Kertels
e4fd9ff16b [d3d11] Always keep barrier control options set by app profile 2024-08-26 23:15:32 +02:00
Robin Kertels
eb8d1885bd [dxgi] Remove emulateUMA option
The option was only used for GTA IV.
It broke and we have a better solution now.
2024-08-24 19:05:44 +02:00
Robin Kertels
9a280b063a [util] Set maxDeviceMemory for GTA IV
... and replace emulateUMA
2024-08-24 19:05:44 +02:00
Philip Rebohle
1c30bc92bb [d3d11] Validate viewport parameters
And skip invalid calls. Fixes Senran Kagura Peach Ball.
2024-08-23 14:39:56 +02:00
Philip Rebohle
6da1ba7cff [dxgi] Avoid reporting large VRAM amounts as a power of two 2024-08-23 01:13:10 +02:00
Philip Rebohle
d89e324bc4 [util] Remove obsolete Metro Exodus EE config
No longer necessary or useful.
2024-08-20 13:33:04 +02:00
Philip Rebohle
be45907479 [dxgi] Under-report iGPU memory if dGPUs are present
Should help games pick the correct GPU on setups with integrated graphics.
2024-08-20 13:33:04 +02:00
Philip Rebohle
02d8fa593b [dxgi] Change reported UMD driver version
Fixes a potential crash in Hunt Showdown.
2024-08-15 22:04:06 +02:00
Philip Rebohle
71e44b380d [util] Enable context lock for EDF6
May or may not fix random crashing.
2024-08-15 20:55:17 +02:00
Philip Rebohle
159f540e10 [dxvk] Bump internal engine version
Due to large shader-related changes.
2024-08-14 22:15:50 +02:00
Philip Rebohle
1e5b78e8ea [d3d9] Enable longMad behaviour by default
And remove the respective config option.
2024-08-14 22:15:50 +02:00
Philip Rebohle
60e04503a6 [d3d11] Enable longMad/longDot behaviour by default
And remove the respective config options.
2024-08-14 22:15:50 +02:00
Philip Rebohle
beaf01ecad [dxbc] Reverse order of long dot products
Matches output of AMD's dxbc compiler this way.
2024-08-14 22:15:50 +02:00
Philip Rebohle
813b653645 [spirv] Implement basic dead code elimination
Fixes invalid SPIR-V in Trails through Daybreak.
2024-08-14 22:15:50 +02:00
Blisto91
6308266a0f [d3d9] Default to Strict floatEmulation for amdvlk 2024.Q3.1
The AMD Linux open source driver now optimizes for the Strict floatEmulation path.
2024-08-13 17:18:34 +02:00
Philip Rebohle
0d0b9eaac1 [util] Enable d3d11.longDot for Trails through Daybreak 2024-08-11 18:30:59 +02:00
Philip Rebohle
4ee907a6df [dxbc,d3d11] Add option to explicitly emit long dot products 2024-08-11 18:30:59 +02:00
Paul Gofman
5c987ea3d1 [d3d9] Handle map failure in texture initializer 2024-08-08 21:42:04 +02:00
Jeff
e38693cdbc [d3d9] Allow querying ID3D9VkInteropTexture from surfaces 2024-08-08 05:25:41 +01:00
Blisto91
7c9e1ed7cd [util] Set maxChunkSize to 1 for Epic Games Launcher
Also move up Battle.net so the launchers are grouped
2024-08-03 14:57:36 +02:00
Blisto91
e2b823b760 [util] Enable cachedDynamicBuffers for Art of Murder
Horrible CPU bound perf
2024-07-31 18:34:39 +02:00
Blisto91
1077d6a67f [util] Set textureMemory to 0 for Operation Racoon City
Works around a crash
2024-07-30 09:15:28 +02:00
Blisto91
33bf09122c [util] Add configs for Splinter Cell Conviction
The game will sometimes black screen upon alt-tab without deviceLossOnFocusLoss.
Spoofing the GPU through dxgi to a known one from its list prevents the System Detection tool from complaining that it is unsupported on some setups.
2024-07-28 23:04:35 +02:00
Eric Sullivan
c26b2ade1d [dxvk] Update shouldSubmit to correctly handle descriptorPoolOverallocation
Currently shouldSubmit will force the dxvk context to be flushed when
too many descriptor pools have been allocated. This heuristic does not
work when VK_NV_descriptor_pool_overallocation is in use because there
will only ever be a single pool.

This change updates the heuristic to use the number of allocated sets
when VK_NV_descriptor_pool_overallocation is in use.
2024-07-25 23:53:03 +02:00
Tobias Jakobi
10ab85c3ba [d3d8] Remove references to d3d8.useShadowBuffers for now
The current D3D8 codebase in DXVK does not implement this
feature, i.e. setting this option is a NOP. It was
implemented in D8VK at some point, but was removed before
the big merge.

Remove any references to avoid confusion.
2024-07-22 00:14:15 +02:00
Robin Kertels
031a98c232 [d3d9] Allow fourcc formats as the source in CheckFormatConversion
The docs say:
"The source format must be a FOURCC format or a valid back buffer format."
2024-07-19 19:25:31 +00:00
Robin Kertels
b7d61b70c1 [d3d9] Use converted format for multiplane formats in CheckFormat 2024-07-19 19:25:31 +00:00
WinterSnowfall
bac7ae2929 [util] Disable countLosableResources for Inquisitor 2024-07-16 16:42:44 +02:00
Felix Klinge
2a2d51e049 changed dxgi.customVendorId to dxgi.hideIntelGpu for Batman Arkham Knight 2024-07-16 16:21:08 +02:00
Felix Klinge
b74725b264 Add Batman Arkham Knight Custom Vendor ID to config to fix the game for Intel GPUs 2024-07-16 16:21:08 +02:00
Robin Kertels
af1ba1b205 [d3d9] FF: Fix return type for lighting op 2024-07-16 16:08:33 +02:00
WinterSnowfall
a8dbbcfa31 [util] Reorder config options by API 2024-07-12 16:42:31 +02:00
Blisto91
ba47af53da [meta] Rearrange readme
Rearrange the readme so the entries are consistently listed in a given section it makes sense. They are ordered from project info, usage, building and native.
2024-07-11 17:49:56 +02:00
Philip Rebohle
008afc1c5f [meta] Release 2.4 2024-07-10 11:56:14 +02:00
WinterSnowfall
d731608d5e [d3d8] Mimic native token allocations 2024-07-10 00:28:10 +02:00
WinterSnowfall
ff137dac9f [d3d8] Implement monotonic state block tokens 2024-07-09 23:20:52 +02:00
Robin Kertels
d456d0b437 [d3d9] StretchRect: Allow using an offscreen surface as dst when stretching 2024-07-09 13:54:59 +00:00
Robin Kertels
cc87870be1 [d3d9] Relax stretch rect check in D3D8 mode 2024-07-09 13:54:59 +00:00
Robin Kertels
a7ae5999a9 [d3d8] Slightly clean up CopyRects 2024-07-09 13:54:59 +00:00
Blisto91
5f9ca08071 [util] Enable deviceLossOnFocussLoss for Rise of Nations
To prevent it from crashing on a alt-tab
2024-07-09 15:42:49 +02:00
4b0c9c611c
[meta] Added d3d8 to list of overrides to create to README 2024-07-08 11:37:02 +01:00
Blisto91
fe9c875fe9 [util] Set cachedDynamicBuffers for The Sims 2 and friends
Helps very low CPU bound performance especially in Castaway Stories.
2024-07-07 14:31:37 +02:00
Blisto91
a63a5753d4 [util] Enable longMad for Tomb Raider Legend
Since the enablement of invariant position by default the game suffers from white flickers on characters when you use the Next Generation Content option
2024-07-07 14:23:11 +02:00
Robin Kertels
5a0f05ae66 [util] Disable counting losables for Battlefield 2 & 2142 2024-07-07 14:21:59 +02:00
WinterSnowfall
6ffd5acefa [util] dxvk.conf cleanup 2024-07-07 14:21:39 +02:00
Robin Kertels
33e7497ef4 [meta] Add Robin Kertels to LICENSE file 2024-07-07 11:51:34 +00:00
Er2
38006e9cda
[dxvk] Add FreeBSD support 2024-07-07 11:22:43 +00:00
Jeff
60e523b4bf
[d3d8] Implement Direct3D 8 Frontend
Co-authored-by: WinterSnowfall <WinterSnowfall@users.noreply.github.com>

## Config Changes

Co-authored-by: Blisto91 <47954800+Blisto91@users.noreply.github.com>
Co-authored-by: simifor <simirmonfor@gmail.com>
2024-07-07 11:10:48 +00:00
WinterSnowfall
ef0c6b6f6f [d3d9] Hardware cursor fixes 2024-07-07 01:32:40 -07:00
Robin Kertels
9b504b506e [d3d9] Rework FF texcoord processing to be more accurate 2024-07-07 01:28:44 -07:00
Blisto91
b2d89db8d8 [util] Disable countLosableResources for Myst V
Works around a crash regression in dxvk 2.3 upon resolution change.
2024-07-05 14:16:18 +02:00
Blisto91
fa5ce49675 [util] Enable longMad for Watch_Dogs 2 and Legion
Works around flickering on characters when a outline or highlight effect is showing.
2024-07-05 13:04:59 +02:00
Robin Kertels
bbe851f6a2 [d3d9] Reduce data copied for SWVP vertex decls 2024-07-05 00:44:28 -07:00
Robin Kertels
7de88ff993 [util] Add move & copy constructors to small_vector 2024-07-05 00:44:28 -07:00
Robin Kertels
ab12ffa0da [d3d9] Use max point size of Vulkan device
The default render state value has to match what we report in the device caps.
Fixes a Wine stateblock test.
2024-07-05 00:44:28 -07:00
Robin Kertels
dc3dd0f88c [d3d9] Ignore the vertex stream offset in StateBlock::Capture
Fixes a Wine test and matches further testing on Windows.
2024-07-05 00:44:28 -07:00
Robin Kertels
da814668bc [d3d9] FF: Prevent specular highlights on the back of geometry
Fixes the Wine test "test_specular_lighting".
2024-07-05 00:44:28 -07:00
Robin Kertels
df9bdfc6ea [util] Return unchanged matrix if matrix cannot be inverted 2024-07-05 00:44:28 -07:00
Robin Kertels
9e422a2b63 [d3d9] Fix default light
Fixes the diffuse alpha and the direction.
2024-07-05 00:44:28 -07:00
Robin Kertels
11db6d691c [d3d9] Fix reference leak in ProcessVertices
Also fixes a Wine test.
2024-07-05 00:44:28 -07:00
Robin Kertels
9c898bd269 [d3d9] Skip presenting if D3D9Swapchain has no associated window 2024-07-05 00:44:28 -07:00
Robin Kertels
175772944c [d3d9] Fix Wine test failures in StretchRect 2024-07-05 00:44:28 -07:00
WinterSnowfall
5ae3cfe402 [d3d9] Fix DF Formats selection logic 2024-07-05 00:43:09 -07:00
WinterSnowfall
b03de97f1b [d3d9] Expose support for D16_LOCKABLE only on AMD 2024-07-05 00:43:09 -07:00
WinterSnowfall
18035820de [d3d9] Remove vestigial D32 support 2024-07-05 00:43:09 -07:00
Łukasz Zając
1783b9591a
[util] Enable 60 FPS lock for WRC4
Fixes an audio issue.
2024-07-04 20:12:08 +02:00
Philip Rebohle
499460184a [build] Zero-pad soversion components as necessary 2024-07-03 13:23:25 +00:00
Philip Rebohle
afbcd94569 [util] Fix up recently added app profiles 2024-06-26 00:44:43 +02:00
Philip Rebohle
86f04a2da3 Revert "[util] Consolidate maxFrameRate options"
This reverts commit 1811f4b995.

The D3D12 Beyond Good and Evil remaster uses the same exe name as the
original D3D9 game, so it turns out the separation was useful after all.
2024-06-26 00:42:31 +02:00
Philip Rebohle
8573190c7d [dxvk] Apply frame rate limiter before signaling frame latency event
Otherwise we add latency for no reason.
2024-06-24 18:12:59 +02:00
Blisto91
fe0e02de18 [util] Set cachedDynamicBuffers for Battle for Middle-Earth 2
Helps slowdowns below 30fps in certain scenarios like when moving the camera over heavy vegetation areas among others
2024-06-22 21:58:16 +02:00
Robin Kertels
3145020a62 [d3d9] Only change vertex offset draw parameters when necessary
... Only change it when the vertex data is actually dynamically uploaded.
2024-06-21 13:18:39 +02:00
WinterSnowfall
e9fc071d95 [d3d9] Validate D3DCREATE_PUREDEVICE usage 2024-06-20 03:34:45 +00:00
Blisto91
a276e13821 [util] Set deviceLossOnFocusLoss for Guild Wars
Works around the game black screening on alt-tab when it is set to fullscreen with a non native resolution
2024-06-19 15:08:37 +02:00
Blisto91
4b4d323ec3 [util] Set cachedDynamicBuffers for Dragonshard
Works around massive FPS decreases in some scenes
2024-06-17 22:49:25 +02:00
Blisto91
d9994665a8 [util] Set strict floatEmulation for New Vegas
Fixes various visual issues with some effects in mods such as New Vegas Reloaded. White spots/shapes, black streaks across the screen (rain?) and probably more.
2024-06-17 22:49:25 +02:00
Blisto91
22b13a94ca [util] Enable deviceLossOnFocusLoss for The Force Unleased
Prevents the game from black screening on each alt-tab
2024-06-16 22:04:22 +02:00
Jeff
3e5eb1660f
[d3d8] Implement Dref scaling and fixed-function depth textures (#3565) 2024-06-14 12:10:49 +02:00
Trevonn
a8710f70a5 [util] Dead Space 2 - Lock to 60 FPS and enable vsync
Similar to the first game it has a poor vsync implementation and physics issues when the frame rate is unlocked.

Locking to 60 FPS and enabling vsync externally provides a better experience after the ingame vsync is disabled
2024-06-13 18:03:12 +02:00
Philip Rebohle
336c9b6acc [dxgi] Allow changing refresh rate even without ALLOW_MODE_SWITCH
Matches Windows behaviour, entering fullscreen state will only prevent
us from changing the display resolution if the flag is not set.
2024-06-12 17:33:41 +02:00
Blisto91
018db92342 [util] Disable Crysis 1 refresh rate fps limiter
Game bug in its d3d10 mode where it selects the lowest supported refresh rate.
2024-06-11 15:45:30 +02:00
Philip Rebohle
51f2e246fa [util,dxvk] Limit frame rate based on deadline
This should work better now that present_wait is universally supported.
2024-06-11 15:45:17 +02:00
Philip Rebohle
1811f4b995 [util] Consolidate maxFrameRate options 2024-06-11 15:45:17 +02:00
Philip Rebohle
5674abe483 [d3d9] Limit frame rate to display refresh as necessary 2024-06-11 15:45:17 +02:00
Philip Rebohle
1c198dcd48 [dxgi] Limit frame rate to display refresh as necessary 2024-06-11 15:45:17 +02:00
Philip Rebohle
379346751a [util] Implement refresh rate heuristic for frame rate limiter 2024-06-11 15:45:17 +02:00
Philip Rebohle
b4c4c9e683 [util] Remove useless vsync parameter from FPS limiter 2024-06-11 15:45:17 +02:00
Sanakan8472
2188caae8e Fix GLFW exception at startup
`GlfwWsiDriver::getInstanceExtensions` was creating an `std::vector` with a size argument in the ctor but then used `push_back` instead of filling the pre-allocated elements, leading to a bunch of nullptr entries at the start that caused an exception later on when accessed.
2024-06-10 13:41:50 +02:00
Blisto91
8d965359a5 [util] Set longMad for Watch_Dogs
Works around flickering on some objects such as the blue light arrow on lowering gates
2024-06-06 19:01:42 +02:00
Philip Rebohle
fd978704fb [dxvk] Add dxvk.deviceFilter config option 2024-06-05 00:49:26 +02:00
Tiagoquix
ee18aecb8a
[util] Add dxvk.maxChunkSize 1 for Origin Web Helper Service and Ubisoft Connect (UPlay) (#4047)
* Add dxvk.maxChunkSize 1 to Ubisoft Connect (UPlay)

* Add Origin Web Helper Service and fix Rockstar Games entries

* Revert Rockstar changes, improve Origin and Ubisoft
2024-06-02 20:08:52 +02:00
Blisto91
c2fd91f835 [util] Set longMad for Ghostbusters Remastered
Works around flickering on character faces
2024-06-02 11:10:13 +02:00
Tiagoquix
79eea564fb Add dxvk.maxChunkSize 1 to Origin 2024-05-31 23:46:26 +02:00
Robin Kertels
7df8017e46 [d3d9] FF: Apply transform flags count to generated texture coords
... and fix cases where projection doesn't get applied.
2024-05-27 20:52:32 +00:00
WinterSnowfall
c98152683f [d3d9] Tweak VCache query results 2024-05-27 19:53:19 +02:00
Blisto91
890ad3f47f [CI] Update CI actions 2024-05-27 19:38:16 +02:00
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
382 changed files with 42609 additions and 16062 deletions

View file

@ -4,18 +4,18 @@ on: [push, pull_request, workflow_dispatch]
jobs:
artifacts-mingw-w64:
runs-on: ubuntu-20.04
runs-on: ubuntu-latest
steps:
- name: Checkout code
id: checkout-code
uses: actions/checkout@v3
uses: actions/checkout@v4
with:
submodules: recursive
fetch-depth: 0
- name: Setup problem matcher
uses: Joshua-Ashton/gcc-problem-matcher@v2
uses: Joshua-Ashton/gcc-problem-matcher@v3
- name: Build release
id: build-release
@ -28,39 +28,56 @@ jobs:
- name: Upload artifacts
id: upload-artifacts
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v4
with:
name: dxvk-${{ env.VERSION_NAME }}
name: dxvk-win-${{ env.VERSION_NAME }}
path: build/dxvk-${{ env.VERSION_NAME }}
if-no-files-found: error
artifacts-steamrt-sniper:
runs-on: ubuntu-20.04
runs-on: ubuntu-latest
container: registry.gitlab.steamos.cloud/steamrt/sniper/sdk:beta
steps:
- name: Checkout code
id: checkout-code
uses: actions/checkout@v3
uses: actions/checkout@v4
with:
submodules: recursive
fetch-depth: 0
- name: Setup problem matcher
uses: Joshua-Ashton/gcc-problem-matcher@v2
uses: Joshua-Ashton/gcc-problem-matcher@v3
- name: Build release
id: build-release
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
id: upload-artifacts
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v4
with:
name: dxvk-${{ env.VERSION_NAME }}
path: build/dxvk-native-${{ env.VERSION_NAME }}
name: dxvk-native-${{ env.VERSION_NAME }}
path: build/dxvk-native-${{ env.VERSION_NAME }}.tar.gz
if-no-files-found: error
merge-artifacts:
runs-on: ubuntu-latest
needs: [artifacts-mingw-w64, artifacts-steamrt-sniper]
steps:
- name: Get version
id: get-version
shell: bash
run: |
echo "VERSION_NAME=${GITHUB_REF##*/}-${GITHUB_SHA##*/}" >> $GITHUB_ENV
- name: Merge Artifacts
uses: actions/upload-artifact/merge@v4
with:
name: dxvk-${{ env.VERSION_NAME }}
pattern: dxvk*
delete-merged: true

View file

@ -4,14 +4,15 @@ on: [push, pull_request, workflow_dispatch]
jobs:
build-set-windows:
runs-on: windows-2022
runs-on: windows-latest
steps:
- name: Checkout code
id: checkout-code
uses: actions/checkout@v3
uses: actions/checkout@v4
with:
submodules: recursive
fetch-depth: 0
- name: Setup glslangValidator
shell: pwsh
@ -32,6 +33,19 @@ jobs:
Write-Output "VSDEVCMD=${installationPath}\Common7\Tools\VsDevCmd.bat" `
| Out-File -FilePath "${Env:GITHUB_ENV}" -Append
- name: Download D3D8 SDK Headers
shell: pwsh
run: |
Invoke-WebRequest -URI https://raw.githubusercontent.com/NovaRain/DXSDK_Collection/master/DXSDK_Aug2007/Include/d3d8.h -OutFile include/d3d8.h
Invoke-WebRequest -URI https://raw.githubusercontent.com/NovaRain/DXSDK_Collection/master/DXSDK_Aug2007/Include/d3d8types.h -OutFile include/d3d8types.h
Invoke-WebRequest -URI https://raw.githubusercontent.com/NovaRain/DXSDK_Collection/master/DXSDK_Aug2007/Include/d3d8caps.h -OutFile include/d3d8caps.h
- name: Get version
id: get-version
shell: bash
run: |
echo "VERSION_NAME=${GITHUB_REF##*/}-${GITHUB_SHA##*/}" >> $GITHUB_ENV
- name: Build MSVC x86
shell: pwsh
run: |
@ -49,3 +63,19 @@ jobs:
| % { [System.Environment]::SetEnvironmentVariable($_[0], $_[1]) }
meson --buildtype release --backend vs2022 build-msvc-x64
msbuild -m build-msvc-x64/dxvk.sln
- name: Prepare artifacts
shell: pwsh
run: |
mkdir artifacts\x32
ls -Path build-msvc-x86\src -Include *.dll,*.pdb -Recurse
| cp -Destination (Join-Path -Path (pwd) -ChildPath artifacts\x32)
mkdir artifacts\x64
ls -Path build-msvc-x64\src -Include *.dll,*.pdb -Recurse
| cp -Destination (Join-Path -Path (pwd) -ChildPath artifacts\x64)
- name: Upload artifacts
uses: actions/upload-artifact@v4
with:
name: dxvk-${{ env.VERSION_NAME }}-msvc-output
path: artifacts\*

View file

@ -1,5 +1,7 @@
Copyright (c) 2017 Philip Rebohle
Copyright (c) 2019 Joshua Ashton
Copyright (c) 2019 Robin Kertels
Copyright (c) 2023 Jeffrey Ellison
zlib/libpng license

176
README.md
View file

@ -1,6 +1,6 @@
# DXVK
A Vulkan-based translation layer for Direct3D 9/10/11 which allows running 3D applications on Linux using Wine.
A Vulkan-based translation layer for Direct3D 8/9/10/11 which allows running 3D applications on Linux using Wine.
For the current status of the project, please refer to the [project wiki](https://github.com/doitsujin/dxvk/wiki).
@ -9,7 +9,7 @@ The most recent development builds can be found [here](https://github.com/doitsu
Release builds can be found [here](https://github.com/doitsujin/dxvk/releases).
## How to use
In order to install a DXVK package obtained from the [release](https://github.com/doitsujin/dxvk/releases) page into a given wine prefix, copy or symlink the DLLs into the following directories as follows, then open `winecfg` and manually add DLL overrides for `d3d11`, `d3d10core`, `dxgi`, and `d3d9`.
In order to install a DXVK package obtained from the [release](https://github.com/doitsujin/dxvk/releases) page into a given wine prefix, copy or symlink the DLLs into the following directories as follows, then open `winecfg` and manually add `native` DLL overrides for `d3d8`, `d3d9`, `d3d10core`, `d3d11` and `dxgi` under the Libraries tab.
In a default Wine prefix that would be as follows:
```
@ -32,9 +32,87 @@ In order to remove DXVK from a prefix, remove the DLLs and DLL overrides, and ru
Tools such as Steam Play, Lutris, Bottles, Heroic Launcher, etc will automatically handle setup of dxvk on their own when enabled.
#### DLL dependencies
Listed below are the DLL requirements for using DXVK with any single API.
- d3d8: `d3d8.dll` and `d3d9.dll`
- d3d9: `d3d9.dll`
- d3d10: `d3d10core.dll`, `d3d11.dll` and `dxgi.dll`
- d3d11: `d3d11.dll` and `dxgi.dll`
### Notes on Vulkan drivers
Before reporting an issue, please check the [Wiki](https://github.com/doitsujin/dxvk/wiki/Driver-support) page on the current driver status and make sure you run a recent enough driver version for your hardware.
### Online multi-player games
Manipulation of Direct3D libraries in multi-player games may be considered cheating and can get your account **banned**. This may also apply to single-player games with an embedded or dedicated multiplayer portion. **Use at your own risk.**
### HUD
The `DXVK_HUD` environment variable controls a HUD which can display the framerate and some stat counters. It accepts a comma-separated list of the following options:
- `devinfo`: Displays the name of the GPU and the driver version.
- `fps`: Shows the current frame rate.
- `frametimes`: Shows a frame time graph.
- `submissions`: Shows the number of command buffers submitted per frame.
- `drawcalls`: Shows the number of draw calls and render passes per frame.
- `pipelines`: Shows the total number of graphics and compute pipelines.
- `descriptors`: Shows the number of descriptor pools and descriptor sets.
- `memory`: Shows the amount of device memory allocated and used.
- `allocations`: Shows detailed memory chunk suballocation info.
- `gpuload`: Shows estimated GPU load. May be inaccurate.
- `version`: Shows DXVK version.
- `api`: Shows the D3D feature level used by the application.
- `cs`: Shows worker thread statistics.
- `compiler`: Shows shader compiler activity
- `samplers`: Shows the current number of sampler pairs used *[D3D9 Only]*
- `ffshaders`: Shows the current number of shaders generated from fixed function state *[D3D9 Only]*
- `swvp`: Shows whether or not the device is running in software vertex processing mode *[D3D9 Only]*
- `scale=x`: Scales the HUD by a factor of `x` (e.g. `1.5`)
- `opacity=y`: Adjusts the HUD opacity by a factor of `y` (e.g. `0.5`, `1.0` being fully opaque).
Additionally, `DXVK_HUD=1` has the same effect as `DXVK_HUD=devinfo,fps`, and `DXVK_HUD=full` enables all available HUD elements.
### Logs
When used with Wine, DXVK will print log messages to `stderr`. Additionally, standalone log files can optionally be generated by setting the `DXVK_LOG_PATH` variable, where log files in the given directory will be called `app_d3d11.log`, `app_dxgi.log` etc., where `app` is the name of the game executable.
On Windows, log files will be created in the game's working directory by default, which is usually next to the game executable.
### Frame rate limit
The `DXVK_FRAME_RATE` environment variable can be used to limit the frame rate. A value of `0` uncaps the frame rate, while any positive value will limit rendering to the given number of frames per second. Alternatively, the configuration file can be used.
### Device filter
Some applications do not provide a method to select a different GPU. In that case, DXVK can be forced to use a given device:
- `DXVK_FILTER_DEVICE_NAME="Device Name"` Selects devices with a matching Vulkan device name, which can be retrieved with tools such as `vulkaninfo`. Matches on substrings, so "VEGA" or "AMD RADV VEGA10" is supported if the full device name is "AMD RADV VEGA10 (LLVM 9.0.0)", for example. If the substring matches more than one device, the first device matched will be used.
**Note:** If the device filter is configured incorrectly, it may filter out all devices and applications will be unable to create a D3D device.
### Debugging
The following environment variables can be used for **debugging** purposes.
- `VK_INSTANCE_LAYERS=VK_LAYER_KHRONOS_validation` Enables Vulkan debug layers. Highly recommended for troubleshooting rendering issues and driver crashes. Requires the Vulkan SDK to be installed on the host system.
- `DXVK_LOG_LEVEL=none|error|warn|info|debug` Controls message logging.
- `DXVK_LOG_PATH=/some/directory` Changes path where log files are stored. Set to `none` to disable log file creation entirely, without disabling logging.
- `DXVK_DEBUG=markers|validation` Enables use of the `VK_EXT_debug_utils` extension for translating performance event markers, or to enable Vulkan validation, respecticely.
- `DXVK_CONFIG_FILE=/xxx/dxvk.conf` Sets path to the configuration file.
- `DXVK_CONFIG="dxgi.hideAmdGpu = True; dxgi.syncInterval = 0"` Can be used to set config variables through the environment instead of a configuration file using the same syntax. `;` is used as a seperator.
### Graphics Pipeline Library
On drivers which support `VK_EXT_graphics_pipeline_library` Vulkan shaders will be compiled at the time the game loads its D3D shaders, rather than at draw time. This reduces or eliminates shader compile stutter in many games when compared to the previous system.
In games that load their shaders during loading screens or in the menu, this can lead to prolonged periods of very high CPU utilization, especially on weaker CPUs. For affected games it is recommended to wait for shader compilation to finish before starting the game to avoid stutter and low performance. Shader compiler activity can be monitored with `DXVK_HUD=compiler`.
This feature largely replaces the state cache.
**Note:** Games which only load their D3D shaders at draw time (e.g. most Unreal Engine games) will still exhibit some stutter, although it should still be less severe than without this feature.
### State cache
DXVK caches pipeline state by default, so that shaders can be recompiled ahead of time on subsequent runs of an application, even if the driver's own shader cache got invalidated in the meantime. This cache is enabled by default, and generally reduces stuttering.
The following environment variables can be used to control the cache:
- `DXVK_STATE_CACHE`: Controls the state cache. The following values are supported:
- `disable`: Disables the cache entirely.
- `reset`: Clears the cache file.
- `DXVK_STATE_CACHE_PATH=/some/directory` Specifies a directory where to put the cache files. Defaults to the current working directory of the application.
This feature is mostly only relevant on systems without support for `VK_EXT_graphics_pipeline_library`
## Build instructions
In order to pull in all submodules that are needed for building, clone the repository using the following command:
@ -42,11 +120,9 @@ In order to pull in all submodules that are needed for building, clone the repos
git clone --recursive https://github.com/doitsujin/dxvk.git
```
### Requirements:
- [wine 7.1](https://www.winehq.org/) or newer
- [Meson](https://mesonbuild.com/) build system (at least version 0.49)
- [Meson](https://mesonbuild.com/) build system (at least version 0.58)
- [Mingw-w64](https://www.mingw-w64.org) compiler and headers (at least version 10.0)
- [glslang](https://github.com/KhronosGroup/glslang) compiler
@ -76,76 +152,9 @@ cd build.w64
ninja install
```
The D3D9, D3D10, D3D11 and DXGI DLLs will be located in `/your/dxvk/directory/bin`. Setup has to be done manually in this case.
The D3D8, D3D9, D3D10, D3D11 and DXGI DLLs will be located in `/your/dxvk/directory/bin`.
### Online multi-player games
Manipulation of Direct3D libraries in multi-player games may be considered cheating and can get your account **banned**. This may also apply to single-player games with an embedded or dedicated multiplayer portion. **Use at your own risk.**
### Logs
When used with Wine, DXVK will print log messages to `stderr`. Additionally, standalone log files can optionally be generated by setting the `DXVK_LOG_PATH` variable, where log files in the given directory will be called `app_d3d11.log`, `app_dxgi.log` etc., where `app` is the name of the game executable.
On Windows, log files will be created in the game's working directory by default, which is usually next to the game executable.
### HUD
The `DXVK_HUD` environment variable controls a HUD which can display the framerate and some stat counters. It accepts a comma-separated list of the following options:
- `devinfo`: Displays the name of the GPU and the driver version.
- `fps`: Shows the current frame rate.
- `frametimes`: Shows a frame time graph.
- `submissions`: Shows the number of command buffers submitted per frame.
- `drawcalls`: Shows the number of draw calls and render passes per frame.
- `pipelines`: Shows the total number of graphics and compute pipelines.
- `descriptors`: Shows the number of descriptor pools and descriptor sets.
- `memory`: Shows the amount of device memory allocated and used.
- `gpuload`: Shows estimated GPU load. May be inaccurate.
- `version`: Shows DXVK version.
- `api`: Shows the D3D feature level used by the application.
- `cs`: Shows worker thread statistics.
- `compiler`: Shows shader compiler activity
- `samplers`: Shows the current number of sampler pairs used *[D3D9 Only]*
- `scale=x`: Scales the HUD by a factor of `x` (e.g. `1.5`)
- `opacity=y`: Adjusts the HUD opacity by a factor of `y` (e.g. `0.5`, `1.0` being fully opaque).
Additionally, `DXVK_HUD=1` has the same effect as `DXVK_HUD=devinfo,fps`, and `DXVK_HUD=full` enables all available HUD elements.
### Frame rate limit
The `DXVK_FRAME_RATE` environment variable can be used to limit the frame rate. A value of `0` uncaps the frame rate, while any positive value will limit rendering to the given number of frames per second. Alternatively, the configuration file can be used.
### Device filter
Some applications do not provide a method to select a different GPU. In that case, DXVK can be forced to use a given device:
- `DXVK_FILTER_DEVICE_NAME="Device Name"` Selects devices with a matching Vulkan device name, which can be retrieved with tools such as `vulkaninfo`. Matches on substrings, so "VEGA" or "AMD RADV VEGA10" is supported if the full device name is "AMD RADV VEGA10 (LLVM 9.0.0)", for example. If the substring matches more than one device, the first device matched will be used.
**Note:** If the device filter is configured incorrectly, it may filter out all devices and applications will be unable to create a D3D device.
### Graphics Pipeline Library
On drivers which support `VK_EXT_graphics_pipeline_library` Vulkan shaders will be compiled at the time the game loads its D3D shaders, rather than at draw time. This reduces or eliminates shader compile stutter in many games when compared to the previous system.
In games that load their shaders during loading screens or in the menu, this can lead to prolonged periods of very high CPU utilization, especially on weaker CPUs. For affected games it is recommended to wait for shader compilation to finish before starting the game to avoid stutter and low performance. Shader compiler activity can be monitored with `DXVK_HUD=compiler`.
This feature largely replaces the state cache.
**Note:** Games which only load their D3D shaders at draw time (e.g. most Unreal Engine games) will still exhibit some stutter, although it should still be less severe than without this feature.
### State cache
DXVK caches pipeline state by default, so that shaders can be recompiled ahead of time on subsequent runs of an application, even if the driver's own shader cache got invalidated in the meantime. This cache is enabled by default, and generally reduces stuttering.
The following environment variables can be used to control the cache:
- `DXVK_STATE_CACHE`: Controls the state cache. The following values are supported:
- `disable`: Disables the cache entirely.
- `reset`: Clears the cache file.
- `DXVK_STATE_CACHE_PATH=/some/directory` Specifies a directory where to put the cache files. Defaults to the current working directory of the application.
This feature is mostly only relevant on systems without support for `VK_EXT_graphics_pipeline_library`
### Debugging
The following environment variables can be used for **debugging** purposes.
- `VK_INSTANCE_LAYERS=VK_LAYER_KHRONOS_validation` Enables Vulkan debug layers. Highly recommended for troubleshooting rendering issues and driver crashes. Requires the Vulkan SDK to be installed on the host system.
- `DXVK_LOG_LEVEL=none|error|warn|info|debug` Controls message logging.
- `DXVK_LOG_PATH=/some/directory` Changes path where log files are stored. Set to `none` to disable log file creation entirely, without disabling logging.
- `DXVK_DEBUG=markers|validation` Enables use of the `VK_EXT_debug_utils` extension for translating performance event markers, or to enable Vulkan validation, respecticely.
- `DXVK_CONFIG_FILE=/xxx/dxvk.conf` Sets path to the configuration file.
- `DXVK_CONFIG="dxgi.hideAmdGpu = True; dxgi.syncInterval = 0"` Can be used to set config variables through the environment instead of a configuration file using the same syntax. `;` is used as a seperator.
## Troubleshooting
### Build troubleshooting
DXVK requires threading support from your mingw-w64 build environment. If you
are missing this, you may see "error: std::cv_status has not been declared"
or similar threading related errors.
@ -163,3 +172,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 `SDL3`, `SDL2`, and `GLFW`.
DXVK Native comes with a slim set of Windows header definitions required for D3D9/11 and the MinGW headers for D3D9/11.
In most cases, it will end up being plug and play with your renderer, but there may be certain teething issues such as:
- `__uuidof(type)` is supported, but `__uuidof(variable)` is not supported. Use `__uuidof_var(variable)` instead.

View file

@ -1 +1 @@
2.3.1
2.5.3

6
buildenv.h.in Normal file
View file

@ -0,0 +1,6 @@
#pragma once
#define DXVK_TARGET "@BUILD_TARGET@"
#define DXVK_COMPILER "@BUILD_COMPILER@"
#define DXVK_COMPILER_VERSION "@BUILD_COMPILER_VERSION@"

258
dxvk.conf
View file

@ -1,3 +1,10 @@
# Device filter. Only exposes devices whose Vulkan device name contains
# the given string. May be useful to force an application to run on a
# specific GPU, but not applications launched by that application.
# dxvk.deviceFilter = ""
# Expose the HDR10 ColorSpace (DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020)
# to the application by default.
# This shows to the game that the global Windows 'HDR Mode' is enabled.
@ -10,6 +17,40 @@
# dxgi.enableHDR = True
# Expose support for dcomp swap chains with a dummy window.
#
# This is not a valid implementation of DirectComposition swapchains,
# however some games may rely on this functionality to be present while
# others may require swap chain creation to fail.
#
# Supported values: True, False
# dxgi.enableDummyCompositionSwapchain = False
# Allows the Vulkan driver to opt-in to exclusive full-screen mode on
# Windows. Certain features, such as variable refresh rate or HDR, will
# not work without this setting, however enabling it will break certain
# games that use additional GDI windows, and it will also break alt+tab.
#
# This setting has no effect on non-Windows platforms.
#
# Supported values: True, False
# dxvk.allowFse = False
# Enables Unreal Engine 4 HDR workarounds for games that do not follow
# the standard -Win64-Shipping.exe naming scheme. May be needed to avoid
# crashes in D3D11 games on HDR-enabled systems due to statically linked
# AMDAGS.
#
# Supported values: True, False
# dxgi.enableUe4Workarounds = False
# Create the VkSurface on the first call to IDXGISwapChain::Present,
# rather than when creating the swap chain. Some games that start
# rendering with a different graphics API may require this option,
@ -35,12 +76,57 @@
# bugs in games that have physics or other simulation tied to their frame
# rate, but do not provide their own limiter.
#
# Supported values : Any non-negative integer
# Supported values
# -1: Always disables the limiter
# 0: Default behaviour. Limits the frame rate to the selected display
# refresh rate when vertical synchronization is enabled if the
# actual display mode does not match the game's one.
# n: Limit to n frames per second.
# dxgi.maxFrameRate = 0
# d3d9.maxFrameRate = 0
# Controls latency sleep and Nvidia Reflex support.
#
# Supported values:
# - Auto: By default, DXVK only supports latency sleep in D3D11 games that
# use Reflex if the graphics driver supports VK_NV_low_latency2,
# and if dxvk-nvapi is enabled in Proton.
# - True: Enables built-in latency reduction based on internal timings.
# This assumes that input sampling for any given frame happens after
# the D3D9 or DXGI Present call returns; games that render and present
# asynchronously will not behave as intended.
# Similarly, this will not have any effect in games with built-in frame
# rate limiters, or if an external limiter (such as MangoHud) is used.
# In some games, enabling this may reduce performance or lead to less
# consistent frame pacing.
# The implementation will either use VK_NV_low_latency2 if supported
# by the driver, or a custom algorithm.
# - False: Disable Reflex support as well as built-in latency reduction.
# dxvk.latencySleep = Auto
# Tolerance for the latency sleep heuristic, in microseconds. Higher values
# increase latency, but may lead to better frame pacing in some cases. Does
# not have any effect if NV_low_latency2 is used.
#
# Supported values: Any non-negative number
# dxvk.latencyTolerance = 1000
# Disables the use of VK_NV_low_latency2. This will make Reflex unavailable
# in games, and if dxvk.latencySleep is set to True, a custom algorithm will
# be used for latency control. By default, the extension will not be used in
# 32-bit applications due to driver issues.
#
# Supported values: Auto, True, False
# dxvk.disableNvLowLatency2 = Auto
# Override PCI vendor and device IDs reported to the application. Can
# cause the app to adjust behaviour depending on the selected values.
#
@ -105,24 +191,6 @@
# dxgi.maxSharedMemory = 0
# Some games think we are on Intel given a lack of NVAPI or
# AGS/atiadlxx support. Report our device memory as shared memory,
# and some small amount for a "carveout".
# Supported values: True, False
# dxgi.emulateUMA = False
# Override back buffer count for the Vulkan swap chain.
# Setting this to 0 or less will have no effect.
#
# Supported values: Any number greater than or equal to 2.
# dxgi.numBackBuffers = 0
# d3d9.numBackBuffers = 0
# Overrides synchronization interval (Vsync) for presentation.
# Setting this to 0 disables vertical synchronization entirely.
# A positive value 'n' will enable Vsync and repeat the same
@ -134,10 +202,10 @@
# d3d9.presentInterval = -1
# Controls tearing behaviour with regards to in-game Vsync settings.
#
# True enables the mailbox present mode in case regular Vsync is disabled.
# This should avoid tearing, but may be unsupported on some systems
# or require setting dxgi.numBackBuffers to a higher value in order
# to work properly.
# This eliminates tearing, but may be unsupported on some systems.
#
# False enables the relaxed fifo present mode in case regular Vsync is enabled.
# This should result in tearing but reduce stutter if FPS are too low,
@ -150,13 +218,14 @@
# dxvk.tearFree = Auto
# Assume single-use mode for command lists created on deferred contexts.
# This may need to be disabled for some applications to avoid rendering
# issues, which may come at a significant performance cost.
# Controls tiler optimizations. Enabling these will alter the behaviour of
# submission heuristics and enables some non-default behaviour in DXVK.
# This option is only intended to be changed for performance testing and
# debugging purposes.
#
# Supported values: True, False
# Supported values: Auto, True, False
# d3d11.dcSingleUseMode = True
# dxvk.tilerMode = Auto
# Override the maximum feature level that a D3D11 device can be created
@ -177,23 +246,25 @@
# Enables relaxed pipeline barriers around UAV writes.
#
# This may improve performance in some games, but may also introduce
# rendering issues. Please don't report bugs with the option enabled.
#
# Ignores write-after-write hazards in compute shaders, and all UAV
# hazards in graphics shaders. This may improve performance in some
# games, but may also introduce rendering issues. Please don't report
# bugs with the option enabled.
#
# Supported values: True, False
# d3d11.relaxedBarriers = False
# Ignores barriers around UAV writes from fragment shaders.
# Enables relaxed UAV pipeline barriers in graphics shaders only.
#
# This may improve performance in some games, but may also introduce
# rendering issues. Please don't report bugs with the option enabled.
# Similar to the relaxedBarriers option, except it does not apply to
# compute UAVs. Please do not report bugs with this option enabled.
#
# Supported values: True, False
# d3d11.ignoreGraphicsBarriers = False
# d3d11.relaxedGraphicsBarriers = False
# Overrides anisotropic filtering for all samplers. Set this to a positive
@ -261,20 +332,33 @@
# d3d11.zeroWorkgroupMemory = False
# Resource size limit for implicit discards, in kilobytes. For small staging
# resources mapped with MAP_WRITE, DXVK will sometimes allocate new backing
# storage in order to avoid GPU synchronization, so setting this too high
# may cause memory issues, setting it to -1 disables the feature.
# Forces insertion of memory barriers after writes to group-shared memory in
# compute shaders. This is only intended to be used as a workaround for games
# that don't properly synchronize access to groupshard variables, and may have
# a negative performance impact as it prevents compiler optimizations.
#
# Supported values: True, False
# d3d11.maxImplicitDiscardSize = 256
# d3d11.forceVolatileTgsmAccess = False
# Resource size limit for buffer-mapped dynamic images, in kilobytes.
# A higher threshold may reduce memory usage and PCI-E bandwidth in
# some games, but may also increase GPU synchronizations. Setting it
# to -1 disables the feature.
# Forces insertion of full memory and control barriers after accessing any
# read-write UAV inside compute shaders. This is only intended to be used as
# a workaround for games that do not synchronize access to coherent UAVs,
# and will likely have a negative performance impact.
#
# Supported values: True, False
# d3d11.maxDynamicImageBufferSize = -1
# d3d11.forceComputeUavBarriers = False
# Clears mapped memory to zero when suballocated memory is freed. This will
# drastically increase CPU overhead and should only be used as a last resort
# if a game does not properly initialize mapped buffers on its own.
#
# Supported values: True, False
# dxvk.zeroMappedMemory = False
# Allocates dynamic resources with the given set of bind flags in
@ -312,6 +396,20 @@
# 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
@ -340,17 +438,6 @@
# dxvk.useRawSsbo = Auto
# Changes memory chunk size.
#
# Can be used to override the maximum memory chunk size.
#
# Supported values:
# - 0 to use the defaults
# - any positive integer to limit the chunk size, in MiB
# dxvk.maxChunkSize = 0
# Controls graphics pipeline library behaviour
#
# Can be used to change VK_EXT_graphics_pipeline_library usage for
@ -379,6 +466,21 @@
# dxvk.trackPipelineLifetime = Auto
# Controls memory defragmentation
#
# By default, DXVK will try to defragment video memory if there is a
# significant amount of memory wasted, or if the allocation budget of
# the application is exceeded. This option is provided solely for
# debug purposes.
#
# Supported values:
# - True: Enable defragmentation
# - Auto: Enable defragmentation, except on blocked drivers
# - False: Disable defragmentation
# dxvk.enableMemoryDefrag = Auto
# Sets enabled HUD elements
#
# Behaves like the DXVK_HUD environment variable if the
@ -394,6 +496,7 @@
# capabilities that the applicatation queries.
#
# Supported values:
# - 0: Fixed-function only
# - 1: Shader Model 1
# - 2: Shader Model 2
# - 3: Shader Model 3
@ -473,16 +576,6 @@
# d3d9.floatEmulation = Auto
# Enable dialog box mode
#
# Changes the default state of dialog box mode.
# *Disables* exclusive fullscreen when enabled.
#
# Supported values:
# - True, False: Always enable / disable
# d3d9.enableDialogMode = False
# Overrides the application's MSAA level on the swapchain
#
# Supported values: -1 (application) and 0 to 16 (user override)
@ -490,17 +583,6 @@
# d3d9.forceSwapchainMSAA = -1
# Long Mad
#
# Should we make our Mads a FFma or do it the long way with an FMul and an FAdd?
# This solves some rendering bugs in games that have z-pass shaders which
# don't match entirely to the regular vertex shader in this way.
#
# Supported values:
# - True/False
# d3d9.longMad = False
# Device Local Constant Buffers
#
# Enables using device local, host accessible memory for constant buffers in D3D9.
@ -514,7 +596,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
@ -540,14 +624,16 @@
# d3d9.supportX4R4G4B4 = True
# Support D32
# Support D16_LOCKABLE
#
# Support the D32 format.
# Support the D16_LOCKABLE format.
# Always enabled on AMD, or when spoofing an AMD GPU
# via customVendorId, disabled by default on Nvidia and Intel.
#
# Supported values:
# - True/False
# d3d9.supportD32 = True
# d3d9.supportD16Lockable = False
# Disable A8 as a Render Target
#
@ -644,18 +730,6 @@
# d3d9.textureMemory = 100
# Always enumerate all monitors on each dxgi output
#
# Used to avoid performance degradation in some games
# (will be deprecated once QueryDisplayConfig optimization
# is in Proton Wine).
#
# Supported values:
# - True/False
# dxgi.useMonitorFallback = False
# Hide integrated graphics from applications
#
# Only has an effect when dedicated GPUs are present on the system. It is

View file

@ -0,0 +1,20 @@
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_sdl3.h',
'wsi/native_sdl2.h',
'wsi/native_glfw.h',
subdir: 'dxvk/wsi',
)

View file

@ -287,6 +287,8 @@ typedef struct RGNDATA {
#define DXGI_ERROR_NAME_ALREADY_EXISTS ((HRESULT)0x887A002C)
#define DXGI_ERROR_SDK_COMPONENT_MISSING ((HRESULT)0x887A002D)
#define D3D11_ERROR_DEFERRED_CONTEXT_MAP_WITHOUT_INITIAL_DISCARD ((HRESULT)0x887C0004)
#define WINAPI
#define WINUSERAPI

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

View file

@ -0,0 +1,25 @@
#include <windows.h>
#include <SDL3/SDL.h>
namespace dxvk::wsi {
inline SDL_Window* fromHwnd(HWND hWindow) {
return reinterpret_cast<SDL_Window*>(hWindow);
}
inline HWND toHwnd(SDL_Window* pWindow) {
return reinterpret_cast<HWND>(pWindow);
}
// Offset so null HMONITORs go to -1
inline SDL_DisplayID fromHmonitor(HMONITOR hMonitor) {
return SDL_DisplayID(reinterpret_cast<uintptr_t>(hMonitor));
}
// Offset so -1 display id goes to 0 == NULL
inline HMONITOR toHmonitor(SDL_DisplayID display) {
return reinterpret_cast<HMONITOR>(uintptr_t(display));
}
}

View file

@ -2,6 +2,8 @@
#ifdef DXVK_WSI_WIN32
#error You shouldnt be using this code path.
#elif DXVK_WSI_SDL3
#include "wsi/native_sdl3.h"
#elif DXVK_WSI_SDL2
#include "wsi/native_sdl2.h"
#elif DXVK_WSI_GLFW

@ -1 +1 @@
Subproject commit 46dc0f6e514f5730784bb2cac2a7c731636839e8
Subproject commit 234c4b7370a8ea3239a214c9e871e4b17c89f4ab

View file

@ -1,5 +1,6 @@
project('dxvk', ['c', 'cpp'], version : 'v2.3.1', meson_version : '>= 0.58', default_options : [ 'cpp_std=c++17', 'warning_level=2' ])
project('dxvk', ['c', 'cpp'], version : '2.5.3', meson_version : '>= 0.58', default_options : [ 'cpp_std=c++17', 'b_vscrt=static_from_buildtype', 'warning_level=2' ])
pkg = import('pkgconfig')
cpu_family = target_machine.cpu_family()
platform = target_machine.system()
fs = import('fs')
@ -17,6 +18,7 @@ compiler_args = [
# gcc
'-Wno-missing-field-initializers',
'-Wno-unused-parameter',
'-Wno-misleading-indentation',
'-Wno-cast-function-type', # Needed for GetProcAddress.
# clang
'-Wno-unused-private-field',
@ -54,6 +56,8 @@ dep_displayinfo = dependency(
)
if platform == 'windows'
dxvk_so_version = {'name_prefix': ''}
compiler_args += [
'-DNOMINMAX',
'-D_WIN32_WINNT=0xa00',
@ -76,16 +80,26 @@ if platform == 'windows'
]
endif
# Enable stdcall fixup on 32-bit
if cpu_family == 'x86'
# Enable stdcall fixup on 32-bit
link_args += [
'-Wl,--enable-stdcall-fixup',
'-Wl,--kill-at',
]
# Fix stack alignment issues with mingw on 32-bit
compiler_args += [
'-mpreferred-stack-boundary=2'
]
endif
else
# setup file alignment + enable PDB output for MSVC builds
# PDBs are useful for Windows consumers of DXVK
compiler_args += [
'/Z7'
]
link_args += [
'/FILEALIGN:4096',
'/DEBUG:FULL'
]
endif
@ -93,12 +107,6 @@ if platform == 'windows'
lib_d3d11 = cpp.find_library('d3d11')
lib_dxgi = cpp.find_library('dxgi')
if dxvk_is_msvc
lib_d3dcompiler_47 = cpp.find_library('d3dcompiler')
else
lib_d3dcompiler_47 = cpp.find_library('d3dcompiler_47')
endif
if dxvk_is_msvc
res_ext = '.res'
wrc = find_program('rc')
@ -115,10 +123,21 @@ if platform == 'windows'
)
endif
dxvk_wsi = 'win32'
dxvk_name_prefix = ''
compiler_args += ['-DDXVK_WSI_WIN32']
else
dxvk_abi_version = '0'
dxvk_version_raw = meson.project_version().strip('v').split('.')
dxvk_version = [ dxvk_version_raw[0] ]
foreach i : [ 1, 2 ]
padded = dxvk_version_raw[i]
if padded.to_int() < 10
padded = '0' + padded
endif
dxvk_version += [ padded ]
endforeach
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@' ] )
@ -128,17 +147,24 @@ else
'./include/native/directx'
]
dxvk_wsi = get_option('dxvk_native_wsi')
if dxvk_wsi == 'sdl2'
lib_sdl2 = cpp.find_library('SDL2')
lib_sdl3 = dependency('SDL3', required: false)
lib_sdl2 = dependency('SDL2', required: false)
lib_glfw = dependency('glfw', required: false)
if lib_sdl3.found()
compiler_args += ['-DDXVK_WSI_SDL3']
endif
if lib_sdl2.found()
compiler_args += ['-DDXVK_WSI_SDL2']
elif dxvk_wsi == 'glfw'
lib_glfw = cpp.find_library('glfw')
endif
if lib_glfw.found()
compiler_args += ['-DDXVK_WSI_GLFW']
endif
if (not lib_sdl3.found() and not lib_sdl2.found() and not lib_glfw.found())
error('SDL3, SDL2, or GLFW are required to build dxvk-native')
endif
dxvk_name_prefix = 'libdxvk_'
dxvk_name_prefix = 'dxvk_'
dxvk_pkg_prefix = 'dxvk-'
link_args += [
'-static-libgcc',
@ -154,13 +180,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@',
@ -179,4 +204,18 @@ dxvk_version = vcs_tag(
output: 'version.h',
)
conf_data = configuration_data()
conf_data.set('BUILD_COMPILER', cpp.get_id())
conf_data.set('BUILD_COMPILER_VERSION', cpp.version())
conf_data.set('BUILD_TARGET', cpu_family)
dxvk_buildenv = configure_file(
configuration : conf_data,
input: 'buildenv.h.in',
output: 'buildenv.h',
)
if platform != 'windows'
subdir('include/native')
endif
subdir('src')

View file

@ -1,4 +1,5 @@
option('enable_dxgi', type : 'boolean', value : true, description: 'Build DXGI')
option('enable_d3d8', type : 'boolean', value : true, description: 'Build D3D8')
option('enable_d3d9', type : 'boolean', value : true, description: 'Build D3D9')
option('enable_d3d10', type : 'boolean', value : true, description: 'Build D3D10')
option('enable_d3d11', type : 'boolean', value : true, description: 'Build D3D11')

View file

@ -25,6 +25,8 @@ shift 2
opt_nopackage=0
opt_devbuild=0
opt_buildid=false
opt_64_only=0
opt_32_only=0
CC=${CC:="gcc"}
CXX=${CXX:="g++"}
@ -41,6 +43,12 @@ while [ $# -gt 0 ]; do
"--build-id")
opt_buildid=true
;;
"--64-only")
opt_64_only=1
;;
"--32-only")
opt_32_only=1
;;
*)
echo "Unrecognized option: $1" >&2
exit 1
@ -81,8 +89,12 @@ function package {
rm -R "dxvk-native-$DXVK_VERSION"
}
build_arch 64 lib
build_arch 32 lib32
if [ $opt_32_only -eq 0 ]; then
build_arch 64 lib
fi
if [ $opt_64_only -eq 0 ]; then
build_arch 32 lib32
fi
if [ $opt_nopackage -eq 0 ]; then
package

View file

@ -25,6 +25,8 @@ shift 2
opt_nopackage=0
opt_devbuild=0
opt_buildid=false
opt_64_only=0
opt_32_only=0
crossfile="build-win"
@ -40,6 +42,12 @@ while [ $# -gt 0 ]; do
"--build-id")
opt_buildid=true
;;
"--64-only")
opt_64_only=1
;;
"--32-only")
opt_32_only=1
;;
*)
echo "Unrecognized option: $1" >&2
exit 1
@ -64,6 +72,7 @@ function build_arch {
$opt_strip \
--bindir "x$1" \
--libdir "x$1" \
-Db_ndebug=if-release \
-Dbuild_id=$opt_buildid \
"$DXVK_BUILD_DIR/build.$1"
@ -83,8 +92,12 @@ function package {
rm -R "dxvk-$DXVK_VERSION"
}
build_arch 64
build_arch 32
if [ $opt_32_only -eq 0 ]; then
build_arch 64
fi
if [ $opt_64_only -eq 0 ]; then
build_arch 32
fi
if [ $opt_nopackage -eq 0 ]; then
package

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

@ -37,8 +37,8 @@ namespace dxvk {
D3D11UserDefinedAnnotation<ContextType>::D3D11UserDefinedAnnotation(
ContextType* container,
const Rc<DxvkDevice>& dxvkDevice)
: m_container(container), m_eventDepth(0),
m_annotationsEnabled(dxvkDevice->instance()->extensions().extDebugUtils) {
: m_container(container),
m_annotationsEnabled(dxvkDevice->debugFlags().test(DxvkDebugFlag::Markers)) {
if (!IsDeferred && m_annotationsEnabled)
RegisterUserDefinedAnnotation<true>(this);
}
@ -75,19 +75,16 @@ namespace dxvk {
INT STDMETHODCALLTYPE D3D11UserDefinedAnnotation<ContextType>::BeginEvent(
D3DCOLOR Color,
LPCWSTR Name) {
if (!m_annotationsEnabled)
if (!m_annotationsEnabled || !Name)
return -1;
D3D10DeviceLock lock = m_container->LockContext();
m_container->EmitCs([color = Color, labelName = dxvk::str::fromws(Name)](DxvkContext *ctx) {
VkDebugUtilsLabelEXT label;
label.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT;
label.pNext = nullptr;
label.pLabelName = labelName.c_str();
DecodeD3DCOLOR(color, label.color);
ctx->beginDebugLabel(&label);
m_container->EmitCs([
cColor = Color,
cLabel = dxvk::str::fromws(Name)
] (DxvkContext* ctx) {
ctx->beginDebugLabel(vk::makeLabel(cColor, cLabel.c_str()));
});
return m_eventDepth++;
@ -101,11 +98,14 @@ namespace dxvk {
D3D10DeviceLock lock = m_container->LockContext();
m_container->EmitCs([](DxvkContext *ctx) {
if (!m_eventDepth)
return 0;
m_container->EmitCs([] (DxvkContext* ctx) {
ctx->endDebugLabel();
});
return m_eventDepth--;
return --m_eventDepth;
}
@ -113,19 +113,16 @@ namespace dxvk {
void STDMETHODCALLTYPE D3D11UserDefinedAnnotation<ContextType>::SetMarker(
D3DCOLOR Color,
LPCWSTR Name) {
if (!m_annotationsEnabled)
if (!m_annotationsEnabled || !Name)
return;
D3D10DeviceLock lock = m_container->LockContext();
m_container->EmitCs([color = Color, labelName = dxvk::str::fromws(Name)](DxvkContext *ctx) {
VkDebugUtilsLabelEXT label;
label.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT;
label.pNext = nullptr;
label.pLabelName = labelName.c_str();
DecodeD3DCOLOR(color, label.color);
ctx->insertDebugLabel(&label);
m_container->EmitCs([
cColor = Color,
cLabel = dxvk::str::fromws(Name)
] (DxvkContext* ctx) {
ctx->insertDebugLabel(vk::makeLabel(cColor, cLabel.c_str()));
});
}

View file

@ -48,9 +48,10 @@ namespace dxvk {
private:
ContextType* m_container;
int32_t m_eventDepth;
bool m_annotationsEnabled;
ContextType* m_container = nullptr;
int32_t m_eventDepth = 0u;
bool m_annotationsEnabled = false;
};
}

View file

@ -1,9 +1,8 @@
#include "d3d11_buffer.h"
#include "d3d11_context.h"
#include "d3d11_context_imm.h"
#include "d3d11_device.h"
#include "../dxvk/dxvk_data.h"
namespace dxvk {
D3D11Buffer::D3D11Buffer(
@ -84,6 +83,10 @@ namespace dxvk {
info.access |= VK_ACCESS_HOST_WRITE_BIT;
}
// Always enable BDA usage if available so that CUDA interop can work
if (m_parent->GetDXVKDevice()->features().vk12.bufferDeviceAddress)
info.usage |= VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT;
if (p11on12Info) {
m_11on12 = *p11on12Info;
@ -95,21 +98,24 @@ namespace dxvk {
m_11on12.Resource->Map(0, nullptr, &importInfo.mapPtr);
m_buffer = m_parent->GetDXVKDevice()->importBuffer(info, importInfo, GetMemoryFlags());
m_mapped = m_buffer->getSliceHandle();
m_mapMode = DetermineMapMode();
m_cookie = m_buffer->cookie();
m_mapPtr = m_buffer->mapPtr(0);
m_mapMode = DetermineMapMode(m_buffer->memFlags());
} else if (!(pDesc->MiscFlags & D3D11_RESOURCE_MISC_TILE_POOL)) {
VkMemoryPropertyFlags memoryFlags = GetMemoryFlags();
m_mapMode = DetermineMapMode(memoryFlags);
// Create the buffer and set the entire buffer slice as mapped,
// so that we only have to update it when invalidating the buffer
m_buffer = m_parent->GetDXVKDevice()->createBuffer(info, GetMemoryFlags());
m_mapped = m_buffer->getSliceHandle();
m_mapMode = DetermineMapMode();
m_buffer = m_parent->GetDXVKDevice()->createBuffer(info, memoryFlags);
m_cookie = m_buffer->cookie();
m_mapPtr = m_buffer->mapPtr(0);
} else {
m_sparseAllocator = m_parent->GetDXVKDevice()->createSparsePageAllocator();
m_sparseAllocator->setCapacity(info.size / SparseMemoryPageSize);
m_mapped = DxvkBufferSliceHandle();
m_cookie = 0u;
m_mapPtr = nullptr;
m_mapMode = D3D11_COMMON_BUFFER_MAP_MODE_NONE;
}
@ -206,6 +212,18 @@ namespace dxvk {
}
void D3D11Buffer::SetDebugName(const char* pName) {
if (m_buffer) {
m_parent->GetContext()->InjectCs(DxvkCsQueue::HighPriority, [
cBuffer = m_buffer,
cName = std::string(pName ? pName : "")
] (DxvkContext* ctx) {
ctx->setDebugName(cBuffer, cName.c_str());
});
}
}
HRESULT D3D11Buffer::NormalizeBufferProperties(D3D11_BUFFER_DESC* pDesc) {
// Zero-sized buffers are illegal
if (!pDesc->ByteWidth && !(pDesc->MiscFlags & D3D11_RESOURCE_MISC_TILE_POOL))
@ -365,12 +383,14 @@ namespace dxvk {
| VK_ACCESS_INDIRECT_COMMAND_READ_BIT
| VK_ACCESS_TRANSFORM_FEEDBACK_COUNTER_READ_BIT_EXT
| VK_ACCESS_TRANSFORM_FEEDBACK_COUNTER_WRITE_BIT_EXT;
info.debugName = "SO counter";
return device->createBuffer(info, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
}
D3D11_COMMON_BUFFER_MAP_MODE D3D11Buffer::DetermineMapMode() {
return (m_buffer->memFlags() & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT)
D3D11_COMMON_BUFFER_MAP_MODE D3D11Buffer::DetermineMapMode(VkMemoryPropertyFlags MemFlags) {
return (MemFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT)
? D3D11_COMMON_BUFFER_MAP_MODE_DIRECT
: D3D11_COMMON_BUFFER_MAP_MODE_NONE;
}

View file

@ -61,6 +61,8 @@ namespace dxvk {
void STDMETHODCALLTYPE GetDesc(
D3D11_BUFFER_DESC *pDesc) final;
void STDMETHODCALLTYPE SetDebugName(const char* pName) final;
bool CheckViewCompatibility(
UINT BindFlags,
DXGI_FORMAT Format) const;
@ -77,6 +79,10 @@ namespace dxvk {
return m_mapMode;
}
uint64_t GetCookie() const {
return m_cookie;
}
Rc<DxvkBuffer> GetBuffer() const {
return m_buffer;
}
@ -113,17 +119,18 @@ namespace dxvk {
: DxvkBufferSlice();
}
DxvkBufferSliceHandle AllocSlice() {
return m_buffer->allocSlice();
Rc<DxvkResourceAllocation> AllocSlice(DxvkLocalAllocationCache* cache) {
return m_buffer->allocateStorage(cache);
}
DxvkBufferSliceHandle DiscardSlice() {
m_mapped = m_buffer->allocSlice();
return m_mapped;
Rc<DxvkResourceAllocation> DiscardSlice(DxvkLocalAllocationCache* cache) {
auto allocation = m_buffer->allocateStorage(cache);
m_mapPtr = allocation->mapPtr();
return allocation;
}
DxvkBufferSliceHandle GetMappedSlice() const {
return m_mapped;
void* GetMapPtr() const {
return m_mapPtr;
}
D3D10Buffer* GetD3D10Iface() {
@ -182,11 +189,14 @@ namespace dxvk {
D3D11_COMMON_BUFFER_MAP_MODE m_mapMode;
Rc<DxvkBuffer> m_buffer;
uint64_t m_cookie = 0u;
Rc<DxvkBuffer> m_soCounter;
Rc<DxvkSparsePageAllocator> m_sparseAllocator;
DxvkBufferSliceHandle m_mapped;
uint64_t m_seq = 0ull;
void* m_mapPtr = nullptr;
D3D11DXGIResource m_resource;
D3D10Buffer m_d3d10;
@ -198,7 +208,8 @@ namespace dxvk {
Rc<DxvkBuffer> CreateSoCounterBuffer();
D3D11_COMMON_BUFFER_MAP_MODE DetermineMapMode();
static D3D11_COMMON_BUFFER_MAP_MODE DetermineMapMode(
VkMemoryPropertyFlags MemFlags);
};

View file

@ -10,20 +10,12 @@ namespace dxvk {
* Used to identify the type of command
* data most recently added to a CS chunk.
*/
enum class D3D11CmdType {
enum class D3D11CmdType : uint32_t {
None,
DrawIndirect,
DrawIndirectIndexed,
};
/**
* \brief Command data header
*
* Stores the command type. All command
* data structs must inherit this struct.
*/
struct D3D11CmdData {
D3D11CmdType type;
Draw,
DrawIndexed,
};
@ -34,10 +26,10 @@ namespace dxvk {
* the first draw, as well as the number of
* draws to execute.
*/
struct D3D11CmdDrawIndirectData : public D3D11CmdData {
struct D3D11CmdDrawIndirectData {
uint32_t offset;
uint32_t count;
uint32_t stride;
};
}
}

View file

@ -74,8 +74,6 @@ namespace dxvk {
m_resources.push_back(std::move(entry));
}
pCommandList->MarkSubmitted();
// Return ID of the last chunk added. The command list
// added can never be empty, so do not handle zero.
return m_chunks.size() - 1;
@ -102,8 +100,6 @@ namespace dxvk {
while (j < m_resources.size() && m_resources[j].chunkId == i)
TrackResourceSequenceNumber(m_resources[j++].ref, seq);
}
MarkSubmitted();
}
@ -150,15 +146,5 @@ namespace dxvk {
} break;
}
}
void D3D11CommandList::MarkSubmitted() {
if (m_submitted.exchange(true) && !m_warned.exchange(true)
&& m_parent->GetOptions()->dcSingleUseMode) {
Logger::warn(
"D3D11: Command list submitted multiple times,\n"
" but d3d11.dcSingleUseMode is enabled");
}
}
}

View file

@ -55,14 +55,9 @@ namespace dxvk {
std::vector<Com<D3D11Query, false>> m_queries;
std::vector<TrackedResource> m_resources;
std::atomic<bool> m_submitted = { false };
std::atomic<bool> m_warned = { false };
void TrackResourceSequenceNumber(
const D3D11ResourceRef& Resource,
uint64_t Seq);
void MarkSubmitted();
};

File diff suppressed because it is too large Load diff

View file

@ -72,7 +72,14 @@ namespace dxvk {
template<typename T> friend class D3D11DeviceContextExt;
template<typename T> friend class D3D11UserDefinedAnnotation;
constexpr static VkDeviceSize StagingBufferSize = 4ull << 20;
// Use a local staging buffer to handle tiny uploads, most
// of the time we're fine with hitting the global allocator
constexpr static VkDeviceSize StagingBufferSize = 256ull << 10;
protected:
// Compile-time debug flag to force lazy binding on (True) or off (False)
constexpr static Tristate DebugLazyBinding = Tristate::Auto;
public:
D3D11CommonContext(
@ -102,6 +109,11 @@ namespace dxvk {
const D3D11_RECT* pRects,
UINT NumRects);
void STDMETHODCALLTYPE DiscardViewBase(
ID3D11View* pResourceView,
const D3D11_RECT* pRects,
UINT NumRects);
void STDMETHODCALLTYPE CopySubresourceRegion(
ID3D11Resource* pDstResource,
UINT DstSubresource,
@ -123,6 +135,17 @@ namespace dxvk {
const D3D11_BOX* pSrcBox,
UINT CopyFlags);
void STDMETHODCALLTYPE CopySubresourceRegionBase(
ID3D11Resource* pDstResource,
UINT DstSubresource,
UINT DstX,
UINT DstY,
UINT DstZ,
ID3D11Resource* pSrcResource,
UINT SrcSubresource,
const D3D11_BOX* pSrcBox,
UINT CopyFlags);
void STDMETHODCALLTYPE CopyResource(
ID3D11Resource* pDstResource,
ID3D11Resource* pSrcResource);
@ -769,19 +792,44 @@ namespace dxvk {
UINT m_flags;
DxvkStagingBuffer m_staging;
Rc<DxvkDataBuffer> m_updateBuffer;
D3D11CmdType m_csDataType = D3D11CmdType::None;
DxvkCsChunkFlags m_csFlags;
DxvkCsChunkRef m_csChunk;
D3D11CmdData* m_cmdData;
DxvkCsDataBlock* m_csData = nullptr;
DxvkLocalAllocationCache m_allocationCache;
DxvkCsChunkRef AllocCsChunk();
DxvkDataSlice AllocUpdateBufferSlice(size_t Size);
DxvkBufferSlice AllocStagingBuffer(
VkDeviceSize Size);
void ApplyDirtyConstantBuffers(
DxbcProgramType Stage,
const DxbcBindingMask& BoundMask,
DxbcBindingMask& DirtyMask);
void ApplyDirtySamplers(
DxbcProgramType Stage,
const DxbcBindingMask& BoundMask,
DxbcBindingMask& DirtyMask);
void ApplyDirtyShaderResources(
DxbcProgramType Stage,
const DxbcBindingMask& BoundMask,
DxbcBindingMask& DirtyMask);
void ApplyDirtyUnorderedAccessViews(
DxbcProgramType Stage,
const DxbcBindingMask& BoundMask,
DxbcBindingMask& DirtyMask);
void ApplyDirtyGraphicsBindings();
void ApplyDirtyComputeBindings();
void ApplyInputLayout();
void ApplyPrimitiveTopology();
@ -800,6 +848,12 @@ namespace dxvk {
void ApplyViewportState();
void BatchDraw(
const VkDrawIndirectCommand& draw);
void BatchDrawIndexed(
const VkDrawIndexedIndirectCommand& draw);
template<DxbcProgramType ShaderStage>
void BindShader(
const D3D11CommonShader* pShaderModule);
@ -837,35 +891,33 @@ namespace dxvk {
D3D11Buffer* pBuffer,
UINT Offset);
template<DxbcProgramType ShaderStage>
void BindConstantBuffer(
DxbcProgramType ShaderStage,
UINT Slot,
D3D11Buffer* pBuffer,
UINT Offset,
UINT Length);
template<DxbcProgramType ShaderStage>
void BindConstantBufferRange(
DxbcProgramType ShaderStage,
UINT Slot,
UINT Offset,
UINT Length);
template<DxbcProgramType ShaderStage>
void BindSampler(
DxbcProgramType ShaderStage,
UINT Slot,
D3D11SamplerState* pSampler);
template<DxbcProgramType ShaderStage>
void BindShaderResource(
DxbcProgramType ShaderStage,
UINT Slot,
D3D11ShaderResourceView* pResource);
template<DxbcProgramType ShaderStage>
void BindUnorderedAccessView(
UINT UavSlot,
D3D11UnorderedAccessView* pUav,
UINT CtrSlot,
UINT Counter);
DxbcProgramType ShaderStage,
UINT Slot,
D3D11UnorderedAccessView* pUav);
VkClearValue ConvertColorValue(
const FLOAT Color[4],
@ -894,6 +946,36 @@ namespace dxvk {
DxvkBufferSlice BufferSlice,
UINT Flags);
template<typename T>
bool DirtyBindingGeneric(
DxbcProgramType ShaderStage,
T BoundMask,
T& DirtyMask,
T DirtyBit,
bool IsNull);
bool DirtyConstantBuffer(
DxbcProgramType ShaderStage,
uint32_t Slot,
bool IsNull);
bool DirtySampler(
DxbcProgramType ShaderStage,
uint32_t Slot,
bool IsNull);
bool DirtyShaderResource(
DxbcProgramType ShaderStage,
uint32_t Slot,
bool IsNull);
bool DirtyComputeUnorderedAccessView(
uint32_t Slot,
bool IsNull);
bool DirtyGraphicsUnorderedAccessView(
uint32_t Slot);
void DiscardBuffer(
ID3D11Resource* pResource);
@ -926,10 +1008,16 @@ namespace dxvk {
D3D11MaxUsedBindings GetMaxUsedBindings();
bool HasDirtyComputeBindings();
bool HasDirtyGraphicsBindings();
void ResetCommandListState();
void ResetContextState();
void ResetDirtyTracking();
void ResetStagingBuffer();
template<DxbcProgramType ShaderStage, typename T>
@ -952,18 +1040,18 @@ namespace dxvk {
void RestoreCommandListState();
template<DxbcProgramType Stage>
void RestoreConstantBuffers();
template<DxbcProgramType Stage>
void RestoreSamplers();
template<DxbcProgramType Stage>
void RestoreShaderResources();
template<DxbcProgramType Stage>
void RestoreUnorderedAccessViews();
void RestoreConstantBuffers(
DxbcProgramType Stage);
void RestoreSamplers(
DxbcProgramType Stage);
void RestoreShaderResources(
DxbcProgramType Stage);
void RestoreUnorderedAccessViews(
DxbcProgramType Stage);
template<DxbcProgramType ShaderStage>
void SetConstantBuffers(
UINT StartSlot,
@ -1046,6 +1134,10 @@ namespace dxvk {
UINT SrcDepthPitch,
UINT CopyFlags);
void UpdateUnorderedAccessViewCounter(
D3D11UnorderedAccessView* pUav,
uint32_t CounterValue);
bool ValidateRenderTargets(
UINT NumViews,
ID3D11RenderTargetView* const* ppRenderTargetViews,
@ -1066,48 +1158,49 @@ namespace dxvk {
DxvkMultisampleState* pMsState,
UINT SampleMask);
template<bool AllowFlush = !IsDeferred, typename Cmd>
template<bool AllowFlush = true, typename Cmd>
void EmitCs(Cmd&& command) {
m_cmdData = nullptr;
if (unlikely(m_csDataType != D3D11CmdType::None)) {
m_csData = nullptr;
m_csDataType = D3D11CmdType::None;
}
if (unlikely(!m_csChunk->push(command))) {
GetTypedContext()->EmitCsChunk(std::move(m_csChunk));
m_csChunk = AllocCsChunk();
if constexpr (AllowFlush)
if constexpr (!IsDeferred && AllowFlush)
GetTypedContext()->ConsiderFlush(GpuFlushType::ImplicitWeakHint);
m_csChunk->push(command);
}
}
template<typename M, bool AllowFlush = !IsDeferred, typename Cmd, typename... Args>
M* EmitCsCmd(Cmd&& command, Args&&... args) {
M* data = m_csChunk->pushCmd<M, Cmd, Args...>(
command, std::forward<Args>(args)...);
template<typename M, bool AllowFlush = true, typename Cmd>
void EmitCsCmd(D3D11CmdType type, size_t count, Cmd&& command) {
m_csDataType = type;
m_csData = m_csChunk->pushCmd<M, Cmd>(command, count);
if (unlikely(!data)) {
if (unlikely(!m_csData)) {
GetTypedContext()->EmitCsChunk(std::move(m_csChunk));
m_csChunk = AllocCsChunk();
if constexpr (AllowFlush)
if constexpr (!IsDeferred && AllowFlush)
GetTypedContext()->ConsiderFlush(GpuFlushType::ImplicitWeakHint);
// We must record this command after the potential
// flush since the caller may still access the data
data = m_csChunk->pushCmd<M, Cmd, Args...>(
command, std::forward<Args>(args)...);
m_csData = m_csChunk->pushCmd<M, Cmd>(command, count);
}
m_cmdData = data;
return data;
}
void FlushCsChunk() {
if (likely(!m_csChunk->empty())) {
m_csData = nullptr;
m_csDataType = D3D11CmdType::None;
GetTypedContext()->EmitCsChunk(std::move(m_csChunk));
m_csChunk = AllocCsChunk();
m_cmdData = nullptr;
}
}

View file

@ -7,7 +7,7 @@ namespace dxvk {
D3D11Device* pParent,
const Rc<DxvkDevice>& Device,
UINT ContextFlags)
: D3D11CommonContext<D3D11DeferredContext>(pParent, Device, ContextFlags, GetCsChunkFlags(pParent)),
: D3D11CommonContext<D3D11DeferredContext>(pParent, Device, ContextFlags, 0u),
m_commandList (CreateCommandList()) {
ResetContextState();
}
@ -206,39 +206,37 @@ namespace dxvk {
if (unlikely(!pResource || !pMappedResource))
return E_INVALIDARG;
if (MapType == D3D11_MAP_WRITE_DISCARD) {
if (likely(MapType == D3D11_MAP_WRITE_DISCARD)) {
D3D11_RESOURCE_DIMENSION resourceDim;
pResource->GetType(&resourceDim);
D3D11_MAPPED_SUBRESOURCE mapInfo;
HRESULT status = resourceDim == D3D11_RESOURCE_DIMENSION_BUFFER
? MapBuffer(pResource, &mapInfo)
: MapImage (pResource, Subresource, &mapInfo);
if (unlikely(FAILED(status))) {
*pMappedResource = D3D11_MAPPED_SUBRESOURCE();
return status;
}
AddMapEntry(pResource, Subresource, resourceDim, mapInfo);
*pMappedResource = mapInfo;
return S_OK;
} else if (MapType == D3D11_MAP_WRITE_NO_OVERWRITE) {
return likely(resourceDim == D3D11_RESOURCE_DIMENSION_BUFFER)
? MapBuffer(pResource, pMappedResource)
: MapImage(pResource, Subresource, pMappedResource);
} else if (likely(MapType == D3D11_MAP_WRITE_NO_OVERWRITE)) {
// The resource must be mapped with D3D11_MAP_WRITE_DISCARD
// before it can be mapped with D3D11_MAP_WRITE_NO_OVERWRITE.
auto entry = FindMapEntry(pResource, Subresource);
if (unlikely(!entry)) {
*pMappedResource = D3D11_MAPPED_SUBRESOURCE();
D3D11_RESOURCE_DIMENSION resourceDim;
pResource->GetType(&resourceDim);
if (likely(resourceDim == D3D11_RESOURCE_DIMENSION_BUFFER)) {
D3D11_MAPPED_SUBRESOURCE sr = FindMapEntry(static_cast<D3D11Buffer*>(pResource)->GetCookie());
pMappedResource->pData = sr.pData;
if (unlikely(!sr.pData))
return D3D11_ERROR_DEFERRED_CONTEXT_MAP_WITHOUT_INITIAL_DISCARD;
pMappedResource->RowPitch = sr.RowPitch;
pMappedResource->DepthPitch = sr.DepthPitch;
return S_OK;
} else {
// Images cannot be mapped with NO_OVERWRITE
pMappedResource->pData = nullptr;
return E_INVALIDARG;
}
// Return same memory region as earlier
*pMappedResource = entry->MapInfo;
return S_OK;
} else {
// Not allowed on deferred contexts
*pMappedResource = D3D11_MAPPED_SUBRESOURCE();
pMappedResource->pData = nullptr;
return E_INVALIDARG;
}
}
@ -265,44 +263,26 @@ namespace dxvk {
ID3D11Resource* pResource,
D3D11_MAPPED_SUBRESOURCE* pMappedResource) {
D3D11Buffer* pBuffer = static_cast<D3D11Buffer*>(pResource);
if (unlikely(pBuffer->GetMapMode() == D3D11_COMMON_BUFFER_MAP_MODE_NONE)) {
Logger::err("D3D11: Cannot map a device-local buffer");
pMappedResource->pData = nullptr;
return E_INVALIDARG;
}
auto bufferSlice = pBuffer->AllocSlice(&m_allocationCache);
pMappedResource->pData = bufferSlice->mapPtr();
pMappedResource->RowPitch = pBuffer->Desc()->ByteWidth;
pMappedResource->DepthPitch = pBuffer->Desc()->ByteWidth;
if (likely(m_csFlags.test(DxvkCsChunkFlag::SingleUse))) {
// For resources that cannot be written by the GPU,
// we may write to the buffer resource directly and
// just swap in the buffer slice as needed.
auto bufferSlice = pBuffer->AllocSlice();
pMappedResource->pData = bufferSlice.mapPtr;
EmitCs([
cDstBuffer = pBuffer->GetBuffer(),
cPhysSlice = bufferSlice
] (DxvkContext* ctx) {
ctx->invalidateBuffer(cDstBuffer, cPhysSlice);
});
} else {
// For GPU-writable resources, we need a data slice
// to perform the update operation at execution time.
auto dataSlice = AllocUpdateBufferSlice(pBuffer->Desc()->ByteWidth);
pMappedResource->pData = dataSlice.ptr();
EmitCs([
cDstBuffer = pBuffer->GetBuffer(),
cDstSlice = std::move(bufferSlice)
] (DxvkContext* ctx) {
ctx->invalidateBuffer(cDstBuffer, Rc<DxvkResourceAllocation>(cDstSlice));
});
EmitCs([
cDstBuffer = pBuffer->GetBuffer(),
cDataSlice = dataSlice
] (DxvkContext* ctx) {
DxvkBufferSliceHandle slice = cDstBuffer->allocSlice();
std::memcpy(slice.mapPtr, cDataSlice.ptr(), cDataSlice.length());
ctx->invalidateBuffer(cDstBuffer, slice);
});
}
AddMapEntry(pBuffer->GetCookie(), *pMappedResource);
return S_OK;
}
@ -313,33 +293,52 @@ namespace dxvk {
D3D11_MAPPED_SUBRESOURCE* pMappedResource) {
D3D11CommonTexture* pTexture = GetCommonTexture(pResource);
if (unlikely(pTexture->GetMapMode() == D3D11_COMMON_TEXTURE_MAP_MODE_NONE)) {
Logger::err("D3D11: Cannot map a device-local image");
if (unlikely(Subresource >= pTexture->CountSubresources())) {
pMappedResource->pData = nullptr;
return E_INVALIDARG;
}
if (unlikely(Subresource >= pTexture->CountSubresources()))
if (unlikely(pTexture->Desc()->Usage != D3D11_USAGE_DYNAMIC)) {
pMappedResource->pData = nullptr;
return E_INVALIDARG;
VkFormat packedFormat = pTexture->GetPackedFormat();
auto formatInfo = lookupFormatInfo(packedFormat);
auto subresource = pTexture->GetSubresourceFromIndex(
formatInfo->aspectMask, Subresource);
VkExtent3D levelExtent = pTexture->MipLevelExtent(subresource.mipLevel);
auto layout = pTexture->GetSubresourceLayout(formatInfo->aspectMask, Subresource);
auto dataSlice = AllocStagingBuffer(util::computeImageDataSize(packedFormat, levelExtent));
pMappedResource->RowPitch = layout.RowPitch;
pMappedResource->DepthPitch = layout.DepthPitch;
pMappedResource->pData = dataSlice.mapPtr(0);
}
UpdateImage(pTexture, &subresource,
VkOffset3D { 0, 0, 0 }, levelExtent,
std::move(dataSlice));
return S_OK;
VkFormat packedFormat = pTexture->GetPackedFormat();
auto formatInfo = lookupFormatInfo(packedFormat);
auto layout = pTexture->GetSubresourceLayout(formatInfo->aspectMask, Subresource);
if (pTexture->GetMapMode() == D3D11_COMMON_TEXTURE_MAP_MODE_DIRECT) {
auto storage = pTexture->AllocStorage();
auto mapPtr = storage->mapPtr();
EmitCs([
cImage = pTexture->GetImage(),
cStorage = std::move(storage)
] (DxvkContext* ctx) {
ctx->invalidateImage(cImage, Rc<DxvkResourceAllocation>(cStorage));
ctx->initImage(cImage, cImage->getAvailableSubresources(), VK_IMAGE_LAYOUT_PREINITIALIZED);
});
pMappedResource->RowPitch = layout.RowPitch;
pMappedResource->DepthPitch = layout.DepthPitch;
pMappedResource->pData = mapPtr;
return S_OK;
} else {
auto dataSlice = AllocStagingBuffer(layout.Size);
pMappedResource->RowPitch = layout.RowPitch;
pMappedResource->DepthPitch = layout.DepthPitch;
pMappedResource->pData = dataSlice.mapPtr(0);
auto subresource = pTexture->GetSubresourceFromIndex(formatInfo->aspectMask, Subresource);
auto mipExtent = pTexture->MipLevelExtent(subresource.mipLevel);
UpdateImage(pTexture, &subresource,
VkOffset3D { 0, 0, 0 }, mipExtent,
std::move(dataSlice));
return S_OK;
}
}
@ -351,19 +350,15 @@ namespace dxvk {
UINT CopyFlags) {
void* mapPtr = nullptr;
if (unlikely(CopyFlags == D3D11_COPY_NO_OVERWRITE)) {
auto entry = FindMapEntry(pDstBuffer, 0);
if (entry)
mapPtr = entry->MapInfo.pData;
}
if (unlikely(CopyFlags == D3D11_COPY_NO_OVERWRITE))
mapPtr = FindMapEntry(pDstBuffer->GetCookie()).pData;
if (likely(!mapPtr)) {
// The caller validates the map mode, so we can
// safely ignore the MapBuffer return value here
D3D11_MAPPED_SUBRESOURCE mapInfo;
MapBuffer(pDstBuffer, &mapInfo);
AddMapEntry(pDstBuffer, 0, D3D11_RESOURCE_DIMENSION_BUFFER, mapInfo);
AddMapEntry(pDstBuffer->GetCookie(), mapInfo);
mapPtr = mapInfo.pData;
}
@ -418,40 +413,27 @@ namespace dxvk {
}
D3D11DeferredContextMapEntry* D3D11DeferredContext::FindMapEntry(
ID3D11Resource* pResource,
UINT Subresource) {
D3D11_MAPPED_SUBRESOURCE D3D11DeferredContext::FindMapEntry(
uint64_t Cookie) {
// Recently mapped resources as well as entries with
// up-to-date map infos will be located at the end
// of the resource array, so scan in reverse order.
size_t size = m_mappedResources.size();
for (size_t i = 1; i <= size; i++) {
auto entry = &m_mappedResources[size - i];
const auto& entry = m_mappedResources[size - i];
if (entry->Resource.Get() == pResource
&& entry->Resource.GetSubresource() == Subresource)
return entry;
if (entry.ResourceCookie == Cookie)
return entry.MapInfo;
}
return nullptr;
return D3D11_MAPPED_SUBRESOURCE();
}
void D3D11DeferredContext::AddMapEntry(
ID3D11Resource* pResource,
UINT Subresource,
D3D11_RESOURCE_DIMENSION ResourceType,
uint64_t Cookie,
const D3D11_MAPPED_SUBRESOURCE& MapInfo) {
m_mappedResources.emplace_back(pResource,
Subresource, ResourceType, MapInfo);
m_mappedResources.push_back({ Cookie, MapInfo });
}
DxvkCsChunkFlags D3D11DeferredContext::GetCsChunkFlags(
D3D11Device* pDevice) {
return pDevice->GetOptions()->dcSingleUseMode
? DxvkCsChunkFlags(DxvkCsChunkFlag::SingleUse)
: DxvkCsChunkFlags();
}
}
}

View file

@ -8,17 +8,8 @@
namespace dxvk {
struct D3D11DeferredContextMapEntry {
D3D11DeferredContextMapEntry() { }
D3D11DeferredContextMapEntry(
ID3D11Resource* pResource,
UINT Subresource,
D3D11_RESOURCE_DIMENSION ResourceType,
const D3D11_MAPPED_SUBRESOURCE& MappedResource)
: Resource(pResource, Subresource, ResourceType),
MapInfo(MappedResource) { }
D3D11ResourceRef Resource;
D3D11_MAPPED_SUBRESOURCE MapInfo;
uint64_t ResourceCookie = 0u;
D3D11_MAPPED_SUBRESOURCE MapInfo = { };
};
class D3D11DeferredContext : public D3D11CommonContext<D3D11DeferredContext> {
@ -130,14 +121,11 @@ namespace dxvk {
void TrackBufferSequenceNumber(
D3D11Buffer* pResource);
D3D11DeferredContextMapEntry* FindMapEntry(
ID3D11Resource* pResource,
UINT Subresource);
D3D11_MAPPED_SUBRESOURCE FindMapEntry(
uint64_t Coookie);
void AddMapEntry(
ID3D11Resource* pResource,
UINT Subresource,
D3D11_RESOURCE_DIMENSION ResourceType,
uint64_t Cookie,
const D3D11_MAPPED_SUBRESOURCE& MapInfo);
static DxvkCsChunkFlags GetCsChunkFlags(

View file

@ -48,12 +48,15 @@ namespace dxvk {
D3D10DeviceLock lock = m_ctx->LockContext();
m_ctx->SetDrawBuffers(pBufferForArgs, nullptr);
if (unlikely(m_ctx->HasDirtyGraphicsBindings()))
m_ctx->ApplyDirtyGraphicsBindings();
m_ctx->EmitCs([
cCount = DrawCount,
cOffset = ByteOffsetForArgs,
cStride = ByteStrideForArgs
] (DxvkContext* ctx) {
ctx->drawIndirect(cOffset, cCount, cStride);
ctx->drawIndirect(cOffset, cCount, cStride, false);
});
}
@ -67,12 +70,15 @@ namespace dxvk {
D3D10DeviceLock lock = m_ctx->LockContext();
m_ctx->SetDrawBuffers(pBufferForArgs, nullptr);
if (unlikely(m_ctx->HasDirtyGraphicsBindings()))
m_ctx->ApplyDirtyGraphicsBindings();
m_ctx->EmitCs([
cCount = DrawCount,
cOffset = ByteOffsetForArgs,
cStride = ByteStrideForArgs
] (DxvkContext* ctx) {
ctx->drawIndexedIndirect(cOffset, cCount, cStride);
ctx->drawIndexedIndirect(cOffset, cCount, cStride, false);
});
}
@ -88,6 +94,9 @@ namespace dxvk {
D3D10DeviceLock lock = m_ctx->LockContext();
m_ctx->SetDrawBuffers(pBufferForArgs, pBufferForCount);
if (unlikely(m_ctx->HasDirtyGraphicsBindings()))
m_ctx->ApplyDirtyGraphicsBindings();
m_ctx->EmitCs([
cMaxCount = MaxDrawCount,
cArgOffset = ByteOffsetForArgs,
@ -110,6 +119,9 @@ namespace dxvk {
D3D10DeviceLock lock = m_ctx->LockContext();
m_ctx->SetDrawBuffers(pBufferForArgs, pBufferForCount);
if (unlikely(m_ctx->HasDirtyGraphicsBindings()))
m_ctx->ApplyDirtyGraphicsBindings();
m_ctx->EmitCs([
cMaxCount = MaxDrawCount,
cArgOffset = ByteOffsetForArgs,
@ -143,13 +155,13 @@ namespace dxvk {
void STDMETHODCALLTYPE D3D11DeviceContextExt<ContextType>::SetBarrierControl(
UINT ControlFlags) {
D3D10DeviceLock lock = m_ctx->LockContext();
DxvkBarrierControlFlags flags;
if (ControlFlags & D3D11_VK_BARRIER_CONTROL_IGNORE_WRITE_AFTER_WRITE)
flags.set(DxvkBarrierControl::IgnoreWriteAfterWrite);
D3D11Device* parent = static_cast<D3D11Device*>(m_ctx->GetParentInterface());
DxvkBarrierControlFlags flags = parent->GetOptionsBarrierControlFlags();
if (ControlFlags & D3D11_VK_BARRIER_CONTROL_IGNORE_GRAPHICS_UAV)
flags.set(DxvkBarrierControl::IgnoreGraphicsBarriers);
if (ControlFlags & D3D11_VK_BARRIER_CONTROL_IGNORE_WRITE_AFTER_WRITE) {
flags.set(DxvkBarrierControl::ComputeAllowReadWriteOverlap,
DxvkBarrierControl::GraphicsAllowReadWriteOverlap);
}
m_ctx->EmitCs([cFlags = flags] (DxvkContext* ctx) {
ctx->setBarrierControl(cFlags);

View file

@ -16,28 +16,24 @@ namespace dxvk {
D3D11Device* pParent,
const Rc<DxvkDevice>& Device)
: D3D11CommonContext<D3D11ImmediateContext>(pParent, Device, 0, DxvkCsChunkFlag::SingleUse),
m_csThread(Device, Device->createContext(DxvkContextType::Primary)),
m_maxImplicitDiscardSize(pParent->GetOptions()->maxImplicitDiscardSize),
m_csThread(Device, Device->createContext()),
m_submissionFence(new sync::CallbackFence()),
m_flushTracker(GetMaxFlushType(pParent, Device)),
m_stagingBufferFence(new sync::Fence(0)),
m_multithread(this, false, pParent->GetOptions()->enableContextLock),
m_videoContext(this, Device) {
EmitCs([
cDevice = m_device,
cRelaxedBarriers = pParent->GetOptions()->relaxedBarriers,
cIgnoreGraphicsBarriers = pParent->GetOptions()->ignoreGraphicsBarriers
cBarrierControlFlags = pParent->GetOptionsBarrierControlFlags()
] (DxvkContext* ctx) {
ctx->beginRecording(cDevice->createCommandList());
DxvkBarrierControlFlags barrierControl;
if (cRelaxedBarriers)
barrierControl.set(DxvkBarrierControl::IgnoreWriteAfterWrite);
if (cIgnoreGraphicsBarriers)
barrierControl.set(DxvkBarrierControl::IgnoreGraphicsBarriers);
ctx->setBarrierControl(barrierControl);
ctx->setBarrierControl(cBarrierControlFlags);
});
// Stall here so that external submissions to the
// CS thread can actually access the command list
SynchronizeCsThread(DxvkCsThread::SynchronizeAll);
ClearState();
}
@ -101,6 +97,10 @@ namespace dxvk {
// Ignore the DONOTFLUSH flag here as some games will spin
// on queries without ever flushing the context otherwise.
D3D10DeviceLock lock = LockContext();
if (unlikely(m_device->debugFlags().test(DxvkDebugFlag::Capture)))
m_flushReason = "Query read-back";
ConsiderFlush(GpuFlushType::ImplicitSynchronization);
}
@ -160,6 +160,9 @@ namespace dxvk {
void STDMETHODCALLTYPE D3D11ImmediateContext::Flush() {
D3D10DeviceLock lock = LockContext();
if (unlikely(m_device->debugFlags().test(DxvkDebugFlag::Capture)))
m_flushReason = "Explicit Flush";
ExecuteFlush(GpuFlushType::ExplicitFlush, nullptr, true);
}
@ -169,6 +172,9 @@ namespace dxvk {
HANDLE hEvent) {
D3D10DeviceLock lock = LockContext();
if (unlikely(m_device->debugFlags().test(DxvkDebugFlag::Capture)))
m_flushReason = "Explicit Flush";
ExecuteFlush(GpuFlushType::ExplicitFlush, hEvent, true);
}
@ -189,6 +195,9 @@ namespace dxvk {
ctx->signalFence(cFence, cValue);
});
if (unlikely(m_device->debugFlags().test(DxvkDebugFlag::Capture)))
m_flushReason = "Fence signal";
ExecuteFlush(GpuFlushType::ExplicitFlush, nullptr, true);
return S_OK;
}
@ -203,6 +212,9 @@ namespace dxvk {
if (!fence)
return E_INVALIDARG;
if (unlikely(m_device->debugFlags().test(DxvkDebugFlag::Capture)))
m_flushReason = "Fence wait";
ExecuteFlush(GpuFlushType::ExplicitFlush, nullptr, true);
EmitCs([
@ -222,7 +234,12 @@ namespace dxvk {
D3D10DeviceLock lock = LockContext();
auto commandList = static_cast<D3D11CommandList*>(pCommandList);
// Reset dirty binding tracking before submitting any CS chunks.
// This is needed so that any submission that might occur during
// this call does not disrupt bindings set by the deferred context.
ResetDirtyTracking();
// Clear state so that the command list can't observe any
// current context state. The command list itself will clean
// up after execution to ensure that no state changes done
@ -283,23 +300,14 @@ namespace dxvk {
D3D11_RESOURCE_DIMENSION resourceDim = D3D11_RESOURCE_DIMENSION_UNKNOWN;
pResource->GetType(&resourceDim);
HRESULT hr;
if (likely(resourceDim == D3D11_RESOURCE_DIMENSION_BUFFER)) {
hr = MapBuffer(
return MapBuffer(
static_cast<D3D11Buffer*>(pResource),
MapType, MapFlags, pMappedResource);
} else {
hr = MapImage(
GetCommonTexture(pResource),
Subresource, MapType, MapFlags,
pMappedResource);
return MapImage(GetCommonTexture(pResource),
Subresource, MapType, MapFlags, pMappedResource);
}
if (unlikely(FAILED(hr)))
*pMappedResource = D3D11_MAPPED_SUBRESOURCE();
return hr;
}
@ -331,6 +339,7 @@ namespace dxvk {
if (unlikely(pResource->GetMapMode() == D3D11_COMMON_BUFFER_MAP_MODE_NONE)) {
Logger::err("D3D11: Cannot map a device-local buffer");
pMappedResource->pData = nullptr;
return E_INVALIDARG;
}
@ -340,24 +349,28 @@ namespace dxvk {
// Allocate a new backing slice for the buffer and set
// it as the 'new' mapped slice. This assumes that the
// only way to invalidate a buffer is by mapping it.
auto physSlice = pResource->DiscardSlice();
pMappedResource->pData = physSlice.mapPtr;
auto bufferSlice = pResource->DiscardSlice(&m_allocationCache);
pMappedResource->pData = bufferSlice->mapPtr();
pMappedResource->RowPitch = bufferSize;
pMappedResource->DepthPitch = bufferSize;
EmitCs([
cBuffer = pResource->GetBuffer(),
cBufferSlice = physSlice
] (DxvkContext* ctx) {
ctx->invalidateBuffer(cBuffer, cBufferSlice);
cBufferSlice = std::move(bufferSlice)
] (DxvkContext* ctx) mutable {
ctx->invalidateBuffer(cBuffer, std::move(cBufferSlice));
});
// Ignore small buffers here. These are often updated per
// draw and won't contribute much to memory waste anyway.
if (unlikely(bufferSize > DxvkPageAllocator::PageSize))
ThrottleDiscard(bufferSize);
return S_OK;
} else if (likely(MapType == D3D11_MAP_WRITE_NO_OVERWRITE)) {
// Put this on a fast path without any extra checks since it's
// a somewhat desired method to partially update large buffers
DxvkBufferSliceHandle physSlice = pResource->GetMappedSlice();
pMappedResource->pData = physSlice.mapPtr;
pMappedResource->pData = pResource->GetMapPtr();
pMappedResource->RowPitch = bufferSize;
pMappedResource->DepthPitch = bufferSize;
return S_OK;
@ -372,7 +385,7 @@ namespace dxvk {
auto buffer = pResource->GetBuffer();
auto sequenceNumber = pResource->GetSequenceNumber();
if (MapType != D3D11_MAP_READ && !MapFlags && bufferSize <= m_maxImplicitDiscardSize) {
if (MapType != D3D11_MAP_READ && !MapFlags && bufferSize <= D3D11Initializer::MaxMemoryPerSubmission) {
SynchronizeCsThread(sequenceNumber);
bool hasWoAccess = buffer->isInUse(DxvkAccess::Write);
@ -385,27 +398,32 @@ namespace dxvk {
}
if (doInvalidatePreserve) {
auto prevSlice = pResource->GetMappedSlice();
auto physSlice = pResource->DiscardSlice();
auto srcPtr = pResource->GetMapPtr();
auto dstSlice = pResource->DiscardSlice(nullptr);
auto dstPtr = dstSlice->mapPtr();
EmitCs([
cBuffer = std::move(buffer),
cBufferSlice = physSlice
] (DxvkContext* ctx) {
ctx->invalidateBuffer(cBuffer, cBufferSlice);
cBufferSlice = std::move(dstSlice)
] (DxvkContext* ctx) mutable {
ctx->invalidateBuffer(cBuffer, std::move(cBufferSlice));
});
std::memcpy(physSlice.mapPtr, prevSlice.mapPtr, physSlice.length);
pMappedResource->pData = physSlice.mapPtr;
std::memcpy(dstPtr, srcPtr, bufferSize);
pMappedResource->pData = dstPtr;
pMappedResource->RowPitch = bufferSize;
pMappedResource->DepthPitch = bufferSize;
ThrottleDiscard(bufferSize);
return S_OK;
} else {
if (!WaitForResource(buffer, sequenceNumber, MapType, MapFlags))
if (!WaitForResource(*buffer, sequenceNumber, MapType, MapFlags)) {
pMappedResource->pData = nullptr;
return DXGI_ERROR_WAS_STILL_DRAWING;
}
DxvkBufferSliceHandle physSlice = pResource->GetMappedSlice();
pMappedResource->pData = physSlice.mapPtr;
pMappedResource->pData = pResource->GetMapPtr();
pMappedResource->RowPitch = bufferSize;
pMappedResource->DepthPitch = bufferSize;
return S_OK;
@ -420,19 +438,46 @@ namespace dxvk {
D3D11_MAP MapType,
UINT MapFlags,
D3D11_MAPPED_SUBRESOURCE* pMappedResource) {
const Rc<DxvkImage> mappedImage = pResource->GetImage();
const Rc<DxvkBuffer> mappedBuffer = pResource->GetMappedBuffer(Subresource);
auto mapMode = pResource->GetMapMode();
if (unlikely(mapMode == D3D11_COMMON_TEXTURE_MAP_MODE_NONE)) {
Logger::err("D3D11: Cannot map a device-local image");
return E_INVALIDARG;
}
if (pMappedResource)
pMappedResource->pData = nullptr;
if (unlikely(Subresource >= pResource->CountSubresources()))
return E_INVALIDARG;
switch (MapType) {
case D3D11_MAP_READ: {
if (!(pResource->Desc()->CPUAccessFlags & D3D11_CPU_ACCESS_READ))
return E_INVALIDARG;
} break;
case D3D11_MAP_READ_WRITE: {
if (!(pResource->Desc()->CPUAccessFlags & D3D11_CPU_ACCESS_READ)
|| !(pResource->Desc()->CPUAccessFlags & D3D11_CPU_ACCESS_WRITE))
return E_INVALIDARG;
} break;
case D3D11_MAP_WRITE: {
if (!(pResource->Desc()->CPUAccessFlags & D3D11_CPU_ACCESS_WRITE)
|| (pResource->Desc()->Usage == D3D11_USAGE_DYNAMIC))
return E_INVALIDARG;
} break;
case D3D11_MAP_WRITE_DISCARD: {
if (!(pResource->Desc()->CPUAccessFlags & D3D11_CPU_ACCESS_WRITE)
|| pResource->Desc()->Usage != D3D11_USAGE_DYNAMIC)
return E_INVALIDARG;
} break;
case D3D11_MAP_WRITE_NO_OVERWRITE: {
// NO_OVERWRITE is explcitly banned for dynamic images
if (!(pResource->Desc()->CPUAccessFlags & D3D11_CPU_ACCESS_WRITE)
|| (pResource->Desc()->Usage != D3D11_USAGE_DEFAULT))
return E_INVALIDARG;
} break;
}
if (likely(pMappedResource != nullptr)) {
// Resources with an unknown memory layout cannot return a pointer
if (pResource->Desc()->Usage == D3D11_USAGE_DEFAULT
@ -449,23 +494,32 @@ namespace dxvk {
uint64_t sequenceNumber = pResource->GetSequenceNumber(Subresource);
auto formatInfo = lookupFormatInfo(packedFormat);
void* mapPtr;
auto layout = pResource->GetSubresourceLayout(formatInfo->aspectMask, Subresource);
if (mapMode == D3D11_COMMON_TEXTURE_MAP_MODE_DIRECT) {
// Wait for the resource to become available. We do not
// support image renaming, so stall on DISCARD instead.
if (MapType == D3D11_MAP_WRITE_DISCARD)
MapFlags &= ~D3D11_MAP_FLAG_DO_NOT_WAIT;
Rc<DxvkImage> mappedImage = pResource->GetImage();
if (MapType != D3D11_MAP_WRITE_NO_OVERWRITE) {
if (!WaitForResource(mappedImage, sequenceNumber, MapType, MapFlags))
if (MapType == D3D11_MAP_WRITE_DISCARD) {
EmitCs([
cImage = std::move(mappedImage),
cStorage = pResource->DiscardStorage()
] (DxvkContext* ctx) {
ctx->invalidateImage(cImage, Rc<DxvkResourceAllocation>(cStorage));
ctx->initImage(cImage, cImage->getAvailableSubresources(), VK_IMAGE_LAYOUT_PREINITIALIZED);
});
ThrottleDiscard(layout.Size);
} else if (MapType != D3D11_MAP_WRITE_NO_OVERWRITE) {
if (!WaitForResource(*mappedImage, sequenceNumber, MapType, MapFlags))
return DXGI_ERROR_WAS_STILL_DRAWING;
}
// Query the subresource's memory layout and hope that
// the application respects the returned pitch values.
mapPtr = mappedImage->mapPtr(0);
} else if (mapMode == D3D11_COMMON_TEXTURE_MAP_MODE_DYNAMIC) {
// Nothing else to really do here, NotifyMap will ensure that we
// actually get a staging buffer that isn't currently in use.
ThrottleDiscard(layout.Size);
} else {
Rc<DxvkBuffer> mappedBuffer = pResource->GetMappedBuffer(Subresource);
constexpr uint32_t DoInvalidate = (1u << 0);
constexpr uint32_t DoPreserve = (1u << 1);
constexpr uint32_t DoWait = (1u << 2);
@ -503,11 +557,11 @@ namespace dxvk {
// Need to synchronize thread to determine pending GPU accesses
SynchronizeCsThread(sequenceNumber);
// Don't implicitly discard large buffers or buffers of images with
// multiple subresources, as that is likely to cause memory issues.
VkDeviceSize bufferSize = pResource->GetMappedSlice(Subresource).length;
// Don't implicitly discard large very large resources
// since that might lead to memory issues.
VkDeviceSize bufferSize = mappedBuffer->info().size;
if (bufferSize >= m_maxImplicitDiscardSize || pResource->CountSubresources() > 1) {
if (bufferSize > D3D11Initializer::MaxMemoryPerSubmission) {
// Don't check access flags, WaitForResource will return
// early anyway if the resource is currently in use
doFlags = DoWait;
@ -530,20 +584,25 @@ namespace dxvk {
}
if (doFlags & DoInvalidate) {
DxvkBufferSliceHandle prevSlice = pResource->GetMappedSlice(Subresource);
DxvkBufferSliceHandle physSlice = pResource->DiscardSlice(Subresource);
VkDeviceSize bufferSize = mappedBuffer->info().size;
auto srcSlice = pResource->GetMappedSlice(Subresource);
auto dstSlice = pResource->DiscardSlice(Subresource);
auto srcPtr = srcSlice->mapPtr();
auto dstPtr = dstSlice->mapPtr();
EmitCs([
cImageBuffer = mappedBuffer,
cBufferSlice = physSlice
] (DxvkContext* ctx) {
ctx->invalidateBuffer(cImageBuffer, cBufferSlice);
cImageBuffer = std::move(mappedBuffer),
cImageBufferSlice = std::move(dstSlice)
] (DxvkContext* ctx) mutable {
ctx->invalidateBuffer(cImageBuffer, std::move(cImageBufferSlice));
});
if (doFlags & DoPreserve)
std::memcpy(physSlice.mapPtr, prevSlice.mapPtr, physSlice.length);
std::memcpy(dstPtr, srcPtr, bufferSize);
mapPtr = physSlice.mapPtr;
ThrottleDiscard(bufferSize);
} else {
if (doFlags & DoWait) {
// We cannot respect DO_NOT_WAIT for buffer-mapped resources since
@ -552,20 +611,17 @@ namespace dxvk {
MapFlags &= ~D3D11_MAP_FLAG_DO_NOT_WAIT;
// Wait for mapped buffer to become available
if (!WaitForResource(mappedBuffer, sequenceNumber, MapType, MapFlags))
if (!WaitForResource(*mappedBuffer, sequenceNumber, MapType, MapFlags))
return DXGI_ERROR_WAS_STILL_DRAWING;
}
mapPtr = pResource->GetMappedSlice(Subresource).mapPtr;
}
}
// Mark the given subresource as mapped
pResource->SetMapType(Subresource, MapType);
// Mark the subresource as successfully mapped
pResource->NotifyMap(Subresource, MapType);
if (pMappedResource) {
auto layout = pResource->GetSubresourceLayout(formatInfo->aspectMask, Subresource);
pMappedResource->pData = reinterpret_cast<char*>(mapPtr) + layout.Offset;
pMappedResource->pData = pResource->GetMapPtr(Subresource, layout.Offset);
pMappedResource->RowPitch = layout.RowPitch;
pMappedResource->DepthPitch = layout.DepthPitch;
}
@ -578,28 +634,35 @@ namespace dxvk {
void D3D11ImmediateContext::UnmapImage(
D3D11CommonTexture* pResource,
UINT Subresource) {
D3D11_MAP mapType = pResource->GetMapType(Subresource);
pResource->SetMapType(Subresource, D3D11_MAP(~0u));
auto mapType = pResource->GetMapType(Subresource);
auto mapMode = pResource->GetMapMode();
if (mapType == D3D11_MAP(~0u))
if (mapType == D3D11CommonTexture::UnmappedSubresource)
return;
// Decrement mapped image counter only after making sure
// the given subresource is actually mapped right now
m_mappedImageCount -= 1;
if ((mapType != D3D11_MAP_READ) && (pResource->GetMapMode() == D3D11_COMMON_TEXTURE_MAP_MODE_BUFFER)) {
// If the texture has an image as well as a staging buffer,
// upload the written buffer data to the image
bool needsUpload = mapType != uint32_t(D3D11_MAP_READ)
&& (mapMode == D3D11_COMMON_TEXTURE_MAP_MODE_BUFFER || mapMode == D3D11_COMMON_TEXTURE_MAP_MODE_DYNAMIC);
if (needsUpload) {
if (pResource->NeedsDirtyRegionTracking()) {
for (uint32_t i = 0; i < pResource->GetDirtyRegionCount(Subresource); i++) {
D3D11_COMMON_TEXTURE_REGION region = pResource->GetDirtyRegion(Subresource, i);
UpdateDirtyImageRegion(pResource, Subresource, &region);
}
pResource->ClearDirtyRegions(Subresource);
} else {
UpdateDirtyImageRegion(pResource, Subresource, nullptr);
}
}
// Unmap the subresource. This will implicitly destroy the
// staging buffer for dynamically mapped images.
pResource->NotifyUnmap(Subresource);
}
@ -618,18 +681,8 @@ namespace dxvk {
VkOffset3D offset = { 0, 0, 0 };
VkExtent3D extent = cSrcImage->mipLevelExtent(cSrcSubresource.mipLevel);
if (cSrcSubresource.aspectMask != (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) {
ctx->copyImageToBuffer(cDstBuffer, 0, 0, 0,
cSrcImage, cSrcSubresource, offset, extent);
} else {
ctx->copyDepthStencilImageToPackedBuffer(cDstBuffer, 0,
VkOffset2D { 0, 0 },
VkExtent2D { extent.width, extent.height },
cSrcImage, cSrcSubresource,
VkOffset2D { 0, 0 },
VkExtent2D { extent.width, extent.height },
cPackedFormat);
}
ctx->copyImageToBuffer(cDstBuffer, 0, 0, 0, cPackedFormat,
cSrcImage, cSrcSubresource, offset, extent);
});
if (pResource->HasSequenceNumber())
@ -676,20 +729,10 @@ namespace dxvk {
cSrcDepthPitch = subresourceLayout.DepthPitch,
cPackedFormat = pResource->GetPackedFormat()
] (DxvkContext* ctx) {
if (cDstSubresource.aspectMask != (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) {
ctx->copyBufferToImage(
cDstImage, cDstSubresource, cDstOffset, cDstExtent,
cSrcBuffer, cSrcOffset, cSrcRowPitch, cSrcDepthPitch);
} else {
ctx->copyPackedBufferToDepthStencilImage(
cDstImage, cDstSubresource,
VkOffset2D { cDstOffset.x, cDstOffset.y },
VkExtent2D { cDstExtent.width, cDstExtent.height },
cSrcBuffer, 0,
VkOffset2D { cDstOffset.x, cDstOffset.y },
VkExtent2D { cDstExtent.width, cDstExtent.height },
cPackedFormat);
}
ctx->copyBufferToImage(
cDstImage, cDstSubresource, cDstOffset, cDstExtent,
cSrcBuffer, cSrcOffset, cSrcRowPitch, cSrcDepthPitch,
cPackedFormat);
});
}
@ -704,22 +747,23 @@ namespace dxvk {
UINT Length,
const void* pSrcData,
UINT CopyFlags) {
DxvkBufferSliceHandle slice;
void* mapPtr = nullptr;
if (likely(CopyFlags != D3D11_COPY_NO_OVERWRITE)) {
slice = pDstBuffer->DiscardSlice();
auto bufferSlice = pDstBuffer->DiscardSlice(&m_allocationCache);
mapPtr = bufferSlice->mapPtr();
EmitCs([
cBuffer = pDstBuffer->GetBuffer(),
cBufferSlice = slice
] (DxvkContext* ctx) {
ctx->invalidateBuffer(cBuffer, cBufferSlice);
cBufferSlice = std::move(bufferSlice)
] (DxvkContext* ctx) mutable {
ctx->invalidateBuffer(cBuffer, std::move(cBufferSlice));
});
} else {
slice = pDstBuffer->GetMappedSlice();
mapPtr = pDstBuffer->GetMapPtr();
}
std::memcpy(reinterpret_cast<char*>(slice.mapPtr) + Offset, pSrcData, Length);
std::memcpy(reinterpret_cast<char*>(mapPtr) + Offset, pSrcData, Length);
}
@ -731,7 +775,11 @@ namespace dxvk {
if (!pState)
return;
// Reset all state affected by the current context state
// Clear dirty tracking here since all context state will be
// re-applied anyway when the context state is swapped in again.
ResetDirtyTracking();
// Reset all state affected by the current context state.
ResetCommandListState();
Com<D3D11DeviceContextState, false> oldState = std::move(m_stateObject);
@ -838,17 +886,28 @@ namespace dxvk {
}
void D3D11ImmediateContext::EndFrame() {
void D3D11ImmediateContext::EndFrame(
Rc<DxvkLatencyTracker> LatencyTracker) {
D3D10DeviceLock lock = LockContext();
EmitCs<false>([] (DxvkContext* ctx) {
// Don't keep draw buffers alive indefinitely. This cannot be
// done in ExecuteFlush because command recording itself might
// flush, so no state changes are allowed to happen there.
SetDrawBuffers(nullptr, nullptr);
EmitCs<false>([
cTracker = std::move(LatencyTracker)
] (DxvkContext* ctx) {
ctx->endFrame();
if (cTracker && cTracker->needsAutoMarkers())
ctx->endLatencyTracking(cTracker);
});
}
bool D3D11ImmediateContext::WaitForResource(
const Rc<DxvkResource>& Resource,
const DxvkPagedResource& Resource,
uint64_t SequenceNumber,
D3D11_MAP MapType,
UINT MapFlags) {
@ -860,37 +919,52 @@ namespace dxvk {
// Wait for any CS chunk using the resource to execute, since
// otherwise we cannot accurately determine if the resource is
// actually being used by the GPU right now.
bool isInUse = Resource->isInUse(access);
if (!isInUse) {
if (!Resource.isInUse(access)) {
SynchronizeCsThread(SequenceNumber);
isInUse = Resource->isInUse(access);
if (!Resource.isInUse(access))
return true;
}
if (unlikely(m_device->debugFlags().test(DxvkDebugFlag::Capture))) {
m_flushReason = str::format("Map ", Resource.getDebugName(), " (MAP",
MapType != D3D11_MAP_WRITE ? "_READ" : "",
MapType != D3D11_MAP_READ ? "_WRITE" : "", ")");
}
if (MapFlags & D3D11_MAP_FLAG_DO_NOT_WAIT) {
if (isInUse) {
// We don't have to wait, but misbehaving games may
// still try to spin on `Map` until the resource is
// idle, so we should flush pending commands
ConsiderFlush(GpuFlushType::ImplicitSynchronization);
return false;
}
// We don't have to wait, but misbehaving games may
// still try to spin on `Map` until the resource is
// idle, so we should flush pending commands
ConsiderFlush(GpuFlushType::ImplicitSynchronization);
return false;
} else {
if (isInUse) {
// Make sure pending commands using the resource get
// executed on the the GPU if we have to wait for it
ExecuteFlush(GpuFlushType::ImplicitSynchronization, nullptr, false);
SynchronizeCsThread(SequenceNumber);
// Make sure pending commands using the resource get
// executed on the the GPU if we have to wait for it
ExecuteFlush(GpuFlushType::ImplicitSynchronization, nullptr, false);
SynchronizeCsThread(SequenceNumber);
m_device->waitForResource(Resource, access);
}
m_device->waitForResource(Resource, access);
return true;
}
return true;
}
void D3D11ImmediateContext::InjectCsChunk(
DxvkCsQueue Queue,
DxvkCsChunkRef&& Chunk,
bool Synchronize) {
// Do not update the sequence number when emitting a chunk
// from an external source since that would break tracking
m_csThread.injectChunk(Queue, std::move(Chunk), Synchronize);
}
void D3D11ImmediateContext::EmitCsChunk(DxvkCsChunkRef&& chunk) {
// Flush init commands so that the CS thread
// can processe them before the first use.
m_parent->FlushInitCommands();
m_csSeqNum = m_csThread.dispatchChunk(std::move(chunk));
}
@ -927,8 +1001,106 @@ namespace dxvk {
}
void D3D11ImmediateContext::ApplyDirtyNullBindings() {
// At the end of a submission, set all bindings that have not been applied yet
// to null on the DXVK context. This way, we avoid keeping resources alive that
// are bound to the DXVK context but not to the immediate context.
//
// Note: This requires that all methods that may modify dirty bindings on the
// DXVK context also reset the corresponding dirty bits *before* performing the
// bind operation, or otherwise an implicit flush can potentially override them.
auto& dirtyState = m_state.lazy.bindingsDirty;
EmitCs<false>([
cDirtyState = dirtyState
] (DxvkContext* ctx) {
for (uint32_t i = 0; i < uint32_t(DxbcProgramType::Count); i++) {
auto dxStage = DxbcProgramType(i);
auto vkStage = GetShaderStage(dxStage);
// Unbind all dirty constant buffers
auto cbvSlot = computeConstantBufferBinding(dxStage, 0);
for (uint32_t index : bit::BitMask(cDirtyState[dxStage].cbvMask))
ctx->bindUniformBuffer(vkStage, cbvSlot + index, DxvkBufferSlice());
// Unbind all dirty samplers
auto samplerSlot = computeSamplerBinding(dxStage, 0);
for (uint32_t index : bit::BitMask(cDirtyState[dxStage].samplerMask))
ctx->bindResourceSampler(vkStage, samplerSlot + index, nullptr);
// Unbind all dirty shader resource views
auto srvSlot = computeSrvBinding(dxStage, 0);
for (uint32_t m = 0; m < cDirtyState[dxStage].srvMask.size(); m++) {
for (uint32_t index : bit::BitMask(cDirtyState[dxStage].srvMask[m]))
ctx->bindResourceImageView(vkStage, srvSlot + index + m * 64u, nullptr);
}
// Unbind all dirty unordered access views
VkShaderStageFlags uavStages = 0u;
if (dxStage == DxbcProgramType::ComputeShader)
uavStages = VK_SHADER_STAGE_COMPUTE_BIT;
else if (dxStage == DxbcProgramType::PixelShader)
uavStages = VK_SHADER_STAGE_ALL_GRAPHICS;
if (uavStages) {
auto uavSlot = computeUavBinding(dxStage, 0);
auto ctrSlot = computeUavCounterBinding(dxStage, 0);
for (uint32_t index : bit::BitMask(cDirtyState[dxStage].uavMask)) {
ctx->bindResourceImageView(vkStage, uavSlot + index, nullptr);
ctx->bindResourceBufferView(vkStage, ctrSlot + index, nullptr);
}
}
}
});
// Since we set the DXVK context bindings to null, any bindings that are null
// on the D3D context are no longer dirty, so we can clear the respective bits.
for (uint32_t i = 0; i < uint32_t(DxbcProgramType::Count); i++) {
auto stage = DxbcProgramType(i);
for (uint32_t index : bit::BitMask(dirtyState[stage].cbvMask)) {
if (!m_state.cbv[stage].buffers[index].buffer.ptr())
dirtyState[stage].cbvMask &= ~(1u << index);
}
for (uint32_t index : bit::BitMask(dirtyState[stage].samplerMask)) {
if (!m_state.samplers[stage].samplers[index])
dirtyState[stage].samplerMask &= ~(1u << index);
}
for (uint32_t m = 0; m < dirtyState[stage].srvMask.size(); m++) {
for (uint32_t index : bit::BitMask(dirtyState[stage].srvMask[m])) {
if (!m_state.srv[stage].views[index + m * 64u].ptr())
dirtyState[stage].srvMask[m] &= ~(uint64_t(1u) << index);
}
}
if (stage == DxbcProgramType::ComputeShader || stage == DxbcProgramType::PixelShader) {
auto& uavs = stage == DxbcProgramType::ComputeShader ? m_state.uav.views : m_state.om.uavs;
for (uint32_t index : bit::BitMask(dirtyState[stage].uavMask)) {
if (!uavs[index].ptr())
dirtyState[stage].uavMask &= ~(uint64_t(1u) << index);
}
}
if (dirtyState[stage].empty())
m_state.lazy.shadersDirty.clr(stage);
}
}
void D3D11ImmediateContext::ConsiderFlush(
GpuFlushType FlushType) {
// In stress test mode, behave as if this would always flush
if (DebugLazyBinding == Tristate::True)
ApplyDirtyNullBindings();
uint64_t chunkId = GetCurrentSequenceNumber();
uint64_t submissionId = m_submissionFence->value();
@ -946,15 +1118,13 @@ namespace dxvk {
if (synchronizeSubmission)
m_submitStatus.result = VK_NOT_READY;
// Flush init context so that new resources are fully initialized
// before the app can access them in any way. This has to happen
// unconditionally since we may otherwise deadlock on Map.
m_parent->FlushInitContext();
// Exit early if there's nothing to do
if (!GetPendingCsChunks() && !hEvent)
return;
// Unbind unused resources
ApplyDirtyNullBindings();
// Signal the submission fence and flush the command list
uint64_t submissionId = ++m_submissionId;
@ -967,10 +1137,16 @@ namespace dxvk {
EmitCs<false>([
cSubmissionFence = m_submissionFence,
cSubmissionId = submissionId,
cSubmissionStatus = synchronizeSubmission ? &m_submitStatus : nullptr
cSubmissionStatus = synchronizeSubmission ? &m_submitStatus : nullptr,
cStagingFence = m_stagingBufferFence,
cStagingMemory = GetStagingMemoryStatistics().allocatedTotal,
cFlushReason = std::exchange(m_flushReason, std::string())
] (DxvkContext* ctx) {
auto debugLabel = vk::makeLabel(0xff5959, cFlushReason.c_str());
ctx->signal(cSubmissionFence, cSubmissionId);
ctx->flushCommandList(cSubmissionStatus);
ctx->signal(cStagingFence, cStagingMemory);
ctx->flushCommandList(&debugLabel, cSubmissionStatus);
});
FlushCsChunk();
@ -983,6 +1159,69 @@ namespace dxvk {
// Vulkan queue submission is performed.
if (synchronizeSubmission)
m_device->waitForSubmission(&m_submitStatus);
// Free local staging buffer so that we don't
// end up with a persistent allocation
ResetStagingBuffer();
// Reset counter for discarded memory in flight
m_discardMemoryOnFlush = m_discardMemoryCounter;
// Notify the device that the context has been flushed,
// this resets some resource initialization heuristics.
m_parent->NotifyContextFlush();
// No point in tracking this across submissions
m_hasPendingMsaaResolve = false;
}
void D3D11ImmediateContext::ThrottleAllocation() {
DxvkStagingBufferStats stats = GetStagingMemoryStatistics();
VkDeviceSize stagingMemoryInFlight = stats.allocatedTotal - m_stagingBufferFence->value();
if (stagingMemoryInFlight > stats.allocatedSinceLastReset + D3D11Initializer::MaxMemoryInFlight) {
// Stall calling thread to avoid situation where we keep growing the staging
// buffer indefinitely, but ignore the newly allocated amount so that we don't
// wait for the GPU to go fully idle in case of a large allocation.
ExecuteFlush(GpuFlushType::ExplicitFlush, nullptr, false);
m_device->waitForFence(*m_stagingBufferFence, stats.allocatedTotal -
stats.allocatedSinceLastReset - D3D11Initializer::MaxMemoryInFlight);
} else if (stats.allocatedSinceLastReset >= D3D11Initializer::MaxMemoryPerSubmission) {
// Flush somewhat aggressively if there's a lot of memory in flight
ExecuteFlush(GpuFlushType::ExplicitFlush, nullptr, false);
}
}
void D3D11ImmediateContext::ThrottleDiscard(
VkDeviceSize Size) {
m_discardMemoryCounter += Size;
if (m_discardMemoryCounter - m_discardMemoryOnFlush >= D3D11Initializer::MaxMemoryPerSubmission)
ThrottleAllocation();
}
DxvkStagingBufferStats D3D11ImmediateContext::GetStagingMemoryStatistics() {
DxvkStagingBufferStats stats = m_staging.getStatistics();
stats.allocatedTotal += m_discardMemoryCounter;
stats.allocatedSinceLastReset += m_discardMemoryCounter - m_discardMemoryOnFlush;
return stats;
}
GpuFlushType D3D11ImmediateContext::GetMaxFlushType(
D3D11Device* pParent,
const Rc<DxvkDevice>& Device) {
if (pParent->GetOptions()->reproducibleCommandStream)
return GpuFlushType::ExplicitFlush;
else if (Device->perfHints().preferRenderPassOps)
return GpuFlushType::ImplicitMediumHint;
else
return GpuFlushType::ImplicitWeakHint;
}
}

View file

@ -97,6 +97,21 @@ namespace dxvk {
return m_multithread.AcquireLock();
}
void InjectCsChunk(
DxvkCsQueue Queue,
DxvkCsChunkRef&& Chunk,
bool Synchronize);
template<typename Fn>
void InjectCs(
DxvkCsQueue Queue,
Fn&& Command) {
auto chunk = AllocCsChunk();
chunk->push(std::move(Command));
InjectCsChunk(Queue, std::move(chunk), false);
}
private:
DxvkCsThread m_csThread;
@ -104,8 +119,6 @@ namespace dxvk {
uint32_t m_mappedImageCount = 0u;
VkDeviceSize m_maxImplicitDiscardSize = 0ull;
Rc<sync::CallbackFence> m_submissionFence;
uint64_t m_submissionId = 0ull;
DxvkSubmitStatus m_submitStatus;
@ -113,11 +126,20 @@ namespace dxvk {
uint64_t m_flushSeqNum = 0ull;
GpuFlushTracker m_flushTracker;
Rc<sync::Fence> m_stagingBufferFence;
VkDeviceSize m_discardMemoryCounter = 0u;
VkDeviceSize m_discardMemoryOnFlush = 0u;
bool m_hasPendingMsaaResolve = false;
D3D10Multithread m_multithread;
D3D11VideoContext m_videoContext;
Com<D3D11DeviceContextState, false> m_stateObject;
std::string m_flushReason;
HRESULT MapBuffer(
D3D11Buffer* pResource,
D3D11_MAP MapType,
@ -153,10 +175,11 @@ namespace dxvk {
void SynchronizeDevice();
void EndFrame();
void EndFrame(
Rc<DxvkLatencyTracker> LatencyTracker);
bool WaitForResource(
const Rc<DxvkResource>& Resource,
const DxvkPagedResource& Resource,
uint64_t SequenceNumber,
D3D11_MAP MapType,
UINT MapFlags);
@ -174,6 +197,8 @@ namespace dxvk {
uint64_t GetPendingCsChunks();
void ApplyDirtyNullBindings();
void ConsiderFlush(
GpuFlushType FlushType);
@ -182,6 +207,17 @@ namespace dxvk {
HANDLE hEvent,
BOOL Synchronize);
void ThrottleAllocation();
void ThrottleDiscard(
VkDeviceSize Size);
DxvkStagingBufferStats GetStagingMemoryStatistics();
static GpuFlushType GetMaxFlushType(
D3D11Device* pParent,
const Rc<DxvkDevice>& Device);
};
}

View file

@ -199,10 +199,11 @@ namespace dxvk {
UINT stencilRef = D3D11_DEFAULT_STENCIL_REFERENCE;
UINT maxRtv = 0u;
UINT minUav = D3D11_1_UAV_SLOT_COUNT;
UINT maxUav = 0u;
void reset() {
for (uint32_t i = 0; i < maxUav; i++)
for (uint32_t i = minUav; i < maxUav; i++)
uavs[i] = nullptr;
for (uint32_t i = 0; i < maxRtv; i++)
@ -220,8 +221,9 @@ namespace dxvk {
sampleMask = D3D11_DEFAULT_SAMPLE_MASK;
stencilRef = D3D11_DEFAULT_STENCIL_REFERENCE;
maxRtv = 0;
maxUav = 0;
maxRtv = 0u;
minUav = D3D11_1_UAV_SLOT_COUNT;
maxUav = 0u;
}
};
@ -232,12 +234,12 @@ namespace dxvk {
* argument and draw count buffer.
*/
struct D3D11ContextStateID {
Com<D3D11Buffer, false> argBuffer = nullptr;
Com<D3D11Buffer, false> cntBuffer = nullptr;
uint64_t argBufferCookie = 0u;
uint64_t cntBufferCookie = 0u;
void reset() {
argBuffer = nullptr;
cntBuffer = nullptr;
argBufferCookie = 0u;
cntBufferCookie = 0u;
}
};
@ -302,6 +304,32 @@ namespace dxvk {
predicateValue = false;
}
};
/**
* \brief Lazy binding state
*
* Keeps track of what state needs to be
* re-applied to the context.
*/
struct D3D11LazyBindings {
DxbcProgramTypeFlags shadersUsed = 0u;
DxbcProgramTypeFlags shadersDirty = 0u;
DxbcProgramTypeFlags graphicsUavShaders = 0u;
D3D11ShaderStageState<DxbcBindingMask> bindingsUsed;
D3D11ShaderStageState<DxbcBindingMask> bindingsDirty;
void reset() {
shadersUsed = 0u;
shadersDirty = 0u;
graphicsUavShaders = 0u;
bindingsUsed.reset();
bindingsDirty.reset();
}
};
/**
* \brief Context state
@ -325,6 +353,8 @@ namespace dxvk {
D3D11SrvBindings srv;
D3D11UavBindings uav;
D3D11SamplerBindings samplers;
D3D11LazyBindings lazy;
};
/**
@ -342,9 +372,9 @@ namespace dxvk {
* \brief Maximum used binding numbers for all context state
*/
struct D3D11MaxUsedBindings {
std::array<D3D11MaxUsedStageBindings, 6> stages;
std::array<D3D11MaxUsedStageBindings, uint32_t(DxbcProgramType::Count)> stages;
uint32_t vbCount;
uint32_t soCount;
};
}
}

View file

@ -3,7 +3,8 @@
#include <utility>
#include <vector>
#include "../dxvk/dxvk_resource.h"
#include "../dxvk/dxvk_memory.h"
#include "../dxvk/dxvk_sparse.h"
#include "../util/com/com_guid.h"
#include "../util/com/com_object.h"

View file

@ -183,7 +183,7 @@ namespace dxvk {
desc.TextureLayout = D3D11_TEXTURE_LAYOUT_UNDEFINED;
ID3D11Texture2D1* texture2D = nullptr;
HRESULT hr = CreateTexture2D1(&desc, pInitialData, ppTexture2D ? &texture2D : nullptr);
HRESULT hr = CreateTexture2DBase(&desc, pInitialData, ppTexture2D ? &texture2D : nullptr);
if (hr != S_OK)
return hr;
@ -202,6 +202,14 @@ namespace dxvk {
if (!pDesc)
return E_INVALIDARG;
return CreateTexture2DBase(pDesc, pInitialData, ppTexture2D);
}
HRESULT STDMETHODCALLTYPE D3D11Device::CreateTexture2DBase(
const D3D11_TEXTURE2D_DESC1* pDesc,
const D3D11_SUBRESOURCE_DATA* pInitialData,
ID3D11Texture2D1** ppTexture2D) {
D3D11_COMMON_TEXTURE_DESC desc;
desc.Width = pDesc->Width;
desc.Height = pDesc->Height;
@ -262,7 +270,7 @@ namespace dxvk {
desc.TextureLayout = D3D11_TEXTURE_LAYOUT_UNDEFINED;
ID3D11Texture3D1* texture3D = nullptr;
HRESULT hr = CreateTexture3D1(&desc, pInitialData, ppTexture3D ? &texture3D : nullptr);
HRESULT hr = CreateTexture3DBase(&desc, pInitialData, ppTexture3D ? &texture3D : nullptr);
if (hr != S_OK)
return hr;
@ -280,7 +288,15 @@ namespace dxvk {
if (!pDesc)
return E_INVALIDARG;
return CreateTexture3DBase(pDesc, pInitialData, ppTexture3D);
}
HRESULT STDMETHODCALLTYPE D3D11Device::CreateTexture3DBase(
const D3D11_TEXTURE3D_DESC1* pDesc,
const D3D11_SUBRESOURCE_DATA* pInitialData,
ID3D11Texture3D1** ppTexture3D) {
D3D11_COMMON_TEXTURE_DESC desc;
desc.Width = pDesc->Width;
desc.Height = pDesc->Height;
@ -325,6 +341,9 @@ namespace dxvk {
ID3D11ShaderResourceView** ppSRView) {
InitReturnPtr(ppSRView);
if (!pResource)
return E_INVALIDARG;
uint32_t plane = GetViewPlaneIndex(pResource, pDesc ? pDesc->Format : DXGI_FORMAT_UNKNOWN);
D3D11_SHADER_RESOURCE_VIEW_DESC1 desc = pDesc
@ -333,7 +352,7 @@ namespace dxvk {
ID3D11ShaderResourceView1* view = nullptr;
HRESULT hr = CreateShaderResourceView1(pResource,
HRESULT hr = CreateShaderResourceViewBase(pResource,
pDesc ? &desc : nullptr,
ppSRView ? &view : nullptr);
@ -353,7 +372,15 @@ namespace dxvk {
if (!pResource)
return E_INVALIDARG;
return CreateShaderResourceViewBase(pResource, pDesc, ppSRView);
}
HRESULT STDMETHODCALLTYPE D3D11Device::CreateShaderResourceViewBase(
ID3D11Resource* pResource,
const D3D11_SHADER_RESOURCE_VIEW_DESC1* pDesc,
ID3D11ShaderResourceView1** ppSRView) {
D3D11_COMMON_RESOURCE_DESC resourceDesc;
GetCommonResourceDesc(pResource, &resourceDesc);
@ -402,21 +429,24 @@ namespace dxvk {
ID3D11UnorderedAccessView** ppUAView) {
InitReturnPtr(ppUAView);
if (!pResource)
return E_INVALIDARG;
uint32_t plane = GetViewPlaneIndex(pResource, pDesc ? pDesc->Format : DXGI_FORMAT_UNKNOWN);
D3D11_UNORDERED_ACCESS_VIEW_DESC1 desc = pDesc
? D3D11UnorderedAccessView::PromoteDesc(pDesc, plane)
: D3D11_UNORDERED_ACCESS_VIEW_DESC1();
ID3D11UnorderedAccessView1* view = nullptr;
HRESULT hr = CreateUnorderedAccessView1(pResource,
HRESULT hr = CreateUnorderedAccessViewBase(pResource,
pDesc ? &desc : nullptr,
ppUAView ? &view : nullptr);
if (hr != S_OK)
return hr;
*ppUAView = view;
return S_OK;
}
@ -430,7 +460,15 @@ namespace dxvk {
if (!pResource)
return E_INVALIDARG;
return CreateUnorderedAccessViewBase(pResource, pDesc, ppUAView);
}
HRESULT STDMETHODCALLTYPE D3D11Device::CreateUnorderedAccessViewBase(
ID3D11Resource* pResource,
const D3D11_UNORDERED_ACCESS_VIEW_DESC1* pDesc,
ID3D11UnorderedAccessView1** ppUAView) {
D3D11_COMMON_RESOURCE_DESC resourceDesc;
GetCommonResourceDesc(pResource, &resourceDesc);
@ -481,6 +519,9 @@ namespace dxvk {
ID3D11RenderTargetView** ppRTView) {
InitReturnPtr(ppRTView);
if (!pResource)
return E_INVALIDARG;
uint32_t plane = GetViewPlaneIndex(pResource, pDesc ? pDesc->Format : DXGI_FORMAT_UNKNOWN);
D3D11_RENDER_TARGET_VIEW_DESC1 desc = pDesc
@ -489,7 +530,7 @@ namespace dxvk {
ID3D11RenderTargetView1* view = nullptr;
HRESULT hr = CreateRenderTargetView1(pResource,
HRESULT hr = CreateRenderTargetViewBase(pResource,
pDesc ? &desc : nullptr,
ppRTView ? &view : nullptr);
@ -509,7 +550,15 @@ namespace dxvk {
if (!pResource)
return E_INVALIDARG;
return CreateRenderTargetViewBase(pResource, pDesc, ppRTView);
}
HRESULT STDMETHODCALLTYPE D3D11Device::CreateRenderTargetViewBase(
ID3D11Resource* pResource,
const D3D11_RENDER_TARGET_VIEW_DESC1* pDesc,
ID3D11RenderTargetView1** ppRTView) {
// DXVK only supports render target views for image resources
D3D11_COMMON_RESOURCE_DESC resourceDesc;
GetCommonResourceDesc(pResource, &resourceDesc);
@ -1202,7 +1251,7 @@ namespace dxvk {
desc.ContextType = D3D11_CONTEXT_TYPE_ALL;
ID3D11Query1* query = nullptr;
HRESULT hr = CreateQuery1(&desc, ppQuery ? &query : nullptr);
HRESULT hr = CreateQueryBase(&desc, ppQuery ? &query : nullptr);
if (hr != S_OK)
return hr;
@ -1219,7 +1268,14 @@ namespace dxvk {
if (!pQueryDesc)
return E_INVALIDARG;
return CreateQueryBase(pQueryDesc, ppQuery);
}
HRESULT STDMETHODCALLTYPE D3D11Device::CreateQueryBase(
const D3D11_QUERY_DESC1* pQueryDesc,
ID3D11Query1** ppQuery) {
HRESULT hr = D3D11Query::ValidateDesc(pQueryDesc);
if (FAILED(hr))
@ -1396,10 +1452,10 @@ namespace dxvk {
|| texture->CountSubresources() <= SrcSubresource)
return;
D3D11_MAP map = texture->GetMapType(SrcSubresource);
uint32_t map = texture->GetMapType(SrcSubresource);
if (map != D3D11_MAP_READ
&& map != D3D11_MAP_READ_WRITE)
if (map != uint32_t(D3D11_MAP_READ)
&& map != uint32_t(D3D11_MAP_READ_WRITE))
return;
CopySubresourceData(
@ -1425,11 +1481,11 @@ namespace dxvk {
|| texture->CountSubresources() <= DstSubresource)
return;
D3D11_MAP map = texture->GetMapType(DstSubresource);
uint32_t map = texture->GetMapType(DstSubresource);
if (map != D3D11_MAP_WRITE
&& map != D3D11_MAP_WRITE_NO_OVERWRITE
&& map != D3D11_MAP_READ_WRITE)
if (map != uint32_t(D3D11_MAP_WRITE)
&& map != uint32_t(D3D11_MAP_WRITE_NO_OVERWRITE)
&& map != uint32_t(D3D11_MAP_READ_WRITE))
return;
CopySubresourceData(
@ -1839,11 +1895,6 @@ namespace dxvk {
}
void D3D11Device::FlushInitContext() {
m_initializer->Flush();
}
D3D_FEATURE_LEVEL D3D11Device::GetMaxFeatureLevel(
const Rc<DxvkInstance>& Instance,
const Rc<DxvkAdapter>& Adapter) {
@ -1905,8 +1956,6 @@ namespace dxvk {
enabled.core.features.shaderImageGatherExtended = VK_TRUE;
enabled.core.features.textureCompressionBC = VK_TRUE;
enabled.vk11.shaderDrawParameters = VK_TRUE;
enabled.vk12.samplerMirrorClampToEdge = VK_TRUE;
enabled.vk13.shaderDemoteToHelperInvocation = VK_TRUE;
@ -1923,7 +1972,6 @@ namespace dxvk {
// Required for Feature Level 11_0
enabled.core.features.drawIndirectFirstInstance = supported.core.features.drawIndirectFirstInstance;
enabled.core.features.fragmentStoresAndAtomics = supported.core.features.fragmentStoresAndAtomics;
enabled.core.features.multiDrawIndirect = supported.core.features.multiDrawIndirect;
enabled.core.features.tessellationShader = supported.core.features.tessellationShader;
// Required for Feature Level 11_1
@ -1969,6 +2017,9 @@ namespace dxvk {
size_t BytecodeLength,
ID3D11ClassLinkage* pClassLinkage,
const DxbcModuleInfo* pModuleInfo) {
if (!BytecodeLength || !pShaderBytecode)
return E_INVALIDARG;
if (pClassLinkage != nullptr)
Logger::warn("D3D11Device::CreateShaderModule: Class linkage not supported");
@ -2384,11 +2435,7 @@ namespace dxvk {
D3D11_COMMON_TEXTURE_SUBRESOURCE_LAYOUT layout = pTexture->GetSubresourceLayout(aspect, Subresource);
// Compute actual map pointer, accounting for the region offset
VkDeviceSize mapOffset = pTexture->ComputeMappedOffset(Subresource, i, offset);
void* mapPtr = pTexture->GetMapMode() == D3D11_COMMON_TEXTURE_MAP_MODE_BUFFER
? pTexture->GetMappedBuffer(Subresource)->mapPtr(mapOffset)
: image->mapPtr(mapOffset);
void* mapPtr = pTexture->GetMapPtr(Subresource, pTexture->ComputeMappedOffset(Subresource, i, offset));
if constexpr (std::is_const<Void>::value) {
// WriteToSubresource
@ -2492,15 +2539,15 @@ namespace dxvk {
D3D11SamplerState* pSS = static_cast<D3D11SamplerState*>(samplerState);
Rc<DxvkSampler> pDSS = pSS->GetDXVKSampler();
VkSampler vkSampler = pDSS->handle();
D3D11ShaderResourceView* pSRV = static_cast<D3D11ShaderResourceView*>(srv);
Rc<DxvkImageView> pIV = pSRV->GetImageView();
VkImageView vkImageView = pIV->handle();
VkImageViewHandleInfoNVX imageViewHandleInfo = {VK_STRUCTURE_TYPE_IMAGE_VIEW_HANDLE_INFO_NVX};
imageViewHandleInfo.imageView = vkImageView;
imageViewHandleInfo.sampler = vkSampler;
LockImage(pIV->image(), 0u);
VkImageViewHandleInfoNVX imageViewHandleInfo = { VK_STRUCTURE_TYPE_IMAGE_VIEW_HANDLE_INFO_NVX };
imageViewHandleInfo.imageView = pIV->handle();
imageViewHandleInfo.sampler = pDSS->handle();
imageViewHandleInfo.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
// note: there's no implicit lifetime management here; it's up to the
@ -2558,21 +2605,9 @@ namespace dxvk {
ID3D11Resource* pResource = static_cast<ID3D11Resource*>(hObject);
D3D11_COMMON_RESOURCE_DESC resourceDesc;
if (FAILED(GetCommonResourceDesc(pResource, &resourceDesc))) {
Logger::warn("GetResourceHandleGPUVirtualAddressAndSize() - GetCommonResourceDesc() failed");
return false;
}
switch (resourceDesc.Dim) {
case D3D11_RESOURCE_DIMENSION_BUFFER:
case D3D11_RESOURCE_DIMENSION_TEXTURE2D:
// okay - we can deal with those two dimensions
break;
case D3D11_RESOURCE_DIMENSION_TEXTURE1D:
case D3D11_RESOURCE_DIMENSION_TEXTURE3D:
case D3D11_RESOURCE_DIMENSION_UNKNOWN:
default:
Logger::warn(str::format("GetResourceHandleGPUVirtualAddressAndSize(?) - failure - unsupported dimension: ", resourceDesc.Dim));
if (FAILED(GetCommonResourceDesc(pResource, &resourceDesc))) {
Logger::warn("GetResourceHandleGPUVirtualAddressAndSize: Invalid resource");
return false;
}
@ -2581,57 +2616,49 @@ namespace dxvk {
if (resourceDesc.Dim == D3D11_RESOURCE_DIMENSION_TEXTURE2D) {
D3D11CommonTexture *texture = GetCommonTexture(pResource);
// Ensure that the image has a stable GPU address and
// won't be relocated by the backend going forward
Rc<DxvkImage> dxvkImage = texture->GetImage();
if (0 == (dxvkImage->info().usage & (VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_SAMPLED_BIT))) {
Logger::warn(str::format("GetResourceHandleGPUVirtualAddressAndSize(res=", pResource,") image info missing required usage bit(s); can't be used for vkGetImageViewHandleNVX - failure"));
if (!LockImage(dxvkImage, VK_IMAGE_USAGE_SAMPLED_BIT))
return false;
}
// The d3d11 nvapi provides us a texture but vulkan only lets us get the GPU address from an imageview. So, make a private imageview and get the address from that...
// The d3d11 nvapi provides us a texture, but vulkan only lets us
// get the GPU address from an image view. So, make a private image
// view and get the address from that.
DxvkImageViewKey viewInfo;
viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
viewInfo.format = dxvkImage->info().format;
viewInfo.aspects = dxvkImage->formatInfo()->aspectMask;
viewInfo.mipIndex = 0;
viewInfo.mipCount = dxvkImage->info().mipLevels;
viewInfo.layerIndex = 0;
viewInfo.layerCount = 1;
viewInfo.usage = VK_IMAGE_USAGE_SAMPLED_BIT;
D3D11_SHADER_RESOURCE_VIEW_DESC resourceViewDesc;
auto dxvkView = dxvkImage->createView(viewInfo);
VkImageViewAddressPropertiesNVX imageViewAddressProperties = { VK_STRUCTURE_TYPE_IMAGE_VIEW_ADDRESS_PROPERTIES_NVX };
const D3D11_COMMON_TEXTURE_DESC *texDesc = texture->Desc();
if (texDesc->ArraySize != 1) {
Logger::debug(str::format("GetResourceHandleGPUVirtualAddressAndSize(?) - unexpected array size: ", texDesc->ArraySize));
}
resourceViewDesc.Format = texDesc->Format;
resourceViewDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
resourceViewDesc.Texture2D.MostDetailedMip = 0;
resourceViewDesc.Texture2D.MipLevels = texDesc->MipLevels;
VkResult vr = dxvkDevice->vkd()->vkGetImageViewAddressNVX(vkDevice,
dxvkView->handle(), &imageViewAddressProperties);
Com<ID3D11ShaderResourceView> pNewSRV;
HRESULT hr = m_device->CreateShaderResourceView(pResource, &resourceViewDesc, &pNewSRV);
if (FAILED(hr)) {
Logger::warn("GetResourceHandleGPUVirtualAddressAndSize() - private CreateShaderResourceView() failed");
return false;
}
Rc<DxvkImageView> dxvkImageView = static_cast<D3D11ShaderResourceView*>(pNewSRV.ptr())->GetImageView();
VkImageView vkImageView = dxvkImageView->handle();
VkImageViewAddressPropertiesNVX imageViewAddressProperties = {VK_STRUCTURE_TYPE_IMAGE_VIEW_ADDRESS_PROPERTIES_NVX};
VkResult res = dxvkDevice->vkd()->vkGetImageViewAddressNVX(vkDevice, vkImageView, &imageViewAddressProperties);
if (res != VK_SUCCESS) {
Logger::warn(str::format("GetResourceHandleGPUVirtualAddressAndSize(): vkGetImageViewAddressNVX() result is failure: ", res));
if (vr != VK_SUCCESS) {
Logger::warn(str::format("GetResourceHandleGPUVirtualAddressAndSize(): Failed: vr = ", vr));
return false;
}
*gpuVAStart = imageViewAddressProperties.deviceAddress;
*gpuVASize = imageViewAddressProperties.size;
}
else if (resourceDesc.Dim == D3D11_RESOURCE_DIMENSION_BUFFER) {
D3D11Buffer *buffer = GetCommonBuffer(pResource);
const DxvkBufferSliceHandle bufSliceHandle = buffer->GetBuffer()->getSliceHandle();
VkBuffer vkBuffer = bufSliceHandle.handle;
} else if (resourceDesc.Dim == D3D11_RESOURCE_DIMENSION_BUFFER) {
Rc<DxvkBuffer> dxvkBuffer = GetCommonBuffer(pResource)->GetBuffer();
LockBuffer(dxvkBuffer);
VkBufferDeviceAddressInfo bdaInfo = { VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO };
bdaInfo.buffer = vkBuffer;
VkDeviceAddress bufAddr = dxvkDevice->vkd()->vkGetBufferDeviceAddress(vkDevice, &bdaInfo);
*gpuVAStart = uint64_t(bufAddr) + bufSliceHandle.offset;
*gpuVASize = bufSliceHandle.length;
*gpuVAStart = dxvkBuffer->gpuAddress();
*gpuVASize = dxvkBuffer->info().size;
} else {
Logger::warn(str::format("GetResourceHandleGPUVirtualAddressAndSize(): Unsupported resource type: ", resourceDesc.Dim));
return false;
}
if (!*gpuVAStart)
@ -2641,102 +2668,99 @@ namespace dxvk {
}
bool STDMETHODCALLTYPE D3D11DeviceExt::CreateUnorderedAccessViewAndGetDriverHandleNVX(ID3D11Resource* pResource, const D3D11_UNORDERED_ACCESS_VIEW_DESC* pDesc, ID3D11UnorderedAccessView** ppUAV, uint32_t* pDriverHandle) {
D3D11_COMMON_RESOURCE_DESC resourceDesc;
if (!SUCCEEDED(GetCommonResourceDesc(pResource, &resourceDesc))) {
Logger::warn("CreateUnorderedAccessViewAndGetDriverHandleNVX() - GetCommonResourceDesc() failed");
return false;
}
bool STDMETHODCALLTYPE D3D11DeviceExt::CreateUnorderedAccessViewAndGetDriverHandleNVX(
ID3D11Resource* pResource,
const D3D11_UNORDERED_ACCESS_VIEW_DESC* pDesc,
ID3D11UnorderedAccessView** ppUAV,
uint32_t* pDriverHandle) {
D3D11_COMMON_RESOURCE_DESC resourceDesc = { };
GetCommonResourceDesc(pResource, &resourceDesc);
if (resourceDesc.Dim != D3D11_RESOURCE_DIMENSION_TEXTURE2D) {
Logger::warn(str::format("CreateUnorderedAccessViewAndGetDriverHandleNVX() - failure - unsupported dimension: ", resourceDesc.Dim));
Logger::warn(str::format("CreateUnorderedAccessViewAndGetDriverHandleNVX(): Unsupported dimension: ", resourceDesc.Dim));
return false;
}
auto texture = GetCommonTexture(pResource);
Rc<DxvkImage> dxvkImage = texture->GetImage();
if (0 == (dxvkImage->info().usage & (VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_SAMPLED_BIT))) {
Logger::warn(str::format("CreateUnorderedAccessViewAndGetDriverHandleNVX(res=", pResource, ") image info missing required usage bit(s); can't be used for vkGetImageViewHandleNVX - failure"));
Rc<DxvkImage> dxvkImage = GetCommonTexture(pResource)->GetImage();
if (!(dxvkImage->info().usage & VK_IMAGE_USAGE_STORAGE_BIT)) {
Logger::warn(str::format("CreateUnorderedAccessViewAndGetDriverHandleNVX(res=", pResource, "): Image not UAV compatible"));
return false;
}
if (!SUCCEEDED(m_device->CreateUnorderedAccessView(pResource, pDesc, ppUAV))) {
return false;
}
Com<ID3D11UnorderedAccessView> uav;
D3D11UnorderedAccessView *pUAV = static_cast<D3D11UnorderedAccessView *>(*ppUAV);
Rc<DxvkDevice> dxvkDevice = m_device->GetDXVKDevice();
VkDevice vkDevice = dxvkDevice->handle();
if (FAILED(m_device->CreateUnorderedAccessView(pResource, pDesc, &uav)))
return false;
Rc<DxvkImageView> dxvkImageView = static_cast<D3D11UnorderedAccessView*>(uav.ptr())->GetImageView();
LockImage(dxvkImageView->image(), 0u);
VkImageViewHandleInfoNVX imageViewHandleInfo = {VK_STRUCTURE_TYPE_IMAGE_VIEW_HANDLE_INFO_NVX};
Rc<DxvkImageView> dxvkImageView = pUAV->GetImageView();
VkImageView vkImageView = dxvkImageView->handle();
imageViewHandleInfo.imageView = vkImageView;
imageViewHandleInfo.imageView = dxvkImageView->handle();
imageViewHandleInfo.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE;
*pDriverHandle = dxvkDevice->vkd()->vkGetImageViewHandleNVX(vkDevice, &imageViewHandleInfo);
Rc<DxvkDevice> dxvkDevice = m_device->GetDXVKDevice();
*pDriverHandle = dxvkDevice->vkd()->vkGetImageViewHandleNVX(
dxvkDevice->handle(), &imageViewHandleInfo);
if (!*pDriverHandle) {
Logger::warn("CreateUnorderedAccessViewAndGetDriverHandleNVX() handle==0 - failure");
pUAV->Release();
Logger::warn("CreateUnorderedAccessViewAndGetDriverHandleNVX(): Handle is 0");
return false;
}
*ppUAV = uav.ref();
return true;
}
bool STDMETHODCALLTYPE D3D11DeviceExt::CreateShaderResourceViewAndGetDriverHandleNVX(ID3D11Resource* pResource, const D3D11_SHADER_RESOURCE_VIEW_DESC* pDesc, ID3D11ShaderResourceView** ppSRV, uint32_t* pDriverHandle) {
D3D11_COMMON_RESOURCE_DESC resourceDesc;
if (!SUCCEEDED(GetCommonResourceDesc(pResource, &resourceDesc))) {
Logger::warn("CreateShaderResourceViewAndGetDriverHandleNVX() - GetCommonResourceDesc() failed");
return false;
}
D3D11_COMMON_RESOURCE_DESC resourceDesc = { };
GetCommonResourceDesc(pResource, &resourceDesc);
if (resourceDesc.Dim != D3D11_RESOURCE_DIMENSION_TEXTURE2D) {
Logger::warn(str::format("CreateShaderResourceViewAndGetDriverHandleNVX() - failure - unsupported dimension: ", resourceDesc.Dim));
Logger::warn(str::format("CreateShaderResourceViewAndGetDriverHandleNVX(): Unsupported dimension: ", resourceDesc.Dim));
return false;
}
auto texture = GetCommonTexture(pResource);
Rc<DxvkImage> dxvkImage = texture->GetImage();
if (0 == (dxvkImage->info().usage & (VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_SAMPLED_BIT))) {
Logger::warn(str::format("CreateShaderResourceViewAndGetDriverHandleNVX(res=", pResource, ") image info missing required usage bit(s); can't be used for vkGetImageViewHandleNVX - failure"));
Rc<DxvkImage> dxvkImage = GetCommonTexture(pResource)->GetImage();
if (!(dxvkImage->info().usage & VK_IMAGE_USAGE_SAMPLED_BIT)) {
Logger::warn(str::format("CreateShaderResourceViewAndGetDriverHandleNVX(res=", pResource, "): Image not SRV compatible"));
return false;
}
if (!SUCCEEDED(m_device->CreateShaderResourceView(pResource, pDesc, ppSRV))) {
return false;
}
Com<ID3D11ShaderResourceView> srv;
D3D11ShaderResourceView* pSRV = static_cast<D3D11ShaderResourceView*>(*ppSRV);
Rc<DxvkDevice> dxvkDevice = m_device->GetDXVKDevice();
VkDevice vkDevice = dxvkDevice->handle();
if (FAILED(m_device->CreateShaderResourceView(pResource, pDesc, &srv)))
return false;
Rc<DxvkImageView> dxvkImageView = static_cast<D3D11ShaderResourceView*>(srv.ptr())->GetImageView();
LockImage(dxvkImageView->image(), 0u);
VkImageViewHandleInfoNVX imageViewHandleInfo = {VK_STRUCTURE_TYPE_IMAGE_VIEW_HANDLE_INFO_NVX};
Rc<DxvkImageView> dxvkImageView = pSRV->GetImageView();
VkImageView vkImageView = dxvkImageView->handle();
imageViewHandleInfo.imageView = vkImageView;
imageViewHandleInfo.imageView = dxvkImageView->handle();
imageViewHandleInfo.descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE;
*pDriverHandle = dxvkDevice->vkd()->vkGetImageViewHandleNVX(vkDevice, &imageViewHandleInfo);
Rc<DxvkDevice> dxvkDevice = m_device->GetDXVKDevice();
*pDriverHandle = dxvkDevice->vkd()->vkGetImageViewHandleNVX(
dxvkDevice->handle(), &imageViewHandleInfo);
if (!*pDriverHandle) {
Logger::warn("CreateShaderResourceViewAndGetDriverHandleNVX() handle==0 - failure");
pSRV->Release();
Logger::warn("CreateShaderResourceViewAndGetDriverHandleNVX(): Handle is 0");
return false;
}
// will need to look-up resource from uint32 handle later
AddSrvAndHandleNVX(*ppSRV, *pDriverHandle);
*ppSRV = srv.ref();
AddSrvAndHandleNVX(srv.ptr(), *pDriverHandle);
return true;
}
bool STDMETHODCALLTYPE D3D11DeviceExt::CreateSamplerStateAndGetDriverHandleNVX(const D3D11_SAMPLER_DESC* pSamplerDesc, ID3D11SamplerState** ppSamplerState, uint32_t* pDriverHandle) {
if (!SUCCEEDED(m_device->CreateSamplerState(pSamplerDesc, ppSamplerState))) {
if (FAILED(m_device->CreateSamplerState(pSamplerDesc, ppSamplerState)))
return false;
}
// for our purposes the actual value doesn't matter, only its uniqueness
static std::atomic<ULONG> s_seqNum = 0;
@ -2782,8 +2806,57 @@ namespace dxvk {
}
bool D3D11DeviceExt::LockImage(
const Rc<DxvkImage>& Image,
VkImageUsageFlags Usage) {
if (!Image->canRelocate() && (Image->info().usage & Usage))
return true;
bool feedback = false;
auto chunk = m_device->AllocCsChunk(DxvkCsChunkFlag::SingleUse);
chunk->push([
cImage = Image,
cUsage = Usage,
&feedback
] (DxvkContext* ctx) {
DxvkImageUsageInfo usageInfo;
usageInfo.usage = cUsage;
usageInfo.stableGpuAddress = VK_TRUE;
feedback = ctx->ensureImageCompatibility(cImage, usageInfo);
});
m_device->GetContext()->InjectCsChunk(DxvkCsQueue::HighPriority, std::move(chunk), true);
if (!feedback) {
Logger::err(str::format("Failed to lock image:"
"\n Image format: ", Image->info().format,
"\n Image usage: ", std::hex, Image->info().usage,
"\n Desired usage: ", std::hex, Usage));
}
return feedback;
}
void D3D11DeviceExt::LockBuffer(
const Rc<DxvkBuffer>& Buffer) {
if (!Buffer->canRelocate())
return;
auto chunk = m_device->AllocCsChunk(DxvkCsChunkFlag::SingleUse);
chunk->push([cBuffer = Buffer] (DxvkContext* ctx) {
ctx->ensureBufferAddress(cBuffer);
});
m_device->GetContext()->InjectCsChunk(DxvkCsQueue::HighPriority, std::move(chunk), true);
}
D3D11VideoDevice::D3D11VideoDevice(
D3D11DXGIDevice* pContainer,
@ -2985,6 +3058,198 @@ namespace dxvk {
D3D11ReflexDevice::D3D11ReflexDevice(
D3D11DXGIDevice* pContainer,
D3D11Device* pDevice)
: m_container(pContainer), m_device(pDevice) {
auto dxvkDevice = pDevice->GetDXVKDevice();
m_reflexEnabled = dxvkDevice->features().nvLowLatency2
&& dxvkDevice->config().latencySleep == Tristate::Auto;
}
D3D11ReflexDevice::~D3D11ReflexDevice() {
}
ULONG STDMETHODCALLTYPE D3D11ReflexDevice::AddRef() {
return m_container->AddRef();
}
ULONG STDMETHODCALLTYPE D3D11ReflexDevice::Release() {
return m_container->Release();
}
HRESULT STDMETHODCALLTYPE D3D11ReflexDevice::QueryInterface(
REFIID riid,
void** ppvObject) {
return m_container->QueryInterface(riid, ppvObject);
}
BOOL STDMETHODCALLTYPE D3D11ReflexDevice::SupportsLowLatency() {
return m_reflexEnabled;
}
HRESULT STDMETHODCALLTYPE D3D11ReflexDevice::LatencySleep() {
if (!m_reflexEnabled)
return DXGI_ERROR_INVALID_CALL;
// Don't keep object locked while sleeping
Rc<DxvkReflexLatencyTrackerNv> tracker;
{ std::lock_guard lock(m_mutex);
tracker = m_tracker;
}
if (tracker)
tracker->latencySleep();
return S_OK;
}
HRESULT STDMETHODCALLTYPE D3D11ReflexDevice::SetLatencySleepMode(
BOOL LowLatencyEnable,
BOOL LowLatencyBoost,
UINT32 MinIntervalUs) {
if (!m_reflexEnabled)
return DXGI_ERROR_INVALID_CALL;
std::lock_guard lock(m_mutex);
if (m_tracker) {
m_tracker->setLatencySleepMode(
LowLatencyEnable, LowLatencyBoost, MinIntervalUs);
}
// Write back in case we have no swapchain yet
m_enableLowLatency = LowLatencyEnable;
m_enableBoost = LowLatencyBoost;
m_minIntervalUs = MinIntervalUs;
return S_OK;
}
HRESULT STDMETHODCALLTYPE D3D11ReflexDevice::SetLatencyMarker(
UINT64 FrameId,
UINT32 MarkerType) {
if (!m_reflexEnabled)
return DXGI_ERROR_INVALID_CALL;
std::lock_guard lock(m_mutex);
if (m_tracker) {
auto marker = VkLatencyMarkerNV(MarkerType);
m_tracker->setLatencyMarker(FrameId, marker);
if (marker == VK_LATENCY_MARKER_RENDERSUBMIT_START_NV) {
m_device->GetContext()->InjectCs(DxvkCsQueue::Ordered, [
cTracker = m_tracker,
cFrameId = FrameId
] (DxvkContext* ctx) {
uint64_t frameId = cTracker->frameIdFromAppFrameId(cFrameId);
if (frameId)
ctx->beginLatencyTracking(cTracker, frameId);
});
} else if (marker == VK_LATENCY_MARKER_RENDERSUBMIT_END_NV) {
m_device->GetContext()->InjectCs(DxvkCsQueue::Ordered, [
cTracker = m_tracker
] (DxvkContext* ctx) {
ctx->endLatencyTracking(cTracker);
});
}
}
return S_OK;
}
HRESULT STDMETHODCALLTYPE D3D11ReflexDevice::GetLatencyInfo(
D3D_LOW_LATENCY_RESULTS* pLowLatencyResults) {
constexpr static size_t FrameCount = 64;
if (!pLowLatencyResults)
return E_INVALIDARG;
for (size_t i = 0; i < FrameCount; i++)
pLowLatencyResults->frameReports[i] = D3D_LOW_LATENCY_FRAME_REPORT();
if (!m_reflexEnabled)
return DXGI_ERROR_INVALID_CALL;
std::lock_guard lock(m_mutex);
if (!m_tracker)
return S_OK;
// Apparently we have to report all 64 frames, or nothing
std::array<DxvkReflexFrameReport, FrameCount> reports = { };
uint32_t reportCount = m_tracker->getFrameReports(FrameCount, reports.data());
if (reportCount < FrameCount)
return S_OK;
for (uint32_t i = 0; i < FrameCount; i++) {
auto& src = reports[i];
auto& dst = pLowLatencyResults->frameReports[i];
dst.frameID = src.report.presentID;
dst.inputSampleTime = src.report.inputSampleTimeUs;
dst.simStartTime = src.report.simStartTimeUs;
dst.simEndTime = src.report.simEndTimeUs;
dst.renderSubmitStartTime = src.report.renderSubmitStartTimeUs;
dst.renderSubmitEndTime = src.report.renderSubmitEndTimeUs;
dst.presentStartTime = src.report.presentStartTimeUs;
dst.presentEndTime = src.report.presentEndTimeUs;
dst.driverStartTime = src.report.driverStartTimeUs;
dst.driverEndTime = src.report.driverEndTimeUs;
dst.osRenderQueueStartTime = src.report.osRenderQueueStartTimeUs;
dst.osRenderQueueEndTime = src.report.osRenderQueueEndTimeUs;
dst.gpuRenderStartTime = src.report.gpuRenderStartTimeUs;
dst.gpuRenderEndTime = src.report.gpuRenderEndTimeUs;
dst.gpuActiveRenderTimeUs = src.gpuActiveTimeUs;
dst.gpuFrameTimeUs = 0;
if (i) {
dst.gpuFrameTimeUs = reports[i - 0].report.gpuRenderEndTimeUs
- reports[i - 1].report.gpuRenderEndTimeUs;
}
}
return S_OK;
}
void D3D11ReflexDevice::RegisterLatencyTracker(
Rc<DxvkLatencyTracker> Tracker) {
std::lock_guard lock(m_mutex);
if (m_tracker)
return;
if ((m_tracker = dynamic_cast<DxvkReflexLatencyTrackerNv*>(Tracker.ptr())))
m_tracker->setLatencySleepMode(m_enableLowLatency, m_enableBoost, m_minIntervalUs);
}
void D3D11ReflexDevice::UnregisterLatencyTracker(
Rc<DxvkLatencyTracker> Tracker) {
std::lock_guard lock(m_mutex);
if (m_tracker == Tracker)
m_tracker = nullptr;
}
DXGIVkSwapChainFactory::DXGIVkSwapChainFactory(
D3D11DXGIDevice* pContainer,
D3D11Device* pDevice)
@ -3086,6 +3351,7 @@ namespace dxvk {
m_d3d11DeviceExt(this, &m_d3d11Device),
m_d3d11Interop (this, &m_d3d11Device),
m_d3d11Video (this, &m_d3d11Device),
m_d3d11Reflex (this, &m_d3d11Device),
m_d3d11on12 (this, &m_d3d11Device, pD3D12Device, pD3D12Queue),
m_metaDevice (this),
m_dxvkFactory (this, &m_d3d11Device) {
@ -3158,8 +3424,14 @@ namespace dxvk {
return S_OK;
}
if (riid == __uuidof(ID3DLowLatencyDevice)) {
*ppvObject = ref(&m_d3d11Reflex);
return S_OK;
}
if (m_d3d11on12.Is11on12Device()) {
if (riid == __uuidof(ID3D11On12Device)) {
if (riid == __uuidof(ID3D11On12Device)
|| riid == __uuidof(ID3D11On12Device1_DXVK)) {
*ppvObject = ref(&m_d3d11on12);
return S_OK;
}

View file

@ -9,6 +9,7 @@
#include "../dxgi/dxgi_interfaces.h"
#include "../dxvk/dxvk_cs.h"
#include "../dxvk/dxvk_latency_reflex.h"
#include "../d3d10/d3d10_device.h"
@ -87,6 +88,11 @@ namespace dxvk {
const D3D11_SUBRESOURCE_DATA* pInitialData,
ID3D11Texture2D1** ppTexture2D);
HRESULT STDMETHODCALLTYPE CreateTexture2DBase(
const D3D11_TEXTURE2D_DESC1* pDesc,
const D3D11_SUBRESOURCE_DATA* pInitialData,
ID3D11Texture2D1** ppTexture2D);
HRESULT STDMETHODCALLTYPE CreateTexture3D(
const D3D11_TEXTURE3D_DESC* pDesc,
const D3D11_SUBRESOURCE_DATA* pInitialData,
@ -97,6 +103,11 @@ namespace dxvk {
const D3D11_SUBRESOURCE_DATA* pInitialData,
ID3D11Texture3D1** ppTexture3D);
HRESULT STDMETHODCALLTYPE CreateTexture3DBase(
const D3D11_TEXTURE3D_DESC1* pDesc,
const D3D11_SUBRESOURCE_DATA* pInitialData,
ID3D11Texture3D1** ppTexture3D);
HRESULT STDMETHODCALLTYPE CreateShaderResourceView(
ID3D11Resource* pResource,
const D3D11_SHADER_RESOURCE_VIEW_DESC* pDesc,
@ -107,6 +118,11 @@ namespace dxvk {
const D3D11_SHADER_RESOURCE_VIEW_DESC1* pDesc,
ID3D11ShaderResourceView1** ppSRView);
HRESULT STDMETHODCALLTYPE CreateShaderResourceViewBase(
ID3D11Resource* pResource,
const D3D11_SHADER_RESOURCE_VIEW_DESC1* pDesc,
ID3D11ShaderResourceView1** ppSRView);
HRESULT STDMETHODCALLTYPE CreateUnorderedAccessView(
ID3D11Resource* pResource,
const D3D11_UNORDERED_ACCESS_VIEW_DESC* pDesc,
@ -117,6 +133,11 @@ namespace dxvk {
const D3D11_UNORDERED_ACCESS_VIEW_DESC1* pDesc,
ID3D11UnorderedAccessView1** ppUAView);
HRESULT STDMETHODCALLTYPE CreateUnorderedAccessViewBase(
ID3D11Resource* pResource,
const D3D11_UNORDERED_ACCESS_VIEW_DESC1* pDesc,
ID3D11UnorderedAccessView1** ppUAView);
HRESULT STDMETHODCALLTYPE CreateRenderTargetView(
ID3D11Resource* pResource,
const D3D11_RENDER_TARGET_VIEW_DESC* pDesc,
@ -127,6 +148,11 @@ namespace dxvk {
const D3D11_RENDER_TARGET_VIEW_DESC1* pDesc,
ID3D11RenderTargetView1** ppRTView);
HRESULT STDMETHODCALLTYPE CreateRenderTargetViewBase(
ID3D11Resource* pResource,
const D3D11_RENDER_TARGET_VIEW_DESC1* pDesc,
ID3D11RenderTargetView1** ppRTView);
HRESULT STDMETHODCALLTYPE CreateDepthStencilView(
ID3D11Resource* pResource,
const D3D11_DEPTH_STENCIL_VIEW_DESC* pDesc,
@ -225,6 +251,10 @@ namespace dxvk {
const D3D11_QUERY_DESC1* pQueryDesc,
ID3D11Query1** ppQuery);
HRESULT STDMETHODCALLTYPE CreateQueryBase(
const D3D11_QUERY_DESC1* pQueryDesc,
ID3D11Query1** ppQuery);
HRESULT STDMETHODCALLTYPE CreatePredicate(
const D3D11_QUERY_DESC* pPredicateDesc,
ID3D11Predicate** ppPredicate);
@ -391,8 +421,21 @@ namespace dxvk {
return m_dxvkDevice;
}
void FlushInitContext();
void FlushInitCommands() {
m_initializer->FlushCsChunk();
}
void NotifyContextFlush() {
m_initializer->NotifyContextFlush();
}
void InitShaderIcb(
D3D11CommonShader* pShader,
size_t IcbSize,
const void* pIcbData) {
return m_initializer->InitShaderIcb(pShader, IcbSize, pIcbData);
}
VkPipelineStageFlags GetEnabledShaderStages() const {
return m_dxvkDevice->getShaderPipelineStages();
}
@ -434,6 +477,18 @@ namespace dxvk {
static DxvkDeviceFeatures GetDeviceFeatures(
const Rc<DxvkAdapter>& Adapter);
DxvkBarrierControlFlags GetOptionsBarrierControlFlags() {
DxvkBarrierControlFlags barrierControl = 0u;
if (m_d3d11Options.relaxedBarriers)
barrierControl.set(DxvkBarrierControl::ComputeAllowWriteOnlyOverlap);
if (m_d3d11Options.relaxedBarriers || m_d3d11Options.relaxedGraphicsBarriers)
barrierControl.set(DxvkBarrierControl::GraphicsAllowReadWriteOverlap);
return barrierControl;
}
private:
@ -580,7 +635,14 @@ namespace dxvk {
ID3D11ShaderResourceView* HandleToSrvNVX(
uint32_t Handle);
bool LockImage(
const Rc<DxvkImage>& Image,
VkImageUsageFlags Usage);
void LockBuffer(
const Rc<DxvkBuffer>& Buffer);
dxvk::mutex m_mapLock;
std::unordered_map<uint32_t, ID3D11SamplerState*> m_samplerHandleToPtr;
std::unordered_map<uint32_t, ID3D11ShaderResourceView*> m_srvHandleToPtr;
@ -697,6 +759,66 @@ namespace dxvk {
};
/**
* \brief Nvidia Reflex interop
*/
class D3D11ReflexDevice : public ID3DLowLatencyDevice {
public:
D3D11ReflexDevice(
D3D11DXGIDevice* pContainer,
D3D11Device* pDevice);
~D3D11ReflexDevice();
ULONG STDMETHODCALLTYPE AddRef();
ULONG STDMETHODCALLTYPE Release();
HRESULT STDMETHODCALLTYPE QueryInterface(
REFIID riid,
void** ppvObject);
BOOL STDMETHODCALLTYPE SupportsLowLatency();
HRESULT STDMETHODCALLTYPE LatencySleep();
HRESULT STDMETHODCALLTYPE SetLatencySleepMode(
BOOL LowLatencyEnable,
BOOL LowLatencyBoost,
UINT32 MinIntervalUs);
HRESULT STDMETHODCALLTYPE SetLatencyMarker(
UINT64 FrameId,
UINT32 MarkerType);
HRESULT STDMETHODCALLTYPE GetLatencyInfo(
D3D_LOW_LATENCY_RESULTS* pLowLatencyResults);
void RegisterLatencyTracker(
Rc<DxvkLatencyTracker> Tracker);
void UnregisterLatencyTracker(
Rc<DxvkLatencyTracker> Tracker);
private:
D3D11DXGIDevice* m_container;
D3D11Device* m_device;
bool m_reflexEnabled = false;
dxvk::mutex m_mutex;
bool m_enableLowLatency = false;
bool m_enableBoost = false;
uint64_t m_minIntervalUs = 0u;
Rc<DxvkReflexLatencyTrackerNv> m_tracker;
};
/**
* \brief DXVK swap chain factory
*/
@ -860,6 +982,7 @@ namespace dxvk {
D3D11DeviceExt m_d3d11DeviceExt;
D3D11VkInterop m_d3d11Interop;
D3D11VideoDevice m_d3d11Video;
D3D11ReflexDevice m_d3d11Reflex;
D3D11on12Device m_d3d11on12;
DXGIDXVKDevice m_metaDevice;

View file

@ -19,24 +19,28 @@ namespace dxvk {
}
HRESULT STDMETHODCALLTYPE GetPrivateData(
REFGUID guid,
UINT *pDataSize,
void *pData) final {
REFGUID guid,
UINT* pDataSize,
void* pData) final {
return m_privateData.getData(
guid, pDataSize, pData);
}
HRESULT STDMETHODCALLTYPE SetPrivateData(
REFGUID guid,
UINT DataSize,
const void *pData) final {
REFGUID guid,
UINT DataSize,
const void* pData) final {
// WKPDID_D3DDebugObjectName, can't use directly due to MSVC link errors
if (guid == GUID{0x429b8c22,0x9188,0x4b0c,0x87,0x42,0xac,0xb0,0xbf,0x85,0xc2,0x00})
SetDebugName(static_cast<const char*>(pData));
return m_privateData.setData(
guid, DataSize, pData);
}
HRESULT STDMETHODCALLTYPE SetPrivateDataInterface(
REFGUID guid,
const IUnknown *pUnknown) final {
REFGUID guid,
const IUnknown* pUnknown) final {
return m_privateData.setInterface(
guid, pUnknown);
}
@ -46,6 +50,10 @@ namespace dxvk {
*ppDevice = ref(GetParentInterface());
}
virtual void STDMETHODCALLTYPE SetDebugName(const char* pName) {
// No-op by default
}
protected:
ID3D11Device* GetParentInterface() const {

View file

@ -1,5 +1,6 @@
#include <cstring>
#include "d3d11_context_imm.h"
#include "d3d11_device.h"
#include "d3d11_initializer.h"
@ -9,9 +10,10 @@ namespace dxvk {
D3D11Device* pParent)
: m_parent(pParent),
m_device(pParent->GetDXVKDevice()),
m_context(m_device->createContext(DxvkContextType::Supplementary)) {
m_context->beginRecording(
m_device->createCommandList());
m_stagingBuffer(m_device, StagingBufferSize),
m_stagingSignal(new sync::Fence(0)),
m_csChunk(m_parent->AllocCsChunk(DxvkCsChunkFlag::SingleUse)) {
}
@ -20,13 +22,12 @@ namespace dxvk {
}
void D3D11Initializer::Flush() {
void D3D11Initializer::NotifyContextFlush() {
std::lock_guard<dxvk::mutex> lock(m_mutex);
if (m_transferCommands != 0)
FlushInternal();
NotifyContextFlushLocked();
}
void D3D11Initializer::InitBuffer(
D3D11Buffer* pBuffer,
const D3D11_SUBRESOURCE_DATA* pInitialData) {
@ -50,7 +51,7 @@ namespace dxvk {
else
InitDeviceLocalTexture(pTexture, pInitialData);
SyncKeyedMutex(pTexture->GetInterface());
SyncSharedTexture(pTexture);
}
@ -61,18 +62,45 @@ namespace dxvk {
if (counterView == nullptr)
return;
auto counterSlice = counterView->slice();
std::lock_guard<dxvk::mutex> lock(m_mutex);
m_transferCommands += 1;
const uint32_t zero = 0;
m_context->updateBuffer(
counterSlice.buffer(),
counterSlice.offset(),
sizeof(zero), &zero);
EmitCs([
cCounterSlice = DxvkBufferSlice(counterView)
] (DxvkContext* ctx) {
const uint32_t zero = 0;
ctx->updateBuffer(
cCounterSlice.buffer(),
cCounterSlice.offset(),
sizeof(zero), &zero);
});
}
FlushImplicit();
void D3D11Initializer::InitShaderIcb(
D3D11CommonShader* pShader,
size_t IcbSize,
const void* pIcbData) {
std::lock_guard<dxvk::mutex> lock(m_mutex);
m_transferCommands += 1;
auto icbSlice = pShader->GetIcb();
auto srcSlice = m_stagingBuffer.alloc(icbSlice.length());
std::memcpy(srcSlice.mapPtr(0), pIcbData, IcbSize);
if (IcbSize < icbSlice.length())
std::memset(srcSlice.mapPtr(IcbSize), 0, icbSlice.length() - IcbSize);
EmitCs([
cIcbSlice = std::move(icbSlice),
cSrcSlice = std::move(srcSlice)
] (DxvkContext* ctx) {
ctx->copyBuffer(cIcbSlice.buffer(), cIcbSlice.offset(),
cSrcSlice.buffer(), cSrcSlice.offset(), cIcbSlice.length());
});
ThrottleAllocationLocked();
}
@ -81,23 +109,33 @@ namespace dxvk {
const D3D11_SUBRESOURCE_DATA* pInitialData) {
std::lock_guard<dxvk::mutex> lock(m_mutex);
DxvkBufferSlice bufferSlice = pBuffer->GetBufferSlice();
Rc<DxvkBuffer> buffer = pBuffer->GetBuffer();
if (pInitialData != nullptr && pInitialData->pSysMem != nullptr) {
m_transferMemory += bufferSlice.length();
auto stagingSlice = m_stagingBuffer.alloc(buffer->info().size);
std::memcpy(stagingSlice.mapPtr(0), pInitialData->pSysMem, stagingSlice.length());
m_transferCommands += 1;
m_context->uploadBuffer(
bufferSlice.buffer(),
pInitialData->pSysMem);
EmitCs([
cBuffer = buffer,
cStagingSlice = std::move(stagingSlice)
] (DxvkContext* ctx) {
ctx->uploadBuffer(cBuffer,
cStagingSlice.buffer(),
cStagingSlice.offset());
});
} else {
m_transferCommands += 1;
m_context->initBuffer(
bufferSlice.buffer());
EmitCs([
cBuffer = buffer
] (DxvkContext* ctx) {
ctx->initBuffer(cBuffer);
});
}
FlushImplicit();
ThrottleAllocationLocked();
}
@ -107,18 +145,10 @@ namespace dxvk {
// If the buffer is mapped, we can write data directly
// to the mapped memory region instead of doing it on
// the GPU. Same goes for zero-initialization.
DxvkBufferSlice bufferSlice = pBuffer->GetBufferSlice();
if (pInitialData != nullptr && pInitialData->pSysMem != nullptr) {
std::memcpy(
bufferSlice.mapPtr(0),
pInitialData->pSysMem,
bufferSlice.length());
} else {
std::memset(
bufferSlice.mapPtr(0), 0,
bufferSlice.length());
}
if (pInitialData && pInitialData->pSysMem)
std::memcpy(pBuffer->GetMapPtr(), pInitialData->pSysMem, pBuffer->Desc()->ByteWidth);
else
std::memset(pBuffer->GetMapPtr(), 0, pBuffer->Desc()->ByteWidth);
}
@ -127,87 +157,96 @@ namespace dxvk {
const D3D11_SUBRESOURCE_DATA* pInitialData) {
std::lock_guard<dxvk::mutex> lock(m_mutex);
// Image migt be null if this is a staging resource
Rc<DxvkImage> image = pTexture->GetImage();
auto mapMode = pTexture->GetMapMode();
auto desc = pTexture->Desc();
VkFormat packedFormat = m_parent->LookupPackedFormat(desc->Format, pTexture->GetFormatMode()).Format;
auto formatInfo = lookupFormatInfo(packedFormat);
if (pInitialData != nullptr && pInitialData->pSysMem != nullptr) {
// pInitialData is an array that stores an entry for
// every single subresource. Since we will define all
// subresources, this counts as initialization.
for (uint32_t layer = 0; layer < desc->ArraySize; layer++) {
for (uint32_t level = 0; level < desc->MipLevels; level++) {
const uint32_t id = D3D11CalcSubresource(
level, layer, desc->MipLevels);
// Compute data size for all subresources and allocate staging buffer memory
DxvkBufferSlice stagingSlice;
VkOffset3D mipLevelOffset = { 0, 0, 0 };
VkExtent3D mipLevelExtent = pTexture->MipLevelExtent(level);
if (pTexture->HasImage()) {
VkDeviceSize dataSize = 0u;
for (uint32_t mip = 0; mip < image->info().mipLevels; mip++) {
dataSize += image->info().numLayers * align(util::computeImageDataSize(
packedFormat, image->mipLevelExtent(mip), formatInfo->aspectMask), CACHE_LINE_SIZE);
}
stagingSlice = m_stagingBuffer.alloc(dataSize);
}
// Copy initial data for each subresource into the staging buffer,
// as well as the mapped per-subresource buffers if available.
VkDeviceSize dataOffset = 0u;
for (uint32_t mip = 0; mip < desc->MipLevels; mip++) {
for (uint32_t layer = 0; layer < desc->ArraySize; layer++) {
uint32_t index = D3D11CalcSubresource(mip, layer, desc->MipLevels);
VkExtent3D mipLevelExtent = pTexture->MipLevelExtent(mip);
if (pTexture->HasImage()) {
VkDeviceSize mipSizePerLayer = util::computeImageDataSize(
packedFormat, image->mipLevelExtent(mip), formatInfo->aspectMask);
if (mapMode != D3D11_COMMON_TEXTURE_MAP_MODE_STAGING) {
m_transferCommands += 1;
m_transferMemory += pTexture->GetSubresourceLayout(formatInfo->aspectMask, id).Size;
VkImageSubresourceLayers subresourceLayers;
subresourceLayers.aspectMask = formatInfo->aspectMask;
subresourceLayers.mipLevel = level;
subresourceLayers.baseArrayLayer = layer;
subresourceLayers.layerCount = 1;
if (formatInfo->aspectMask != (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) {
m_context->uploadImage(
image, subresourceLayers,
pInitialData[id].pSysMem,
pInitialData[id].SysMemPitch,
pInitialData[id].SysMemSlicePitch);
} else {
m_context->updateDepthStencilImage(
image, subresourceLayers,
VkOffset2D { mipLevelOffset.x, mipLevelOffset.y },
VkExtent2D { mipLevelExtent.width, mipLevelExtent.height },
pInitialData[id].pSysMem,
pInitialData[id].SysMemPitch,
pInitialData[id].SysMemSlicePitch,
packedFormat);
}
util::packImageData(stagingSlice.mapPtr(dataOffset),
pInitialData[index].pSysMem, pInitialData[index].SysMemPitch, pInitialData[index].SysMemSlicePitch,
0, 0, pTexture->GetVkImageType(), mipLevelExtent, 1, formatInfo, formatInfo->aspectMask);
dataOffset += align(mipSizePerLayer, CACHE_LINE_SIZE);
}
if (mapMode != D3D11_COMMON_TEXTURE_MAP_MODE_NONE) {
util::packImageData(pTexture->GetMappedBuffer(id)->mapPtr(0),
pInitialData[id].pSysMem, pInitialData[id].SysMemPitch, pInitialData[id].SysMemSlicePitch,
if (pTexture->HasPersistentBuffers()) {
util::packImageData(pTexture->GetMapPtr(index, 0),
pInitialData[index].pSysMem, pInitialData[index].SysMemPitch, pInitialData[index].SysMemSlicePitch,
0, 0, pTexture->GetVkImageType(), mipLevelExtent, 1, formatInfo, formatInfo->aspectMask);
}
}
}
// Upload all subresources of the image in one go
if (pTexture->HasImage()) {
EmitCs([
cImage = std::move(image),
cStagingSlice = std::move(stagingSlice),
cFormat = packedFormat
] (DxvkContext* ctx) {
ctx->uploadImage(cImage,
cStagingSlice.buffer(),
cStagingSlice.offset(),
CACHE_LINE_SIZE, cFormat);
});
}
} else {
if (mapMode != D3D11_COMMON_TEXTURE_MAP_MODE_STAGING) {
if (pTexture->HasImage()) {
m_transferCommands += 1;
// While the Microsoft docs state that resource contents are
// undefined if no initial data is provided, some applications
// expect a resource to be pre-cleared.
VkImageSubresourceRange subresources;
subresources.aspectMask = formatInfo->aspectMask;
subresources.baseMipLevel = 0;
subresources.levelCount = desc->MipLevels;
subresources.baseArrayLayer = 0;
subresources.layerCount = desc->ArraySize;
m_context->initImage(image, subresources, VK_IMAGE_LAYOUT_UNDEFINED);
EmitCs([
cImage = std::move(image)
] (DxvkContext* ctx) {
ctx->initImage(cImage,
cImage->getAvailableSubresources(),
VK_IMAGE_LAYOUT_UNDEFINED);
});
}
if (mapMode != D3D11_COMMON_TEXTURE_MAP_MODE_NONE) {
if (pTexture->HasPersistentBuffers()) {
for (uint32_t i = 0; i < pTexture->CountSubresources(); i++) {
auto buffer = pTexture->GetMappedBuffer(i);
std::memset(buffer->mapPtr(0), 0, buffer->info().size);
auto layout = pTexture->GetSubresourceLayout(formatInfo->aspectMask, i);
std::memset(pTexture->GetMapPtr(i, layout.Offset), 0, layout.Size);
}
}
}
FlushImplicit();
ThrottleAllocationLocked();
}
@ -215,38 +254,47 @@ namespace dxvk {
D3D11CommonTexture* pTexture,
const D3D11_SUBRESOURCE_DATA* pInitialData) {
Rc<DxvkImage> image = pTexture->GetImage();
auto formatInfo = image->formatInfo();
for (uint32_t layer = 0; layer < pTexture->Desc()->ArraySize; layer++) {
for (uint32_t level = 0; level < pTexture->Desc()->MipLevels; level++) {
uint32_t subresourceIndex = D3D11CalcSubresource(level, layer, pTexture->Desc()->MipLevels);
for (uint32_t layer = 0; layer < image->info().numLayers; layer++) {
for (uint32_t level = 0; level < image->info().mipLevels; level++) {
VkImageSubresource subresource;
subresource.aspectMask = image->formatInfo()->aspectMask;
subresource.aspectMask = formatInfo->aspectMask;
subresource.mipLevel = level;
subresource.arrayLayer = layer;
VkExtent3D blockCount = util::computeBlockCount(
image->mipLevelExtent(level),
image->formatInfo()->blockSize);
image->mipLevelExtent(level), formatInfo->blockSize);
VkSubresourceLayout layout = image->querySubresourceLayout(subresource);
auto layout = pTexture->GetSubresourceLayout(
subresource.aspectMask, subresourceIndex);
auto initialData = pInitialData
? &pInitialData[D3D11CalcSubresource(level, layer, image->info().mipLevels)]
: nullptr;
if (pInitialData && pInitialData[subresourceIndex].pSysMem) {
const auto& initialData = pInitialData[subresourceIndex];
for (uint32_t z = 0; z < blockCount.depth; z++) {
for (uint32_t y = 0; y < blockCount.height; y++) {
auto size = blockCount.width * image->formatInfo()->elementSize;
auto dst = image->mapPtr(layout.offset + y * layout.rowPitch + z * layout.depthPitch);
for (uint32_t z = 0; z < blockCount.depth; z++) {
for (uint32_t y = 0; y < blockCount.height; y++) {
auto size = blockCount.width * formatInfo->elementSize;
auto dst = pTexture->GetMapPtr(subresourceIndex, layout.Offset
+ y * layout.RowPitch
+ z * layout.DepthPitch);
auto src = reinterpret_cast<const char*>(initialData.pSysMem)
+ y * initialData.SysMemPitch
+ z * initialData.SysMemSlicePitch;
if (initialData) {
auto src = reinterpret_cast<const char*>(initialData->pSysMem)
+ y * initialData->SysMemPitch
+ z * initialData->SysMemSlicePitch;
std::memcpy(dst, src, size);
} else {
std::memset(dst, 0, size);
if (size < layout.RowPitch)
std::memset(reinterpret_cast<char*>(dst) + size, 0, layout.RowPitch - size);
}
}
} else {
void* dst = pTexture->GetMapPtr(subresourceIndex, layout.Offset);
std::memset(dst, 0, layout.Size);
}
}
}
@ -254,46 +302,110 @@ namespace dxvk {
// Initialize the image on the GPU
std::lock_guard<dxvk::mutex> lock(m_mutex);
VkImageSubresourceRange subresources = image->getAvailableSubresources();
m_context->initImage(image, subresources, VK_IMAGE_LAYOUT_PREINITIALIZED);
EmitCs([
cImage = std::move(image)
] (DxvkContext* ctx) {
ctx->initImage(cImage,
cImage->getAvailableSubresources(),
VK_IMAGE_LAYOUT_PREINITIALIZED);
});
m_transferCommands += 1;
FlushImplicit();
ThrottleAllocationLocked();
}
void D3D11Initializer::InitTiledTexture(
D3D11CommonTexture* pTexture) {
m_context->initSparseImage(pTexture->GetImage());
std::lock_guard<dxvk::mutex> lock(m_mutex);
EmitCs([
cImage = pTexture->GetImage()
] (DxvkContext* ctx) {
ctx->initSparseImage(cImage);
});
m_transferCommands += 1;
FlushImplicit();
ThrottleAllocationLocked();
}
void D3D11Initializer::FlushImplicit() {
if (m_transferCommands > MaxTransferCommands
|| m_transferMemory > MaxTransferMemory)
FlushInternal();
void D3D11Initializer::ThrottleAllocationLocked() {
DxvkStagingBufferStats stats = m_stagingBuffer.getStatistics();
// If the amount of memory in flight exceeds the limit, stall the
// calling thread and wait for some memory to actually get released.
VkDeviceSize stagingMemoryInFlight = stats.allocatedTotal - m_stagingSignal->value();
if (stagingMemoryInFlight > MaxMemoryInFlight) {
ExecuteFlushLocked();
m_stagingSignal->wait(stats.allocatedTotal - MaxMemoryInFlight);
} else if (m_transferCommands >= MaxCommandsPerSubmission || stats.allocatedSinceLastReset >= MaxMemoryPerSubmission) {
// Flush pending commands if there are a lot of updates in flight
// to keep both execution time and staging memory in check.
ExecuteFlushLocked();
}
}
void D3D11Initializer::FlushInternal() {
m_context->flushCommandList(nullptr);
m_transferCommands = 0;
m_transferMemory = 0;
void D3D11Initializer::ExecuteFlush() {
std::lock_guard lock(m_mutex);
ExecuteFlushLocked();
}
void D3D11Initializer::SyncKeyedMutex(ID3D11Resource *pResource) {
Com<IDXGIKeyedMutex> keyedMutex;
if (pResource->QueryInterface(__uuidof(IDXGIKeyedMutex), reinterpret_cast<void**>(&keyedMutex)) != S_OK)
void D3D11Initializer::ExecuteFlushLocked() {
DxvkStagingBufferStats stats = m_stagingBuffer.getStatistics();
EmitCs([
cSignal = m_stagingSignal,
cSignalValue = stats.allocatedTotal
] (DxvkContext* ctx) {
ctx->signal(cSignal, cSignalValue);
ctx->flushCommandList(nullptr, nullptr);
});
FlushCsChunk();
NotifyContextFlushLocked();
}
void D3D11Initializer::SyncSharedTexture(D3D11CommonTexture* pResource) {
if (!(pResource->Desc()->MiscFlags & (D3D11_RESOURCE_MISC_SHARED | D3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX | D3D11_RESOURCE_MISC_SHARED_NTHANDLE)))
return;
keyedMutex->AcquireSync(0, 0);
keyedMutex->ReleaseSync(0);
// Ensure that initialization commands are submitted and waited on before
// returning control to the application in order to avoid race conditions
// in case the texture is used immediately on a secondary device.
if (pResource->HasImage()) {
ExecuteFlush();
m_device->waitForResource(*pResource->GetImage(), DxvkAccess::Write);
}
// If a keyed mutex is used, initialize that to the correct state as well.
Com<IDXGIKeyedMutex> keyedMutex;
if (SUCCEEDED(pResource->GetInterface()->QueryInterface(
__uuidof(IDXGIKeyedMutex), reinterpret_cast<void**>(&keyedMutex)))) {
keyedMutex->AcquireSync(0, 0);
keyedMutex->ReleaseSync(0);
}
}
}
void D3D11Initializer::FlushCsChunkLocked() {
m_parent->GetContext()->InjectCsChunk(DxvkCsQueue::HighPriority, std::move(m_csChunk), false);
m_csChunk = m_parent->AllocCsChunk(DxvkCsChunkFlag::SingleUse);
}
void D3D11Initializer::NotifyContextFlushLocked() {
m_stagingBuffer.reset();
m_transferCommands = 0;
}
}

View file

@ -1,7 +1,11 @@
#pragma once
#include "../dxvk/dxvk_staging.h"
#include "d3d11_buffer.h"
#include "d3d11_shader.h"
#include "d3d11_texture.h"
#include "d3d11_view_uav.h"
namespace dxvk {
@ -16,16 +20,33 @@ namespace dxvk {
* zero-initialization for buffers and images.
*/
class D3D11Initializer {
constexpr static size_t MaxTransferMemory = 32 * 1024 * 1024;
constexpr static size_t MaxTransferCommands = 512;
// Use a staging buffer with a linear allocator to service small uploads
constexpr static VkDeviceSize StagingBufferSize = 1ull << 20;
public:
// Maximum number of copy and clear commands to record before flushing
constexpr static size_t MaxCommandsPerSubmission = 512u;
// Maximum amount of staging memory to allocate before flushing
constexpr static size_t MaxMemoryPerSubmission = (env::is32BitHostPlatform() ? 12u : 48u) << 20;
// Maximum amount of memory in flight. If there are pending uploads while
// this limit is exceeded, further initialization will be stalled.
constexpr static size_t MaxMemoryInFlight = 3u * MaxMemoryPerSubmission;
D3D11Initializer(
D3D11Device* pParent);
~D3D11Initializer();
void Flush();
void FlushCsChunk() {
std::lock_guard<dxvk::mutex> lock(m_csMutex);
if (!m_csChunk->empty())
FlushCsChunkLocked();
}
void NotifyContextFlush();
void InitBuffer(
D3D11Buffer* pBuffer,
@ -38,16 +59,25 @@ namespace dxvk {
void InitUavCounter(
D3D11UnorderedAccessView* pUav);
void InitShaderIcb(
D3D11CommonShader* pShader,
size_t IcbSize,
const void* pIcbData);
private:
dxvk::mutex m_mutex;
D3D11Device* m_parent;
Rc<DxvkDevice> m_device;
Rc<DxvkContext> m_context;
DxvkStagingBuffer m_stagingBuffer;
Rc<sync::Fence> m_stagingSignal;
size_t m_transferCommands = 0;
size_t m_transferMemory = 0;
dxvk::mutex m_csMutex;
DxvkCsChunkRef m_csChunk;
void InitDeviceLocalBuffer(
D3D11Buffer* pBuffer,
@ -68,11 +98,30 @@ namespace dxvk {
void InitTiledTexture(
D3D11CommonTexture* pTexture);
void FlushImplicit();
void FlushInternal();
void ThrottleAllocationLocked();
void SyncKeyedMutex(ID3D11Resource *pResource);
void ExecuteFlush();
void ExecuteFlushLocked();
void SyncSharedTexture(
D3D11CommonTexture* pResource);
void FlushCsChunkLocked();
void NotifyContextFlushLocked();
template<typename Cmd>
void EmitCs(Cmd&& command) {
std::lock_guard<dxvk::mutex> lock(m_csMutex);
if (unlikely(!m_csChunk->push(command))) {
FlushCsChunkLocked();
m_csChunk->push(command);
}
}
};
}
}

View file

@ -24,7 +24,9 @@ enum D3D11_VK_EXTENSION : uint32_t {
*/
enum D3D11_VK_BARRIER_CONTROL : uint32_t {
D3D11_VK_BARRIER_CONTROL_IGNORE_WRITE_AFTER_WRITE = 1 << 0,
D3D11_VK_BARRIER_CONTROL_IGNORE_GRAPHICS_UAV = 1 << 1,
// Removed:
// D3D11_VK_BARRIER_CONTROL_IGNORE_GRAPHICS_UAV = 1 << 1,
};
@ -183,10 +185,70 @@ ID3D11VkExtContext1 : public ID3D11VkExtContext {
};
/**
* \brief Frame reports used for Reflex interop
*/
struct D3D_LOW_LATENCY_FRAME_REPORT
{
UINT64 frameID;
UINT64 inputSampleTime;
UINT64 simStartTime;
UINT64 simEndTime;
UINT64 renderSubmitStartTime;
UINT64 renderSubmitEndTime;
UINT64 presentStartTime;
UINT64 presentEndTime;
UINT64 driverStartTime;
UINT64 driverEndTime;
UINT64 osRenderQueueStartTime;
UINT64 osRenderQueueEndTime;
UINT64 gpuRenderStartTime;
UINT64 gpuRenderEndTime;
UINT32 gpuActiveRenderTimeUs;
UINT32 gpuFrameTimeUs;
UINT8 rsvd[120];
};
/**
* \brief Data structure used for Reflex interop
*/
struct D3D_LOW_LATENCY_RESULTS
{
UINT32 version;
D3D_LOW_LATENCY_FRAME_REPORT frameReports[64];
UINT8 rsvd[32];
};
/**
* \brief D3D interop interface for Nvidia Reflex
*/
MIDL_INTERFACE("f3112584-41f9-348d-a59b-00b7e1d285d6")
ID3DLowLatencyDevice : public IUnknown {
virtual BOOL STDMETHODCALLTYPE SupportsLowLatency() = 0;
virtual HRESULT STDMETHODCALLTYPE LatencySleep() = 0;
virtual HRESULT STDMETHODCALLTYPE SetLatencySleepMode(
BOOL LowLatencyEnable,
BOOL LowLatencyBoost,
UINT32 MinIntervalUs) = 0;
virtual HRESULT STDMETHODCALLTYPE SetLatencyMarker(
UINT64 FrameId,
UINT32 MarkerType) = 0;
virtual HRESULT STDMETHODCALLTYPE GetLatencyInfo(
D3D_LOW_LATENCY_RESULTS* pLowLatencyResults) = 0;
};
#ifndef _MSC_VER
__CRT_UUID_DECL(ID3D11VkExtShader, 0xbb8a4fb9,0x3935,0x4762,0xb4,0x4b,0x35,0x18,0x9a,0x26,0x41,0x4a);
__CRT_UUID_DECL(ID3D11VkExtDevice, 0x8a6e3c42,0xf74c,0x45b7,0x82,0x65,0xa2,0x31,0xb6,0x77,0xca,0x17);
__CRT_UUID_DECL(ID3D11VkExtDevice1, 0xcfcf64ef,0x9586,0x46d0,0xbc,0xa4,0x97,0xcf,0x2c,0xa6,0x1b,0x06);
__CRT_UUID_DECL(ID3D11VkExtContext, 0xfd0bca13,0x5cb6,0x4c3a,0x98,0x7e,0x47,0x50,0xde,0x2c,0xa7,0x91);
__CRT_UUID_DECL(ID3D11VkExtContext1, 0x874b09b2,0xae0b,0x41d8,0x84,0x76,0x5f,0x3b,0x7a,0x0e,0x87,0x9d);
__CRT_UUID_DECL(ID3DLowLatencyDevice, 0xf3112584,0x41f9,0x348d,0xa5,0x9b,0x00,0xb7,0xe1,0xd2,0x85,0xd6);
#endif

View file

@ -147,4 +147,11 @@ namespace dxvk {
}
}
HRESULT STDMETHODCALLTYPE D3D11on12Device::GetD3D12Device(
REFIID riid,
void** ppvDevice) {
return m_d3d12Queue->GetDevice(riid, ppvDevice);
}
}

View file

@ -4,6 +4,21 @@
#include "../util/log/log.h"
/**
* \brief Declaration of the ID3D11On12Device1 interface
*
* Various different headers that we need to be compatible with
* can't seem to agree on the signature of GetD3D12Device, and
* older wine/mingw headers don't support this interface at all.
*/
MIDL_INTERFACE("bdb64df4-ea2f-4c70-b861-aaab1258bb5d")
ID3D11On12Device1_DXVK : public ID3D11On12Device {
virtual HRESULT STDMETHODCALLTYPE GetD3D12Device(
REFIID riid,
void** ppvDevice) = 0;
};
namespace dxvk {
class D3D11Device;
@ -22,7 +37,7 @@ namespace dxvk {
};
class D3D11on12Device : public ID3D11On12Device {
class D3D11on12Device : public ID3D11On12Device1_DXVK {
public:
@ -58,6 +73,10 @@ namespace dxvk {
ID3D11Resource* const* ppResources,
UINT ResourceCount);
HRESULT STDMETHODCALLTYPE GetD3D12Device(
REFIID riid,
void** ppvDevice);
bool Is11on12Device() const {
return m_d3d12Device != nullptr;
}
@ -73,3 +92,7 @@ namespace dxvk {
};
}
#ifndef _MSC_VER
__CRT_UUID_DECL(ID3D11On12Device1_DXVK, 0xbdb64df4,0xea2f,0x4c70,0xb8,0x61,0xaa,0xab,0x12,0x58,0xbb,0x5d);
#endif

View file

@ -13,11 +13,11 @@ namespace dxvk {
}
D3D11Options::D3D11Options(const Config& config) {
this->dcSingleUseMode = config.getOption<bool>("d3d11.dcSingleUseMode", true);
this->zeroInitWorkgroupMemory = config.getOption<bool>("d3d11.zeroInitWorkgroupMemory", false);
this->forceVolatileTgsmAccess = config.getOption<bool>("d3d11.forceVolatileTgsmAccess", false);
this->forceComputeUavBarriers = config.getOption<bool>("d3d11.forceComputeUavBarriers", false);
this->relaxedBarriers = config.getOption<bool>("d3d11.relaxedBarriers", false);
this->ignoreGraphicsBarriers = config.getOption<bool>("d3d11.ignoreGraphicsBarriers", false);
this->relaxedGraphicsBarriers = config.getOption<bool>("d3d11.relaxedGraphicsBarriers", false);
this->maxTessFactor = config.getOption<int32_t>("d3d11.maxTessFactor", 0);
this->samplerAnisotropy = config.getOption<int32_t>("d3d11.samplerAnisotropy", -1);
this->samplerLodBias = config.getOption<float>("d3d11.samplerLodBias", 0.0f);
@ -28,24 +28,13 @@ namespace dxvk {
this->disableMsaa = config.getOption<bool>("d3d11.disableMsaa", false);
this->enableContextLock = config.getOption<bool>("d3d11.enableContextLock", false);
this->deferSurfaceCreation = config.getOption<bool>("dxgi.deferSurfaceCreation", false);
this->numBackBuffers = config.getOption<int32_t>("dxgi.numBackBuffers", 0);
this->maxFrameLatency = config.getOption<int32_t>("dxgi.maxFrameLatency", 0);
this->maxFrameRate = config.getOption<int32_t>("dxgi.maxFrameRate", 0);
this->exposeDriverCommandLists = config.getOption<bool>("d3d11.exposeDriverCommandLists", true);
this->reproducibleCommandStream = config.getOption<bool>("d3d11.reproducibleCommandStream", false);
// Clamp LOD bias so that people don't abuse this in unintended ways
this->samplerLodBias = dxvk::fclamp(this->samplerLodBias, -2.0f, 1.0f);
int32_t maxImplicitDiscardSize = config.getOption<int32_t>("d3d11.maxImplicitDiscardSize", 256);
this->maxImplicitDiscardSize = maxImplicitDiscardSize >= 0
? VkDeviceSize(maxImplicitDiscardSize) << 10
: VkDeviceSize(~0ull);
int32_t maxDynamicImageBufferSize = config.getOption<int32_t>("d3d11.maxDynamicImageBufferSize", -1);
this->maxDynamicImageBufferSize = maxDynamicImageBufferSize >= 0
? VkDeviceSize(maxDynamicImageBufferSize) << 10
: VkDeviceSize(~0ull);
auto cachedDynamicResources = config.getOption<std::string>("d3d11.cachedDynamicResources", std::string());
if (IsAPITracingDXGI()) {
@ -72,4 +61,4 @@ namespace dxvk {
this->shaderDumpPath = env::getEnvVar("DXVK_SHADER_DUMP_PATH");
}
}
}

View file

@ -13,113 +13,105 @@ namespace dxvk {
struct D3D11Options {
D3D11Options(const Config& config);
/// Enables speed hack for mapping on deferred contexts
///
/// This can substantially speed up some games, but may
/// cause issues if the game submits command lists more
/// than once.
bool dcSingleUseMode;
/// Zero-initialize workgroup memory
///
/// Workargound for games that don't initialize
/// TGSM in compute shaders before reading it.
bool zeroInitWorkgroupMemory;
bool zeroInitWorkgroupMemory = false;
/// Force thread-group shared memory accesses to be volatile
///
/// Workaround for compute shaders that read and
/// write from the same shared memory location
/// without explicit synchronization.
bool forceVolatileTgsmAccess;
bool forceVolatileTgsmAccess = false;
/// Force UAV synchronization insided compute shaders
///
/// Workaround for compute shaders that access overlapping
/// memory regions within a UAV without proper workgroup
/// synchroniation. Will have a negative performance impact.
bool forceComputeUavBarriers = false;
/// Use relaxed memory barriers
///
/// May improve performance in some games,
/// but might also cause rendering issues.
bool relaxedBarriers;
bool relaxedBarriers = false;
/// Ignore graphics barriers
///
/// May improve performance in some games,
/// but might also cause rendering issues.
bool ignoreGraphicsBarriers;
bool relaxedGraphicsBarriers = false;
/// Maximum tessellation factor.
///
/// Limits tessellation factors in tessellation
/// control shaders. Values from 8 to 64 are
/// supported, other values will be ignored.
int32_t maxTessFactor;
int32_t maxTessFactor = 0;
/// Anisotropic filter override
///
/// Enforces anisotropic filtering with the
/// given anisotropy value for all samplers.
int32_t samplerAnisotropy;
int32_t samplerAnisotropy = -1;
/// Mipmap LOD bias
///
/// Enforces the given LOD bias for all samplers.
float samplerLodBias;
float samplerLodBias = 0.0f;
/// Clamps negative LOD bias
bool clampNegativeLodBias;
bool clampNegativeLodBias = false;
/// Declare vertex positions in shaders as invariant
bool invariantPosition;
bool invariantPosition = true;
/// Enable float control bits
bool floatControls;
/// Back buffer count for the Vulkan swap chain.
/// Overrides DXGI_SWAP_CHAIN_DESC::BufferCount.
int32_t numBackBuffers;
bool floatControls = true;
/// Override maximum frame latency if the app specifies
/// a higher value. May help with frame timing issues.
int32_t maxFrameLatency;
/// Limit frame rate
int32_t maxFrameRate;
/// Limit discardable resource size
VkDeviceSize maxImplicitDiscardSize;
/// Limit size of buffer-mapped images
VkDeviceSize maxDynamicImageBufferSize;
int32_t maxFrameLatency = 0;
/// Defer surface creation until first present call. This
/// fixes issues with games that create multiple swap chains
/// for a single window that may interfere with each other.
bool deferSurfaceCreation;
bool deferSurfaceCreation = false;
/// Enables sample rate shading by interpolating fragment shader
/// inputs at the sample location rather than pixel center,
/// unless otherwise specified by the application.
bool forceSampleRateShading;
bool forceSampleRateShading = false;
/// Forces the sample count of all textures to be 1, and
/// performs the required shader and resolve fixups.
bool disableMsaa;
bool disableMsaa = false;
/// Dynamic resources with the given bind flags will be allocated
/// in cached system memory. Enabled automatically when recording
/// an api trace.
uint32_t cachedDynamicResources;
uint32_t cachedDynamicResources = 0;
/// Always lock immediate context on every API call. May be
/// useful for debugging purposes or when applications have
/// race conditions.
bool enableContextLock;
bool enableContextLock = false;
/// Whether to expose the driver command list feature. Enabled by
/// default and generally beneficial, but some games may assume that
/// this is not supported when running on an AMD GPU.
bool exposeDriverCommandLists;
bool exposeDriverCommandLists = true;
/// Ensure that for the same D3D commands the output VK commands
/// don't change between runs. Useful for comparative benchmarking,
/// can negatively affect performance.
bool reproducibleCommandStream = false;
/// Shader dump path
std::string shaderDumpPath;
};
}
}

View file

@ -103,8 +103,8 @@ namespace dxvk {
D3D11_VK_QUERY_STATE m_state;
std::array<Rc<DxvkGpuQuery>, MaxGpuQueries> m_query;
std::array<Rc<DxvkGpuEvent>, MaxGpuEvents> m_event;
std::array<Rc<DxvkQuery>, MaxGpuQueries> m_query;
std::array<Rc<DxvkEvent>, MaxGpuEvents> m_event;
D3D10Query m_d3d10;

View file

@ -95,7 +95,9 @@ namespace dxvk {
D3D11CommonTexture* texture = GetCommonTexture(m_resource);
Rc<DxvkDevice> dxvkDevice = m_device->GetDXVKDevice();
VkResult vr = dxvkDevice->vkd()->wine_vkAcquireKeyedMutex(dxvkDevice->handle(), texture->GetImage()->memory().memory(), Key, dwMilliseconds);
VkResult vr = dxvkDevice->vkd()->wine_vkAcquireKeyedMutex(
dxvkDevice->handle(), texture->GetImage()->getMemoryInfo().memory, Key, dwMilliseconds);
switch (vr) {
case VK_SUCCESS: return S_OK;
case VK_TIMEOUT: return WAIT_TIMEOUT;
@ -120,12 +122,13 @@ namespace dxvk {
Logger::warn("D3D11DXGIKeyedMutex::ReleaseSync: Called without context locking enabled.");
D3D10DeviceLock lock = context->LockContext();
context->WaitForResource(texture->GetImage(), DxvkCsThread::SynchronizeAll, D3D11_MAP_READ_WRITE, 0);
context->WaitForResource(*texture->GetImage(), DxvkCsThread::SynchronizeAll, D3D11_MAP_READ_WRITE, 0);
}
return dxvkDevice->vkd()->wine_vkReleaseKeyedMutex(dxvkDevice->handle(), texture->GetImage()->memory().memory(), Key) == VK_SUCCESS
? S_OK
: DXGI_ERROR_INVALID_CALL;
VkResult vr = dxvkDevice->vkd()->wine_vkReleaseKeyedMutex(
dxvkDevice->handle(), texture->GetImage()->getMemoryInfo().memory, Key);
return vr == VK_SUCCESS ? S_OK : DXGI_ERROR_INVALID_CALL;
}
D3D11DXGIResource::D3D11DXGIResource(

View file

@ -9,63 +9,58 @@ namespace dxvk {
const D3D11_SAMPLER_DESC& desc)
: D3D11StateObject<ID3D11SamplerState>(device),
m_desc(desc), m_d3d10(this) {
DxvkSamplerCreateInfo info;
DxvkSamplerKey info = { };
// While D3D11_FILTER is technically an enum, its value bits
// can be used to decode the filter properties more efficiently.
const uint32_t filterBits = uint32_t(desc.Filter);
info.magFilter = (filterBits & 0x04) ? VK_FILTER_LINEAR : VK_FILTER_NEAREST;
info.minFilter = (filterBits & 0x10) ? VK_FILTER_LINEAR : VK_FILTER_NEAREST;
VkFilter minFilter = (filterBits & 0x10) ? VK_FILTER_LINEAR : VK_FILTER_NEAREST;
VkFilter magFilter = (filterBits & 0x04) ? VK_FILTER_LINEAR : VK_FILTER_NEAREST;
info.setFilter(minFilter, magFilter,
(filterBits & 0x01) ? VK_SAMPLER_MIPMAP_MODE_LINEAR : VK_SAMPLER_MIPMAP_MODE_NEAREST);
// Enforce LOD bias specified in the device options
float lodBias = desc.MipLODBias;
if (minFilter == VK_FILTER_LINEAR && magFilter == VK_FILTER_LINEAR) {
lodBias += device->GetOptions()->samplerLodBias;
if (device->GetOptions()->clampNegativeLodBias)
lodBias = std::max(lodBias, 0.0f);
}
info.setLodRange(desc.MinLOD, desc.MaxLOD, lodBias);
// Enforce anisotropy specified in the device options
uint32_t anisotropy = (filterBits & 0x40) ? desc.MaxAnisotropy : 0u;
int32_t samplerAnisotropyOption = device->GetOptions()->samplerAnisotropy;
if (samplerAnisotropyOption >= 0 && minFilter == VK_FILTER_LINEAR)
anisotropy = samplerAnisotropyOption;
info.setAniso(anisotropy);
// Set up the remaining properties, which are
// stored directly in the sampler description
info.mipmapMode = (filterBits & 0x01) ? VK_SAMPLER_MIPMAP_MODE_LINEAR : VK_SAMPLER_MIPMAP_MODE_NEAREST;
info.mipmapLodBias = desc.MipLODBias;
info.mipmapLodMin = desc.MinLOD;
info.mipmapLodMax = desc.MaxLOD;
info.useAnisotropy = (filterBits & 0x40) ? VK_TRUE : VK_FALSE;
info.maxAnisotropy = float(desc.MaxAnisotropy);
info.addressModeU = DecodeAddressMode(desc.AddressU);
info.addressModeV = DecodeAddressMode(desc.AddressV);
info.addressModeW = DecodeAddressMode(desc.AddressW);
info.compareToDepth = (filterBits & 0x180) == 0x80 ? VK_TRUE : VK_FALSE;
info.compareOp = DecodeCompareOp(desc.ComparisonFunc);
info.setAddressModes(
DecodeAddressMode(desc.AddressU),
DecodeAddressMode(desc.AddressV),
DecodeAddressMode(desc.AddressW));
info.reductionMode = DecodeReductionMode(filterBits);
info.setDepthCompare((filterBits & 0x180) == 0x80,
DecodeCompareOp(desc.ComparisonFunc));
info.setReduction(DecodeReductionMode(filterBits));
for (uint32_t i = 0; i < 4; i++)
info.borderColor.float32[i] = desc.BorderColor[i];
info.usePixelCoord = VK_FALSE; // Not supported in D3D11
info.nonSeamless = VK_FALSE;
// Make sure to use a valid anisotropy value
if (desc.MaxAnisotropy < 1) info.maxAnisotropy = 1.0f;
if (desc.MaxAnisotropy > 16) info.maxAnisotropy = 16.0f;
// Enforce LOD bias specified in the device options
if (info.minFilter == VK_FILTER_LINEAR && info.magFilter == VK_FILTER_LINEAR) {
info.mipmapLodBias += device->GetOptions()->samplerLodBias;
if (device->GetOptions()->clampNegativeLodBias)
info.mipmapLodBias = std::max(info.mipmapLodBias, 0.0f);
}
// Enforce anisotropy specified in the device options
int32_t samplerAnisotropyOption = device->GetOptions()->samplerAnisotropy;
if (samplerAnisotropyOption >= 0 && info.minFilter == VK_FILTER_LINEAR) {
info.useAnisotropy = samplerAnisotropyOption > 0;
info.maxAnisotropy = float(samplerAnisotropyOption);
}
m_sampler = device->GetDXVKDevice()->createSampler(info);
}
D3D11SamplerState::~D3D11SamplerState() {
}

View file

@ -59,25 +59,33 @@ namespace dxvk {
}
// Create shader constant buffer if necessary
const DxvkShaderCreateInfo& shaderInfo = m_shader->info();
auto icb = module.icbInfo();
if (shaderInfo.uniformSize) {
DxvkBufferCreateInfo info;
info.size = shaderInfo.uniformSize;
info.usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT;
info.stages = util::pipelineStages(shaderInfo.stage);
info.access = VK_ACCESS_UNIFORM_READ_BIT;
VkMemoryPropertyFlags memFlags
= VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT
| VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT
| VK_MEMORY_PROPERTY_HOST_COHERENT_BIT;
m_buffer = pDevice->GetDXVKDevice()->createBuffer(info, memFlags);
std::memcpy(m_buffer->mapPtr(0), shaderInfo.uniformData, shaderInfo.uniformSize);
if (icb.size) {
DxvkBufferCreateInfo info = { };
info.size = align(icb.size, 256u);
info.usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT
| VK_BUFFER_USAGE_TRANSFER_SRC_BIT
| VK_BUFFER_USAGE_TRANSFER_DST_BIT;
info.stages = util::pipelineStages(m_shader->info().stage);
info.access = VK_ACCESS_UNIFORM_READ_BIT
| VK_ACCESS_TRANSFER_READ_BIT
| VK_ACCESS_TRANSFER_WRITE_BIT;
info.debugName = "Icb";
m_buffer = pDevice->GetDXVKDevice()->createBuffer(info, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
// Upload immediate constant buffer to VRAM
pDevice->InitShaderIcb(this, icb.size, icb.data);
}
pDevice->GetDXVKDevice()->registerShader(m_shader);
// Write back binding mask
auto bindings = module.bindings();
if (bindings)
m_bindings = *bindings;
}

View file

@ -18,7 +18,7 @@
namespace dxvk {
class D3D11Device;
/**
* \brief Common shader object
*
@ -52,12 +52,18 @@ namespace dxvk {
std::string GetName() const {
return m_shader->debugName();
}
DxbcBindingMask GetBindingMask() const {
return m_bindings;
}
private:
Rc<DxvkShader> m_shader;
Rc<DxvkBuffer> m_buffer;
DxbcBindingMask m_bindings = { };
};

View file

@ -2,6 +2,8 @@
#include "d3d11_device.h"
#include "d3d11_swapchain.h"
#include "../dxvk/dxvk_latency_builtin.h"
#include "../util/util_win32_compat.h"
namespace dxvk {
@ -63,16 +65,11 @@ namespace dxvk {
m_surfaceFactory(pSurfaceFactory),
m_desc(*pDesc),
m_device(pDevice->GetDXVKDevice()),
m_context(m_device->createContext(DxvkContextType::Supplementary)),
m_frameLatencyCap(pDevice->GetOptions()->maxFrameLatency) {
CreateFrameLatencyEvent();
CreatePresenter();
CreateBackBuffer();
CreateBackBuffers();
CreateBlitter();
CreateHud();
if (!pDevice->GetOptions()->deferSurfaceCreation)
RecreateSwapChain();
}
@ -82,10 +79,10 @@ namespace dxvk {
if (this_thread::isInModuleDetachment())
return;
m_device->waitForSubmission(&m_presentStatus);
m_device->waitForIdle();
m_presenter->destroyResources();
DestroyFrameLatencyEvent();
DestroyLatencyTracker();
}
@ -99,7 +96,8 @@ namespace dxvk {
if (riid == __uuidof(IUnknown)
|| riid == __uuidof(IDXGIVkSwapChain)
|| riid == __uuidof(IDXGIVkSwapChain1)) {
|| riid == __uuidof(IDXGIVkSwapChain1)
|| riid == __uuidof(IDXGIVkSwapChain2)) {
*ppvObject = ref(this);
return S_OK;
}
@ -140,12 +138,12 @@ namespace dxvk {
void** ppBuffer) {
InitReturnPtr(ppBuffer);
if (BufferId > 0) {
Logger::err("D3D11: GetImage: BufferId > 0 not supported");
if (BufferId >= m_backBuffers.size()) {
Logger::err("D3D11: GetImage: Invalid buffer ID");
return DXGI_ERROR_UNSUPPORTED;
}
return m_backBuffer->QueryInterface(riid, ppBuffer);
return m_backBuffers[BufferId]->QueryInterface(riid, ppBuffer);
}
@ -177,14 +175,14 @@ namespace dxvk {
const DXGI_SWAP_CHAIN_DESC1* pDesc,
const UINT* pNodeMasks,
IUnknown* const* ppPresentQueues) {
m_dirty |= m_desc.Format != pDesc->Format
|| m_desc.Width != pDesc->Width
|| m_desc.Height != pDesc->Height
|| m_desc.BufferCount != pDesc->BufferCount
|| m_desc.Flags != pDesc->Flags;
if (m_desc.Format != pDesc->Format)
m_presenter->setSurfaceFormat(GetSurfaceFormat(pDesc->Format));
if (m_desc.Width != pDesc->Width || m_desc.Height != pDesc->Height)
m_presenter->setSurfaceExtent({ m_desc.Width, m_desc.Height });
m_desc = *pDesc;
CreateBackBuffer();
CreateBackBuffers();
return S_OK;
}
@ -254,33 +252,24 @@ namespace dxvk {
UINT SyncInterval,
UINT PresentFlags,
const DXGI_PRESENT_PARAMETERS* pPresentParameters) {
if (!(PresentFlags & DXGI_PRESENT_TEST))
m_dirty |= m_presenter->setSyncInterval(SyncInterval) != VK_SUCCESS;
HRESULT hr = S_OK;
if (!m_presenter->hasSwapChain()) {
RecreateSwapChain();
m_dirty = false;
}
if (!m_presenter->hasSwapChain())
hr = DXGI_STATUS_OCCLUDED;
if (m_device->getDeviceStatus() != VK_SUCCESS)
hr = DXGI_ERROR_DEVICE_RESET;
if (PresentFlags & DXGI_PRESENT_TEST)
return hr;
if (PresentFlags & DXGI_PRESENT_TEST) {
if (hr != S_OK)
return hr;
VkResult status = m_presenter->checkSwapChainStatus();
return status == VK_SUCCESS ? S_OK : DXGI_STATUS_OCCLUDED;
}
if (hr != S_OK) {
SyncFrameLatency();
return hr;
}
if (std::exchange(m_dirty, false))
RecreateSwapChain();
try {
hr = PresentImage(SyncInterval);
} catch (const DxvkError& e) {
@ -293,6 +282,18 @@ namespace dxvk {
// applications using the semaphore may deadlock. This works because
// we do not increment the frame ID in those situations.
SyncFrameLatency();
// Ignore latency stuff if presentation failed
DxvkLatencyStats latencyStats = { };
if (hr == S_OK && m_latency) {
latencyStats = m_latency->getStatistics(m_frameId);
m_latency->sleepAndBeginFrame(m_frameId + 1, std::abs(m_targetFrameRate));
}
if (m_latencyHud)
m_latencyHud->accumulateStats(latencyStats);
return hr;
}
@ -301,7 +302,8 @@ namespace dxvk {
DXGI_COLOR_SPACE_TYPE ColorSpace) {
UINT supportFlags = 0;
const VkColorSpaceKHR vkColorSpace = ConvertColorSpace(ColorSpace);
VkColorSpaceKHR vkColorSpace = ConvertColorSpace(ColorSpace);
if (m_presenter->supportsColorSpace(vkColorSpace))
supportFlags |= DXGI_SWAP_CHAIN_COLOR_SPACE_SUPPORT_FLAG_PRESENT;
@ -311,13 +313,14 @@ namespace dxvk {
HRESULT STDMETHODCALLTYPE D3D11SwapChain::SetColorSpace(
DXGI_COLOR_SPACE_TYPE ColorSpace) {
if (!(CheckColorSpaceSupport(ColorSpace) & DXGI_SWAP_CHAIN_COLOR_SPACE_SUPPORT_FLAG_PRESENT))
VkColorSpaceKHR colorSpace = ConvertColorSpace(ColorSpace);
if (!m_presenter->supportsColorSpace(colorSpace))
return E_INVALIDARG;
const VkColorSpaceKHR vkColorSpace = ConvertColorSpace(ColorSpace);
m_dirty |= vkColorSpace != m_colorspace;
m_colorspace = vkColorSpace;
m_colorSpace = colorSpace;
m_presenter->setSurfaceFormat(GetSurfaceFormat(m_desc.Format));
return S_OK;
}
@ -325,10 +328,8 @@ namespace dxvk {
HRESULT STDMETHODCALLTYPE D3D11SwapChain::SetHDRMetaData(
const DXGI_VK_HDR_METADATA* pMetaData) {
// For some reason this call always seems to succeed on Windows
if (pMetaData->Type == DXGI_HDR_METADATA_TYPE_HDR10) {
m_hdrMetadata = ConvertHDRMetadata(pMetaData->HDR10);
m_dirtyHdrMetadata = true;
}
if (pMetaData->Type == DXGI_HDR_METADATA_TYPE_HDR10)
m_presenter->setHdrMetadata(ConvertHDRMetadata(pMetaData->HDR10));
return S_OK;
}
@ -347,136 +348,146 @@ namespace dxvk {
}
void STDMETHODCALLTYPE D3D11SwapChain::SetTargetFrameRate(
double FrameRate) {
m_targetFrameRate = FrameRate;
if (m_presenter != nullptr)
m_presenter->setFrameRateLimit(m_targetFrameRate, GetActualFrameLatency());
}
Rc<DxvkImageView> D3D11SwapChain::GetBackBufferView() {
Rc<DxvkImage> image = GetCommonTexture(m_backBuffers[0].ptr())->GetImage();
DxvkImageViewKey key;
key.viewType = VK_IMAGE_VIEW_TYPE_2D;
key.usage = VK_IMAGE_USAGE_SAMPLED_BIT;
key.format = image->info().format;
key.aspects = VK_IMAGE_ASPECT_COLOR_BIT;
key.mipIndex = 0u;
key.mipCount = 1u;
key.layerIndex = 0u;
key.layerCount = 1u;
return image->createView(key);
}
HRESULT D3D11SwapChain::PresentImage(UINT SyncInterval) {
// Flush pending rendering commands before
auto immediateContext = m_parent->GetContext();
immediateContext->EndFrame();
immediateContext->Flush();
auto immediateContextLock = immediateContext->LockContext();
for (uint32_t i = 0; i < SyncInterval || i < 1; i++) {
SynchronizePresent();
immediateContext->EndFrame(m_latency);
immediateContext->ExecuteFlush(GpuFlushType::ExplicitFlush, nullptr, true);
if (!m_presenter->hasSwapChain())
return i ? S_OK : DXGI_STATUS_OCCLUDED;
m_presenter->setSyncInterval(SyncInterval);
// Presentation semaphores and WSI swap chain image
PresenterInfo info = m_presenter->info();
PresenterSync sync;
// Presentation semaphores and WSI swap chain image
if (m_latency)
m_latency->notifyCpuPresentBegin(m_frameId + 1u);
uint32_t imageIndex = 0;
PresenterSync sync;
Rc<DxvkImage> backBuffer;
VkResult status = m_presenter->acquireNextImage(sync, imageIndex);
VkResult status = m_presenter->acquireNextImage(sync, backBuffer);
while (status != VK_SUCCESS && status != VK_SUBOPTIMAL_KHR) {
RecreateSwapChain();
if (status != VK_SUCCESS && m_latency)
m_latency->discardTimings();
if (!m_presenter->hasSwapChain())
return i ? S_OK : DXGI_STATUS_OCCLUDED;
info = m_presenter->info();
status = m_presenter->acquireNextImage(sync, imageIndex);
if (status < 0)
return E_FAIL;
if (status == VK_NOT_READY)
return DXGI_STATUS_OCCLUDED;
m_frameId += 1;
// Present from CS thread so that we don't
// have to synchronize with it first.
DxvkImageViewKey viewInfo = { };
viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
viewInfo.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
viewInfo.format = backBuffer->info().format;
viewInfo.aspects = VK_IMAGE_ASPECT_COLOR_BIT;
viewInfo.mipIndex = 0u;
viewInfo.mipCount = 1u;
viewInfo.layerIndex = 0u;
viewInfo.layerCount = 1u;
immediateContext->EmitCs([
cDevice = m_device,
cBlitter = m_blitter,
cBackBuffer = backBuffer->createView(viewInfo),
cSwapImage = GetBackBufferView(),
cSync = sync,
cPresenter = m_presenter,
cLatency = m_latency,
cColorSpace = m_colorSpace,
cFrameId = m_frameId
] (DxvkContext* ctx) {
// Update back buffer color space as necessary
if (cSwapImage->image()->info().colorSpace != cColorSpace) {
DxvkImageUsageInfo usage = { };
usage.colorSpace = cColorSpace;
ctx->ensureImageCompatibility(cSwapImage->image(), usage);
}
if (m_hdrMetadata && m_dirtyHdrMetadata) {
m_presenter->setHdrMetadata(*m_hdrMetadata);
m_dirtyHdrMetadata = false;
// Blit the D3D back buffer onto the actual Vulkan
// swap chain and render the HUD if we have one.
auto contextObjects = ctx->beginExternalRendering();
cBlitter->present(contextObjects,
cBackBuffer, VkRect2D(),
cSwapImage, VkRect2D());
// Submit current command list and present
ctx->synchronizeWsi(cSync);
ctx->flushCommandList(nullptr, nullptr);
cDevice->presentImage(cPresenter, cLatency, cFrameId, nullptr);
});
if (m_backBuffers.size() > 1u)
RotateBackBuffers(immediateContext);
immediateContext->FlushCsChunk();
if (m_latency) {
m_latency->notifyCpuPresentEnd(m_frameId);
if (m_latency->needsAutoMarkers()) {
immediateContext->EmitCs([
cLatency = m_latency,
cFrameId = m_frameId
] (DxvkContext* ctx) {
ctx->beginLatencyTracking(cLatency, cFrameId + 1u);
});
}
m_context->beginRecording(
m_device->createCommandList());
m_blitter->presentImage(m_context.ptr(),
m_imageViews.at(imageIndex), VkRect2D(),
m_swapImageView, VkRect2D());
if (m_hud != nullptr)
m_hud->render(m_context, info.format, info.imageExtent);
SubmitPresent(immediateContext, sync, i);
}
return S_OK;
}
void D3D11SwapChain::SubmitPresent(
D3D11ImmediateContext* pContext,
const PresenterSync& Sync,
uint32_t Repeat) {
auto lock = pContext->LockContext();
void D3D11SwapChain::RotateBackBuffers(D3D11ImmediateContext* ctx) {
small_vector<Rc<DxvkImage>, 4> images;
// Bump frame ID as necessary
if (!Repeat)
m_frameId += 1;
for (uint32_t i = 0; i < m_backBuffers.size(); i++)
images.push_back(GetCommonTexture(m_backBuffers[i].ptr())->GetImage());
// Present from CS thread so that we don't
// have to synchronize with it first.
m_presentStatus.result = VK_NOT_READY;
pContext->EmitCs([this,
cRepeat = Repeat,
cSync = Sync,
cHud = m_hud,
cPresentMode = m_presenter->info().presentMode,
cFrameId = m_frameId,
cCommandList = m_context->endRecording()
ctx->EmitCs([
cImages = std::move(images)
] (DxvkContext* ctx) {
cCommandList->setWsiSemaphores(cSync);
m_device->submitCommandList(cCommandList, nullptr);
auto allocation = cImages[0]->storage();
if (cHud != nullptr && !cRepeat)
cHud->update();
for (size_t i = 0u; i + 1 < cImages.size(); i++)
ctx->invalidateImage(cImages[i], cImages[i + 1]->storage());
uint64_t frameId = cRepeat ? 0 : cFrameId;
m_device->presentImage(m_presenter,
cPresentMode, frameId, &m_presentStatus);
ctx->invalidateImage(cImages[cImages.size() - 1u], std::move(allocation));
});
pContext->FlushCsChunk();
}
void D3D11SwapChain::SynchronizePresent() {
// Recreate swap chain if the previous present call failed
VkResult status = m_device->waitForSubmission(&m_presentStatus);
if (status != VK_SUCCESS)
RecreateSwapChain();
}
void D3D11SwapChain::RecreateSwapChain() {
// Ensure that we can safely destroy the swap chain
m_device->waitForSubmission(&m_presentStatus);
m_device->waitForIdle();
m_presentStatus.result = VK_SUCCESS;
m_dirtyHdrMetadata = true;
PresenterDesc presenterDesc;
presenterDesc.imageExtent = { m_desc.Width, m_desc.Height };
presenterDesc.imageCount = PickImageCount(m_desc.BufferCount + 1);
presenterDesc.numFormats = PickFormats(m_desc.Format, presenterDesc.formats);
presenterDesc.fullScreenExclusive = PickFullscreenMode();
VkResult vr = m_presenter->recreateSwapChain(presenterDesc);
if (vr == VK_ERROR_SURFACE_LOST_KHR) {
vr = m_presenter->recreateSurface([this] (VkSurfaceKHR* surface) {
return CreateSurface(surface);
});
if (vr)
throw DxvkError(str::format("D3D11SwapChain: Failed to recreate surface: ", vr));
vr = m_presenter->recreateSwapChain(presenterDesc);
}
if (vr)
throw DxvkError(str::format("D3D11SwapChain: Failed to recreate swap chain: ", vr));
CreateRenderTargetViews();
}
@ -489,76 +500,37 @@ namespace dxvk {
void D3D11SwapChain::CreatePresenter() {
PresenterDesc presenterDesc;
presenterDesc.imageExtent = { m_desc.Width, m_desc.Height };
presenterDesc.imageCount = PickImageCount(m_desc.BufferCount + 1);
presenterDesc.numFormats = PickFormats(m_desc.Format, presenterDesc.formats);
presenterDesc.fullScreenExclusive = PickFullscreenMode();
PresenterDesc presenterDesc = { };
presenterDesc.deferSurfaceCreation = m_parent->GetOptions()->deferSurfaceCreation;
m_presenter = new Presenter(m_device, m_frameLatencySignal, presenterDesc);
m_presenter->setFrameRateLimit(m_parent->GetOptions()->maxFrameRate);
m_presenter = new Presenter(m_device, m_frameLatencySignal, presenterDesc, [
cAdapter = m_device->adapter(),
cFactory = m_surfaceFactory
] (VkSurfaceKHR* surface) {
return cFactory->CreateSurface(
cAdapter->vki()->instance(),
cAdapter->handle(), surface);
});
m_presenter->setSurfaceFormat(GetSurfaceFormat(m_desc.Format));
m_presenter->setSurfaceExtent({ m_desc.Width, m_desc.Height });
m_presenter->setFrameRateLimit(m_targetFrameRate, GetActualFrameLatency());
m_latency = m_device->createLatencyTracker(m_presenter);
Com<D3D11ReflexDevice> reflex = GetReflexDevice();
reflex->RegisterLatencyTracker(m_latency);
}
VkResult D3D11SwapChain::CreateSurface(VkSurfaceKHR* pSurface) {
Rc<DxvkAdapter> adapter = m_device->adapter();
return m_surfaceFactory->CreateSurface(
adapter->vki()->instance(),
adapter->handle(), pSurface);
}
void D3D11SwapChain::CreateRenderTargetViews() {
PresenterInfo info = m_presenter->info();
m_imageViews.clear();
m_imageViews.resize(info.imageCount);
DxvkImageCreateInfo imageInfo;
imageInfo.type = VK_IMAGE_TYPE_2D;
imageInfo.format = info.format.format;
imageInfo.flags = 0;
imageInfo.sampleCount = VK_SAMPLE_COUNT_1_BIT;
imageInfo.extent = { info.imageExtent.width, info.imageExtent.height, 1 };
imageInfo.numLayers = 1;
imageInfo.mipLevels = 1;
imageInfo.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
imageInfo.stages = 0;
imageInfo.access = 0;
imageInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
imageInfo.layout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
imageInfo.shared = VK_TRUE;
DxvkImageViewCreateInfo viewInfo;
viewInfo.type = VK_IMAGE_VIEW_TYPE_2D;
viewInfo.format = info.format.format;
viewInfo.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
viewInfo.aspect = VK_IMAGE_ASPECT_COLOR_BIT;
viewInfo.minLevel = 0;
viewInfo.numLevels = 1;
viewInfo.minLayer = 0;
viewInfo.numLayers = 1;
for (uint32_t i = 0; i < info.imageCount; i++) {
VkImage imageHandle = m_presenter->getImage(i).image;
Rc<DxvkImage> image = new DxvkImage(
m_device.ptr(), imageInfo, imageHandle,
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
m_imageViews[i] = new DxvkImageView(
m_device->vkd(), image, viewInfo);
}
}
void D3D11SwapChain::CreateBackBuffer() {
void D3D11SwapChain::CreateBackBuffers() {
// Explicitly destroy current swap image before
// creating a new one to free up resources
m_swapImage = nullptr;
m_swapImageView = nullptr;
m_backBuffer = nullptr;
m_backBuffers.clear();
bool sequential = m_desc.SwapEffect == DXGI_SWAP_EFFECT_SEQUENTIAL ||
m_desc.SwapEffect == DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL;
uint32_t backBufferCount = sequential ? m_desc.BufferCount : 1u;
// Create new back buffer
D3D11_COMMON_TEXTURE_DESC desc;
@ -589,57 +561,49 @@ namespace dxvk {
DXGI_USAGE dxgiUsage = DXGI_USAGE_BACK_BUFFER;
if (m_desc.SwapEffect == DXGI_SWAP_EFFECT_DISCARD
|| m_desc.SwapEffect == DXGI_SWAP_EFFECT_FLIP_DISCARD)
dxgiUsage |= DXGI_USAGE_DISCARD_ON_PRESENT;
for (uint32_t i = 0; i < backBufferCount; i++) {
if (m_desc.SwapEffect == DXGI_SWAP_EFFECT_DISCARD
|| m_desc.SwapEffect == DXGI_SWAP_EFFECT_FLIP_DISCARD)
dxgiUsage |= DXGI_USAGE_DISCARD_ON_PRESENT;
m_backBuffer = new D3D11Texture2D(m_parent, this, &desc, dxgiUsage);
m_swapImage = GetCommonTexture(m_backBuffer.ptr())->GetImage();
m_backBuffers.push_back(new D3D11Texture2D(
m_parent, this, &desc, dxgiUsage));
// Create an image view that allows the
// image to be bound as a shader resource.
DxvkImageViewCreateInfo viewInfo;
viewInfo.type = VK_IMAGE_VIEW_TYPE_2D;
viewInfo.format = m_swapImage->info().format;
viewInfo.usage = VK_IMAGE_USAGE_SAMPLED_BIT;
viewInfo.aspect = VK_IMAGE_ASPECT_COLOR_BIT;
viewInfo.minLevel = 0;
viewInfo.numLevels = 1;
viewInfo.minLayer = 0;
viewInfo.numLayers = 1;
m_swapImageView = m_device->createImageView(m_swapImage, viewInfo);
// Initialize the image so that we can use it. Clearing
dxgiUsage |= DXGI_USAGE_READ_ONLY;
}
small_vector<Rc<DxvkImage>, 4> images;
for (uint32_t i = 0; i < backBufferCount; i++)
images.push_back(GetCommonTexture(m_backBuffers[i].ptr())->GetImage());
// Initialize images so that we can use them. Clearing
// to black prevents garbled output for the first frame.
VkImageSubresourceRange subresources;
subresources.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
subresources.baseMipLevel = 0;
subresources.levelCount = 1;
subresources.baseArrayLayer = 0;
subresources.layerCount = 1;
m_parent->GetContext()->InjectCs(DxvkCsQueue::HighPriority, [
cImages = std::move(images)
] (DxvkContext* ctx) {
for (size_t i = 0; i < cImages.size(); i++) {
ctx->setDebugName(cImages[i], str::format("Back buffer ", i).c_str());
m_context->beginRecording(
m_device->createCommandList());
m_context->initImage(m_swapImage,
subresources, VK_IMAGE_LAYOUT_UNDEFINED);
m_device->submitCommandList(
m_context->endRecording(),
nullptr);
ctx->initImage(cImages[i],
cImages[i]->getAvailableSubresources(),
VK_IMAGE_LAYOUT_UNDEFINED);
}
});
}
void D3D11SwapChain::CreateBlitter() {
m_blitter = new DxvkSwapchainBlitter(m_device);
}
Rc<hud::Hud> hud = hud::Hud::createHud(m_device);
if (hud) {
hud->addItem<hud::HudClientApiItem>("api", 1, GetApiName());
void D3D11SwapChain::CreateHud() {
m_hud = hud::Hud::createHud(m_device);
if (m_latency)
m_latencyHud = hud->addItem<hud::HudLatencyItem>("latency", 4);
}
if (m_hud != nullptr)
m_hud->addItem<hud::HudClientApiItem>("api", 1, GetApiName());
m_blitter = new DxvkSwapchainBlitter(m_device, std::move(hud));
}
@ -648,6 +612,20 @@ namespace dxvk {
}
void D3D11SwapChain::DestroyLatencyTracker() {
// Need to make sure the context stops using
// the tracker for submissions
m_parent->GetContext()->InjectCs(DxvkCsQueue::Ordered, [
cLatency = m_latency
] (DxvkContext* ctx) {
ctx->endLatencyTracking(cLatency);
});
Com<D3D11ReflexDevice> reflex = GetReflexDevice();
reflex->UnregisterLatencyTracker(m_latency);
}
void D3D11SwapChain::SyncFrameLatency() {
// Wait for the sync event so that we respect the maximum frame latency
m_frameLatencySignal->wait(m_frameId - GetActualFrameLatency());
@ -683,53 +661,34 @@ namespace dxvk {
}
uint32_t D3D11SwapChain::PickFormats(
DXGI_FORMAT Format,
VkSurfaceFormatKHR* pDstFormats) {
uint32_t n = 0;
VkSurfaceFormatKHR D3D11SwapChain::GetSurfaceFormat(DXGI_FORMAT Format) {
switch (Format) {
default:
Logger::warn(str::format("D3D11SwapChain: Unexpected format: ", m_desc.Format));
[[fallthrough]];
[[fallthrough]];
case DXGI_FORMAT_R8G8B8A8_UNORM:
case DXGI_FORMAT_B8G8R8A8_UNORM: {
pDstFormats[n++] = { VK_FORMAT_R8G8B8A8_UNORM, m_colorspace };
pDstFormats[n++] = { VK_FORMAT_B8G8R8A8_UNORM, m_colorspace };
} break;
case DXGI_FORMAT_B8G8R8A8_UNORM:
return { VK_FORMAT_R8G8B8A8_UNORM, m_colorSpace };
case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB:
case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB: {
pDstFormats[n++] = { VK_FORMAT_R8G8B8A8_SRGB, m_colorspace };
pDstFormats[n++] = { VK_FORMAT_B8G8R8A8_SRGB, m_colorspace };
} break;
case DXGI_FORMAT_R10G10B10A2_UNORM: {
pDstFormats[n++] = { VK_FORMAT_A2B10G10R10_UNORM_PACK32, m_colorspace };
pDstFormats[n++] = { VK_FORMAT_A2R10G10B10_UNORM_PACK32, m_colorspace };
} break;
case DXGI_FORMAT_R16G16B16A16_FLOAT: {
pDstFormats[n++] = { VK_FORMAT_R16G16B16A16_SFLOAT, m_colorspace };
} break;
case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB:
return { VK_FORMAT_R8G8B8A8_SRGB, m_colorSpace };
case DXGI_FORMAT_R10G10B10A2_UNORM:
return { VK_FORMAT_A2B10G10R10_UNORM_PACK32, m_colorSpace };
case DXGI_FORMAT_R16G16B16A16_FLOAT:
return { VK_FORMAT_R16G16B16A16_SFLOAT, m_colorSpace };
}
return n;
}
uint32_t D3D11SwapChain::PickImageCount(
UINT Preferred) {
int32_t option = m_parent->GetOptions()->numBackBuffers;
return option > 0 ? uint32_t(option) : uint32_t(Preferred);
}
Com<D3D11ReflexDevice> D3D11SwapChain::GetReflexDevice() {
Com<ID3DLowLatencyDevice> llDevice;
m_parent->QueryInterface(__uuidof(ID3DLowLatencyDevice), reinterpret_cast<void**>(&llDevice));
VkFullScreenExclusiveEXT D3D11SwapChain::PickFullscreenMode() {
return m_desc.Flags & DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH
? VK_FULL_SCREEN_EXCLUSIVE_ALLOWED_EXT
: VK_FULL_SCREEN_EXCLUSIVE_DISALLOWED_EXT;
return static_cast<D3D11ReflexDevice*>(llDevice.ptr());
}

View file

@ -4,6 +4,7 @@
#include "../dxvk/hud/dxvk_hud.h"
#include "../dxvk/dxvk_latency.h"
#include "../dxvk/dxvk_swapchain_blitter.h"
#include "../util/sync/sync_signal.h"
@ -13,7 +14,7 @@ namespace dxvk {
class D3D11Device;
class D3D11DXGIDevice;
class D3D11SwapChain : public ComObject<IDXGIVkSwapChain1> {
class D3D11SwapChain : public ComObject<IDXGIVkSwapChain2> {
constexpr static uint32_t DefaultFrameLatency = 1;
public:
@ -86,6 +87,9 @@ namespace dxvk {
void STDMETHODCALLTYPE GetFrameStatistics(
DXGI_VK_FRAME_STATISTICS* pFrameStatistics);
void STDMETHODCALLTYPE SetTargetFrameRate(
double FrameRate);
private:
enum BindingIds : uint32_t {
@ -101,76 +105,53 @@ namespace dxvk {
DXGI_SWAP_CHAIN_DESC1 m_desc;
Rc<DxvkDevice> m_device;
Rc<DxvkContext> m_context;
Rc<Presenter> m_presenter;
Rc<DxvkImage> m_swapImage;
Rc<DxvkImageView> m_swapImageView;
Rc<DxvkSwapchainBlitter> m_blitter;
Rc<DxvkLatencyTracker> m_latency;
Rc<hud::Hud> m_hud;
small_vector<Com<D3D11Texture2D, false>, 4> m_backBuffers;
Com<D3D11Texture2D, false> m_backBuffer;
DxvkSubmitStatus m_presentStatus;
uint64_t m_frameId = DXGI_MAX_SWAP_CHAIN_BUFFERS;
uint32_t m_frameLatency = DefaultFrameLatency;
uint32_t m_frameLatencyCap = 0;
HANDLE m_frameLatencyEvent = nullptr;
Rc<sync::CallbackFence> m_frameLatencySignal;
std::vector<Rc<DxvkImageView>> m_imageViews;
VkColorSpaceKHR m_colorSpace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR;
uint64_t m_frameId = DXGI_MAX_SWAP_CHAIN_BUFFERS;
uint32_t m_frameLatency = DefaultFrameLatency;
uint32_t m_frameLatencyCap = 0;
HANDLE m_frameLatencyEvent = nullptr;
Rc<sync::CallbackFence> m_frameLatencySignal;
bool m_dirty = true;
VkColorSpaceKHR m_colorspace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR;
std::optional<VkHdrMetadataEXT> m_hdrMetadata;
bool m_dirtyHdrMetadata = true;
double m_targetFrameRate = 0.0;
dxvk::mutex m_frameStatisticsLock;
DXGI_VK_FRAME_STATISTICS m_frameStatistics = { };
Rc<hud::HudLatencyItem> m_latencyHud;
Rc<DxvkImageView> GetBackBufferView();
HRESULT PresentImage(UINT SyncInterval);
void SubmitPresent(
D3D11ImmediateContext* pContext,
const PresenterSync& Sync,
uint32_t Repeat);
void SynchronizePresent();
void RecreateSwapChain();
void RotateBackBuffers(D3D11ImmediateContext* ctx);
void CreateFrameLatencyEvent();
void CreatePresenter();
VkResult CreateSurface(VkSurfaceKHR* pSurface);
void CreateRenderTargetViews();
void CreateBackBuffer();
void CreateBackBuffers();
void CreateBlitter();
void CreateHud();
void DestroyFrameLatencyEvent();
void DestroyLatencyTracker();
void SyncFrameLatency();
uint32_t GetActualFrameLatency();
uint32_t PickFormats(
DXGI_FORMAT Format,
VkSurfaceFormatKHR* pDstFormats);
uint32_t PickImageCount(
UINT Preferred);
VkFullScreenExclusiveEXT PickFullscreenMode();
VkSurfaceFormatKHR GetSurfaceFormat(DXGI_FORMAT Format);
Com<D3D11ReflexDevice> GetReflexDevice();
std::string GetApiName() const;

View file

@ -1,4 +1,5 @@
#include "d3d11_device.h"
#include "d3d11_context_imm.h"
#include "d3d11_gdi.h"
#include "d3d11_texture.h"
@ -58,9 +59,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)
@ -171,7 +169,8 @@ namespace dxvk {
imageInfo.tiling = VK_IMAGE_TILING_LINEAR;
// Determine map mode based on our findings
m_mapMode = DetermineMapMode(&imageInfo);
VkMemoryPropertyFlags memoryProperties = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
std::tie(m_mapMode, memoryProperties) = DetermineMapMode(&imageInfo);
// If the image is mapped directly to host memory, we need
// to enable linear tiling, and DXVK needs to be aware that
@ -190,14 +189,25 @@ namespace dxvk {
}
// If necessary, create the mapped linear buffer
if (m_mapMode != D3D11_COMMON_TEXTURE_MAP_MODE_NONE) {
for (uint32_t i = 0; i < m_desc.ArraySize; i++) {
for (uint32_t j = 0; j < m_desc.MipLevels; j++) {
if (m_mapMode != D3D11_COMMON_TEXTURE_MAP_MODE_DIRECT)
m_buffers.push_back(CreateMappedBuffer(j));
uint32_t subresourceCount = m_desc.ArraySize * m_desc.MipLevels;
m_mapInfo.push_back({ D3D11_MAP(~0u), 0ull });
}
if (m_mapMode != D3D11_COMMON_TEXTURE_MAP_MODE_NONE) {
m_mapInfo.resize(subresourceCount);
for (uint32_t i = 0; i < subresourceCount; i++) {
m_mapInfo[i].layout = DetermineSubresourceLayout(&imageInfo,
GetSubresourceFromIndex(formatProperties->aspectMask, i));
}
}
if (m_mapMode == D3D11_COMMON_TEXTURE_MAP_MODE_BUFFER
|| m_mapMode == D3D11_COMMON_TEXTURE_MAP_MODE_STAGING
|| m_mapMode == D3D11_COMMON_TEXTURE_MAP_MODE_DYNAMIC) {
m_buffers.resize(subresourceCount);
if (m_mapMode != D3D11_COMMON_TEXTURE_MAP_MODE_DYNAMIC) {
for (uint32_t i = 0; i < subresourceCount; i++)
CreateMappedBuffer(i);
}
}
@ -211,15 +221,6 @@ namespace dxvk {
if (imageInfo.tiling == VK_IMAGE_TILING_OPTIMAL && !isMultiPlane && imageInfo.sharing.mode == DxvkSharedHandleMode::None)
imageInfo.layout = OptimizeLayout(imageInfo.usage);
// For some formats, we need to enable sampled and/or
// render target capabilities if available, but these
// should in no way affect the default image layout
imageInfo.usage |= EnableMetaPackUsage(imageInfo.format, m_desc.CPUAccessFlags);
imageInfo.usage |= EnableMetaCopyUsage(imageInfo.format, imageInfo.tiling);
for (uint32_t i = 0; i < imageInfo.viewFormatCount; i++)
imageInfo.usage |= EnableMetaCopyUsage(imageInfo.viewFormats[i], imageInfo.tiling);
// Check if we can actually create the image
if (!CheckImageSupport(&imageInfo, imageInfo.tiling)) {
throw DxvkError(str::format(
@ -234,14 +235,7 @@ namespace dxvk {
"\n Usage: ", std::hex, m_desc.BindFlags,
"\n Flags: ", std::hex, m_desc.MiscFlags));
}
// Create the image on a host-visible memory type
// in case it is going to be mapped directly.
VkMemoryPropertyFlags memoryProperties = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
if (m_mapMode == D3D11_COMMON_TEXTURE_MAP_MODE_DIRECT)
memoryProperties = GetMemoryFlags();
if (m_11on12.Resource != nullptr)
vkImage = VkImage(m_11on12.VulkanHandle);
@ -250,6 +244,9 @@ namespace dxvk {
else
m_image = m_device->GetDXVKDevice()->importImage(imageInfo, vkImage, memoryProperties);
if (m_mapMode == D3D11_COMMON_TEXTURE_MAP_MODE_DIRECT)
m_mapPtr = m_image->mapPtr(0);
if (imageInfo.sharing.mode == DxvkSharedHandleMode::Export)
ExportImageInfo();
}
@ -284,73 +281,24 @@ namespace dxvk {
}
VkImageSubresource D3D11CommonTexture::GetSubresourceFromIndex(
VkImageAspectFlags Aspect,
UINT Subresource) const {
VkImageSubresource result;
result.aspectMask = Aspect;
result.mipLevel = Subresource % m_desc.MipLevels;
result.arrayLayer = Subresource / m_desc.MipLevels;
return result;
}
D3D11_COMMON_TEXTURE_SUBRESOURCE_LAYOUT D3D11CommonTexture::GetSubresourceLayout(
VkImageAspectFlags AspectMask,
UINT Subresource) const {
// Color is mapped directly and depth-stencil are interleaved
// in packed formats, so just use the cached subresource layout
constexpr VkImageAspectFlags PlaneAspects = VK_IMAGE_ASPECT_PLANE_0_BIT
| VK_IMAGE_ASPECT_PLANE_1_BIT | VK_IMAGE_ASPECT_PLANE_2_BIT;
if ((Subresource < m_mapInfo.size()) && !(AspectMask & PlaneAspects))
return m_mapInfo[Subresource].layout;
// Safe-guard against invalid subresource index
if (Subresource >= m_desc.ArraySize * m_desc.MipLevels)
return D3D11_COMMON_TEXTURE_SUBRESOURCE_LAYOUT();
// Image info is only needed for direct-mapped images
VkImageSubresource subresource = GetSubresourceFromIndex(AspectMask, Subresource);
D3D11_COMMON_TEXTURE_SUBRESOURCE_LAYOUT layout = { };
switch (m_mapMode) {
case D3D11_COMMON_TEXTURE_MAP_MODE_DIRECT: {
auto vkLayout = m_image->querySubresourceLayout(subresource);
layout.Offset = vkLayout.offset;
layout.Size = vkLayout.size;
layout.RowPitch = vkLayout.rowPitch;
layout.DepthPitch = vkLayout.depthPitch;
} break;
case D3D11_COMMON_TEXTURE_MAP_MODE_NONE:
case D3D11_COMMON_TEXTURE_MAP_MODE_BUFFER:
case D3D11_COMMON_TEXTURE_MAP_MODE_STAGING: {
auto packedFormatInfo = lookupFormatInfo(m_packedFormat);
VkImageAspectFlags aspects = packedFormatInfo->aspectMask;
VkExtent3D mipExtent = MipLevelExtent(subresource.mipLevel);
while (aspects) {
auto aspect = vk::getNextAspect(aspects);
auto extent = mipExtent;
auto elementSize = packedFormatInfo->elementSize;
if (packedFormatInfo->flags.test(DxvkFormatFlag::MultiPlane)) {
auto plane = &packedFormatInfo->planes[vk::getPlaneIndex(aspect)];
extent.width /= plane->blockSize.width;
extent.height /= plane->blockSize.height;
elementSize = plane->elementSize;
}
auto blockCount = util::computeBlockCount(extent, packedFormatInfo->blockSize);
if (!layout.RowPitch) {
layout.RowPitch = elementSize * blockCount.width;
layout.DepthPitch = elementSize * blockCount.width * blockCount.height;
}
VkDeviceSize size = elementSize * blockCount.width * blockCount.height * blockCount.depth;
if (aspect & AspectMask)
layout.Size += size;
else if (!layout.Size)
layout.Offset += size;
}
} break;
}
// D3D wants us to return the total subresource size in some instances
if (m_dimension < D3D11_RESOURCE_DIMENSION_TEXTURE2D) layout.RowPitch = layout.Size;
if (m_dimension < D3D11_RESOURCE_DIMENSION_TEXTURE3D) layout.DepthPitch = layout.Size;
return layout;
return DetermineSubresourceLayout(nullptr, subresource);
}
@ -425,8 +373,31 @@ namespace dxvk {
return viewFormat.Format == baseFormat.Format && planeCount == 1;
}
}
void D3D11CommonTexture::SetDebugName(const char* pName) {
if (m_image) {
m_device->GetContext()->InjectCs(DxvkCsQueue::HighPriority, [
cImage = m_image,
cName = std::string(pName ? pName : "")
] (DxvkContext* ctx) {
ctx->setDebugName(cImage, cName.c_str());
});
}
if (m_mapMode == D3D11_COMMON_TEXTURE_MAP_MODE_STAGING) {
for (uint32_t i = 0; i < m_buffers.size(); i++) {
m_device->GetContext()->InjectCs(DxvkCsQueue::HighPriority, [
cBuffer = m_buffers[i].buffer,
cName = std::string(pName ? pName : "")
] (DxvkContext* ctx) {
ctx->setDebugName(cBuffer, cName.c_str());
});
}
}
}
HRESULT D3D11CommonTexture::NormalizeTextureProperties(D3D11_COMMON_TEXTURE_DESC* pDesc) {
if (pDesc->Width == 0 || pDesc->Height == 0 || pDesc->Depth == 0 || pDesc->ArraySize == 0)
return E_INVALIDARG;
@ -572,136 +543,178 @@ namespace dxvk {
return (support.linear & Features) == Features
|| (support.optimal & Features) == Features;
}
VkImageUsageFlags D3D11CommonTexture::EnableMetaCopyUsage(
VkFormat Format,
VkImageTiling Tiling) const {
VkFormatFeatureFlags2 requestedFeatures = 0;
if (Format == VK_FORMAT_D16_UNORM || Format == VK_FORMAT_D32_SFLOAT) {
requestedFeatures |= VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_BIT
| VK_FORMAT_FEATURE_2_DEPTH_STENCIL_ATTACHMENT_BIT;
}
if (Format == VK_FORMAT_R16_UNORM || Format == VK_FORMAT_R32_SFLOAT) {
requestedFeatures |= VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_BIT
| VK_FORMAT_FEATURE_2_COLOR_ATTACHMENT_BIT;
}
if (Format == VK_FORMAT_D32_SFLOAT_S8_UINT || Format == VK_FORMAT_D24_UNORM_S8_UINT)
requestedFeatures |= VK_FORMAT_FEATURE_2_DEPTH_STENCIL_ATTACHMENT_BIT;
if (!requestedFeatures)
return 0;
// Enable usage flags for all supported and requested features
DxvkFormatFeatures support = m_device->GetDXVKDevice()->getFormatFeatures(Format);
requestedFeatures &= Tiling == VK_IMAGE_TILING_OPTIMAL
? support.optimal
: support.linear;
VkImageUsageFlags requestedUsage = 0;
if (requestedFeatures & VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_BIT)
requestedUsage |= VK_IMAGE_USAGE_SAMPLED_BIT;
if (requestedFeatures & VK_FORMAT_FEATURE_2_DEPTH_STENCIL_ATTACHMENT_BIT)
requestedUsage |= VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
if (requestedFeatures & VK_FORMAT_FEATURE_2_COLOR_ATTACHMENT_BIT)
requestedUsage |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
return requestedUsage;
}
VkImageUsageFlags D3D11CommonTexture::EnableMetaPackUsage(
VkFormat Format,
UINT CpuAccess) const {
if ((CpuAccess & D3D11_CPU_ACCESS_READ) == 0)
return 0;
const auto dsMask = VK_IMAGE_ASPECT_DEPTH_BIT
| VK_IMAGE_ASPECT_STENCIL_BIT;
auto formatInfo = lookupFormatInfo(Format);
return formatInfo->aspectMask == dsMask
? VK_IMAGE_USAGE_SAMPLED_BIT
: 0;
}
VkMemoryPropertyFlags D3D11CommonTexture::GetMemoryFlags() const {
std::pair<D3D11_COMMON_TEXTURE_MAP_MODE, VkMemoryPropertyFlags> D3D11CommonTexture::DetermineMapMode(
const DxvkImageCreateInfo* pImageInfo) const {
// Don't map an image unless the application requests it
if (!m_desc.CPUAccessFlags)
return { D3D11_COMMON_TEXTURE_MAP_MODE_NONE, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT };
// For default images, always use a persistent staging buffer. Readback
// may cause a GPU sync, but nobody seems to be using this feature anyway.
if (m_desc.Usage == D3D11_USAGE_DEFAULT)
return { D3D11_COMMON_TEXTURE_MAP_MODE_BUFFER, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT };
// If the resource cannot be used in the actual rendering pipeline, we
// do not need to create an actual image and can instead implement copy
// functions as buffer-to-image and image-to-buffer copies.
if (m_desc.Usage == D3D11_USAGE_STAGING)
return { D3D11_COMMON_TEXTURE_MAP_MODE_STAGING, 0u };
// If the packed format and image format don't match, we need to use
// a staging buffer and perform format conversion when mapping.
if (m_packedFormat != pImageInfo->format)
return { D3D11_COMMON_TEXTURE_MAP_MODE_DYNAMIC, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT };
// Multi-plane and depth-stencil images have a special memory layout
// in D3D11, so we can't expose those directly to the app
auto formatInfo = lookupFormatInfo(pImageInfo->format);
if (formatInfo->aspectMask != VK_IMAGE_ASPECT_COLOR_BIT)
return { D3D11_COMMON_TEXTURE_MAP_MODE_DYNAMIC, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT };
// If we can't use linear tiling for this image, we have to use a buffer
if (!CheckImageSupport(pImageInfo, VK_IMAGE_TILING_LINEAR))
return { D3D11_COMMON_TEXTURE_MAP_MODE_DYNAMIC, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT };
// Determine memory flags for the actual image if we use direct mapping.
// Depending on the concrete use case, we may fall back to different
// memory types.
VkMemoryPropertyFlags memoryFlags = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT
| VK_MEMORY_PROPERTY_HOST_COHERENT_BIT;
bool useCached = (m_device->GetOptions()->cachedDynamicResources == ~0u)
|| (m_device->GetOptions()->cachedDynamicResources & m_desc.BindFlags);
|| (m_device->GetOptions()->cachedDynamicResources & m_desc.BindFlags)
|| (m_desc.CPUAccessFlags & D3D11_CPU_ACCESS_READ);
if (m_desc.Usage == D3D11_USAGE_STAGING || useCached)
memoryFlags |= VK_MEMORY_PROPERTY_HOST_CACHED_BIT;
else if (m_desc.Usage == D3D11_USAGE_DEFAULT || m_desc.BindFlags)
else if (m_desc.BindFlags)
memoryFlags |= VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
return memoryFlags;
// If there are multiple subresources, go through a buffer because
// we can otherwise not really discard individual subresources.
if (m_desc.ArraySize > 1u || m_desc.MipLevels != 1u)
return { D3D11_COMMON_TEXTURE_MAP_MODE_DYNAMIC, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT };
// If the image is essentially linear already, expose it directly since
// there won't be any tangible benefit to using optimal tiling anyway.
VkExtent3D blockCount = util::computeBlockCount(pImageInfo->extent, formatInfo->blockSize);
if (blockCount.height == 1u && blockCount.depth == 1u)
return { D3D11_COMMON_TEXTURE_MAP_MODE_DIRECT, memoryFlags };
// If the image looks like a video, we can generally expect it to get
// updated and read once per frame. This is one of the most common use
// cases for a mapped image, expose it directly in order to avoid copies.
if (blockCount.depth == 1u && blockCount.height >= 160 && formatInfo->elementSize <= 4u) {
static const std::array<std::pair<uint32_t, uint32_t>, 3> videoApectRatios = {{
{ 4, 3 },
{ 16, 9 },
{ 21, 9 },
}};
bool isVideoAspectRatio = false;
for (const auto& a : videoApectRatios) {
// Due to codec limitations, video dimensions are often rounded to
// a multiple of 8. Account for this when checking the size.
isVideoAspectRatio |= blockCount.width > (a.first * (blockCount.height - 8u)) / a.second
&& blockCount.width < (a.first * (blockCount.height + 8u)) / a.second;
}
if (isVideoAspectRatio) {
// Keep video images in system memory to not waste precious HVV space
return { D3D11_COMMON_TEXTURE_MAP_MODE_DIRECT, memoryFlags & ~VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT };
}
}
// If the image exceeds a certain size, map it directly because the overhead
// of potentially copying the whole thing every frame likely outweighs any
// benefit we might get from faster memory and tiling. This solves such an
// issue in Warhammer III, which discards a 48 MB texture every single frame.
constexpr VkDeviceSize MaxImageStagingBufferSize = 1ull << 20;
VkDeviceSize imageSize = util::flattenImageExtent(blockCount) * formatInfo->elementSize;
if (imageSize > MaxImageStagingBufferSize)
return { D3D11_COMMON_TEXTURE_MAP_MODE_DIRECT, memoryFlags };
// For smaller images, use a staging buffer. There are some common use
// cases where the image will only get written once, e.g. SMAA look-up
// tables in some games, which will benefit from faster GPU access.
return { D3D11_COMMON_TEXTURE_MAP_MODE_DYNAMIC, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT };
}
D3D11_COMMON_TEXTURE_MAP_MODE D3D11CommonTexture::DetermineMapMode(
const DxvkImageCreateInfo* pImageInfo) const {
// Don't map an image unless the application requests it
if (!m_desc.CPUAccessFlags)
return D3D11_COMMON_TEXTURE_MAP_MODE_NONE;
// If the resource cannot be used in the actual rendering pipeline, we
// do not need to create an actual image and can instead implement copy
// functions as buffer-to-image and image-to-buffer copies.
if (!m_desc.BindFlags && m_desc.Usage != D3D11_USAGE_DEFAULT)
return D3D11_COMMON_TEXTURE_MAP_MODE_STAGING;
D3D11_COMMON_TEXTURE_SUBRESOURCE_LAYOUT D3D11CommonTexture::DetermineSubresourceLayout(
const DxvkImageCreateInfo* pImageInfo,
const VkImageSubresource& subresource) const {
auto formatInfo = lookupFormatInfo(m_packedFormat);
// Depth-stencil formats in D3D11 can be mapped and follow special
// packing rules, so we need to copy that data into a buffer first
if (GetPackedDepthStencilFormat(m_desc.Format))
return D3D11_COMMON_TEXTURE_MAP_MODE_BUFFER;
if (m_mapMode == D3D11_COMMON_TEXTURE_MAP_MODE_DIRECT) {
VkSubresourceLayout vkLayout = m_device->GetDXVKDevice()->queryImageSubresourceLayout(*pImageInfo, subresource);
// Multi-plane images have a special memory layout in D3D11
if (lookupFormatInfo(pImageInfo->format)->flags.test(DxvkFormatFlag::MultiPlane))
return D3D11_COMMON_TEXTURE_MAP_MODE_BUFFER;
D3D11_COMMON_TEXTURE_SUBRESOURCE_LAYOUT result = { };
result.Offset = vkLayout.offset;
result.RowPitch = vkLayout.rowPitch;
result.DepthPitch = vkLayout.depthPitch;
// If we can't use linear tiling for this image, we have to use a buffer
if (!this->CheckImageSupport(pImageInfo, VK_IMAGE_TILING_LINEAR))
return D3D11_COMMON_TEXTURE_MAP_MODE_BUFFER;
// We will only ever use direct mapping for single-aspect images,
// so ignore any sort of multi-plane shenanigans on this path
auto mipExtent = MipLevelExtent(subresource.mipLevel);
auto blockCount = util::computeBlockCount(mipExtent, formatInfo->blockSize);
// If supported and requested, create a linear image. Default images
// can be used for resolves and other operations regardless of bind
// flags, so we need to use a proper image for those.
if (m_desc.TextureLayout == D3D11_TEXTURE_LAYOUT_ROW_MAJOR)
return D3D11_COMMON_TEXTURE_MAP_MODE_DIRECT;
// If the image dimensions support it, try to look as close to a
// linear buffer as we can. Some games use the depth pitch as a
// subresource size and will crash if it includes any padding.
if (blockCount.depth == 1u) {
if (blockCount.height == 1u) {
result.RowPitch = formatInfo->elementSize * blockCount.width;
result.DepthPitch = result.RowPitch;
} else {
result.DepthPitch = vkLayout.rowPitch * blockCount.height;
}
}
// For default images, prefer direct mapping if the image is CPU readable
// since mapping for reads would have to stall otherwise. If the image is
// only writable, prefer a write-through buffer.
if (m_desc.Usage == D3D11_USAGE_DEFAULT) {
return (m_desc.CPUAccessFlags & D3D11_CPU_ACCESS_READ)
? D3D11_COMMON_TEXTURE_MAP_MODE_DIRECT
: D3D11_COMMON_TEXTURE_MAP_MODE_BUFFER;
result.Size = blockCount.depth * result.DepthPitch;
return result;
} else {
D3D11_COMMON_TEXTURE_SUBRESOURCE_LAYOUT result = { };
VkImageAspectFlags aspects = formatInfo->aspectMask;
VkExtent3D mipExtent = MipLevelExtent(subresource.mipLevel);
while (aspects) {
auto aspect = vk::getNextAspect(aspects);
auto extent = mipExtent;
auto elementSize = formatInfo->elementSize;
if (formatInfo->flags.test(DxvkFormatFlag::MultiPlane)) {
auto plane = &formatInfo->planes[vk::getPlaneIndex(aspect)];
extent.width /= plane->blockSize.width;
extent.height /= plane->blockSize.height;
elementSize = plane->elementSize;
}
auto blockCount = util::computeBlockCount(extent, formatInfo->blockSize);
if (!result.RowPitch) {
result.RowPitch = elementSize * blockCount.width;
result.DepthPitch = elementSize * blockCount.width * blockCount.height;
}
VkDeviceSize size = elementSize * blockCount.width * blockCount.height * blockCount.depth;
if (aspect & subresource.aspectMask)
result.Size += size;
else if (!result.Size)
result.Offset += size;
}
return result;
}
// The overhead of frequently uploading large dynamic images may outweigh
// the benefit of linear tiling, so use a linear image in those cases.
VkDeviceSize threshold = m_device->GetOptions()->maxDynamicImageBufferSize;
VkDeviceSize size = util::computeImageDataSize(pImageInfo->format, pImageInfo->extent);
if (size > threshold)
return D3D11_COMMON_TEXTURE_MAP_MODE_DIRECT;
// Dynamic images that can be sampled by a shader should generally go
// through a buffer to allow optimal tiling and to avoid running into
// bugs where games ignore the pitch when mapping the image.
return D3D11_COMMON_TEXTURE_MAP_MODE_BUFFER;
}
@ -747,23 +760,25 @@ namespace dxvk {
}
D3D11CommonTexture::MappedBuffer D3D11CommonTexture::CreateMappedBuffer(UINT MipLevel) const {
void D3D11CommonTexture::CreateMappedBuffer(UINT Subresource) {
const DxvkFormatInfo* formatInfo = lookupFormatInfo(
m_device->LookupPackedFormat(m_desc.Format, GetFormatMode()).Format);
DxvkBufferCreateInfo info;
info.size = GetSubresourceLayout(formatInfo->aspectMask, MipLevel).Size;
info.size = GetSubresourceLayout(formatInfo->aspectMask, Subresource).Size;
info.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT
| VK_BUFFER_USAGE_TRANSFER_DST_BIT
| VK_BUFFER_USAGE_STORAGE_BUFFER_BIT
| VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT
| VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT;
info.stages = VK_PIPELINE_STAGE_TRANSFER_BIT
| VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
| VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT
| VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
info.access = VK_ACCESS_TRANSFER_READ_BIT
| VK_ACCESS_TRANSFER_WRITE_BIT
| VK_ACCESS_SHADER_READ_BIT
| VK_ACCESS_SHADER_WRITE_BIT;
info.debugName = "Image buffer";
// We may read mapped buffers even if it is
// marked as CPU write-only on the D3D11 side.
@ -782,11 +797,18 @@ namespace dxvk {
if (m_desc.Usage == D3D11_USAGE_STAGING || useCached)
memType |= VK_MEMORY_PROPERTY_HOST_CACHED_BIT;
MappedBuffer result;
result.buffer = m_device->GetDXVKDevice()->createBuffer(info, memType);
result.slice = result.buffer->getSliceHandle();
return result;
auto& entry = m_buffers[Subresource];
entry.buffer = m_device->GetDXVKDevice()->createBuffer(info, memType);
entry.slice = entry.buffer->storage();
}
void D3D11CommonTexture::FreeMappedBuffer(
UINT Subresource) {
auto& entry = m_buffers[Subresource];
entry.buffer = nullptr;
entry.slice = nullptr;
}
@ -802,33 +824,34 @@ namespace dxvk {
VkImageLayout D3D11CommonTexture::OptimizeLayout(VkImageUsageFlags Usage) {
const VkImageUsageFlags usageFlags = Usage;
// Filter out unnecessary flags. Transfer operations
// are handled by the backend in a transparent manner.
Usage &= ~(VK_IMAGE_USAGE_TRANSFER_DST_BIT
| VK_IMAGE_USAGE_TRANSFER_SRC_BIT);
// Storage images require GENERAL.
if (Usage & VK_IMAGE_USAGE_STORAGE_BIT)
return VK_IMAGE_LAYOUT_GENERAL;
// Also use GENERAL if the image cannot be rendered to. This
// should not harm any hardware in practice and may avoid some
// redundant layout transitions for regular textures.
if (Usage == VK_IMAGE_USAGE_SAMPLED_BIT)
return VK_IMAGE_LAYOUT_GENERAL;
// If the image is used only as an attachment, we never
// have to transform the image back to a different layout
// have to transform the image back to a different layout.
if (Usage == VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT)
return VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
if (Usage == VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT)
return VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
Usage &= ~(VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT
| VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT);
// If the image is used for reading but not as a storage
// image, we can optimize the image for texture access
if (Usage == VK_IMAGE_USAGE_SAMPLED_BIT) {
return usageFlags & VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT
? VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL
: VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
}
// Otherwise, we have to stick with the default layout
return VK_IMAGE_LAYOUT_GENERAL;
// Otherwise, pick a layout that can be used for reading.
return usageFlags & VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT
? VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL
: VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
}
@ -1195,8 +1218,13 @@ namespace dxvk {
pDesc->CPUAccessFlags = m_texture.Desc()->CPUAccessFlags;
pDesc->MiscFlags = m_texture.Desc()->MiscFlags;
}
void STDMETHODCALLTYPE D3D11Texture1D::SetDebugName(const char* pName) {
m_texture.SetDebugName(pName);
}
///////////////////////////////////////////
// D 3 D 1 1 T E X T U R E 2 D
D3D11Texture2D::D3D11Texture2D(
@ -1378,6 +1406,11 @@ namespace dxvk {
}
void STDMETHODCALLTYPE D3D11Texture2D::SetDebugName(const char* pName) {
m_texture.SetDebugName(pName);
}
///////////////////////////////////////////
// D 3 D 1 1 T E X T U R E 3 D
D3D11Texture3D::D3D11Texture3D(
@ -1489,6 +1522,11 @@ namespace dxvk {
}
void STDMETHODCALLTYPE D3D11Texture3D::SetDebugName(const char* pName) {
m_texture.SetDebugName(pName);
}
D3D11CommonTexture* GetCommonTexture(ID3D11Resource* pResource) {
D3D11_RESOURCE_DIMENSION dimension = D3D11_RESOURCE_DIMENSION_UNKNOWN;
pResource->GetType(&dimension);

View file

@ -1,5 +1,7 @@
#pragma once
#include "../util/util_small_vector.h"
#include "../dxvk/dxvk_cs.h"
#include "../dxvk/dxvk_device.h"
@ -24,6 +26,7 @@ namespace dxvk {
enum D3D11_COMMON_TEXTURE_MAP_MODE {
D3D11_COMMON_TEXTURE_MAP_MODE_NONE, ///< Not mapped
D3D11_COMMON_TEXTURE_MAP_MODE_BUFFER, ///< Mapped through buffer
D3D11_COMMON_TEXTURE_MAP_MODE_DYNAMIC, ///< Mapped through temporary buffer
D3D11_COMMON_TEXTURE_MAP_MODE_DIRECT, ///< Directly mapped to host mem
D3D11_COMMON_TEXTURE_MAP_MODE_STAGING, ///< Buffer only, no image
};
@ -81,7 +84,9 @@ namespace dxvk {
class D3D11CommonTexture {
public:
static constexpr uint32_t UnmappedSubresource = ~0u;
D3D11CommonTexture(
ID3D11Resource* pInterface,
D3D11Device* pDevice,
@ -170,29 +175,73 @@ namespace dxvk {
return m_mapMode;
}
/**
* \brief Checks whether this texture has an image
*
* Staging textures will not use an image, only mapped buffers.
* \returns \c true for non-staging textures.
*/
bool HasImage() const {
return m_mapMode != D3D11_COMMON_TEXTURE_MAP_MODE_STAGING;
}
/**
* \brief Checks whether this texture has persistent buffers
* \returns \c true for buffer-mapped textures or staging textures.
*/
bool HasPersistentBuffers() const {
return m_mapMode == D3D11_COMMON_TEXTURE_MAP_MODE_BUFFER
|| m_mapMode == D3D11_COMMON_TEXTURE_MAP_MODE_STAGING;
}
/**
* \brief Map type of a given subresource
*
* \param [in] Subresource Subresource index
* \returns Current map mode of that subresource
*/
D3D11_MAP GetMapType(UINT Subresource) const {
uint32_t GetMapType(UINT Subresource) const {
return Subresource < m_mapInfo.size()
? D3D11_MAP(m_mapInfo[Subresource].mapType)
: D3D11_MAP(~0u);
? m_mapInfo[Subresource].mapType
: UnmappedSubresource;
}
/**
* \brief Sets map type for a given subresource
*
*
* Also ensures taht a staging buffer is created
* in case of dynamic mapping.
* \param [in] Subresource The subresource
* \param [in] MapType The map type
*/
void SetMapType(UINT Subresource, D3D11_MAP MapType) {
if (Subresource < m_mapInfo.size())
m_mapInfo[Subresource].mapType = MapType;
void NotifyMap(UINT Subresource, D3D11_MAP MapType) {
if (likely(Subresource < m_mapInfo.size())) {
m_mapInfo[Subresource].mapType = uint32_t(MapType);
if (m_mapMode == D3D11_COMMON_TEXTURE_MAP_MODE_DYNAMIC)
CreateMappedBuffer(Subresource);
}
}
/**
* \brief Resets map info for a given subresource
*
* For dynamic mapping, this will also free the
* staging buffer.
* \param [in] Subresource The subresource
*/
void NotifyUnmap(UINT Subresource) {
if (likely(Subresource < m_mapInfo.size())) {
m_mapInfo[Subresource].mapType = UnmappedSubresource;
if (m_mapMode == D3D11_COMMON_TEXTURE_MAP_MODE_DYNAMIC)
FreeMappedBuffer(Subresource);
if (Subresource < m_buffers.size())
m_buffers[Subresource].dirtyRegions.clear();
}
}
/**
* \brief The DXVK image
* \returns The DXVK image
@ -219,13 +268,13 @@ namespace dxvk {
* \param [in] Subresource Subresource to discard
* \returns Newly allocated mapped buffer slice
*/
DxvkBufferSliceHandle DiscardSlice(UINT Subresource) {
Rc<DxvkResourceAllocation> DiscardSlice(UINT Subresource) {
if (Subresource < m_buffers.size()) {
DxvkBufferSliceHandle slice = m_buffers[Subresource].buffer->allocSlice();
Rc<DxvkResourceAllocation> slice = m_buffers[Subresource].buffer->allocateStorage();
m_buffers[Subresource].slice = slice;
return slice;
} else {
return DxvkBufferSliceHandle();
return nullptr;
}
}
@ -235,10 +284,10 @@ namespace dxvk {
* \param [in] Subresource Subresource index to query
* \returns Currently mapped buffer slice
*/
DxvkBufferSliceHandle GetMappedSlice(UINT Subresource) const {
Rc<DxvkResourceAllocation> GetMappedSlice(UINT Subresource) const {
return Subresource < m_buffers.size()
? m_buffers[Subresource].slice
: DxvkBufferSliceHandle();
: nullptr;
}
/**
@ -261,17 +310,7 @@ namespace dxvk {
* \returns \c true if tracking is supported for this resource
*/
bool HasSequenceNumber() const {
if (m_mapMode == D3D11_COMMON_TEXTURE_MAP_MODE_NONE)
return false;
// For buffer-mapped images we only need to track copies to
// and from that buffer, so we can safely ignore bind flags
if (m_mapMode == D3D11_COMMON_TEXTURE_MAP_MODE_BUFFER)
return m_desc.Usage != D3D11_USAGE_DEFAULT;
// Otherwise we can only do accurate tracking if the
// image cannot be used in the rendering pipeline.
return m_desc.BindFlags == 0;
return m_mapMode == D3D11_COMMON_TEXTURE_MAP_MODE_STAGING;
}
/**
@ -303,6 +342,52 @@ namespace dxvk {
}
}
/**
* \brief Allocates new backing storage
* \returns New backing storage for the image
*/
Rc<DxvkResourceAllocation> AllocStorage() {
return m_image->allocateStorage();
}
/**
* \brief Discards backing storage
*
* Also updates the mapped pointer if the image is mapped.
* \returns New backing storage for the image
*/
Rc<DxvkResourceAllocation> DiscardStorage() {
auto storage = m_image->allocateStorage();
m_mapPtr = storage->mapPtr();
return storage;
}
/**
* \brief Queries map pointer of the raw image
*
* If the image is mapped directly, the returned pointer will
* point directly to the image, otherwise it will point to a
* buffer that contains image data.
* \param [in] Subresource Subresource index
* \param [in] Offset Offset derived from the subresource layout
*/
void* GetMapPtr(uint32_t Subresource, size_t Offset) const {
switch (m_mapMode) {
case D3D11_COMMON_TEXTURE_MAP_MODE_DIRECT:
return reinterpret_cast<char*>(m_mapPtr) + Offset;
case D3D11_COMMON_TEXTURE_MAP_MODE_BUFFER:
case D3D11_COMMON_TEXTURE_MAP_MODE_DYNAMIC:
case D3D11_COMMON_TEXTURE_MAP_MODE_STAGING:
return reinterpret_cast<char*>(m_buffers[Subresource].slice->mapPtr()) + Offset;
case D3D11_COMMON_TEXTURE_MAP_MODE_NONE:
return nullptr;
}
return nullptr;
}
/**
* \brief Adds a dirty region
*
@ -320,17 +405,6 @@ namespace dxvk {
m_buffers[Subresource].dirtyRegions.push_back(region);
}
/**
* \brief Clears dirty regions
*
* Removes all dirty regions from the given subresource.
* \param [in] Subresource Subresource index
*/
void ClearDirtyRegions(UINT Subresource) {
if (Subresource < m_buffers.size())
m_buffers[Subresource].dirtyRegions.clear();
}
/**
* \brief Counts dirty regions
*
@ -390,7 +464,13 @@ namespace dxvk {
*/
VkImageSubresource GetSubresourceFromIndex(
VkImageAspectFlags Aspect,
UINT Subresource) const;
UINT Subresource) const {
VkImageSubresource result;
result.aspectMask = Aspect;
result.mipLevel = Subresource % m_desc.MipLevels;
result.arrayLayer = Subresource / m_desc.MipLevels;
return result;
}
/**
* \brief Computes subresource layout for the given subresource
@ -445,6 +525,14 @@ namespace dxvk {
return m_11on12;
}
/**
* \brief Sets debug name for texture
*
* Passes the given name to the backing image or buffer.
* \param [in] name Debug name
*/
void SetDebugName(const char* pName);
/**
* \brief Normalizes and validates texture description
*
@ -473,15 +561,16 @@ namespace dxvk {
private:
struct MappedBuffer {
Rc<DxvkBuffer> buffer;
DxvkBufferSliceHandle slice;
Rc<DxvkBuffer> buffer;
Rc<DxvkResourceAllocation> slice;
std::vector<D3D11_COMMON_TEXTURE_REGION> dirtyRegions;
};
struct MappedInfo {
D3D11_MAP mapType;
uint64_t seq;
D3D11_COMMON_TEXTURE_SUBRESOURCE_LAYOUT layout = { };
uint32_t mapType = UnmappedSubresource;
uint64_t seq = 0u;
};
ID3D11Resource* m_interface;
@ -494,11 +583,16 @@ namespace dxvk {
VkFormat m_packedFormat;
Rc<DxvkImage> m_image;
std::vector<MappedBuffer> m_buffers;
std::vector<MappedInfo> m_mapInfo;
small_vector<MappedBuffer, 6> m_buffers;
small_vector<MappedInfo, 6> m_mapInfo;
void* m_mapPtr = nullptr;
void CreateMappedBuffer(
UINT Subresource);
MappedBuffer CreateMappedBuffer(
UINT MipLevel) const;
void FreeMappedBuffer(
UINT Subresource);
BOOL CheckImageSupport(
const DxvkImageCreateInfo* pImageInfo,
@ -508,21 +602,15 @@ namespace dxvk {
VkFormat Format,
VkFormatFeatureFlags2 Features) const;
VkImageUsageFlags EnableMetaCopyUsage(
VkFormat Format,
VkImageTiling Tiling) const;
VkImageUsageFlags EnableMetaPackUsage(
VkFormat Format,
UINT CpuAccess) const;
VkMemoryPropertyFlags GetMemoryFlags() const;
D3D11_COMMON_TEXTURE_MAP_MODE DetermineMapMode(
std::pair<D3D11_COMMON_TEXTURE_MAP_MODE, VkMemoryPropertyFlags> DetermineMapMode(
const DxvkImageCreateInfo* pImageInfo) const;
D3D11_COMMON_TEXTURE_SUBRESOURCE_LAYOUT DetermineSubresourceLayout(
const DxvkImageCreateInfo* pImageInfo,
const VkImageSubresource& subresource) const;
void ExportImageInfo();
static BOOL IsR32UavCompatibleFormat(
DXGI_FORMAT Format);
@ -679,6 +767,8 @@ namespace dxvk {
void STDMETHODCALLTYPE GetDesc(
D3D11_TEXTURE1D_DESC *pDesc) final;
void STDMETHODCALLTYPE SetDebugName(const char* pName) final;
D3D11CommonTexture* GetCommonTexture() {
return &m_texture;
}
@ -745,6 +835,8 @@ namespace dxvk {
void STDMETHODCALLTYPE GetDesc1(
D3D11_TEXTURE2D_DESC1* pDesc) final;
void STDMETHODCALLTYPE SetDebugName(const char* pName) final;
D3D11CommonTexture* GetCommonTexture() {
return &m_texture;
}
@ -795,6 +887,8 @@ namespace dxvk {
void STDMETHODCALLTYPE GetDesc1(
D3D11_TEXTURE3D_DESC1* pDesc) final;
void STDMETHODCALLTYPE SetDebugName(const char* pName) final;
D3D11CommonTexture* GetCommonTexture() {
return &m_texture;
}

View file

@ -52,15 +52,15 @@ namespace dxvk {
* \returns Corresponding Vulkan shader stage
*/
constexpr VkShaderStageFlagBits GetShaderStage(DxbcProgramType ProgramType) {
switch (ProgramType) {
case DxbcProgramType::VertexShader: return VK_SHADER_STAGE_VERTEX_BIT;
case DxbcProgramType::HullShader: return VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT;
case DxbcProgramType::DomainShader: return VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT;
case DxbcProgramType::GeometryShader: return VK_SHADER_STAGE_GEOMETRY_BIT;
case DxbcProgramType::PixelShader: return VK_SHADER_STAGE_FRAGMENT_BIT;
case DxbcProgramType::ComputeShader: return VK_SHADER_STAGE_COMPUTE_BIT;
default: return VkShaderStageFlagBits(0);
}
constexpr uint64_t lut
= (uint64_t(VK_SHADER_STAGE_VERTEX_BIT) << (8u * uint32_t(DxbcProgramType::VertexShader)))
| (uint64_t(VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT) << (8u * uint32_t(DxbcProgramType::HullShader)))
| (uint64_t(VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT) << (8u * uint32_t(DxbcProgramType::DomainShader)))
| (uint64_t(VK_SHADER_STAGE_GEOMETRY_BIT) << (8u * uint32_t(DxbcProgramType::GeometryShader)))
| (uint64_t(VK_SHADER_STAGE_FRAGMENT_BIT) << (8u * uint32_t(DxbcProgramType::PixelShader)))
| (uint64_t(VK_SHADER_STAGE_COMPUTE_BIT) << (8u * uint32_t(DxbcProgramType::ComputeShader)));
return VkShaderStageFlagBits((lut >> (8u * uint32_t(ProgramType))) & 0xff);
}
}
}

View file

@ -173,35 +173,23 @@ namespace dxvk {
Rc<DxvkImage> dxvkImage = GetCommonTexture(pResource)->GetImage();
if (!(dxvkImage->info().usage & VK_IMAGE_USAGE_SAMPLED_BIT)) {
DxvkImageCreateInfo info = dxvkImage->info();
info.flags = VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT | VK_IMAGE_CREATE_EXTENDED_USAGE_BIT;
info.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT;
info.stages = VK_PIPELINE_STAGE_TRANSFER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
info.access = VK_ACCESS_TRANSFER_WRITE_BIT | VK_ACCESS_SHADER_READ_BIT;
info.tiling = VK_IMAGE_TILING_OPTIMAL;
info.layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
info.shared = VK_FALSE;
dxvkImage = m_copy = pDevice->GetDXVKDevice()->createImage(info, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
}
DXGI_VK_FORMAT_INFO formatInfo = pDevice->LookupFormat(resourceDesc.Format, DXGI_VK_FORMAT_MODE_COLOR);
DXGI_VK_FORMAT_FAMILY formatFamily = pDevice->LookupFamily(resourceDesc.Format, DXGI_VK_FORMAT_MODE_COLOR);
VkImageAspectFlags aspectMask = lookupFormatInfo(formatInfo.Format)->aspectMask;
DxvkImageViewCreateInfo viewInfo;
viewInfo.format = formatInfo.Format;
viewInfo.swizzle = formatInfo.Swizzle;
viewInfo.usage = VK_IMAGE_USAGE_SAMPLED_BIT;
DxvkImageViewKey viewInfo;
viewInfo.format = formatInfo.Format;
viewInfo.usage = VK_IMAGE_USAGE_SAMPLED_BIT;
viewInfo.packedSwizzle = DxvkImageViewKey::packSwizzle(formatInfo.Swizzle);
switch (m_desc.ViewDimension) {
case D3D11_VPIV_DIMENSION_TEXTURE2D:
viewInfo.type = VK_IMAGE_VIEW_TYPE_2D;
viewInfo.minLevel = m_desc.Texture2D.MipSlice;
viewInfo.numLevels = 1;
viewInfo.minLayer = 0;
viewInfo.numLayers = 1;
viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
viewInfo.mipIndex = m_desc.Texture2D.MipSlice;
viewInfo.mipCount = 1;
viewInfo.layerIndex = m_desc.Texture2D.ArraySlice;
viewInfo.layerCount = 1;
break;
case D3D11_VPIV_DIMENSION_UNKNOWN:
@ -209,17 +197,17 @@ namespace dxvk {
}
m_subresources.aspectMask = aspectMask;
m_subresources.baseArrayLayer = viewInfo.minLayer;
m_subresources.layerCount = viewInfo.numLayers;
m_subresources.mipLevel = viewInfo.minLevel;
m_subresources.baseArrayLayer = viewInfo.layerIndex;
m_subresources.layerCount = viewInfo.layerCount;
m_subresources.mipLevel = viewInfo.mipIndex;
for (uint32_t i = 0; aspectMask && i < m_views.size(); i++) {
viewInfo.aspect = vk::getNextAspect(aspectMask);
viewInfo.aspects = vk::getNextAspect(aspectMask);
if (viewInfo.aspect != VK_IMAGE_ASPECT_COLOR_BIT)
if (viewInfo.aspects != VK_IMAGE_ASPECT_COLOR_BIT)
viewInfo.format = formatFamily.Formats[i];
m_views[i] = pDevice->GetDXVKDevice()->createImageView(dxvkImage, viewInfo);
m_views[i] = dxvkImage->createView(viewInfo);
}
m_isYCbCr = IsYCbCrFormat(resourceDesc.Format);
@ -287,35 +275,34 @@ namespace dxvk {
DXGI_VK_FORMAT_INFO formatInfo = pDevice->LookupFormat(
resourceDesc.Format, DXGI_VK_FORMAT_MODE_COLOR);
DxvkImageViewCreateInfo viewInfo;
viewInfo.format = formatInfo.Format;
viewInfo.aspect = lookupFormatInfo(viewInfo.format)->aspectMask;
viewInfo.swizzle = formatInfo.Swizzle;
viewInfo.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
DxvkImageViewKey viewInfo;
viewInfo.format = formatInfo.Format;
viewInfo.aspects = lookupFormatInfo(viewInfo.format)->aspectMask;
viewInfo.packedSwizzle = DxvkImageViewKey::packSwizzle(formatInfo.Swizzle);
viewInfo.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
switch (m_desc.ViewDimension) {
case D3D11_VPOV_DIMENSION_TEXTURE2D:
viewInfo.type = VK_IMAGE_VIEW_TYPE_2D;
viewInfo.minLevel = m_desc.Texture2D.MipSlice;
viewInfo.numLevels = 1;
viewInfo.minLayer = 0;
viewInfo.numLayers = 1;
viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
viewInfo.mipIndex = m_desc.Texture2D.MipSlice;
viewInfo.mipCount = 1;
viewInfo.layerIndex = 0;
viewInfo.layerCount = 1;
break;
case D3D11_VPOV_DIMENSION_TEXTURE2DARRAY:
viewInfo.type = VK_IMAGE_VIEW_TYPE_2D_ARRAY;
viewInfo.minLevel = m_desc.Texture2DArray.MipSlice;
viewInfo.numLevels = 1;
viewInfo.minLayer = m_desc.Texture2DArray.FirstArraySlice;
viewInfo.numLayers = m_desc.Texture2DArray.ArraySize;
viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D_ARRAY;
viewInfo.mipIndex = m_desc.Texture2DArray.MipSlice;
viewInfo.mipCount = 1;
viewInfo.layerIndex = m_desc.Texture2DArray.FirstArraySlice;
viewInfo.layerCount = m_desc.Texture2DArray.ArraySize;
break;
case D3D11_VPOV_DIMENSION_UNKNOWN:
throw DxvkError("Invalid view dimension");
}
m_view = pDevice->GetDXVKDevice()->createImageView(
GetCommonTexture(pResource)->GetImage(), viewInfo);
m_view = GetCommonTexture(pResource)->GetImage()->createView(viewInfo);
}
@ -1026,6 +1013,10 @@ namespace dxvk {
const D3D11_VIDEO_PROCESSOR_STREAM* pStreams) {
D3D10DeviceLock lock = m_ctx->LockContext();
m_ctx->EmitCs([] (DxvkContext* ctx) {
ctx->beginDebugLabel(vk::makeLabel(0x59eaff, "Video blit"));
});
auto videoProcessor = static_cast<D3D11VideoProcessor*>(pVideoProcessor);
bool hasStreamsEnabled = false;
@ -1038,7 +1029,9 @@ namespace dxvk {
continue;
if (!hasStreamsEnabled) {
m_ctx->ResetDirtyTracking();
m_ctx->ResetCommandListState();
BindOutputView(pOutputView);
hasStreamsEnabled = true;
}
@ -1048,9 +1041,14 @@ namespace dxvk {
if (hasStreamsEnabled) {
UnbindResources();
m_ctx->RestoreCommandListState();
}
m_ctx->EmitCs([] (DxvkContext* ctx) {
ctx->endDebugLabel();
});
return S_OK;
}
@ -1185,6 +1183,13 @@ namespace dxvk {
auto dxvkView = static_cast<D3D11VideoProcessorOutputView*>(pOutputView)->GetView();
m_ctx->EmitCs([this, cView = dxvkView] (DxvkContext* ctx) {
DxvkImageUsageInfo usage = { };
usage.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
usage.stages = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
usage.access = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
ctx->ensureImageCompatibility(cView->image(), usage);
DxvkRenderTargets rt;
rt.color[0].view = cView;
rt.color[0].layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
@ -1219,30 +1224,19 @@ namespace dxvk {
auto view = static_cast<D3D11VideoProcessorInputView*>(pStream->pInputSurface);
if (view->NeedsCopy()) {
m_ctx->EmitCs([
cDstImage = view->GetShadowCopy(),
cSrcImage = view->GetImage(),
cSrcLayers = view->GetImageSubresources()
] (DxvkContext* ctx) {
VkImageSubresourceLayers cDstLayers;
cDstLayers.aspectMask = cSrcLayers.aspectMask;
cDstLayers.baseArrayLayer = 0;
cDstLayers.layerCount = cSrcLayers.layerCount;
cDstLayers.mipLevel = cSrcLayers.mipLevel;
ctx->copyImage(
cDstImage, cDstLayers, VkOffset3D(),
cSrcImage, cSrcLayers, VkOffset3D(),
cDstImage->info().extent);
});
}
m_ctx->EmitCs([this,
cStreamState = *pStreamState,
cImage = view->GetImage(),
cViews = view->GetViews(),
cIsYCbCr = view->IsYCbCr()
] (DxvkContext* ctx) {
DxvkImageUsageInfo usage = { };
usage.usage = VK_IMAGE_USAGE_SAMPLED_BIT;
usage.stages = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
usage.access = VK_ACCESS_SHADER_READ_BIT;
ctx->ensureImageCompatibility(cImage, usage);
VkViewport viewport;
viewport.x = 0.0f;
viewport.y = 0.0f;
@ -1262,12 +1256,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;
@ -1280,27 +1290,28 @@ namespace dxvk {
uboData.yMax = 0.9215686f;
}
DxvkBufferSliceHandle uboSlice = m_ubo->allocSlice();
memcpy(uboSlice.mapPtr, &uboData, sizeof(uboData));
Rc<DxvkResourceAllocation> uboSlice = m_ubo->allocateStorage();
memcpy(uboSlice->mapPtr(), &uboData, sizeof(uboData));
ctx->invalidateBuffer(m_ubo, uboSlice);
ctx->invalidateBuffer(m_ubo, std::move(uboSlice));
ctx->setViewports(1, &viewport, &scissor);
ctx->bindShader<VK_SHADER_STAGE_VERTEX_BIT>(Rc<DxvkShader>(m_vs));
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);
VkDrawIndirectCommand draw = { };
draw.vertexCount = 3u;
draw.instanceCount = 1u;
ctx->bindResourceSampler(VK_SHADER_STAGE_FRAGMENT_BIT, 1, nullptr);
ctx->draw(1, &draw);
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);
});
}
@ -1311,42 +1322,20 @@ namespace dxvk {
bufferInfo.usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT;
bufferInfo.stages = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
bufferInfo.access = VK_ACCESS_UNIFORM_READ_BIT;
bufferInfo.debugName = "Video blit parameters";
m_ubo = m_device->createBuffer(bufferInfo, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
}
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

@ -138,10 +138,6 @@ namespace dxvk {
return m_isYCbCr;
}
bool NeedsCopy() const {
return m_copy != nullptr;
}
Rc<DxvkImage> GetImage() const {
return GetCommonTexture(m_resource.ptr())->GetImage();
}
@ -150,10 +146,6 @@ namespace dxvk {
return m_subresources;
}
Rc<DxvkImage> GetShadowCopy() const {
return m_copy;
}
std::array<Rc<DxvkImageView>, 2> GetViews() const {
return m_views;
}
@ -163,7 +155,6 @@ namespace dxvk {
Com<ID3D11Resource> m_resource;
D3D11_VIDEO_PROCESSOR_INPUT_VIEW_DESC m_desc;
VkImageSubresourceLayers m_subresources;
Rc<DxvkImage> m_copy;
std::array<Rc<DxvkImageView>, 2> m_views;
bool m_isYCbCr = false;
@ -584,6 +575,7 @@ namespace dxvk {
struct alignas(16) UboData {
float colorMatrix[3][4];
float coordMatrix[3][2];
VkRect2D srcRect;
float yMin, yMax;
VkBool32 isPlanar;
};
@ -593,7 +585,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 +604,6 @@ namespace dxvk {
void CreateUniformBuffer();
void CreateSampler();
void CreateShaders();
void CreateResources();

View file

@ -55,7 +55,7 @@ namespace dxvk {
* \param [in] b Second view to check
* \returns \c true if the views overlap
*/
inline bool CheckViewOverlap(const D3D11_VK_VIEW_INFO& a, const D3D11_VK_VIEW_INFO b) {
inline bool CheckViewOverlap(const D3D11_VK_VIEW_INFO& a, const D3D11_VK_VIEW_INFO& b) {
if (likely(a.pResource != b.pResource))
return false;
@ -78,4 +78,4 @@ namespace dxvk {
return a && b && CheckViewOverlap(a->GetViewInfo(), b->GetViewInfo());
}
}
}

View file

@ -17,58 +17,58 @@ namespace dxvk {
D3D11_COMMON_RESOURCE_DESC resourceDesc;
GetCommonResourceDesc(pResource, &resourceDesc);
DxvkImageViewCreateInfo viewInfo;
DxvkImageViewKey viewInfo;
viewInfo.format = pDevice->LookupFormat(pDesc->Format, DXGI_VK_FORMAT_MODE_DEPTH).Format;
viewInfo.aspect = lookupFormatInfo(viewInfo.format)->aspectMask;
viewInfo.usage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
viewInfo.aspects = lookupFormatInfo(viewInfo.format)->aspectMask;
viewInfo.usage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
switch (pDesc->ViewDimension) {
case D3D11_DSV_DIMENSION_TEXTURE1D:
viewInfo.type = VK_IMAGE_VIEW_TYPE_1D;
viewInfo.minLevel = pDesc->Texture1D.MipSlice;
viewInfo.numLevels = 1;
viewInfo.minLayer = 0;
viewInfo.numLayers = 1;
viewInfo.viewType = VK_IMAGE_VIEW_TYPE_1D;
viewInfo.mipIndex = pDesc->Texture1D.MipSlice;
viewInfo.mipCount = 1;
viewInfo.layerIndex = 0;
viewInfo.layerCount = 1;
break;
case D3D11_DSV_DIMENSION_TEXTURE1DARRAY:
viewInfo.type = VK_IMAGE_VIEW_TYPE_1D_ARRAY;
viewInfo.minLevel = pDesc->Texture1DArray.MipSlice;
viewInfo.numLevels = 1;
viewInfo.minLayer = pDesc->Texture1DArray.FirstArraySlice;
viewInfo.numLayers = pDesc->Texture1DArray.ArraySize;
viewInfo.viewType = VK_IMAGE_VIEW_TYPE_1D_ARRAY;
viewInfo.mipIndex = pDesc->Texture1DArray.MipSlice;
viewInfo.mipCount = 1;
viewInfo.layerIndex = pDesc->Texture1DArray.FirstArraySlice;
viewInfo.layerCount = pDesc->Texture1DArray.ArraySize;
break;
case D3D11_DSV_DIMENSION_TEXTURE2D:
viewInfo.type = VK_IMAGE_VIEW_TYPE_2D;
viewInfo.minLevel = pDesc->Texture2D.MipSlice;
viewInfo.numLevels = 1;
viewInfo.minLayer = 0;
viewInfo.numLayers = 1;
viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
viewInfo.mipIndex = pDesc->Texture2D.MipSlice;
viewInfo.mipCount = 1;
viewInfo.layerIndex = 0;
viewInfo.layerCount = 1;
break;
case D3D11_DSV_DIMENSION_TEXTURE2DARRAY:
viewInfo.type = VK_IMAGE_VIEW_TYPE_2D_ARRAY;
viewInfo.minLevel = pDesc->Texture2DArray.MipSlice;
viewInfo.numLevels = 1;
viewInfo.minLayer = pDesc->Texture2DArray.FirstArraySlice;
viewInfo.numLayers = pDesc->Texture2DArray.ArraySize;
viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D_ARRAY;
viewInfo.mipIndex = pDesc->Texture2DArray.MipSlice;
viewInfo.mipCount = 1;
viewInfo.layerIndex = pDesc->Texture2DArray.FirstArraySlice;
viewInfo.layerCount = pDesc->Texture2DArray.ArraySize;
break;
case D3D11_DSV_DIMENSION_TEXTURE2DMS:
viewInfo.type = VK_IMAGE_VIEW_TYPE_2D;
viewInfo.minLevel = 0;
viewInfo.numLevels = 1;
viewInfo.minLayer = 0;
viewInfo.numLayers = 1;
viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
viewInfo.mipIndex = 0;
viewInfo.mipCount = 1;
viewInfo.layerIndex = 0;
viewInfo.layerCount = 1;
break;
case D3D11_DSV_DIMENSION_TEXTURE2DMSARRAY:
viewInfo.type = VK_IMAGE_VIEW_TYPE_2D_ARRAY;
viewInfo.minLevel = 0;
viewInfo.numLevels = 1;
viewInfo.minLayer = pDesc->Texture2DMSArray.FirstArraySlice;
viewInfo.numLayers = pDesc->Texture2DMSArray.ArraySize;
viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D_ARRAY;
viewInfo.mipIndex = 0;
viewInfo.mipCount = 1;
viewInfo.layerIndex = pDesc->Texture2DMSArray.FirstArraySlice;
viewInfo.layerCount = pDesc->Texture2DMSArray.ArraySize;
break;
default:
@ -77,20 +77,22 @@ namespace dxvk {
// Normalize view type so that we won't accidentally
// bind 2D array views and 2D views at the same time
if (viewInfo.numLayers == 1) {
if (viewInfo.type == VK_IMAGE_VIEW_TYPE_1D_ARRAY) viewInfo.type = VK_IMAGE_VIEW_TYPE_1D;
if (viewInfo.type == VK_IMAGE_VIEW_TYPE_2D_ARRAY) viewInfo.type = VK_IMAGE_VIEW_TYPE_2D;
if (viewInfo.layerCount == 1) {
if (viewInfo.viewType == VK_IMAGE_VIEW_TYPE_1D_ARRAY)
viewInfo.viewType = VK_IMAGE_VIEW_TYPE_1D;
if (viewInfo.viewType == VK_IMAGE_VIEW_TYPE_2D_ARRAY)
viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
}
// Populate view info struct
m_info.pResource = pResource;
m_info.Dimension = resourceDesc.Dim;
m_info.BindFlags = resourceDesc.BindFlags;
m_info.Image.Aspects = viewInfo.aspect;
m_info.Image.MinLevel = viewInfo.minLevel;
m_info.Image.MinLayer = viewInfo.minLayer;
m_info.Image.NumLevels = viewInfo.numLevels;
m_info.Image.NumLayers = viewInfo.numLayers;
m_info.Image.Aspects = viewInfo.aspects;
m_info.Image.MinLevel = viewInfo.mipIndex;
m_info.Image.MinLayer = viewInfo.layerIndex;
m_info.Image.NumLevels = viewInfo.mipCount;
m_info.Image.NumLayers = viewInfo.layerCount;
if (m_desc.Flags & D3D11_DSV_READ_ONLY_DEPTH)
m_info.Image.Aspects &= ~VK_IMAGE_ASPECT_DEPTH_BIT;
@ -99,13 +101,15 @@ namespace dxvk {
m_info.Image.Aspects &= ~VK_IMAGE_ASPECT_STENCIL_BIT;
// Create the underlying image view object
m_view = pDevice->GetDXVKDevice()->createImageView(
GetCommonTexture(pResource)->GetImage(), viewInfo);
m_view = GetCommonTexture(pResource)->GetImage()->createView(viewInfo);
}
D3D11DepthStencilView::~D3D11DepthStencilView() {
ResourceReleasePrivate(m_resource);
m_resource = nullptr;
m_view = nullptr;
}

View file

@ -50,24 +50,20 @@ namespace dxvk {
}
VkImageLayout GetRenderLayout() const {
if (m_view->imageInfo().tiling == VK_IMAGE_TILING_OPTIMAL) {
switch (m_desc.Flags & (D3D11_DSV_READ_ONLY_DEPTH | D3D11_DSV_READ_ONLY_STENCIL)) {
default: // case 0
return VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
case D3D11_DSV_READ_ONLY_DEPTH:
return VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL_KHR;
case D3D11_DSV_READ_ONLY_STENCIL:
return VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL_KHR;
case D3D11_DSV_READ_ONLY_DEPTH | D3D11_DSV_READ_ONLY_STENCIL:
return VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL;
}
} else {
return VK_IMAGE_LAYOUT_GENERAL;
switch (m_desc.Flags & (D3D11_DSV_READ_ONLY_DEPTH | D3D11_DSV_READ_ONLY_STENCIL)) {
default: // case 0
return VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
case D3D11_DSV_READ_ONLY_DEPTH:
return VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL_KHR;
case D3D11_DSV_READ_ONLY_STENCIL:
return VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL_KHR;
case D3D11_DSV_READ_ONLY_DEPTH | D3D11_DSV_READ_ONLY_STENCIL:
return VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL;
}
}
UINT GetSampleCount() const {
return UINT(m_view->imageInfo().sampleCount);
return UINT(m_view->image()->info().sampleCount);
}
VkImageAspectFlags GetWritableAspectMask() const {

View file

@ -22,67 +22,67 @@ namespace dxvk {
DXGI_VK_FORMAT_INFO formatInfo = pDevice->LookupFormat(
pDesc->Format, DXGI_VK_FORMAT_MODE_COLOR);
DxvkImageViewCreateInfo viewInfo;
viewInfo.format = formatInfo.Format;
viewInfo.aspect = lookupFormatInfo(viewInfo.format)->aspectMask;
viewInfo.swizzle = formatInfo.Swizzle;
viewInfo.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
DxvkImageViewKey viewInfo;
viewInfo.format = formatInfo.Format;
viewInfo.aspects = lookupFormatInfo(viewInfo.format)->aspectMask;
viewInfo.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
viewInfo.packedSwizzle = DxvkImageViewKey::packSwizzle(formatInfo.Swizzle);
switch (pDesc->ViewDimension) {
case D3D11_RTV_DIMENSION_TEXTURE1D:
viewInfo.type = VK_IMAGE_VIEW_TYPE_1D;
viewInfo.minLevel = pDesc->Texture1D.MipSlice;
viewInfo.numLevels = 1;
viewInfo.minLayer = 0;
viewInfo.numLayers = 1;
viewInfo.viewType = VK_IMAGE_VIEW_TYPE_1D;
viewInfo.mipIndex = pDesc->Texture1D.MipSlice;
viewInfo.mipCount = 1;
viewInfo.layerIndex = 0;
viewInfo.layerCount = 1;
break;
case D3D11_RTV_DIMENSION_TEXTURE1DARRAY:
viewInfo.type = VK_IMAGE_VIEW_TYPE_1D_ARRAY;
viewInfo.minLevel = pDesc->Texture1DArray.MipSlice;
viewInfo.numLevels = 1;
viewInfo.minLayer = pDesc->Texture1DArray.FirstArraySlice;
viewInfo.numLayers = pDesc->Texture1DArray.ArraySize;
viewInfo.viewType = VK_IMAGE_VIEW_TYPE_1D_ARRAY;
viewInfo.mipIndex = pDesc->Texture1DArray.MipSlice;
viewInfo.mipCount = 1;
viewInfo.layerIndex = pDesc->Texture1DArray.FirstArraySlice;
viewInfo.layerCount = pDesc->Texture1DArray.ArraySize;
break;
case D3D11_RTV_DIMENSION_TEXTURE2D:
viewInfo.type = VK_IMAGE_VIEW_TYPE_2D;
viewInfo.minLevel = pDesc->Texture2D.MipSlice;
viewInfo.numLevels = 1;
viewInfo.minLayer = 0;
viewInfo.numLayers = 1;
viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
viewInfo.mipIndex = pDesc->Texture2D.MipSlice;
viewInfo.mipCount = 1;
viewInfo.layerIndex = 0;
viewInfo.layerCount = 1;
break;
case D3D11_RTV_DIMENSION_TEXTURE2DARRAY:
viewInfo.type = VK_IMAGE_VIEW_TYPE_2D_ARRAY;
viewInfo.minLevel = pDesc->Texture2DArray.MipSlice;
viewInfo.numLevels = 1;
viewInfo.minLayer = pDesc->Texture2DArray.FirstArraySlice;
viewInfo.numLayers = pDesc->Texture2DArray.ArraySize;
viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D_ARRAY;
viewInfo.mipIndex = pDesc->Texture2DArray.MipSlice;
viewInfo.mipCount = 1;
viewInfo.layerIndex = pDesc->Texture2DArray.FirstArraySlice;
viewInfo.layerCount = pDesc->Texture2DArray.ArraySize;
break;
case D3D11_RTV_DIMENSION_TEXTURE2DMS:
viewInfo.type = VK_IMAGE_VIEW_TYPE_2D;
viewInfo.minLevel = 0;
viewInfo.numLevels = 1;
viewInfo.minLayer = 0;
viewInfo.numLayers = 1;
viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
viewInfo.mipIndex = 0;
viewInfo.mipCount = 1;
viewInfo.layerIndex = 0;
viewInfo.layerCount = 1;
break;
case D3D11_RTV_DIMENSION_TEXTURE2DMSARRAY:
viewInfo.type = VK_IMAGE_VIEW_TYPE_2D_ARRAY;
viewInfo.minLevel = 0;
viewInfo.numLevels = 1;
viewInfo.minLayer = pDesc->Texture2DMSArray.FirstArraySlice;
viewInfo.numLayers = pDesc->Texture2DMSArray.ArraySize;
viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D_ARRAY;
viewInfo.mipIndex = 0;
viewInfo.mipCount = 1;
viewInfo.layerIndex = pDesc->Texture2DMSArray.FirstArraySlice;
viewInfo.layerCount = pDesc->Texture2DMSArray.ArraySize;
break;
case D3D11_RTV_DIMENSION_TEXTURE3D:
viewInfo.type = VK_IMAGE_VIEW_TYPE_2D_ARRAY;
viewInfo.minLevel = pDesc->Texture3D.MipSlice;
viewInfo.numLevels = 1;
viewInfo.minLayer = pDesc->Texture3D.FirstWSlice;
viewInfo.numLayers = pDesc->Texture3D.WSize;
viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D_ARRAY;
viewInfo.mipIndex = pDesc->Texture3D.MipSlice;
viewInfo.mipCount = 1;
viewInfo.layerIndex = pDesc->Texture3D.FirstWSlice;
viewInfo.layerCount = pDesc->Texture3D.WSize;
break;
default:
@ -90,32 +90,37 @@ namespace dxvk {
}
if (texture->GetPlaneCount() > 1)
viewInfo.aspect = vk::getPlaneAspect(GetPlaneSlice(pDesc));
viewInfo.aspects = vk::getPlaneAspect(GetPlaneSlice(pDesc));
// Normalize view type so that we won't accidentally
// bind 2D array views and 2D views at the same time
if (viewInfo.numLayers == 1) {
if (viewInfo.type == VK_IMAGE_VIEW_TYPE_1D_ARRAY) viewInfo.type = VK_IMAGE_VIEW_TYPE_1D;
if (viewInfo.type == VK_IMAGE_VIEW_TYPE_2D_ARRAY) viewInfo.type = VK_IMAGE_VIEW_TYPE_2D;
if (viewInfo.layerCount == 1) {
if (viewInfo.viewType == VK_IMAGE_VIEW_TYPE_1D_ARRAY)
viewInfo.viewType = VK_IMAGE_VIEW_TYPE_1D;
if (viewInfo.viewType == VK_IMAGE_VIEW_TYPE_2D_ARRAY)
viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
}
// Populate view info struct
m_info.pResource = pResource;
m_info.Dimension = resourceDesc.Dim;
m_info.BindFlags = resourceDesc.BindFlags;
m_info.Image.Aspects = viewInfo.aspect;
m_info.Image.MinLevel = viewInfo.minLevel;
m_info.Image.MinLayer = viewInfo.minLayer;
m_info.Image.NumLevels = viewInfo.numLevels;
m_info.Image.NumLayers = viewInfo.numLayers;
m_info.Image.Aspects = viewInfo.aspects;
m_info.Image.MinLevel = viewInfo.mipIndex;
m_info.Image.MinLayer = viewInfo.layerIndex;
m_info.Image.NumLevels = viewInfo.mipCount;
m_info.Image.NumLayers = viewInfo.layerCount;
// Create the underlying image view object
m_view = pDevice->GetDXVKDevice()->createImageView(texture->GetImage(), viewInfo);
m_view = texture->GetImage()->createView(viewInfo);
}
D3D11RenderTargetView::~D3D11RenderTargetView() {
ResourceReleasePrivate(m_resource);
m_resource = nullptr;
m_view = nullptr;
}

View file

@ -52,13 +52,11 @@ namespace dxvk {
}
VkImageLayout GetRenderLayout() const {
return m_view->imageInfo().tiling == VK_IMAGE_TILING_OPTIMAL
? VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL
: VK_IMAGE_LAYOUT_GENERAL;
return VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
}
UINT GetSampleCount() const {
return UINT(m_view->imageInfo().sampleCount);
return UINT(m_view->image()->info().sampleCount);
}
D3D10RenderTargetView* GetD3D10Iface() {

View file

@ -42,123 +42,123 @@ namespace dxvk {
}
// Fill in buffer view info
DxvkBufferViewCreateInfo viewInfo;
DxvkBufferViewKey viewInfo;
viewInfo.usage = VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT;
if (bufInfo.Flags & D3D11_BUFFEREX_SRV_FLAG_RAW) {
// Raw buffer view. We'll represent this as a
// uniform texel buffer with UINT32 elements.
viewInfo.format = VK_FORMAT_R32_UINT;
viewInfo.rangeOffset = sizeof(uint32_t) * bufInfo.FirstElement;
viewInfo.rangeLength = sizeof(uint32_t) * bufInfo.NumElements;
viewInfo.offset = sizeof(uint32_t) * bufInfo.FirstElement;
viewInfo.size = sizeof(uint32_t) * bufInfo.NumElements;
} else if (pDesc->Format == DXGI_FORMAT_UNKNOWN) {
// Structured buffer view
viewInfo.format = VK_FORMAT_R32_UINT;
viewInfo.rangeOffset = buffer->Desc()->StructureByteStride * bufInfo.FirstElement;
viewInfo.rangeLength = buffer->Desc()->StructureByteStride * bufInfo.NumElements;
viewInfo.offset = buffer->Desc()->StructureByteStride * bufInfo.FirstElement;
viewInfo.size = buffer->Desc()->StructureByteStride * bufInfo.NumElements;
} else {
viewInfo.format = pDevice->LookupFormat(pDesc->Format, DXGI_VK_FORMAT_MODE_COLOR).Format;
const DxvkFormatInfo* formatInfo = lookupFormatInfo(viewInfo.format);
viewInfo.rangeOffset = formatInfo->elementSize * bufInfo.FirstElement;
viewInfo.rangeLength = formatInfo->elementSize * bufInfo.NumElements;
viewInfo.offset = formatInfo->elementSize * bufInfo.FirstElement;
viewInfo.size = formatInfo->elementSize * bufInfo.NumElements;
}
// Populate view info struct
m_info.Buffer.Offset = viewInfo.rangeOffset;
m_info.Buffer.Length = viewInfo.rangeLength;
m_info.Buffer.Offset = viewInfo.offset;
m_info.Buffer.Length = viewInfo.size;
// Create underlying buffer view object
m_bufferView = pDevice->GetDXVKDevice()->createBufferView(
buffer->GetBuffer(), viewInfo);
m_bufferView = buffer->GetBuffer()->createView(viewInfo);
} else {
auto texture = GetCommonTexture(pResource);
auto formatInfo = pDevice->LookupFormat(pDesc->Format, texture->GetFormatMode());
DxvkImageViewCreateInfo viewInfo;
viewInfo.format = formatInfo.Format;
viewInfo.aspect = formatInfo.Aspect;
viewInfo.swizzle = formatInfo.Swizzle;
viewInfo.usage = VK_IMAGE_USAGE_SAMPLED_BIT;
DxvkImageViewKey viewInfo;
viewInfo.format = formatInfo.Format;
viewInfo.aspects = formatInfo.Aspect;
viewInfo.usage = VK_IMAGE_USAGE_SAMPLED_BIT;
viewInfo.packedSwizzle = DxvkImageViewKey::packSwizzle(formatInfo.Swizzle);
// Shaders expect the stencil value in the G component
if (viewInfo.aspect == VK_IMAGE_ASPECT_STENCIL_BIT) {
viewInfo.swizzle = VkComponentMapping {
if (viewInfo.aspects == VK_IMAGE_ASPECT_STENCIL_BIT) {
viewInfo.packedSwizzle = DxvkImageViewKey::packSwizzle({
VK_COMPONENT_SWIZZLE_ZERO, VK_COMPONENT_SWIZZLE_R,
VK_COMPONENT_SWIZZLE_ZERO, VK_COMPONENT_SWIZZLE_ZERO };
VK_COMPONENT_SWIZZLE_ZERO, VK_COMPONENT_SWIZZLE_ZERO });
}
switch (pDesc->ViewDimension) {
case D3D11_SRV_DIMENSION_TEXTURE1D:
viewInfo.type = VK_IMAGE_VIEW_TYPE_1D;
viewInfo.minLevel = pDesc->Texture1D.MostDetailedMip;
viewInfo.numLevels = pDesc->Texture1D.MipLevels;
viewInfo.minLayer = 0;
viewInfo.numLayers = 1;
viewInfo.viewType = VK_IMAGE_VIEW_TYPE_1D;
viewInfo.mipIndex = pDesc->Texture1D.MostDetailedMip;
viewInfo.mipCount = pDesc->Texture1D.MipLevels;
viewInfo.layerIndex = 0;
viewInfo.layerCount = 1;
break;
case D3D11_SRV_DIMENSION_TEXTURE1DARRAY:
viewInfo.type = VK_IMAGE_VIEW_TYPE_1D_ARRAY;
viewInfo.minLevel = pDesc->Texture1DArray.MostDetailedMip;
viewInfo.numLevels = pDesc->Texture1DArray.MipLevels;
viewInfo.minLayer = pDesc->Texture1DArray.FirstArraySlice;
viewInfo.numLayers = pDesc->Texture1DArray.ArraySize;
viewInfo.viewType = VK_IMAGE_VIEW_TYPE_1D_ARRAY;
viewInfo.mipIndex = pDesc->Texture1DArray.MostDetailedMip;
viewInfo.mipCount = pDesc->Texture1DArray.MipLevels;
viewInfo.layerIndex = pDesc->Texture1DArray.FirstArraySlice;
viewInfo.layerCount = pDesc->Texture1DArray.ArraySize;
break;
case D3D11_SRV_DIMENSION_TEXTURE2D:
viewInfo.type = VK_IMAGE_VIEW_TYPE_2D;
viewInfo.minLevel = pDesc->Texture2D.MostDetailedMip;
viewInfo.numLevels = pDesc->Texture2D.MipLevels;
viewInfo.minLayer = 0;
viewInfo.numLayers = 1;
viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
viewInfo.mipIndex = pDesc->Texture2D.MostDetailedMip;
viewInfo.mipCount = pDesc->Texture2D.MipLevels;
viewInfo.layerIndex = 0;
viewInfo.layerCount = 1;
break;
case D3D11_SRV_DIMENSION_TEXTURE2DARRAY:
viewInfo.type = VK_IMAGE_VIEW_TYPE_2D_ARRAY;
viewInfo.minLevel = pDesc->Texture2DArray.MostDetailedMip;
viewInfo.numLevels = pDesc->Texture2DArray.MipLevels;
viewInfo.minLayer = pDesc->Texture2DArray.FirstArraySlice;
viewInfo.numLayers = pDesc->Texture2DArray.ArraySize;
viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D_ARRAY;
viewInfo.mipIndex = pDesc->Texture2DArray.MostDetailedMip;
viewInfo.mipCount = pDesc->Texture2DArray.MipLevels;
viewInfo.layerIndex = pDesc->Texture2DArray.FirstArraySlice;
viewInfo.layerCount = pDesc->Texture2DArray.ArraySize;
break;
case D3D11_SRV_DIMENSION_TEXTURE2DMS:
viewInfo.type = VK_IMAGE_VIEW_TYPE_2D;
viewInfo.minLevel = 0;
viewInfo.numLevels = 1;
viewInfo.minLayer = 0;
viewInfo.numLayers = 1;
viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
viewInfo.mipIndex = 0;
viewInfo.mipCount = 1;
viewInfo.layerIndex = 0;
viewInfo.layerCount = 1;
break;
case D3D11_SRV_DIMENSION_TEXTURE2DMSARRAY:
viewInfo.type = VK_IMAGE_VIEW_TYPE_2D_ARRAY;
viewInfo.minLevel = 0;
viewInfo.numLevels = 1;
viewInfo.minLayer = pDesc->Texture2DMSArray.FirstArraySlice;
viewInfo.numLayers = pDesc->Texture2DMSArray.ArraySize;
viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D_ARRAY;
viewInfo.mipIndex = 0;
viewInfo.mipCount = 1;
viewInfo.layerIndex = pDesc->Texture2DMSArray.FirstArraySlice;
viewInfo.layerCount = pDesc->Texture2DMSArray.ArraySize;
break;
case D3D11_SRV_DIMENSION_TEXTURE3D:
viewInfo.type = VK_IMAGE_VIEW_TYPE_3D;
viewInfo.minLevel = pDesc->Texture3D.MostDetailedMip;
viewInfo.numLevels = pDesc->Texture3D.MipLevels;
viewInfo.minLayer = 0;
viewInfo.numLayers = 1;
viewInfo.viewType = VK_IMAGE_VIEW_TYPE_3D;
viewInfo.mipIndex = pDesc->Texture3D.MostDetailedMip;
viewInfo.mipCount = pDesc->Texture3D.MipLevels;
viewInfo.layerIndex = 0;
viewInfo.layerCount = 1;
break;
case D3D11_SRV_DIMENSION_TEXTURECUBE: {
const bool cubeArraysEnabled = pDevice->GetDXVKDevice()->features().core.features.imageCubeArray;
viewInfo.type = cubeArraysEnabled ? VK_IMAGE_VIEW_TYPE_CUBE_ARRAY : VK_IMAGE_VIEW_TYPE_CUBE;
viewInfo.minLevel = pDesc->TextureCube.MostDetailedMip;
viewInfo.numLevels = pDesc->TextureCube.MipLevels;
viewInfo.minLayer = 0;
viewInfo.numLayers = 6;
viewInfo.viewType = cubeArraysEnabled ? VK_IMAGE_VIEW_TYPE_CUBE_ARRAY : VK_IMAGE_VIEW_TYPE_CUBE;
viewInfo.mipIndex = pDesc->TextureCube.MostDetailedMip;
viewInfo.mipCount = pDesc->TextureCube.MipLevels;
viewInfo.layerIndex = 0;
viewInfo.layerCount = 6;
} break;
case D3D11_SRV_DIMENSION_TEXTURECUBEARRAY:
viewInfo.type = VK_IMAGE_VIEW_TYPE_CUBE_ARRAY;
viewInfo.minLevel = pDesc->TextureCubeArray.MostDetailedMip;
viewInfo.numLevels = pDesc->TextureCubeArray.MipLevels;
viewInfo.minLayer = pDesc->TextureCubeArray.First2DArrayFace;
viewInfo.numLayers = pDesc->TextureCubeArray.NumCubes * 6;
viewInfo.viewType = VK_IMAGE_VIEW_TYPE_CUBE_ARRAY;
viewInfo.mipIndex = pDesc->TextureCubeArray.MostDetailedMip;
viewInfo.mipCount = pDesc->TextureCubeArray.MipLevels;
viewInfo.layerIndex = pDesc->TextureCubeArray.First2DArrayFace;
viewInfo.layerCount = pDesc->TextureCubeArray.NumCubes * 6;
break;
default:
@ -166,23 +166,27 @@ namespace dxvk {
}
if (texture->GetPlaneCount() > 1)
viewInfo.aspect = vk::getPlaneAspect(GetPlaneSlice(pDesc));
viewInfo.aspects = vk::getPlaneAspect(GetPlaneSlice(pDesc));
// Populate view info struct
m_info.Image.Aspects = viewInfo.aspect;
m_info.Image.MinLevel = viewInfo.minLevel;
m_info.Image.MinLayer = viewInfo.minLayer;
m_info.Image.NumLevels = viewInfo.numLevels;
m_info.Image.NumLayers = viewInfo.numLayers;
m_info.Image.Aspects = viewInfo.aspects;
m_info.Image.MinLevel = viewInfo.mipIndex;
m_info.Image.MinLayer = viewInfo.layerIndex;
m_info.Image.NumLevels = viewInfo.mipCount;
m_info.Image.NumLayers = viewInfo.layerCount;
// Create the underlying image view object
m_imageView = pDevice->GetDXVKDevice()->createImageView(texture->GetImage(), viewInfo);
m_imageView = texture->GetImage()->createView(viewInfo);
}
}
D3D11ShaderResourceView::~D3D11ShaderResourceView() {
ResourceReleasePrivate(m_resource);
m_resource = nullptr;
m_imageView = nullptr;
m_bufferView = nullptr;
}

View file

@ -25,86 +25,86 @@ namespace dxvk {
if (resourceDesc.Dim == D3D11_RESOURCE_DIMENSION_BUFFER) {
auto buffer = static_cast<D3D11Buffer*>(pResource);
DxvkBufferViewCreateInfo viewInfo;
DxvkBufferViewKey viewInfo;
viewInfo.usage = VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT;
if (pDesc->Buffer.Flags & D3D11_BUFFEREX_SRV_FLAG_RAW) {
viewInfo.format = VK_FORMAT_R32_UINT;
viewInfo.rangeOffset = sizeof(uint32_t) * pDesc->Buffer.FirstElement;
viewInfo.rangeLength = sizeof(uint32_t) * pDesc->Buffer.NumElements;
viewInfo.format = VK_FORMAT_R32_UINT;
viewInfo.offset = sizeof(uint32_t) * pDesc->Buffer.FirstElement;
viewInfo.size = sizeof(uint32_t) * pDesc->Buffer.NumElements;
} else if (pDesc->Format == DXGI_FORMAT_UNKNOWN) {
viewInfo.format = VK_FORMAT_R32_UINT;
viewInfo.rangeOffset = buffer->Desc()->StructureByteStride * pDesc->Buffer.FirstElement;
viewInfo.rangeLength = buffer->Desc()->StructureByteStride * pDesc->Buffer.NumElements;
viewInfo.format = VK_FORMAT_R32_UINT;
viewInfo.offset = buffer->Desc()->StructureByteStride * pDesc->Buffer.FirstElement;
viewInfo.size = buffer->Desc()->StructureByteStride * pDesc->Buffer.NumElements;
} else {
viewInfo.format = pDevice->LookupFormat(pDesc->Format, DXGI_VK_FORMAT_MODE_COLOR).Format;
const DxvkFormatInfo* formatInfo = lookupFormatInfo(viewInfo.format);
viewInfo.rangeOffset = formatInfo->elementSize * pDesc->Buffer.FirstElement;
viewInfo.rangeLength = formatInfo->elementSize * pDesc->Buffer.NumElements;
viewInfo.offset = formatInfo->elementSize * pDesc->Buffer.FirstElement;
viewInfo.size = formatInfo->elementSize * pDesc->Buffer.NumElements;
}
if (pDesc->Buffer.Flags & (D3D11_BUFFER_UAV_FLAG_APPEND | D3D11_BUFFER_UAV_FLAG_COUNTER))
m_counterView = CreateCounterBufferView();
// Populate view info struct
m_info.Buffer.Offset = viewInfo.rangeOffset;
m_info.Buffer.Length = viewInfo.rangeLength;
m_info.Buffer.Offset = viewInfo.offset;
m_info.Buffer.Length = viewInfo.size;
m_bufferView = pDevice->GetDXVKDevice()->createBufferView(
buffer->GetBuffer(), viewInfo);
m_bufferView = buffer->GetBuffer()->createView(viewInfo);
} else {
auto texture = GetCommonTexture(pResource);
auto formatInfo = pDevice->LookupFormat(pDesc->Format, texture->GetFormatMode());
DxvkImageViewCreateInfo viewInfo;
viewInfo.format = formatInfo.Format;
viewInfo.aspect = formatInfo.Aspect;
viewInfo.usage = VK_IMAGE_USAGE_STORAGE_BIT;
DxvkImageViewKey viewInfo;
viewInfo.format = formatInfo.Format;
viewInfo.aspects = formatInfo.Aspect;
viewInfo.usage = VK_IMAGE_USAGE_STORAGE_BIT;
if (!util::isIdentityMapping(formatInfo.Swizzle))
Logger::warn(str::format("UAV format ", pDesc->Format, " has non-identity swizzle, but UAV swizzles are not supported"));
switch (pDesc->ViewDimension) {
case D3D11_UAV_DIMENSION_TEXTURE1D:
viewInfo.type = VK_IMAGE_VIEW_TYPE_1D;
viewInfo.minLevel = pDesc->Texture1D.MipSlice;
viewInfo.numLevels = 1;
viewInfo.minLayer = 0;
viewInfo.numLayers = 1;
viewInfo.viewType = VK_IMAGE_VIEW_TYPE_1D;
viewInfo.mipIndex = pDesc->Texture1D.MipSlice;
viewInfo.mipCount = 1;
viewInfo.layerIndex = 0;
viewInfo.layerCount = 1;
break;
case D3D11_UAV_DIMENSION_TEXTURE1DARRAY:
viewInfo.type = VK_IMAGE_VIEW_TYPE_1D_ARRAY;
viewInfo.minLevel = pDesc->Texture1DArray.MipSlice;
viewInfo.numLevels = 1;
viewInfo.minLayer = pDesc->Texture1DArray.FirstArraySlice;
viewInfo.numLayers = pDesc->Texture1DArray.ArraySize;
viewInfo.viewType = VK_IMAGE_VIEW_TYPE_1D_ARRAY;
viewInfo.mipIndex = pDesc->Texture1DArray.MipSlice;
viewInfo.mipCount = 1;
viewInfo.layerIndex = pDesc->Texture1DArray.FirstArraySlice;
viewInfo.layerCount = pDesc->Texture1DArray.ArraySize;
break;
case D3D11_UAV_DIMENSION_TEXTURE2D:
viewInfo.type = VK_IMAGE_VIEW_TYPE_2D;
viewInfo.minLevel = pDesc->Texture2D.MipSlice;
viewInfo.numLevels = 1;
viewInfo.minLayer = 0;
viewInfo.numLayers = 1;
viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
viewInfo.mipIndex = pDesc->Texture2D.MipSlice;
viewInfo.mipCount = 1;
viewInfo.layerIndex = 0;
viewInfo.layerCount = 1;
break;
case D3D11_UAV_DIMENSION_TEXTURE2DARRAY:
viewInfo.type = VK_IMAGE_VIEW_TYPE_2D_ARRAY;
viewInfo.minLevel = pDesc->Texture2DArray.MipSlice;
viewInfo.numLevels = 1;
viewInfo.minLayer = pDesc->Texture2DArray.FirstArraySlice;
viewInfo.numLayers = pDesc->Texture2DArray.ArraySize;
viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D_ARRAY;
viewInfo.mipIndex = pDesc->Texture2DArray.MipSlice;
viewInfo.mipCount = 1;
viewInfo.layerIndex = pDesc->Texture2DArray.FirstArraySlice;
viewInfo.layerCount = pDesc->Texture2DArray.ArraySize;
break;
case D3D11_UAV_DIMENSION_TEXTURE3D:
// FIXME we actually have to map this to a
// 2D array view in order to support W slices
viewInfo.type = VK_IMAGE_VIEW_TYPE_3D;
viewInfo.minLevel = pDesc->Texture3D.MipSlice;
viewInfo.numLevels = 1;
viewInfo.minLayer = 0;
viewInfo.numLayers = 1;
viewInfo.viewType = VK_IMAGE_VIEW_TYPE_3D;
viewInfo.mipIndex = pDesc->Texture3D.MipSlice;
viewInfo.mipCount = 1;
viewInfo.layerIndex = 0;
viewInfo.layerCount = 1;
break;
default:
@ -112,23 +112,27 @@ namespace dxvk {
}
if (texture->GetPlaneCount() > 1)
viewInfo.aspect = vk::getPlaneAspect(GetPlaneSlice(pDesc));
viewInfo.aspects = vk::getPlaneAspect(GetPlaneSlice(pDesc));
// Populate view info struct
m_info.Image.Aspects = viewInfo.aspect;
m_info.Image.MinLevel = viewInfo.minLevel;
m_info.Image.MinLayer = viewInfo.minLayer;
m_info.Image.NumLevels = viewInfo.numLevels;
m_info.Image.NumLayers = viewInfo.numLayers;
m_info.Image.Aspects = viewInfo.aspects;
m_info.Image.MinLevel = viewInfo.mipIndex;
m_info.Image.MinLayer = viewInfo.layerIndex;
m_info.Image.NumLevels = viewInfo.mipCount;
m_info.Image.NumLayers = viewInfo.layerCount;
m_imageView = pDevice->GetDXVKDevice()->createImageView(
GetCommonTexture(pResource)->GetImage(), viewInfo);
m_imageView = GetCommonTexture(pResource)->GetImage()->createView(viewInfo);
}
}
D3D11UnorderedAccessView::~D3D11UnorderedAccessView() {
ResourceReleasePrivate(m_resource);
m_resource = nullptr;
m_bufferView = nullptr;
m_counterView = nullptr;
m_imageView = nullptr;
}
@ -446,15 +450,17 @@ namespace dxvk {
| VK_ACCESS_TRANSFER_READ_BIT
| VK_ACCESS_SHADER_WRITE_BIT
| VK_ACCESS_SHADER_READ_BIT;
info.debugName = "UAV counter";
Rc<DxvkBuffer> buffer = device->createBuffer(info, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
DxvkBufferViewCreateInfo viewInfo;
DxvkBufferViewKey viewInfo;
viewInfo.format = VK_FORMAT_UNDEFINED;
viewInfo.rangeOffset = 0;
viewInfo.rangeLength = sizeof(uint32_t);
viewInfo.offset = 0;
viewInfo.size = sizeof(uint32_t);
viewInfo.usage = VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT;
return device->createBufferView(buffer, viewInfo);
return buffer->createView(viewInfo);
}
}

View file

@ -43,6 +43,10 @@ namespace dxvk {
return m_info.BindFlags & Flags;
}
BOOL HasCounter() const {
return m_counterView != nullptr;
}
D3D11_RESOURCE_DIMENSION GetResourceType() const {
D3D11_RESOURCE_DIMENSION type;
m_resource->GetType(&type);

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

6
src/d3d8/d3d8.def Normal file
View file

@ -0,0 +1,6 @@
LIBRARY D3D8.DLL
EXPORTS
ValidatePixelShader @ 2
ValidateVertexShader @ 3
DebugSetMute @ 4
Direct3DCreate8 @ 5

10
src/d3d8/d3d8.sym Normal file
View file

@ -0,0 +1,10 @@
{
global:
ValidatePixelShader;
ValidateVertexShader;
DebugSetMute;
Direct3DCreate8;
local:
*;
};

250
src/d3d8/d3d8_batch.h Normal file
View file

@ -0,0 +1,250 @@
#pragma once
#include "d3d8_include.h"
#include "d3d8_buffer.h"
#include "d3d8_format.h"
#include <vector>
#include <cstdint>
namespace dxvk {
inline constexpr size_t D3DPT_COUNT = size_t(D3DPT_TRIANGLEFAN) + 1;
inline constexpr D3DPRIMITIVETYPE D3DPT_INVALID = D3DPRIMITIVETYPE(0);
// Vertex buffer that can handle many tiny locks while
// still maintaing the lock ordering of direct-mapped buffers.
class D3D8BatchBuffer final : public D3D8VertexBuffer {
public:
D3D8BatchBuffer(
D3D8Device* pDevice,
D3DPOOL Pool,
DWORD Usage,
UINT Length,
DWORD FVF)
: D3D8VertexBuffer(pDevice, nullptr, Pool, Usage)
, m_data(Length)
, m_fvf(FVF) {
}
HRESULT STDMETHODCALLTYPE Lock(
UINT OffsetToLock,
UINT SizeToLock,
BYTE** ppbData,
DWORD Flags) {
*ppbData = m_data.data() + OffsetToLock;
return D3D_OK;
}
HRESULT STDMETHODCALLTYPE Unlock() {
return D3D_OK;
}
HRESULT STDMETHODCALLTYPE GetDesc(D3DVERTEXBUFFER_DESC* pDesc) {
if (unlikely(pDesc == nullptr))
return D3DERR_INVALIDCALL;
pDesc->Format = D3DFMT_VERTEXDATA;
pDesc->Type = D3DRTYPE_VERTEXBUFFER;
pDesc->Usage = m_usage;
pDesc->Pool = m_pool;
pDesc->Size = m_data.size();
pDesc->FVF = m_fvf;
return D3D_OK;
}
void STDMETHODCALLTYPE PreLoad() {
}
const void* GetPtr(UINT byteOffset = 0) const {
return m_data.data() + byteOffset;
}
UINT Size() const {
return m_data.size();
}
private:
std::vector<BYTE> m_data;
DWORD m_fvf;
};
// Main handler for batching D3D8 draw calls.
class D3D8Batcher {
struct Batch {
D3DPRIMITIVETYPE PrimitiveType = D3DPT_INVALID;
std::vector<uint16_t> Indices;
UINT Offset = 0;
UINT MinVertex = std::numeric_limits<uint32_t>::max();
UINT MaxVertex = 0;
UINT PrimitiveCount = 0;
UINT DrawCallCount = 0;
};
public:
D3D8Batcher(D3D8Device* pDevice8, Com<d3d9::IDirect3DDevice9>&& pDevice9)
: m_device8(pDevice8)
, m_device(std::move(pDevice9)) {
}
inline D3D8BatchBuffer* CreateVertexBuffer(UINT Length, DWORD Usage, DWORD FVF, D3DPOOL Pool) {
return ref(new D3D8BatchBuffer(m_device8, Pool, Usage, Length, FVF));
}
inline void StateChange() {
if (likely(m_batches.empty()))
return;
for (auto& draw : m_batches) {
if (draw.PrimitiveType == D3DPT_INVALID)
continue;
for (auto& index : draw.Indices)
index -= draw.MinVertex;
m_device->DrawIndexedPrimitiveUP(
d3d9::D3DPRIMITIVETYPE(draw.PrimitiveType),
0,
draw.MaxVertex - draw.MinVertex,
draw.PrimitiveCount,
draw.Indices.data(),
d3d9::D3DFMT_INDEX16,
m_stream->GetPtr(draw.MinVertex * m_stride),
m_stride);
m_device->SetStreamSource(0, D3D8VertexBuffer::GetD3D9Nullable(m_stream), 0, m_stride);
m_device->SetIndices(D3D8IndexBuffer::GetD3D9Nullable(m_indices));
draw.PrimitiveType = D3DPRIMITIVETYPE(0);
draw.Offset = 0;
draw.MinVertex = std::numeric_limits<uint32_t>::max();
draw.MaxVertex = 0;
draw.PrimitiveCount = 0;
draw.DrawCallCount = 0;
}
}
inline void EndFrame() {
// Nothing to be done.
}
inline HRESULT DrawPrimitive(
D3DPRIMITIVETYPE PrimitiveType,
UINT StartVertex,
UINT PrimitiveCount) {
// None of this linestrip or fan malarkey
D3DPRIMITIVETYPE batchedPrimType = PrimitiveType;
switch (PrimitiveType) {
case D3DPT_LINESTRIP: batchedPrimType = D3DPT_LINELIST; break;
case D3DPT_TRIANGLEFAN: batchedPrimType = D3DPT_TRIANGLELIST; break;
default: break;
}
Batch* batch = &m_batches[size_t(batchedPrimType)];
batch->PrimitiveType = batchedPrimType;
//UINT vertices = GetVertexCount8(PrimitiveType, PrimitiveCount);
switch (PrimitiveType) {
case D3DPT_POINTLIST:
batch->Indices.resize(batch->Offset + PrimitiveCount);
for (UINT i = 0; i < PrimitiveCount; i++)
batch->Indices[batch->Offset++] = (StartVertex + i);
break;
case D3DPT_LINELIST:
batch->Indices.resize(batch->Offset + PrimitiveCount * 2);
for (UINT i = 0; i < PrimitiveCount; i++) {
batch->Indices[batch->Offset++] = (StartVertex + i * 2 + 0);
batch->Indices[batch->Offset++] = (StartVertex + i * 2 + 1);
}
break;
case D3DPT_LINESTRIP:
batch->Indices.resize(batch->Offset + PrimitiveCount * 2);
for (UINT i = 0; i < PrimitiveCount; i++) {
batch->Indices[batch->Offset++] = (StartVertex + i + 0);
batch->Indices[batch->Offset++] = (StartVertex + i + 1);
}
break;
case D3DPT_TRIANGLELIST:
batch->Indices.resize(batch->Offset + PrimitiveCount * 3);
for (UINT i = 0; i < PrimitiveCount; i++) {
batch->Indices[batch->Offset++] = (StartVertex + i * 3 + 0);
batch->Indices[batch->Offset++] = (StartVertex + i * 3 + 1);
batch->Indices[batch->Offset++] = (StartVertex + i * 3 + 2);
}
break;
case D3DPT_TRIANGLESTRIP:
// Join with degenerate triangle
// 1 2 3, 3 4, 4 5 6
batch->Indices.resize(batch->Offset + PrimitiveCount + 2);
if (batch->Offset > 0) {
batch->Indices[batch->Offset + 1] = batch->Indices[batch->Offset-2];
batch->Indices[batch->Offset += 2] = StartVertex;
}
for (UINT i = 0; i < PrimitiveCount; i++) {
batch->Indices[batch->Offset++] = (StartVertex + i + 0);
}
break;
// 1 2 3 4 5 6 7 -> 1 2 3, 1 3 4, 1 4 5, 1 5 6, 1 6 7
case D3DPT_TRIANGLEFAN:
batch->Indices.resize(batch->Offset + PrimitiveCount * 3);
for (UINT i = 0; i < PrimitiveCount; i++) {
batch->Indices[batch->Offset++] = (StartVertex + 0);
batch->Indices[batch->Offset++] = (StartVertex + i + 1);
batch->Indices[batch->Offset++] = (StartVertex + i + 2);
}
break;
default:
return D3DERR_INVALIDCALL;
}
batch->MinVertex = std::min(batch->MinVertex, StartVertex);
if (!batch->Indices.empty())
batch->MaxVertex = std::max(batch->MaxVertex, UINT(batch->Indices.back() + 1));
batch->PrimitiveCount += PrimitiveCount;
batch->DrawCallCount++;
return D3D_OK;
}
inline void SetStream(UINT num, D3D8VertexBuffer* stream, UINT stride) {
if (unlikely(num != 0)) {
StateChange();
return;
}
if (unlikely(m_stream != stream || m_stride != stride)) {
StateChange();
m_stream = static_cast<D3D8BatchBuffer*>(stream);
m_stride = stride;
}
}
inline void SetIndices(D3D8IndexBuffer* indices, INT baseVertexIndex) {
if (m_indices != indices || m_baseVertexIndex != baseVertexIndex) {
StateChange();
m_indices = indices;
m_baseVertexIndex = baseVertexIndex;
}
}
private:
D3D8Device* m_device8;
Com<d3d9::IDirect3DDevice9> m_device;
D3D8BatchBuffer* m_stream = nullptr;
UINT m_stride = 0;
D3D8IndexBuffer* m_indices = nullptr;
INT m_baseVertexIndex = 0;
std::array<Batch, D3DPT_COUNT> m_batches;
};
}

38
src/d3d8/d3d8_buffer.cpp Normal file
View file

@ -0,0 +1,38 @@
#include "d3d8_buffer.h"
#include "d3d8_device.h"
namespace dxvk {
// D3D8VertexBuffer
D3D8VertexBuffer::D3D8VertexBuffer(
D3D8Device* pDevice,
Com<d3d9::IDirect3DVertexBuffer9>&& pBuffer,
D3DPOOL Pool,
DWORD Usage)
: D3D8VertexBufferBase(pDevice, std::move(pBuffer), Pool, Usage) {
}
D3DRESOURCETYPE STDMETHODCALLTYPE D3D8VertexBuffer::GetType() { return D3DRTYPE_VERTEXBUFFER; }
HRESULT STDMETHODCALLTYPE D3D8VertexBuffer::GetDesc(D3DVERTEXBUFFER_DESC* pDesc) {
return GetD3D9()->GetDesc(reinterpret_cast<d3d9::D3DVERTEXBUFFER_DESC*>(pDesc));
}
// D3D8IndexBuffer
D3D8IndexBuffer::D3D8IndexBuffer(
D3D8Device* pDevice,
Com<d3d9::IDirect3DIndexBuffer9>&& pBuffer,
D3DPOOL Pool,
DWORD Usage)
: D3D8IndexBufferBase(pDevice, std::move(pBuffer), Pool, Usage) {
}
D3DRESOURCETYPE STDMETHODCALLTYPE D3D8IndexBuffer::GetType() { return D3DRTYPE_INDEXBUFFER; }
HRESULT STDMETHODCALLTYPE D3D8IndexBuffer::GetDesc(D3DINDEXBUFFER_DESC* pDesc) {
return GetD3D9()->GetDesc(reinterpret_cast<d3d9::D3DINDEXBUFFER_DESC*>(pDesc));
}
}

93
src/d3d8/d3d8_buffer.h Normal file
View file

@ -0,0 +1,93 @@
#pragma once
#include "d3d8_include.h"
#include "d3d8_options.h"
#include "d3d8_resource.h"
namespace dxvk {
template <typename D3D9, typename D3D8>
class D3D8Buffer : public D3D8Resource<D3D9, D3D8> {
public:
D3D8Buffer(
D3D8Device* pDevice,
Com<D3D9>&& pBuffer,
D3DPOOL Pool,
DWORD Usage)
: D3D8Resource<D3D9, D3D8> (pDevice, Pool, std::move(pBuffer))
, m_usage (Usage) {
m_options = this->GetParent()->GetOptions();
}
HRESULT STDMETHODCALLTYPE Lock(
UINT OffsetToLock,
UINT SizeToLock,
BYTE** ppbData,
DWORD Flags) {
if (m_options->forceLegacyDiscard &&
(Flags & D3DLOCK_DISCARD) &&
!((m_usage & D3DUSAGE_DYNAMIC) &&
(m_usage & D3DUSAGE_WRITEONLY)))
Flags &= ~D3DLOCK_DISCARD;
return this->GetD3D9()->Lock(
OffsetToLock,
SizeToLock,
reinterpret_cast<void**>(ppbData),
Flags);
}
HRESULT STDMETHODCALLTYPE Unlock() {
return this->GetD3D9()->Unlock();
}
void STDMETHODCALLTYPE PreLoad() {
this->GetD3D9()->PreLoad();
}
protected:
const D3D8Options* m_options;
const DWORD m_usage;
};
using D3D8VertexBufferBase = D3D8Buffer<d3d9::IDirect3DVertexBuffer9, IDirect3DVertexBuffer8>;
class D3D8VertexBuffer : public D3D8VertexBufferBase {
public:
D3D8VertexBuffer(
D3D8Device* pDevice,
Com<d3d9::IDirect3DVertexBuffer9>&& pBuffer,
D3DPOOL Pool,
DWORD Usage);
D3DRESOURCETYPE STDMETHODCALLTYPE GetType() final;
HRESULT STDMETHODCALLTYPE GetDesc(D3DVERTEXBUFFER_DESC* pDesc);
};
using D3D8IndexBufferBase = D3D8Buffer<d3d9::IDirect3DIndexBuffer9, IDirect3DIndexBuffer8>;
class D3D8IndexBuffer final : public D3D8IndexBufferBase {
public:
D3D8IndexBuffer(
D3D8Device* pDevice,
Com<d3d9::IDirect3DIndexBuffer9>&& pBuffer,
D3DPOOL Pool,
DWORD Usage);
D3DRESOURCETYPE STDMETHODCALLTYPE GetType() final;
HRESULT STDMETHODCALLTYPE GetDesc(D3DINDEXBUFFER_DESC* pDesc) final;
};
}

8
src/d3d8/d3d8_caps.h Normal file
View file

@ -0,0 +1,8 @@
#pragma once
namespace dxvk::d8caps {
inline constexpr uint32_t MAX_TEXTURE_STAGES = 8;
inline constexpr uint32_t MAX_STREAMS = 16;
}

194
src/d3d8/d3d8_d3d9_util.h Normal file
View file

@ -0,0 +1,194 @@
#pragma once
// Utility functions for converting
// between DirectX8 and DirectX9 types.
#include "d3d8_include.h"
#include "d3d8_format.h"
#include "d3d8_options.h"
#include <utility>
namespace dxvk {
// (8<-9) D3DCAPSX: Writes to D3DCAPS8 from D3DCAPS9
inline void ConvertCaps8(const d3d9::D3DCAPS9& caps9, D3DCAPS8* pCaps8) {
// should be aligned
std::memcpy(pCaps8, &caps9, sizeof(D3DCAPS8));
// Max supported shader model is PS 1.4 and VS 1.1
pCaps8->VertexShaderVersion = D3DVS_VERSION(1, 1);
// Late fixed-function capable hardware will advertise VS 1.1
// support, but will not advertise any support for PS
if (likely(caps9.PixelShaderVersion != D3DPS_VERSION(0, 0)))
pCaps8->PixelShaderVersion = D3DPS_VERSION(1, 4);
// Remove D3D9-specific caps:
pCaps8->Caps2 &= ~D3DCAPS2_CANAUTOGENMIPMAP;
pCaps8->Caps3 &= ~D3DCAPS3_LINEAR_TO_SRGB_PRESENTATION
& ~D3DCAPS3_COPY_TO_VIDMEM
& ~D3DCAPS3_COPY_TO_SYSTEMMEM;
pCaps8->PrimitiveMiscCaps &= ~D3DPMISCCAPS_INDEPENDENTWRITEMASKS
& ~D3DPMISCCAPS_PERSTAGECONSTANT
& ~D3DPMISCCAPS_FOGANDSPECULARALPHA
& ~D3DPMISCCAPS_SEPARATEALPHABLEND
& ~D3DPMISCCAPS_MRTINDEPENDENTBITDEPTHS
& ~D3DPMISCCAPS_MRTPOSTPIXELSHADERBLENDING
& ~D3DPMISCCAPS_FOGVERTEXCLAMPED
& ~D3DPMISCCAPS_POSTBLENDSRGBCONVERT;
pCaps8->RasterCaps &= ~D3DPRASTERCAPS_SCISSORTEST
& ~D3DPRASTERCAPS_SLOPESCALEDEPTHBIAS
& ~D3DPRASTERCAPS_DEPTHBIAS
& ~D3DPRASTERCAPS_MULTISAMPLE_TOGGLE;
pCaps8->SrcBlendCaps &= ~D3DPBLENDCAPS_BLENDFACTOR;
pCaps8->DestBlendCaps &= ~D3DPBLENDCAPS_BLENDFACTOR;
pCaps8->LineCaps &= ~D3DLINECAPS_ANTIALIAS;
pCaps8->StencilCaps &= ~D3DSTENCILCAPS_TWOSIDED;
pCaps8->VertexProcessingCaps &= ~D3DVTXPCAPS_TEXGEN_SPHEREMAP;
// Add D3D8-specific caps:
// Removed in D3D9, since it can always render windowed
pCaps8->Caps2 |= D3DCAPS2_CANRENDERWINDOWED
// A remnant from a bygone age of ddraw interop most likely
/* | D3DCAPS2_NO2DDURING3DSCENE*/;
// Used in conjunction with D3DPRASTERCAPS_PAT, but generally unadvertised
/*pCaps8->PrimitiveMiscCaps |= D3DPMISCCAPS_LINEPATTERNREP;*/
// Replaced by D3DPRASTERCAPS_DEPTHBIAS in D3D9
pCaps8->RasterCaps |= D3DPRASTERCAPS_ZBIAS
// Advertised on Nvidia cards by modern drivers, but not on AMD or Intel
/* | D3DPRASTERCAPS_ANTIALIASEDGES*/
// Advertised on Nvidia cards, but not on AMD or Intel
/* | D3DPRASTERCAPS_STRETCHBLTMULTISAMPLE*/
// TODO: Implement D3DRS_LINEPATTERN - vkCmdSetLineRasterizationModeEXT
/* | D3DPRASTERCAPS_PAT*/;
// MAG only filter caps, generally unsupported
/*pCaps8->TextureFilterCaps |= D3DPTFILTERCAPS_MAGFAFLATCUBIC*/
/* | D3DPTFILTERCAPS_MAGFGAUSSIANCUBIC;*/
/*pCaps8->CubeTextureFilterCaps = pCaps8->TextureFilterCaps;*/
/*pCaps8->VolumeTextureFilterCaps = pCaps8->TextureFilterCaps;*/
// Not advertised on any modern hardware
/*pCaps8->VertexProcessingCaps |= D3DVTXPCAPS_NO_VSDT_UBYTE4;*/
}
// (9<-8) D3DD3DPRESENT_PARAMETERS: Returns D3D9's params given an input for D3D8
inline d3d9::D3DPRESENT_PARAMETERS ConvertPresentParameters9(D3DPRESENT_PARAMETERS* pParams) {
// A 0 back buffer count needs to be corrected and made visible to the D3D8 application as well
pParams->BackBufferCount = std::max(pParams->BackBufferCount, 1u);
if (pParams->BackBufferFormat == D3DFMT_UNKNOWN)
pParams->BackBufferFormat = D3DFMT_X8R8G8B8;
d3d9::D3DPRESENT_PARAMETERS params;
params.BackBufferWidth = pParams->BackBufferWidth;
params.BackBufferHeight = pParams->BackBufferHeight;
params.BackBufferFormat = d3d9::D3DFORMAT(pParams->BackBufferFormat);
params.BackBufferCount = pParams->BackBufferCount;
params.MultiSampleType = d3d9::D3DMULTISAMPLE_TYPE(pParams->MultiSampleType);
// MultiSampleQuality is only used with D3DMULTISAMPLE_NONMASKABLE, which is not available in D3D8
params.MultiSampleQuality = 0;
// If an application passes multiple D3DPRESENT_INTERVAL flags, this will be
// validated appropriately by D3D9. Simply copy the values here.
UINT PresentationInterval = pParams->FullScreen_PresentationInterval;
if (pParams->Windowed) {
// D3D8: For windowed swap chain, the back buffer is copied to the window immediately.
PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
}
D3DSWAPEFFECT SwapEffect = pParams->SwapEffect;
if (SwapEffect == D3DSWAPEFFECT_COPY_VSYNC) {
// D3DSWAPEFFECT_COPY_VSYNC has been removed from D3D9, use D3DSWAPEFFECT_COPY
SwapEffect = D3DSWAPEFFECT_COPY;
// D3D8: In windowed mode, D3DSWAPEFFECT_COPY_VSYNC enables VSYNC.
// In fullscreen, D3DPRESENT_INTERVAL_IMMEDIATE is meaningless.
if (pParams->Windowed || PresentationInterval == D3DPRESENT_INTERVAL_IMMEDIATE) {
PresentationInterval = D3DPRESENT_INTERVAL_ONE;
}
}
params.SwapEffect = d3d9::D3DSWAPEFFECT(SwapEffect);
params.hDeviceWindow = pParams->hDeviceWindow;
params.Windowed = pParams->Windowed;
params.EnableAutoDepthStencil = pParams->EnableAutoDepthStencil;
params.AutoDepthStencilFormat = d3d9::D3DFORMAT(pParams->AutoDepthStencilFormat);
params.Flags = pParams->Flags;
// D3DPRESENT_RATE_UNLIMITED is unsupported, use D3DPRESENT_RATE_DEFAULT (or 0)
if (unlikely(pParams->FullScreen_RefreshRateInHz == D3DPRESENT_RATE_UNLIMITED)) {
params.FullScreen_RefreshRateInHz = D3DPRESENT_RATE_DEFAULT;
} else {
params.FullScreen_RefreshRateInHz = pParams->FullScreen_RefreshRateInHz;
}
// FullScreen_PresentationInterval -> PresentationInterval
params.PresentationInterval = PresentationInterval;
return params;
}
// (8<-9) Convert D3DSURFACE_DESC
inline void ConvertSurfaceDesc8(const d3d9::D3DSURFACE_DESC* pSurf9, D3DSURFACE_DESC* pSurf8) {
pSurf8->Format = D3DFORMAT(pSurf9->Format);
pSurf8->Type = D3DRESOURCETYPE(pSurf9->Type);
pSurf8->Usage = pSurf9->Usage;
pSurf8->Pool = D3DPOOL(pSurf9->Pool);
pSurf8->Size = getSurfaceSize(pSurf8->Format, pSurf9->Width, pSurf9->Height);
pSurf8->MultiSampleType = D3DMULTISAMPLE_TYPE(pSurf9->MultiSampleType);
// DX8: No multisample quality
pSurf8->Width = pSurf9->Width;
pSurf8->Height = pSurf9->Height;
}
// (8<-9) Convert D3DVOLUME_DESC
inline void ConvertVolumeDesc8(const d3d9::D3DVOLUME_DESC* pVol9, D3DVOLUME_DESC* pVol8) {
pVol8->Format = D3DFORMAT(pVol9->Format);
pVol8->Type = D3DRESOURCETYPE(pVol9->Type);
pVol8->Usage = pVol9->Usage;
pVol8->Pool = D3DPOOL(pVol9->Pool);
pVol8->Size = getSurfaceSize(pVol8->Format, pVol9->Width, pVol9->Height) * pVol9->Depth;
pVol8->Width = pVol9->Width;
pVol8->Height = pVol9->Height;
pVol8->Depth = pVol9->Depth;
}
// If this D3DTEXTURESTAGESTATETYPE has been remapped to a d3d9::D3DSAMPLERSTATETYPE
// it will be returned, otherwise returns -1u
inline d3d9::D3DSAMPLERSTATETYPE GetSamplerStateType9(const D3DTEXTURESTAGESTATETYPE StageType) {
switch (StageType) {
// 13-21:
case D3DTSS_ADDRESSU: return d3d9::D3DSAMP_ADDRESSU;
case D3DTSS_ADDRESSV: return d3d9::D3DSAMP_ADDRESSV;
case D3DTSS_BORDERCOLOR: return d3d9::D3DSAMP_BORDERCOLOR;
case D3DTSS_MAGFILTER: return d3d9::D3DSAMP_MAGFILTER;
case D3DTSS_MINFILTER: return d3d9::D3DSAMP_MINFILTER;
case D3DTSS_MIPFILTER: return d3d9::D3DSAMP_MIPFILTER;
case D3DTSS_MIPMAPLODBIAS: return d3d9::D3DSAMP_MIPMAPLODBIAS;
case D3DTSS_MAXMIPLEVEL: return d3d9::D3DSAMP_MAXMIPLEVEL;
case D3DTSS_MAXANISOTROPY: return d3d9::D3DSAMP_MAXANISOTROPY;
// 25:
case D3DTSS_ADDRESSW: return d3d9::D3DSAMP_ADDRESSW;
default: return d3d9::D3DSAMPLERSTATETYPE(-1u);
}
}
}

2188
src/d3d8/d3d8_device.cpp Normal file

File diff suppressed because it is too large Load diff

478
src/d3d8/d3d8_device.h Normal file
View file

@ -0,0 +1,478 @@
#pragma once
#include "d3d8_include.h"
#include "d3d8_multithread.h"
#include "d3d8_texture.h"
#include "d3d8_buffer.h"
#include "d3d8_swapchain.h"
#include "d3d8_state_block.h"
#include "d3d8_d3d9_util.h"
#include "d3d8_caps.h"
#include "d3d8_batch.h"
#include "../d3d9/d3d9_bridge.h"
#include <array>
#include <vector>
#include <type_traits>
#include <unordered_map>
namespace dxvk {
class D3D8Interface;
struct D3D8VertexShaderInfo;
using D3D8DeviceBase = D3D8WrappedObject<d3d9::IDirect3DDevice9, IDirect3DDevice8>;
class D3D8Device final : public D3D8DeviceBase {
friend class D3D8StateBlock;
public:
D3D8Device(
D3D8Interface* pParent,
Com<d3d9::IDirect3DDevice9>&& pDevice,
D3DDEVTYPE DeviceType,
HWND hFocusWindow,
DWORD BehaviorFlags,
D3DPRESENT_PARAMETERS* pParams);
~D3D8Device();
HRESULT STDMETHODCALLTYPE TestCooperativeLevel();
UINT STDMETHODCALLTYPE GetAvailableTextureMem();
HRESULT STDMETHODCALLTYPE ResourceManagerDiscardBytes(DWORD bytes);
HRESULT STDMETHODCALLTYPE GetDirect3D(IDirect3D8** ppD3D8);
HRESULT STDMETHODCALLTYPE GetDeviceCaps(D3DCAPS8* pCaps);
HRESULT STDMETHODCALLTYPE GetDisplayMode(D3DDISPLAYMODE* pMode);
HRESULT STDMETHODCALLTYPE GetCreationParameters(D3DDEVICE_CREATION_PARAMETERS* pParameters);
HRESULT STDMETHODCALLTYPE SetCursorProperties(
UINT XHotSpot,
UINT YHotSpot,
IDirect3DSurface8* pCursorBitmap);
void STDMETHODCALLTYPE SetCursorPosition(UINT XScreenSpace, UINT YScreenSpace, DWORD Flags);
// Microsoft d3d8.h in the DirectX 9 SDK uses a different function signature...
void STDMETHODCALLTYPE SetCursorPosition(int X, int Y, DWORD Flags);
BOOL STDMETHODCALLTYPE ShowCursor(BOOL bShow);
HRESULT STDMETHODCALLTYPE CreateAdditionalSwapChain(
D3DPRESENT_PARAMETERS* pPresentationParameters,
IDirect3DSwapChain8** ppSwapChain);
HRESULT STDMETHODCALLTYPE Reset(D3DPRESENT_PARAMETERS* pPresentationParameters);
HRESULT STDMETHODCALLTYPE Present(
const RECT* pSourceRect,
const RECT* pDestRect,
HWND hDestWindowOverride,
const RGNDATA* pDirtyRegion);
HRESULT STDMETHODCALLTYPE GetBackBuffer(
UINT iBackBuffer,
D3DBACKBUFFER_TYPE Type,
IDirect3DSurface8** ppBackBuffer);
HRESULT STDMETHODCALLTYPE GetRasterStatus(D3DRASTER_STATUS* pRasterStatus);
void STDMETHODCALLTYPE SetGammaRamp(DWORD Flags, const D3DGAMMARAMP* pRamp);
void STDMETHODCALLTYPE GetGammaRamp(D3DGAMMARAMP* pRamp);
HRESULT STDMETHODCALLTYPE CreateTexture(
UINT Width,
UINT Height,
UINT Levels,
DWORD Usage,
D3DFORMAT Format,
D3DPOOL Pool,
IDirect3DTexture8** ppTexture);
HRESULT STDMETHODCALLTYPE CreateVolumeTexture(
UINT Width,
UINT Height,
UINT Depth,
UINT Levels,
DWORD Usage,
D3DFORMAT Format,
D3DPOOL Pool,
IDirect3DVolumeTexture8** ppVolumeTexture);
HRESULT STDMETHODCALLTYPE CreateCubeTexture(
UINT EdgeLength,
UINT Levels,
DWORD Usage,
D3DFORMAT Format,
D3DPOOL Pool,
IDirect3DCubeTexture8** ppCubeTexture);
HRESULT STDMETHODCALLTYPE CreateVertexBuffer(
UINT Length,
DWORD Usage,
DWORD FVF,
D3DPOOL Pool,
IDirect3DVertexBuffer8** ppVertexBuffer);
HRESULT STDMETHODCALLTYPE CreateIndexBuffer(
UINT Length,
DWORD Usage,
D3DFORMAT Format,
D3DPOOL Pool,
IDirect3DIndexBuffer8** ppIndexBuffer);
HRESULT STDMETHODCALLTYPE CreateRenderTarget(
UINT Width,
UINT Height,
D3DFORMAT Format,
D3DMULTISAMPLE_TYPE MultiSample,
BOOL Lockable,
IDirect3DSurface8** ppSurface);
HRESULT STDMETHODCALLTYPE CreateDepthStencilSurface(
UINT Width,
UINT Height,
D3DFORMAT Format,
D3DMULTISAMPLE_TYPE MultiSample,
IDirect3DSurface8** ppSurface);
HRESULT STDMETHODCALLTYPE CreateImageSurface(UINT Width, UINT Height, D3DFORMAT Format, IDirect3DSurface8** ppSurface);
HRESULT STDMETHODCALLTYPE CopyRects(
IDirect3DSurface8* pSourceSurface,
const RECT* pSourceRectsArray,
UINT cRects,
IDirect3DSurface8* pDestinationSurface,
const POINT* pDestPointsArray);
HRESULT STDMETHODCALLTYPE UpdateTexture(
IDirect3DBaseTexture8* pSourceTexture,
IDirect3DBaseTexture8* pDestinationTexture);
HRESULT STDMETHODCALLTYPE GetFrontBuffer(IDirect3DSurface8* pDestSurface);
HRESULT STDMETHODCALLTYPE SetRenderTarget(IDirect3DSurface8* pRenderTarget, IDirect3DSurface8* pNewZStencil);
HRESULT STDMETHODCALLTYPE GetRenderTarget(IDirect3DSurface8** ppRenderTarget);
HRESULT STDMETHODCALLTYPE GetDepthStencilSurface(IDirect3DSurface8** ppZStencilSurface);
HRESULT STDMETHODCALLTYPE BeginScene();
HRESULT STDMETHODCALLTYPE EndScene();
HRESULT STDMETHODCALLTYPE Clear(
DWORD Count,
const D3DRECT* pRects,
DWORD Flags,
D3DCOLOR Color,
float Z,
DWORD Stencil);
HRESULT STDMETHODCALLTYPE SetTransform(D3DTRANSFORMSTATETYPE State, const D3DMATRIX* pMatrix);
HRESULT STDMETHODCALLTYPE GetTransform(D3DTRANSFORMSTATETYPE State, D3DMATRIX* pMatrix);
HRESULT STDMETHODCALLTYPE MultiplyTransform(D3DTRANSFORMSTATETYPE TransformState, const D3DMATRIX* pMatrix);
HRESULT STDMETHODCALLTYPE SetViewport(const D3DVIEWPORT8* pViewport);
HRESULT STDMETHODCALLTYPE GetViewport(D3DVIEWPORT8* pViewport);
HRESULT STDMETHODCALLTYPE SetMaterial(const D3DMATERIAL8* pMaterial);
HRESULT STDMETHODCALLTYPE GetMaterial(D3DMATERIAL8* pMaterial);
HRESULT STDMETHODCALLTYPE SetLight(DWORD Index, const D3DLIGHT8* pLight);
HRESULT STDMETHODCALLTYPE GetLight(DWORD Index, D3DLIGHT8* pLight);
HRESULT STDMETHODCALLTYPE LightEnable(DWORD Index, BOOL Enable);
HRESULT STDMETHODCALLTYPE GetLightEnable(DWORD Index, BOOL* pEnable);
HRESULT STDMETHODCALLTYPE SetClipPlane(DWORD Index, const float* pPlane);
HRESULT STDMETHODCALLTYPE GetClipPlane(DWORD Index, float* pPlane);
HRESULT STDMETHODCALLTYPE SetRenderState(D3DRENDERSTATETYPE State, DWORD Value);
HRESULT STDMETHODCALLTYPE GetRenderState(D3DRENDERSTATETYPE State, DWORD* pValue);
HRESULT STDMETHODCALLTYPE CreateStateBlock(
D3DSTATEBLOCKTYPE Type,
DWORD* pToken);
HRESULT STDMETHODCALLTYPE CaptureStateBlock(DWORD Token);
HRESULT STDMETHODCALLTYPE ApplyStateBlock(DWORD Token);
HRESULT STDMETHODCALLTYPE DeleteStateBlock(DWORD Token);
HRESULT STDMETHODCALLTYPE BeginStateBlock();
HRESULT STDMETHODCALLTYPE EndStateBlock(DWORD* pToken);
HRESULT STDMETHODCALLTYPE SetClipStatus(const D3DCLIPSTATUS8* pClipStatus);
HRESULT STDMETHODCALLTYPE GetClipStatus(D3DCLIPSTATUS8* pClipStatus);
HRESULT STDMETHODCALLTYPE GetTexture(DWORD Stage, IDirect3DBaseTexture8** ppTexture);
HRESULT STDMETHODCALLTYPE SetTexture(DWORD Stage, IDirect3DBaseTexture8* pTexture);
HRESULT STDMETHODCALLTYPE GetTextureStageState(
DWORD Stage,
D3DTEXTURESTAGESTATETYPE Type,
DWORD* pValue);
HRESULT STDMETHODCALLTYPE SetTextureStageState(
DWORD Stage,
D3DTEXTURESTAGESTATETYPE Type,
DWORD Value);
HRESULT STDMETHODCALLTYPE ValidateDevice(DWORD* pNumPasses);
HRESULT STDMETHODCALLTYPE GetInfo(DWORD DevInfoID, void* pDevInfoStruct, DWORD DevInfoStructSize);
HRESULT STDMETHODCALLTYPE SetPaletteEntries(UINT PaletteNumber, const PALETTEENTRY* pEntries);
HRESULT STDMETHODCALLTYPE GetPaletteEntries(UINT PaletteNumber, PALETTEENTRY* pEntries);
HRESULT STDMETHODCALLTYPE SetCurrentTexturePalette(UINT PaletteNumber);
HRESULT STDMETHODCALLTYPE GetCurrentTexturePalette(UINT* PaletteNumber);
HRESULT STDMETHODCALLTYPE DrawPrimitive(
D3DPRIMITIVETYPE PrimitiveType,
UINT StartVertex,
UINT PrimitiveCount);
HRESULT STDMETHODCALLTYPE DrawIndexedPrimitive(
D3DPRIMITIVETYPE PrimitiveType,
UINT MinVertexIndex,
UINT NumVertices,
UINT StartIndex,
UINT PrimitiveCount);
HRESULT STDMETHODCALLTYPE DrawPrimitiveUP(
D3DPRIMITIVETYPE PrimitiveType,
UINT PrimitiveCount,
const void* pVertexStreamZeroData,
UINT VertexStreamZeroStride);
HRESULT STDMETHODCALLTYPE DrawIndexedPrimitiveUP(
D3DPRIMITIVETYPE PrimitiveType,
UINT MinVertexIndex,
UINT NumVertices,
UINT PrimitiveCount,
const void* pIndexData,
D3DFORMAT IndexDataFormat,
const void* pVertexStreamZeroData,
UINT VertexStreamZeroStride);
HRESULT STDMETHODCALLTYPE ProcessVertices(
UINT SrcStartIndex,
UINT DestIndex,
UINT VertexCount,
IDirect3DVertexBuffer8* pDestBuffer,
DWORD Flags);
HRESULT STDMETHODCALLTYPE CreateVertexShader(
const DWORD* pDeclaration,
const DWORD* pFunction,
DWORD* pHandle,
DWORD Usage);
HRESULT STDMETHODCALLTYPE SetVertexShader(DWORD Handle);
HRESULT STDMETHODCALLTYPE GetVertexShader(DWORD* pHandle);
HRESULT STDMETHODCALLTYPE DeleteVertexShader(DWORD Handle);
HRESULT STDMETHODCALLTYPE SetVertexShaderConstant(
DWORD StartRegister,
const void* pConstantData,
DWORD ConstantCount);
HRESULT STDMETHODCALLTYPE GetVertexShaderConstant(DWORD Register, void* pConstantData, DWORD ConstantCount);
HRESULT STDMETHODCALLTYPE GetVertexShaderDeclaration(DWORD Handle, void* pData, DWORD* pSizeOfData);
HRESULT STDMETHODCALLTYPE GetVertexShaderFunction(DWORD Handle, void* pData, DWORD* pSizeOfData);
HRESULT STDMETHODCALLTYPE SetStreamSource(
UINT StreamNumber,
IDirect3DVertexBuffer8* pStreamData,
UINT Stride);
HRESULT STDMETHODCALLTYPE GetStreamSource(
UINT StreamNumber,
IDirect3DVertexBuffer8** ppStreamData,
UINT* pStride);
HRESULT STDMETHODCALLTYPE SetIndices(IDirect3DIndexBuffer8* pIndexData, UINT BaseVertexIndex);
HRESULT STDMETHODCALLTYPE GetIndices(
IDirect3DIndexBuffer8** ppIndexData,
UINT* pBaseVertexIndex);
HRESULT STDMETHODCALLTYPE CreatePixelShader(
const DWORD* pFunction,
DWORD* pHandle);
HRESULT STDMETHODCALLTYPE SetPixelShader(DWORD Handle);
HRESULT STDMETHODCALLTYPE GetPixelShader(DWORD* pHandle);
HRESULT STDMETHODCALLTYPE DeletePixelShader(THIS_ DWORD Handle);
HRESULT STDMETHODCALLTYPE GetPixelShaderConstant(DWORD Register, void* pConstantData, DWORD ConstantCount);
HRESULT STDMETHODCALLTYPE SetPixelShaderConstant(
DWORD StartRegister,
const void* pConstantData,
DWORD ConstantCount);
HRESULT STDMETHODCALLTYPE GetPixelShaderFunction(DWORD Handle, void* pData, DWORD* pSizeOfData);
HRESULT STDMETHODCALLTYPE DrawRectPatch(
UINT Handle,
const float* pNumSegs,
const D3DRECTPATCH_INFO* pRectPatchInfo);
HRESULT STDMETHODCALLTYPE DrawTriPatch(
UINT Handle,
const float* pNumSegs,
const D3DTRIPATCH_INFO* pTriPatchInfo);
HRESULT STDMETHODCALLTYPE DeletePatch(UINT Handle);
const D3D8Options* GetOptions() const {
return &m_d3d8Options;
}
inline bool ShouldRecord() { return m_recorder != nullptr; }
inline bool ShouldBatch() { return m_batcher != nullptr; }
D3D8DeviceLock LockDevice() {
return m_multithread.AcquireLock();
}
/**
* Marks any state change in the device, so we can signal
* the batcher to emit draw calls. StateChange should be
* called immediately before changing any D3D9 state.
*/
inline void StateChange() {
if (ShouldBatch())
m_batcher->StateChange();
}
inline void ResetState() {
// Mirrors how D3D9 handles the BackBufferCount
m_presentParams.BackBufferCount = std::max(m_presentParams.BackBufferCount, 1u);
// Purge cached objects
m_textures.fill(nullptr);
m_streams.fill(D3D8VBO());
m_indices = nullptr;
m_renderTarget = nullptr;
m_depthStencil = nullptr;
m_backBuffers.clear();
m_backBuffers.resize(m_presentParams.BackBufferCount);
m_autoDepthStencil = nullptr;
m_shadowPerspectiveDivide = false;
}
inline void RecreateBackBuffersAndAutoDepthStencil() {
for (UINT i = 0; i < m_presentParams.BackBufferCount; i++) {
Com<d3d9::IDirect3DSurface9> pSurface9;
GetD3D9()->GetBackBuffer(0, i, d3d9::D3DBACKBUFFER_TYPE_MONO, &pSurface9);
m_backBuffers[i] = new D3D8Surface(this, D3DPOOL_DEFAULT, std::move(pSurface9));
}
Com<d3d9::IDirect3DSurface9> pStencil9;
// This call will fail if the D3D9 device is created without
// the EnableAutoDepthStencil presentation parameter set to TRUE.
HRESULT res = GetD3D9()->GetDepthStencilSurface(&pStencil9);
m_autoDepthStencil = FAILED(res) ? nullptr : new D3D8Surface(this, D3DPOOL_DEFAULT, std::move(pStencil9));
m_renderTarget = m_backBuffers[0];
m_depthStencil = m_autoDepthStencil;
}
friend d3d9::IDirect3DPixelShader9* getPixelShaderPtr(D3D8Device* device, DWORD Handle);
friend D3D8VertexShaderInfo* getVertexShaderInfo(D3D8Device* device, DWORD Handle);
private:
Com<IDxvkD3D8Bridge> m_bridge;
const D3D8Options& m_d3d8Options;
Com<D3D8Interface> m_parent;
D3DPRESENT_PARAMETERS m_presentParams;
// Value of D3DRS_LINEPATTERN
D3DLINEPATTERN m_linePattern = {};
// Value of D3DRS_ZVISIBLE (although the RS is not supported, its value is stored)
DWORD m_zVisible = 0;
// Value of D3DRS_PATCHSEGMENTS
float m_patchSegments = 1.0f;
// Controls fixed-function exclusive mode (no PS support)
bool m_isFixedFunctionOnly = false;
bool m_shadowPerspectiveDivide = false;
D3D8StateBlock* m_recorder = nullptr;
DWORD m_recorderToken = 0;
DWORD m_token = 0;
std::unordered_map<DWORD, D3D8StateBlock> m_stateBlocks;
D3D8Batcher* m_batcher = nullptr;
struct D3D8VBO {
Com<D3D8VertexBuffer, false> buffer = nullptr;
UINT stride = 0;
};
std::array<Com<D3D8Texture2D, false>, d8caps::MAX_TEXTURE_STAGES> m_textures;
std::array<D3D8VBO, d8caps::MAX_STREAMS> m_streams;
Com<D3D8IndexBuffer, false> m_indices;
UINT m_baseVertexIndex = 0;
std::vector<Com<D3D8Surface, false>> m_backBuffers;
Com<D3D8Surface, false> m_autoDepthStencil;
Com<D3D8Surface, false> m_renderTarget;
Com<D3D8Surface, false> m_depthStencil;
std::vector<D3D8VertexShaderInfo> m_vertexShaders;
std::vector<Com<d3d9::IDirect3DPixelShader9>> m_pixelShaders;
DWORD m_currentVertexShader = 0; // can be FVF or vs index (marked by D3DFVF_RESERVED0)
DWORD m_currentPixelShader = 0;
D3DDEVTYPE m_deviceType;
HWND m_window;
DWORD m_behaviorFlags;
D3D8Multithread m_multithread;
};
}

View file

@ -0,0 +1,83 @@
#pragma once
// Common methods for device-tied objects.
// - AddRef, Release from IUnknown
// - GetDevice from various classes including IDirect3DResource8
#include "d3d8_include.h"
#include "d3d8_wrapped_object.h"
namespace dxvk {
class D3D8Device;
template <typename D3D9, typename D3D8>
class D3D8DeviceChild : public D3D8WrappedObject<D3D9, D3D8> {
public:
D3D8DeviceChild(D3D8Device* pDevice, Com<D3D9>&& Object)
: D3D8WrappedObject<D3D9, D3D8>(std::move(Object))
, m_parent( pDevice ) { }
ULONG STDMETHODCALLTYPE AddRef() {
uint32_t refCount = this->m_refCount++;
if (unlikely(!refCount)) {
this->AddRefPrivate();
GetDevice()->AddRef();
}
return refCount + 1;
}
ULONG STDMETHODCALLTYPE Release() {
uint32_t oldRefCount, refCount;
do {
oldRefCount = this->m_refCount.load(std::memory_order_acquire);
// clamp value to 0 to prevent underruns
if (unlikely(!oldRefCount))
return 0;
refCount = oldRefCount - 1;
} while (!this->m_refCount.compare_exchange_weak(oldRefCount,
refCount,
std::memory_order_release,
std::memory_order_acquire));
if (unlikely(!refCount)) {
auto* pDevice = GetDevice();
this->ReleasePrivate();
pDevice->Release();
}
return refCount;
}
HRESULT STDMETHODCALLTYPE GetDevice(IDirect3DDevice8** ppDevice) {
InitReturnPtr(ppDevice);
if (ppDevice == nullptr)
return D3DERR_INVALIDCALL;
*ppDevice = ref(GetDevice());
return D3D_OK;
}
IDirect3DDevice8* GetDevice() {
return reinterpret_cast<IDirect3DDevice8*>(m_parent);
}
D3D8Device* GetParent() {
return m_parent;
}
protected:
D3D8Device* m_parent;
};
}

220
src/d3d8/d3d8_format.h Normal file
View file

@ -0,0 +1,220 @@
#pragma once
#include "d3d8_include.h"
namespace dxvk {
constexpr bool isDXT(D3DFORMAT fmt) {
return fmt == D3DFMT_DXT1
|| fmt == D3DFMT_DXT2
|| fmt == D3DFMT_DXT3
|| fmt == D3DFMT_DXT4
|| fmt == D3DFMT_DXT5;
}
constexpr bool isDXT(d3d9::D3DFORMAT fmt) {
return isDXT(D3DFORMAT(fmt));
}
constexpr bool isUnsupportedSurfaceFormat(D3DFORMAT fmt) {
// mirror what dxvk doesn't support in terms of d3d9 surface formats
return fmt == D3DFMT_R8G8B8
|| fmt == D3DFMT_R3G3B2
|| fmt == D3DFMT_A8R3G3B2
|| fmt == D3DFMT_A8P8
|| fmt == D3DFMT_P8;
// not included in the d3d8 spec
//|| fmt == D3DFMT_CXV8U8;
}
constexpr bool isSupportedDepthStencilFormat(D3DFORMAT fmt) {
// native d3d8 doesn't support D3DFMT_D32, D3DFMT_D15S1 or D3DFMT_D24X4S4
return fmt == D3DFMT_D16_LOCKABLE
|| fmt == D3DFMT_D16
//|| fmt == D3DFMT_D32
//|| fmt == D3DFMT_D15S1
//|| fmt == D3DFMT_D24X4S4
|| fmt == D3DFMT_D24S8
|| fmt == D3DFMT_D24X8;
}
constexpr bool isDepthStencilFormat(D3DFORMAT fmt) {
return fmt == D3DFMT_D16_LOCKABLE
|| fmt == D3DFMT_D16
|| fmt == D3DFMT_D32
|| fmt == D3DFMT_D15S1
|| fmt == D3DFMT_D24X4S4
|| fmt == D3DFMT_D24S8
|| fmt == D3DFMT_D24X8;
}
// Get bytes per pixel (or 4x4 block for DXT)
constexpr UINT getFormatStride(D3DFORMAT fmt) {
switch (fmt) {
default:
case D3DFMT_UNKNOWN:
return 0;
case D3DFMT_R3G3B2:
case D3DFMT_A8:
case D3DFMT_P8:
case D3DFMT_L8:
case D3DFMT_A4L4:
return 1;
case D3DFMT_R5G6B5:
case D3DFMT_X1R5G5B5:
case D3DFMT_A1R5G5B5:
case D3DFMT_A4R4G4B4:
case D3DFMT_A8R3G3B2:
case D3DFMT_X4R4G4B4:
case D3DFMT_A8P8:
case D3DFMT_A8L8:
case D3DFMT_V8U8:
case D3DFMT_L6V5U5:
case D3DFMT_D16_LOCKABLE:
case D3DFMT_D15S1:
case D3DFMT_D16:
case D3DFMT_UYVY:
case D3DFMT_YUY2:
return 2;
case D3DFMT_R8G8B8:
return 3;
case D3DFMT_A8R8G8B8:
case D3DFMT_X8R8G8B8:
case D3DFMT_A2B10G10R10:
//case D3DFMT_A8B8G8R8:
//case D3DFMT_X8B8G8R8:
case D3DFMT_G16R16:
case D3DFMT_X8L8V8U8:
case D3DFMT_Q8W8V8U8:
case D3DFMT_V16U16:
case D3DFMT_W11V11U10:
case D3DFMT_A2W10V10U10:
case D3DFMT_D32:
case D3DFMT_D24S8:
case D3DFMT_D24X8:
case D3DFMT_D24X4S4:
return 4;
case D3DFMT_DXT1:
return 8;
case D3DFMT_DXT2:
case D3DFMT_DXT3:
case D3DFMT_DXT4:
case D3DFMT_DXT5:
return 16;
}
}
constexpr uint32_t GetVertexCount8(D3DPRIMITIVETYPE type, UINT count) {
switch (type) {
default:
case D3DPT_TRIANGLELIST: return count * 3;
case D3DPT_POINTLIST: return count;
case D3DPT_LINELIST: return count * 2;
case D3DPT_LINESTRIP: return count + 1;
case D3DPT_TRIANGLESTRIP: return count + 2;
case D3DPT_TRIANGLEFAN: return count + 2;
}
}
// Essentially the same logic as D3D9VertexDecl::SetFVF
constexpr UINT GetFVFStride(DWORD FVF) {
uint32_t texCount = 0;
uint32_t betas = 0;
uint8_t betaIdx = 0xFF;
UINT size = 0;
switch (FVF & D3DFVF_POSITION_MASK) {
case D3DFVF_XYZ:
case D3DFVF_XYZB1:
case D3DFVF_XYZB2:
case D3DFVF_XYZB3:
case D3DFVF_XYZB4:
case D3DFVF_XYZB5:
size += sizeof(float) * 3;
if ((FVF & D3DFVF_POSITION_MASK) == D3DFVF_XYZ)
break;
betas = (((FVF & D3DFVF_XYZB5) - D3DFVF_XYZB1) >> 1) + 1;
if (FVF & D3DFVF_LASTBETA_D3DCOLOR)
betaIdx = sizeof(D3DCOLOR);
else if (FVF & D3DFVF_LASTBETA_UBYTE4)
betaIdx = sizeof(BYTE) * 4;
else if ((FVF & D3DFVF_XYZB5) == D3DFVF_XYZB5)
betaIdx = sizeof(float);
if (betaIdx != 0xFF)
betas--;
if (betas > 0) {
if (betas <= 4)
size += sizeof(float) * betas;
}
if (betaIdx != 0xFF) {
size += betaIdx;
}
break;
case D3DFVF_XYZW:
case D3DFVF_XYZRHW:
size += sizeof(float) * 4;
break;
default:
break;
}
if (FVF & D3DFVF_NORMAL) {
size += sizeof(float) * 3;
}
if (FVF & D3DFVF_PSIZE) {
size += sizeof(float);
}
if (FVF & D3DFVF_DIFFUSE) {
size += sizeof(D3DCOLOR);
}
if (FVF & D3DFVF_SPECULAR) {
size += sizeof(D3DCOLOR);
}
texCount = (FVF & D3DFVF_TEXCOUNT_MASK) >> D3DFVF_TEXCOUNT_SHIFT;
texCount = std::min(texCount, 8u);
for (uint32_t i = 0; i < texCount; i++) {
switch ((FVF >> (16 + i * 2)) & 0x3) {
case D3DFVF_TEXTUREFORMAT1:
size += sizeof(float);
break;
case D3DFVF_TEXTUREFORMAT2:
size += sizeof(float) * 2;
break;
case D3DFVF_TEXTUREFORMAT3:
size += sizeof(float) * 3;
break;
case D3DFVF_TEXTUREFORMAT4:
size += sizeof(float) * 4;
break;
default:
break;
}
}
return size;
}
constexpr UINT getSurfaceSize(D3DFORMAT Format, UINT Width, UINT Height) {
if (isDXT(Format)) {
Width = ((Width + 3) >> 2);
Height = ((Height + 3) >> 2);
}
return Width * Height * getFormatStride(Format);
}
}

206
src/d3d8/d3d8_include.h Normal file
View file

@ -0,0 +1,206 @@
#pragma once
#ifndef _MSC_VER
#ifdef _WIN32_WINNT
#undef _WIN32_WINNT
#endif
#define _WIN32_WINNT 0x0A00
#endif
#include <stdint.h>
#include <d3d8.h>
// Declare __uuidof for D3D8 interfaces
#ifdef __CRT_UUID_DECL
__CRT_UUID_DECL(IDirect3D8, 0x1DD9E8DA,0x1C77,0x4D40,0xB0,0xCF,0x98,0xFE,0xFD,0xFF,0x95,0x12);
__CRT_UUID_DECL(IDirect3DDevice8, 0x7385E5DF,0x8FE8,0x41D5,0x86,0xB6,0xD7,0xB4,0x85,0x47,0xB6,0xCF);
__CRT_UUID_DECL(IDirect3DResource8, 0x1B36BB7B,0x09B7,0x410A,0xB4,0x45,0x7D,0x14,0x30,0xD7,0xB3,0x3F);
__CRT_UUID_DECL(IDirect3DVertexBuffer8, 0x8AEEEAC7,0x05F9,0x44D4,0xB5,0x91,0x00,0x0B,0x0D,0xF1,0xCB,0x95);
__CRT_UUID_DECL(IDirect3DVolume8, 0xBD7349F5,0x14F1,0x42E4,0x9C,0x79,0x97,0x23,0x80,0xDB,0x40,0xC0);
__CRT_UUID_DECL(IDirect3DSwapChain8, 0x928C088B,0x76B9,0x4C6B,0xA5,0x36,0xA5,0x90,0x85,0x38,0x76,0xCD);
__CRT_UUID_DECL(IDirect3DSurface8, 0xB96EEBCA,0xB326,0x4EA5,0x88,0x2F,0x2F,0xF5,0xBA,0xE0,0x21,0xDD);
__CRT_UUID_DECL(IDirect3DIndexBuffer8, 0x0E689C9A,0x053D,0x44A0,0x9D,0x92,0xDB,0x0E,0x3D,0x75,0x0F,0x86);
__CRT_UUID_DECL(IDirect3DBaseTexture8, 0xB4211CFA,0x51B9,0x4A9F,0xAB,0x78,0xDB,0x99,0xB2,0xBB,0x67,0x8E);
__CRT_UUID_DECL(IDirect3DTexture8, 0xE4CDD575,0x2866,0x4F01,0xB1,0x2E,0x7E,0xEC,0xE1,0xEC,0x93,0x58);
__CRT_UUID_DECL(IDirect3DCubeTexture8, 0x3EE5B968,0x2ACA,0x4C34,0x8B,0xB5,0x7E,0x0C,0x3D,0x19,0xB7,0x50);
__CRT_UUID_DECL(IDirect3DVolumeTexture8, 0x4B8AAAFA,0x140F,0x42BA,0x91,0x31,0x59,0x7E,0xAF,0xAA,0x2E,0xAD);
#elif defined(_MSC_VER)
interface DECLSPEC_UUID("1DD9E8DA-1C77-4D40-B0CF-98FEFDFF9512") IDirect3D8;
interface DECLSPEC_UUID("7385E5DF-8FE8-41D5-86B6-D7B48547B6CF") IDirect3DDevice8;
interface DECLSPEC_UUID("1B36BB7B-09B7-410A-B445-7D1430D7B33F") IDirect3DResource8;
interface DECLSPEC_UUID("8AEEEAC7-05F9-44D4-B591-000B0DF1CB95") IDirect3DVertexBuffer8;
interface DECLSPEC_UUID("BD7349F5-14F1-42E4-9C79-972380DB40C0") IDirect3DVolume8;
interface DECLSPEC_UUID("928C088B-76B9-4C6B-A536-A590853876CD") IDirect3DSwapChain8;
interface DECLSPEC_UUID("B96EEBCA-B326-4EA5-882F-2FF5BAE021DD") IDirect3DSurface8;
interface DECLSPEC_UUID("0E689C9A-053D-44A0-9D92-DB0E3D750F86") IDirect3DIndexBuffer8;
interface DECLSPEC_UUID("B4211CFA-51B9-4A9F-AB78-DB99B2BB678E") IDirect3DBaseTexture8;
interface DECLSPEC_UUID("E4CDD575-2866-4F01-B12E-7EECE1EC9358") IDirect3DTexture8;
interface DECLSPEC_UUID("3EE5B968-2ACA-4C34-8BB5-7E0C3D19B750") IDirect3DCubeTexture8;
interface DECLSPEC_UUID("4B8AAAFA-140F-42BA-9131-597EAFAA2EAD") IDirect3DVolumeTexture8;
#endif
// Undefine D3D8 macros
#undef DIRECT3D_VERSION
#undef D3D_SDK_VERSION
#undef D3DCS_ALL // parentheses added in D3D9
#undef D3DFVF_POSITION_MASK // changed from 0x00E to 0x400E in D3D9
#undef D3DFVF_RESERVED2 // reduced from 4 to 2 in DX9
#undef D3DSP_REGNUM_MASK // changed from 0x00000FFF to 0x000007FF in D3D9
#if defined(__MINGW32__) || defined(__GNUC__)
// Avoid redundant definitions (add D3D*_DEFINED macros here)
#define D3DRECT_DEFINED
#define D3DMATRIX_DEFINED
// Temporarily override __CRT_UUID_DECL to allow usage in d3d9 namespace
#pragma push_macro("__CRT_UUID_DECL")
#ifdef __CRT_UUID_DECL
#undef __CRT_UUID_DECL
#endif
#ifdef __MINGW32__
#define __CRT_UUID_DECL(type,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8) \
} \
extern "C++" template<> struct __mingw_uuidof_s<d3d9::type> { static constexpr IID __uuid_inst = {l,w1,w2, {b1,b2,b3,b4,b5,b6,b7,b8}}; }; \
extern "C++" template<> constexpr const GUID &__mingw_uuidof<d3d9::type>() { return __mingw_uuidof_s<d3d9::type>::__uuid_inst; } \
extern "C++" template<> constexpr const GUID &__mingw_uuidof<d3d9::type*>() { return __mingw_uuidof_s<d3d9::type>::__uuid_inst; } \
namespace d3d9 {
#elif defined(__GNUC__)
#define __CRT_UUID_DECL(type, a, b, c, d, e, f, g, h, i, j, k) \
} \
extern "C++" { template <> constexpr GUID __uuidof_helper<d3d9::type>() { return GUID{a,b,c,{d,e,f,g,h,i,j,k}}; } } \
extern "C++" { template <> constexpr GUID __uuidof_helper<d3d9::type*>() { return __uuidof_helper<d3d9::type>(); } } \
extern "C++" { template <> constexpr GUID __uuidof_helper<const d3d9::type*>() { return __uuidof_helper<d3d9::type>(); } } \
extern "C++" { template <> constexpr GUID __uuidof_helper<d3d9::type&>() { return __uuidof_helper<d3d9::type>(); } } \
extern "C++" { template <> constexpr GUID __uuidof_helper<const d3d9::type&>() { return __uuidof_helper<d3d9::type>(); } } \
namespace d3d9 {
#endif
#endif // defined(__MINGW32__) || defined(__GNUC__)
/**
* \brief Direct3D 9
*
* All D3D9 interfaces are included within
* a namespace, so as not to collide with
* D3D8 interfaces.
*/
namespace d3d9 {
#include <d3d9.h>
}
// Indicates d3d9:: namespace is in-use.
#define DXVK_D3D9_NAMESPACE
#if defined(__MINGW32__) || defined(__GNUC__)
#pragma pop_macro("__CRT_UUID_DECL")
#endif
//for some reason we need to specify __declspec(dllexport) for MinGW
#if defined(__WINE__) || !defined(_WIN32)
#define DLLEXPORT __attribute__((visibility("default")))
#else
#define DLLEXPORT
#endif
#include "../util/com/com_guid.h"
#include "../util/com/com_object.h"
#include "../util/com/com_pointer.h"
#include "../util/log/log.h"
#include "../util/log/log_debug.h"
#include "../util/sync/sync_recursive.h"
#include "../util/util_error.h"
#include "../util/util_likely.h"
#include "../util/util_string.h"
// Missed definitions in Wine/MinGW.
#ifndef D3DPRESENT_BACK_BUFFERS_MAX_EX
#define D3DPRESENT_BACK_BUFFERS_MAX_EX 30
#endif
#ifndef D3DSI_OPCODE_MASK
#define D3DSI_OPCODE_MASK 0x0000FFFF
#endif
#ifndef D3DSP_TEXTURETYPE_MASK
#define D3DSP_TEXTURETYPE_MASK 0x78000000
#endif
#ifndef D3DUSAGE_AUTOGENMIPMAP
#define D3DUSAGE_AUTOGENMIPMAP 0x00000400L
#endif
#ifndef D3DSP_DCL_USAGE_MASK
#define D3DSP_DCL_USAGE_MASK 0x0000000f
#endif
#ifndef D3DSP_OPCODESPECIFICCONTROL_MASK
#define D3DSP_OPCODESPECIFICCONTROL_MASK 0x00ff0000
#endif
#ifndef D3DSP_OPCODESPECIFICCONTROL_SHIFT
#define D3DSP_OPCODESPECIFICCONTROL_SHIFT 16
#endif
#ifndef D3DCURSOR_IMMEDIATE_UPDATE
#define D3DCURSOR_IMMEDIATE_UPDATE 0x00000001L
#endif
#ifndef D3DPRESENT_FORCEIMMEDIATE
#define D3DPRESENT_FORCEIMMEDIATE 0x00000100L
#endif
// From d3dtypes.h
#ifndef D3DDEVINFOID_TEXTUREMANAGER
#define D3DDEVINFOID_TEXTUREMANAGER 1
#endif
#ifndef D3DDEVINFOID_D3DTEXTUREMANAGER
#define D3DDEVINFOID_D3DTEXTUREMANAGER 2
#endif
#ifndef D3DDEVINFOID_TEXTURING
#define D3DDEVINFOID_TEXTURING 3
#endif
// From d3dhal.h
#ifndef D3DDEVINFOID_VCACHE
#define D3DDEVINFOID_VCACHE 4
#endif
// MinGW headers are broken. Who'dve guessed?
#ifndef _MSC_VER
// Missing from d3d8types.h
#ifndef D3DDEVINFOID_RESOURCEMANAGER
#define D3DDEVINFOID_RESOURCEMANAGER 5
#endif
#ifndef D3DDEVINFOID_VERTEXSTATS
#define D3DDEVINFOID_VERTEXSTATS 6 // Aka D3DDEVINFOID_D3DVERTEXSTATS
#endif
#ifndef D3DPRESENT_RATE_UNLIMITED
#define D3DPRESENT_RATE_UNLIMITED 0x7FFFFFFF
#endif
#else // _MSC_VER
// These are enum typedefs in the MinGW headers, but not defined by Microsoft
#define D3DVSDT_TYPE DWORD
#define D3DVSDE_REGISTER DWORD
#endif

159
src/d3d8/d3d8_interface.cpp Normal file
View file

@ -0,0 +1,159 @@
#include "d3d8_interface.h"
#include "d3d8_device.h"
#include "d3d8_texture.h"
#include <cstring>
namespace dxvk {
D3D8Interface::D3D8Interface() {
m_d3d9 = d3d9::Direct3DCreate9(D3D_SDK_VERSION);
// Get the bridge interface to D3D9.
if (FAILED(m_d3d9->QueryInterface(__uuidof(IDxvkD3D8InterfaceBridge), (void**)&m_bridge))) {
throw DxvkError("D3D8Interface: ERROR! Failed to get D3D9 Bridge. d3d9.dll might not be DXVK!");
}
m_bridge->SetD3D8CompatibilityMode(true);
m_d3d8Options = D3D8Options(*m_bridge->GetConfig());
m_adapterCount = m_d3d9->GetAdapterCount();
m_adapterModeCounts.resize(m_adapterCount);
m_adapterModes.reserve(m_adapterCount);
for (UINT adapter = 0; adapter < m_adapterCount; adapter++) {
m_adapterModes.emplace_back();
// cache adapter modes and mode counts for each d3d9 format
for (d3d9::D3DFORMAT fmt : ADAPTER_FORMATS) {
const UINT modeCount = m_d3d9->GetAdapterModeCount(adapter, fmt);
for (UINT mode = 0; mode < modeCount; mode++) {
m_adapterModes[adapter].emplace_back();
m_d3d9->EnumAdapterModes(adapter, fmt, mode, &(m_adapterModes[adapter].back()));
// can't use modeCount as it's only for one fmt
m_adapterModeCounts[adapter]++;
}
}
}
}
HRESULT STDMETHODCALLTYPE D3D8Interface::QueryInterface(REFIID riid, void** ppvObject) {
if (ppvObject == nullptr)
return E_POINTER;
*ppvObject = nullptr;
if (riid == __uuidof(IUnknown)
|| riid == __uuidof(IDirect3D8)) {
*ppvObject = ref(this);
return S_OK;
}
Logger::warn("D3D8Interface::QueryInterface: Unknown interface query");
Logger::warn(str::format(riid));
return E_NOINTERFACE;
}
HRESULT STDMETHODCALLTYPE D3D8Interface::GetAdapterIdentifier(
UINT Adapter,
DWORD Flags,
D3DADAPTER_IDENTIFIER8* pIdentifier) {
if (unlikely(pIdentifier == nullptr))
return D3DERR_INVALIDCALL;
// This flag now has the opposite effect.
// Either way, WHQLevel will be 1 with Direct3D9Ex
if (Flags & D3DENUM_NO_WHQL_LEVEL)
Flags &= ~D3DENUM_WHQL_LEVEL;
else
Flags |= D3DENUM_WHQL_LEVEL;
d3d9::D3DADAPTER_IDENTIFIER9 identifier9;
HRESULT res = m_d3d9->GetAdapterIdentifier(Adapter, Flags, &identifier9);
if (likely(SUCCEEDED(res))) {
strncpy(pIdentifier->Driver, identifier9.Driver, MAX_DEVICE_IDENTIFIER_STRING);
strncpy(pIdentifier->Description, identifier9.Description, MAX_DEVICE_IDENTIFIER_STRING);
pIdentifier->DriverVersion = identifier9.DriverVersion;
pIdentifier->VendorId = identifier9.VendorId;
pIdentifier->DeviceId = identifier9.DeviceId;
pIdentifier->SubSysId = identifier9.SubSysId;
pIdentifier->Revision = identifier9.Revision;
pIdentifier->DeviceIdentifier = identifier9.DeviceIdentifier;
pIdentifier->WHQLLevel = identifier9.WHQLLevel;
}
return res;
}
HRESULT __stdcall D3D8Interface::EnumAdapterModes(
UINT Adapter,
UINT Mode,
D3DDISPLAYMODE* pMode) {
if (Adapter >= m_adapterCount || Mode >= m_adapterModeCounts[Adapter] || pMode == nullptr) {
return D3DERR_INVALIDCALL;
}
pMode->Width = m_adapterModes[Adapter][Mode].Width;
pMode->Height = m_adapterModes[Adapter][Mode].Height;
pMode->RefreshRate = m_adapterModes[Adapter][Mode].RefreshRate;
pMode->Format = D3DFORMAT(m_adapterModes[Adapter][Mode].Format);
return D3D_OK;
}
HRESULT __stdcall D3D8Interface::CreateDevice(
UINT Adapter,
D3DDEVTYPE DeviceType,
HWND hFocusWindow,
DWORD BehaviorFlags,
D3DPRESENT_PARAMETERS* pPresentationParameters,
IDirect3DDevice8** ppReturnedDeviceInterface) {
InitReturnPtr(ppReturnedDeviceInterface);
if (unlikely(pPresentationParameters == nullptr ||
ppReturnedDeviceInterface == nullptr))
return D3DERR_INVALIDCALL;
// D3DSWAPEFFECT_COPY can not be used with more than one back buffer.
// This is also technically true for D3DSWAPEFFECT_COPY_VSYNC, however
// RC Cars depends on it not being rejected.
if (unlikely(pPresentationParameters->SwapEffect == D3DSWAPEFFECT_COPY
&& pPresentationParameters->BackBufferCount > 1))
return D3DERR_INVALIDCALL;
// In D3D8 nothing except D3DPRESENT_INTERVAL_DEFAULT can be used
// as a flag for windowed presentation.
if (unlikely(pPresentationParameters->Windowed
&& pPresentationParameters->FullScreen_PresentationInterval != D3DPRESENT_INTERVAL_DEFAULT))
return D3DERR_INVALIDCALL;
Com<d3d9::IDirect3DDevice9> pDevice9 = nullptr;
d3d9::D3DPRESENT_PARAMETERS params = ConvertPresentParameters9(pPresentationParameters);
HRESULT res = m_d3d9->CreateDevice(
Adapter,
(d3d9::D3DDEVTYPE)DeviceType,
hFocusWindow,
BehaviorFlags,
&params,
&pDevice9
);
if (likely(SUCCEEDED(res)))
*ppReturnedDeviceInterface = ref(new D3D8Device(
this, std::move(pDevice9),
DeviceType, hFocusWindow, BehaviorFlags,
pPresentationParameters
));
return res;
}
}

172
src/d3d8/d3d8_interface.h Normal file
View file

@ -0,0 +1,172 @@
#pragma once
#include "d3d8_include.h"
#include "d3d8_d3d9_util.h"
#include "d3d8_options.h"
#include "d3d8_format.h"
#include "../d3d9/d3d9_bridge.h"
namespace dxvk {
/**
* \brief D3D8 interface implementation
*
* Implements the IDirect3DDevice8 interfaces
* which provides the way to get adapters and create other objects such as \ref IDirect3DDevice8.
* similar to \ref DxgiFactory but for D3D8.
*/
class D3D8Interface final : public ComObjectClamp<IDirect3D8> {
static constexpr d3d9::D3DFORMAT ADAPTER_FORMATS[] = {
d3d9::D3DFMT_A1R5G5B5,
//d3d9::D3DFMT_A2R10G10B10, (not in D3D8)
d3d9::D3DFMT_A8R8G8B8,
d3d9::D3DFMT_R5G6B5,
d3d9::D3DFMT_X1R5G5B5,
d3d9::D3DFMT_X8R8G8B8
};
public:
D3D8Interface();
HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void** ppvObject);
HRESULT STDMETHODCALLTYPE RegisterSoftwareDevice(void* pInitializeFunction) {
return m_d3d9->RegisterSoftwareDevice(pInitializeFunction);
}
UINT STDMETHODCALLTYPE GetAdapterCount() {
return m_d3d9->GetAdapterCount();
}
HRESULT STDMETHODCALLTYPE GetAdapterIdentifier(
UINT Adapter,
DWORD Flags,
D3DADAPTER_IDENTIFIER8* pIdentifier);
UINT STDMETHODCALLTYPE GetAdapterModeCount(UINT Adapter) {
return m_adapterModeCounts[Adapter];
}
HRESULT STDMETHODCALLTYPE EnumAdapterModes(
UINT Adapter,
UINT Mode,
D3DDISPLAYMODE* pMode);
HRESULT STDMETHODCALLTYPE GetAdapterDisplayMode(UINT Adapter, D3DDISPLAYMODE* pMode) {
return m_d3d9->GetAdapterDisplayMode(Adapter, (d3d9::D3DDISPLAYMODE*)pMode);
}
HRESULT STDMETHODCALLTYPE CheckDeviceType(
UINT Adapter,
D3DDEVTYPE DevType,
D3DFORMAT AdapterFormat,
D3DFORMAT BackBufferFormat,
BOOL bWindowed) {
// Ignore the bWindowed parameter when querying D3D9. D3D8 does
// identical validations between windowed and fullscreen modes, adhering
// to the stricter fullscreen adapter and back buffer format validations.
return m_d3d9->CheckDeviceType(
Adapter,
(d3d9::D3DDEVTYPE)DevType,
(d3d9::D3DFORMAT)AdapterFormat,
(d3d9::D3DFORMAT)BackBufferFormat,
FALSE
);
}
HRESULT STDMETHODCALLTYPE CheckDeviceFormat(
UINT Adapter,
D3DDEVTYPE DeviceType,
D3DFORMAT AdapterFormat,
DWORD Usage,
D3DRESOURCETYPE RType,
D3DFORMAT CheckFormat) {
return m_d3d9->CheckDeviceFormat(
Adapter,
(d3d9::D3DDEVTYPE)DeviceType,
(d3d9::D3DFORMAT)AdapterFormat,
Usage,
(d3d9::D3DRESOURCETYPE)RType,
(d3d9::D3DFORMAT)CheckFormat
);
}
HRESULT STDMETHODCALLTYPE CheckDeviceMultiSampleType(
UINT Adapter,
D3DDEVTYPE DeviceType,
D3DFORMAT SurfaceFormat,
BOOL Windowed,
D3DMULTISAMPLE_TYPE MultiSampleType) {
DWORD* pQualityLevels = nullptr;
return m_d3d9->CheckDeviceMultiSampleType(
Adapter,
(d3d9::D3DDEVTYPE)DeviceType,
(d3d9::D3DFORMAT)SurfaceFormat,
Windowed,
(d3d9::D3DMULTISAMPLE_TYPE)MultiSampleType,
pQualityLevels
);
}
HRESULT STDMETHODCALLTYPE CheckDepthStencilMatch(
UINT Adapter,
D3DDEVTYPE DeviceType,
D3DFORMAT AdapterFormat,
D3DFORMAT RenderTargetFormat,
D3DFORMAT DepthStencilFormat) {
if (isSupportedDepthStencilFormat(DepthStencilFormat))
return m_d3d9->CheckDepthStencilMatch(
Adapter,
(d3d9::D3DDEVTYPE)DeviceType,
(d3d9::D3DFORMAT)AdapterFormat,
(d3d9::D3DFORMAT)RenderTargetFormat,
(d3d9::D3DFORMAT)DepthStencilFormat
);
return D3DERR_NOTAVAILABLE;
}
HRESULT STDMETHODCALLTYPE GetDeviceCaps(
UINT Adapter,
D3DDEVTYPE DeviceType,
D3DCAPS8* pCaps) {
if (unlikely(pCaps == nullptr))
return D3DERR_INVALIDCALL;
d3d9::D3DCAPS9 caps9;
HRESULT res = m_d3d9->GetDeviceCaps(Adapter, (d3d9::D3DDEVTYPE)DeviceType, &caps9);
if (likely(SUCCEEDED(res)))
ConvertCaps8(caps9, pCaps);
return res;
}
HMONITOR STDMETHODCALLTYPE GetAdapterMonitor(UINT Adapter) {
return m_d3d9->GetAdapterMonitor(Adapter);
}
HRESULT STDMETHODCALLTYPE CreateDevice(
UINT Adapter,
D3DDEVTYPE DeviceType,
HWND hFocusWindow,
DWORD BehaviorFlags,
D3DPRESENT_PARAMETERS* pPresentationParameters,
IDirect3DDevice8** ppReturnedDeviceInterface);
const D3D8Options& GetOptions() { return m_d3d8Options; }
private:
UINT m_adapterCount;
std::vector<UINT> m_adapterModeCounts;
std::vector<std::vector<d3d9::D3DDISPLAYMODE>> m_adapterModes;
Com<d3d9::IDirect3D9> m_d3d9;
Com<IDxvkD3D8InterfaceBridge> m_bridge;
D3D8Options m_d3d8Options;
};
}

124
src/d3d8/d3d8_main.cpp Normal file
View file

@ -0,0 +1,124 @@
#include "d3d8_interface.h"
namespace dxvk {
Logger Logger::s_instance("d3d8.log");
HRESULT CreateD3D8(IDirect3D8** ppDirect3D8) {
if (!ppDirect3D8)
return D3DERR_INVALIDCALL;
*ppDirect3D8 = ref(new D3D8Interface());
return D3D_OK;
}
}
extern "C" {
DLLEXPORT HRESULT __stdcall ValidatePixelShader(
const DWORD* pPixelShader,
const D3DCAPS8* pCaps,
BOOL ErrorReturn,
char** pErrorString) {
HRESULT res = S_OK;
std::string errorMessage = "";
// ValidatePixelShader returns immediately in case of a NULL pPixelShader
if (unlikely(pPixelShader == nullptr)) {
dxvk::Logger::warn("D3D8: ValidatePixelShader: Null pPixelShader");
return E_FAIL;
} else {
const uint32_t majorVersion = D3DSHADER_VERSION_MAJOR(pPixelShader[0]);
const uint32_t minorVersion = D3DSHADER_VERSION_MINOR(pPixelShader[0]);
if (unlikely(majorVersion != 1 || minorVersion > 4)) {
errorMessage = dxvk::str::format("D3D8: ValidatePixelShader: Unsupported PS version ",
majorVersion, ".", minorVersion);
res = E_FAIL;
} else if (unlikely(pCaps && pPixelShader[0] > pCaps->PixelShaderVersion)) {
errorMessage = dxvk::str::format("D3D8: ValidatePixelShader: Caps: Unsupported PS version ",
majorVersion, ".", minorVersion);
res = E_FAIL;
}
}
if (unlikely(res != S_OK)) {
dxvk::Logger::warn(errorMessage);
if (!ErrorReturn)
errorMessage = "";
}
#ifdef _WIN32
if (pErrorString != nullptr) {
const size_t errorMessageSize = errorMessage.size() + 1;
// Wine tests call HeapFree() on the returned error string,
// so the expectation is for it to be allocated on the heap.
*pErrorString = (char*) HeapAlloc(GetProcessHeap(), 0, errorMessageSize);
if (*pErrorString)
memcpy(*pErrorString, errorMessage.c_str(), errorMessageSize);
}
#endif
return res;
}
DLLEXPORT HRESULT __stdcall ValidateVertexShader(
const DWORD* pVertexShader,
const DWORD* pVertexDecl,
const D3DCAPS8* pCaps,
BOOL ErrorReturn,
char** pErrorString) {
HRESULT res = S_OK;
std::string errorMessage = "";
if (unlikely(pVertexShader == nullptr)) {
errorMessage = "D3D8: ValidateVertexShader: Null pVertexShader";
res = E_FAIL;
} else {
const uint32_t majorVersion = D3DSHADER_VERSION_MAJOR(pVertexShader[0]);
const uint32_t minorVersion = D3DSHADER_VERSION_MINOR(pVertexShader[0]);
if (unlikely(majorVersion != 1 || minorVersion > 1)) {
errorMessage = dxvk::str::format("D3D8: ValidateVertexShader: Unsupported VS version ",
majorVersion, ".", minorVersion);
res = E_FAIL;
} else if (unlikely(pCaps && pVertexShader[0] > pCaps->VertexShaderVersion)) {
errorMessage = dxvk::str::format("D3D8: ValidateVertexShader: Caps: Unsupported VS version ",
majorVersion, ".", minorVersion);
res = E_FAIL;
}
}
if (unlikely(res != S_OK)) {
dxvk::Logger::warn(errorMessage);
if (!ErrorReturn)
errorMessage = "";
}
#ifdef _WIN32
if (pErrorString != nullptr) {
const size_t errorMessageSize = errorMessage.size() + 1;
// Wine tests call HeapFree() on the returned error string,
// so the expectation is for it to be allocated on the heap.
*pErrorString = (char*) HeapAlloc(GetProcessHeap(), 0, errorMessageSize);
if (*pErrorString)
memcpy(*pErrorString, errorMessage.c_str(), errorMessageSize);
}
#endif
return res;
}
DLLEXPORT void __stdcall DebugSetMute() {}
DLLEXPORT IDirect3D8* __stdcall Direct3DCreate8(UINT nSDKVersion) {
IDirect3D8* pDirect3D = nullptr;
dxvk::CreateD3D8(&pDirect3D);
return pDirect3D;
}
}

View file

@ -0,0 +1,9 @@
#include "d3d8_device.h"
namespace dxvk {
D3D8Multithread::D3D8Multithread(
BOOL Protected)
: m_protected( Protected ) { }
}

View file

@ -0,0 +1,77 @@
#pragma once
#include "d3d8_include.h"
namespace dxvk {
/**
* \brief Device lock
*
* Lightweight RAII wrapper that implements
* a subset of the functionality provided by
* \c std::unique_lock, with the goal of being
* cheaper to construct and destroy.
*/
class D3D8DeviceLock {
public:
D3D8DeviceLock()
: m_mutex(nullptr) { }
D3D8DeviceLock(sync::RecursiveSpinlock& mutex)
: m_mutex(&mutex) {
mutex.lock();
}
D3D8DeviceLock(D3D8DeviceLock&& other)
: m_mutex(other.m_mutex) {
other.m_mutex = nullptr;
}
D3D8DeviceLock& operator = (D3D8DeviceLock&& other) {
if (m_mutex)
m_mutex->unlock();
m_mutex = other.m_mutex;
other.m_mutex = nullptr;
return *this;
}
~D3D8DeviceLock() {
if (m_mutex != nullptr)
m_mutex->unlock();
}
private:
sync::RecursiveSpinlock* m_mutex;
};
/**
* \brief D3D8 context lock
*/
class D3D8Multithread {
public:
D3D8Multithread(
BOOL Protected);
D3D8DeviceLock AcquireLock() {
return m_protected
? D3D8DeviceLock(m_mutex)
: D3D8DeviceLock();
}
private:
BOOL m_protected;
sync::RecursiveSpinlock m_mutex;
};
}

57
src/d3d8/d3d8_options.cpp Normal file
View file

@ -0,0 +1,57 @@
#include "d3d8_options.h"
#include "../d3d9/d3d9_bridge.h"
#include "../util/config/config.h"
#include "../util/util_string.h"
#include <charconv>
namespace dxvk {
static inline uint32_t parseDword(std::string_view str) {
uint32_t value = std::numeric_limits<uint32_t>::max();
std::from_chars(str.data(), str.data() + str.size(), value);
return value;
}
void D3D8Options::parseVsDecl(const std::string& decl) {
if (decl.empty())
return;
if (decl.find_first_of("0123456789") == std::string::npos) {
Logger::warn(str::format("D3D8: Invalid forceVsDecl value: ", decl));
Logger::warn("D3D8: Expected numbers.");
return;
}
if (decl.find_first_of(":,;") == std::string::npos) {
Logger::warn(str::format("D3D8: Invalid forceVsDecl value: ", decl));
Logger::warn("D3D8: Expected a comma-separated list of colon-separated number pairs.");
return;
}
std::vector<std::string_view> decls = str::split(decl, ":,;");
if (decls.size() % 2 != 0) {
Logger::warn(str::format("D3D8: Invalid forceVsDecl value: ", decl));
Logger::warn("D3D8: Expected an even number of numbers.");
return;
}
for (size_t i = 0; i < decls.size(); i += 2) {
uint32_t reg = parseDword(decls[i]);
uint32_t type = parseDword(decls[i+1]);
if (reg > D3DVSDE_NORMAL2) {
Logger::warn(str::format("D3D8: Invalid forceVsDecl register number: ", decls[i]));
return;
}
if (type > D3DVSDT_SHORT4) {
Logger::warn(str::format("D3D8: Invalid forceVsDecl type: ", decls[i+1]));
return;
}
forceVsDecl.emplace_back(D3DVSDE_REGISTER(reg), D3DVSDT_TYPE(type));
}
}
}

65
src/d3d8/d3d8_options.h Normal file
View file

@ -0,0 +1,65 @@
#pragma once
#include "d3d8_include.h"
#include "../d3d9/d3d9_bridge.h"
#include "../util/config/config.h"
namespace dxvk {
struct D3D8Options {
/// Some games rely on undefined behavior by using undeclared vertex shader inputs.
/// The simplest way to fix them is to simply modify their vertex shader decl.
///
/// This option takes a comma-separated list of colon-separated number pairs, where
/// the first number is a D3DVSDE_REGISTER value, the second is a D3DVSDT_TYPE value.
/// e.g. "0:2,3:2,7:1" for float3 position : v0, float3 normal : v3, float2 uv : v7
std::vector<std::pair<D3DVSDE_REGISTER, D3DVSDT_TYPE>> forceVsDecl;
/// Specialized drawcall batcher, typically for games that draw a lot of similar
/// geometry in separate drawcalls (sometimes even one triangle at a time).
///
/// May hurt performance outside of specifc games that benefit from it.
bool batching = false;
/// The Lord of the Rings: The Fellowship of the Ring tries to create a P8 texture
/// in D3DPOOL_MANAGED on Nvidia and Intel, which fails, but has a separate code
/// path for ATI/AMD that creates it in D3DPOOL_SCRATCH instead, which works.
///
/// The internal logic determining this path doesn't seem to be d3d-related, but
/// the game works universally if we mimic its own ATI/AMD workaround during P8
/// texture creation.
///
/// Early Nvidia GPUs, such as the GeForce 4 generation cards, included and exposed
/// P8 texture support. However, it was no longer advertised with cards in the FX series
/// and above. Most likely ATI/AMD drivers never supported P8 in the first place.
bool placeP8InScratch = false;
/// Rayman 3 relies on D3DLOCK_DISCARD being ignored for everything except D3DUSAGE_DYNAMIC +
/// D3DUSAGE_WRITEONLY buffers, however this approach incurs a performance penalty.
///
/// Some titles might abuse this early D3D8 quirk, however at some point in its history
/// it was brought in line with standard D3D9 behavior.
bool forceLegacyDiscard = false;
/// Splinter Cell expects shadow map texture coordinates to be perspective divided
/// even though D3DTTFF_PROJECTED is never set for any texture coordinates. This flag
/// forces that flag for the necessary stages when a depth texture is bound to slot 0
bool shadowPerspectiveDivide = false;
D3D8Options() {}
D3D8Options(const Config& config) {
auto forceVsDeclStr = config.getOption<std::string>("d3d8.forceVsDecl", "");
batching = config.getOption<bool> ("d3d8.batching", batching);
placeP8InScratch = config.getOption<bool> ("d3d8.placeP8InScratch", placeP8InScratch);
forceLegacyDiscard = config.getOption<bool> ("d3d8.forceLegacyDiscard", forceLegacyDiscard);
shadowPerspectiveDivide = config.getOption<bool> ("d3d8.shadowPerspectiveDivide", shadowPerspectiveDivide);
parseVsDecl(forceVsDeclStr);
}
void parseVsDecl(const std::string& decl);
};
}

117
src/d3d8/d3d8_resource.h Normal file
View file

@ -0,0 +1,117 @@
#pragma once
/** Implements IDirect3DResource8
*
* - SetPrivateData, GetPrivateData, FreePrivateData
* - SetPriority, GetPriority
*
* - Subclasses provide: PreLoad, GetType
*/
#include "d3d8_device_child.h"
#include "../util/com/com_private_data.h"
namespace dxvk {
template <typename D3D9, typename D3D8>
class D3D8Resource : public D3D8DeviceChild<D3D9, D3D8> {
public:
D3D8Resource(D3D8Device* pDevice, D3DPOOL Pool, Com<D3D9>&& Object)
: D3D8DeviceChild<D3D9, D3D8>(pDevice, std::move(Object))
, m_pool ( Pool )
, m_priority ( 0 ) { }
HRESULT STDMETHODCALLTYPE SetPrivateData(
REFGUID refguid,
const void* pData,
DWORD SizeOfData,
DWORD Flags) final {
HRESULT hr;
if (Flags & D3DSPD_IUNKNOWN) {
if(unlikely(SizeOfData != sizeof(IUnknown*)))
return D3DERR_INVALIDCALL;
IUnknown* unknown =
const_cast<IUnknown*>(
reinterpret_cast<const IUnknown*>(pData));
hr = m_privateData.setInterface(
refguid, unknown);
}
else
hr = m_privateData.setData(
refguid, SizeOfData, pData);
if (unlikely(FAILED(hr)))
return D3DERR_INVALIDCALL;
return D3D_OK;
}
HRESULT STDMETHODCALLTYPE GetPrivateData(
REFGUID refguid,
void* pData,
DWORD* pSizeOfData) final {
if (unlikely(pData == nullptr && pSizeOfData == nullptr))
return D3DERR_NOTFOUND;
HRESULT hr = m_privateData.getData(
refguid, reinterpret_cast<UINT*>(pSizeOfData), pData);
if (unlikely(FAILED(hr))) {
if(hr == DXGI_ERROR_MORE_DATA)
return D3DERR_MOREDATA;
else if (hr == DXGI_ERROR_NOT_FOUND)
return D3DERR_NOTFOUND;
else
return D3DERR_INVALIDCALL;
}
return D3D_OK;
}
HRESULT STDMETHODCALLTYPE FreePrivateData(REFGUID refguid) final {
HRESULT hr = m_privateData.setData(refguid, 0, nullptr);
if (unlikely(FAILED(hr)))
return D3DERR_INVALIDCALL;
return D3D_OK;
}
DWORD STDMETHODCALLTYPE SetPriority(DWORD PriorityNew) {
// Priority can only be set for D3DPOOL_MANAGED resources
if (likely(m_pool == D3DPOOL_MANAGED)) {
DWORD oldPriority = m_priority;
m_priority = PriorityNew;
return oldPriority;
}
return m_priority;
}
DWORD STDMETHODCALLTYPE GetPriority() {
return m_priority;
}
virtual IUnknown* GetInterface(REFIID riid) override try {
return D3D8DeviceChild<D3D9, D3D8>::GetInterface(riid);
} catch (HRESULT err) {
if (riid == __uuidof(IDirect3DResource8))
return this;
throw err;
}
protected:
const D3DPOOL m_pool;
DWORD m_priority;
private:
ComPrivateData m_privateData;
};
}

338
src/d3d8/d3d8_shader.cpp Normal file
View file

@ -0,0 +1,338 @@
#include "d3d8_shader.h"
#define VSD_SHIFT_MASK(token, field) ((token & field ## MASK) >> field ## SHIFT)
#define VSD_ENCODE(token, field) ((token << field ## _SHIFT) & field ## _MASK)
// Magic number from D3DVSD_SKIP(...)
#define VSD_SKIP_FLAG 0x10000000
// This bit is set on all parameter (non-instruction) tokens.
#define VS_BIT_PARAM 0x80000000
namespace dxvk {
static constexpr int D3D8_NUM_VERTEX_INPUT_REGISTERS = 17;
/**
* Standard mapping of vertex input registers v0-v16 to D3D9 usages and usage indices
* (See D3DVSDE_REGISTER values in d3d8types.h or DirectX 8 docs for vertex shader input registers vN)
*
* \cite https://learn.microsoft.com/en-us/windows/win32/direct3d9/mapping-between-a-directx-9-declaration-and-directx-8
*/
static constexpr BYTE D3D8_VERTEX_INPUT_REGISTERS[D3D8_NUM_VERTEX_INPUT_REGISTERS][2] = {
{d3d9::D3DDECLUSAGE_POSITION, 0}, // dcl_position v0
{d3d9::D3DDECLUSAGE_BLENDWEIGHT, 0}, // dcl_blendweight v1
{d3d9::D3DDECLUSAGE_BLENDINDICES, 0}, // dcl_blendindices v2
{d3d9::D3DDECLUSAGE_NORMAL, 0}, // dcl_normal v3
{d3d9::D3DDECLUSAGE_PSIZE, 0}, // dcl_psize v4
{d3d9::D3DDECLUSAGE_COLOR, 0}, // dcl_color v5 ; diffuse
{d3d9::D3DDECLUSAGE_COLOR, 1}, // dcl_color1 v6 ; specular
{d3d9::D3DDECLUSAGE_TEXCOORD, 0}, // dcl_texcoord0 v7
{d3d9::D3DDECLUSAGE_TEXCOORD, 1}, // dcl_texcoord1 v8
{d3d9::D3DDECLUSAGE_TEXCOORD, 2}, // dcl_texcoord2 v9
{d3d9::D3DDECLUSAGE_TEXCOORD, 3}, // dcl_texcoord3 v10
{d3d9::D3DDECLUSAGE_TEXCOORD, 4}, // dcl_texcoord4 v11
{d3d9::D3DDECLUSAGE_TEXCOORD, 5}, // dcl_texcoord5 v12
{d3d9::D3DDECLUSAGE_TEXCOORD, 6}, // dcl_texcoord6 v13
{d3d9::D3DDECLUSAGE_TEXCOORD, 7}, // dcl_texcoord7 v14
{d3d9::D3DDECLUSAGE_POSITION, 1}, // dcl_position1 v15 ; position 2
{d3d9::D3DDECLUSAGE_NORMAL, 1}, // dcl_normal1 v16 ; normal 2
};
/** Width in bytes of each d3d9::D3DDECLTYPE or d3d8 D3DVSDT_TYPE */
static constexpr BYTE D3D9_DECL_TYPE_SIZES[d3d9::MAXD3DDECLTYPE + 1] = {
4, // FLOAT1
8, // FLOAT2
12, // FLOAT3
16, // FLOAT4
4, // D3DCOLOR
4, // UBYTE4
4, // SHORT2
8, // SHORT4
// The following are for vs2.0+ //
4, // UBYTE4N
4, // SHORT2N
8, // SHORT4N
4, // USHORT2N
8, // USHORT4N
6, // UDEC3
6, // DEC3N
8, // FLOAT16_2
16, // FLOAT16_4
0 // UNUSED
};
/**
* Encodes a \ref DxsoShaderInstruction
*
* \param [in] opcode DxsoOpcode
* \cite https://learn.microsoft.com/en-us/windows-hardware/drivers/display/instruction-token
*/
constexpr DWORD encodeInstruction(d3d9::D3DSHADER_INSTRUCTION_OPCODE_TYPE opcode) {
DWORD token = 0;
token |= opcode & 0xFFFF; // bits 0:15
return token;
}
/**
* Encodes a \ref DxsoRegister
*
* \param [in] regType DxsoRegisterType
* \cite https://learn.microsoft.com/en-us/windows-hardware/drivers/display/destination-parameter-token
*/
constexpr DWORD encodeDestRegister(d3d9::D3DSHADER_PARAM_REGISTER_TYPE type, UINT reg) {
DWORD token = 0;
token |= reg & 0x7FF; // bits 0:10 num
token |= ((type & 0x07) << 28); // bits 28:30 type[0:2]
token |= ((type & 0x18) >> 3) << 11; // bits 11:12 type[3:4]
// UINT addrMode : 1; // bit 13 hasRelative
token |= 0b1111 << 16; // bits 16:19 DxsoRegMask
// UINT resultModifier : 3; // bits 20:23
// UINT resultShift : 3; // bits 24:27
token |= 1 << 31; // bit 31 always 1
return token;
}
/**
* Encodes a \ref DxsoDeclaration
*
* \cite https://learn.microsoft.com/en-us/windows-hardware/drivers/display/dcl-instruction
*/
constexpr DWORD encodeDeclaration(d3d9::D3DDECLUSAGE usage, DWORD index) {
DWORD token = 0;
token |= VSD_ENCODE(usage, D3DSP_DCL_USAGE); // bits 0:4 DxsoUsage (TODO: missing MSB)
token |= VSD_ENCODE(index, D3DSP_DCL_USAGEINDEX); // bits 16:19 usageIndex
token |= 1 << 31; // bit 31 always 1
return token;
}
/**
* Converts a D3D8 vertex shader + declaration
* to a D3D9 vertex shader + declaration.
*/
D3D9VertexShaderCode TranslateVertexShader8(
const DWORD* pDeclaration,
const DWORD* pFunction,
const D3D8Options& options) {
using d3d9::D3DDECLTYPE;
using d3d9::D3DDECLTYPE_UNUSED;
D3D9VertexShaderCode result;
std::vector<DWORD>& tokens = result.function;
std::vector<DWORD> defs; // Constant definitions
// shaderInputRegisters:
// set bit N to enable input register vN
DWORD shaderInputRegisters = 0;
d3d9::D3DVERTEXELEMENT9* vertexElements = result.declaration;
unsigned int elementIdx = 0;
// These are used for pDeclaration and pFunction
int i = 0;
DWORD token;
std::stringstream dbg;
dbg << "D3D8: Vertex Declaration Tokens:\n\t";
WORD currentStream = 0;
WORD currentOffset = 0;
auto addVertexElement = [&] (D3DVSDE_REGISTER reg, D3DVSDT_TYPE type) {
vertexElements[elementIdx].Stream = currentStream;
vertexElements[elementIdx].Offset = currentOffset;
vertexElements[elementIdx].Method = d3d9::D3DDECLMETHOD_DEFAULT;
vertexElements[elementIdx].Type = D3DDECLTYPE(type); // (D3DVSDT_TYPE values map directly to D3DDECLTYPE)
vertexElements[elementIdx].Usage = D3D8_VERTEX_INPUT_REGISTERS[reg][0];
vertexElements[elementIdx].UsageIndex = D3D8_VERTEX_INPUT_REGISTERS[reg][1];
// Increase stream offset
currentOffset += D3D9_DECL_TYPE_SIZES[type];
// Enable register vn
shaderInputRegisters |= 1 << reg;
// Finished with this element
elementIdx++;
};
// Remap d3d8 decl tokens to d3d9 vertex elements,
// and enable bits on shaderInputRegisters for each.
if (options.forceVsDecl.size() == 0) do {
token = pDeclaration[i++];
D3DVSD_TOKENTYPE tokenType = D3DVSD_TOKENTYPE(VSD_SHIFT_MASK(token, D3DVSD_TOKENTYPE));
switch (tokenType) {
case D3DVSD_TOKEN_NOP:
dbg << "NOP";
break;
case D3DVSD_TOKEN_STREAM: {
dbg << "STREAM ";
// TODO: D3DVSD_STREAM_TESS
if (token & D3DVSD_STREAMTESSMASK) {
dbg << "TESS";
}
DWORD streamNum = VSD_SHIFT_MASK(token, D3DVSD_STREAMNUMBER);
currentStream = WORD(streamNum);
currentOffset = 0; // reset offset
dbg << ", num=" << streamNum;
break;
}
case D3DVSD_TOKEN_STREAMDATA: {
dbg << "STREAMDATA ";
// D3DVSD_SKIP
if (token & VSD_SKIP_FLAG) {
auto skipCount = VSD_SHIFT_MASK(token, D3DVSD_SKIPCOUNT);
dbg << "SKIP " << " count=" << skipCount;
currentOffset += WORD(skipCount) * sizeof(DWORD);
break;
}
// D3DVSD_REG
DWORD dataLoadType = VSD_SHIFT_MASK(token, D3DVSD_DATALOADTYPE);
if ( dataLoadType == 0 ) { // vertex
D3DVSDT_TYPE type = D3DVSDT_TYPE(VSD_SHIFT_MASK(token, D3DVSD_DATATYPE));
D3DVSDE_REGISTER reg = D3DVSDE_REGISTER(VSD_SHIFT_MASK(token, D3DVSD_VERTEXREG));
addVertexElement(reg, type);
dbg << "type=" << type << ", register=" << reg;
} else {
// TODO: When would this bit be 1?
dbg << "D3DVSD_DATALOADTYPE " << dataLoadType;
}
break;
}
case D3DVSD_TOKEN_TESSELLATOR:
dbg << "TESSELLATOR " << std::hex << token;
// TODO: D3DVSD_TOKEN_TESSELLATOR
break;
case D3DVSD_TOKEN_CONSTMEM: {
dbg << "CONSTMEM ";
DWORD count = VSD_SHIFT_MASK(token, D3DVSD_CONSTCOUNT);
DWORD regCount = count * 4;
DWORD addr = VSD_SHIFT_MASK(token, D3DVSD_CONSTADDRESS);
DWORD rs = VSD_SHIFT_MASK(token, D3DVSD_CONSTRS);
dbg << "count=" << count << ", addr=" << addr << ", rs=" << rs;
// Add a DEF instruction for each constant
for (DWORD j = 0; j < regCount; j += 4) {
defs.push_back(encodeInstruction(d3d9::D3DSIO_DEF));
defs.push_back(encodeDestRegister(d3d9::D3DSPR_CONST2, addr));
defs.push_back(pDeclaration[i+j+0]);
defs.push_back(pDeclaration[i+j+1]);
defs.push_back(pDeclaration[i+j+2]);
defs.push_back(pDeclaration[i+j+3]);
addr++;
}
i += regCount;
break;
}
case D3DVSD_TOKEN_EXT: {
dbg << "EXT " << std::hex << token << " ";
DWORD extInfo = VSD_SHIFT_MASK(token, D3DVSD_EXTINFO);
DWORD extCount = VSD_SHIFT_MASK(token, D3DVSD_EXTCOUNT);
dbg << "info=" << extInfo << ", count=" << extCount;
break;
}
case D3DVSD_TOKEN_END: {
vertexElements[elementIdx++] = D3DDECL_END();
dbg << "END";
break;
}
default:
dbg << "UNKNOWN TYPE";
break;
}
dbg << "\n\t";
//dbg << std::hex << token << " ";
} while (token != D3DVSD_END());
Logger::debug(dbg.str());
// If forceVsDecl is set, use that decl instead.
if (options.forceVsDecl.size() > 0) {
for (auto [reg, type] : options.forceVsDecl) {
addVertexElement(reg, type);
}
vertexElements[elementIdx++] = D3DDECL_END();
}
if (pFunction != nullptr) {
// Copy first token (version)
tokens.push_back(pFunction[0]);
DWORD vsMajor = D3DSHADER_VERSION_MAJOR(pFunction[0]);
DWORD vsMinor = D3DSHADER_VERSION_MINOR(pFunction[0]);
Logger::debug(str::format("VS version: ", vsMajor, ".", vsMinor));
// Insert dcl instructions
for (int vn = 0; vn < D3D8_NUM_VERTEX_INPUT_REGISTERS; vn++) {
// If bit N is set then we need to dcl register vN
if ((shaderInputRegisters & (1 << vn)) != 0) {
Logger::debug(str::format("\tShader Input Regsiter: v", vn));
DWORD usage = D3D8_VERTEX_INPUT_REGISTERS[vn][0];
DWORD index = D3D8_VERTEX_INPUT_REGISTERS[vn][1];
tokens.push_back(encodeInstruction(d3d9::D3DSIO_DCL)); // dcl opcode
tokens.push_back(encodeDeclaration(d3d9::D3DDECLUSAGE(usage), index)); // usage token
tokens.push_back(encodeDestRegister(d3d9::D3DSPR_INPUT, vn)); // dest register num
}
}
// Copy constant defs
for (DWORD def : defs) {
tokens.push_back(def);
}
// Copy shader tokens from input,
// skip first token (we already copied it)
i = 1;
do {
token = pFunction[i++];
DWORD opcode = token & D3DSI_OPCODE_MASK;
// Instructions
if ((token & VS_BIT_PARAM) == 0) {
// Swizzle fixup for opcodes that require explicit use of a replicate swizzle.
if (opcode == D3DSIO_RSQ || opcode == D3DSIO_RCP
|| opcode == D3DSIO_EXP || opcode == D3DSIO_LOG
|| opcode == D3DSIO_EXPP || opcode == D3DSIO_LOGP) {
tokens.push_back(token); // instr
tokens.push_back(token = pFunction[i++]); // dest
token = pFunction[i++]; // src0
// If no swizzling is done, then use the w-component.
// See d8vk#43 for more information as this may need to change in some cases.
if (((token & D3DVS_NOSWIZZLE) == D3DVS_NOSWIZZLE)) {
token &= ~D3DVS_SWIZZLE_MASK;
token |= (D3DVS_X_W | D3DVS_Y_W | D3DVS_Z_W | D3DVS_W_W);
}
}
}
tokens.push_back(token);
} while (token != D3DVS_END());
}
return result;
}
}

18
src/d3d8/d3d8_shader.h Normal file
View file

@ -0,0 +1,18 @@
#pragma once
#include "d3d8_include.h"
#include "d3d8_options.h"
namespace dxvk {
struct D3D9VertexShaderCode {
d3d9::D3DVERTEXELEMENT9 declaration[MAXD3DDECLLENGTH + 1];
std::vector<DWORD> function;
};
D3D9VertexShaderCode TranslateVertexShader8(
const DWORD* pDeclaration,
const DWORD* pFunction,
const D3D8Options& overrides);
}

View file

@ -0,0 +1,109 @@
#include "d3d8_device.h"
#include "d3d8_state_block.h"
namespace dxvk {
D3D8StateBlock::D3D8StateBlock(
D3D8Device* pDevice,
D3DSTATEBLOCKTYPE Type,
Com<d3d9::IDirect3DStateBlock9>&& pStateBlock)
: m_device(pDevice)
, m_stateBlock(std::move(pStateBlock))
, m_type(Type)
, m_isSWVP(pDevice->GetD3D9()->GetSoftwareVertexProcessing()) {
if (Type == D3DSBT_VERTEXSTATE || Type == D3DSBT_ALL) {
// Lights, D3DTSS_TEXCOORDINDEX and D3DTSS_TEXTURETRANSFORMFLAGS,
// vertex shader, VS constants, and various render states.
m_capture.vs = true;
}
if (Type == D3DSBT_PIXELSTATE || Type == D3DSBT_ALL) {
// Pixel shader, PS constants, and various RS/TSS states.
m_capture.ps = true;
}
if (Type == D3DSBT_ALL) {
m_capture.indices = true;
m_capture.swvp = true;
m_capture.textures.setAll();
m_capture.streams.setAll();
}
m_textures.fill(nullptr);
m_streams.fill(D3D8VBOP());
}
// Construct a state block without a D3D9 object
D3D8StateBlock::D3D8StateBlock(D3D8Device* pDevice)
: D3D8StateBlock(pDevice, D3DSTATEBLOCKTYPE(0), nullptr) {
}
// Attach a D3D9 object to a state block that doesn't have one yet
void D3D8StateBlock::SetD3D9(Com<d3d9::IDirect3DStateBlock9>&& pStateBlock) {
if (likely(m_stateBlock == nullptr)) {
m_stateBlock = std::move(pStateBlock);
} else {
Logger::err("D3D8StateBlock::SetD3D9: m_stateBlock has already been initialized");
}
}
HRESULT D3D8StateBlock::Capture() {
if (unlikely(m_stateBlock == nullptr))
return D3DERR_INVALIDCALL;
if (m_capture.vs) m_device->GetVertexShader(&m_vertexShader);
if (m_capture.ps) m_device->GetPixelShader(&m_pixelShader);
for (DWORD stage = 0; stage < m_textures.size(); stage++) {
if (m_capture.textures.get(stage))
m_textures[stage] = m_device->m_textures[stage].ptr();
}
for (DWORD stream = 0; stream < m_streams.size(); stream++) {
if (m_capture.streams.get(stream)) {
m_streams[stream].buffer = m_device->m_streams[stream].buffer.ptr();
m_streams[stream].stride = m_device->m_streams[stream].stride;
}
}
if (m_capture.indices) {
m_baseVertexIndex = m_device->m_baseVertexIndex;
m_indices = m_device->m_indices.ptr();
}
if (m_capture.swvp)
m_device->GetRenderState(D3DRS_SOFTWAREVERTEXPROCESSING, (DWORD*)&m_isSWVP);
return m_stateBlock->Capture();
}
HRESULT D3D8StateBlock::Apply() {
if (unlikely(m_stateBlock == nullptr))
return D3DERR_INVALIDCALL;
HRESULT res = m_stateBlock->Apply();
if (m_capture.vs) m_device->SetVertexShader(m_vertexShader);
if (m_capture.ps) m_device->SetPixelShader(m_pixelShader);
for (DWORD stage = 0; stage < m_textures.size(); stage++) {
if (m_capture.textures.get(stage))
m_device->SetTexture(stage, m_textures[stage]);
}
for (DWORD stream = 0; stream < m_streams.size(); stream++) {
if (m_capture.streams.get(stream))
m_device->SetStreamSource(stream, m_streams[stream].buffer, m_streams[stream].stride);
}
if (m_capture.indices)
m_device->SetIndices(m_indices, m_baseVertexIndex);
// This was a very easy footgun for D3D8 applications.
if (m_capture.swvp)
m_device->SetRenderState(D3DRS_SOFTWAREVERTEXPROCESSING, m_isSWVP);
return res;
}
}

120
src/d3d8/d3d8_state_block.h Normal file
View file

@ -0,0 +1,120 @@
#pragma once
#include "d3d8_caps.h"
#include "d3d8_include.h"
#include "d3d8_device.h"
#include "d3d8_device_child.h"
#include "../util/util_bit.h"
#include <array>
namespace dxvk {
struct D3D8StateCapture {
bool vs : 1;
bool ps : 1;
bool indices : 1;
bool swvp : 1;
bit::bitset<d8caps::MAX_TEXTURE_STAGES> textures;
bit::bitset<d8caps::MAX_STREAMS> streams;
D3D8StateCapture()
: vs(false)
, ps(false)
, indices(false)
, swvp(false) {
// Ensure all bits are initialized to false
textures.clearAll();
streams.clearAll();
}
};
// Wrapper class for D3D9 state blocks. Captures D3D8-specific state.
class D3D8StateBlock {
public:
D3D8StateBlock(
D3D8Device* pDevice,
D3DSTATEBLOCKTYPE Type,
Com<d3d9::IDirect3DStateBlock9>&& pStateBlock);
D3D8StateBlock(D3D8Device* pDevice);
void SetD3D9(Com<d3d9::IDirect3DStateBlock9>&& pStateBlock);
HRESULT Capture();
HRESULT Apply();
inline HRESULT SetVertexShader(DWORD Handle) {
m_vertexShader = Handle;
m_capture.vs = true;
return D3D_OK;
}
inline HRESULT SetPixelShader(DWORD Handle) {
m_pixelShader = Handle;
m_capture.ps = true;
return D3D_OK;
}
inline HRESULT SetTexture(DWORD Stage, IDirect3DBaseTexture8* pTexture) {
m_textures[Stage] = pTexture;
m_capture.textures.set(Stage, true);
return D3D_OK;
}
inline HRESULT SetStreamSource(UINT StreamNumber, IDirect3DVertexBuffer8* pStreamData, UINT Stride) {
m_streams[StreamNumber].buffer = pStreamData;
// The previous stride is preserved if pStreamData is NULL
if (likely(pStreamData != nullptr))
m_streams[StreamNumber].stride = Stride;
m_capture.streams.set(StreamNumber, true);
return D3D_OK;
}
inline HRESULT SetIndices(IDirect3DIndexBuffer8* pIndexData, UINT BaseVertexIndex) {
m_indices = pIndexData;
m_baseVertexIndex = BaseVertexIndex;
m_capture.indices = true;
return D3D_OK;
}
inline HRESULT SetSoftwareVertexProcessing(bool value) {
m_isSWVP = value;
m_capture.swvp = true;
return D3D_OK;
}
private:
D3D8Device* m_device;
Com<d3d9::IDirect3DStateBlock9> m_stateBlock;
D3DSTATEBLOCKTYPE m_type;
struct D3D8VBOP {
IDirect3DVertexBuffer8* buffer = nullptr;
UINT stride = 0;
};
// State Data //
D3D8StateCapture m_capture;
DWORD m_vertexShader = 0;
DWORD m_pixelShader = 0;
std::array<IDirect3DBaseTexture8*, d8caps::MAX_TEXTURE_STAGES> m_textures;
std::array<D3D8VBOP, d8caps::MAX_STREAMS> m_streams;
IDirect3DIndexBuffer8* m_indices = nullptr;
UINT m_baseVertexIndex = 0;
bool m_isSWVP; // D3DRS_SOFTWAREVERTEXPROCESSING
};
}

View file

@ -0,0 +1,60 @@
#pragma once
#include "d3d8_resource.h"
namespace dxvk {
// Base class for Surfaces and Volumes,
// which can be attached to Textures.
template <typename D3D9, typename D3D8>
class D3D8Subresource : public D3D8Resource<D3D9, D3D8> {
using Resource = D3D8Resource<D3D9, D3D8>;
public:
D3D8Subresource(
D3D8Device* pDevice,
const D3DPOOL Pool,
Com<D3D9>&& Object,
IDirect3DBaseTexture8* pBaseTexture)
: Resource(pDevice, Pool, std::move(Object)),
m_container(pBaseTexture) {
}
// Refing subresources implicitly refs the container texture,
ULONG STDMETHODCALLTYPE AddRef() final {
if (m_container != nullptr)
return m_container->AddRef();
return Resource::AddRef();
}
// and releasing them implicitly releases the texture.
ULONG STDMETHODCALLTYPE Release() final {
if (m_container != nullptr)
return m_container->Release();
return Resource::Release();
}
// Clients can grab the container if they want
HRESULT STDMETHODCALLTYPE GetContainer(REFIID riid, void** ppContainer) final {
if (m_container != nullptr)
return m_container->QueryInterface(riid, ppContainer);
return this->GetDevice()->QueryInterface(riid, ppContainer);
}
inline IDirect3DBaseTexture8* GetBaseTexture() {
return m_container;
}
protected:
IDirect3DBaseTexture8* m_container;
};
}

78
src/d3d8/d3d8_surface.cpp Normal file
View file

@ -0,0 +1,78 @@
#include "d3d8_surface.h"
#include "d3d8_device.h"
#include "d3d8_d3d9_util.h"
namespace dxvk {
D3D8Surface::D3D8Surface(
D3D8Device* pDevice,
const D3DPOOL Pool,
IDirect3DBaseTexture8* pTexture,
Com<d3d9::IDirect3DSurface9>&& pSurface)
: D3D8SurfaceBase (pDevice, Pool, std::move(pSurface), pTexture) {
}
// A surface does not need to be attached to a texture
D3D8Surface::D3D8Surface(
D3D8Device* pDevice,
const D3DPOOL Pool,
Com<d3d9::IDirect3DSurface9>&& pSurface)
: D3D8Surface (pDevice, Pool, nullptr, std::move(pSurface)) {
}
HRESULT STDMETHODCALLTYPE D3D8Surface::GetDesc(D3DSURFACE_DESC* pDesc) {
if (unlikely(pDesc == nullptr))
return D3DERR_INVALIDCALL;
d3d9::D3DSURFACE_DESC desc;
HRESULT res = GetD3D9()->GetDesc(&desc);
if (likely(SUCCEEDED(res)))
ConvertSurfaceDesc8(&desc, pDesc);
return res;
}
HRESULT STDMETHODCALLTYPE D3D8Surface::LockRect(
D3DLOCKED_RECT* pLockedRect,
CONST RECT* pRect,
DWORD Flags) {
return GetD3D9()->LockRect((d3d9::D3DLOCKED_RECT*)pLockedRect, pRect, Flags);
}
HRESULT STDMETHODCALLTYPE D3D8Surface::UnlockRect() {
return GetD3D9()->UnlockRect();
}
// TODO: Consider creating only one texture to
// encompass all surface levels of a texture.
Com<d3d9::IDirect3DSurface9> D3D8Surface::GetBlitImage() {
if (unlikely(m_blitImage == nullptr)) {
m_blitImage = CreateBlitImage();
}
return m_blitImage;
}
Com<d3d9::IDirect3DSurface9> D3D8Surface::CreateBlitImage() {
d3d9::D3DSURFACE_DESC desc;
GetD3D9()->GetDesc(&desc);
// NOTE: This adds a D3DPOOL_DEFAULT resource to the
// device, which counts as losable during device reset
Com<d3d9::IDirect3DSurface9> image = nullptr;
HRESULT res = GetParent()->GetD3D9()->CreateRenderTarget(
desc.Width, desc.Height, desc.Format,
d3d9::D3DMULTISAMPLE_NONE, 0,
FALSE,
&image,
NULL);
if (FAILED(res))
throw new DxvkError("D3D8: Failed to create blit image");
return image;
}
}

50
src/d3d8/d3d8_surface.h Normal file
View file

@ -0,0 +1,50 @@
#pragma once
#include "d3d8_include.h"
#include "d3d8_subresource.h"
namespace dxvk {
// Note: IDirect3DSurface8 does not actually inherit from IDirect3DResource8,
// however it does expose serveral of the methods typically found part of
// IDirect3DResource8, such as Set/Get/FreePrivateData, so model it as such.
using D3D8SurfaceBase = D3D8Subresource<d3d9::IDirect3DSurface9, IDirect3DSurface8>;
class D3D8Surface final : public D3D8SurfaceBase {
public:
D3D8Surface(
D3D8Device* pDevice,
const D3DPOOL Pool,
IDirect3DBaseTexture8* pTexture,
Com<d3d9::IDirect3DSurface9>&& pSurface);
D3D8Surface(
D3D8Device* pDevice,
const D3DPOOL Pool,
Com<d3d9::IDirect3DSurface9>&& pSurface);
HRESULT STDMETHODCALLTYPE GetDesc(D3DSURFACE_DESC* pDesc) final;
HRESULT STDMETHODCALLTYPE LockRect(
D3DLOCKED_RECT* pLockedRect,
CONST RECT* pRect,
DWORD Flags) final;
HRESULT STDMETHODCALLTYPE UnlockRect() final;
/**
* \brief Allocate or reuse an image of the same size
* as this texture for performing blit into system mem.
*/
Com<d3d9::IDirect3DSurface9> GetBlitImage();
private:
Com<d3d9::IDirect3DSurface9> CreateBlitImage();
Com<d3d9::IDirect3DSurface9> m_blitImage;
};
}

View file

@ -0,0 +1,41 @@
#include "d3d8_swapchain.h"
namespace dxvk {
D3D8SwapChain::D3D8SwapChain(
D3D8Device* pDevice,
D3DPRESENT_PARAMETERS* pPresentationParameters,
Com<d3d9::IDirect3DSwapChain9>&& pSwapChain)
: D3D8SwapChainBase(pDevice, std::move(pSwapChain)) {
m_backBuffers.resize(pPresentationParameters->BackBufferCount);
}
HRESULT STDMETHODCALLTYPE D3D8SwapChain::Present(const RECT *src, const RECT *dst, HWND hWnd, const RGNDATA *dirtyRegion) {
return GetD3D9()->Present(src, dst, hWnd, dirtyRegion, 0);
}
HRESULT STDMETHODCALLTYPE D3D8SwapChain::GetBackBuffer(
UINT BackBuffer,
D3DBACKBUFFER_TYPE Type,
IDirect3DSurface8** ppBackBuffer) {
if (unlikely(ppBackBuffer == nullptr))
return D3DERR_INVALIDCALL;
// Same logic as in D3D8Device::GetBackBuffer
if (BackBuffer >= m_backBuffers.size() || m_backBuffers[BackBuffer] == nullptr) {
Com<d3d9::IDirect3DSurface9> pSurface9;
HRESULT res = GetD3D9()->GetBackBuffer(BackBuffer, (d3d9::D3DBACKBUFFER_TYPE)Type, &pSurface9);
if (likely(SUCCEEDED(res))) {
m_backBuffers[BackBuffer] = new D3D8Surface(GetParent(), D3DPOOL_DEFAULT, std::move(pSurface9));
*ppBackBuffer = m_backBuffers[BackBuffer].ref();
}
return res;
}
*ppBackBuffer = m_backBuffers[BackBuffer].ref();
return D3D_OK;
}
}

31
src/d3d8/d3d8_swapchain.h Normal file
View file

@ -0,0 +1,31 @@
#pragma once
#include "d3d8_device_child.h"
#include "d3d8_surface.h"
namespace dxvk {
using D3D8SwapChainBase = D3D8DeviceChild<d3d9::IDirect3DSwapChain9, IDirect3DSwapChain8>;
class D3D8SwapChain final : public D3D8SwapChainBase {
public:
D3D8SwapChain(
D3D8Device* pDevice,
D3DPRESENT_PARAMETERS* pPresentationParameters,
Com<d3d9::IDirect3DSwapChain9>&& pSwapChain);
HRESULT STDMETHODCALLTYPE Present(const RECT *src, const RECT *dst, HWND hWnd, const RGNDATA *dirtyRegion) final;
HRESULT STDMETHODCALLTYPE GetBackBuffer(
UINT BackBuffer,
D3DBACKBUFFER_TYPE Type,
IDirect3DSurface8** ppBackBuffer) final;
private:
std::vector<Com<D3D8Surface, false>> m_backBuffers;
};
}

152
src/d3d8/d3d8_texture.cpp Normal file
View file

@ -0,0 +1,152 @@
#include "d3d8_texture.h"
#include "d3d8_d3d9_util.h"
namespace dxvk {
// D3D8Texture2D
D3D8Texture2D::D3D8Texture2D(
D3D8Device* pDevice,
const D3DPOOL Pool,
Com<d3d9::IDirect3DTexture9>&& pTexture)
: D3D8Texture2DBase(pDevice, Pool, std::move(pTexture), pTexture->GetLevelCount()) {
}
D3DRESOURCETYPE STDMETHODCALLTYPE D3D8Texture2D::GetType() { return D3DRTYPE_TEXTURE; }
HRESULT STDMETHODCALLTYPE D3D8Texture2D::GetLevelDesc(UINT Level, D3DSURFACE_DESC* pDesc) {
if (unlikely(pDesc == nullptr))
return D3DERR_INVALIDCALL;
d3d9::D3DSURFACE_DESC surf;
HRESULT res = GetD3D9()->GetLevelDesc(Level, &surf);
if (likely(SUCCEEDED(res)))
ConvertSurfaceDesc8(&surf, pDesc);
return res;
}
HRESULT STDMETHODCALLTYPE D3D8Texture2D::GetSurfaceLevel(UINT Level, IDirect3DSurface8** ppSurfaceLevel) {
return GetSubresource(Level, ppSurfaceLevel);
}
HRESULT STDMETHODCALLTYPE D3D8Texture2D::LockRect(
UINT Level,
D3DLOCKED_RECT* pLockedRect,
CONST RECT* pRect,
DWORD Flags) {
return GetD3D9()->LockRect(Level, reinterpret_cast<d3d9::D3DLOCKED_RECT*>(pLockedRect), pRect, Flags);
}
HRESULT STDMETHODCALLTYPE D3D8Texture2D::UnlockRect(UINT Level) {
return GetD3D9()->UnlockRect(Level);
}
HRESULT STDMETHODCALLTYPE D3D8Texture2D::AddDirtyRect(CONST RECT* pDirtyRect) {
return GetD3D9()->AddDirtyRect(pDirtyRect);
}
// D3D8Texture3D
D3D8Texture3D::D3D8Texture3D(
D3D8Device* pDevice,
const D3DPOOL Pool,
Com<d3d9::IDirect3DVolumeTexture9>&& pVolumeTexture)
: D3D8Texture3DBase(pDevice, Pool, std::move(pVolumeTexture), pVolumeTexture->GetLevelCount()) {}
D3DRESOURCETYPE STDMETHODCALLTYPE D3D8Texture3D::GetType() { return D3DRTYPE_VOLUMETEXTURE; }
HRESULT STDMETHODCALLTYPE D3D8Texture3D::GetLevelDesc(UINT Level, D3DVOLUME_DESC *pDesc) {
if (unlikely(pDesc == nullptr))
return D3DERR_INVALIDCALL;
d3d9::D3DVOLUME_DESC vol;
HRESULT res = GetD3D9()->GetLevelDesc(Level, &vol);
if (likely(SUCCEEDED(res)))
ConvertVolumeDesc8(&vol, pDesc);
return res;
}
HRESULT STDMETHODCALLTYPE D3D8Texture3D::GetVolumeLevel(UINT Level, IDirect3DVolume8** ppVolumeLevel) {
return GetSubresource(Level, ppVolumeLevel);
}
HRESULT STDMETHODCALLTYPE D3D8Texture3D::LockBox(
UINT Level,
D3DLOCKED_BOX* pLockedBox,
CONST D3DBOX* pBox,
DWORD Flags) {
return GetD3D9()->LockBox(
Level,
reinterpret_cast<d3d9::D3DLOCKED_BOX*>(pLockedBox),
reinterpret_cast<const d3d9::D3DBOX*>(pBox),
Flags
);
}
HRESULT STDMETHODCALLTYPE D3D8Texture3D::UnlockBox(UINT Level) {
return GetD3D9()->UnlockBox(Level);
}
HRESULT STDMETHODCALLTYPE D3D8Texture3D::AddDirtyBox(CONST D3DBOX* pDirtyBox) {
return GetD3D9()->AddDirtyBox(reinterpret_cast<const d3d9::D3DBOX*>(pDirtyBox));
}
// D3D8TextureCube
D3D8TextureCube::D3D8TextureCube(
D3D8Device* pDevice,
const D3DPOOL Pool,
Com<d3d9::IDirect3DCubeTexture9>&& pTexture)
: D3D8TextureCubeBase(pDevice, Pool, std::move(pTexture), pTexture->GetLevelCount() * CUBE_FACES) {
}
D3DRESOURCETYPE STDMETHODCALLTYPE D3D8TextureCube::GetType() { return D3DRTYPE_CUBETEXTURE; }
HRESULT STDMETHODCALLTYPE D3D8TextureCube::GetLevelDesc(UINT Level, D3DSURFACE_DESC* pDesc) {
if (unlikely(pDesc == nullptr))
return D3DERR_INVALIDCALL;
d3d9::D3DSURFACE_DESC surf;
HRESULT res = GetD3D9()->GetLevelDesc(Level, &surf);
if (likely(SUCCEEDED(res)))
ConvertSurfaceDesc8(&surf, pDesc);
return res;
}
HRESULT STDMETHODCALLTYPE D3D8TextureCube::GetCubeMapSurface(
D3DCUBEMAP_FACES Face,
UINT Level,
IDirect3DSurface8** ppSurfaceLevel) {
return GetSubresource((Level * CUBE_FACES) + Face, ppSurfaceLevel);
}
HRESULT STDMETHODCALLTYPE D3D8TextureCube::LockRect(
D3DCUBEMAP_FACES Face,
UINT Level,
D3DLOCKED_RECT* pLockedRect,
const RECT* pRect,
DWORD Flags) {
return GetD3D9()->LockRect(
d3d9::D3DCUBEMAP_FACES(Face),
Level,
reinterpret_cast<d3d9::D3DLOCKED_RECT*>(pLockedRect),
pRect,
Flags);
}
HRESULT STDMETHODCALLTYPE D3D8TextureCube::UnlockRect(D3DCUBEMAP_FACES Face, UINT Level) {
return GetD3D9()->UnlockRect(d3d9::D3DCUBEMAP_FACES(Face), Level);
}
HRESULT STDMETHODCALLTYPE D3D8TextureCube::AddDirtyRect(D3DCUBEMAP_FACES Face, const RECT* pDirtyRect) {
return GetD3D9()->AddDirtyRect(d3d9::D3DCUBEMAP_FACES(Face), pDirtyRect);
}
}

197
src/d3d8/d3d8_texture.h Normal file
View file

@ -0,0 +1,197 @@
#pragma once
#include "d3d8_resource.h"
#include "d3d8_surface.h"
#include "d3d8_volume.h"
#include <vector>
#include <new>
namespace dxvk {
template <typename SubresourceType, typename D3D9, typename D3D8>
class D3D8BaseTexture : public D3D8Resource<D3D9, D3D8> {
public:
constexpr static UINT CUBE_FACES = 6;
using SubresourceType8 = typename SubresourceType::D3D8;
using SubresourceType9 = typename SubresourceType::D3D9;
D3D8BaseTexture(
D3D8Device* pDevice,
const D3DPOOL Pool,
Com<D3D9>&& pBaseTexture,
UINT SubresourceCount)
: D3D8Resource<D3D9, D3D8> ( pDevice, Pool, std::move(pBaseTexture) ) {
m_subresources.resize(SubresourceCount, nullptr);
}
~D3D8BaseTexture() {
for (size_t i = 0; i < m_subresources.size(); i++)
if (m_subresources[i] != nullptr)
m_subresources[i] = nullptr;
}
virtual IUnknown* GetInterface(REFIID riid) final override try {
return D3D8Resource<D3D9, D3D8>::GetInterface(riid);
} catch (HRESULT err) {
if (riid == __uuidof(IDirect3DBaseTexture8))
return this;
throw err;
}
void STDMETHODCALLTYPE PreLoad() final {
this->GetD3D9()->PreLoad();
}
DWORD STDMETHODCALLTYPE SetLOD(DWORD LODNew) final {
return this->GetD3D9()->SetLOD(LODNew);
}
DWORD STDMETHODCALLTYPE GetLOD() final {
return this->GetD3D9()->GetLOD();
}
DWORD STDMETHODCALLTYPE GetLevelCount() final {
return this->GetD3D9()->GetLevelCount();
}
protected:
HRESULT STDMETHODCALLTYPE GetSubresource(UINT Index, SubresourceType8** ppSubresource) {
InitReturnPtr(ppSubresource);
if (unlikely(ppSubresource == nullptr))
return D3DERR_INVALIDCALL;
if (unlikely(Index >= m_subresources.size()))
return D3DERR_INVALIDCALL;
if (m_subresources[Index] == nullptr) {
try {
Com<SubresourceType9> subresource = LookupSubresource(Index);
// Cache the subresource
m_subresources[Index] = new SubresourceType(this->m_parent, this->m_pool, this, std::move(subresource));
} catch (HRESULT res) {
return res;
}
}
*ppSubresource = m_subresources[Index].ref();
return D3D_OK;
}
private:
Com<SubresourceType9> LookupSubresource(UINT Index) {
Com<SubresourceType9> ptr = nullptr;
HRESULT res = D3DERR_INVALIDCALL;
if constexpr (std::is_same_v<D3D8, IDirect3DTexture8>) {
res = this->GetD3D9()->GetSurfaceLevel(Index, &ptr);
} else if constexpr (std::is_same_v<D3D8, IDirect3DVolumeTexture8>) {
res = this->GetD3D9()->GetVolumeLevel(Index, &ptr);
} else if constexpr (std::is_same_v<D3D8, IDirect3DCubeTexture8>) {
res = this->GetD3D9()->GetCubeMapSurface(d3d9::D3DCUBEMAP_FACES(Index % CUBE_FACES), Index / CUBE_FACES, &ptr);
}
if (FAILED(res))
throw res;
return ptr;
}
std::vector<Com<SubresourceType, false>> m_subresources;
};
using D3D8Texture2DBase = D3D8BaseTexture<D3D8Surface, d3d9::IDirect3DTexture9, IDirect3DTexture8>;
class D3D8Texture2D final : public D3D8Texture2DBase {
public:
D3D8Texture2D(
D3D8Device* pDevice,
const D3DPOOL Pool,
Com<d3d9::IDirect3DTexture9>&& pTexture);
D3DRESOURCETYPE STDMETHODCALLTYPE GetType() final;
HRESULT STDMETHODCALLTYPE GetLevelDesc(UINT Level, D3DSURFACE_DESC* pDesc);
HRESULT STDMETHODCALLTYPE GetSurfaceLevel(UINT Level, IDirect3DSurface8** ppSurfaceLevel);
HRESULT STDMETHODCALLTYPE LockRect(
UINT Level,
D3DLOCKED_RECT* pLockedRect,
CONST RECT* pRect,
DWORD Flags);
HRESULT STDMETHODCALLTYPE UnlockRect(UINT Level);
HRESULT STDMETHODCALLTYPE AddDirtyRect(CONST RECT* pDirtyRect);
};
using D3D8Texture3DBase = D3D8BaseTexture<D3D8Volume, d3d9::IDirect3DVolumeTexture9, IDirect3DVolumeTexture8>;
class D3D8Texture3D final : public D3D8Texture3DBase {
public:
D3D8Texture3D(
D3D8Device* pDevice,
const D3DPOOL Pool,
Com<d3d9::IDirect3DVolumeTexture9>&& pVolumeTexture);
D3DRESOURCETYPE STDMETHODCALLTYPE GetType() final;
HRESULT STDMETHODCALLTYPE GetLevelDesc(UINT Level, D3DVOLUME_DESC *pDesc);
HRESULT STDMETHODCALLTYPE GetVolumeLevel(UINT Level, IDirect3DVolume8** ppVolumeLevel);
HRESULT STDMETHODCALLTYPE LockBox(
UINT Level,
D3DLOCKED_BOX* pLockedBox,
CONST D3DBOX* pBox,
DWORD Flags);
HRESULT STDMETHODCALLTYPE UnlockBox(UINT Level);
HRESULT STDMETHODCALLTYPE AddDirtyBox(CONST D3DBOX* pDirtyBox);
};
using D3D8TextureCubeBase = D3D8BaseTexture<D3D8Surface, d3d9::IDirect3DCubeTexture9, IDirect3DCubeTexture8>;
class D3D8TextureCube final : public D3D8TextureCubeBase {
public:
D3D8TextureCube(
D3D8Device* pDevice,
const D3DPOOL Pool,
Com<d3d9::IDirect3DCubeTexture9>&& pTexture);
D3DRESOURCETYPE STDMETHODCALLTYPE GetType() final;
HRESULT STDMETHODCALLTYPE GetLevelDesc(UINT Level, D3DSURFACE_DESC* pDesc);
HRESULT STDMETHODCALLTYPE GetCubeMapSurface(
D3DCUBEMAP_FACES Face,
UINT Level,
IDirect3DSurface8** ppSurfaceLevel);
HRESULT STDMETHODCALLTYPE LockRect(
D3DCUBEMAP_FACES Face,
UINT Level,
D3DLOCKED_RECT* pLockedRect,
const RECT* pRect,
DWORD Flags);
HRESULT STDMETHODCALLTYPE UnlockRect(D3DCUBEMAP_FACES Face, UINT Level);
HRESULT STDMETHODCALLTYPE AddDirtyRect(D3DCUBEMAP_FACES Face, const RECT* pDirtyRect);
};
}

40
src/d3d8/d3d8_volume.cpp Normal file
View file

@ -0,0 +1,40 @@
#include "d3d8_volume.h"
#include "d3d8_d3d9_util.h"
namespace dxvk {
D3D8Volume::D3D8Volume(
D3D8Device* pDevice,
const D3DPOOL Pool,
IDirect3DVolumeTexture8* pTexture,
Com<d3d9::IDirect3DVolume9>&& pVolume)
: D3D8VolumeBase(pDevice, Pool, std::move(pVolume), pTexture) {
}
HRESULT STDMETHODCALLTYPE D3D8Volume::GetDesc(D3DVOLUME_DESC* pDesc) {
if (unlikely(pDesc == nullptr))
return D3DERR_INVALIDCALL;
d3d9::D3DVOLUME_DESC desc;
HRESULT res = GetD3D9()->GetDesc(&desc);
if (likely(SUCCEEDED(res)))
ConvertVolumeDesc8(&desc, pDesc);
return res;
}
HRESULT STDMETHODCALLTYPE D3D8Volume::LockBox(D3DLOCKED_BOX* pLockedBox, CONST D3DBOX* pBox, DWORD Flags) {
return GetD3D9()->LockBox(
reinterpret_cast<d3d9::D3DLOCKED_BOX*>(pLockedBox),
reinterpret_cast<const d3d9::D3DBOX*>(pBox),
Flags
);
}
HRESULT STDMETHODCALLTYPE D3D8Volume::UnlockBox() {
return GetD3D9()->UnlockBox();
}
}

26
src/d3d8/d3d8_volume.h Normal file
View file

@ -0,0 +1,26 @@
#pragma once
#include "d3d8_subresource.h"
namespace dxvk {
using D3D8VolumeBase = D3D8Subresource<d3d9::IDirect3DVolume9, IDirect3DVolume8>;
class D3D8Volume final : public D3D8VolumeBase {
public:
D3D8Volume(
D3D8Device* pDevice,
const D3DPOOL Pool,
IDirect3DVolumeTexture8* pTexture,
Com<d3d9::IDirect3DVolume9>&& pVolume);
HRESULT STDMETHODCALLTYPE GetDesc(D3DVOLUME_DESC* pDesc);
HRESULT STDMETHODCALLTYPE LockBox(D3DLOCKED_BOX* pLockedBox, CONST D3DBOX* pBox, DWORD Flags) final;
HRESULT STDMETHODCALLTYPE UnlockBox() final;
};
}

View file

@ -0,0 +1,67 @@
#pragma once
#include "d3d8_include.h"
namespace dxvk {
template <typename D3D9Type, typename D3D8Type>
class D3D8WrappedObject : public ComObjectClamp<D3D8Type> {
public:
using D3D9 = D3D9Type;
using D3D8 = D3D8Type;
D3D8WrappedObject(Com<D3D9>&& object)
: m_d3d9(std::move(object)) {
}
D3D9* GetD3D9() {
return m_d3d9.ptr();
}
// For cases where the object may be null.
static D3D9* GetD3D9Nullable(D3D8WrappedObject* self) {
if (unlikely(self == NULL)) {
return NULL;
}
return self->m_d3d9.ptr();
}
template <typename T>
static D3D9* GetD3D9Nullable(Com<T>& self) {
return GetD3D9Nullable(self.ptr());
}
virtual IUnknown* GetInterface(REFIID riid) {
if (riid == __uuidof(IUnknown))
return this;
if (riid == __uuidof(D3D8))
return this;
throw E_NOINTERFACE;
}
HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void** ppvObject) final {
if (ppvObject == nullptr)
return E_POINTER;
*ppvObject = nullptr;
try {
*ppvObject = ref(this->GetInterface(riid));
return S_OK;
} catch (HRESULT err) {
Logger::warn("D3D8WrappedObject::QueryInterface: Unknown interface query");
Logger::warn(str::format(riid));
return err;
}
}
private:
Com<D3D9> m_d3d9;
};
}

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