mirror of https://github.com/doitsujin/dxvk
Compare commits
170 Commits
Author | SHA1 | Date |
---|---|---|
Robin Kertels | 60cfafe027 | |
Robin Kertels | 889802887f | |
WinterSnowfall | a1ce690c5c | |
WinterSnowfall | 07d007c642 | |
Danylo Piliaiev | 58d8ea2d31 | |
Philip Rebohle | 61bd62c327 | |
Philip Rebohle | 7bc77b597e | |
Simon McVittie | 2ff2c826a5 | |
Simon McVittie | f9b4046223 | |
Simon McVittie | 83436a97f2 | |
Ethan Lee | e991bfa604 | |
Ethan Lee | f33453afbb | |
Robin Kertels | 65dd3c7df3 | |
Robin Kertels | dfc3776b24 | |
Philip Rebohle | 3420cd78ac | |
Philip Rebohle | 4225f35034 | |
Philip Rebohle | 2cb2f8694e | |
Blisto91 | c1f665f92b | |
WinterSnowfall | 20185a5309 | |
Blisto91 | 0c2efda804 | |
Blisto91 | c7d61b2fc0 | |
Ethan Lee | 6259e86392 | |
Ethan Lee | d5d236a1e2 | |
Ethan Lee | 10b83d184b | |
Ethan Lee | 0f7c1f753a | |
Ethan Lee | 529129c332 | |
Ethan Lee | 4055a92856 | |
Blisto91 | 7bad17c1d1 | |
Blisto91 | 6b76d70d9d | |
Philip Rebohle | 611dc60018 | |
WinterSnowfall | b2789ab894 | |
Philip Rebohle | ab715a8876 | |
talkingerbil | 1fb35b6d19 | |
Rémi Bernon | 4333ee872d | |
Rémi Bernon | b99d42c688 | |
Blisto91 | dacb8b434b | |
Philip Rebohle | ea4cb84d8a | |
Philip Rebohle | 65373792d2 | |
Lierrmm | 29253da356 | |
Robin Kertels | 79398b468d | |
Robin Kertels | e7d14e97de | |
Philip Rebohle | c613078ba8 | |
Philip Rebohle | 2970645f33 | |
Philip Rebohle | 462165da19 | |
Philip Rebohle | 3f27a0ee58 | |
Katharine Chui | aac3396671 | |
Katharine Chui | 92a43ebf65 | |
Blisto91 | 8ba5256dc7 | |
Philip Rebohle | 2b70ba8f77 | |
Philip Rebohle | 9c66c4bf1d | |
Philip Rebohle | 00872e9e4f | |
Philip Rebohle | 35157357dd | |
Philip Rebohle | 617ebf4e05 | |
Philip Rebohle | c2489d5a45 | |
Philip Rebohle | 6ef98c613f | |
Philip Rebohle | 7441137a33 | |
WinterSnowfall | 571948cfc0 | |
Martino Fontana | 133f0794bc | |
Philip Rebohle | 44695f9311 | |
Casey Bowman | 49e9ea5f5a | |
Blisto91 | 198bd3a4b8 | |
Philip Rebohle | f06c646315 | |
Philip Rebohle | 855b2746b6 | |
Blisto91 | 28c7c09bf5 | |
Philip Rebohle | 2742486540 | |
Philip Rebohle | 037d0fa1ad | |
Philip Rebohle | cbf51a7a25 | |
Philip Rebohle | 70e34dc31c | |
Philip Rebohle | c5aeb0f87a | |
Philip Rebohle | a163082770 | |
Blisto91 | 2e1a19c7fd | |
Joshua Ashton | 0beb18ef73 | |
Joshua Ashton | ef4428ab8c | |
Philip Rebohle | 1085ba713e | |
Philip Rebohle | e857b09432 | |
Kaitlyn | 538f1d13d4 | |
Kaitlyn | 783c9d4591 | |
Kaitlyn | 1a685b1c67 | |
Robin Kertels | 8b8be7c2bf | |
Billy Laws | 0776d764a4 | |
Robin Kertels | 15ddadc4de | |
Philip Rebohle | 69a52b3da0 | |
Philip Rebohle | 707ad6f328 | |
Philip Rebohle | 3a6992ea97 | |
Robin Kertels | 72c86b8229 | |
Robin Kertels | 85215b10d6 | |
Philip Rebohle | fd3fbf6607 | |
Minelelol | 0a699fddb6 | |
Blisto91 | afec5cce88 | |
Ethan Lee | 4b0e3111d1 | |
Philip Rebohle | 0414bbe2d5 | |
Robin Kertels | 20490b678f | |
Blisto91 | 428c98bc63 | |
Robin Kertels | a0e39e94fa | |
Robin Kertels | eaa732d0b3 | |
Robin Kertels | 49b18f03fe | |
Philip Rebohle | c9cea93b7b | |
Philip Rebohle | 69d74a46a0 | |
Philip Rebohle | 94098aa97d | |
Philip Rebohle | c677ba9b3e | |
Philip Rebohle | 77c7396ee1 | |
Philip Rebohle | f07e5f9eaa | |
Philip Rebohle | d5c3011f54 | |
Blisto91 | 6b3b934471 | |
Philip Rebohle | 9004c132ed | |
Philip Rebohle | 24d4c9c938 | |
Philip Rebohle | 5ded7d67f0 | |
Philip Rebohle | 234f3ea071 | |
Robin Kertels | c5a37d443a | |
Robin Kertels | f254afb4fb | |
Robin Kertels | 39c19e9299 | |
Robin Kertels | 738fd4f895 | |
Philip Rebohle | 9491b56beb | |
Robin Kertels | ab3593185f | |
Robin Kertels | e9a0fec5b3 | |
Echo J | fae78407a2 | |
Robin Kertels | 5312ef1cf9 | |
Robin Kertels | 62d64bd63a | |
Robin Kertels | f83ba898af | |
Ethan Lee | 30f2b2df31 | |
Philip Rebohle | 05cb963e22 | |
Philip Rebohle | eb339bc7e4 | |
Ethan Lee | c423819e90 | |
Tatsuyuki Ishi | e2a46a347d | |
Tatsuyuki Ishi | afc6aa70fb | |
Tatsuyuki Ishi | 799aeff560 | |
Robin Kertels | 2ca8fdf890 | |
Robin Kertels | 0841f5faf4 | |
Ethan Lee | 2334bbccb0 | |
Robin Kertels | 7d9864c077 | |
Dean Beeler | d4c5fc74e7 | |
Tatsuyuki Ishi | 6199776869 | |
Tatsuyuki Ishi | 6faf3c1acd | |
Tatsuyuki Ishi | ab6bd8b17f | |
Tatsuyuki Ishi | 89267b62ad | |
Blisto91 | 34d8e65fd7 | |
Joshua Ashton | 1568c263fb | |
Joshua Ashton | 0cd4165658 | |
Joshua Ashton | 4b8e8bed6e | |
r-a-sattarov | ac78048c23 | |
Richard Yao | 14560600a9 | |
Blisto91 | 854e06d3f0 | |
Blisto91 | eb806952d8 | |
Blisto91 | a44dfabe26 | |
spiffeeroo | 5e06cf9573 | |
Blisto91 | 2cf590f636 | |
Robin Kertels | a7a63b37c3 | |
Robin Kertels | 9cde0b5798 | |
Blisto91 | adb33d3af1 | |
Philip Rebohle | 1b31aa5dbc | |
Philip Rebohle | 03c09ce15f | |
Blisto91 | 91f7f43c35 | |
Robin Kertels | d998dee46e | |
Philip Rebohle | ea3149801f | |
xpander69 | 1cb58b0732 | |
Philip Rebohle | 2ed1778df9 | |
Philip Rebohle | a427d22cde | |
Joshua Ashton | 22c2abb9b7 | |
Blisto91 | f45911a28f | |
Blisto91 | e00db24557 | |
Paul Gofman | 552d2f0a6d | |
WinterSnowfall | 4d974685c9 | |
Blisto91 | f0ff0007dc | |
Robin Kertels | 494f7fd38d | |
WinterSnowfall | 0632da1935 | |
Philip Rebohle | 83dc4678df | |
Paul Gofman | f93cfbc26a | |
Philip Rebohle | c113b791a1 | |
Ellie Hermaszewska | 41191af3b1 | |
Philip Rebohle | 5828f0e2b9 |
|
@ -54,7 +54,7 @@ jobs:
|
|||
shell: bash
|
||||
run: |
|
||||
export VERSION_NAME="${GITHUB_REF##*/}-${GITHUB_SHA##*/}"
|
||||
./package-native.sh ${VERSION_NAME} build --no-package
|
||||
./package-native.sh ${VERSION_NAME} build
|
||||
echo "VERSION_NAME=${VERSION_NAME}" >> $GITHUB_ENV
|
||||
|
||||
- name: Upload artifacts
|
||||
|
@ -62,5 +62,5 @@ jobs:
|
|||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: dxvk-${{ env.VERSION_NAME }}
|
||||
path: build/dxvk-native-${{ env.VERSION_NAME }}
|
||||
path: build/dxvk-native-${{ env.VERSION_NAME }}.tar.gz
|
||||
if-no-files-found: error
|
||||
|
|
19
README.md
19
README.md
|
@ -163,3 +163,22 @@ For non debian based distros, make sure that your mingw-w64-gcc cross compiler
|
|||
does have `--enable-threads=posix` enabled during configure. If your distro does
|
||||
ship its mingw-w64-gcc binary with `--enable-threads=win32` you might have to
|
||||
recompile locally or open a bug at your distro's bugtracker to ask for it.
|
||||
|
||||
# DXVK Native
|
||||
|
||||
DXVK Native is a version of DXVK which allows it to be used natively without Wine.
|
||||
|
||||
This is primarily useful for game and application ports to either avoid having to write another rendering backend, or to help with port bringup during development.
|
||||
|
||||
[Release builds](https://github.com/doitsujin/dxvk/releases) are built using the Steam Runtime.
|
||||
|
||||
### How does it work?
|
||||
|
||||
DXVK Native replaces certain Windows-isms with a platform and framework-agnostic replacement, for example, `HWND`s can become `SDL_Window*`s, etc.
|
||||
All it takes to do that is to add another WSI backend.
|
||||
|
||||
**Note:** DXVK Native requires a backend to be explicitly set via the `DXVK_WSI_DRIVER` environment variable. The current built-in options are `SDL2` and `GLFW`.
|
||||
|
||||
DXVK Native comes with a slim set of Windows header definitions required for D3D9/11 and the MinGW headers for D3D9/11.
|
||||
In most cases, it will end up being plug and play with your renderer, but there may be certain teething issues such as:
|
||||
- `__uuidof(type)` is supported, but `__uuidof(variable)` is not supported. Use `__uuidof_var(variable)` instead.
|
||||
|
|
75
dxvk.conf
75
dxvk.conf
|
@ -62,7 +62,7 @@
|
|||
|
||||
|
||||
# Report Nvidia GPUs as AMD GPUs. Unless NVAPI support is explicitly
|
||||
# enabled through proton, this is done by default in order to work
|
||||
# enabled through Proton, this is done by default in order to work
|
||||
# around crashes or low performance with Nvidia-speciic code paths
|
||||
# in games, especially Unreal Engine.
|
||||
#
|
||||
|
@ -71,6 +71,13 @@
|
|||
# dxgi.hideNvidiaGpu = Auto
|
||||
|
||||
|
||||
# Report Nvidia GPUs running on NVK as AMD GPUs.
|
||||
#
|
||||
# Supported values: Auto, True, False
|
||||
|
||||
# dxgi.hideNvkGpu = Auto
|
||||
|
||||
|
||||
# Report AMD GPUs as Nvidia GPUs. This is only done for games that are
|
||||
# known to have issues with AMDAGS or other AMD-specific code paths.
|
||||
#
|
||||
|
@ -90,6 +97,7 @@
|
|||
# Override maximum amount of device memory and shared system memory
|
||||
# reported to the application. This may fix texture streaming issues
|
||||
# in games that do not support cards with large amounts of VRAM.
|
||||
# This is not a hard cap and applications can choose to ignore it.
|
||||
#
|
||||
# Supported values: Any number in Megabytes.
|
||||
|
||||
|
@ -292,6 +300,32 @@
|
|||
# d3d11.enableContextLock = False
|
||||
|
||||
|
||||
# Exposes or hides support for driver command lists
|
||||
#
|
||||
# Some games use the feature flag to decide whether to use deferred
|
||||
# contexts or not. We enable this by default, but in some situations
|
||||
# this can lead to issues if games detect an AMD GPU where command
|
||||
# lists are not natively supported on Windows.
|
||||
#
|
||||
# Supported values: True, False
|
||||
|
||||
# d3d11.exposeDriverCommandLists = True
|
||||
|
||||
|
||||
# Reproducible Command Stream
|
||||
#
|
||||
# Ensure that for the same D3D commands the output VK commands
|
||||
# don't change between runs. Useful for comparative benchmarking,
|
||||
# can negatively affect performance and can break some games
|
||||
# that don't use queries correctly.
|
||||
#
|
||||
# Supported values:
|
||||
# - True/False
|
||||
|
||||
# d3d11.reproducibleCommandStream = False
|
||||
# d3d9.reproducibleCommandStream = False
|
||||
|
||||
|
||||
# Sets number of pipeline compiler threads.
|
||||
#
|
||||
# If the graphics pipeline library feature is enabled, the given
|
||||
|
@ -479,6 +513,7 @@
|
|||
# Supported values:
|
||||
# - True/False
|
||||
|
||||
# d3d11.longMad = False
|
||||
# d3d9.longMad = False
|
||||
|
||||
# Device Local Constant Buffers
|
||||
|
@ -494,7 +529,9 @@
|
|||
|
||||
# Support DF formats
|
||||
#
|
||||
# Support the vendor extension DF floating point depth formats
|
||||
# Support the vendor extension DF floating point depth formats on AMD and Intel.
|
||||
# Note that this config is ignored and disabled by default on Nvidia, or when
|
||||
# spoofing a Nvidia GPU, as it does not support these formats natively.
|
||||
#
|
||||
# Supported values:
|
||||
# - True/False
|
||||
|
@ -623,3 +660,37 @@
|
|||
# DO NOT CHANGE THIS UNLESS YOU HAVE A VERY GOOD REASON.
|
||||
|
||||
# d3d9.textureMemory = 100
|
||||
|
||||
# Hide integrated graphics from applications
|
||||
#
|
||||
# Only has an effect when dedicated GPUs are present on the system. It is
|
||||
# not recommended to use this option at all unless absolutely necessary for
|
||||
# a game to work; prefer using DXVK_FILTER_DEVICE_NAME whenever possible.
|
||||
#
|
||||
# Supported values:
|
||||
# - True/False
|
||||
|
||||
# dxvk.hideIntegratedGraphics = False
|
||||
|
||||
# Trigger DEVICELOST when losing focus
|
||||
#
|
||||
# D3D9 requires the application to call Device::Reset after
|
||||
# it loses focus in fullscreen.
|
||||
# Some games rely on observing a D3DERR_DEVICELOST or D3DERR_NOTRESET.
|
||||
# Others don't handle it correctly.
|
||||
#
|
||||
# Supported values:
|
||||
# - True/False
|
||||
|
||||
# d3d9.deviceLossOnFocusLoss = False
|
||||
|
||||
# Reject Device::Reset if any losable resource is still alive
|
||||
#
|
||||
# D3D9 rejects Device::Reset if there's still any alive resources of specific types.
|
||||
# (State blocks, additional swapchains, D3DPOOL_DEFAULT resources)
|
||||
# Some games leak resources leading to a hang.
|
||||
#
|
||||
# Supported values:
|
||||
# - True/False
|
||||
|
||||
# d3d9.countLosableResources = True
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
install_subdir(
|
||||
'directx',
|
||||
install_dir: get_option('includedir') / 'dxvk',
|
||||
strip_directory: true,
|
||||
exclude_files: '.git'
|
||||
)
|
||||
|
||||
install_subdir(
|
||||
'windows',
|
||||
install_dir: get_option('includedir') / 'dxvk',
|
||||
strip_directory: true,
|
||||
)
|
||||
|
||||
install_headers(
|
||||
'wsi/native_wsi.h',
|
||||
'wsi/native_sdl2.h',
|
||||
'wsi/native_glfw.h',
|
||||
subdir: 'dxvk/wsi',
|
||||
)
|
|
@ -48,7 +48,6 @@ typedef const void* LPCVOID;
|
|||
typedef size_t SIZE_T;
|
||||
|
||||
typedef int8_t INT8;
|
||||
|
||||
typedef uint8_t UINT8;
|
||||
typedef uint8_t BYTE;
|
||||
|
||||
|
@ -56,9 +55,13 @@ typedef int16_t SHORT;
|
|||
typedef uint16_t USHORT;
|
||||
|
||||
typedef int64_t LONGLONG;
|
||||
typedef int64_t INT64;
|
||||
|
||||
typedef uint64_t ULONGLONG;
|
||||
typedef uint64_t UINT64;
|
||||
|
||||
typedef intptr_t LONG_PTR;
|
||||
typedef uintptr_t ULONG_PTR;
|
||||
|
||||
typedef float FLOAT;
|
||||
|
||||
|
@ -330,12 +333,21 @@ typedef struct RGNDATA {
|
|||
#define DECLARE_INTERFACE(x) struct x
|
||||
#define DECLARE_INTERFACE_(x, y) struct x : public y
|
||||
#else
|
||||
#ifdef CONST_VTABLE
|
||||
#define DECLARE_INTERFACE(x) \
|
||||
typedef interface x { \
|
||||
const struct x##Vtbl *lpVtbl; \
|
||||
} x; \
|
||||
typedef const struct x##Vtbl x##Vtbl; \
|
||||
const struct x##Vtbl
|
||||
#else
|
||||
#define DECLARE_INTERFACE(x) \
|
||||
typedef interface x { \
|
||||
struct x##Vtbl *lpVtbl; \
|
||||
} x; \
|
||||
typedef struct x##Vtbl x##Vtbl; \
|
||||
struct x##Vtbl
|
||||
#endif // CONST_VTABLE
|
||||
#define DECLARE_INTERFACE_(x, y) DECLARE_INTERFACE(x)
|
||||
#endif // __cplusplus
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#include <windows.h>
|
||||
|
||||
#include <SDL2/SDL.h>
|
||||
#include <SDL.h>
|
||||
|
||||
namespace dxvk::wsi {
|
||||
|
||||
|
@ -22,4 +22,4 @@ namespace dxvk::wsi {
|
|||
return reinterpret_cast<HMONITOR>(static_cast<intptr_t>(displayId + 1));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit 0bcc624926a25a2a273d07877fd25a6ff5ba1cfb
|
||||
Subproject commit 8b246ff75c6615ba4532fe4fde20f1be090c3764
|
|
@ -1 +1 @@
|
|||
Subproject commit 85c2334e92e215cce34e8e0ed8b2dce4700f4a50
|
||||
Subproject commit 46dc0f6e514f5730784bb2cac2a7c731636839e8
|
107
meson.build
107
meson.build
|
@ -1,11 +1,13 @@
|
|||
project('dxvk', ['c', 'cpp'], version : 'v2.3', meson_version : '>= 0.49', default_options : [ 'cpp_std=c++17', 'warning_level=2' ])
|
||||
project('dxvk', ['c', 'cpp'], version : 'v2.3.1', meson_version : '>= 0.58', default_options : [ 'cpp_std=c++17', 'warning_level=2' ])
|
||||
|
||||
pkg = import('pkgconfig')
|
||||
cpu_family = target_machine.cpu_family()
|
||||
platform = target_machine.system()
|
||||
fs = import('fs')
|
||||
|
||||
cpp = meson.get_compiler('cpp')
|
||||
cc = meson.get_compiler('c')
|
||||
dxvk_is_msvc = cpp.get_id() == 'msvc'
|
||||
dxvk_is_msvc = cpp.get_argument_syntax() == 'msvc'
|
||||
|
||||
compiler_args = [
|
||||
'-msse',
|
||||
|
@ -33,42 +35,60 @@ if get_option('build_id')
|
|||
]
|
||||
endif
|
||||
|
||||
dxvk_include_dirs = [
|
||||
'./include',
|
||||
'./include/vulkan/include',
|
||||
'./include/spirv/include'
|
||||
]
|
||||
dxvk_include_dirs = ['./include']
|
||||
if fs.is_dir('./include/vulkan/include')
|
||||
dxvk_include_dirs += ['./include/vulkan/include']
|
||||
elif not cpp.check_header('vulkan/vulkan.h')
|
||||
error('Missing Vulkan-Headers')
|
||||
endif
|
||||
if fs.is_dir('./include/spirv/include')
|
||||
dxvk_include_dirs += ['./include/spirv/include']
|
||||
elif not cpp.check_header('spirv/unified1/spirv.hpp')
|
||||
error('Missing SPIRV-Headers')
|
||||
endif
|
||||
|
||||
proj_displayinfo = subproject('libdisplay-info')
|
||||
dep_displayinfo = proj_displayinfo.get_variable('di_dep')
|
||||
dep_displayinfo = dependency(
|
||||
'libdisplay-info',
|
||||
version: ['>= 0.0.0', '< 0.2.0'],
|
||||
fallback: ['libdisplay-info', 'di_dep'],
|
||||
default_options: ['default_library=static'],
|
||||
)
|
||||
|
||||
if platform == 'windows'
|
||||
dxvk_so_version = {'name_prefix': ''}
|
||||
|
||||
compiler_args += [
|
||||
'-DNOMINMAX',
|
||||
'-D_WIN32_WINNT=0xa00',
|
||||
]
|
||||
|
||||
link_args += [
|
||||
'-static',
|
||||
'-static-libgcc',
|
||||
'-static-libstdc++',
|
||||
# We need to set the section alignment for debug symbols to
|
||||
# work properly as well as avoiding a memcpy from the Wine loader.
|
||||
'-Wl,--file-alignment=4096',
|
||||
]
|
||||
|
||||
# Wine's built-in back traces only work with dwarf4 symbols
|
||||
if get_option('debug')
|
||||
compiler_args += [
|
||||
'-gdwarf-4',
|
||||
]
|
||||
endif
|
||||
|
||||
# Enable stdcall fixup on 32-bit
|
||||
if cpu_family == 'x86'
|
||||
if not dxvk_is_msvc
|
||||
link_args += [
|
||||
'-Wl,--enable-stdcall-fixup',
|
||||
'-Wl,--kill-at',
|
||||
'-static',
|
||||
'-static-libgcc',
|
||||
'-static-libstdc++',
|
||||
# We need to set the section alignment for debug symbols to
|
||||
# work properly as well as avoiding a memcpy from the Wine loader.
|
||||
'-Wl,--file-alignment=4096',
|
||||
]
|
||||
|
||||
# Wine's built-in back traces only work with dwarf4 symbols
|
||||
if get_option('debug')
|
||||
compiler_args += [
|
||||
'-gdwarf-4',
|
||||
]
|
||||
endif
|
||||
|
||||
# Enable stdcall fixup on 32-bit
|
||||
if cpu_family == 'x86'
|
||||
link_args += [
|
||||
'-Wl,--enable-stdcall-fixup',
|
||||
'-Wl,--kill-at',
|
||||
]
|
||||
endif
|
||||
else
|
||||
link_args += [
|
||||
'/FILEALIGN:4096',
|
||||
]
|
||||
endif
|
||||
|
||||
|
@ -98,10 +118,13 @@ if platform == 'windows'
|
|||
)
|
||||
endif
|
||||
|
||||
dxvk_wsi = 'win32'
|
||||
dxvk_name_prefix = ''
|
||||
compiler_args += ['-DDXVK_WSI_WIN32']
|
||||
else
|
||||
dxvk_abi_version = '0'
|
||||
dxvk_version = meson.project_version().strip('v').split('.')
|
||||
dxvk_so_version = {'version': dxvk_abi_version + '.' + dxvk_version[0] + dxvk_version[1] + dxvk_version[2]}
|
||||
|
||||
wrc = find_program('touch')
|
||||
wrc_generator = generator(wrc, output : [ '@BASENAME@_ignored.h' ], arguments : [ '@OUTPUT@' ] )
|
||||
|
||||
|
@ -111,17 +134,20 @@ else
|
|||
'./include/native/directx'
|
||||
]
|
||||
|
||||
dxvk_wsi = get_option('dxvk_native_wsi')
|
||||
|
||||
if dxvk_wsi == 'sdl2'
|
||||
lib_sdl2 = cpp.find_library('SDL2')
|
||||
lib_sdl2 = dependency('SDL2', required: false)
|
||||
lib_glfw = dependency('glfw', required: false)
|
||||
if lib_sdl2.found()
|
||||
compiler_args += ['-DDXVK_WSI_SDL2']
|
||||
elif dxvk_wsi == 'glfw'
|
||||
lib_glfw = cpp.find_library('glfw')
|
||||
endif
|
||||
if lib_glfw.found()
|
||||
compiler_args += ['-DDXVK_WSI_GLFW']
|
||||
endif
|
||||
if (not lib_sdl2.found() and not lib_glfw.found())
|
||||
error('SDL2 or GLFW are required to build dxvk-native')
|
||||
endif
|
||||
|
||||
dxvk_name_prefix = 'libdxvk_'
|
||||
dxvk_name_prefix = 'dxvk_'
|
||||
dxvk_pkg_prefix = 'dxvk-'
|
||||
|
||||
link_args += [
|
||||
'-static-libgcc',
|
||||
|
@ -137,13 +163,12 @@ add_project_link_arguments(cpp.get_supported_link_arguments(link_args), language
|
|||
add_project_link_arguments(cc.get_supported_link_arguments(link_args), language: 'c')
|
||||
|
||||
exe_ext = ''
|
||||
dll_ext = ''
|
||||
def_spec_ext = '.def'
|
||||
|
||||
glsl_compiler = find_program('glslang', 'glslangValidator')
|
||||
glsl_args = [
|
||||
'--quiet',
|
||||
'--target-env', 'vulkan1.2',
|
||||
'--target-env', 'vulkan1.3',
|
||||
'--vn', '@BASENAME@',
|
||||
'--depfile', '@DEPFILE@',
|
||||
'@INPUT@',
|
||||
|
@ -162,4 +187,8 @@ dxvk_version = vcs_tag(
|
|||
output: 'version.h',
|
||||
)
|
||||
|
||||
if platform != 'windows'
|
||||
subdir('include/native')
|
||||
endif
|
||||
|
||||
subdir('src')
|
||||
|
|
|
@ -56,13 +56,14 @@ function build_arch {
|
|||
opt_strip=--strip
|
||||
fi
|
||||
|
||||
CC="$CC -m$1" CXX="$CXX -m$1" meson setup \
|
||||
--buildtype "release" \
|
||||
--prefix "$DXVK_BUILD_DIR/usr" \
|
||||
$opt_strip \
|
||||
--bindir "$2" \
|
||||
--libdir "$2" \
|
||||
-Dbuild_id=$opt_buildid \
|
||||
CC="$CC -m$1" CXX="$CXX -m$1" meson setup \
|
||||
--buildtype "release" \
|
||||
--prefix "$DXVK_BUILD_DIR/usr" \
|
||||
$opt_strip \
|
||||
--bindir "$2" \
|
||||
--libdir "$2" \
|
||||
-Dbuild_id=$opt_buildid \
|
||||
--force-fallback-for=libdisplay-info \
|
||||
"$DXVK_BUILD_DIR/build.$1"
|
||||
|
||||
cd "$DXVK_BUILD_DIR/build.$1"
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -12,7 +12,7 @@ namespace dxvk {
|
|||
const D3D11_ON_12_RESOURCE_INFO* p11on12Info)
|
||||
: D3D11DeviceChild<ID3D11Buffer>(pDevice),
|
||||
m_desc (*pDesc),
|
||||
m_resource (this),
|
||||
m_resource (this, pDevice),
|
||||
m_d3d10 (this) {
|
||||
DxvkBufferCreateInfo info;
|
||||
info.flags = 0;
|
||||
|
|
|
@ -386,11 +386,16 @@ namespace dxvk {
|
|||
const UINT Values[4]) {
|
||||
D3D10DeviceLock lock = LockContext();
|
||||
|
||||
auto uav = static_cast<D3D11UnorderedAccessView*>(pUnorderedAccessView);
|
||||
|
||||
if (!uav)
|
||||
if (!pUnorderedAccessView)
|
||||
return;
|
||||
|
||||
Com<ID3D11UnorderedAccessView> qiUav;
|
||||
|
||||
if (FAILED(pUnorderedAccessView->QueryInterface(IID_PPV_ARGS(&qiUav))))
|
||||
return;
|
||||
|
||||
auto uav = static_cast<D3D11UnorderedAccessView*>(qiUav.ptr());
|
||||
|
||||
// Gather UAV format info. We'll use this to determine
|
||||
// whether we need to create a temporary view or not.
|
||||
D3D11_UNORDERED_ACCESS_VIEW_DESC uavDesc;
|
||||
|
@ -923,6 +928,34 @@ namespace dxvk {
|
|||
const void* pSrcData,
|
||||
UINT SrcRowPitch,
|
||||
UINT SrcDepthPitch) {
|
||||
if (IsDeferred && unlikely(pDstBox != nullptr) && unlikely(!m_parent->GetOptions()->exposeDriverCommandLists)) {
|
||||
// If called from a deferred context and native command list support is not
|
||||
// exposed, we need to apply the destination box to the source pointer. This
|
||||
// only applies to UpdateSubresource, not to UpdateSubresource1. See MSDN:
|
||||
// https://msdn.microsoft.com/en-us/library/windows/desktop/ff476486(v=vs.85).aspx)
|
||||
size_t srcOffset = pDstBox->left;
|
||||
|
||||
// For textures, the offset logic needs to take the format into account.
|
||||
// Ignore that multi-planar images exist, this is hairy enough already.
|
||||
D3D11CommonTexture* dstTexture = GetCommonTexture(pDstResource);
|
||||
|
||||
if (dstTexture) {
|
||||
auto dstFormat = dstTexture->GetPackedFormat();
|
||||
auto dstFormatInfo = lookupFormatInfo(dstFormat);
|
||||
|
||||
size_t blockSize = dstFormatInfo->elementSize;
|
||||
|
||||
VkOffset3D offset;
|
||||
offset.x = pDstBox->left / dstFormatInfo->blockSize.width;
|
||||
offset.y = pDstBox->top / dstFormatInfo->blockSize.height;
|
||||
offset.z = pDstBox->front / dstFormatInfo->blockSize.depth;
|
||||
|
||||
srcOffset = offset.x * blockSize + offset.y * SrcRowPitch + offset.z * SrcDepthPitch;
|
||||
}
|
||||
|
||||
pSrcData = reinterpret_cast<const char*>(pSrcData) + srcOffset;
|
||||
}
|
||||
|
||||
UpdateResource(pDstResource, DstSubresource, pDstBox,
|
||||
pSrcData, SrcRowPitch, SrcDepthPitch, 0);
|
||||
}
|
||||
|
|
|
@ -1130,7 +1130,7 @@ namespace dxvk {
|
|||
if (likely(pBuffer != nullptr))
|
||||
bufferSize = static_cast<D3D11Buffer*>(pBuffer)->Desc()->ByteWidth;
|
||||
|
||||
return bufferSize >= Offset + Size;
|
||||
return uint64_t(bufferSize) >= uint64_t(Offset) + uint64_t(Size);
|
||||
}
|
||||
|
||||
private:
|
||||
|
|
|
@ -19,6 +19,7 @@ namespace dxvk {
|
|||
m_csThread(Device, Device->createContext(DxvkContextType::Primary)),
|
||||
m_maxImplicitDiscardSize(pParent->GetOptions()->maxImplicitDiscardSize),
|
||||
m_submissionFence(new sync::CallbackFence()),
|
||||
m_flushTracker(pParent->GetOptions()->reproducibleCommandStream),
|
||||
m_multithread(this, false, pParent->GetOptions()->enableContextLock),
|
||||
m_videoContext(this, Device) {
|
||||
EmitCs([
|
||||
|
|
|
@ -89,6 +89,10 @@ namespace dxvk {
|
|||
void SynchronizeCsThread(
|
||||
uint64_t SequenceNumber);
|
||||
|
||||
D3D10Multithread& GetMultithread() {
|
||||
return m_multithread;
|
||||
}
|
||||
|
||||
D3D10DeviceLock LockContext() {
|
||||
return m_multithread.AcquireLock();
|
||||
}
|
||||
|
|
|
@ -45,10 +45,10 @@ namespace dxvk {
|
|||
m_dxvkDevice (pContainer->GetDXVKDevice()),
|
||||
m_dxvkAdapter (m_dxvkDevice->adapter()),
|
||||
m_d3d11Formats (m_dxvkDevice),
|
||||
m_d3d11Options (m_dxvkDevice->instance()->config(), m_dxvkDevice),
|
||||
m_d3d11Options (m_dxvkDevice->instance()->config()),
|
||||
m_dxbcOptions (m_dxvkDevice, m_d3d11Options),
|
||||
m_maxFeatureLevel (GetMaxFeatureLevel(m_dxvkDevice->instance(), m_dxvkDevice->adapter())),
|
||||
m_deviceFeatures (m_dxvkDevice->instance(), m_dxvkDevice->adapter(), m_featureLevel) {
|
||||
m_deviceFeatures (m_dxvkDevice->instance(), m_dxvkDevice->adapter(), m_d3d11Options, m_featureLevel) {
|
||||
m_initializer = new D3D11Initializer(this);
|
||||
m_context = new D3D11ImmediateContext(this, m_dxvkDevice);
|
||||
m_d3d10Device = new D3D10Device(this, m_context.ptr());
|
||||
|
@ -1348,7 +1348,7 @@ namespace dxvk {
|
|||
m_deviceFeatures = D3D11DeviceFeatures(
|
||||
m_dxvkDevice->instance(),
|
||||
m_dxvkDevice->adapter(),
|
||||
m_featureLevel);
|
||||
m_d3d11Options, m_featureLevel);
|
||||
}
|
||||
|
||||
if (pChosenFeatureLevel)
|
||||
|
@ -3411,8 +3411,9 @@ namespace dxvk {
|
|||
|
||||
|
||||
HRESULT STDMETHODCALLTYPE D3D11DXGIDevice::EnqueueSetEvent(HANDLE hEvent) {
|
||||
Logger::err("D3D11DXGIDevice::EnqueueSetEvent: Not implemented");
|
||||
return DXGI_ERROR_UNSUPPORTED;
|
||||
auto immediateContext = m_d3d11Device.GetContext();
|
||||
immediateContext->Flush1(D3D11_CONTEXT_TYPE_ALL, hEvent);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -12,6 +12,7 @@ namespace dxvk {
|
|||
D3D11DeviceFeatures::D3D11DeviceFeatures(
|
||||
const Rc<DxvkInstance>& Instance,
|
||||
const Rc<DxvkAdapter>& Adapter,
|
||||
const D3D11Options& Options,
|
||||
D3D_FEATURE_LEVEL FeatureLevel)
|
||||
: m_features (Adapter->features()),
|
||||
m_properties (Adapter->devicePropertiesExt()) {
|
||||
|
@ -107,7 +108,7 @@ namespace dxvk {
|
|||
m_gpuVirtualAddress.MaxGPUVirtualAddressBitsPerProcess = 40;
|
||||
|
||||
// Marker support only depends on the debug utils extension
|
||||
m_marker.Profile = Instance->extensions().extDebugUtils;
|
||||
m_marker.Profile = static_cast<bool>(Instance->extensions().extDebugUtils);
|
||||
|
||||
// DXVK will keep all shaders in memory once created, and all Vulkan
|
||||
// drivers that we know of that can run DXVK have an on-disk cache.
|
||||
|
@ -118,11 +119,11 @@ namespace dxvk {
|
|||
m_shaderMinPrecision.PixelShaderMinPrecision = 0;
|
||||
m_shaderMinPrecision.AllOtherShaderStagesMinPrecision = 0;
|
||||
|
||||
// Report native support for command lists here so that we do not actually have
|
||||
// to re-implement the UpdateSubresource bug from the D3D11 runtime, see MSDN:
|
||||
// https://msdn.microsoft.com/en-us/library/windows/desktop/ff476486(v=vs.85).aspx)
|
||||
// Report native support for command lists by default. Deferred context
|
||||
// usage can be beneficial for us as ExecuteCommandList has low overhead,
|
||||
// and we avoid having to deal with known UpdateSubresource bugs this way.
|
||||
m_threading.DriverConcurrentCreates = TRUE;
|
||||
m_threading.DriverCommandLists = TRUE;
|
||||
m_threading.DriverCommandLists = Options.exposeDriverCommandLists;
|
||||
}
|
||||
|
||||
|
||||
|
@ -182,7 +183,8 @@ namespace dxvk {
|
|||
D3D_FEATURE_LEVEL D3D11DeviceFeatures::GetMaxFeatureLevel(
|
||||
const Rc<DxvkInstance>& Instance,
|
||||
const Rc<DxvkAdapter>& Adapter) {
|
||||
D3D11DeviceFeatures features(Instance, Adapter, D3D_FEATURE_LEVEL_12_1);
|
||||
D3D11Options options(Instance->config());
|
||||
D3D11DeviceFeatures features(Instance, Adapter, options, D3D_FEATURE_LEVEL_12_1);
|
||||
return features.GetMaxFeatureLevel();
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
#include "d3d11_include.h"
|
||||
#include "d3d11_options.h"
|
||||
|
||||
#include "../dxvk/dxvk_adapter.h"
|
||||
#include "../dxvk/dxvk_instance.h"
|
||||
|
@ -21,6 +22,7 @@ namespace dxvk {
|
|||
D3D11DeviceFeatures(
|
||||
const Rc<DxvkInstance>& Instance,
|
||||
const Rc<DxvkAdapter>& Adapter,
|
||||
const D3D11Options& Options,
|
||||
D3D_FEATURE_LEVEL FeatureLevel);
|
||||
|
||||
~D3D11DeviceFeatures();
|
||||
|
|
|
@ -183,13 +183,7 @@ ID3D11VkExtContext1 : public ID3D11VkExtContext {
|
|||
};
|
||||
|
||||
|
||||
#ifdef _MSC_VER
|
||||
struct __declspec(uuid("bb8a4fb9-3935-4762-b44b-35189a26414a")) ID3D11VkExtShader;
|
||||
struct __declspec(uuid("8a6e3c42-f74c-45b7-8265-a231b677ca17")) ID3D11VkExtDevice;
|
||||
struct __declspec(uuid("cfcf64ef-9586-46d0-bca4-97cf2ca61b06")) ID3D11VkExtDevice1;
|
||||
struct __declspec(uuid("fd0bca13-5cb6-4c3a-987e-4750de2ca791")) ID3D11VkExtContext;
|
||||
struct __declspec(uuid("874b09b2-ae0b-41d8-8476-5f3b7a0e879d")) ID3D11VkExtContext1;
|
||||
#else
|
||||
#ifndef _MSC_VER
|
||||
__CRT_UUID_DECL(ID3D11VkExtShader, 0xbb8a4fb9,0x3935,0x4762,0xb4,0x4b,0x35,0x18,0x9a,0x26,0x41,0x4a);
|
||||
__CRT_UUID_DECL(ID3D11VkExtDevice, 0x8a6e3c42,0xf74c,0x45b7,0x82,0x65,0xa2,0x31,0xb6,0x77,0xca,0x17);
|
||||
__CRT_UUID_DECL(ID3D11VkExtDevice1, 0xcfcf64ef,0x9586,0x46d0,0xbc,0xa4,0x97,0xcf,0x2c,0xa6,0x1b,0x06);
|
||||
|
|
|
@ -38,7 +38,7 @@ extern "C" {
|
|||
DXGI_ADAPTER_DESC desc;
|
||||
pAdapter->GetDesc(&desc);
|
||||
|
||||
dxvkInstance = new DxvkInstance();
|
||||
dxvkInstance = new DxvkInstance(0);
|
||||
dxvkAdapter = dxvkInstance->findAdapterByLuid(&desc.AdapterLuid);
|
||||
|
||||
if (dxvkAdapter == nullptr)
|
||||
|
@ -376,7 +376,7 @@ extern "C" {
|
|||
instanceInfo.extensionCount = instanceExtensions.size();
|
||||
instanceInfo.extensionNames = instanceExtensions.data();
|
||||
|
||||
Rc<DxvkInstance> dxvkInstance = new DxvkInstance(instanceInfo);
|
||||
Rc<DxvkInstance> dxvkInstance = new DxvkInstance(instanceInfo, 0);
|
||||
|
||||
// Find adapter by physical device handle
|
||||
Rc<DxvkAdapter> dxvkAdapter;
|
||||
|
|
|
@ -49,8 +49,6 @@ ID3D12DXVKInteropDevice : public IUnknown {
|
|||
|
||||
};
|
||||
|
||||
#ifdef _MSC_VER
|
||||
struct __declspec(uuid("39da4e09-bd1c-4198-9fae-86bbe3be41fd")) ID3D12DXVKInteropDevice;
|
||||
#else
|
||||
#ifndef _MSC_VER
|
||||
__CRT_UUID_DECL(ID3D12DXVKInteropDevice, 0x39da4e09, 0xbd1c, 0x4198, 0x9f,0xae, 0x86,0xbb,0xe3,0xbe,0x41,0xfd)
|
||||
#endif
|
||||
|
|
|
@ -12,7 +12,7 @@ namespace dxvk {
|
|||
#endif
|
||||
}
|
||||
|
||||
D3D11Options::D3D11Options(const Config& config, const Rc<DxvkDevice>& device) {
|
||||
D3D11Options::D3D11Options(const Config& config) {
|
||||
this->dcSingleUseMode = config.getOption<bool>("d3d11.dcSingleUseMode", true);
|
||||
this->zeroInitWorkgroupMemory = config.getOption<bool>("d3d11.zeroInitWorkgroupMemory", false);
|
||||
this->forceVolatileTgsmAccess = config.getOption<bool>("d3d11.forceVolatileTgsmAccess", false);
|
||||
|
@ -31,7 +31,9 @@ namespace dxvk {
|
|||
this->numBackBuffers = config.getOption<int32_t>("dxgi.numBackBuffers", 0);
|
||||
this->maxFrameLatency = config.getOption<int32_t>("dxgi.maxFrameLatency", 0);
|
||||
this->maxFrameRate = config.getOption<int32_t>("dxgi.maxFrameRate", 0);
|
||||
this->syncInterval = config.getOption<int32_t>("dxgi.syncInterval", -1);
|
||||
this->exposeDriverCommandLists = config.getOption<bool>("d3d11.exposeDriverCommandLists", true);
|
||||
this->longMad = config.getOption<bool>("d3d11.longMad", false);
|
||||
this->reproducibleCommandStream = config.getOption<bool>("d3d11.reproducibleCommandStream", false);
|
||||
|
||||
// Clamp LOD bias so that people don't abuse this in unintended ways
|
||||
this->samplerLodBias = dxvk::fclamp(this->samplerLodBias, -2.0f, 1.0f);
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
namespace dxvk {
|
||||
|
||||
struct D3D11Options {
|
||||
D3D11Options(const Config& config, const Rc<DxvkDevice>& device);
|
||||
D3D11Options(const Config& config);
|
||||
|
||||
/// Enables speed hack for mapping on deferred contexts
|
||||
///
|
||||
|
@ -76,10 +76,6 @@ namespace dxvk {
|
|||
/// Overrides DXGI_SWAP_CHAIN_DESC::BufferCount.
|
||||
int32_t numBackBuffers;
|
||||
|
||||
/// Sync interval. Overrides the value
|
||||
/// passed to IDXGISwapChain::Present.
|
||||
int32_t syncInterval;
|
||||
|
||||
/// Override maximum frame latency if the app specifies
|
||||
/// a higher value. May help with frame timing issues.
|
||||
int32_t maxFrameLatency;
|
||||
|
@ -117,8 +113,21 @@ namespace dxvk {
|
|||
/// race conditions.
|
||||
bool enableContextLock;
|
||||
|
||||
/// Whether to expose the driver command list feature. Enabled by
|
||||
/// default and generally beneficial, but some games may assume that
|
||||
/// this is not supported when running on an AMD GPU.
|
||||
bool exposeDriverCommandLists;
|
||||
|
||||
/// Shader dump path
|
||||
std::string shaderDumpPath;
|
||||
|
||||
/// Should we make our Mads a FFma or do it the long way with an FMul and an FAdd?
|
||||
bool longMad;
|
||||
|
||||
/// Ensure that for the same D3D commands the output VK commands
|
||||
/// don't change between runs. Useful for comparative benchmarking,
|
||||
/// can negatively affect performance.
|
||||
bool reproducibleCommandStream;
|
||||
};
|
||||
|
||||
}
|
|
@ -9,11 +9,10 @@
|
|||
namespace dxvk {
|
||||
|
||||
D3D11DXGIKeyedMutex::D3D11DXGIKeyedMutex(
|
||||
ID3D11Resource* pResource)
|
||||
: m_resource(pResource) {
|
||||
Com<ID3D11Device> device;
|
||||
m_resource->GetDevice(&device);
|
||||
m_device = static_cast<D3D11Device*>(device.ptr());
|
||||
ID3D11Resource* pResource,
|
||||
D3D11Device* pDevice)
|
||||
: m_resource(pResource),
|
||||
m_device(pDevice) {
|
||||
|
||||
m_supported = m_device->GetDXVKDevice()->features().khrWin32KeyedMutex
|
||||
&& m_device->GetDXVKDevice()->vkd()->wine_vkAcquireKeyedMutex != nullptr
|
||||
|
@ -112,7 +111,17 @@ namespace dxvk {
|
|||
D3D11CommonTexture* texture = GetCommonTexture(m_resource);
|
||||
Rc<DxvkDevice> dxvkDevice = m_device->GetDXVKDevice();
|
||||
|
||||
m_device->GetContext()->WaitForResource(texture->GetImage(), DxvkCsThread::SynchronizeAll, D3D11_MAP_READ_WRITE, 0);
|
||||
{
|
||||
D3D11ImmediateContext* context = m_device->GetContext();
|
||||
D3D10Multithread& multithread = context->GetMultithread();
|
||||
static bool s_errorShown = false;
|
||||
|
||||
if (!multithread.GetMultithreadProtected() && !std::exchange(s_errorShown, true))
|
||||
Logger::warn("D3D11DXGIKeyedMutex::ReleaseSync: Called without context locking enabled.");
|
||||
|
||||
D3D10DeviceLock lock = context->LockContext();
|
||||
context->WaitForResource(texture->GetImage(), DxvkCsThread::SynchronizeAll, D3D11_MAP_READ_WRITE, 0);
|
||||
}
|
||||
|
||||
return dxvkDevice->vkd()->wine_vkReleaseKeyedMutex(dxvkDevice->handle(), texture->GetImage()->memory().memory(), Key) == VK_SUCCESS
|
||||
? S_OK
|
||||
|
@ -120,9 +129,10 @@ namespace dxvk {
|
|||
}
|
||||
|
||||
D3D11DXGIResource::D3D11DXGIResource(
|
||||
ID3D11Resource* pResource)
|
||||
ID3D11Resource* pResource,
|
||||
D3D11Device* pDevice)
|
||||
: m_resource(pResource),
|
||||
m_keyedMutex(pResource) {
|
||||
m_keyedMutex(pResource, pDevice) {
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -30,7 +30,8 @@ namespace dxvk {
|
|||
public:
|
||||
|
||||
D3D11DXGIKeyedMutex(
|
||||
ID3D11Resource* pResource);
|
||||
ID3D11Resource* pResource,
|
||||
D3D11Device* pDevice);
|
||||
|
||||
~D3D11DXGIKeyedMutex();
|
||||
|
||||
|
@ -88,7 +89,8 @@ namespace dxvk {
|
|||
public:
|
||||
|
||||
D3D11DXGIResource(
|
||||
ID3D11Resource* pResource);
|
||||
ID3D11Resource* pResource,
|
||||
D3D11Device* pDevice);
|
||||
|
||||
~D3D11DXGIResource();
|
||||
|
||||
|
|
|
@ -254,11 +254,6 @@ namespace dxvk {
|
|||
UINT SyncInterval,
|
||||
UINT PresentFlags,
|
||||
const DXGI_PRESENT_PARAMETERS* pPresentParameters) {
|
||||
auto options = m_parent->GetOptions();
|
||||
|
||||
if (options->syncInterval >= 0)
|
||||
SyncInterval = options->syncInterval;
|
||||
|
||||
if (!(PresentFlags & DXGI_PRESENT_TEST))
|
||||
m_dirty |= m_presenter->setSyncInterval(SyncInterval) != VK_SUCCESS;
|
||||
|
||||
|
|
|
@ -58,9 +58,6 @@ namespace dxvk {
|
|||
"\n MiscFlags: ", m_desc.MiscFlags,
|
||||
"\n FeatureLevel: ", pDevice->GetFeatureLevel()));
|
||||
|
||||
if (m_desc.MiscFlags & D3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX)
|
||||
Logger::warn("D3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX: not supported.");
|
||||
|
||||
imageInfo.shared = true;
|
||||
imageInfo.sharing.mode = hSharedHandle == INVALID_HANDLE_VALUE ? DxvkSharedHandleMode::Export : DxvkSharedHandleMode::Import;
|
||||
imageInfo.sharing.type = (m_desc.MiscFlags & D3D11_RESOURCE_MISC_SHARED_NTHANDLE)
|
||||
|
@ -214,9 +211,12 @@ namespace dxvk {
|
|||
// For some formats, we need to enable sampled and/or
|
||||
// render target capabilities if available, but these
|
||||
// should in no way affect the default image layout
|
||||
imageInfo.usage |= EnableMetaCopyUsage(imageInfo.format, imageInfo.tiling);
|
||||
imageInfo.usage |= EnableMetaPackUsage(imageInfo.format, m_desc.CPUAccessFlags);
|
||||
|
||||
imageInfo.usage |= EnableMetaCopyUsage(imageInfo.format, imageInfo.tiling);
|
||||
|
||||
for (uint32_t i = 0; i < imageInfo.viewFormatCount; i++)
|
||||
imageInfo.usage |= EnableMetaCopyUsage(imageInfo.viewFormats[i], imageInfo.tiling);
|
||||
|
||||
// Check if we can actually create the image
|
||||
if (!CheckImageSupport(&imageInfo, imageInfo.tiling)) {
|
||||
throw DxvkError(str::format(
|
||||
|
@ -1099,7 +1099,7 @@ namespace dxvk {
|
|||
m_texture (this, pDevice, pDesc, p11on12Info, D3D11_RESOURCE_DIMENSION_TEXTURE1D, 0, VK_NULL_HANDLE, nullptr),
|
||||
m_interop (this, &m_texture),
|
||||
m_surface (this, &m_texture),
|
||||
m_resource(this),
|
||||
m_resource(this, pDevice),
|
||||
m_d3d10 (this) {
|
||||
|
||||
}
|
||||
|
@ -1205,7 +1205,7 @@ namespace dxvk {
|
|||
m_texture (this, pDevice, pDesc, p11on12Info, D3D11_RESOURCE_DIMENSION_TEXTURE2D, 0, VK_NULL_HANDLE, hSharedHandle),
|
||||
m_interop (this, &m_texture),
|
||||
m_surface (this, &m_texture),
|
||||
m_resource (this),
|
||||
m_resource (this, pDevice),
|
||||
m_d3d10 (this),
|
||||
m_swapChain (nullptr) {
|
||||
}
|
||||
|
@ -1220,7 +1220,7 @@ namespace dxvk {
|
|||
m_texture (this, pDevice, pDesc, nullptr, D3D11_RESOURCE_DIMENSION_TEXTURE2D, DxgiUsage, vkImage, nullptr),
|
||||
m_interop (this, &m_texture),
|
||||
m_surface (this, &m_texture),
|
||||
m_resource (this),
|
||||
m_resource (this, pDevice),
|
||||
m_d3d10 (this),
|
||||
m_swapChain (nullptr) {
|
||||
|
||||
|
@ -1236,7 +1236,7 @@ namespace dxvk {
|
|||
m_texture (this, pDevice, pDesc, nullptr, D3D11_RESOURCE_DIMENSION_TEXTURE2D, DxgiUsage, VK_NULL_HANDLE, nullptr),
|
||||
m_interop (this, &m_texture),
|
||||
m_surface (this, &m_texture),
|
||||
m_resource (this),
|
||||
m_resource (this, pDevice),
|
||||
m_d3d10 (this),
|
||||
m_swapChain (pSwapChain) {
|
||||
|
||||
|
@ -1384,7 +1384,7 @@ namespace dxvk {
|
|||
: D3D11DeviceChild<ID3D11Texture3D1>(pDevice),
|
||||
m_texture (this, pDevice, pDesc, p11on12Info, D3D11_RESOURCE_DIMENSION_TEXTURE3D, 0, VK_NULL_HANDLE, nullptr),
|
||||
m_interop (this, &m_texture),
|
||||
m_resource(this),
|
||||
m_resource(this, pDevice),
|
||||
m_d3d10 (this) {
|
||||
|
||||
}
|
||||
|
|
|
@ -1262,12 +1262,28 @@ namespace dxvk {
|
|||
viewport.height = float(cStreamState.dstRect.bottom) - viewport.y;
|
||||
}
|
||||
|
||||
VkExtent3D viewExtent = cViews[0]->mipLevelExtent(0);
|
||||
|
||||
VkRect2D srcRect;
|
||||
srcRect.offset = { 0, 0 };
|
||||
srcRect.extent = { viewExtent.width, viewExtent.height };
|
||||
|
||||
if (cStreamState.srcRectEnabled) {
|
||||
srcRect.offset.x = cStreamState.srcRect.left;
|
||||
srcRect.offset.y = cStreamState.srcRect.top;
|
||||
srcRect.extent.width = cStreamState.srcRect.right - srcRect.offset.x;
|
||||
srcRect.extent.height = cStreamState.srcRect.bottom - srcRect.offset.y;
|
||||
}
|
||||
|
||||
UboData uboData = { };
|
||||
uboData.colorMatrix[0][0] = 1.0f;
|
||||
uboData.colorMatrix[1][1] = 1.0f;
|
||||
uboData.colorMatrix[2][2] = 1.0f;
|
||||
uboData.coordMatrix[0][0] = 1.0f;
|
||||
uboData.coordMatrix[1][1] = 1.0f;
|
||||
uboData.coordMatrix[0][0] = float(srcRect.extent.width) / float(viewExtent.width);
|
||||
uboData.coordMatrix[1][1] = float(srcRect.extent.height) / float(viewExtent.height);
|
||||
uboData.coordMatrix[2][0] = float(srcRect.offset.x) / float(viewExtent.width);
|
||||
uboData.coordMatrix[2][1] = float(srcRect.offset.y) / float(viewExtent.height);
|
||||
uboData.srcRect = srcRect;
|
||||
uboData.yMin = 0.0f;
|
||||
uboData.yMax = 1.0f;
|
||||
uboData.isPlanar = cViews[1] != nullptr;
|
||||
|
@ -1290,17 +1306,14 @@ namespace dxvk {
|
|||
ctx->bindShader<VK_SHADER_STAGE_FRAGMENT_BIT>(Rc<DxvkShader>(m_fs));
|
||||
|
||||
ctx->bindUniformBuffer(VK_SHADER_STAGE_FRAGMENT_BIT, 0, DxvkBufferSlice(m_ubo));
|
||||
ctx->bindResourceSampler(VK_SHADER_STAGE_FRAGMENT_BIT, 1, Rc<DxvkSampler>(m_sampler));
|
||||
|
||||
for (uint32_t i = 0; i < cViews.size(); i++)
|
||||
ctx->bindResourceImageView(VK_SHADER_STAGE_FRAGMENT_BIT, 2 + i, Rc<DxvkImageView>(cViews[i]));
|
||||
ctx->bindResourceImageView(VK_SHADER_STAGE_FRAGMENT_BIT, 1 + i, Rc<DxvkImageView>(cViews[i]));
|
||||
|
||||
ctx->draw(3, 1, 0, 0);
|
||||
|
||||
ctx->bindResourceSampler(VK_SHADER_STAGE_FRAGMENT_BIT, 1, nullptr);
|
||||
|
||||
for (uint32_t i = 0; i < cViews.size(); i++)
|
||||
ctx->bindResourceImageView(VK_SHADER_STAGE_FRAGMENT_BIT, 2 + i, nullptr);
|
||||
ctx->bindResourceImageView(VK_SHADER_STAGE_FRAGMENT_BIT, 1 + i, nullptr);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -1315,38 +1328,14 @@ namespace dxvk {
|
|||
}
|
||||
|
||||
|
||||
void D3D11VideoContext::CreateSampler() {
|
||||
DxvkSamplerCreateInfo samplerInfo;
|
||||
samplerInfo.magFilter = VK_FILTER_LINEAR;
|
||||
samplerInfo.minFilter = VK_FILTER_LINEAR;
|
||||
samplerInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_NEAREST;
|
||||
samplerInfo.mipmapLodBias = 0.0f;
|
||||
samplerInfo.mipmapLodMin = 0.0f;
|
||||
samplerInfo.mipmapLodMax = 0.0f;
|
||||
samplerInfo.useAnisotropy = VK_FALSE;
|
||||
samplerInfo.maxAnisotropy = 1.0f;
|
||||
samplerInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
|
||||
samplerInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
|
||||
samplerInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
|
||||
samplerInfo.compareToDepth = VK_FALSE;
|
||||
samplerInfo.compareOp = VK_COMPARE_OP_ALWAYS;
|
||||
samplerInfo.reductionMode = VK_SAMPLER_REDUCTION_MODE_WEIGHTED_AVERAGE;
|
||||
samplerInfo.borderColor = VkClearColorValue();
|
||||
samplerInfo.usePixelCoord = VK_FALSE;
|
||||
samplerInfo.nonSeamless = VK_FALSE;
|
||||
m_sampler = m_device->createSampler(samplerInfo);
|
||||
}
|
||||
|
||||
|
||||
void D3D11VideoContext::CreateShaders() {
|
||||
SpirvCodeBuffer vsCode(d3d11_video_blit_vert);
|
||||
SpirvCodeBuffer fsCode(d3d11_video_blit_frag);
|
||||
|
||||
const std::array<DxvkBindingInfo, 4> fsBindings = {{
|
||||
const std::array<DxvkBindingInfo, 3> fsBindings = {{
|
||||
{ VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 0, VK_IMAGE_VIEW_TYPE_MAX_ENUM, VK_SHADER_STAGE_FRAGMENT_BIT, VK_ACCESS_UNIFORM_READ_BIT, VK_TRUE },
|
||||
{ VK_DESCRIPTOR_TYPE_SAMPLER, 1, VK_IMAGE_VIEW_TYPE_MAX_ENUM, VK_SHADER_STAGE_FRAGMENT_BIT, 0 },
|
||||
{ VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, 1, VK_IMAGE_VIEW_TYPE_2D, VK_SHADER_STAGE_FRAGMENT_BIT, VK_ACCESS_SHADER_READ_BIT },
|
||||
{ VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, 2, VK_IMAGE_VIEW_TYPE_2D, VK_SHADER_STAGE_FRAGMENT_BIT, VK_ACCESS_SHADER_READ_BIT },
|
||||
{ VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, 3, VK_IMAGE_VIEW_TYPE_2D, VK_SHADER_STAGE_FRAGMENT_BIT, VK_ACCESS_SHADER_READ_BIT },
|
||||
}};
|
||||
|
||||
DxvkShaderCreateInfo vsInfo;
|
||||
|
@ -1368,7 +1357,6 @@ namespace dxvk {
|
|||
if (std::exchange(m_resourcesCreated, true))
|
||||
return;
|
||||
|
||||
CreateSampler();
|
||||
CreateUniformBuffer();
|
||||
CreateShaders();
|
||||
}
|
||||
|
|
|
@ -584,6 +584,7 @@ namespace dxvk {
|
|||
struct alignas(16) UboData {
|
||||
float colorMatrix[3][4];
|
||||
float coordMatrix[3][2];
|
||||
VkRect2D srcRect;
|
||||
float yMin, yMax;
|
||||
VkBool32 isPlanar;
|
||||
};
|
||||
|
@ -593,7 +594,6 @@ namespace dxvk {
|
|||
Rc<DxvkDevice> m_device;
|
||||
Rc<DxvkShader> m_vs;
|
||||
Rc<DxvkShader> m_fs;
|
||||
Rc<DxvkSampler> m_sampler;
|
||||
Rc<DxvkBuffer> m_ubo;
|
||||
|
||||
VkExtent2D m_dstExtent = { 0u, 0u };
|
||||
|
@ -613,8 +613,6 @@ namespace dxvk {
|
|||
|
||||
void CreateUniformBuffer();
|
||||
|
||||
void CreateSampler();
|
||||
|
||||
void CreateShaders();
|
||||
|
||||
void CreateResources();
|
||||
|
|
|
@ -298,7 +298,7 @@ namespace dxvk {
|
|||
D3D11_BUFFER_DESC bufferDesc;
|
||||
static_cast<D3D11Buffer*>(pResource)->GetDesc(&bufferDesc);
|
||||
|
||||
if (bufferDesc.MiscFlags == D3D11_RESOURCE_MISC_BUFFER_STRUCTURED) {
|
||||
if (bufferDesc.MiscFlags & D3D11_RESOURCE_MISC_BUFFER_STRUCTURED) {
|
||||
pDesc->Format = DXGI_FORMAT_UNKNOWN;
|
||||
pDesc->ViewDimension = D3D11_SRV_DIMENSION_BUFFER;
|
||||
pDesc->Buffer.FirstElement = 0;
|
||||
|
|
|
@ -214,7 +214,7 @@ namespace dxvk {
|
|||
D3D11_BUFFER_DESC bufferDesc;
|
||||
static_cast<D3D11Buffer*>(pResource)->GetDesc(&bufferDesc);
|
||||
|
||||
if (bufferDesc.MiscFlags == D3D11_RESOURCE_MISC_BUFFER_STRUCTURED) {
|
||||
if (bufferDesc.MiscFlags & D3D11_RESOURCE_MISC_BUFFER_STRUCTURED) {
|
||||
pDesc->Format = DXGI_FORMAT_UNKNOWN;
|
||||
pDesc->ViewDimension = D3D11_UAV_DIMENSION_BUFFER;
|
||||
pDesc->Buffer.FirstElement = 0;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -162,6 +162,9 @@ namespace dxvk {
|
|||
if (mapping.FormatSrgb == VK_FORMAT_UNDEFINED && srgb)
|
||||
return D3DERR_NOTAVAILABLE;
|
||||
|
||||
if (RType == D3DRTYPE_CUBETEXTURE && mapping.Aspect != VK_IMAGE_ASPECT_COLOR_BIT)
|
||||
return D3DERR_NOTAVAILABLE;
|
||||
|
||||
if (RType == D3DRTYPE_VERTEXBUFFER || RType == D3DRTYPE_INDEXBUFFER)
|
||||
return D3D_OK;
|
||||
|
||||
|
@ -224,11 +227,15 @@ namespace dxvk {
|
|||
if (!IsDepthFormat(DepthStencilFormat))
|
||||
return D3DERR_NOTAVAILABLE;
|
||||
|
||||
auto dsfMapping = ConvertFormatUnfixed(DepthStencilFormat);
|
||||
if (dsfMapping.FormatColor == VK_FORMAT_UNDEFINED)
|
||||
return D3DERR_NOTAVAILABLE;
|
||||
|
||||
if (RenderTargetFormat == dxvk::D3D9Format::NULL_FORMAT)
|
||||
return D3D_OK;
|
||||
|
||||
auto mapping = ConvertFormatUnfixed(RenderTargetFormat);
|
||||
if (mapping.FormatColor == VK_FORMAT_UNDEFINED)
|
||||
auto rtfMapping = ConvertFormatUnfixed(RenderTargetFormat);
|
||||
if (rtfMapping.FormatColor == VK_FORMAT_UNDEFINED)
|
||||
return D3DERR_NOTAVAILABLE;
|
||||
|
||||
return D3D_OK;
|
||||
|
@ -788,7 +795,8 @@ namespace dxvk {
|
|||
// Fix up the D3DFORMAT to match what we are enumerating
|
||||
mode.Format = static_cast<D3DFORMAT>(Format);
|
||||
|
||||
m_modes.push_back(mode);
|
||||
if (std::count(m_modes.begin(), m_modes.end(), mode) == 0)
|
||||
m_modes.push_back(mode);
|
||||
}
|
||||
|
||||
// Sort display modes by width, height and refresh rate,
|
||||
|
|
|
@ -32,6 +32,10 @@ namespace dxvk {
|
|||
m_device->m_implicitSwapchain->SetApiName(name);
|
||||
}
|
||||
|
||||
void DxvkD3D8Bridge::SetD3D8CompatibilityMode(const bool compatMode) {
|
||||
m_device->SetD3D8CompatibilityMode(compatMode);
|
||||
}
|
||||
|
||||
HRESULT DxvkD3D8Bridge::UpdateTextureFromBuffer(
|
||||
IDirect3DSurface9* pDestSurface,
|
||||
IDirect3DSurface9* pSrcSurface,
|
||||
|
@ -104,4 +108,4 @@ namespace dxvk {
|
|||
const Config* DxvkD3D8InterfaceBridge::GetConfig() const {
|
||||
return &m_interface->GetInstance()->config();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -30,6 +30,13 @@ IDxvkD3D8Bridge : public IUnknown {
|
|||
*/
|
||||
virtual void SetAPIName(const char* name) = 0;
|
||||
|
||||
/**
|
||||
* \brief Enables or disables D3D9-specific device features and validations
|
||||
*
|
||||
* \param [in] compatibility state
|
||||
*/
|
||||
virtual void SetD3D8CompatibilityMode(const bool compatMode) = 0;
|
||||
|
||||
/**
|
||||
* \brief Updates a D3D9 surface from a D3D9 buffer
|
||||
*
|
||||
|
@ -58,10 +65,7 @@ IDxvkD3D8InterfaceBridge : public IUnknown {
|
|||
virtual const dxvk::Config* GetConfig() const = 0;
|
||||
};
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
struct DECLSPEC_UUID("D3D9D3D8-42A9-4C1E-AA97-BEEFCAFE2000") IDxvkD3D8Bridge;
|
||||
struct DECLSPEC_UUID("D3D9D3D8-A407-773E-18E9-CAFEBEEF3000") IDxvkD3D8InterfaceBridge;
|
||||
#else
|
||||
#ifndef _MSC_VER
|
||||
__CRT_UUID_DECL(IDxvkD3D8Bridge, 0xD3D9D3D8, 0x42A9, 0x4C1E, 0xAA, 0x97, 0xBE, 0xEF, 0xCA, 0xFE, 0x20, 0x00);
|
||||
__CRT_UUID_DECL(IDxvkD3D8InterfaceBridge, 0xD3D9D3D8, 0xA407, 0x773E, 0x18, 0xE9, 0xCA, 0xFE, 0xBE, 0xEF, 0x30, 0x00);
|
||||
#endif
|
||||
|
@ -83,6 +87,7 @@ namespace dxvk {
|
|||
void** ppvObject);
|
||||
|
||||
void SetAPIName(const char* name);
|
||||
void SetD3D8CompatibilityMode(const bool compatMode);
|
||||
|
||||
HRESULT UpdateTextureFromBuffer(
|
||||
IDirect3DSurface9* pDestSurface,
|
||||
|
|
|
@ -125,7 +125,12 @@ namespace dxvk {
|
|||
|
||||
template <D3D9_COMMON_BUFFER_TYPE Type>
|
||||
inline DxvkBufferSlice GetBufferSlice(VkDeviceSize offset, VkDeviceSize length) const {
|
||||
return DxvkBufferSlice(GetBuffer<Type>(), offset, length);
|
||||
if (likely(length && offset < m_desc.Size)) {
|
||||
return DxvkBufferSlice(GetBuffer<Type>(), offset,
|
||||
std::min<VkDeviceSize>(m_desc.Size - offset, length));
|
||||
}
|
||||
|
||||
return DxvkBufferSlice();
|
||||
}
|
||||
|
||||
inline DxvkBufferSliceHandle AllocMapSlice() {
|
||||
|
@ -206,6 +211,10 @@ namespace dxvk {
|
|||
: DxvkCsThread::SynchronizeAll;
|
||||
}
|
||||
|
||||
bool IsSysmemDynamic() const {
|
||||
return m_desc.Pool == D3DPOOL_SYSTEMMEM && (m_desc.Usage & D3DUSAGE_DYNAMIC) != 0;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
Rc<DxvkBuffer> CreateBuffer() const;
|
||||
|
|
|
@ -31,11 +31,12 @@ namespace dxvk {
|
|||
AddDirtyBox(nullptr, i);
|
||||
}
|
||||
|
||||
if (m_desc.Pool != D3DPOOL_DEFAULT) {
|
||||
if (m_desc.Pool != D3DPOOL_DEFAULT && pSharedHandle) {
|
||||
throw DxvkError("D3D9: Incompatible pool type for texture sharing.");
|
||||
}
|
||||
|
||||
if (IsPoolManaged(m_desc.Pool)) {
|
||||
SetAllNeedUpload();
|
||||
if (pSharedHandle) {
|
||||
throw DxvkError("D3D9: Incompatible pool type for texture sharing.");
|
||||
}
|
||||
}
|
||||
|
||||
m_mapping = pDevice->LookupFormat(m_desc.Format);
|
||||
|
@ -117,6 +118,7 @@ namespace dxvk {
|
|||
|
||||
HRESULT D3D9CommonTexture::NormalizeTextureProperties(
|
||||
D3D9DeviceEx* pDevice,
|
||||
D3DRESOURCETYPE ResourceType,
|
||||
D3D9_COMMON_TEXTURE_DESC* pDesc) {
|
||||
auto* options = pDevice->GetOptions();
|
||||
|
||||
|
@ -130,6 +132,11 @@ namespace dxvk {
|
|||
options->disableA8RT)
|
||||
return D3DERR_INVALIDCALL;
|
||||
|
||||
// Cube textures with depth formats are not supported on any native
|
||||
// driver, and allowing them triggers a broken code path in Gothic 3.
|
||||
if (ResourceType == D3DRTYPE_CUBETEXTURE && mapping.Aspect != VK_IMAGE_ASPECT_COLOR_BIT)
|
||||
return D3DERR_INVALIDCALL;
|
||||
|
||||
// If the mapping is invalid then lets return invalid
|
||||
// Some edge cases:
|
||||
// NULL format does not map to anything, but should succeed
|
||||
|
|
|
@ -179,11 +179,14 @@ namespace dxvk {
|
|||
* Fills in undefined values and validates the texture
|
||||
* parameters. Any error returned by this method should
|
||||
* be forwarded to the application.
|
||||
* \param [in] pDevice D3D9 device
|
||||
* \param [in] ResourceType Resource type
|
||||
* \param [in,out] pDesc Texture description
|
||||
* \returns \c S_OK if the parameters are valid
|
||||
*/
|
||||
static HRESULT NormalizeTextureProperties(
|
||||
D3D9DeviceEx* pDevice,
|
||||
D3DRESOURCETYPE ResourceType,
|
||||
D3D9_COMMON_TEXTURE_DESC* pDesc);
|
||||
|
||||
/**
|
||||
|
|
|
@ -13,7 +13,7 @@ namespace dxvk {
|
|||
DxsoProgramType ShaderStage,
|
||||
DxsoConstantBuffers BufferType,
|
||||
VkDeviceSize Size)
|
||||
: D3D9ConstantBuffer(pDevice, getBufferUsage(pDevice, ShaderStage, BufferType), GetShaderStage(ShaderStage),
|
||||
: D3D9ConstantBuffer(pDevice, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, GetShaderStage(ShaderStage),
|
||||
computeResourceSlotId(ShaderStage, DxsoBindingType::ConstantBuffer, BufferType),
|
||||
Size) {
|
||||
|
||||
|
@ -135,21 +135,4 @@ namespace dxvk {
|
|||
device->properties().extRobustness2.robustUniformBufferAccessSizeAlignment);
|
||||
}
|
||||
|
||||
|
||||
VkBufferUsageFlags D3D9ConstantBuffer::getBufferUsage(
|
||||
D3D9DeviceEx* pDevice,
|
||||
DxsoProgramType ShaderStage,
|
||||
DxsoConstantBuffers BufferType) {
|
||||
VkBufferUsageFlags result = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT;
|
||||
|
||||
// We won't always need this, but the only buffer that
|
||||
// this applies to is so large that it will not matter.
|
||||
if (pDevice->CanSWVP()
|
||||
&& ShaderStage == DxsoProgramType::VertexShader
|
||||
&& BufferType == DxsoConstantBuffers::VSConstantBuffer)
|
||||
result |= VK_BUFFER_USAGE_STORAGE_BUFFER_BIT;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -80,11 +80,6 @@ namespace dxvk {
|
|||
|
||||
VkDeviceSize getAlignment(const Rc<DxvkDevice>& device) const;
|
||||
|
||||
static VkBufferUsageFlags getBufferUsage(
|
||||
D3D9DeviceEx* pDevice,
|
||||
DxsoProgramType ShaderStage,
|
||||
DxsoConstantBuffers BufferType);
|
||||
|
||||
};
|
||||
|
||||
}
|
|
@ -56,6 +56,7 @@ namespace dxvk {
|
|||
, m_csThread ( dxvkDevice, dxvkDevice->createContext(DxvkContextType::Primary) )
|
||||
, m_csChunk ( AllocCsChunk() )
|
||||
, m_submissionFence (new sync::Fence())
|
||||
, m_flushTracker (m_d3d9Options.reproducibleCommandStream)
|
||||
, m_d3d9Interop ( this )
|
||||
, m_d3d9On12 ( this )
|
||||
, m_d3d8Bridge ( this ) {
|
||||
|
@ -455,6 +456,8 @@ namespace dxvk {
|
|||
SetDepthStencilSurface(nullptr);
|
||||
}
|
||||
|
||||
m_flags.clr(D3D9DeviceFlag::InScene);
|
||||
|
||||
/*
|
||||
* Before calling the IDirect3DDevice9::Reset method for a device,
|
||||
* an application should release any explicit render targets,
|
||||
|
@ -464,7 +467,7 @@ namespace dxvk {
|
|||
* We have to check after ResetState clears the references held by SetTexture, etc.
|
||||
* This matches what Windows D3D9 does.
|
||||
*/
|
||||
if (unlikely(m_losableResourceCounter.load() != 0 && !IsExtended())) {
|
||||
if (unlikely(m_losableResourceCounter.load() != 0 && !IsExtended() && m_d3d9Options.countLosableResources)) {
|
||||
Logger::warn(str::format("Device reset failed because device still has alive losable resources: Device not reset. Remaining resources: ", m_losableResourceCounter.load()));
|
||||
m_deviceLostState = D3D9DeviceLostState::NotReset;
|
||||
return D3DERR_INVALIDCALL;
|
||||
|
@ -479,9 +482,20 @@ namespace dxvk {
|
|||
return hr;
|
||||
}
|
||||
|
||||
// Unbind all buffers that were still bound to the backend to avoid leaks.
|
||||
EmitCs([](DxvkContext* ctx) {
|
||||
ctx->bindIndexBuffer(DxvkBufferSlice(), VK_INDEX_TYPE_UINT32);
|
||||
for (uint32_t i = 0; i < caps::MaxStreams; i++) {
|
||||
ctx->bindVertexBuffer(i, DxvkBufferSlice(), 0);
|
||||
}
|
||||
});
|
||||
|
||||
Flush();
|
||||
SynchronizeCsThread(DxvkCsThread::SynchronizeAll);
|
||||
|
||||
if (m_d3d9Options.deferSurfaceCreation)
|
||||
m_deviceHasBeenReset = true;
|
||||
|
||||
return D3D_OK;
|
||||
}
|
||||
|
||||
|
@ -581,7 +595,7 @@ namespace dxvk {
|
|||
|| (Usage & D3DUSAGE_DYNAMIC)
|
||||
|| IsVendorFormat(EnumerateFormat(Format));
|
||||
|
||||
if (FAILED(D3D9CommonTexture::NormalizeTextureProperties(this, &desc)))
|
||||
if (FAILED(D3D9CommonTexture::NormalizeTextureProperties(this, D3DRTYPE_TEXTURE, &desc)))
|
||||
return D3DERR_INVALIDCALL;
|
||||
|
||||
try {
|
||||
|
@ -651,7 +665,7 @@ namespace dxvk {
|
|||
|| (Usage & D3DUSAGE_DYNAMIC)
|
||||
|| IsVendorFormat(EnumerateFormat(Format));
|
||||
|
||||
if (FAILED(D3D9CommonTexture::NormalizeTextureProperties(this, &desc)))
|
||||
if (FAILED(D3D9CommonTexture::NormalizeTextureProperties(this, D3DRTYPE_VOLUMETEXTURE, &desc)))
|
||||
return D3DERR_INVALIDCALL;
|
||||
|
||||
try {
|
||||
|
@ -708,7 +722,7 @@ namespace dxvk {
|
|||
|| (Usage & D3DUSAGE_DYNAMIC)
|
||||
|| IsVendorFormat(EnumerateFormat(Format));
|
||||
|
||||
if (FAILED(D3D9CommonTexture::NormalizeTextureProperties(this, &desc)))
|
||||
if (FAILED(D3D9CommonTexture::NormalizeTextureProperties(this, D3DRTYPE_CUBETEXTURE, &desc)))
|
||||
return D3DERR_INVALIDCALL;
|
||||
|
||||
try {
|
||||
|
@ -1034,6 +1048,9 @@ namespace dxvk {
|
|||
if (srcTexInfo->Desc()->Format != dstTexInfo->Desc()->Format)
|
||||
return D3DERR_INVALIDCALL;
|
||||
|
||||
if (src->GetSurfaceExtent() != dst->GetSurfaceExtent())
|
||||
return D3DERR_INVALIDCALL;
|
||||
|
||||
if (dstTexInfo->Desc()->Pool == D3DPOOL_DEFAULT)
|
||||
return this->StretchRect(pRenderTarget, nullptr, pDestSurface, nullptr, D3DTEXF_NONE);
|
||||
|
||||
|
@ -1077,7 +1094,12 @@ namespace dxvk {
|
|||
if (unlikely(iSwapChain != 0))
|
||||
return D3DERR_INVALIDCALL;
|
||||
|
||||
return m_implicitSwapchain->GetFrontBufferData(pDestSurface);
|
||||
D3D9DeviceLock lock = LockDevice();
|
||||
|
||||
// In windowed mode, GetFrontBufferData takes a screenshot of the entire screen.
|
||||
// We use the last used swapchain as a workaround.
|
||||
// Total War: Medieval 2 relies on this.
|
||||
return m_mostRecentlyUsedSwapchain->GetFrontBufferData(pDestSurface);
|
||||
}
|
||||
|
||||
|
||||
|
@ -1595,6 +1617,23 @@ namespace dxvk {
|
|||
|
||||
m_flags.clr(D3D9DeviceFlag::InScene);
|
||||
|
||||
// D3D9 resets the internally bound vertex buffers and index buffer in EndScene if they were unbound in the meantime.
|
||||
// We have to ignore unbinding those buffers because of Operation Flashpoint Red River,
|
||||
// so we should also clear the bindings here, to avoid leaks.
|
||||
if (m_state.indices == nullptr) {
|
||||
EmitCs([](DxvkContext* ctx) {
|
||||
ctx->bindIndexBuffer(DxvkBufferSlice(), VK_INDEX_TYPE_UINT32);
|
||||
});
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < caps::MaxStreams; i++) {
|
||||
if (m_state.vertexBuffers[i].vertexBuffer == nullptr) {
|
||||
EmitCs([cIndex = i](DxvkContext* ctx) {
|
||||
ctx->bindVertexBuffer(cIndex, DxvkBufferSlice(), 0);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return D3D_OK;
|
||||
}
|
||||
|
||||
|
@ -2360,7 +2399,8 @@ namespace dxvk {
|
|||
try {
|
||||
const Com<D3D9StateBlock> sb = new D3D9StateBlock(this, ConvertStateBlockType(Type));
|
||||
*ppSB = sb.ref();
|
||||
m_losableResourceCounter++;
|
||||
if (!m_isD3D8Compatible)
|
||||
m_losableResourceCounter++;
|
||||
|
||||
return D3D_OK;
|
||||
}
|
||||
|
@ -2392,7 +2432,8 @@ namespace dxvk {
|
|||
return D3DERR_INVALIDCALL;
|
||||
|
||||
*ppSB = m_recorder.ref();
|
||||
m_losableResourceCounter++;
|
||||
if (!m_isD3D8Compatible)
|
||||
m_losableResourceCounter++;
|
||||
m_recorder = nullptr;
|
||||
|
||||
return D3D_OK;
|
||||
|
@ -2610,7 +2651,21 @@ namespace dxvk {
|
|||
if (unlikely(!PrimitiveCount))
|
||||
return S_OK;
|
||||
|
||||
PrepareDraw(PrimitiveType);
|
||||
bool dynamicSysmemVBOs;
|
||||
uint32_t firstIndex = 0;
|
||||
int32_t baseVertexIndex = 0;
|
||||
uint32_t vertexCount = GetVertexCount(PrimitiveType, PrimitiveCount);
|
||||
UploadDynamicSysmemBuffers(
|
||||
StartVertex,
|
||||
vertexCount,
|
||||
firstIndex,
|
||||
0,
|
||||
baseVertexIndex,
|
||||
&dynamicSysmemVBOs,
|
||||
nullptr
|
||||
);
|
||||
|
||||
PrepareDraw(PrimitiveType, !dynamicSysmemVBOs, false);
|
||||
|
||||
EmitCs([this,
|
||||
cPrimType = PrimitiveType,
|
||||
|
@ -2631,7 +2686,6 @@ namespace dxvk {
|
|||
return D3D_OK;
|
||||
}
|
||||
|
||||
|
||||
HRESULT STDMETHODCALLTYPE D3D9DeviceEx::DrawIndexedPrimitive(
|
||||
D3DPRIMITIVETYPE PrimitiveType,
|
||||
INT BaseVertexIndex,
|
||||
|
@ -2647,7 +2701,20 @@ namespace dxvk {
|
|||
if (unlikely(!PrimitiveCount))
|
||||
return S_OK;
|
||||
|
||||
PrepareDraw(PrimitiveType);
|
||||
bool dynamicSysmemVBOs;
|
||||
bool dynamicSysmemIBO;
|
||||
uint32_t indexCount = GetVertexCount(PrimitiveType, PrimitiveCount);
|
||||
UploadDynamicSysmemBuffers(
|
||||
MinVertexIndex,
|
||||
NumVertices,
|
||||
StartIndex,
|
||||
indexCount,
|
||||
BaseVertexIndex,
|
||||
&dynamicSysmemVBOs,
|
||||
&dynamicSysmemIBO
|
||||
);
|
||||
|
||||
PrepareDraw(PrimitiveType, !dynamicSysmemVBOs, !dynamicSysmemIBO);
|
||||
|
||||
EmitCs([this,
|
||||
cPrimType = PrimitiveType,
|
||||
|
@ -2683,7 +2750,7 @@ namespace dxvk {
|
|||
if (unlikely(!PrimitiveCount))
|
||||
return S_OK;
|
||||
|
||||
PrepareDraw(PrimitiveType);
|
||||
PrepareDraw(PrimitiveType, false, false);
|
||||
|
||||
uint32_t vertexCount = GetVertexCount(PrimitiveType, PrimitiveCount);
|
||||
|
||||
|
@ -2735,7 +2802,7 @@ namespace dxvk {
|
|||
if (unlikely(!PrimitiveCount))
|
||||
return S_OK;
|
||||
|
||||
PrepareDraw(PrimitiveType);
|
||||
PrepareDraw(PrimitiveType, false, false);
|
||||
|
||||
uint32_t vertexCount = GetVertexCount(PrimitiveType, PrimitiveCount);
|
||||
|
||||
|
@ -2822,7 +2889,7 @@ namespace dxvk {
|
|||
D3D9CommonBuffer* dst = static_cast<D3D9VertexBuffer*>(pDestBuffer)->GetCommonBuffer();
|
||||
D3D9VertexDecl* decl = static_cast<D3D9VertexDecl*> (pVertexDecl);
|
||||
|
||||
PrepareDraw(D3DPT_FORCE_DWORD);
|
||||
PrepareDraw(D3DPT_FORCE_DWORD, true, true);
|
||||
|
||||
if (decl == nullptr) {
|
||||
DWORD FVF = dst->Desc()->FVF;
|
||||
|
@ -2837,7 +2904,7 @@ namespace dxvk {
|
|||
decl = iter->second.ptr();
|
||||
}
|
||||
|
||||
uint32_t offset = DestIndex * decl->GetSize();
|
||||
uint32_t offset = DestIndex * decl->GetSize(0);
|
||||
|
||||
auto slice = dst->GetBufferSlice<D3D9_COMMON_BUFFER_TYPE_REAL>();
|
||||
slice = slice.subSlice(offset, slice.length() - offset);
|
||||
|
@ -2884,7 +2951,7 @@ namespace dxvk {
|
|||
}
|
||||
|
||||
if (dst->GetMapMode() == D3D9_COMMON_BUFFER_MAP_MODE_BUFFER) {
|
||||
uint32_t copySize = VertexCount * decl->GetSize();
|
||||
uint32_t copySize = VertexCount * decl->GetSize(0);
|
||||
|
||||
EmitCs([
|
||||
cSrcBuffer = dst->GetBuffer<D3D9_COMMON_BUFFER_TYPE_REAL>(),
|
||||
|
@ -3220,6 +3287,11 @@ namespace dxvk {
|
|||
|
||||
vbo.offset = OffsetInBytes;
|
||||
vbo.stride = Stride;
|
||||
} else {
|
||||
// D3D9 doesn't actually unbind any vertex buffer when passing null.
|
||||
// Operation Flashpoint: Red River relies on this behavior.
|
||||
needsUpdate = false;
|
||||
vbo.offset = 0;
|
||||
}
|
||||
|
||||
if (needsUpdate)
|
||||
|
@ -3325,7 +3397,8 @@ namespace dxvk {
|
|||
|
||||
m_state.indices = buffer;
|
||||
|
||||
BindIndices();
|
||||
if (buffer != nullptr)
|
||||
BindIndices();
|
||||
|
||||
return D3D_OK;
|
||||
}
|
||||
|
@ -3726,7 +3799,7 @@ namespace dxvk {
|
|||
desc.IsAttachmentOnly = TRUE;
|
||||
desc.IsLockable = Lockable;
|
||||
|
||||
if (FAILED(D3D9CommonTexture::NormalizeTextureProperties(this, &desc)))
|
||||
if (FAILED(D3D9CommonTexture::NormalizeTextureProperties(this, D3DRTYPE_TEXTURE, &desc)))
|
||||
return D3DERR_INVALIDCALL;
|
||||
|
||||
try {
|
||||
|
@ -3774,7 +3847,7 @@ namespace dxvk {
|
|||
// Docs: Off-screen plain surfaces are always lockable, regardless of their pool types.
|
||||
desc.IsLockable = TRUE;
|
||||
|
||||
if (FAILED(D3D9CommonTexture::NormalizeTextureProperties(this, &desc)))
|
||||
if (FAILED(D3D9CommonTexture::NormalizeTextureProperties(this, D3DRTYPE_TEXTURE, &desc)))
|
||||
return D3DERR_INVALIDCALL;
|
||||
|
||||
if (pSharedHandle != nullptr && Pool != D3DPOOL_DEFAULT)
|
||||
|
@ -3829,7 +3902,7 @@ namespace dxvk {
|
|||
// Docs don't say anything, so just assume it's lockable.
|
||||
desc.IsLockable = TRUE;
|
||||
|
||||
if (FAILED(D3D9CommonTexture::NormalizeTextureProperties(this, &desc)))
|
||||
if (FAILED(D3D9CommonTexture::NormalizeTextureProperties(this, D3DRTYPE_TEXTURE, &desc)))
|
||||
return D3DERR_INVALIDCALL;
|
||||
|
||||
try {
|
||||
|
@ -5087,6 +5160,191 @@ namespace dxvk {
|
|||
}
|
||||
|
||||
|
||||
|
||||
void D3D9DeviceEx::UploadDynamicSysmemBuffers(
|
||||
UINT& FirstVertexIndex,
|
||||
UINT NumVertices,
|
||||
UINT& FirstIndex,
|
||||
UINT NumIndices,
|
||||
INT& BaseVertexIndex,
|
||||
bool* pDynamicVBOs,
|
||||
bool* pDynamicIBO
|
||||
) {
|
||||
bool dynamicSysmemVBOs = true;
|
||||
for (uint32_t i = 0; i < caps::MaxStreams && dynamicSysmemVBOs; i++) {
|
||||
auto* vbo = GetCommonBuffer(m_state.vertexBuffers[i].vertexBuffer);
|
||||
dynamicSysmemVBOs &= vbo == nullptr || vbo->IsSysmemDynamic();
|
||||
}
|
||||
D3D9CommonBuffer* ibo = GetCommonBuffer(m_state.indices);
|
||||
bool dynamicSysmemIBO = NumIndices != 0 && ibo != nullptr && ibo->IsSysmemDynamic();
|
||||
|
||||
*pDynamicVBOs = dynamicSysmemVBOs;
|
||||
|
||||
if (pDynamicIBO)
|
||||
*pDynamicIBO = dynamicSysmemIBO;
|
||||
|
||||
if (likely(!dynamicSysmemVBOs && !dynamicSysmemIBO))
|
||||
return;
|
||||
|
||||
// The UP buffer allocator will invalidate,
|
||||
// so we can only use 1 UP buffer slice per draw.
|
||||
// First we calculate the size of that UP buffer slice
|
||||
// and store all sizes and offsets into it.
|
||||
|
||||
struct VBOCopy {
|
||||
uint32_t srcOffset;
|
||||
uint32_t dstOffset;
|
||||
uint32_t copyBufferLength;
|
||||
uint32_t copyElementCount;
|
||||
uint32_t copyElementSize;
|
||||
uint32_t copyElementStride;
|
||||
};
|
||||
uint32_t totalUpBufferSize = 0;
|
||||
std::array<VBOCopy, caps::MaxStreams> vboCopies = {};
|
||||
|
||||
for (uint32_t i = 0; i < caps::MaxStreams && dynamicSysmemVBOs; i++) {
|
||||
auto* vbo = GetCommonBuffer(m_state.vertexBuffers[i].vertexBuffer);
|
||||
if (likely(vbo == nullptr)) {
|
||||
continue;
|
||||
}
|
||||
const uint32_t vertexSize = m_state.vertexDecl->GetSize(i);
|
||||
const uint32_t vertexStride = m_state.vertexBuffers[i].stride;
|
||||
const uint32_t srcStride = vertexStride;
|
||||
const uint32_t dstStride = std::min(vertexStride, vertexSize);
|
||||
|
||||
uint32_t elementCount = NumVertices;
|
||||
if (m_state.streamFreq[i] & D3DSTREAMSOURCE_INSTANCEDATA) {
|
||||
elementCount = GetInstanceCount();
|
||||
}
|
||||
const uint32_t vboOffset = m_state.vertexBuffers[i].offset;
|
||||
const uint32_t vertexOffset = (FirstVertexIndex + BaseVertexIndex) * srcStride;
|
||||
const uint32_t vertexBufferSize = vbo->Desc()->Size;
|
||||
const uint32_t srcOffset = vboOffset + vertexOffset;
|
||||
|
||||
if (unlikely(srcOffset > vertexBufferSize)) {
|
||||
// All vertices are out of bounds
|
||||
vboCopies[i].copyBufferLength = 0;
|
||||
} else if (unlikely(srcOffset + elementCount * srcStride > vertexBufferSize)) {
|
||||
// Some vertices are (partially) out of bounds
|
||||
uint32_t boundVertexBufferRange = vertexBufferSize - vboOffset;
|
||||
elementCount = boundVertexBufferRange / srcStride;
|
||||
// Copy all complete vertices
|
||||
vboCopies[i].copyBufferLength = elementCount * dstStride;
|
||||
// Copy the remaining partial vertex
|
||||
vboCopies[i].copyBufferLength += std::min(dstStride, boundVertexBufferRange % srcStride);
|
||||
} else {
|
||||
// No vertices are out of bounds
|
||||
vboCopies[i].copyBufferLength = elementCount * dstStride;
|
||||
}
|
||||
|
||||
vboCopies[i].copyElementCount = elementCount;
|
||||
vboCopies[i].copyElementStride = srcStride;
|
||||
vboCopies[i].copyElementSize = dstStride;
|
||||
vboCopies[i].srcOffset = srcOffset;
|
||||
vboCopies[i].dstOffset = totalUpBufferSize;
|
||||
totalUpBufferSize += vboCopies[i].copyBufferLength;
|
||||
}
|
||||
|
||||
uint32_t iboUPBufferSize = 0;
|
||||
uint32_t iboUPBufferOffset = 0;
|
||||
if (dynamicSysmemIBO) {
|
||||
auto* ibo = GetCommonBuffer(m_state.indices);
|
||||
if (likely(ibo != nullptr)) {
|
||||
uint32_t indexStride = ibo->Desc()->Format == D3D9Format::INDEX16 ? 2 : 4;
|
||||
uint32_t offset = indexStride * FirstIndex;
|
||||
uint32_t indexBufferSize = ibo->Desc()->Size;
|
||||
if (offset < indexBufferSize) {
|
||||
iboUPBufferSize = std::min(NumIndices * indexStride, indexBufferSize - offset);
|
||||
iboUPBufferOffset = totalUpBufferSize;
|
||||
totalUpBufferSize += iboUPBufferSize;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (unlikely(totalUpBufferSize == 0)) {
|
||||
*pDynamicVBOs = false;
|
||||
if (pDynamicIBO)
|
||||
*pDynamicIBO = false;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
auto upSlice = AllocUPBuffer(totalUpBufferSize);
|
||||
|
||||
// Now copy the actual data and bind it.
|
||||
for (uint32_t i = 0; i < caps::MaxStreams && dynamicSysmemVBOs; i++) {
|
||||
const VBOCopy& copy = vboCopies[i];
|
||||
|
||||
if (likely(copy.copyBufferLength != 0)) {
|
||||
const auto* vbo = GetCommonBuffer(m_state.vertexBuffers[i].vertexBuffer);
|
||||
uint8_t* data = reinterpret_cast<uint8_t*>(upSlice.mapPtr) + copy.dstOffset;
|
||||
const uint8_t* src = reinterpret_cast<uint8_t*>(vbo->GetMappedSlice().mapPtr) + copy.srcOffset;
|
||||
|
||||
if (likely(copy.copyElementStride == copy.copyElementSize)) {
|
||||
std::memcpy(data, src, copy.copyBufferLength);
|
||||
} else {
|
||||
for (uint32_t j = 0; j < copy.copyElementCount; j++) {
|
||||
std::memcpy(data + j * copy.copyElementSize, src + j * copy.copyElementStride, copy.copyElementSize);
|
||||
}
|
||||
if (unlikely(copy.copyBufferLength > copy.copyElementCount * copy.copyElementSize)) {
|
||||
// Partial vertex at the end
|
||||
std::memcpy(
|
||||
data + copy.copyElementCount * copy.copyElementSize,
|
||||
src + copy.copyElementCount * copy.copyElementStride,
|
||||
copy.copyBufferLength - copy.copyElementCount * copy.copyElementSize);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto vboSlice = upSlice.slice.subSlice(copy.dstOffset, copy.copyBufferLength);
|
||||
EmitCs([
|
||||
cStream = i,
|
||||
cBufferSlice = std::move(vboSlice),
|
||||
cStride = copy.copyElementSize
|
||||
](DxvkContext* ctx) mutable {
|
||||
ctx->bindVertexBuffer(cStream, std::move(cBufferSlice), cStride);
|
||||
});
|
||||
m_flags.set(D3D9DeviceFlag::DirtyVertexBuffers);
|
||||
}
|
||||
|
||||
// Change the draw call parameters to reflect the changed vertex buffers
|
||||
if (NumIndices != 0) {
|
||||
BaseVertexIndex = -FirstVertexIndex;
|
||||
} else {
|
||||
FirstVertexIndex = 0;
|
||||
}
|
||||
|
||||
if (dynamicSysmemIBO) {
|
||||
if (unlikely(iboUPBufferSize == 0)) {
|
||||
EmitCs([](DxvkContext* ctx) {
|
||||
ctx->bindIndexBuffer(DxvkBufferSlice(), VK_INDEX_TYPE_UINT32);
|
||||
});
|
||||
m_flags.set(D3D9DeviceFlag::DirtyIndexBuffer);
|
||||
} else {
|
||||
auto* ibo = GetCommonBuffer(m_state.indices);
|
||||
uint32_t indexStride = ibo->Desc()->Format == D3D9Format::INDEX16 ? 2 : 4;
|
||||
VkIndexType indexType = DecodeIndexType(ibo->Desc()->Format);
|
||||
uint32_t offset = indexStride * FirstIndex;
|
||||
uint8_t* data = reinterpret_cast<uint8_t*>(upSlice.mapPtr) + iboUPBufferOffset;
|
||||
uint8_t* src = reinterpret_cast<uint8_t*>(ibo->GetMappedSlice().mapPtr) + offset;
|
||||
std::memcpy(data, src, iboUPBufferSize);
|
||||
|
||||
auto iboSlice = upSlice.slice.subSlice(iboUPBufferOffset, iboUPBufferSize);
|
||||
EmitCs([
|
||||
cBufferSlice = std::move(iboSlice),
|
||||
cIndexType = indexType
|
||||
](DxvkContext* ctx) mutable {
|
||||
ctx->bindIndexBuffer(std::move(cBufferSlice), cIndexType);
|
||||
});
|
||||
m_flags.set(D3D9DeviceFlag::DirtyIndexBuffer);
|
||||
}
|
||||
|
||||
// Change the draw call parameters to reflect the changed index buffer
|
||||
FirstIndex = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void D3D9DeviceEx::EmitCsChunk(DxvkCsChunkRef&& chunk) {
|
||||
m_csSeqNum = m_csThread.dispatchChunk(std::move(chunk));
|
||||
}
|
||||
|
@ -5133,7 +5391,7 @@ namespace dxvk {
|
|||
|
||||
// Round to nearest
|
||||
_controlfp(_RC_NEAR, _MCW_RC);
|
||||
#elif (defined(__GNUC__) || defined(__MINGW32__)) && (defined(__i386__) || defined(__x86_64__) || defined(__ia64))
|
||||
#elif (defined(__GNUC__) || defined(__MINGW32__)) && (defined(__i386__) || (defined(__x86_64__) && !defined(__arm64ec__)) || defined(__ia64))
|
||||
// For GCC/MinGW we can use inline asm to set it.
|
||||
// This only works for x86 and x64 processors however.
|
||||
|
||||
|
@ -5255,7 +5513,7 @@ namespace dxvk {
|
|||
uint32_t floatCount = m_vsFloatConstsCount;
|
||||
if (constSet.meta.needsConstantCopies) {
|
||||
auto shader = GetCommonShader(m_state.vertexShader);
|
||||
floatCount = std::max(floatCount, shader->GetMaxDefinedConstant());
|
||||
floatCount = std::max(floatCount, shader->GetMaxDefinedConstant() + 1);
|
||||
}
|
||||
floatCount = std::min(floatCount, constSet.meta.maxConstIndexF);
|
||||
|
||||
|
@ -5317,7 +5575,7 @@ namespace dxvk {
|
|||
uint32_t floatCount = ShaderStage == DxsoProgramType::VertexShader ? m_vsFloatConstsCount : m_psFloatConstsCount;
|
||||
if (constSet.meta.needsConstantCopies) {
|
||||
auto shader = GetCommonShader(Shader);
|
||||
floatCount = std::max(floatCount, shader->GetMaxDefinedConstant());
|
||||
floatCount = std::max(floatCount, shader->GetMaxDefinedConstant() + 1);
|
||||
}
|
||||
floatCount = std::min(constSet.meta.maxConstIndexF, floatCount);
|
||||
|
||||
|
@ -5450,10 +5708,13 @@ namespace dxvk {
|
|||
}
|
||||
|
||||
|
||||
|
||||
void D3D9DeviceEx::Flush() {
|
||||
template <bool Synchronize9On12>
|
||||
void D3D9DeviceEx::ExecuteFlush() {
|
||||
D3D9DeviceLock lock = LockDevice();
|
||||
|
||||
if constexpr (Synchronize9On12)
|
||||
m_submitStatus.result = VK_NOT_READY;
|
||||
|
||||
m_initializer->Flush();
|
||||
m_converter->Flush();
|
||||
|
||||
|
@ -5465,16 +5726,32 @@ namespace dxvk {
|
|||
|
||||
EmitCs<false>([
|
||||
cSubmissionFence = m_submissionFence,
|
||||
cSubmissionId = submissionId
|
||||
cSubmissionId = submissionId,
|
||||
cSubmissionStatus = Synchronize9On12 ? &m_submitStatus : nullptr
|
||||
] (DxvkContext* ctx) {
|
||||
ctx->signal(cSubmissionFence, cSubmissionId);
|
||||
ctx->flushCommandList(nullptr);
|
||||
ctx->flushCommandList(cSubmissionStatus);
|
||||
});
|
||||
|
||||
FlushCsChunk();
|
||||
|
||||
m_flushSeqNum = m_csSeqNum;
|
||||
m_flushTracker.notifyFlush(m_flushSeqNum, submissionId);
|
||||
|
||||
// If necessary, block calling thread until the
|
||||
// Vulkan queue submission is performed.
|
||||
if constexpr (Synchronize9On12)
|
||||
m_dxvkDevice->waitForSubmission(&m_submitStatus);
|
||||
}
|
||||
|
||||
|
||||
void D3D9DeviceEx::Flush() {
|
||||
ExecuteFlush<false>();
|
||||
}
|
||||
|
||||
|
||||
void D3D9DeviceEx::FlushAndSync9On12() {
|
||||
ExecuteFlush<true>();
|
||||
}
|
||||
|
||||
|
||||
|
@ -6449,7 +6726,7 @@ namespace dxvk {
|
|||
}
|
||||
|
||||
|
||||
void D3D9DeviceEx::PrepareDraw(D3DPRIMITIVETYPE PrimitiveType) {
|
||||
void D3D9DeviceEx::PrepareDraw(D3DPRIMITIVETYPE PrimitiveType, bool UploadVBOs, bool UploadIBO) {
|
||||
if (unlikely(m_activeHazardsRT != 0 || m_activeHazardsDS != 0))
|
||||
MarkRenderHazards();
|
||||
|
||||
|
@ -6462,7 +6739,7 @@ namespace dxvk {
|
|||
|
||||
for (uint32_t i = 0; i < caps::MaxStreams; i++) {
|
||||
auto* vbo = GetCommonBuffer(m_state.vertexBuffers[i].vertexBuffer);
|
||||
if (vbo != nullptr && vbo->NeedsUpload())
|
||||
if (vbo != nullptr && vbo->NeedsUpload() && UploadVBOs)
|
||||
FlushBuffer(vbo);
|
||||
}
|
||||
|
||||
|
@ -6478,7 +6755,7 @@ namespace dxvk {
|
|||
GenerateTextureMips(texturesToGen);
|
||||
|
||||
auto* ibo = GetCommonBuffer(m_state.indices);
|
||||
if (ibo != nullptr && ibo->NeedsUpload())
|
||||
if (ibo != nullptr && ibo->NeedsUpload() && UploadIBO)
|
||||
FlushBuffer(ibo);
|
||||
|
||||
UpdateFog();
|
||||
|
@ -6611,6 +6888,19 @@ namespace dxvk {
|
|||
}
|
||||
|
||||
BindSpecConstants();
|
||||
|
||||
if (unlikely(m_flags.test(D3D9DeviceFlag::DirtyVertexBuffers) && UploadVBOs)) {
|
||||
for (uint32_t i = 0; i < caps::MaxStreams; i++) {
|
||||
const D3D9VBO& vbo = m_state.vertexBuffers[i];
|
||||
BindVertexBuffer(i, vbo.vertexBuffer.ptr(), vbo.offset, vbo.stride);
|
||||
}
|
||||
m_flags.clr(D3D9DeviceFlag::DirtyVertexBuffers);
|
||||
}
|
||||
|
||||
if (unlikely(m_flags.test(D3D9DeviceFlag::DirtyIndexBuffer) && UploadIBO)) {
|
||||
BindIndices();
|
||||
m_flags.clr(D3D9DeviceFlag::DirtyIndexBuffer);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -7614,8 +7904,10 @@ namespace dxvk {
|
|||
if (FAILED(hr))
|
||||
return hr;
|
||||
}
|
||||
else
|
||||
else {
|
||||
m_implicitSwapchain = new D3D9SwapChainEx(this, pPresentationParameters, pFullscreenDisplayMode);
|
||||
m_mostRecentlyUsedSwapchain = m_implicitSwapchain.ptr();
|
||||
}
|
||||
|
||||
if (pPresentationParameters->EnableAutoDepthStencil) {
|
||||
D3D9_COMMON_TEXTURE_DESC desc;
|
||||
|
@ -7635,7 +7927,7 @@ namespace dxvk {
|
|||
// Docs: Also note that - unlike textures - swap chain back buffers, render targets [..] can be locked
|
||||
desc.IsLockable = TRUE;
|
||||
|
||||
if (FAILED(D3D9CommonTexture::NormalizeTextureProperties(this, &desc)))
|
||||
if (FAILED(D3D9CommonTexture::NormalizeTextureProperties(this, D3DRTYPE_TEXTURE, &desc)))
|
||||
return D3DERR_NOTAVAILABLE;
|
||||
|
||||
m_autoDepthStencil = new D3D9Surface(this, &desc, nullptr, nullptr);
|
||||
|
|
|
@ -66,6 +66,8 @@ namespace dxvk {
|
|||
DirtyInputLayout,
|
||||
DirtyViewportScissor,
|
||||
DirtyMultiSampleState,
|
||||
DirtyVertexBuffers,
|
||||
DirtyIndexBuffer,
|
||||
|
||||
DirtyFogState,
|
||||
DirtyFogColor,
|
||||
|
@ -764,6 +766,24 @@ namespace dxvk {
|
|||
HRESULT UnlockBuffer(
|
||||
D3D9CommonBuffer* pResource);
|
||||
|
||||
/**
|
||||
* @brief Uploads data from D3DPOOL_SYSMEM + D3DUSAGE_DYNAMIC buffers and binds the temporary buffers.
|
||||
*
|
||||
* @param FirstVertexIndex The first vertex
|
||||
* @param NumVertices The number of vertices that are accessed. If this is 0, the vertex buffer binding will not be modified.
|
||||
* @param FirstIndex The first index
|
||||
* @param NumIndices The number of indices that will be drawn. If this is 0, the index buffer binding will not be modified.
|
||||
*/
|
||||
void UploadDynamicSysmemBuffers(
|
||||
UINT& FirstVertexIndex,
|
||||
UINT NumVertices,
|
||||
UINT& FirstIndex,
|
||||
UINT NumIndices,
|
||||
INT& BaseVertexIndex,
|
||||
bool* pDynamicVBOs,
|
||||
bool* pDynamicIBO);
|
||||
|
||||
|
||||
void SetupFPU();
|
||||
|
||||
int64_t DetermineInitialTextureMemory();
|
||||
|
@ -773,6 +793,7 @@ namespace dxvk {
|
|||
void SynchronizeCsThread(uint64_t SequenceNumber);
|
||||
|
||||
void Flush();
|
||||
void FlushAndSync9On12();
|
||||
|
||||
void EndFrame();
|
||||
|
||||
|
@ -816,7 +837,7 @@ namespace dxvk {
|
|||
inline bool IsAlphaToCoverageEnabled() {
|
||||
const bool alphaTest = m_state.renderStates[D3DRS_ALPHATESTENABLE] != 0;
|
||||
|
||||
return m_amdATOC || (m_nvATOC && alphaTest);
|
||||
return (m_amdATOC || (m_nvATOC && alphaTest)) && m_flags.test(D3D9DeviceFlag::ValidSampleMask);
|
||||
}
|
||||
|
||||
inline bool IsDepthBiasEnabled() {
|
||||
|
@ -895,7 +916,7 @@ namespace dxvk {
|
|||
|
||||
uint32_t GetInstanceCount() const;
|
||||
|
||||
void PrepareDraw(D3DPRIMITIVETYPE PrimitiveType);
|
||||
void PrepareDraw(D3DPRIMITIVETYPE PrimitiveType, bool UploadVBOs, bool UploadIBOs);
|
||||
|
||||
template <DxsoProgramType ShaderStage>
|
||||
void BindShader(
|
||||
|
@ -970,6 +991,17 @@ namespace dxvk {
|
|||
void TouchMappedTexture(D3D9CommonTexture* pTexture);
|
||||
void RemoveMappedTexture(D3D9CommonTexture* pTexture);
|
||||
|
||||
bool IsD3D8Compatible() const {
|
||||
return m_isD3D8Compatible;
|
||||
}
|
||||
|
||||
void SetD3D8CompatibilityMode(bool compatMode) {
|
||||
if (compatMode)
|
||||
Logger::info("The D3D9 device is now operating in D3D8 compatibility mode.");
|
||||
|
||||
m_isD3D8Compatible = compatMode;
|
||||
}
|
||||
|
||||
// Device Lost
|
||||
bool IsDeviceLost() const {
|
||||
return m_deviceLostState != D3D9DeviceLostState::Ok;
|
||||
|
@ -1022,6 +1054,15 @@ namespace dxvk {
|
|||
bool CanSWVP() const {
|
||||
return m_behaviorFlags & (D3DCREATE_MIXED_VERTEXPROCESSING | D3DCREATE_SOFTWARE_VERTEXPROCESSING);
|
||||
}
|
||||
|
||||
// Device Reset detection for D3D9SwapChainEx::Present
|
||||
bool IsDeviceReset() {
|
||||
return std::exchange(m_deviceHasBeenReset, false);
|
||||
}
|
||||
|
||||
template <bool Synchronize9On12>
|
||||
void ExecuteFlush();
|
||||
|
||||
void DetermineConstantLayouts(bool canSWVP);
|
||||
|
||||
D3D9BufferSlice AllocUPBuffer(VkDeviceSize size);
|
||||
|
@ -1046,7 +1087,7 @@ namespace dxvk {
|
|||
}
|
||||
|
||||
inline uint32_t GetUPBufferSize(uint32_t vertexCount, uint32_t stride) {
|
||||
return (vertexCount - 1) * stride + std::max(m_state.vertexDecl->GetSize(), stride);
|
||||
return (vertexCount - 1) * stride + std::max(m_state.vertexDecl->GetSize(0), stride);
|
||||
}
|
||||
|
||||
inline void FillUPVertexBuffer(void* buffer, const void* userData, uint32_t dataSize, uint32_t bufferSize) {
|
||||
|
@ -1204,6 +1245,34 @@ namespace dxvk {
|
|||
|
||||
uint64_t GetCurrentSequenceNumber();
|
||||
|
||||
/**
|
||||
* @brief Get the swapchain that was used the most recently for presenting
|
||||
* Has to be externally synchronized.
|
||||
*
|
||||
* @return D3D9SwapChainEx* Swapchain
|
||||
*/
|
||||
D3D9SwapChainEx* GetMostRecentlyUsedSwapchain() {
|
||||
return m_mostRecentlyUsedSwapchain;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set the swapchain that was used the most recently for presenting
|
||||
* Has to be externally synchronized.
|
||||
*
|
||||
* @param swapchain Swapchain
|
||||
*/
|
||||
void SetMostRecentlyUsedSwapchain(D3D9SwapChainEx* swapchain) {
|
||||
m_mostRecentlyUsedSwapchain = swapchain;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Reset the most recently swapchain back to the implicit one
|
||||
* Has to be externally synchronized.
|
||||
*/
|
||||
void ResetMostRecentlyUsedSwapchain() {
|
||||
m_mostRecentlyUsedSwapchain = m_implicitSwapchain.ptr();
|
||||
}
|
||||
|
||||
Com<D3D9InterfaceEx> m_parent;
|
||||
D3DDEVTYPE m_deviceType;
|
||||
HWND m_window;
|
||||
|
@ -1318,13 +1387,15 @@ namespace dxvk {
|
|||
D3D9ShaderMasks m_psShaderMasks = FixedFunctionMask;
|
||||
|
||||
bool m_isSWVP;
|
||||
bool m_amdATOC = false;
|
||||
bool m_nvATOC = false;
|
||||
bool m_ffZTest = false;
|
||||
bool m_isD3D8Compatible = false;
|
||||
bool m_amdATOC = false;
|
||||
bool m_nvATOC = false;
|
||||
bool m_ffZTest = false;
|
||||
|
||||
VkImageLayout m_hazardLayout = VK_IMAGE_LAYOUT_GENERAL;
|
||||
|
||||
bool m_usingGraphicsPipelines = false;
|
||||
bool m_deviceHasBeenReset = false;
|
||||
|
||||
DxvkDepthBiasRepresentation m_depthBiasRepresentation = { VK_DEPTH_BIAS_REPRESENTATION_LEAST_REPRESENTABLE_VALUE_FORMAT_EXT, false };
|
||||
float m_depthBiasScale = 0.0f;
|
||||
|
@ -1354,6 +1425,8 @@ namespace dxvk {
|
|||
|
||||
Rc<sync::Fence> m_submissionFence;
|
||||
uint64_t m_submissionId = 0ull;
|
||||
DxvkSubmitStatus m_submitStatus;
|
||||
|
||||
uint64_t m_flushSeqNum = 0ull;
|
||||
GpuFlushTracker m_flushTracker;
|
||||
|
||||
|
@ -1364,6 +1437,8 @@ namespace dxvk {
|
|||
HWND m_fullscreenWindow = NULL;
|
||||
std::atomic<uint32_t> m_losableResourceCounter = { 0 };
|
||||
|
||||
D3D9SwapChainEx* m_mostRecentlyUsedSwapchain = nullptr;
|
||||
|
||||
#ifdef D3D9_ALLOW_UNMAPPING
|
||||
lru_list<D3D9CommonTexture*> m_mappedTextures;
|
||||
#endif
|
||||
|
|
|
@ -336,7 +336,7 @@ namespace dxvk {
|
|||
}
|
||||
|
||||
|
||||
uint32_t SetupRenderStateBlock(SpirvModule& spvModule, uint32_t count) {
|
||||
uint32_t SetupRenderStateBlock(SpirvModule& spvModule) {
|
||||
uint32_t floatType = spvModule.defFloatType(32);
|
||||
uint32_t uintType = spvModule.defIntType(32, 0);
|
||||
uint32_t vec3Type = spvModule.defVectorType(floatType, 3);
|
||||
|
@ -357,7 +357,7 @@ namespace dxvk {
|
|||
floatType,
|
||||
}};
|
||||
|
||||
uint32_t rsStruct = spvModule.defStructTypeUnique(count, rsMembers.data());
|
||||
uint32_t rsStruct = spvModule.defStructTypeUnique(rsMembers.size(), rsMembers.data());
|
||||
uint32_t rsBlock = spvModule.newVar(
|
||||
spvModule.defPointerType(rsStruct, spv::StorageClassPushConstant),
|
||||
spv::StorageClassPushConstant);
|
||||
|
@ -369,9 +369,6 @@ namespace dxvk {
|
|||
|
||||
uint32_t memberIdx = 0;
|
||||
auto SetMemberName = [&](const char* name, uint32_t offset) {
|
||||
if (memberIdx >= count)
|
||||
return;
|
||||
|
||||
spvModule.setDebugMemberName (rsStruct, memberIdx, name);
|
||||
spvModule.memberDecorateOffset (rsStruct, memberIdx, offset);
|
||||
memberIdx++;
|
||||
|
@ -781,8 +778,6 @@ namespace dxvk {
|
|||
uint32_t m_inputMask = 0u;
|
||||
uint32_t m_outputMask = 0u;
|
||||
uint32_t m_flatShadingMask = 0u;
|
||||
uint32_t m_pushConstOffset = 0u;
|
||||
uint32_t m_pushConstSize = 0u;
|
||||
|
||||
DxsoProgramType m_programType;
|
||||
D3D9FFShaderKeyVS m_vsKey;
|
||||
|
@ -892,8 +887,8 @@ namespace dxvk {
|
|||
info.inputMask = m_inputMask;
|
||||
info.outputMask = m_outputMask;
|
||||
info.flatShadingInputs = m_flatShadingMask;
|
||||
info.pushConstOffset = m_pushConstOffset;
|
||||
info.pushConstSize = m_pushConstSize;
|
||||
info.pushConstStages = VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT;
|
||||
info.pushConstSize = sizeof(D3D9RenderStateInfo);
|
||||
|
||||
return new DxvkShader(info, m_module.compile());
|
||||
}
|
||||
|
@ -1111,6 +1106,17 @@ namespace dxvk {
|
|||
const uint32_t wIndex = 3;
|
||||
|
||||
uint32_t flags = (m_vsKey.Data.Contents.TransformFlags >> (i * 3)) & 0b111;
|
||||
|
||||
if (flags == D3DTTFF_COUNT1) {
|
||||
// D3DTTFF_COUNT1 behaves like D3DTTFF_DISABLE on NV and like D3DTTFF_COUNT2 on AMD.
|
||||
// The Nvidia behavior is easier to implement.
|
||||
flags = D3DTTFF_DISABLE;
|
||||
}
|
||||
|
||||
// Passing 0xffffffff results in it getting clamped to the dimensions of the texture coords and getting treated as PROJECTED
|
||||
// but D3D9 does not apply the transformation matrix.
|
||||
bool applyTransform = flags >= D3DTTFF_COUNT1 && flags <= D3DTTFF_COUNT4;
|
||||
|
||||
uint32_t count;
|
||||
switch (inputFlags) {
|
||||
default:
|
||||
|
@ -1121,11 +1127,14 @@ namespace dxvk {
|
|||
count = flags;
|
||||
if (texcoordCount) {
|
||||
// Clamp by the number of elements in the texcoord input.
|
||||
if (!count || count > texcoordCount)
|
||||
if (!count || count > texcoordCount) {
|
||||
count = texcoordCount;
|
||||
}
|
||||
else
|
||||
}
|
||||
} else {
|
||||
count = 0;
|
||||
flags = D3DTTFF_DISABLE;
|
||||
applyTransform = false;
|
||||
}
|
||||
break;
|
||||
|
||||
case (DXVK_TSS_TCI_CAMERASPACENORMAL >> TCIOffset):
|
||||
|
@ -1141,7 +1150,7 @@ namespace dxvk {
|
|||
case (DXVK_TSS_TCI_CAMERASPACEREFLECTIONVECTOR >> TCIOffset): {
|
||||
uint32_t vtx3 = m_module.opVectorShuffle(m_vec3Type, vtx, vtx, 3, indices.data());
|
||||
vtx3 = m_module.opNormalize(m_vec3Type, vtx3);
|
||||
|
||||
|
||||
uint32_t reflection = m_module.opReflect(m_vec3Type, vtx3, normal);
|
||||
|
||||
std::array<uint32_t, 4> transformIndices;
|
||||
|
@ -1179,9 +1188,8 @@ namespace dxvk {
|
|||
}
|
||||
}
|
||||
|
||||
uint32_t type = flags;
|
||||
if (type != D3DTTFF_DISABLE) {
|
||||
if (!m_vsKey.Data.Contents.HasPositionT) {
|
||||
if (applyTransform || (count != 4 && count != 0)) {
|
||||
if (applyTransform && !m_vsKey.Data.Contents.HasPositionT) {
|
||||
for (uint32_t j = count; j < 4; j++) {
|
||||
// If we're outside the component count of the vertex decl for this texcoord then we pad with zeroes.
|
||||
// Otherwise, pad with ones.
|
||||
|
@ -1198,8 +1206,8 @@ namespace dxvk {
|
|||
}
|
||||
|
||||
// Pad the unused section of it with the value for projection.
|
||||
uint32_t lastIdx = count - 1;
|
||||
uint32_t projValue = m_module.opCompositeExtract(m_floatType, transformed, 1, &lastIdx);
|
||||
uint32_t projIdx = std::max(2u, count - 1);
|
||||
uint32_t projValue = m_module.opCompositeExtract(m_floatType, transformed, 1, &projIdx);
|
||||
|
||||
for (uint32_t j = count; j < 4; j++)
|
||||
transformed = m_module.opCompositeInsert(m_vec4Type, projValue, transformed, 1, &j);
|
||||
|
@ -1384,20 +1392,7 @@ namespace dxvk {
|
|||
|
||||
|
||||
void D3D9FFShaderCompiler::setupRenderStateInfo() {
|
||||
uint32_t count;
|
||||
|
||||
if (m_programType == DxsoProgramType::PixelShader) {
|
||||
m_pushConstOffset = 0;
|
||||
m_pushConstSize = offsetof(D3D9RenderStateInfo, pointSize);
|
||||
count = 5;
|
||||
}
|
||||
else {
|
||||
m_pushConstOffset = offsetof(D3D9RenderStateInfo, pointSize);
|
||||
m_pushConstSize = sizeof(float) * 6;
|
||||
count = 11;
|
||||
}
|
||||
|
||||
m_rsBlock = SetupRenderStateBlock(m_module, count);
|
||||
m_rsBlock = SetupRenderStateBlock(m_module);
|
||||
}
|
||||
|
||||
|
||||
|
@ -1808,22 +1803,17 @@ namespace dxvk {
|
|||
texcoord = m_module.opVectorShuffle(texcoord_t,
|
||||
texcoord, texcoord, texcoordCnt, indices.data());
|
||||
|
||||
uint32_t projIdx = m_fsKey.Stages[i].Contents.ProjectedCount;
|
||||
if (projIdx == 0 || projIdx > texcoordCnt) {
|
||||
projIdx = 4; // Always use w if ProjectedCount is 0.
|
||||
}
|
||||
--projIdx;
|
||||
|
||||
bool shouldProject = m_fsKey.Stages[i].Contents.Projected;
|
||||
uint32_t projValue = 0;
|
||||
|
||||
if (m_fsKey.Stages[i].Contents.Projected) {
|
||||
if (shouldProject) {
|
||||
// Always use w, the vertex shader puts the correct value there.
|
||||
const uint32_t projIdx = 3;
|
||||
projValue = m_module.opCompositeExtract(m_floatType, m_ps.in.TEXCOORD[i], 1, &projIdx);
|
||||
uint32_t insertIdx = texcoordCnt - 1;
|
||||
texcoord = m_module.opCompositeInsert(texcoord_t, projValue, texcoord, 1, &insertIdx);
|
||||
}
|
||||
|
||||
bool shouldProject = m_fsKey.Stages[i].Contents.Projected;
|
||||
|
||||
if (i != 0 && (
|
||||
m_fsKey.Stages[i - 1].Contents.ColorOp == D3DTOP_BUMPENVMAP ||
|
||||
m_fsKey.Stages[i - 1].Contents.ColorOp == D3DTOP_BUMPENVMAPLUMINANCE)) {
|
||||
|
|
|
@ -59,7 +59,7 @@ namespace dxvk {
|
|||
void DoFixedFunctionAlphaTest(SpirvModule& spvModule, const D3D9AlphaTestContext& ctx);
|
||||
|
||||
// Returns a render state block
|
||||
uint32_t SetupRenderStateBlock(SpirvModule& spvModule, uint32_t count);
|
||||
uint32_t SetupRenderStateBlock(SpirvModule& spvModule);
|
||||
|
||||
struct D3D9PointSizeInfoVS {
|
||||
uint32_t defaultValue;
|
||||
|
|
|
@ -134,7 +134,7 @@ namespace dxvk {
|
|||
info.stage = VK_SHADER_STAGE_COMPUTE_BIT;
|
||||
info.bindingCount = bindings.size();
|
||||
info.bindings = bindings.data();
|
||||
info.pushConstOffset = 0;
|
||||
info.pushConstStages = VK_SHADER_STAGE_COMPUTE_BIT;
|
||||
info.pushConstSize = sizeof(VkExtent2D);
|
||||
|
||||
return new DxvkShader(info, std::move(code));
|
||||
|
|
|
@ -101,9 +101,7 @@ IDirect3DDevice9On12 : public IUnknown {
|
|||
virtual HRESULT STDMETHODCALLTYPE ReturnUnderlyingResource(IDirect3DResource9* resource, UINT num_sync, UINT64* signal_values, ID3D12Fence** fences) = 0;
|
||||
};
|
||||
|
||||
#ifdef _MSC_VER
|
||||
struct __declspec(uuid("e7fda234-b589-4049-940d-8878977531c8")) IDirect3DDevice9On12;
|
||||
#else
|
||||
#ifndef _MSC_VER
|
||||
__CRT_UUID_DECL(IDirect3DDevice9On12, 0xe7fda234,0xb589,0x4049,0x94,0x0d,0x88,0x78,0x97,0x75,0x31,0xc8);
|
||||
#endif
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@ namespace dxvk {
|
|||
Singleton<DxvkInstance> g_dxvkInstance;
|
||||
|
||||
D3D9InterfaceEx::D3D9InterfaceEx(bool bExtended)
|
||||
: m_instance ( g_dxvkInstance.acquire() )
|
||||
: m_instance ( g_dxvkInstance.acquire(DxvkInstanceFlag::ClientApiIsD3D9) )
|
||||
, m_d3d8Bridge ( this )
|
||||
, m_extended ( bExtended )
|
||||
, m_d3d9Options ( nullptr, m_instance->config() )
|
||||
|
|
|
@ -229,12 +229,7 @@ ID3D9VkExtSwapchain : public IUnknown {
|
|||
virtual void STDMETHODCALLTYPE UnlockAdditionalFormats() = 0;
|
||||
};
|
||||
|
||||
#ifdef _MSC_VER
|
||||
struct __declspec(uuid("3461a81b-ce41-485b-b6b5-fcf08ba6a6bd")) ID3D9VkInteropInterface;
|
||||
struct __declspec(uuid("d56344f5-8d35-46fd-806d-94c351b472c1")) ID3D9VkInteropTexture;
|
||||
struct __declspec(uuid("2eaa4b89-0107-4bdb-87f7-0f541c493ce0")) ID3D9VkInteropDevice;
|
||||
struct __declspec(uuid("13776e93-4aa9-430a-a4ec-fe9e281181d5")) ID3D9VkExtSwapchain;
|
||||
#else
|
||||
#ifndef _MSC_VER
|
||||
__CRT_UUID_DECL(ID3D9VkInteropInterface, 0x3461a81b,0xce41,0x485b,0xb6,0xb5,0xfc,0xf0,0x8b,0xa6,0xa6,0xbd);
|
||||
__CRT_UUID_DECL(ID3D9VkInteropTexture, 0xd56344f5,0x8d35,0x46fd,0x80,0x6d,0x94,0xc3,0x51,0xb4,0x72,0xc1);
|
||||
__CRT_UUID_DECL(ID3D9VkInteropDevice, 0x2eaa4b89,0x0107,0x4bdb,0x87,0xf7,0x0f,0x54,0x1c,0x49,0x3c,0xe0);
|
||||
|
|
|
@ -81,7 +81,7 @@ namespace dxvk {
|
|||
D3D9Memory (D3D9Memory&& other);
|
||||
D3D9Memory& operator = (D3D9Memory&& other);
|
||||
|
||||
operator bool() const { return m_chunk != nullptr; }
|
||||
explicit operator bool() const { return m_chunk != nullptr; }
|
||||
|
||||
void Map();
|
||||
void Unmap();
|
||||
|
@ -139,7 +139,7 @@ namespace dxvk {
|
|||
D3D9Memory (D3D9Memory&& other);
|
||||
D3D9Memory& operator = (D3D9Memory&& other);
|
||||
|
||||
operator bool() const { return m_ptr != nullptr; }
|
||||
explicit operator bool() const { return m_ptr != nullptr; }
|
||||
|
||||
void Map() {}
|
||||
void Unmap() {}
|
||||
|
|
|
@ -30,8 +30,11 @@ namespace dxvk {
|
|||
return E_NOINTERFACE;
|
||||
}
|
||||
HRESULT STDMETHODCALLTYPE D3D9On12::ReturnUnderlyingResource(IDirect3DResource9* resource, UINT num_sync, UINT64* signal_values, ID3D12Fence** fences) {
|
||||
Logger::err("D3D9On12::GetD3D12Device: ReturnUnderlyingResource: Stub");
|
||||
return E_NOINTERFACE;
|
||||
if (num_sync)
|
||||
Logger::err("D3D9On12::GetD3D12Device: ReturnUnderlyingResource: Stub");
|
||||
|
||||
m_device->FlushAndSync9On12();
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -37,8 +37,8 @@ namespace dxvk {
|
|||
this->customDeviceId = parsePciId(config.getOption<std::string>("d3d9.customDeviceId"));
|
||||
this->customDeviceDesc = config.getOption<std::string>("d3d9.customDeviceDesc");
|
||||
|
||||
const int32_t vendorId = this->customDeviceId != -1
|
||||
? this->customDeviceId
|
||||
const uint32_t vendorId = this->customVendorId != -1
|
||||
? this->customVendorId
|
||||
: (adapter != nullptr ? adapter->deviceProperties().vendorID : 0);
|
||||
|
||||
this->maxFrameLatency = config.getOption<int32_t> ("d3d9.maxFrameLatency", 0);
|
||||
|
@ -53,14 +53,14 @@ namespace dxvk {
|
|||
this->deferSurfaceCreation = config.getOption<bool> ("d3d9.deferSurfaceCreation", false);
|
||||
this->samplerAnisotropy = config.getOption<int32_t> ("d3d9.samplerAnisotropy", -1);
|
||||
this->maxAvailableMemory = config.getOption<int32_t> ("d3d9.maxAvailableMemory", 4096);
|
||||
this->supportDFFormats = config.getOption<bool> ("d3d9.supportDFFormats", true);
|
||||
this->supportDFFormats = config.getOption<bool> ("d3d9.supportDFFormats", vendorId != uint32_t(DxvkGpuVendor::Nvidia));
|
||||
this->supportX4R4G4B4 = config.getOption<bool> ("d3d9.supportX4R4G4B4", true);
|
||||
this->supportD32 = config.getOption<bool> ("d3d9.supportD32", true);
|
||||
this->useD32forD24 = config.getOption<bool> ("d3d9.useD32forD24", false);
|
||||
this->disableA8RT = config.getOption<bool> ("d3d9.disableA8RT", false);
|
||||
this->invariantPosition = config.getOption<bool> ("d3d9.invariantPosition", true);
|
||||
this->memoryTrackTest = config.getOption<bool> ("d3d9.memoryTrackTest", false);
|
||||
this->supportVCache = config.getOption<bool> ("d3d9.supportVCache", vendorId == 0x10de);
|
||||
this->supportVCache = config.getOption<bool> ("d3d9.supportVCache", vendorId == uint32_t(DxvkGpuVendor::Nvidia));
|
||||
this->enableDialogMode = config.getOption<bool> ("d3d9.enableDialogMode", false);
|
||||
this->forceSamplerTypeSpecConstants = config.getOption<bool> ("d3d9.forceSamplerTypeSpecConstants", false);
|
||||
this->forceSwapchainMSAA = config.getOption<int32_t> ("d3d9.forceSwapchainMSAA", -1);
|
||||
|
@ -76,6 +76,8 @@ namespace dxvk {
|
|||
this->deviceLossOnFocusLoss = config.getOption<bool> ("d3d9.deviceLossOnFocusLoss", false);
|
||||
this->samplerLodBias = config.getOption<float> ("d3d9.samplerLodBias", 0.0f);
|
||||
this->clampNegativeLodBias = config.getOption<bool> ("d3d9.clampNegativeLodBias", false);
|
||||
this->countLosableResources = config.getOption<bool> ("d3d9.countLosableResources", true);
|
||||
this->reproducibleCommandStream = config.getOption<bool> ("d3d9.reproducibleCommandStream", false);
|
||||
|
||||
// Clamp LOD bias so that people don't abuse this in unintended ways
|
||||
this->samplerLodBias = dxvk::fclamp(this->samplerLodBias, -2.0f, 1.0f);
|
||||
|
@ -89,8 +91,8 @@ namespace dxvk {
|
|||
d3d9FloatEmulation = D3D9FloatEmulation::Enabled;
|
||||
} else {
|
||||
bool hasMulz = adapter != nullptr
|
||||
&& (adapter->matchesDriver(VK_DRIVER_ID_MESA_RADV, 0, 0)
|
||||
|| adapter->matchesDriver(VK_DRIVER_ID_MESA_NVK, 0, 0));
|
||||
&& (adapter->matchesDriver(VK_DRIVER_ID_MESA_RADV)
|
||||
|| adapter->matchesDriver(VK_DRIVER_ID_MESA_NVK));
|
||||
d3d9FloatEmulation = hasMulz ? D3D9FloatEmulation::Strict : D3D9FloatEmulation::Enabled;
|
||||
}
|
||||
|
||||
|
|
|
@ -152,6 +152,14 @@ namespace dxvk {
|
|||
|
||||
/// Enable emulation of device loss when a fullscreen app loses focus
|
||||
bool deviceLossOnFocusLoss;
|
||||
|
||||
/// Disable counting losable resources and rejecting calls to Reset() if any are still alive
|
||||
bool countLosableResources;
|
||||
|
||||
/// Ensure that for the same D3D commands the output VK commands
|
||||
/// don't change between runs. Useful for comparative benchmarking,
|
||||
/// can negatively affect performance.
|
||||
bool reproducibleCommandStream;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -41,11 +41,6 @@ namespace dxvk {
|
|||
case D3DQUERYTYPE_TIMESTAMPFREQ:
|
||||
break;
|
||||
|
||||
case D3DQUERYTYPE_VERTEXSTATS:
|
||||
m_query[0] = dxvkDevice->createGpuQuery(
|
||||
VK_QUERY_TYPE_PIPELINE_STATISTICS, 0, 0);
|
||||
break;
|
||||
|
||||
default:
|
||||
throw DxvkError(str::format("D3D9Query: Unsupported query type ", m_queryType));
|
||||
}
|
||||
|
@ -246,11 +241,6 @@ namespace dxvk {
|
|||
m_dataCache.TimestampFreq = GetTimestampQueryFrequency();
|
||||
break;
|
||||
|
||||
case D3DQUERYTYPE_VERTEXSTATS:
|
||||
m_dataCache.VertexStats.NumRenderedTriangles = queryData[0].statistic.iaPrimitives;
|
||||
m_dataCache.VertexStats.NumExtraClippingTriangles = queryData[0].statistic.clipPrimitives;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -276,7 +266,6 @@ namespace dxvk {
|
|||
void D3D9Query::Begin(DxvkContext* ctx) {
|
||||
switch (m_queryType) {
|
||||
case D3DQUERYTYPE_OCCLUSION:
|
||||
case D3DQUERYTYPE_VERTEXSTATS:
|
||||
ctx->beginQuery(m_query[0]);
|
||||
break;
|
||||
|
||||
|
@ -296,7 +285,6 @@ namespace dxvk {
|
|||
ctx->writeTimestamp(m_query[0]);
|
||||
break;
|
||||
|
||||
case D3DQUERYTYPE_VERTEXSTATS:
|
||||
case D3DQUERYTYPE_OCCLUSION:
|
||||
ctx->endQuery(m_query[0]);
|
||||
break;
|
||||
|
@ -314,7 +302,6 @@ namespace dxvk {
|
|||
|
||||
bool D3D9Query::QueryBeginnable(D3DQUERYTYPE QueryType) {
|
||||
return QueryType == D3DQUERYTYPE_OCCLUSION
|
||||
|| QueryType == D3DQUERYTYPE_VERTEXSTATS
|
||||
|| QueryType == D3DQUERYTYPE_TIMESTAMPDISJOINT;
|
||||
}
|
||||
|
||||
|
@ -338,7 +325,6 @@ namespace dxvk {
|
|||
case D3DQUERYTYPE_TIMESTAMP:
|
||||
case D3DQUERYTYPE_TIMESTAMPDISJOINT:
|
||||
case D3DQUERYTYPE_TIMESTAMPFREQ:
|
||||
case D3DQUERYTYPE_VERTEXSTATS:
|
||||
return D3D_OK;
|
||||
|
||||
default:
|
||||
|
|
|
@ -195,7 +195,7 @@ namespace dxvk {
|
|||
const T* operator & () const { ensure(); return m_data.get(); }
|
||||
T* operator & () { ensure(); return m_data.get(); }
|
||||
|
||||
operator bool() { return m_data != nullptr; }
|
||||
explicit operator bool() const { return m_data != nullptr; }
|
||||
operator T() { ensure(); return *m_data; }
|
||||
|
||||
void ensure() const { if (!m_data) m_data = std::make_unique<T>(); }
|
||||
|
@ -213,7 +213,7 @@ namespace dxvk {
|
|||
|
||||
T& operator=(const T& x) { m_data = x; return m_data; }
|
||||
|
||||
operator bool() { return true; }
|
||||
explicit operator bool() const { return true; }
|
||||
operator T() { return m_data; }
|
||||
|
||||
const T* operator -> () const { return &m_data; }
|
||||
|
|
|
@ -18,7 +18,8 @@ namespace dxvk {
|
|||
}
|
||||
|
||||
D3D9StateBlock::~D3D9StateBlock() {
|
||||
m_parent->DecrementLosableCounter();
|
||||
if (!m_parent->IsD3D8Compatible())
|
||||
m_parent->DecrementLosableCounter();
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE D3D9StateBlock::QueryInterface(
|
||||
|
@ -575,4 +576,4 @@ namespace dxvk {
|
|||
this->Capture();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -65,6 +65,16 @@ namespace dxvk {
|
|||
if (this_thread::isInModuleDetachment())
|
||||
return;
|
||||
|
||||
{
|
||||
// Locking here and in Device::GetFrontBufferData
|
||||
// ensures that other threads don't accidentally access a stale pointer.
|
||||
D3D9DeviceLock lock = m_parent->LockDevice();
|
||||
|
||||
if (m_parent->GetMostRecentlyUsedSwapchain() == this) {
|
||||
m_parent->ResetMostRecentlyUsedSwapchain();
|
||||
}
|
||||
}
|
||||
|
||||
DestroyBackBuffers();
|
||||
|
||||
ResetWindowProc(m_window);
|
||||
|
@ -112,6 +122,8 @@ namespace dxvk {
|
|||
DWORD dwFlags) {
|
||||
D3D9DeviceLock lock = m_parent->LockDevice();
|
||||
|
||||
m_parent->SetMostRecentlyUsedSwapchain(this);
|
||||
|
||||
if (unlikely(m_parent->IsDeviceLost()))
|
||||
return D3DERR_DEVICELOST;
|
||||
|
||||
|
@ -147,6 +159,8 @@ namespace dxvk {
|
|||
bool recreate = false;
|
||||
recreate |= m_wctx->presenter == nullptr;
|
||||
recreate |= m_dialog != m_lastDialog;
|
||||
if (options->deferSurfaceCreation)
|
||||
recreate |= m_parent->IsDeviceReset();
|
||||
|
||||
if (m_wctx->presenter != nullptr) {
|
||||
m_dirty |= m_wctx->presenter->setSyncInterval(presentInterval) != VK_SUCCESS;
|
||||
|
@ -380,6 +394,20 @@ namespace dxvk {
|
|||
blitInfo.srcOffsets[0] = VkOffset3D{ 0, 0, 0 };
|
||||
blitInfo.srcOffsets[1] = VkOffset3D{ int32_t(srcExtent.width), int32_t(srcExtent.height), 1 };
|
||||
|
||||
#ifdef _WIN32
|
||||
if (m_presentParams.Windowed) {
|
||||
// In windowed mode, GetFrontBufferData takes a screenshot of the entire screen.
|
||||
// So place the copy of the front buffer at the position of the window.
|
||||
POINT point = { 0, 0 };
|
||||
if (ClientToScreen(m_window, &point) != 0) {
|
||||
blitInfo.dstOffsets[0].x = point.x;
|
||||
blitInfo.dstOffsets[0].y = point.y;
|
||||
blitInfo.dstOffsets[1].x += point.x;
|
||||
blitInfo.dstOffsets[1].y += point.y;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
m_parent->EmitCs([
|
||||
cDstImage = blittedSrc,
|
||||
cDstMap = dstTexInfo->GetMapping().Swizzle,
|
||||
|
|
|
@ -144,7 +144,7 @@ namespace dxvk {
|
|||
uint32_t primitiveId = m_module.opLoad(uint_t, primitiveIdPtr);
|
||||
|
||||
// The size of any given vertex
|
||||
uint32_t vertexSize = m_module.constu32(pDecl->GetSize() / sizeof(uint32_t));
|
||||
uint32_t vertexSize = m_module.constu32(pDecl->GetSize(0) / sizeof(uint32_t));
|
||||
|
||||
//The offset of this vertex from the beginning of the buffer
|
||||
uint32_t thisVertexOffset = m_module.opIMul(uint_t, vertexSize, primitiveId);
|
||||
|
|
|
@ -204,38 +204,6 @@ namespace dxvk {
|
|||
|
||||
bool IsDepthFormat(D3D9Format Format);
|
||||
|
||||
inline bool operator == (const D3DVIEWPORT9& a, const D3DVIEWPORT9& b) {
|
||||
return a.X == b.X &&
|
||||
a.Y == b.Y &&
|
||||
a.Width == b.Width &&
|
||||
a.Height == b.Height &&
|
||||
a.MinZ == b.MinZ &&
|
||||
a.MaxZ == b.MaxZ;
|
||||
}
|
||||
|
||||
inline bool operator != (const D3DVIEWPORT9& a, const D3DVIEWPORT9& b) {
|
||||
return !(a == b);
|
||||
}
|
||||
|
||||
inline bool operator == (const RECT& a, const RECT& b) {
|
||||
return a.left == b.left &&
|
||||
a.right == b.right &&
|
||||
a.top == b.top &&
|
||||
a.bottom == b.bottom;
|
||||
}
|
||||
|
||||
inline bool operator != (const RECT& a, const RECT& b) {
|
||||
return !(a == b);
|
||||
}
|
||||
|
||||
inline bool operator == (const POINT& a, const POINT& b) {
|
||||
return a.x == b.x && a.y == b.y;
|
||||
}
|
||||
|
||||
inline bool operator != (const POINT& a, const POINT& b) {
|
||||
return !(a == b);
|
||||
}
|
||||
|
||||
inline bool IsPoolManaged(D3DPOOL Pool) {
|
||||
return Pool == D3DPOOL_MANAGED || Pool == D3DPOOL_MANAGED_EX;
|
||||
}
|
||||
|
@ -295,4 +263,47 @@ namespace dxvk {
|
|||
return D3D9TextureStageStateTypes(Type - 1);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
inline bool operator == (const D3DVIEWPORT9& a, const D3DVIEWPORT9& b) {
|
||||
return a.X == b.X &&
|
||||
a.Y == b.Y &&
|
||||
a.Width == b.Width &&
|
||||
a.Height == b.Height &&
|
||||
a.MinZ == b.MinZ &&
|
||||
a.MaxZ == b.MaxZ;
|
||||
}
|
||||
|
||||
inline bool operator != (const D3DVIEWPORT9& a, const D3DVIEWPORT9& b) {
|
||||
return !(a == b);
|
||||
}
|
||||
|
||||
inline bool operator == (const RECT& a, const RECT& b) {
|
||||
return a.left == b.left &&
|
||||
a.right == b.right &&
|
||||
a.top == b.top &&
|
||||
a.bottom == b.bottom;
|
||||
}
|
||||
|
||||
inline bool operator != (const RECT& a, const RECT& b) {
|
||||
return !(a == b);
|
||||
}
|
||||
|
||||
inline bool operator == (const POINT& a, const POINT& b) {
|
||||
return a.x == b.x && a.y == b.y;
|
||||
}
|
||||
|
||||
inline bool operator != (const POINT& a, const POINT& b) {
|
||||
return !(a == b);
|
||||
}
|
||||
|
||||
inline bool operator == (const D3DDISPLAYMODEEX& a, const D3DDISPLAYMODEEX& b) {
|
||||
return a.Size == b.Size &&
|
||||
a.Width == b.Width &&
|
||||
a.Height == b.Height &&
|
||||
a.RefreshRate == b.RefreshRate &&
|
||||
a.Format == b.Format &&
|
||||
a.ScanLineOrdering == b.ScanLineOrdering;
|
||||
}
|
||||
|
||||
|
|
|
@ -354,8 +354,8 @@ namespace dxvk {
|
|||
|
||||
void D3D9VertexDecl::Classify() {
|
||||
for (const auto& element : m_elements) {
|
||||
if (element.Stream == 0 && element.Type != D3DDECLTYPE_UNUSED)
|
||||
m_size = std::max(m_size, element.Offset + GetDecltypeSize(D3DDECLTYPE(element.Type)));
|
||||
if (element.Type != D3DDECLTYPE_UNUSED)
|
||||
m_sizes[element.Stream] = std::max(m_sizes[element.Stream], element.Offset + GetDecltypeSize(D3DDECLTYPE(element.Type)));
|
||||
|
||||
if (element.Usage == D3DDECLUSAGE_COLOR && element.UsageIndex == 0)
|
||||
m_flags.set(D3D9VertexDeclFlag::HasColor0);
|
||||
|
|
|
@ -50,8 +50,8 @@ namespace dxvk {
|
|||
return m_elements;
|
||||
}
|
||||
|
||||
UINT GetSize() const {
|
||||
return m_size;
|
||||
UINT GetSize(UINT Stream) const {
|
||||
return m_sizes[Stream];
|
||||
}
|
||||
|
||||
bool TestFlag(D3D9VertexDeclFlag flag) const {
|
||||
|
@ -94,8 +94,7 @@ namespace dxvk {
|
|||
|
||||
uint32_t m_texcoordMask = 0;
|
||||
|
||||
// The size of Stream 0. That's all we care about.
|
||||
uint32_t m_size = 0;
|
||||
std::array<uint32_t, caps::MaxStreams> m_sizes = {};
|
||||
|
||||
};
|
||||
|
||||
|
|
|
@ -57,17 +57,24 @@ if platform != 'windows'
|
|||
d3d9_link_depends += files('d3d9.sym')
|
||||
endif
|
||||
|
||||
d3d9_dll = shared_library('d3d9'+dll_ext, d3d9_src, glsl_generator.process(d3d9_shaders), d3d9_res,
|
||||
name_prefix : dxvk_name_prefix,
|
||||
d3d9_dll = shared_library(dxvk_name_prefix+'d3d9', d3d9_src, glsl_generator.process(d3d9_shaders), d3d9_res,
|
||||
dependencies : [ dxso_dep, dxvk_dep ],
|
||||
include_directories : dxvk_include_path,
|
||||
install : true,
|
||||
vs_module_defs : 'd3d9'+def_spec_ext,
|
||||
link_args : d3d9_ld_args,
|
||||
link_depends : [ d3d9_link_depends ],
|
||||
kwargs : dxvk_so_version,
|
||||
)
|
||||
|
||||
d3d9_dep = declare_dependency(
|
||||
link_with : [ d3d9_dll ],
|
||||
include_directories : [ dxvk_include_path ],
|
||||
)
|
||||
|
||||
if platform != 'windows'
|
||||
pkg.generate(d3d9_dll,
|
||||
filebase: dxvk_pkg_prefix + 'd3d9',
|
||||
subdirs: 'dxvk',
|
||||
)
|
||||
endif
|
||||
|
|
|
@ -87,9 +87,9 @@ namespace dxvk {
|
|||
}
|
||||
|
||||
for (uint32_t i = 0; i < ins.dstCount; i++) {
|
||||
if (ins.dst[0].type == DxbcOperandType::IndexableTemp) {
|
||||
uint32_t index = ins.dst[0].idx[0].offset;
|
||||
m_analysis->xRegMasks[index] |= ins.dst[0].mask;
|
||||
if (ins.dst[i].type == DxbcOperandType::IndexableTemp) {
|
||||
uint32_t index = ins.dst[i].idx[0].offset;
|
||||
m_analysis->xRegMasks[index] |= ins.dst[i].mask;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,7 +23,11 @@ namespace dxvk {
|
|||
entry.systemValue = static_cast<DxbcSystemValue>(reader.readu32());
|
||||
entry.componentType = componentTypes.at(reader.readu32());
|
||||
entry.registerId = reader.readu32();
|
||||
entry.componentMask = bit::extract(reader.readu32(), 0, 3);
|
||||
|
||||
uint32_t mask = reader.readu32();
|
||||
|
||||
entry.componentMask = bit::extract(mask, 0, 3);
|
||||
entry.componentUsed = bit::extract(mask, 8, 11);
|
||||
|
||||
if (hasPrecision)
|
||||
reader.readu32();
|
||||
|
|
|
@ -20,6 +20,7 @@ namespace dxvk {
|
|||
uint32_t semanticIndex;
|
||||
uint32_t registerId;
|
||||
DxbcRegMask componentMask;
|
||||
DxbcRegMask componentUsed;
|
||||
DxbcScalarType componentType;
|
||||
DxbcSystemValue systemValue;
|
||||
uint32_t streamId;
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -512,6 +512,7 @@ namespace dxvk {
|
|||
// Entry point description - we'll need to declare
|
||||
// the function ID and all input/output variables.
|
||||
uint32_t m_entryPointId = 0;
|
||||
bool m_hasRawAccessChains = false;
|
||||
|
||||
////////////////////////////////////////////
|
||||
// Inter-stage shader interface slots. Also
|
||||
|
@ -944,19 +945,6 @@ namespace dxvk {
|
|||
const DxbcRegister& operand,
|
||||
const DxbcRegister& address);
|
||||
|
||||
///////////////////////////////
|
||||
// Resource load/store methods
|
||||
DxbcRegisterValue emitRawBufferLoad(
|
||||
const DxbcRegister& operand,
|
||||
DxbcRegisterValue elementIndex,
|
||||
DxbcRegMask writeMask,
|
||||
uint32_t& sparseFeedbackId);
|
||||
|
||||
void emitRawBufferStore(
|
||||
const DxbcRegister& operand,
|
||||
DxbcRegisterValue elementIndex,
|
||||
DxbcRegisterValue value);
|
||||
|
||||
//////////////////////////
|
||||
// Resource query methods
|
||||
DxbcRegisterValue emitQueryBufferSize(
|
||||
|
@ -1233,6 +1221,9 @@ namespace dxvk {
|
|||
uint32_t getUavCoherence(
|
||||
uint32_t registerId,
|
||||
DxbcUavFlags flags);
|
||||
|
||||
bool ignoreInputSystemValue(
|
||||
DxbcSystemValue sv) const;
|
||||
|
||||
///////////////////////////
|
||||
// Type definition methods
|
||||
|
|
|
@ -149,6 +149,10 @@ namespace dxvk {
|
|||
: m_mask((x ? 0x1 : 0) | (y ? 0x2 : 0)
|
||||
| (z ? 0x4 : 0) | (w ? 0x8 : 0)) { }
|
||||
|
||||
uint32_t raw() const {
|
||||
return m_mask;
|
||||
}
|
||||
|
||||
bool operator [] (uint32_t id) const {
|
||||
return (m_mask >> id) & 1;
|
||||
}
|
||||
|
@ -196,7 +200,7 @@ namespace dxvk {
|
|||
return out;
|
||||
}
|
||||
|
||||
operator bool () const {
|
||||
explicit operator bool () const {
|
||||
return m_mask != 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -17,9 +17,6 @@ namespace dxvk {
|
|||
|
||||
useDepthClipWorkaround
|
||||
= !devFeatures.extDepthClipEnable.depthClipEnable;
|
||||
useSubgroupOpsForAtomicCounters
|
||||
= (devInfo.vk11.subgroupSupportedStages & VK_SHADER_STAGE_COMPUTE_BIT)
|
||||
&& (devInfo.vk11.subgroupSupportedOperations & VK_SUBGROUP_FEATURE_BALLOT_BIT);
|
||||
|
||||
VkFormatFeatureFlags2 r32Features
|
||||
= device->getFormatFeatures(VK_FORMAT_R32_SFLOAT).optimal
|
||||
|
@ -27,6 +24,7 @@ namespace dxvk {
|
|||
& device->getFormatFeatures(VK_FORMAT_R32_SINT).optimal;
|
||||
|
||||
supportsTypedUavLoadR32 = (r32Features & VK_FORMAT_FEATURE_2_STORAGE_READ_WITHOUT_FORMAT_BIT);
|
||||
supportsRawAccessChains = device->features().nvRawAccessChains.shaderRawAccessChains;
|
||||
|
||||
switch (device->config().useRawSsbo) {
|
||||
case Tristate::Auto: minSsboAlignment = devInfo.core.properties.limits.minStorageBufferOffsetAlignment; break;
|
||||
|
@ -40,6 +38,7 @@ namespace dxvk {
|
|||
disableMsaa = options.disableMsaa;
|
||||
forceSampleRateShading = options.forceSampleRateShading;
|
||||
enableSampleShadingInterlock = device->features().extFragmentShaderInterlock.fragmentShaderSampleInterlock;
|
||||
longMad = options.longMad;
|
||||
|
||||
// Figure out float control flags to match D3D11 rules
|
||||
if (options.floatControls) {
|
||||
|
|
|
@ -27,9 +27,8 @@ namespace dxvk {
|
|||
/// on typed UAV loads are required
|
||||
bool supportsTypedUavLoadR32 = false;
|
||||
|
||||
/// Use subgroup operations to reduce the number of
|
||||
/// atomic operations for append/consume buffers.
|
||||
bool useSubgroupOpsForAtomicCounters = false;
|
||||
/// Determines whether raw access chains are supported
|
||||
bool supportsRawAccessChains = false;
|
||||
|
||||
/// Clear thread-group shared memory to zero
|
||||
bool zeroInitWorkgroupMemory = false;
|
||||
|
@ -55,6 +54,9 @@ namespace dxvk {
|
|||
|
||||
/// Minimum storage buffer alignment
|
||||
VkDeviceSize minSsboAlignment = 0;
|
||||
|
||||
/// Should we make our Mads a FFma or do it the long way with an FMul and an FAdd?
|
||||
bool longMad;
|
||||
};
|
||||
|
||||
}
|
|
@ -130,7 +130,7 @@ namespace dxvk {
|
|||
// We can't really reconstruct the version numbers
|
||||
// returned by Windows drivers from Vulkan data
|
||||
if (SUCCEEDED(hr) && pUMDVersion)
|
||||
pUMDVersion->QuadPart = ~0ull;
|
||||
pUMDVersion->QuadPart = INT64_MAX;
|
||||
|
||||
if (FAILED(hr)) {
|
||||
Logger::err("DXGI: CheckInterfaceSupport: Unsupported interface");
|
||||
|
@ -272,7 +272,8 @@ namespace dxvk {
|
|||
auto deviceProp = m_adapter->deviceProperties();
|
||||
auto memoryProp = m_adapter->memoryProperties();
|
||||
auto vk11 = m_adapter->devicePropertiesExt().vk11;
|
||||
|
||||
auto vk12 = m_adapter->devicePropertiesExt().vk12;
|
||||
|
||||
// Custom Vendor / Device ID
|
||||
if (options->customVendorId >= 0)
|
||||
deviceProp.vendorID = options->customVendorId;
|
||||
|
@ -298,7 +299,10 @@ namespace dxvk {
|
|||
fallbackDevice = 0x2487;
|
||||
}
|
||||
|
||||
bool hideGpu = (deviceProp.vendorID == uint16_t(DxvkGpuVendor::Nvidia) && options->hideNvidiaGpu)
|
||||
bool hideNvidiaGpu = vk12.driverID == VK_DRIVER_ID_NVIDIA_PROPRIETARY
|
||||
? options->hideNvidiaGpu : options->hideNvkGpu;
|
||||
|
||||
bool hideGpu = (deviceProp.vendorID == uint16_t(DxvkGpuVendor::Nvidia) && hideNvidiaGpu)
|
||||
|| (deviceProp.vendorID == uint16_t(DxvkGpuVendor::Amd) && options->hideAmdGpu)
|
||||
|| (deviceProp.vendorID == uint16_t(DxvkGpuVendor::Intel) && options->hideIntelGpu);
|
||||
|
||||
|
|
|
@ -79,7 +79,7 @@ namespace dxvk {
|
|||
|
||||
|
||||
DxgiFactory::DxgiFactory(UINT Flags)
|
||||
: m_instance (g_dxvkInstance.acquire()),
|
||||
: m_instance (g_dxvkInstance.acquire(0)),
|
||||
m_interop (this),
|
||||
m_options (m_instance->config()),
|
||||
m_monitorInfo (this, m_options),
|
||||
|
@ -230,7 +230,7 @@ namespace dxvk {
|
|||
descFs.Windowed = pDesc->Windowed;
|
||||
|
||||
IDXGISwapChain1* swapChain = nullptr;
|
||||
HRESULT hr = CreateSwapChainForHwnd(
|
||||
HRESULT hr = CreateSwapChainForHwndBase(
|
||||
pDevice, pDesc->OutputWindow,
|
||||
&desc, &descFs, nullptr,
|
||||
&swapChain);
|
||||
|
@ -244,6 +244,19 @@ namespace dxvk {
|
|||
IUnknown* pDevice,
|
||||
HWND hWnd,
|
||||
const DXGI_SWAP_CHAIN_DESC1* pDesc,
|
||||
const DXGI_SWAP_CHAIN_FULLSCREEN_DESC* pFullscreenDesc,
|
||||
IDXGIOutput* pRestrictToOutput,
|
||||
IDXGISwapChain1** ppSwapChain) {
|
||||
return CreateSwapChainForHwndBase(
|
||||
pDevice, hWnd,
|
||||
pDesc, pFullscreenDesc, pRestrictToOutput,
|
||||
ppSwapChain);
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE DxgiFactory::CreateSwapChainForHwndBase(
|
||||
IUnknown* pDevice,
|
||||
HWND hWnd,
|
||||
const DXGI_SWAP_CHAIN_DESC1* pDesc,
|
||||
const DXGI_SWAP_CHAIN_FULLSCREEN_DESC* pFullscreenDesc,
|
||||
IDXGIOutput* pRestrictToOutput,
|
||||
IDXGISwapChain1** ppSwapChain) {
|
||||
|
|
|
@ -200,6 +200,14 @@ namespace dxvk {
|
|||
UINT m_flags;
|
||||
BOOL m_monitorFallback;
|
||||
|
||||
|
||||
HRESULT STDMETHODCALLTYPE CreateSwapChainForHwndBase(
|
||||
IUnknown* pDevice,
|
||||
HWND hWnd,
|
||||
const DXGI_SWAP_CHAIN_DESC1* pDesc,
|
||||
const DXGI_SWAP_CHAIN_FULLSCREEN_DESC* pFullscreenDesc,
|
||||
IDXGIOutput* pRestrictToOutput,
|
||||
IDXGISwapChain1** ppSwapChain);
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -318,10 +318,12 @@ namespace dxvk {
|
|||
VK_FORMAT_R8_UINT,
|
||||
VK_IMAGE_ASPECT_COLOR_BIT },
|
||||
// DXGI_FORMAT_A8_UNORM
|
||||
{ VK_FORMAT_A8_UNORM_KHR,
|
||||
{ VK_FORMAT_R8_UNORM,
|
||||
VK_FORMAT_UNDEFINED,
|
||||
VK_FORMAT_R8_UINT,
|
||||
VK_IMAGE_ASPECT_COLOR_BIT, 0 },
|
||||
VK_FORMAT_UNDEFINED,
|
||||
VK_IMAGE_ASPECT_COLOR_BIT, 0,
|
||||
{ VK_COMPONENT_SWIZZLE_ZERO, VK_COMPONENT_SWIZZLE_ZERO,
|
||||
VK_COMPONENT_SWIZZLE_ZERO, VK_COMPONENT_SWIZZLE_R }},
|
||||
// DXGI_FORMAT_R1_UNORM
|
||||
{ }, // Unsupported
|
||||
// DXGI_FORMAT_R9G9B9E5_SHAREDEXP
|
||||
|
@ -858,16 +860,6 @@ namespace dxvk {
|
|||
RemapDepthFormat(DXGI_FORMAT_X24_TYPELESS_G8_UINT, VK_FORMAT_D32_SFLOAT_S8_UINT);
|
||||
RemapDepthFormat(DXGI_FORMAT_D24_UNORM_S8_UINT, VK_FORMAT_D32_SFLOAT_S8_UINT);
|
||||
}
|
||||
|
||||
// Map A8_UNORM to R8_UNORM with appropriate swizzles if necessary
|
||||
if (!CheckImageFormatSupport(device, VK_FORMAT_A8_UNORM_KHR,
|
||||
VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_BIT |
|
||||
VK_FORMAT_FEATURE_2_COLOR_ATTACHMENT_BIT |
|
||||
VK_FORMAT_FEATURE_2_STORAGE_IMAGE_BIT)) {
|
||||
RemapColorFormat(DXGI_FORMAT_A8_UNORM, VK_FORMAT_R8_UNORM,
|
||||
{ VK_COMPONENT_SWIZZLE_ZERO, VK_COMPONENT_SWIZZLE_ZERO,
|
||||
VK_COMPONENT_SWIZZLE_ZERO, VK_COMPONENT_SWIZZLE_R });
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -458,21 +458,7 @@ IDXGIVkInteropFactory1 : public IDXGIVkInteropFactory {
|
|||
};
|
||||
|
||||
|
||||
#ifdef _MSC_VER
|
||||
struct __declspec(uuid("907bf281-ea3c-43b4-a8e4-9f231107b4ff")) IDXGIDXVKAdapter;
|
||||
struct __declspec(uuid("92a5d77b-b6e1-420a-b260-fdd701272827")) IDXGIDXVKDevice;
|
||||
struct __declspec(uuid("c06a236f-5be3-448a-8943-89c611c0c2c1")) IDXGIVkMonitorInfo;
|
||||
struct __declspec(uuid("4c5e1b0d-b0c8-4131-bfd8-9b2476f7f408")) IDXGIVkInteropFactory;
|
||||
struct __declspec(uuid("2a289dbd-2d0a-4a51-89f7-f2adce465cd6")) IDXGIVkInteropFactory1;
|
||||
struct __declspec(uuid("3a6d8f2c-b0e8-4ab4-b4dc-4fd24891bfa5")) IDXGIVkInteropAdapter;
|
||||
struct __declspec(uuid("e2ef5fa5-dc21-4af7-90c4-f67ef6a09323")) IDXGIVkInteropDevice;
|
||||
struct __declspec(uuid("e2ef5fa5-dc21-4af7-90c4-f67ef6a09324")) IDXGIVkInteropDevice1;
|
||||
struct __declspec(uuid("5546cf8c-77e7-4341-b05d-8d4d5000e77d")) IDXGIVkInteropSurface;
|
||||
struct __declspec(uuid("1e7895a1-1bc3-4f9c-a670-290a4bc9581a")) IDXGIVkSurfaceFactory;
|
||||
struct __declspec(uuid("e4a9059e-b569-46ab-8de7-501bd2bc7f7a")) IDXGIVkSwapChain;
|
||||
struct __declspec(uuid("785326d4-b77b-4826-ae70-8d08308ee6d1")) IDXGIVkSwapChain1;
|
||||
struct __declspec(uuid("e7d6c3ca-23a0-4e08-9f2f-ea5231df6633")) IDXGIVkSwapChainFactory;
|
||||
#else
|
||||
#ifndef _MSC_VER
|
||||
__CRT_UUID_DECL(IDXGIDXVKAdapter, 0x907bf281,0xea3c,0x43b4,0xa8,0xe4,0x9f,0x23,0x11,0x07,0xb4,0xff);
|
||||
__CRT_UUID_DECL(IDXGIDXVKDevice, 0x92a5d77b,0xb6e1,0x420a,0xb2,0x60,0xfd,0xf7,0x01,0x27,0x28,0x27);
|
||||
__CRT_UUID_DECL(IDXGIVkMonitorInfo, 0xc06a236f,0x5be3,0x448a,0x89,0x43,0x89,0xc6,0x11,0xc0,0xc2,0xc1);
|
||||
|
|
|
@ -107,7 +107,11 @@ namespace dxvk {
|
|||
return 32;
|
||||
|
||||
case DXGI_FORMAT_R16G16B16A16_FLOAT:
|
||||
return 64;
|
||||
// Floating point output doesn't really make sense.
|
||||
// This seemingly works on Windows, and based on FindClosestMode etc documentaton,
|
||||
// this seems required to work for any format that scanout it supported for.
|
||||
// Treat as 10-bit -> 32.
|
||||
return 32;
|
||||
|
||||
default:
|
||||
Logger::warn(str::format(
|
||||
|
|
|
@ -26,6 +26,21 @@ namespace dxvk {
|
|||
return id;
|
||||
}
|
||||
|
||||
/* First generation XeSS causes crash on proton for Intel due to missing
|
||||
* Intel interface. Avoid crash by pretending to be non-Intel if the
|
||||
* libxess.dll module is loaded by an application.
|
||||
*/
|
||||
static bool isXessUsed() {
|
||||
#ifdef _WIN32
|
||||
if (GetModuleHandleA("libxess") != nullptr ||
|
||||
GetModuleHandleA("libxess_dx11") != nullptr)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
static bool isNvapiEnabled() {
|
||||
return env::getEnvVar("DXVK_ENABLE_NVAPI") == "1";
|
||||
|
@ -78,17 +93,16 @@ namespace dxvk {
|
|||
this->maxDeviceMemory = VkDeviceSize(config.getOption<int32_t>("dxgi.maxDeviceMemory", 0)) << 20;
|
||||
this->maxSharedMemory = VkDeviceSize(config.getOption<int32_t>("dxgi.maxSharedMemory", 0)) << 20;
|
||||
|
||||
this->syncInterval = config.getOption<int32_t>("dxgi.syncInterval", -1);
|
||||
|
||||
// Expose Nvidia GPUs properly if NvAPI is enabled in environment
|
||||
this->hideNvidiaGpu = !isNvapiEnabled();
|
||||
applyTristate(this->hideNvidiaGpu, config.getOption<Tristate>("dxgi.hideNvidiaGpu", Tristate::Auto));
|
||||
|
||||
Tristate hideNvidiaGpuOption = config.getOption<Tristate>("dxgi.hideNvidiaGpu", Tristate::Auto);
|
||||
|
||||
if (hideNvidiaGpuOption == Tristate::Auto && !config.getOption<bool>("dxgi.nvapiHack", true)) {
|
||||
Logger::warn("dxgi.nvapiHack is deprecated, please set dxgi.hideNvidiaGpu instead.");
|
||||
hideNvidiaGpuOption = Tristate::False;
|
||||
}
|
||||
|
||||
applyTristate(this->hideNvidiaGpu, hideNvidiaGpuOption);
|
||||
// Treat NVK adapters the same as Nvidia cards on the proprietary by
|
||||
// default, but provide an override in case something isn't working.
|
||||
this->hideNvkGpu = this->hideNvidiaGpu;
|
||||
applyTristate(this->hideNvkGpu, config.getOption<Tristate>("dxgi.hideNvkGpu", Tristate::Auto));
|
||||
|
||||
// Expose AMD and Intel GPU by default, unless a config override is active.
|
||||
// Implement as a tristate so that we have the option to introduce similar
|
||||
|
@ -96,6 +110,12 @@ namespace dxvk {
|
|||
this->hideAmdGpu = config.getOption<Tristate>("dxgi.hideAmdGpu", Tristate::Auto) == Tristate::True;
|
||||
this->hideIntelGpu = config.getOption<Tristate>("dxgi.hideIntelGpu", Tristate::Auto) == Tristate::True;
|
||||
|
||||
/* Force vendor ID to non-Intel ID when XeSS is in use */
|
||||
if (isXessUsed()) {
|
||||
Logger::info(str::format("Detected XeSS usage, hiding Intel GPU Vendor"));
|
||||
this->hideIntelGpu = true;
|
||||
}
|
||||
|
||||
this->enableHDR = config.getOption<bool>("dxgi.enableHDR", env::getEnvVar("DXVK_HDR") == "1");
|
||||
if (this->enableHDR && isHDRDisallowed()) {
|
||||
Logger::info("HDR was configured to be enabled, but has been force disabled as a UE4 DX11 game was detected.");
|
||||
|
|
|
@ -33,9 +33,13 @@ namespace dxvk {
|
|||
/// Emulate UMA
|
||||
bool emulateUMA;
|
||||
|
||||
/// Reports Nvidia GPUs as a different vendor (usually AMD)
|
||||
/// Reports Nvidia GPUs running on the proprietary driver as a different
|
||||
/// vendor (usually AMD). Proton will generally disable this option.
|
||||
bool hideNvidiaGpu;
|
||||
|
||||
/// Reports Nvidia GPUs running on NVK as a different vendor (usually AMD)
|
||||
bool hideNvkGpu;
|
||||
|
||||
/// Reports AMD GPUs as a different vendor (usually Nvidia)
|
||||
bool hideAmdGpu;
|
||||
|
||||
|
@ -44,6 +48,10 @@ namespace dxvk {
|
|||
|
||||
/// Enable HDR
|
||||
bool enableHDR;
|
||||
|
||||
/// Sync interval. Overrides the value
|
||||
/// passed to IDXGISwapChain::Present.
|
||||
int32_t syncInterval;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -32,6 +32,9 @@ namespace dxvk {
|
|||
// Apply initial window mode and fullscreen state
|
||||
if (!m_descFs.Windowed && FAILED(EnterFullscreenMode(nullptr)))
|
||||
throw DxvkError("DXGI: Failed to set initial fullscreen state");
|
||||
|
||||
// Ensure that RGBA16 swap chains are scRGB if supported
|
||||
UpdateColorSpace(m_desc.Format, m_colorSpace);
|
||||
}
|
||||
|
||||
|
||||
|
@ -300,18 +303,30 @@ namespace dxvk {
|
|||
|
||||
|
||||
HRESULT STDMETHODCALLTYPE DxgiSwapChain::Present(UINT SyncInterval, UINT Flags) {
|
||||
return Present1(SyncInterval, Flags, nullptr);
|
||||
return PresentBase(SyncInterval, Flags, nullptr);
|
||||
}
|
||||
|
||||
|
||||
|
||||
HRESULT STDMETHODCALLTYPE DxgiSwapChain::Present1(
|
||||
UINT SyncInterval,
|
||||
UINT PresentFlags,
|
||||
const DXGI_PRESENT_PARAMETERS* pPresentParameters) {
|
||||
|
||||
return PresentBase(SyncInterval, PresentFlags, pPresentParameters);
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE DxgiSwapChain::PresentBase(
|
||||
UINT SyncInterval,
|
||||
UINT PresentFlags,
|
||||
const DXGI_PRESENT_PARAMETERS* pPresentParameters) {
|
||||
|
||||
if (SyncInterval > 4)
|
||||
return DXGI_ERROR_INVALID_CALL;
|
||||
|
||||
auto options = m_factory->GetOptions();
|
||||
|
||||
if (options->syncInterval >= 0)
|
||||
SyncInterval = options->syncInterval;
|
||||
|
||||
UpdateGlobalHDRState();
|
||||
|
||||
std::lock_guard<dxvk::recursive_mutex> lockWin(m_lockWindow);
|
||||
|
@ -393,7 +408,13 @@ namespace dxvk {
|
|||
if (Format != DXGI_FORMAT_UNKNOWN)
|
||||
m_desc.Format = Format;
|
||||
|
||||
return m_presenter->ChangeProperties(&m_desc, pCreationNodeMask, ppPresentQueue);
|
||||
HRESULT hr = m_presenter->ChangeProperties(&m_desc, pCreationNodeMask, ppPresentQueue);
|
||||
|
||||
if (FAILED(hr))
|
||||
return hr;
|
||||
|
||||
UpdateColorSpace(m_desc.Format, m_colorSpace);
|
||||
return hr;
|
||||
}
|
||||
|
||||
|
||||
|
@ -567,36 +588,31 @@ namespace dxvk {
|
|||
if (!pColorSpaceSupport)
|
||||
return E_INVALIDARG;
|
||||
|
||||
// Don't expose any color spaces other than standard
|
||||
// sRGB if the enableHDR option is not set.
|
||||
//
|
||||
// If we ever have a use for the non-SRGB non-HDR colorspaces
|
||||
// some day, we may want to revisit this.
|
||||
if (ColorSpace != DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709
|
||||
&& !m_factory->GetOptions()->enableHDR) {
|
||||
*pColorSpaceSupport = 0;
|
||||
return S_OK;
|
||||
}
|
||||
std::lock_guard<dxvk::mutex> lock(m_lockBuffer);
|
||||
|
||||
if (ValidateColorSpaceSupport(m_desc.Format, ColorSpace))
|
||||
*pColorSpaceSupport = DXGI_SWAP_CHAIN_COLOR_SPACE_SUPPORT_FLAG_PRESENT;
|
||||
else
|
||||
*pColorSpaceSupport = 0;
|
||||
|
||||
UINT support = m_presenter->CheckColorSpaceSupport(ColorSpace);
|
||||
*pColorSpaceSupport = support;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
HRESULT STDMETHODCALLTYPE DxgiSwapChain::SetColorSpace1(DXGI_COLOR_SPACE_TYPE ColorSpace) {
|
||||
UINT support = m_presenter->CheckColorSpaceSupport(ColorSpace);
|
||||
std::lock_guard<dxvk::mutex> lock(m_lockBuffer);
|
||||
|
||||
if (!support)
|
||||
if (!ValidateColorSpaceSupport(m_desc.Format, ColorSpace))
|
||||
return E_INVALIDARG;
|
||||
|
||||
std::lock_guard<dxvk::mutex> lock(m_lockBuffer);
|
||||
HRESULT hr = m_presenter->SetColorSpace(ColorSpace);
|
||||
if (SUCCEEDED(hr)) {
|
||||
// If this was a colorspace other than our current one,
|
||||
// punt us into that one on the DXGI output.
|
||||
m_monitorInfo->PuntColorSpace(ColorSpace);
|
||||
}
|
||||
// Write back color space if setting it up succeeded. This way, we preserve
|
||||
// the current color space even if the swap chain temporarily switches to a
|
||||
// back buffer format which does not support it.
|
||||
HRESULT hr = UpdateColorSpace(m_desc.Format, ColorSpace);
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
m_colorSpace = ColorSpace;
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
|
@ -864,6 +880,7 @@ namespace dxvk {
|
|||
m_monitorInfo->ReleaseMonitorData();
|
||||
}
|
||||
|
||||
|
||||
void DxgiSwapChain::UpdateGlobalHDRState() {
|
||||
// Update the global HDR state if called from the legacy NVAPI
|
||||
// interfaces, etc.
|
||||
|
@ -888,4 +905,51 @@ namespace dxvk {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
bool DxgiSwapChain::ValidateColorSpaceSupport(
|
||||
DXGI_FORMAT Format,
|
||||
DXGI_COLOR_SPACE_TYPE ColorSpace) {
|
||||
// RGBA16 swap chains are treated as scRGB even on SDR displays,
|
||||
// and regular sRGB is not exposed when this format is used.
|
||||
if (Format == DXGI_FORMAT_R16G16B16A16_FLOAT)
|
||||
return ColorSpace == DXGI_COLOR_SPACE_RGB_FULL_G10_NONE_P709;
|
||||
|
||||
// For everything else, we will always expose plain sRGB
|
||||
if (ColorSpace == DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709)
|
||||
return true;
|
||||
|
||||
// Only expose HDR10 color space if HDR option is enabled
|
||||
if (ColorSpace == DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020)
|
||||
return m_factory->GetOptions()->enableHDR && m_presenter->CheckColorSpaceSupport(ColorSpace);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
HRESULT DxgiSwapChain::UpdateColorSpace(
|
||||
DXGI_FORMAT Format,
|
||||
DXGI_COLOR_SPACE_TYPE ColorSpace) {
|
||||
// Don't do anything if the explicitly sepected color space
|
||||
// is compatible with the back buffer format already
|
||||
if (!ValidateColorSpaceSupport(Format, ColorSpace)) {
|
||||
ColorSpace = Format == DXGI_FORMAT_R16G16B16A16_FLOAT
|
||||
? DXGI_COLOR_SPACE_RGB_FULL_G10_NONE_P709
|
||||
: DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709;
|
||||
}
|
||||
|
||||
// Ensure that we pick a supported color space. This is relevant for
|
||||
// mapping scRGB to sRGB on SDR setups, matching Windows behaviour.
|
||||
if (!m_presenter->CheckColorSpaceSupport(ColorSpace))
|
||||
ColorSpace = DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709;
|
||||
|
||||
HRESULT hr = m_presenter->SetColorSpace(ColorSpace);
|
||||
|
||||
// If this was a colorspace other than our current one,
|
||||
// punt us into that one on the DXGI output.
|
||||
if (SUCCEEDED(hr))
|
||||
m_monitorInfo->PuntColorSpace(ColorSpace);
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -193,6 +193,8 @@ namespace dxvk {
|
|||
bool m_frameStatisticsDisjoint = true;
|
||||
wsi::DxvkWindowState m_windowState;
|
||||
|
||||
DXGI_COLOR_SPACE_TYPE m_colorSpace = DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709;
|
||||
|
||||
uint32_t m_globalHDRStateSerial = 0;
|
||||
|
||||
HRESULT EnterFullscreenMode(
|
||||
|
@ -223,6 +225,18 @@ namespace dxvk {
|
|||
|
||||
void UpdateGlobalHDRState();
|
||||
|
||||
bool ValidateColorSpaceSupport(
|
||||
DXGI_FORMAT Format,
|
||||
DXGI_COLOR_SPACE_TYPE ColorSpace);
|
||||
|
||||
HRESULT UpdateColorSpace(
|
||||
DXGI_FORMAT Format,
|
||||
DXGI_COLOR_SPACE_TYPE ColorSpace);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE PresentBase(
|
||||
UINT SyncInterval,
|
||||
UINT PresentFlags,
|
||||
const DXGI_PRESENT_PARAMETERS* pPresentParameters);
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -21,17 +21,24 @@ if platform != 'windows'
|
|||
dxgi_link_depends += files('dxgi.sym')
|
||||
endif
|
||||
|
||||
dxgi_dll = shared_library('dxgi'+dll_ext, dxgi_src, dxgi_res,
|
||||
name_prefix : dxvk_name_prefix,
|
||||
dxgi_dll = shared_library(dxvk_name_prefix+'dxgi', dxgi_src, dxgi_res,
|
||||
dependencies : [ dxvk_dep ],
|
||||
include_directories : dxvk_include_path,
|
||||
install : true,
|
||||
vs_module_defs : 'dxgi'+def_spec_ext,
|
||||
link_args : dxgi_ld_args,
|
||||
link_depends : [ dxgi_link_depends ],
|
||||
kwargs : dxvk_so_version,
|
||||
)
|
||||
|
||||
dxgi_dep = declare_dependency(
|
||||
link_with : [ dxgi_dll ],
|
||||
include_directories : [ dxvk_include_path ],
|
||||
)
|
||||
|
||||
if platform != 'windows'
|
||||
pkg.generate(dxgi_dll,
|
||||
filebase: dxvk_pkg_prefix + 'dxgi',
|
||||
subdirs: 'dxvk',
|
||||
)
|
||||
endif
|
||||
|
|
|
@ -228,8 +228,8 @@ namespace dxvk {
|
|||
info.bindings = m_bindings.data();
|
||||
info.inputMask = m_inputMask;
|
||||
info.outputMask = m_outputMask;
|
||||
info.pushConstOffset = m_pushConstOffset;
|
||||
info.pushConstSize = m_pushConstSize;
|
||||
info.pushConstStages = VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT;
|
||||
info.pushConstSize = sizeof(D3D9RenderStateInfo);
|
||||
|
||||
if (m_programInfo.type() == DxsoProgramTypes::PixelShader)
|
||||
info.flatShadingInputs = m_ps.flatShadingMask;
|
||||
|
@ -2029,12 +2029,22 @@ namespace dxvk {
|
|||
result.id = resultIndices[0];
|
||||
else
|
||||
result.id = m_module.opCompositeConstruct(typeId, result.type.ccount, resultIndices.data());
|
||||
|
||||
if (m_moduleInfo.options.d3d9FloatEmulation == D3D9FloatEmulation::Enabled) {
|
||||
result.id = m_module.opNMin(typeId, result.id,
|
||||
m_module.constfReplicant(FLT_MAX, result.type.ccount));
|
||||
}
|
||||
break;
|
||||
}
|
||||
[[fallthrough]];
|
||||
case DxsoOpcode::Exp:
|
||||
result.id = m_module.opExp2(typeId,
|
||||
emitRegisterLoad(src[0], mask).id);
|
||||
|
||||
if (m_moduleInfo.options.d3d9FloatEmulation == D3D9FloatEmulation::Enabled) {
|
||||
result.id = m_module.opNMin(typeId, result.id,
|
||||
m_module.constfReplicant(FLT_MAX, result.type.ccount));
|
||||
}
|
||||
break;
|
||||
case DxsoOpcode::Pow: {
|
||||
uint32_t base = emitRegisterLoad(src[0], mask).id;
|
||||
|
@ -3551,30 +3561,7 @@ void DxsoCompiler::emitControlFlowGenericLoop(
|
|||
|
||||
|
||||
void DxsoCompiler::setupRenderStateInfo() {
|
||||
uint32_t count;
|
||||
|
||||
// Only need alpha ref for PS 3.
|
||||
// No FF fog component.
|
||||
if (m_programInfo.type() == DxsoProgramType::PixelShader) {
|
||||
if (m_programInfo.majorVersion() == 3) {
|
||||
m_pushConstOffset = offsetof(D3D9RenderStateInfo, alphaRef);
|
||||
m_pushConstSize = sizeof(float);
|
||||
}
|
||||
else {
|
||||
m_pushConstOffset = 0;
|
||||
m_pushConstSize = offsetof(D3D9RenderStateInfo, pointSize);
|
||||
}
|
||||
|
||||
count = 5;
|
||||
}
|
||||
else {
|
||||
m_pushConstOffset = offsetof(D3D9RenderStateInfo, pointSize);
|
||||
// Point scale never triggers on programmable
|
||||
m_pushConstSize = sizeof(float) * 3;
|
||||
count = 8;
|
||||
}
|
||||
|
||||
m_rsBlock = SetupRenderStateBlock(m_module, count);
|
||||
m_rsBlock = SetupRenderStateBlock(m_module);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -344,8 +344,6 @@ namespace dxvk {
|
|||
// covers vertex input and fragment output.
|
||||
uint32_t m_inputMask = 0u;
|
||||
uint32_t m_outputMask = 0u;
|
||||
uint32_t m_pushConstOffset = 0u;
|
||||
uint32_t m_pushConstSize = 0u;
|
||||
|
||||
///////////////////////////////////
|
||||
// Shader-specific data structures
|
||||
|
|
|
@ -346,6 +346,11 @@ namespace dxvk {
|
|||
enabledFeatures.vk13.synchronization2 = VK_TRUE;
|
||||
enabledFeatures.vk13.dynamicRendering = VK_TRUE;
|
||||
|
||||
// Maintenance4 may cause performance problems on amdvlk in some cases
|
||||
if (m_deviceInfo.vk12.driverID != VK_DRIVER_ID_AMD_OPEN_SOURCE
|
||||
&& m_deviceInfo.vk12.driverID != VK_DRIVER_ID_AMD_PROPRIETARY)
|
||||
enabledFeatures.vk13.maintenance4 = VK_TRUE;
|
||||
|
||||
// We expose depth clip rather than depth clamp to client APIs
|
||||
enabledFeatures.extDepthClipEnable.depthClipEnable =
|
||||
m_deviceFeatures.extDepthClipEnable.depthClipEnable;
|
||||
|
@ -410,21 +415,26 @@ namespace dxvk {
|
|||
m_deviceFeatures.khrPresentWait.presentWait;
|
||||
|
||||
// Unless we're on an Nvidia driver where these extensions are known to be broken
|
||||
if (matchesDriver(VK_DRIVER_ID_NVIDIA_PROPRIETARY, 0, VK_MAKE_VERSION(535, 0, 0))) {
|
||||
if (matchesDriver(VK_DRIVER_ID_NVIDIA_PROPRIETARY, Version(), Version(535, 0, 0))) {
|
||||
enabledFeatures.khrPresentId.presentId = VK_FALSE;
|
||||
enabledFeatures.khrPresentWait.presentWait = VK_FALSE;
|
||||
}
|
||||
|
||||
// Enable descriptor pool overallocation if supported
|
||||
enabledFeatures.nvDescriptorPoolOverallocation.descriptorPoolOverallocation =
|
||||
m_deviceFeatures.nvDescriptorPoolOverallocation.descriptorPoolOverallocation;
|
||||
|
||||
// Enable raw access chains for shader backends
|
||||
enabledFeatures.nvRawAccessChains.shaderRawAccessChains =
|
||||
m_deviceFeatures.nvRawAccessChains.shaderRawAccessChains;
|
||||
|
||||
// Create pNext chain for additional device features
|
||||
initFeatureChain(enabledFeatures, devExtensions, instance->extensions());
|
||||
|
||||
// Log feature support info an extension list
|
||||
Logger::info(str::format("Device properties:"
|
||||
"\n Device : ", m_deviceInfo.core.properties.deviceName,
|
||||
"\n Driver : ", m_deviceInfo.vk12.driverName, " ",
|
||||
VK_VERSION_MAJOR(m_deviceInfo.core.properties.driverVersion), ".",
|
||||
VK_VERSION_MINOR(m_deviceInfo.core.properties.driverVersion), ".",
|
||||
VK_VERSION_PATCH(m_deviceInfo.core.properties.driverVersion)));
|
||||
"\n Driver : ", m_deviceInfo.vk12.driverName, " ", m_deviceInfo.driverVersion.toString()));
|
||||
|
||||
Logger::info("Enabled device extensions:");
|
||||
this->logNameList(extensionNameList);
|
||||
|
@ -606,6 +616,14 @@ namespace dxvk {
|
|||
enabledFeatures.khrPresentWait = *reinterpret_cast<const VkPhysicalDevicePresentWaitFeaturesKHR*>(f);
|
||||
break;
|
||||
|
||||
case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_POOL_OVERALLOCATION_FEATURES_NV:
|
||||
enabledFeatures.nvDescriptorPoolOverallocation = *reinterpret_cast<const VkPhysicalDeviceDescriptorPoolOverallocationFeaturesNV*>(f);
|
||||
break;
|
||||
|
||||
case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAW_ACCESS_CHAINS_FEATURES_NV:
|
||||
enabledFeatures.nvRawAccessChains = *reinterpret_cast<const VkPhysicalDeviceRawAccessChainsFeaturesNV*>(f);
|
||||
break;
|
||||
|
||||
default:
|
||||
// Ignore any unknown feature structs
|
||||
break;
|
||||
|
@ -618,9 +636,7 @@ namespace dxvk {
|
|||
Logger::info(str::format("Device properties:"
|
||||
"\n Device name: ", m_deviceInfo.core.properties.deviceName,
|
||||
"\n Driver: ", m_deviceInfo.vk12.driverName, " ",
|
||||
VK_VERSION_MAJOR(m_deviceInfo.core.properties.driverVersion), ".",
|
||||
VK_VERSION_MINOR(m_deviceInfo.core.properties.driverVersion), ".",
|
||||
VK_VERSION_PATCH(m_deviceInfo.core.properties.driverVersion)));
|
||||
m_deviceInfo.driverVersion.toString()));
|
||||
|
||||
Logger::info("Enabled device extensions:");
|
||||
this->logNameList(extensionNameList);
|
||||
|
@ -656,26 +672,29 @@ namespace dxvk {
|
|||
|
||||
bool DxvkAdapter::matchesDriver(
|
||||
VkDriverIdKHR driver,
|
||||
uint32_t minVer,
|
||||
uint32_t maxVer) const {
|
||||
Version minVer,
|
||||
Version maxVer) const {
|
||||
bool driverMatches = driver == m_deviceInfo.vk12.driverID;
|
||||
|
||||
if (minVer) driverMatches &= m_deviceInfo.core.properties.driverVersion >= minVer;
|
||||
if (maxVer) driverMatches &= m_deviceInfo.core.properties.driverVersion < maxVer;
|
||||
if (minVer) driverMatches &= m_deviceInfo.driverVersion >= minVer;
|
||||
if (maxVer) driverMatches &= m_deviceInfo.driverVersion < maxVer;
|
||||
|
||||
return driverMatches;
|
||||
}
|
||||
|
||||
|
||||
bool DxvkAdapter::matchesDriver(
|
||||
VkDriverIdKHR driver) const {
|
||||
return driver == m_deviceInfo.vk12.driverID;
|
||||
}
|
||||
|
||||
|
||||
void DxvkAdapter::logAdapterInfo() const {
|
||||
const auto deviceInfo = this->devicePropertiesExt();
|
||||
const auto memoryInfo = this->memoryProperties();
|
||||
|
||||
Logger::info(str::format(deviceInfo.core.properties.deviceName, ":",
|
||||
"\n Driver : ", deviceInfo.vk12.driverName, " ",
|
||||
VK_VERSION_MAJOR(deviceInfo.core.properties.driverVersion), ".",
|
||||
VK_VERSION_MINOR(deviceInfo.core.properties.driverVersion), ".",
|
||||
VK_VERSION_PATCH(deviceInfo.core.properties.driverVersion)));
|
||||
"\n Driver : ", deviceInfo.vk12.driverName, " ", deviceInfo.driverVersion.toString()));
|
||||
|
||||
for (uint32_t i = 0; i < memoryInfo.memoryHeapCount; i++) {
|
||||
constexpr VkDeviceSize mib = 1024 * 1024;
|
||||
|
@ -777,22 +796,8 @@ namespace dxvk {
|
|||
m_vki->vkGetPhysicalDeviceProperties2(m_handle, &m_deviceInfo.core);
|
||||
|
||||
// Some drivers reports the driver version in a slightly different format
|
||||
switch (m_deviceInfo.vk12.driverID) {
|
||||
case VK_DRIVER_ID_NVIDIA_PROPRIETARY:
|
||||
m_deviceInfo.core.properties.driverVersion = VK_MAKE_VERSION(
|
||||
(m_deviceInfo.core.properties.driverVersion >> 22) & 0x3ff,
|
||||
(m_deviceInfo.core.properties.driverVersion >> 14) & 0x0ff,
|
||||
(m_deviceInfo.core.properties.driverVersion >> 6) & 0x0ff);
|
||||
break;
|
||||
|
||||
case VK_DRIVER_ID_INTEL_PROPRIETARY_WINDOWS:
|
||||
m_deviceInfo.core.properties.driverVersion = VK_MAKE_VERSION(
|
||||
m_deviceInfo.core.properties.driverVersion >> 14,
|
||||
m_deviceInfo.core.properties.driverVersion & 0x3fff, 0);
|
||||
break;
|
||||
|
||||
default:;
|
||||
}
|
||||
m_deviceInfo.driverVersion = decodeDriverVersion(
|
||||
m_deviceInfo.vk12.driverID, m_deviceInfo.core.properties.driverVersion);
|
||||
}
|
||||
|
||||
|
||||
|
@ -927,6 +932,16 @@ namespace dxvk {
|
|||
m_deviceFeatures.khrPresentWait.pNext = std::exchange(m_deviceFeatures.core.pNext, &m_deviceFeatures.khrPresentWait);
|
||||
}
|
||||
|
||||
if (m_deviceExtensions.supports(VK_NV_DESCRIPTOR_POOL_OVERALLOCATION_EXTENSION_NAME)) {
|
||||
m_deviceFeatures.nvDescriptorPoolOverallocation.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_POOL_OVERALLOCATION_FEATURES_NV;
|
||||
m_deviceFeatures.nvDescriptorPoolOverallocation.pNext = std::exchange(m_deviceFeatures.core.pNext, &m_deviceFeatures.nvDescriptorPoolOverallocation);
|
||||
}
|
||||
|
||||
if (m_deviceExtensions.supports(VK_NV_RAW_ACCESS_CHAINS_EXTENSION_NAME)) {
|
||||
m_deviceFeatures.nvRawAccessChains.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAW_ACCESS_CHAINS_FEATURES_NV;
|
||||
m_deviceFeatures.nvRawAccessChains.pNext = std::exchange(m_deviceFeatures.core.pNext, &m_deviceFeatures.nvRawAccessChains);
|
||||
}
|
||||
|
||||
if (m_deviceExtensions.supports(VK_NVX_BINARY_IMPORT_EXTENSION_NAME))
|
||||
m_deviceFeatures.nvxBinaryImport = VK_TRUE;
|
||||
|
||||
|
@ -994,6 +1009,8 @@ namespace dxvk {
|
|||
&devExtensions.khrPresentWait,
|
||||
&devExtensions.khrSwapchain,
|
||||
&devExtensions.khrWin32KeyedMutex,
|
||||
&devExtensions.nvDescriptorPoolOverallocation,
|
||||
&devExtensions.nvRawAccessChains,
|
||||
&devExtensions.nvxBinaryImport,
|
||||
&devExtensions.nvxImageViewHandle,
|
||||
}};
|
||||
|
@ -1133,6 +1150,16 @@ namespace dxvk {
|
|||
enabledFeatures.khrPresentWait.pNext = std::exchange(enabledFeatures.core.pNext, &enabledFeatures.khrPresentWait);
|
||||
}
|
||||
|
||||
if (devExtensions.nvDescriptorPoolOverallocation) {
|
||||
enabledFeatures.nvDescriptorPoolOverallocation.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_POOL_OVERALLOCATION_FEATURES_NV;
|
||||
enabledFeatures.nvDescriptorPoolOverallocation.pNext = std::exchange(enabledFeatures.core.pNext, &enabledFeatures.nvDescriptorPoolOverallocation);
|
||||
}
|
||||
|
||||
if (devExtensions.nvRawAccessChains) {
|
||||
enabledFeatures.nvRawAccessChains.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAW_ACCESS_CHAINS_FEATURES_NV;
|
||||
enabledFeatures.nvRawAccessChains.pNext = std::exchange(enabledFeatures.core.pNext, &enabledFeatures.nvRawAccessChains);
|
||||
}
|
||||
|
||||
if (devExtensions.nvxBinaryImport)
|
||||
enabledFeatures.nvxBinaryImport = VK_TRUE;
|
||||
|
||||
|
@ -1279,6 +1306,10 @@ namespace dxvk {
|
|||
"\n presentId : ", features.khrPresentId.presentId ? "1" : "0",
|
||||
"\n", VK_KHR_PRESENT_WAIT_EXTENSION_NAME,
|
||||
"\n presentWait : ", features.khrPresentWait.presentWait ? "1" : "0",
|
||||
"\n", VK_NV_DESCRIPTOR_POOL_OVERALLOCATION_EXTENSION_NAME,
|
||||
"\n descriptorPoolOverallocation : ", features.nvDescriptorPoolOverallocation.descriptorPoolOverallocation ? "1" : "0",
|
||||
"\n", VK_NV_RAW_ACCESS_CHAINS_EXTENSION_NAME,
|
||||
"\n shaderRawAccessChains : ", features.nvRawAccessChains.shaderRawAccessChains ? "1" : "0",
|
||||
"\n", VK_NVX_BINARY_IMPORT_EXTENSION_NAME,
|
||||
"\n extension supported : ", features.nvxBinaryImport ? "1" : "0",
|
||||
"\n", VK_NVX_IMAGE_VIEW_HANDLE_EXTENSION_NAME,
|
||||
|
@ -1295,4 +1326,25 @@ namespace dxvk {
|
|||
"\n Sparse : ", queues.sparse != VK_QUEUE_FAMILY_IGNORED ? str::format(queues.sparse) : "n/a"));
|
||||
}
|
||||
|
||||
|
||||
Version DxvkAdapter::decodeDriverVersion(VkDriverId driverId, uint32_t version) {
|
||||
switch (driverId) {
|
||||
case VK_DRIVER_ID_NVIDIA_PROPRIETARY:
|
||||
return Version(
|
||||
(version >> 22) & 0x3ff,
|
||||
(version >> 14) & 0x0ff,
|
||||
(version >> 6) & 0x0ff);
|
||||
break;
|
||||
|
||||
case VK_DRIVER_ID_INTEL_PROPRIETARY_WINDOWS:
|
||||
return Version(version >> 14, version & 0x3fff, 0);
|
||||
|
||||
default:
|
||||
return Version(
|
||||
VK_API_VERSION_MAJOR(version),
|
||||
VK_API_VERSION_MINOR(version),
|
||||
VK_API_VERSION_PATCH(version));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -255,8 +255,17 @@ namespace dxvk {
|
|||
*/
|
||||
bool matchesDriver(
|
||||
VkDriverIdKHR driver,
|
||||
uint32_t minVer,
|
||||
uint32_t maxVer) const;
|
||||
Version minVer,
|
||||
Version maxVer) const;
|
||||
|
||||
/**
|
||||
* \brief Tests if the driver matches certain criteria
|
||||
*
|
||||
* \param [in] driver Driver ID
|
||||
* \returns \c True if the driver matches these criteria
|
||||
*/
|
||||
bool matchesDriver(
|
||||
VkDriverIdKHR driver) const;
|
||||
|
||||
/**
|
||||
* \brief Logs DXVK adapter info
|
||||
|
@ -343,6 +352,8 @@ namespace dxvk {
|
|||
static void logFeatures(const DxvkDeviceFeatures& features);
|
||||
static void logQueueFamilies(const DxvkAdapterQueueIndices& queues);
|
||||
|
||||
static Version decodeDriverVersion(VkDriverId driverId, uint32_t version);
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -28,8 +28,6 @@ public:
|
|||
|
||||
};
|
||||
|
||||
#ifdef _MSC_VER
|
||||
struct __declspec(uuid("7f2c2f72-1cc8-4979-8d9c-7e3faeddecde")) IDXVKUserDefinedAnnotation;
|
||||
#else
|
||||
#ifndef _MSC_VER
|
||||
__CRT_UUID_DECL(IDXVKUserDefinedAnnotation, 0x7f2c2f72,0x1cc8,0x4979,0x8d,0x9c,0x7e,0x3f,0xae,0xdd,0xec,0xde);
|
||||
#endif
|
||||
|
|
|
@ -671,7 +671,7 @@ namespace dxvk {
|
|||
uint32_t indexCount,
|
||||
uint32_t instanceCount,
|
||||
uint32_t firstIndex,
|
||||
uint32_t vertexOffset,
|
||||
int32_t vertexOffset,
|
||||
uint32_t firstInstance) {
|
||||
m_vkd->vkCmdDrawIndexed(m_cmd.execBuffer,
|
||||
indexCount, instanceCount,
|
||||
|
|
|
@ -48,9 +48,7 @@ namespace dxvk {
|
|||
// Retrieve actual pipeline handle on first use. This
|
||||
// may wait for an ongoing compile job to finish, or
|
||||
// compile the pipeline immediately on the calling thread.
|
||||
m_libraryHandle = m_library->acquirePipelineHandle(
|
||||
DxvkShaderPipelineLibraryCompileArgs());
|
||||
|
||||
m_libraryHandle = m_library->acquirePipelineHandle().handle;
|
||||
return m_libraryHandle;
|
||||
} else {
|
||||
// Slow path for compute shaders that do use spec constants
|
||||
|
|
|
@ -1354,7 +1354,7 @@ namespace dxvk {
|
|||
uint32_t indexCount,
|
||||
uint32_t instanceCount,
|
||||
uint32_t firstIndex,
|
||||
uint32_t vertexOffset,
|
||||
int32_t vertexOffset,
|
||||
uint32_t firstInstance) {
|
||||
if (this->commitGraphicsState<true, false>()) {
|
||||
m_cmd->cmdDrawIndexed(
|
||||
|
@ -1997,7 +1997,7 @@ namespace dxvk {
|
|||
depthOp.loadOpS = VK_ATTACHMENT_LOAD_OP_LOAD;
|
||||
depthOp.loadLayout = imageView->imageInfo().layout;
|
||||
depthOp.storeLayout = imageView->imageInfo().layout;
|
||||
|
||||
|
||||
if (clearAspects & VK_IMAGE_ASPECT_COLOR_BIT)
|
||||
colorOp.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
|
||||
else if (discardAspects & VK_IMAGE_ASPECT_COLOR_BIT)
|
||||
|
@ -2010,7 +2010,7 @@ namespace dxvk {
|
|||
|
||||
if (clearAspects & VK_IMAGE_ASPECT_STENCIL_BIT)
|
||||
depthOp.loadOpS = VK_ATTACHMENT_LOAD_OP_CLEAR;
|
||||
else if (discardAspects & VK_IMAGE_ASPECT_DEPTH_BIT)
|
||||
else if (discardAspects & VK_IMAGE_ASPECT_STENCIL_BIT)
|
||||
depthOp.loadOpS = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
|
||||
|
||||
if (attachmentIndex >= 0 && !m_state.om.framebufferInfo.isWritable(attachmentIndex, clearAspects | discardAspects)) {
|
||||
|
@ -2041,6 +2041,8 @@ namespace dxvk {
|
|||
}
|
||||
|
||||
if (attachmentIndex < 0) {
|
||||
bool hasViewFormatMismatch = imageView->info().format != imageView->imageInfo().format;
|
||||
|
||||
if (m_execBarriers.isImageDirty(imageView->image(), imageView->imageSubresources(), DxvkAccess::Write))
|
||||
m_execBarriers.recordCommands(m_cmd);
|
||||
|
||||
|
@ -2075,6 +2077,11 @@ namespace dxvk {
|
|||
|
||||
attachmentInfo.loadOp = colorOp.loadOp;
|
||||
|
||||
// We can't use LOAD_OP_CLEAR if the view format does not match the
|
||||
// underlying image format, so just discard here and use clear later.
|
||||
if (hasViewFormatMismatch && attachmentInfo.loadOp == VK_ATTACHMENT_LOAD_OP_CLEAR)
|
||||
attachmentInfo.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
|
||||
|
||||
renderingInfo.colorAttachmentCount = 1;
|
||||
renderingInfo.pColorAttachments = &attachmentInfo;
|
||||
|
||||
|
@ -2110,6 +2117,20 @@ namespace dxvk {
|
|||
}
|
||||
|
||||
m_cmd->cmdBeginRendering(&renderingInfo);
|
||||
|
||||
if (hasViewFormatMismatch) {
|
||||
VkClearAttachment clearInfo = { };
|
||||
clearInfo.aspectMask = imageView->info().aspect;
|
||||
clearInfo.clearValue = clearValue;
|
||||
|
||||
VkClearRect clearRect = { };
|
||||
clearRect.rect.extent.width = extent.width;
|
||||
clearRect.rect.extent.height = extent.height;
|
||||
clearRect.layerCount = imageView->info().numLayers;
|
||||
|
||||
m_cmd->cmdClearAttachments(1, &clearInfo, 1, &clearRect);
|
||||
}
|
||||
|
||||
m_cmd->cmdEndRendering();
|
||||
|
||||
m_execBarriers.accessImage(
|
||||
|
@ -3563,69 +3584,90 @@ namespace dxvk {
|
|||
VkImageSubresourceLayers srcSubresource,
|
||||
VkOffset3D srcOffset,
|
||||
VkExtent3D extent) {
|
||||
VkFormat viewFormat = m_common->metaCopy().getCopyDestinationFormat(
|
||||
dstSubresource.aspectMask,
|
||||
srcSubresource.aspectMask,
|
||||
srcImage->info().format);
|
||||
DxvkMetaCopyFormats viewFormats = m_common->metaCopy().getFormats(
|
||||
dstImage->info().format, dstSubresource.aspectMask,
|
||||
srcImage->info().format, srcSubresource.aspectMask);
|
||||
|
||||
if (!viewFormat) {
|
||||
Logger::err("DxvkContext: copyImageFb: Unsupported format");
|
||||
return;
|
||||
}
|
||||
|
||||
// Usually we should be able to draw directly to the destination image,
|
||||
// but in some cases this might not be possible, e.g. if when copying
|
||||
// from something like D32_SFLOAT to RGBA8_UNORM. In those situations,
|
||||
// create a temporary image to draw to, and then copy to the actual
|
||||
// destination image using a regular Vulkan transfer function.
|
||||
bool useDirectCopy = (dstImage->info().usage & (VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT))
|
||||
&& (dstImage->isViewCompatible(viewFormat));
|
||||
bool dstIsCompatible = (dstImage->info().usage & (VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT))
|
||||
&& (dstImage->isViewCompatible(viewFormats.dstFormat));
|
||||
bool srcIsCompatible = (srcImage->info().usage & (VK_IMAGE_USAGE_SAMPLED_BIT))
|
||||
&& (srcImage->isViewCompatible(viewFormats.srcFormat));
|
||||
|
||||
if (useDirectCopy) {
|
||||
if (dstIsCompatible && srcIsCompatible) {
|
||||
this->copyImageFbDirect(
|
||||
dstImage, dstSubresource, dstOffset, viewFormat,
|
||||
srcImage, srcSubresource, srcOffset, extent);
|
||||
} else {
|
||||
dstImage, dstSubresource, dstOffset, viewFormats.dstFormat,
|
||||
srcImage, srcSubresource, srcOffset, viewFormats.srcFormat, extent);
|
||||
} else if (dstIsCompatible || srcIsCompatible) {
|
||||
DxvkImageCreateInfo imageInfo = dstImage->info();
|
||||
imageInfo.format = viewFormat;
|
||||
imageInfo.flags = 0;
|
||||
imageInfo.usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
|
||||
imageInfo.extent = extent;
|
||||
imageInfo.numLayers = dstSubresource.layerCount;
|
||||
imageInfo.mipLevels = 1;
|
||||
imageInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
|
||||
imageInfo.layout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
|
||||
imageInfo.stages = VK_PIPELINE_STAGE_TRANSFER_BIT;
|
||||
imageInfo.access = VK_ACCESS_TRANSFER_READ_BIT;
|
||||
imageInfo.viewFormatCount = 0;
|
||||
|
||||
if (dstImage->formatInfo()->aspectMask & VK_IMAGE_ASPECT_COLOR_BIT) {
|
||||
imageInfo.usage |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
|
||||
imageInfo.stages |= VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
|
||||
imageInfo.access |= VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
|
||||
} else {
|
||||
imageInfo.usage |= VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
|
||||
imageInfo.stages |= VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT
|
||||
| VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
|
||||
imageInfo.access |= VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
|
||||
if (!dstIsCompatible) {
|
||||
imageInfo.format = viewFormats.dstFormat;
|
||||
imageInfo.numLayers = dstSubresource.layerCount;
|
||||
imageInfo.usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
|
||||
imageInfo.layout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
|
||||
imageInfo.stages = VK_PIPELINE_STAGE_TRANSFER_BIT;
|
||||
imageInfo.access = VK_ACCESS_TRANSFER_READ_BIT;
|
||||
|
||||
if (dstImage->formatInfo()->aspectMask & VK_IMAGE_ASPECT_COLOR_BIT) {
|
||||
imageInfo.usage |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
|
||||
imageInfo.stages |= VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
|
||||
imageInfo.access |= VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
|
||||
} else {
|
||||
imageInfo.usage |= VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
|
||||
imageInfo.stages |= VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT
|
||||
| VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
|
||||
imageInfo.access |= VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
|
||||
}
|
||||
} else /* if (!srcIsCompatible) */ {
|
||||
imageInfo.format = viewFormats.srcFormat;
|
||||
imageInfo.numLayers = srcSubresource.layerCount;
|
||||
imageInfo.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT;
|
||||
imageInfo.layout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
|
||||
imageInfo.stages = VK_PIPELINE_STAGE_TRANSFER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
|
||||
imageInfo.access = VK_ACCESS_TRANSFER_WRITE_BIT | VK_ACCESS_SHADER_READ_BIT;
|
||||
}
|
||||
|
||||
Rc<DxvkImage> tmpImage = m_device->createImage(imageInfo,
|
||||
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
|
||||
Rc<DxvkImage> tmpImage = m_device->createImage(imageInfo, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
|
||||
|
||||
VkImageSubresourceLayers tmpSubresource = dstSubresource;
|
||||
VkImageSubresourceLayers tmpSubresource = { };
|
||||
tmpSubresource.aspectMask = tmpImage->formatInfo()->aspectMask;
|
||||
tmpSubresource.mipLevel = 0;
|
||||
tmpSubresource.baseArrayLayer = 0;
|
||||
tmpSubresource.layerCount = imageInfo.numLayers;
|
||||
|
||||
VkOffset3D tmpOffset = { 0, 0, 0 };
|
||||
|
||||
this->copyImageFbDirect(
|
||||
tmpImage, tmpSubresource, tmpOffset, viewFormat,
|
||||
srcImage, srcSubresource, srcOffset, extent);
|
||||
if (!dstIsCompatible) {
|
||||
this->copyImageFbDirect(
|
||||
tmpImage, tmpSubresource, tmpOffset, viewFormats.dstFormat,
|
||||
srcImage, srcSubresource, srcOffset, viewFormats.srcFormat, extent);
|
||||
|
||||
this->copyImageHw(
|
||||
dstImage, dstSubresource, dstOffset,
|
||||
tmpImage, tmpSubresource, tmpOffset, extent);
|
||||
this->copyImageHw(
|
||||
dstImage, dstSubresource, dstOffset,
|
||||
tmpImage, tmpSubresource, tmpOffset, extent);
|
||||
} else /* if (!srcIsCompatible) */ {
|
||||
this->copyImageHw(
|
||||
tmpImage, tmpSubresource, tmpOffset,
|
||||
srcImage, srcSubresource, srcOffset, extent);
|
||||
|
||||
this->copyImageFbDirect(
|
||||
dstImage, dstSubresource, dstOffset, viewFormats.dstFormat,
|
||||
tmpImage, tmpSubresource, tmpOffset, viewFormats.srcFormat, extent);
|
||||
}
|
||||
} else {
|
||||
Logger::err(str::format("DxvkContext: copyImageFb: Unsupported operation:\n"
|
||||
" srcFormat = ", srcImage->info().format, " (aspect ", srcSubresource.aspectMask, ")\n",
|
||||
" dstFormat = ", dstImage->info().format, " (aspect ", dstSubresource.aspectMask, ")"));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3638,6 +3680,7 @@ namespace dxvk {
|
|||
const Rc<DxvkImage>& srcImage,
|
||||
VkImageSubresourceLayers srcSubresource,
|
||||
VkOffset3D srcOffset,
|
||||
VkFormat srcFormat,
|
||||
VkExtent3D extent) {
|
||||
this->invalidateState();
|
||||
|
||||
|
@ -3701,8 +3744,6 @@ namespace dxvk {
|
|||
m_execAcquires.recordCommands(m_cmd);
|
||||
|
||||
// Create source and destination image views
|
||||
VkFormat srcFormat = srcImage->info().format;
|
||||
|
||||
Rc<DxvkMetaCopyViews> views = new DxvkMetaCopyViews(m_device->vkd(),
|
||||
dstImage, dstSubresource, dstFormat,
|
||||
srcImage, srcSubresource, srcFormat);
|
||||
|
@ -4721,8 +4762,10 @@ namespace dxvk {
|
|||
this->renderPassEmitPostBarriers(framebufferInfo, ops);
|
||||
|
||||
uint32_t colorInfoCount = 0;
|
||||
uint32_t lateClearCount = 0;
|
||||
|
||||
std::array<VkRenderingAttachmentInfo, MaxNumRenderTargets> colorInfos;
|
||||
std::array<VkClearAttachment, MaxNumRenderTargets> lateClears;
|
||||
|
||||
for (uint32_t i = 0; i < MaxNumRenderTargets; i++) {
|
||||
const auto& colorTarget = framebufferInfo.getColorTarget(i);
|
||||
|
@ -4734,9 +4777,21 @@ namespace dxvk {
|
|||
colorInfos[i].loadOp = ops.colorOps[i].loadOp;
|
||||
colorInfos[i].storeOp = VK_ATTACHMENT_STORE_OP_STORE;
|
||||
|
||||
if (ops.colorOps[i].loadOp == VK_ATTACHMENT_LOAD_OP_CLEAR)
|
||||
if (ops.colorOps[i].loadOp == VK_ATTACHMENT_LOAD_OP_CLEAR) {
|
||||
colorInfos[i].clearValue.color = ops.colorOps[i].clearValue;
|
||||
|
||||
// We can't use LOAD_OP_CLEAR if the view format does not match the
|
||||
// underlying image format, so just discard here and use clear later.
|
||||
if (colorTarget.view->info().format != colorTarget.view->imageInfo().format) {
|
||||
colorInfos[i].loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
|
||||
|
||||
auto& clear = lateClears[lateClearCount++];
|
||||
clear.colorAttachment = i;
|
||||
clear.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
clear.clearValue.color = ops.colorOps[i].clearValue;
|
||||
}
|
||||
}
|
||||
|
||||
colorInfoCount = i + 1;
|
||||
}
|
||||
}
|
||||
|
@ -4784,6 +4839,15 @@ namespace dxvk {
|
|||
|
||||
m_cmd->cmdBeginRendering(&renderingInfo);
|
||||
|
||||
if (lateClearCount) {
|
||||
VkClearRect clearRect = { };
|
||||
clearRect.rect.extent.width = fbSize.width;
|
||||
clearRect.rect.extent.height = fbSize.height;
|
||||
clearRect.layerCount = fbSize.layers;
|
||||
|
||||
m_cmd->cmdClearAttachments(lateClearCount, lateClears.data(), 1, &clearRect);
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < framebufferInfo.numAttachments(); i++) {
|
||||
m_cmd->trackResource<DxvkAccess::None> (framebufferInfo.getAttachment(i).view);
|
||||
m_cmd->trackResource<DxvkAccess::Write>(framebufferInfo.getAttachment(i).view->image());
|
||||
|
@ -4920,7 +4984,7 @@ namespace dxvk {
|
|||
// Mark compute resources and push constants as dirty
|
||||
m_descriptorState.dirtyStages(VK_SHADER_STAGE_COMPUTE_BIT);
|
||||
|
||||
if (newPipeline->getBindings()->layout().getPushConstantRange().size)
|
||||
if (newPipeline->getBindings()->layout().getPushConstantRange(true).size)
|
||||
m_flags.set(DxvkContextFlag::DirtyPushConstants);
|
||||
|
||||
m_flags.clr(DxvkContextFlag::CpDirtyPipelineState);
|
||||
|
@ -4994,7 +5058,7 @@ namespace dxvk {
|
|||
|
||||
m_descriptorState.dirtyStages(VK_SHADER_STAGE_ALL_GRAPHICS);
|
||||
|
||||
if (newPipeline->getBindings()->layout().getPushConstantRange().size)
|
||||
if (newPipeline->getBindings()->layout().getPushConstantRange(true).size)
|
||||
m_flags.set(DxvkContextFlag::DirtyPushConstants);
|
||||
|
||||
m_flags.clr(DxvkContextFlag::GpDirtyPipeline);
|
||||
|
@ -5594,11 +5658,13 @@ namespace dxvk {
|
|||
auto bufferInfo = m_state.vi.indexBuffer.getDescriptor();
|
||||
|
||||
if (m_features.test(DxvkContextFeature::IndexBufferRobustness)) {
|
||||
VkDeviceSize align = m_state.vi.indexType == VK_INDEX_TYPE_UINT16 ? 2 : 4;
|
||||
VkDeviceSize range = bufferInfo.buffer.range & ~(align - 1);
|
||||
|
||||
m_cmd->cmdBindIndexBuffer2(
|
||||
bufferInfo.buffer.buffer,
|
||||
bufferInfo.buffer.offset,
|
||||
bufferInfo.buffer.range,
|
||||
m_state.vi.indexType);
|
||||
range, m_state.vi.indexType);
|
||||
} else {
|
||||
m_cmd->cmdBindIndexBuffer(
|
||||
bufferInfo.buffer.buffer,
|
||||
|
@ -5859,16 +5925,19 @@ namespace dxvk {
|
|||
auto bindings = BindPoint == VK_PIPELINE_BIND_POINT_GRAPHICS
|
||||
? m_state.gp.pipeline->getBindings()
|
||||
: m_state.cp.pipeline->getBindings();
|
||||
|
||||
VkPushConstantRange pushConstRange = bindings->layout().getPushConstantRange();
|
||||
|
||||
// Optimized pipelines may have push constants trimmed, so look up
|
||||
// the exact layout used for the currently bound pipeline.
|
||||
bool independentSets = BindPoint == VK_PIPELINE_BIND_POINT_GRAPHICS
|
||||
&& m_flags.test(DxvkContextFlag::GpIndependentSets);
|
||||
|
||||
VkPushConstantRange pushConstRange = bindings->layout().getPushConstantRange(independentSets);
|
||||
|
||||
if (!pushConstRange.size)
|
||||
return;
|
||||
|
||||
// Push constants should be compatible between complete and
|
||||
// independent layouts, so always ask for the complete one
|
||||
m_cmd->cmdPushConstants(
|
||||
bindings->getPipelineLayout(false),
|
||||
bindings->getPipelineLayout(independentSets),
|
||||
pushConstRange.stageFlags,
|
||||
pushConstRange.offset,
|
||||
pushConstRange.size,
|
||||
|
|
|
@ -810,7 +810,7 @@ namespace dxvk {
|
|||
uint32_t indexCount,
|
||||
uint32_t instanceCount,
|
||||
uint32_t firstIndex,
|
||||
uint32_t vertexOffset,
|
||||
int32_t vertexOffset,
|
||||
uint32_t firstInstance);
|
||||
|
||||
/**
|
||||
|
@ -1506,6 +1506,7 @@ namespace dxvk {
|
|||
const Rc<DxvkImage>& srcImage,
|
||||
VkImageSubresourceLayers srcSubresource,
|
||||
VkOffset3D srcOffset,
|
||||
VkFormat srcFormat,
|
||||
VkExtent3D extent);
|
||||
|
||||
bool copyImageClear(
|
||||
|
|
|
@ -350,7 +350,7 @@ namespace dxvk {
|
|||
return m_chunk;
|
||||
}
|
||||
|
||||
operator bool () const {
|
||||
explicit operator bool () const {
|
||||
return m_chunk != nullptr;
|
||||
}
|
||||
|
||||
|
|
|
@ -72,7 +72,7 @@ namespace dxvk {
|
|||
// memory bloat. This may be necessary for off-screen
|
||||
// rendering applications, or in situations where games
|
||||
// pre-render a lot of images without presenting in between.
|
||||
return m_descriptorPools.size() >= 8;
|
||||
return m_descriptorPools.size() > MaxDesiredPoolCount;
|
||||
}
|
||||
|
||||
|
||||
|
@ -100,29 +100,25 @@ namespace dxvk {
|
|||
|
||||
|
||||
void DxvkDescriptorPool::reset() {
|
||||
// As a heuristic to save memory, check how many descriptors
|
||||
// have actively been used in the past couple of submissions.
|
||||
bool isLowUsageFrame = false;
|
||||
|
||||
// As a heuristic to save memory, check how many descriptor
|
||||
// sets were actually being used in past submissions.
|
||||
size_t poolCount = m_descriptorPools.size();
|
||||
bool needsReset = poolCount > MaxDesiredPoolCount;
|
||||
|
||||
if (poolCount > 1 || m_setsAllocated > m_manager->getMaxSetCount() / 2) {
|
||||
double factor = std::max(11.0 / 3.0 - double(poolCount) / 3.0, 1.0);
|
||||
isLowUsageFrame = double(m_setsUsed) * factor < double(m_setsAllocated);
|
||||
needsReset = double(m_setsUsed) * factor < double(m_setsAllocated);
|
||||
}
|
||||
|
||||
m_lowUsageFrames = isLowUsageFrame
|
||||
? m_lowUsageFrames + 1
|
||||
: 0;
|
||||
m_setsUsed = 0;
|
||||
|
||||
if (m_lowUsageFrames < 16) {
|
||||
if (!needsReset) {
|
||||
for (auto& entry : m_setLists)
|
||||
entry.second.reset();
|
||||
} else {
|
||||
// If most sets are no longer being used, reset and destroy
|
||||
// descriptor pools and reset all lookup tables in order to
|
||||
// accomodate more descriptors of different layouts.
|
||||
// If most sets are no longer needed, reset and destroy
|
||||
// descriptor pools and reset all lookup tables in order
|
||||
// to accomodate more descriptors of different layouts.
|
||||
for (auto pool : m_descriptorPools)
|
||||
m_manager->recycleVulkanDescriptorPool(pool);
|
||||
|
||||
|
@ -131,7 +127,6 @@ namespace dxvk {
|
|||
m_setMaps.clear();
|
||||
|
||||
m_setsAllocated = 0;
|
||||
m_lowUsageFrames = 0;
|
||||
}
|
||||
|
||||
m_cachedEntry = { nullptr, nullptr };
|
||||
|
@ -311,7 +306,12 @@ namespace dxvk {
|
|||
info.maxSets = m_maxSets;
|
||||
info.poolSizeCount = pools.size();
|
||||
info.pPoolSizes = pools.data();
|
||||
|
||||
|
||||
if (m_device->features().nvDescriptorPoolOverallocation.descriptorPoolOverallocation) {
|
||||
info.flags |= VK_DESCRIPTOR_POOL_CREATE_ALLOW_OVERALLOCATION_POOLS_BIT_NV
|
||||
| VK_DESCRIPTOR_POOL_CREATE_ALLOW_OVERALLOCATION_SETS_BIT_NV;
|
||||
}
|
||||
|
||||
VkDescriptorPool pool = VK_NULL_HANDLE;
|
||||
|
||||
if (vk->vkCreateDescriptorPool(vk->device(), &info, nullptr, &pool) != VK_SUCCESS)
|
||||
|
|
|
@ -80,7 +80,7 @@ namespace dxvk {
|
|||
* to be updated.
|
||||
*/
|
||||
class DxvkDescriptorPool : public RcObject {
|
||||
|
||||
constexpr static uint32_t MaxDesiredPoolCount = 2;
|
||||
public:
|
||||
|
||||
DxvkDescriptorPool(
|
||||
|
@ -155,8 +155,6 @@ namespace dxvk {
|
|||
|
||||
uint32_t m_prevSetsAllocated = 0;
|
||||
|
||||
uint32_t m_lowUsageFrames = 0;
|
||||
|
||||
DxvkDescriptorSetMap* getSetMapCached(
|
||||
const DxvkBindingLayoutObjects* layout);
|
||||
|
||||
|
|
|
@ -82,7 +82,7 @@ namespace dxvk {
|
|||
|
||||
// Disable lifetime tracking for drivers that do not have any
|
||||
// significant issues with 32-bit address space to begin with
|
||||
if (m_adapter->matchesDriver(VK_DRIVER_ID_MESA_RADV_KHR, 0, 0))
|
||||
if (m_adapter->matchesDriver(VK_DRIVER_ID_MESA_RADV_KHR))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
|
@ -325,12 +325,12 @@ namespace dxvk {
|
|||
DxvkDevicePerfHints DxvkDevice::getPerfHints() {
|
||||
DxvkDevicePerfHints hints;
|
||||
hints.preferFbDepthStencilCopy = m_features.extShaderStencilExport
|
||||
&& (m_adapter->matchesDriver(VK_DRIVER_ID_MESA_RADV_KHR, 0, 0)
|
||||
|| m_adapter->matchesDriver(VK_DRIVER_ID_AMD_OPEN_SOURCE_KHR, 0, 0)
|
||||
|| m_adapter->matchesDriver(VK_DRIVER_ID_AMD_PROPRIETARY_KHR, 0, 0));
|
||||
&& (m_adapter->matchesDriver(VK_DRIVER_ID_MESA_RADV_KHR)
|
||||
|| m_adapter->matchesDriver(VK_DRIVER_ID_AMD_OPEN_SOURCE_KHR)
|
||||
|| m_adapter->matchesDriver(VK_DRIVER_ID_AMD_PROPRIETARY_KHR));
|
||||
hints.preferFbResolve = m_features.amdShaderFragmentMask
|
||||
&& (m_adapter->matchesDriver(VK_DRIVER_ID_AMD_OPEN_SOURCE_KHR, 0, 0)
|
||||
|| m_adapter->matchesDriver(VK_DRIVER_ID_AMD_PROPRIETARY_KHR, 0, 0));
|
||||
&& (m_adapter->matchesDriver(VK_DRIVER_ID_AMD_OPEN_SOURCE_KHR)
|
||||
|| m_adapter->matchesDriver(VK_DRIVER_ID_AMD_PROPRIETARY_KHR));
|
||||
return hints;
|
||||
}
|
||||
|
||||
|
|
|
@ -17,10 +17,10 @@ namespace dxvk {
|
|||
|
||||
|
||||
bool DxvkDeviceFilter::testAdapter(const VkPhysicalDeviceProperties& properties) const {
|
||||
if (properties.apiVersion < VK_MAKE_VERSION(1, 3, 0)) {
|
||||
if (properties.apiVersion < VK_MAKE_API_VERSION(0, 1, 3, 0)) {
|
||||
Logger::warn(str::format("Skipping Vulkan ",
|
||||
VK_VERSION_MAJOR(properties.apiVersion), ".",
|
||||
VK_VERSION_MINOR(properties.apiVersion), " adapter: ",
|
||||
VK_API_VERSION_MAJOR(properties.apiVersion), ".",
|
||||
VK_API_VERSION_MINOR(properties.apiVersion), " adapter: ",
|
||||
properties.deviceName));
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
|
||||
#include "dxvk_include.h"
|
||||
|
||||
#include "../util/util_version.h"
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
/**
|
||||
|
@ -13,6 +15,7 @@ namespace dxvk {
|
|||
* so before using them, check whether they are supported.
|
||||
*/
|
||||
struct DxvkDeviceInfo {
|
||||
Version driverVersion;
|
||||
VkPhysicalDeviceProperties2 core;
|
||||
VkPhysicalDeviceVulkan11Properties vk11;
|
||||
VkPhysicalDeviceVulkan12Properties vk12;
|
||||
|
@ -68,6 +71,8 @@ namespace dxvk {
|
|||
VkPhysicalDeviceMaintenance5FeaturesKHR khrMaintenance5;
|
||||
VkPhysicalDevicePresentIdFeaturesKHR khrPresentId;
|
||||
VkPhysicalDevicePresentWaitFeaturesKHR khrPresentWait;
|
||||
VkPhysicalDeviceDescriptorPoolOverallocationFeaturesNV nvDescriptorPoolOverallocation;
|
||||
VkPhysicalDeviceRawAccessChainsFeaturesNV nvRawAccessChains;
|
||||
VkBool32 nvxBinaryImport;
|
||||
VkBool32 nvxImageViewHandle;
|
||||
VkBool32 khrWin32KeyedMutex;
|
||||
|
|
|
@ -61,7 +61,7 @@ namespace dxvk {
|
|||
* provided by the extension can be used.
|
||||
* \returns \c true if the extension is enabled
|
||||
*/
|
||||
operator bool () const {
|
||||
explicit operator bool () const {
|
||||
return m_revision != 0;
|
||||
}
|
||||
|
||||
|
@ -325,6 +325,8 @@ namespace dxvk {
|
|||
DxvkExt khrPresentWait = { VK_KHR_PRESENT_WAIT_EXTENSION_NAME, DxvkExtMode::Optional };
|
||||
DxvkExt khrSwapchain = { VK_KHR_SWAPCHAIN_EXTENSION_NAME, DxvkExtMode::Required };
|
||||
DxvkExt khrWin32KeyedMutex = { VK_KHR_WIN32_KEYED_MUTEX_EXTENSION_NAME, DxvkExtMode::Optional };
|
||||
DxvkExt nvDescriptorPoolOverallocation = { VK_NV_DESCRIPTOR_POOL_OVERALLOCATION_EXTENSION_NAME, DxvkExtMode::Optional };
|
||||
DxvkExt nvRawAccessChains = { VK_NV_RAW_ACCESS_CHAINS_EXTENSION_NAME, DxvkExtMode::Optional };
|
||||
DxvkExt nvxBinaryImport = { VK_NVX_BINARY_IMPORT_EXTENSION_NAME, DxvkExtMode::Disabled };
|
||||
DxvkExt nvxImageViewHandle = { VK_NVX_IMAGE_VIEW_HANDLE_EXTENSION_NAME, DxvkExtMode::Disabled };
|
||||
};
|
||||
|
|
|
@ -1111,7 +1111,9 @@ namespace dxvk {
|
|||
|
||||
if (doCreateBasePipeline)
|
||||
baseHandle = this->getBasePipeline(state);
|
||||
else
|
||||
|
||||
// Fast-linking may fail in some situations
|
||||
if (!baseHandle)
|
||||
fastHandle = this->getOptimizedPipeline(state);
|
||||
|
||||
// Log pipeline state if requested, or on failure
|
||||
|
@ -1148,6 +1150,13 @@ namespace dxvk {
|
|||
|| (state.rs.lineMode() != VK_LINE_RASTERIZATION_MODE_DEFAULT_EXT && isLineRendering))
|
||||
return false;
|
||||
|
||||
// Depth clip is assumed to be enabled. If the driver does not
|
||||
// support dynamic depth clip, we'd have to late-compile anyway
|
||||
// unless the pipeline is used multiple times.
|
||||
if (!m_device->features().extExtendedDynamicState3.extendedDynamicState3DepthClipEnable
|
||||
&& !state.rs.depthClipEnable())
|
||||
return false;
|
||||
|
||||
if (m_shaders.tcs != nullptr) {
|
||||
// If tessellation shaders are present, the input patch
|
||||
// vertex count must match the shader's definition.
|
||||
|
@ -1219,9 +1228,6 @@ namespace dxvk {
|
|||
key.viLibrary = m_manager->createVertexInputLibrary(viState);
|
||||
key.foLibrary = m_manager->createFragmentOutputLibrary(foState);
|
||||
|
||||
if (!m_device->features().extExtendedDynamicState3.extendedDynamicState3DepthClipEnable)
|
||||
key.args.depthClipEnable = state.rs.depthClipEnable();
|
||||
|
||||
auto entry = m_basePipelines.find(key);
|
||||
if (entry != m_basePipelines.end())
|
||||
return entry->second;
|
||||
|
@ -1236,10 +1242,11 @@ namespace dxvk {
|
|||
const DxvkGraphicsPipelineBaseInstanceKey& key) const {
|
||||
auto vk = m_device->vkd();
|
||||
|
||||
DxvkShaderPipelineLibraryHandle vs = m_vsLibrary->acquirePipelineHandle();
|
||||
DxvkShaderPipelineLibraryHandle fs = m_fsLibrary->acquirePipelineHandle();
|
||||
|
||||
std::array<VkPipeline, 4> libraries = {{
|
||||
key.viLibrary->getHandle(),
|
||||
m_vsLibrary->acquirePipelineHandle(key.args),
|
||||
m_fsLibrary->acquirePipelineHandle(key.args),
|
||||
key.viLibrary->getHandle(), vs.handle, fs.handle,
|
||||
key.foLibrary->getHandle(),
|
||||
}};
|
||||
|
||||
|
@ -1248,13 +1255,14 @@ namespace dxvk {
|
|||
libInfo.pLibraries = libraries.data();
|
||||
|
||||
VkGraphicsPipelineCreateInfo info = { VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, &libInfo };
|
||||
info.flags = vs.linkFlags | fs.linkFlags;
|
||||
info.layout = m_bindings->getPipelineLayout(true);
|
||||
info.basePipelineIndex = -1;
|
||||
|
||||
VkPipeline pipeline = VK_NULL_HANDLE;
|
||||
VkResult vr = vk->vkCreateGraphicsPipelines(vk->device(), VK_NULL_HANDLE, 1, &info, nullptr, &pipeline);
|
||||
|
||||
if (vr != VK_SUCCESS)
|
||||
if (vr && vr != VK_PIPELINE_COMPILE_REQUIRED_EXT)
|
||||
Logger::err(str::format("DxvkGraphicsPipeline: Failed to create base pipeline: ", vr));
|
||||
|
||||
return pipeline;
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue